Logo Search packages:      
Sourcecode: ffe version File versions  Download package

execute.c

/* 
 *    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.67 2007-05-30 07:32:48 timo Exp $ */

#include "ffe.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

#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;
    int retval = 0;
    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
            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);
}




Generated by  Doxygen 1.6.0   Back to index