/* * ffe - flat file extractor * * Copyright (C) 2006 Timo Savinen * This file is part of ffe. * * ffe is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * ffe is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ffe; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* $Id: execute.c,v 1.69 2007-10-29 17:49:31 timo Exp $ */ #include "ffe.h" #include #include #include #include #ifdef PACKAGE static char *program = PACKAGE; #else static char *program = "ffe"; #endif #define GUESS_LINES 10000 #define GUESS_BUFFER (1024 * 1024) #define READ_LINE_LEN (128 * 1024) #define FIELD_SIZE (8 * 1024) #define WRITE_BUFFER (512 * 1024) extern struct replace *replace; static struct input_file *files = NULL; static struct input_file *current_file = NULL; static FILE *input_fp = NULL; static char *output_file = NULL; static FILE *output_fp = NULL; static char *guess_buffer[GUESS_LINES]; static int guess_line_length[GUESS_LINES]; static char *read_buffer = NULL; static size_t read_buffer_size = READ_LINE_LEN; static char *field_buffer = NULL; static int field_buffer_size = FIELD_SIZE; static int guess_lines = 0; static int read_guess_line = 0; /* write buffer definitions */ static char *write_buffer = NULL; static int write_buffer_size = WRITE_BUFFER; static char *write_pos; static char *write_buffer_end; /* file number counters */ static long int current_file_lineno; static long int current_total_lineno; /* examples of non matching lines */ #define NO_MATCH_LINES 10 static int no_matching_lines = 0; /* header definition from structure */ static int headers; char *current_file_name = NULL; void set_output_file(char *name) { if(name == NULL) { output_fp = stdout; output_file = "(stdout)"; } else { output_fp = fopen(name,"w"); if(output_fp == NULL) { panic("cannot open file",name,strerror(errno)); } output_file = name; } } void close_output_file() { if(fclose(output_fp) != 0) { panic("Error closing file",output_file,strerror(errno)); } } void set_input_file(char *name) { register struct input_file *f = files; if(files == NULL) { files = xmalloc(sizeof(struct input_file)); f = files; } else { while(f->next != NULL) f = f->next; f->next = xmalloc(sizeof(struct input_file)); f = f->next; } f->next = NULL; f->name = xstrdup(name); f->lineno = 0; } void open_input_file() { read_buffer = xmalloc(read_buffer_size); field_buffer = xmalloc(field_buffer_size); if(files->name[0] == '-' && !files->name[1]) { input_fp = stdin; files->name = "(stdin)"; } else { input_fp = fopen(files->name,"r"); if(input_fp == NULL) { panic("Cannot open file",files->name,strerror(errno)); } } current_file = files; current_file->lineno = 0; current_file_name = current_file->name; } /* reads one file from input */ /* returns the line length */ /* return -1 on EOF */ int read_input_line() { int ccount; do { #ifdef HAVE_GETLINE ccount = getline(&read_buffer,&read_buffer_size,input_fp); #else if(fgets(read_buffer,read_buffer_size,input_fp) != NULL) { ccount = strlen(read_buffer); } else { ccount = -1; } #endif if(ccount == -1) { if(fclose(input_fp)) { panic("Error closing file",files->name,strerror(errno)); } current_file = current_file->next; if(current_file != NULL) { if(current_file->name[0] == '-' && !current_file->name[1]) { input_fp = stdin; current_file->name = "(stdin)"; } else { input_fp = fopen(current_file->name,"r"); if(input_fp == NULL) { panic("Cannot open file",current_file->name,strerror(errno)); } } current_file_name = current_file->name; current_file->lineno = 0; } } else { current_file->lineno++; } } while(ccount == -1 && current_file != NULL); if(ccount > 0) { current_file_lineno = current_file->lineno; ccount--; /* remove newline */ read_buffer[ccount] = 0; } return ccount; } /* calculate field count from line containing separated fields */ int get_field_count(char quote, char *type, char *line) { int inside_quote = 0; int fields = 0; register char *p = line; if(type[0] == FIXED_LENGTH) return 0; if (*p) fields++; /* at least one */ while(*p) { if(*p == type[1] && !inside_quote) { fields++; if(type[2] == '*') while(*p == type[1]) p++; } if(((*p == quote && p[1] == quote) || (*p == '\\' && p[1] == quote)) && inside_quote && quote) { p++; } else if(*p == quote && quote) { inside_quote = !inside_quote; } if(*p) p++; } return fields; } /* returns a pointer for one field of the fixed length record */ /* note first position is 1 */ char * get_fixed_field(int position, int length, int line_length, char *line) { register char *t,*s; if(length >= field_buffer_size - 1) { field_buffer_size = length * 2; field_buffer = xrealloc(field_buffer,field_buffer_size); } if(position < line_length && position) { position--; /* to get first as zero */ s = line + position; t = field_buffer; while(length && *s) { *t = *s; t++; s++; length--; } *t = 0; } else { field_buffer[0] = 0; } return field_buffer; } /* returns pointer to field in separated record */ char * get_separated_field(int position, char quote, char *type, char *line) { register char *p = line; int fieldno = 1; int inside_quote = 0; register int i = 0; while(*p && fieldno <= position) { if(*p == type[1] && !inside_quote) { fieldno++; if(type[2] == '*') while(*p == type[1]) p++; } if(((*p == quote && p[1] == quote) || (*p == '\\' && p[1] == quote)) && inside_quote && quote) { p++; } else if(*p == quote && quote) { inside_quote = !inside_quote; if(inside_quote && p[1]) p++; } if(fieldno == position) { if(*p == type[1] || (*p == quote && quote)) { if(inside_quote) { field_buffer[i] = *p; i++; } } else { field_buffer[i] = *p; i++; } if(i >= field_buffer_size - 1) { field_buffer_size = i * 2; field_buffer = xrealloc(field_buffer,field_buffer_size); } } if(*p) p++; } field_buffer[i] = 0; return field_buffer; } /* calculates votes for record, length has the buffer len and buffer contains the line to be examined */ int vote_record(char quote, char *type,int header,struct record *record,int length, char *buffer) { struct id *i = record->i; int vote = 0; int ids = 0; while(i != NULL) { ids++; switch(type[0]) { case FIXED_LENGTH: if(strcmp(i->key,get_fixed_field(i->position, strlen(i->key), length, buffer)) == 0) vote++; break; case SEPARATED: if(header && current_file_lineno == 1) // forgive header lines { vote++; } else { if(strcmp(i->key,get_separated_field(i->position,quote,type,buffer)) == 0) vote++; } break; } i = i->next; } if(vote || record->i == NULL) /* if keys are ok or missing, then check line length */ { switch(type[0]) { case FIXED_LENGTH: if(record->length == length) vote++; break; case SEPARATED: if(record->length == get_field_count(quote,type,buffer)) vote++; break; } } if(vote == ids + 1) /* every id and line length must match to get a vote */ { return 1; } else { return 0; } } /* calculates votes for one input line */ void vote(int bindex) { struct structure *s = structure; struct record *r; int votes,total_votes = 0; while(s != NULL) { r = s->r; votes = 0; if(s->vote == bindex) // check only structures having all records matched so far { while(r != NULL && !votes) { votes = vote_record(s->quote,s->type,s->header,r,guess_line_length[bindex],guess_buffer[bindex]); s->vote += votes; /* only one vote per line */ r = r->next; } } total_votes += votes; s = s->next; } if(!total_votes && no_matching_lines < NO_MATCH_LINES) { no_matching_lines++; fprintf(stderr,"%s: Line %ld in \'%s\' does not match, line length = %d\n",program,current_file->lineno,current_file->name,guess_line_length[bindex]); } } /* calculates votes for structures */ /* returns pointer for structure name having more that 50 % of total votes */ char * check_votes() { struct structure *s = structure; char *winner = NULL; int errors = 0; while(s != NULL && guess_lines) { if(s->vote == guess_lines) { if(winner == NULL) { winner = s->name; } else { if(!errors) { fprintf(stderr,"%s: Input data matches several structures: \'%s\'",program,winner); } fprintf(stderr," \'%s\'",s->name); errors++; } } s = s->next; } if(errors) { fprintf(stderr,"\n"); winner = NULL; } return winner; } /* tries guess the input file structure */ /* returns pointer to the name of guessed structure */ char * guess_structure() { int memory_used = 0; int len; do { len = read_input_line(); if(len != -1) { guess_buffer[guess_lines] = xstrdup(read_buffer); guess_line_length[guess_lines] = len; memory_used += len; vote(guess_lines); guess_lines++; } } while(len != -1 && guess_lines < GUESS_LINES && memory_used < GUESS_BUFFER); return check_votes(); } /* start write to write buffer */ void start_write() { write_pos = write_buffer; } /* write char to write buffer */ inline void writec(char c) { *write_pos = c; if(write_pos == write_buffer_end) { int written = write_buffer_end - write_buffer; write_buffer_size = write_buffer_size * 2; write_buffer = xrealloc(write_buffer,write_buffer_size); write_pos = write_buffer + written; write_buffer_end = write_buffer + (write_buffer_size - 1); } write_pos++; } /* write string to write buffer */ inline void writes(char *string) { register char *s = string; if(s != NULL) { while(*s) { writec(*s); s++; } } } void flush_write() { size_t bytes; bytes = write_pos - write_buffer; if(fwrite(write_buffer,1,bytes,output_fp) != bytes) { panic("Error writing to",output_file,NULL); } } /* prints arbitrary text */ /* text can contain %-directives (no %d,%D, or %n) */ void print_text(struct structure *s, struct record *r,char *buffer) { register char *text = buffer; char num[64]; if(text == NULL) return; if(r != NULL && (r->o == no_output)) return; if(s->o == no_output) return; start_write(); while(*text) { if(*text == '%' && text[1]) { text++; switch(*text) { case 'f': writes(current_file_name); break; case 's': writes(s->name); break; case 'r': if(r != NULL) writes(r->name); break; case 'o': sprintf(num,"%ld",current_file_lineno); writes(num); break; case 'O': sprintf(num,"%ld",current_total_lineno); writes(num); break; case '%': writec('%'); break; default: writec('%'); writec(*text); break; } } else { writec(*text); } text++; } flush_write(); } /* prints a header text */ /* text can contain only one %-directive %n */ /* return values: */ /* 1 - Header is printed or header should not be printed */ /* 0 - Header is not printed and should be printed */ int print_header(struct structure *s, struct record *r) { struct print_field *pf = r->pf; if(r->o == no_output || r->o->header == NULL) return 1; /* no header for this run */ if(pf == NULL) return 0; /* no printable fields for this record */ start_write(); while(pf != NULL) { char *text = r->o->header; while(*text) { if(*text == '%' && text[1]) { text++; switch(*text) { case 'n': writes(pf->f->name); break; default: writec('%'); writec(*text); break; } } else { writec(*text); } text++; } if(pf->next != NULL && r->o->separator != NULL) writes(r->o->separator); pf = pf->next; } writes(r->o->record_trailer); flush_write(); return 1; /* header printed */ } /* returns pointer to next input line lines are forst read from guess buffer (if allocated) and after that from input stream, current_file_name,current_file_lineno etc are updated accordingly. returns NULL if no more lines length will be written to len */ char * get_input_line(int *len) { static struct input_file *curr_guess_file = NULL; char *ret = NULL; *len = -1; if(curr_guess_file == NULL) { curr_guess_file = files; current_file_name = curr_guess_file->name; } do { if(read_guess_line < guess_lines) { if(current_file_lineno == curr_guess_file->lineno) { curr_guess_file = curr_guess_file->next; while(!curr_guess_file->lineno) { curr_guess_file = curr_guess_file->next; } current_file_name = curr_guess_file->name; current_file_lineno = 0; } current_file_lineno++; ret = guess_buffer[read_guess_line]; *len = guess_line_length[read_guess_line]; read_guess_line++; } else if(current_file != NULL) { *len = read_input_line(); ret = read_buffer; } if(*len == -1) { ret = NULL; } else { current_total_lineno++; } } while(current_file_lineno == 1 && headers == HEADER_ALL && current_total_lineno > 1); return ret; } /* bpositions will be updated according current input buffer */ void update_field_positions(char *type,char quote,struct field *fields,int len,char *buffer) { register char *p = buffer; register int inside_quote = 0; struct field *f = fields; switch(type[0]) { case FIXED_LENGTH: while(f != NULL) { if(len > f->position) { f->bposition = f->position; } else { f->bposition = -1; } f = f->next; } break; case SEPARATED: while(f != NULL) { f->bposition = -1; f = f->next; } f = fields; while(*p && f != NULL) { if(p == buffer) // first { if(*p != type[1]) f->bposition = 0; f = f->next; } if((*p == type[1] && !inside_quote)) { p++; if(type[2] == '*') while(*p == type[1]) p++; if(*p != type[1]) { f->bposition = (int) (p - buffer); } else { p--; } f = f->next; } if(((*p == quote && p[1] == quote) || (*p == '\\' && p[1] == quote)) && inside_quote && quote) { p++; } else if(*p == quote && quote) { inside_quote = !inside_quote; } if(*p) p++; } break; } } /* check which record applies to current line */ struct record * select_record(struct structure *s,int length,char *buffer) { register struct record *r; r = s->r; while(r != NULL) { if(vote_record(s->quote,s->type,s->header,r,length,buffer)) return r; r = r->next; } return NULL; } /* print a single fixed field */ void print_fixed_field(char format,struct field *f,char *buffer) { register int i = 0; register char *data; char *start = write_pos; if(f->const_data != NULL) { data = f->const_data; } else { data = &buffer[f->bposition]; } switch(format) { case 'd': case 'D': case 'e': while(i < f->length) writec(data[i++]); break; case 't': while(isspace(data[i])) i++; while(i < f->length) writec(data[i++]); if(write_pos > start && isspace(write_pos[-1])) { write_pos--; while(write_pos > start && (isspace(*write_pos))) write_pos--; write_pos++; } break; } } /* print a single separated field */ void print_separated_field(char format,char quote,char separator,struct field *f,char *buffer) { register char *p; char *start; int inside_quote = 0; start = write_pos; if(f->const_data != NULL) // use fixed field printing for const data { print_fixed_field(format,f,buffer); } else { if(f->bposition < 0) { if(format == 'D') while(write_pos - start < f->length) writec(' '); return; } switch(format) { case 'd': case 't': case 'D': case 'e': p = &buffer[f->bposition]; if(quote || format == 't') while(isspace(*p)) p++; if(*p == quote && quote) { p++; inside_quote = 1; if(format == 't') while(isspace(*p)) p++; } while((*p != separator || inside_quote) && *p) { if(((*p == quote && p[1] == quote) || (*p == '\\' && p[1] == quote)) && quote) { p++; } else if(*p == quote) { if(inside_quote) { if(format == 't' && isspace(write_pos[-1])) { write_pos--; while(write_pos > start && isspace(*write_pos)) write_pos--; write_pos++; } if(format == 'D') while(write_pos - start < f->length) writec(' '); return; } } writec(*p); if(*p) p++; } if(format == 't' && isspace(write_pos[-1])) { write_pos--; while(write_pos > start && isspace(*write_pos)) write_pos--; write_pos++; } if(format == 'D') while(write_pos - start < f->length) writec(' '); break; } } } /* search the lookup table, return the found value */ char * make_lookup(struct lookup *l,char *search) { register char *k,*s; int search_len = strlen(search); int max_len = -1; char *ret_val = NULL; char *longest = NULL; struct lookup_data *d = l->data; switch(l->type) { case EXACT: if(search_len <= l->max_key_len) { while(d != NULL && ret_val == NULL) { k = d->key; s = search; while(*k == *s && *k) { k++; s++; } if(!*s && !*k) ret_val = d->value; d = d->next; } } break; case LONGEST: while(d != NULL && max_len < l->max_key_len) { k = d->key; s = search; while(*k == *s && *k) { k++; s++; } if(!*k && d->key_len > max_len) { max_len = d->key_len; longest = d->value; } d = d->next; } ret_val = longest; break; } if(ret_val == NULL) ret_val = l->default_value; return ret_val; } /* print fields */ /* returns the count of fields actually printed */ int print_fields(struct structure *s, struct record *r,char *buffer) { char num[64]; int max_justify_len = 0; register int i; register char *d,*f; char justify = r->o->justify; char *indent = r->o->indent,*separator = r->o->separator; char *data_start,*rep_start,*rep_pos; char *field_start; char *lookup_value; int retval = 0; int replacing,just_replaced; int lookup_len; struct print_field *pf = r->pf; if(r->o == no_output) return retval; while(pf != NULL) { pf->justify_length = -1; pf = pf->next; } pf = r->pf; start_write(); while(pf != NULL) { d = r->o->data; data_start = write_pos; pf->data = data_start; pf->empty = 1; replacing = 0; just_replaced = 0; lookup_value = NULL; if(pf->f->lookup != NULL) d = r->o->lookup; while(*d) { if(justify != LEFT_JUSTIFY && justify != RIGHT_JUSTIFY && justify == *d && pf->justify_length == -1 && !replacing) { pf->justify_length = (int) (write_pos - data_start); if(pf->justify_length > max_justify_len) { max_justify_len = pf->justify_length; } } if(*d == '%') { d++; switch(*d) { case 'f': writes(current_file_name); break; case 's': writes(s->name); break; case 'r': if(r != NULL) writes(r->name); break; case 'o': sprintf(num,"%ld",current_file_lineno); writes(num); break; case 'O': sprintf(num,"%ld",current_total_lineno); writes(num); break; case 'p': if(pf->f->const_data == NULL) { sprintf(num,"%d",pf->f->position + (s->type[0] == FIXED_LENGTH ? 1 : 0)); writes(num); } break; case '%': writec('%'); break; case 'n': writes(pf->f->name); break; case 'l': case 'L': if(pf->f->lookup != NULL) { if(lookup_value == NULL) { field_start = write_pos; // misuse write buffer for temp space for field value switch(s->type[0]) // write trimmed data for search key { case FIXED_LENGTH: print_fixed_field('t',pf->f,buffer); break; case SEPARATED: print_separated_field('t',s->quote,s->type[1],pf->f,buffer); break; } writec(0); lookup_value = make_lookup(pf->f->lookup,field_start); write_pos = field_start; // restore write buffer } } else if(lookup_value == NULL) { lookup_value = ""; } writes(lookup_value); if(*d == 'L') { lookup_len = strlen(lookup_value); while(lookup_len++ < pf->f->length) writec(' '); } break; case 'd': case 't': case 'D': case 'e': field_start = write_pos; if(pf->f->rep != NULL && !replacing) // start possible replacing { replacing = 1; just_replaced = 1; rep_pos = d; rep_start = write_pos; d = pf->f->rep->value; break; // end case } switch(s->type[0]) { case FIXED_LENGTH: print_fixed_field(*d,pf->f,buffer); break; case SEPARATED: print_separated_field(*d,s->quote,s->type[1],pf->f,buffer); break; } if(!r->o->print_empty) { f = field_start; while(f < write_pos) { if(strchr(r->o->empty_chars,*f) == NULL) { pf->empty = 0; f = write_pos; // to stop while loop } f++; } } if(*d == 'e') write_pos = field_start; break; default: writec('%'); writec(*d); break; } if(!just_replaced) d++; } else { writec(*d); d++; } if(replacing && !*d) { d = rep_pos; d++; replacing = 0; if(*rep_pos == 'D') { if(write_pos - rep_start < pf->f->length) { while(write_pos - rep_start < pf->f->length) writec(' '); } else if(write_pos - rep_start > pf->f->length) { write_pos = rep_start + pf->f->length; } } } if(just_replaced) just_replaced = 0; } if(justify == RIGHT_JUSTIFY) { pf->justify_length = (int) (write_pos - data_start); if (pf->justify_length > max_justify_len) { max_justify_len = pf->justify_length; } } writec(0); // end of data marker pf = pf->next; } pf = r->pf; /* count the number of fields to be printed */ /* we need this before hand, because we must know if the is att least */ /* one field to be printed, then all separators must be printed */ while(pf != NULL) { if(r->o->print_empty || !pf->empty) { retval++; } pf = pf->next; } pf = r->pf; while(pf != NULL && retval) { if(r->o->print_empty || !pf->empty) { if(indent != NULL) { fputs(indent,output_fp); fputs(indent,output_fp); } if((justify != LEFT_JUSTIFY && justify != RIGHT_JUSTIFY && max_justify_len) || justify == RIGHT_JUSTIFY) { i = pf->justify_length; while(i < max_justify_len && i != -1) { putc(' ',output_fp); i++; } } fputs(pf->data,output_fp); } if(pf->next != NULL && separator != NULL) fputs(separator,output_fp); pf = pf->next; } return retval; } /* make a list of printable fields if include list is non empty use names from it else use the whole field list in f */ struct print_field * make_print_list(struct include_field *fl,struct field *f) { struct print_field *ret = NULL,*c = NULL; struct field *n; if(fl == NULL) { while(f != NULL) { if(strcmp(f->name,"FILLER") != 0) { if(ret == NULL) { ret = xmalloc(sizeof(struct print_field)); c = ret; } else { c->next = xmalloc(sizeof(struct print_field)); c = c->next; } c->f = f; c->next = NULL; } f = f->next; } } else { while(fl != NULL) { n = const_field; // first check const list while(n != NULL && (strcasecmp(fl->name,n->name) != 0)) { n = n->next; } if(n == NULL) // if not found in const list check input fields { n = f; while(n != NULL && (strcasecmp(fl->name,n->name) != 0)) { n = n->next; } } if(n != NULL) { if(ret == NULL) { ret = xmalloc(sizeof(struct print_field)); c = ret; } else { c->next = xmalloc(sizeof(struct print_field)); c = c->next; } c->f = n; c->next = NULL; fl->found = 1; } fl = fl->next; } } return ret; } /* check that all fields we found from current structure */ /* return the count of unmatched fields */ int check_field_list(struct include_field *fl) { int ret = 0; while(fl != NULL) { if(!fl->found) { if(!fl->reported) fprintf(stderr,"%s: Field '%s' was not found in the current structure\n",program,fl->name); fl->reported = 1; ret++; } fl = fl->next; } return ret; } void init_structure(struct structure *s,struct record *current_record,int length, char *buffer) { struct record *r; struct field *f; struct replace *rep; struct expression *e; int list_errors = 0; r = s->r; while(r != NULL) { f = r->f; while(f != NULL) { if(s->header && f->name == NULL) f->name = xstrdup(get_separated_field(f->position,s->quote,s->type,buffer)); rep = replace; while(rep != NULL) { if(strcasecmp(f->name,rep->field) == 0) { f->rep = rep; rep->found = 1; } rep = rep->next; } e = expression; while(e != NULL) { if(strcasecmp(f->name,e->field) == 0) { e->found = 1; } e = e->next; } f = f->next; } r = r->next; } r = s->r; while(r != NULL) { if(r->o != no_output) r->pf = make_print_list(r->o->fl,r->f); r = r->next; } r = s->r; while(r != NULL) { if(check_field_list(r->o->fl)) list_errors++; r = r->next; } if(list_errors) panic("Some fields from field list were not found in the current structure or constant values",s->name,NULL); rep = replace; while(rep != NULL) { if(!rep->found) panic("Field to be replaced was not found in the current structure",rep->field,NULL); rep = rep->next; } e = expression; while(e != NULL) { if(!e->found) panic("Field in expression was not found in the current structure",e->field,NULL); e = e->next; } } void invalid_input(char *file, long int lineno,int strict,int length) { fprintf(stderr,"%s: Invalid input line in file \'%s\', line %ld, line length = %d\n",program,file,lineno,length); if(strict) panic("Use of -l option does not cause program to abort in case of invalid input line",NULL,NULL); } /* returns true if and = 0 and attleast one expression is true * or and = 1 and all expressions are true */ int eval_expression(struct structure *s, int and,int invert, char *buffer) { struct expression *e = expression; struct expr_list *el; int retval = 0; int eq_found; int prev_retval; int loop_break = 0; int expression_count = 0; if(e == NULL) return 0; e = expression; while(e != NULL && !loop_break) { if(e->f != NULL) { start_write(); switch(s->type[0]) { case FIXED_LENGTH: print_fixed_field('d',e->f,buffer); break; case SEPARATED: print_separated_field('d',s->quote,s->type[1],e->f,buffer); break; } writec(0); // end of string if(e->el != NULL) { el = e->el; prev_retval = retval; eq_found = 0; do { switch(e->op) { case OP_START: if(strncmp(el->value,write_buffer,el->value_len) == 0) retval++; break; case OP_EQUAL: if(strcmp(el->value,write_buffer) == 0) retval++; break; case OP_CONTAINS: if(strstr(write_buffer,el->value) != NULL) retval++; break; case OP_NOT_EQUAL: if(strcmp(write_buffer,el->value) == 0) eq_found++; break; #ifdef HAVE_REGEX case OP_REQEXP: if(regexec(&el->reg,write_buffer,(size_t) 0, NULL, 0) == 0) retval++; break; #endif } el = el->next; } while(el != NULL && prev_retval == retval && !eq_found); if(e->op == OP_NOT_EQUAL && !eq_found) retval++; } else { switch(e->op) { case OP_START: if(strncmp(e->value,write_buffer,e->value_len) == 0) retval++; break; case OP_EQUAL: if(strcmp(e->value,write_buffer) == 0) retval++; break; case OP_CONTAINS: if(strstr(write_buffer,e->value) != NULL) retval++; break; case OP_NOT_EQUAL: if(strcmp(write_buffer,e->value) != 0) retval++; break; #ifdef HAVE_REGEX case OP_REQEXP: if(regexec(&e->reg,write_buffer,(size_t) 0, NULL, 0) == 0) retval++; break; #endif } } } if(!and && retval) { loop_break = 1; } expression_count++; if(and && retval != expression_count) { loop_break = 1; } e = e->next; } if(and) { if (retval == expression_count) { retval = 1; } else { retval = 0; } } if(invert) retval = !retval; return retval; } /* initialize expressions field pointers */ /* pointers are preinitialized for faster execution */ void init_expression_list(struct record *r) { struct expression *e; struct field *f = r->f; e = expression; while(e != NULL) { e->f = NULL; e = e->next; } e = expression; while(f != NULL) { e = expression; while(e != NULL) { if(strcasecmp(e->field,f->name) == 0 && e->f == NULL) { e->f = f; } e = e->next; } f = f->next; } } /* main loop for execution */ void execute(struct structure *s,int strict, int expression_and,int expression_invert) { char *input_line; struct record *r = NULL; struct record *prev_record = NULL; int length; int header_printed = 0; int fields_printed; int first_line = 1; current_file_lineno = 0; current_total_lineno = 0; current_file_name = files->name; headers = s->header; write_buffer = xmalloc(write_buffer_size); write_buffer_end = write_buffer + (write_buffer_size - 1); print_text(s,NULL,s->o->file_header); while((input_line = get_input_line(&length)) != NULL) { prev_record = r; r = select_record(s,length,input_line); if(r == NULL) { invalid_input(current_file_name,current_file_lineno,strict,length); } else { if(first_line) { init_structure(s,r,length,input_line); } if(expression != NULL && (prev_record != r || prev_record == NULL)) { init_expression_list(r); } if((!first_line || !headers) && r->o != no_output) { if((r->pf == NULL && r->o->no_data == 1) || r->pf != NULL) { update_field_positions(s->type,s->quote,r->f,length,input_line); if(expression == NULL || (eval_expression(s,expression_and,expression_invert,input_line))) { if(r->o->header != NULL && !header_printed) { header_printed = print_header(s,r); } if(r->o->indent != NULL) print_text(s,r,r->o->indent); print_text(s,r,r->o->record_header); fields_printed = print_fields(s,r,input_line); if(fields_printed || r->o->print_empty) { if(r->o->indent != NULL) print_text(s,r,r->o->indent); print_text(s,r,r->o->record_trailer); } } } } if(first_line) first_line = 0; } } print_text(s,r,s->o->file_trailer); free(write_buffer); }