/*  (c) 1990 S.Hawtin.
  Permission is granted to copy this file provided
   1) It is not used for commercial gain
   2) This notice is included in all copies
   3) Altered copies are marked as such

  No liability is accepted for the contents of the file.

*/

/* Translate text files between different formats */

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* The name of the data file */
char *data_name = "asc2doc.dat";
char *object = "";
int line_length = -1;
int gotdata = 0;

#define MY_EOF -1
#define MY_EOL -2
#define MY_GOES 256

#define MAX_TRANS 20
#define TRANS_LENGTH 10

typedef struct
   {
    char from[TRANS_LENGTH];
    char to[TRANS_LENGTH];
    int  where;
    } Translation;

Translation table[MAX_TRANS];
int num_trans;

/* Variables controlled by $ vars in the data file */
typedef struct
   {char *name;
    int *int_val;
    } VarStruct;

VarStruct vars[] =
   {   {"line",&line_length},
       {NULL,NULL}
    };

char from_name[80];
char to_name[80];

int
tyi(fptr)
    FILE *fptr;
   {/* Read next character from format file */
    int next,i;
    char var[32];

    next = fgetc(fptr);
    switch(next)
       {
        case '$':
            /* Set a $ variable in the program */
            i = 0;
            do {
                next = fgetc(fptr);
                var[i++] = next;
                } while (next>=0 && !isspace(next));
            var[--i] = '\0';
            for(i = 0;vars[i].name!=NULL && stricmp(var,vars[i].name)!=0;i++);
            if(vars[i].name!=NULL)
               {/* we are setting variable number i */
                fgets(var,32,fptr);
                ungetc('\n',fptr);
                *vars[i].int_val = atoi(var);
                }
            /* We have our variable value, now treat the rest of the line as 
               a comment */
        case '#':
            /* Comment, skip chars until eol or eof */
            while(next>=0)
               {next = fgetc(fptr);
                if(next=='\n')
                    next = MY_EOL;
                if(feof(fptr))
                    next = MY_EOF;
                }
            break;
        case '\n': case '\r':
            next = MY_EOL;
            break;
        case EOF:
            next = MY_EOF;
            break;
        case '\t': case '\v':
            next = ' ';
            break;
        case '\\':
            next = fgetc(fptr);
            switch(next)
               {case 'n': case 'N':
                    next = '\n';
                    break;
                case 't': case 'T':
                    next = '\t';
                    break;
                case 'r': case 'R':
                    next = '\r';
                    break;
                case '-': case '_':
                    next = MY_GOES;
                    break;
                }
        }
    if(feof(fptr))
        next = MY_EOF;

    return(next);
    }

void
read_quote(name,fptr)
    char *name;
    FILE *fptr;
   {
    int next,i;

    do {
        next = tyi(fptr);
        } while(next!='\"' && next>0);

    i = 0;
    do {
        name[i] = tyi(fptr);
        } while (name[i++]!='\"' && next>0);
    name[i-1] = '\0';
    }

tyo(next,fptr)
    int  next;
    FILE *fptr;
   {/* Output a character to the file, if line-len is not -1 then 
       we collect words together to limit the line length */
    static char buffer[128];
    static int buf_ptr = 0;
    static int line_pos = 0;
    static int space = 0;

    if(isspace(next))
        space = -1;
      else if (space)
       {if(line_length>0 && (line_pos+buf_ptr)>=line_length)
           {fputc('\n',fptr);
            line_pos = 0;
            }
        buffer[buf_ptr] = '\0';
        fputs(buffer,fptr);
        line_pos += buf_ptr;
        buf_ptr = 0;
        space = 0;
        }
    if(next!=MY_EOF && next!='\n')
        buffer[buf_ptr++] = next;
      else
       {if(next=='\n')
            buffer[buf_ptr++] = next;
        buffer[buf_ptr] = '\0';
        fputs(buffer,fptr);
        buf_ptr = 0;
        line_pos = 0;
        }
    if(line_length>0 && buf_ptr>line_length)
       {/* Line would be too long with this word, lets go */
        fputc('\n',fptr);
        buffer[buf_ptr] = '\0';
        fputs(buffer,fptr);
        fputc('\n',fptr);
        line_pos = 0;
        buf_ptr = 0;
        }
    }

