#include <stdio.h>
#include <fcntl.h>

#define ASTR    0;
#define DIGIT   1;
#define WSPC    2;
#define NEWLINE 3;
#define DASH    4;
#define MISC    5;

long ftell();

struct state_rec
    {
        short next;
        short action;
    };
    
struct state_rec s_table[8][6] =
    {
        /* state 0 */
        {
            { 1, 0 },   /* ASTR */
            { 0, 0 },   /* DIGIT */
            { 0, 0 },   /* WSPC */
            { 0, 0 },   /* NEWLINE */
            { 0, 99},   /* DASH */
            { 0, 99 }    /* MISC */
        },
        /* state 1 */
        {
            { 0, 99 },   /* ASTR */
            { 2, 2 },   /* DIGIT */
            { 1, 0 },   /* WSPC */
            { 0, 99 },   /* NEWLINE */
            { 0, 99},   /* DASH */
            { 0, 99 }    /* MISC */
        },
        /* state 2 */
        {
            { 3, 4 },   /* ASTR */
            { 2, 3 },   /* DIGIT */
            { 3, 4 },   /* WSPC */
            { 4, 4 },   /* NEWLINE */
            { 0, 99},   /* DASH */
            { 3, 4 }    /* MISC */
        },
        /* state 3 */
        {
            { 3, 0 },   /* ASTR */
            { 3, 0 },   /* DIGIT */
            { 3, 0 },   /* WSPC */
            { 4, 0 },   /* NEWLINE */
            { 3, 0},   /* DASH */
            { 3, 0 }    /* MISC */
        },
        /* state 4 */
        {
            { 0, 99 },   /* ASTR */
            { 5, 2 },   /* DIGIT */
            { 4, 0 },   /* WSPC */
            { 4, 0 },   /* NEWLINE */
            { 5, 7},   /* DASH */
            { 0, 99 }    /* MISC */
        },
        /* state 5 */
        {
            { 0, 6 },   /* ASTR */
            { 5, 3 },   /* DIGIT */
            { 6, 5 },   /* WSPC */
            { 6, 5 },   /* NEWLINE */
            { 0, 99},   /* DASH */
            { 0, 99 }    /* MISC */
        },
        /* state 6 */
        {
            { 1, 1 },   /* ASTR */
            { 5, 2 },   /* DIGIT */
            { 6, 0 },   /* WSPC */
            { 6, 0 },   /* NEWLINE */
            { 5, 7},   /* DASH */
            { 0, 99 }    /* MISC */
        }
    };

FILE *infile;
int outfile;

char inname[100];
char outname[100];
char linebuf[100];

unsigned long d_index[256];
short data[30000];


main(argc,argv)
    int argc;
    char *argv[];
{
    short CellWidth,CellHeight;
    short HighChar;
    unsigned long pos;
    short val;
    char c;
    short class, i;
    short state,nextstate;
    short action;
    short sign;
    
    state=0;
    pos=0;
    HighChar=0;

    if(argc!=2)
    {
        printf("bad args\n");
        exit();
    }
    
    strcpy(inname,argv[1]);
    strcat(inname,".fnt");
    
    strcpy(outname,"pltdata:");
    strcat(outname,argv[1]);
    
    infile=fopen(inname,"r");
    if( infile == NULL )
    {
        printf("can't open %s\n",inname);
        exit();
    }
    
    outfile=open(outname,O_CREAT | O_WRONLY);
    if( outfile == -1 )
    {
        printf("can't open %s\n",outname);
        exit();
    }
    
    printf("Creating %s.\n",outname);

    for (i=0; i<256; i++)
        d_index[i]=-1;

    linebuf[0]=0;
    fgets(linebuf,99,infile);
    
    if( sscanf(linebuf,"%d %d",&CellWidth,&CellHeight) != 2 )
    {
        printf("error in width or height\n");
        exit();
    }
    
    while( feof(infile) == 0 )
    {
        c=fgetc(infile);
        if( c == EOF )
            break;
        
        switch(c)
        {
            case '*':   class=ASTR;
                        break;
            
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':   class=DIGIT;
                        break;
            
            case ' ':
            case '\t':  class=WSPC;
                        break;
            
            case '\n':  class=NEWLINE;
                        break;
            
            case '-':   class=DASH;
                        break;
            
            default:    class=MISC;
        }
        
        nextstate=s_table[state][class].next;
        action=s_table[state][class].action;

#ifdef DEBUG
        printf("cs %d c '%c' ns %d ac %d\n",state,c,nextstate,action);
#endif

        
        switch(action)
        {
            case 1: data[pos]=-1;
                    pos++;
                    break;
                    
            case 2: val = c - '0';
                    sign=1;
                    break;
            
            case 3: val = (val * 10) + (c - '0');
                    break;
            
            case 4: d_index[val] = pos;
                    if(HighChar < val)
                        HighChar = val;
                    break;
            
            case 5: data[pos] = sign*val;
                    pos++;
                    break;
                    
            case 6: data[pos] = sign*val;
                    pos++;
                    data[pos] = -1;
                    pos++;
                    break;
            
            case 7: sign=-1;
                    val=0;
                    break;
            
            case 99: printf("\nerror: c='%c' pos=%ld\n",c,(long)ftell(infile));
                     exit();
                     break;
                     
        }
        
        state=nextstate;
    }
    
    data[pos++]=-1;
    write(outfile,&HighChar,sizeof(short));
    write(outfile,&CellWidth,sizeof(short));
    write(outfile,&CellHeight,sizeof(short));
    
    write(outfile,d_index,(int)((HighChar+1)*sizeof(long)));
    
    write(outfile,&pos,sizeof(long));
    
    write(outfile,data,(int)(pos*sizeof(short)));
    
    fclose(infile);
    close(outfile);
}