translate(source,dest)
    FILE *source;
    FILE *dest;
   {/* Translate between file formats */
    int trans,next,i,state;

    /* Keep looking till we find a translation */
    for(i = 0;i<num_trans;i++)
        table[i].where = 0;
    next = fgetc(source);
    state = 0;

    while(state!=4)
       {
        state = 0;
        for(i = 0;i<num_trans;i++)
           {if(table[i].from[table[i].where]=='\0')
               {state = 1;
                trans = i;
                }
            if(table[i].from[table[i].where]==next)
               {
                if(state==0)
                    trans = i;
                state = 2;
                table[i].where++;
                }
              else if(table[i].where!=0 && state==0)
               {state = 3;
                trans = i;
                table[i].where++;
                }
              else
                table[i].where=0;
            }
        switch (state)
           {
            case 1:
                for(i=0;table[trans].to[i]!='\0';i++)
                    tyo(table[trans].to[i],dest);
                table[trans].where = 0;
                tyo(next,dest);
                break;
            case 3:
                for(i=0;i<table[trans].where;i++)
                    tyo(table[trans].from[i],dest);
                table[trans].where = 0;
            case 0:
                tyo(next,dest);
                break;
            }

        if(feof(source))
           {/* Flush the buffer and set state to 4 */
            if(state!=0)
                for(i=0;i<table[trans].where;i++)
                    tyo(table[trans].to[i],dest);
            tyo(MY_EOF);
            state = 4;
            }
          else
            next = fgetc(source);
        }
    }

main(argc,argv)
    int argc;
    char **argv;
   {/* Translate between text file formats */
    int i;
    FILE *data_fptr;
    int next;

    /* First get the command line options */
    for(i=1;i<argc;i++)
       {if(argv[i][0] == '-')
           {
            switch(argv[i][1])
               {
                case 'L': case 'l':
                    line_length = atoi(&argv[i][2]);
                    break;
                case 'O': case 'o':
                    object = &argv[i][2];
                    break;
                default:
                    goto out_options;
                }
            }
          else if(!gotdata)
           {/* Data file name */
            data_name = argv[i];
            gotdata = -1;
            }
          else
           {
out_options:
            printf("Options are\n\n");
            printf("    -o<object>\n");
            printf("    -l<line_length>\n");
            printf("    <datafile>\n");
            exit(20);
            }
        }
    /* So we now have the options, open the data file and read the 
       translations that we need */
    data_fptr = fopen(data_name,"r");
    if(data_fptr==NULL)
       {printf("Failed to open \"%s\"\n",data_name);
        exit(20);
        }

    /* Read to the start of the first translation */
    do {
        next = tyi(data_fptr);
        } while (next==MY_EOL);

    /* We have the first character of the first translation */
    for(num_trans=0;next>0;num_trans++)
       {/* Deal with each translation in turn */
        i = 0;
        do {
            table[num_trans].from[i++] = next;
            next = tyi(data_fptr);
            } while (next>0 && next!=MY_GOES);
        table[num_trans].from[i] = '\0';
        if(i>TRANS_LENGTH)
           {printf("Translation %d too long\n",num_trans);
            exit(20);
            }
        i = 0;
        do {
            next = tyi(data_fptr);
            table[num_trans].to[i++] = next;
            } while (next>0);
        table[num_trans].to[i-1] = '\0';
        if(i>TRANS_LENGTH)
           {printf("Translation %d too long\n",num_trans);
            exit(20);
            }
        next = tyi(data_fptr);
        }

    /* Read to the start of the first data name */
    do {
        next = tyi(data_fptr);
        } while (isspace(next) || next==MY_EOL);

    /* Right now go through the files and translate the ones we want */
    do {/* Read the next name */
        i = 0;
        while((object[i]!='\0') && (next>0) && (object[i]==next))
           {next = tyi(data_fptr);
            i++;
            }
        read_quote(from_name,data_fptr);
        read_quote(to_name,data_fptr);
        if(object[i]=='\0')
           {/* We have an object that matches the object name */
            FILE *from_fptr;
            FILE *to_fptr;

            printf("Translating \"%s\" -> \"%s\"\n",from_name,to_name);
            from_fptr=fopen(from_name,"r");
            if(from_fptr==NULL)
                printf("Cannot open \"%s\"\n",from_name);
              else
               {to_fptr=fopen(to_name,"w");
                if(to_fptr==NULL)
                    printf("Cannot open \"%s\"\n",to_name);
                  else
                   {
                    translate(from_fptr,to_fptr);
                    fclose(to_fptr);
                    }
                fclose(from_fptr);
                }
            }
        do {
            next = tyi(data_fptr);
            } while ((next>0 && isspace(next)) || next==MY_EOL);
        } while (next!=MY_EOF);
    /* Tidy up */
    fclose(data_fptr);
    }
