/* --------------------------------------------*\
| lingua.c (version 1.3) -- (C) SichemSoft 1994 |
| Roghorst 160, 6708 KS Wageningen, Netherlands |
| utility for language independent applications |
| author: Anneke Sicherer-Roetman, date: 940311 |
\* --------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include "lingua.h"

/* opens file with error checking */
static FILE *openfile(char *name,char *mode)
{
   FILE *fp;

   fp=fopen(name,mode);
   if (!fp) printf("%s not opened\n",name);
   return fp;
} /* openfile */

/* writes array size in text area of file */
unsigned writesize(FILE *fp,unsigned long pos,unsigned size)
{
   unsigned long filpos; unsigned checksum; register int i;

   filpos=ftell(fp); fseek(fp,pos,SEEK_SET);
   fwrite(&size,sizeof(size),1,fp);
   fseek(fp,filpos,SEEK_SET);
   for (i=0,checksum=0; i<sizeof(size); i++)
      checksum+=((char*)(&size))[i]^UIT_ENCRYPT;
   return checksum;
}

/* returns pointer to string value by skipping spaces and tabs */
char *value(char *buf)
{
   char *p;
   p=strchr(buf,' '); if (!p) p=strchr(buf,'\t');
   if (!p) return NULL;
   *p=0; p++; while (*p==' ' || *p=='\t') p++;
   return p;
}

/* main text processing routine */
int main(int argc,char *argv[])
{
   FILE *txt,*etf,*header;
   char fname[81],buf[256],linefeed[3],*p,*q,space='_';
   unsigned long memoffset=0,filoffset=0,offset=0;
   unsigned long filpos1=0,filpos2=0,filpos3=0;
   unsigned memcount=0,filcount=0,lines=0,len=0,l=0;
   unsigned checksum=0,headlen=0,arrsize=0;
   unsigned array=FALSE,multi=FALSE,file=FALSE;

   /* copyright message and arguments check */
   puts("Lingua v1.3 - (C)1994 SichemSoft Wageningen Netherlands");
   if (argc!=2 && argc!=3) {
      puts("lingua <file> [<version>]"); return 1;
   }

   /* open all files */
   strcpy(fname,argv[1]);
   if (!strchr(fname,'.')) strcat(fname,".txt");
   if ((txt=openfile(fname,"r"))==NULL) return 2;
   if ((header=openfile("ui_text.h","w"))==NULL) return 2;
   strcpy(strchr(fname,'.')+1,"etf");
   if ((etf=openfile(fname,writeRA))==NULL) return 2;

   /* start of UI_TEXT.H */
   fputs("/* ui_text.h */\n\n",header);
   fputs("#ifndef UI_TEXT_H\n",header);
   fputs("#define UI_TEXT_H\n\n",header);
   fputs("#ifdef __cplusplus\n",header);
   fputs("extern \"C\" {\n",header);
   fputs("#endif\n\n",header);
   fputs("int ui_loadtext(char *fname,char *vers);\n",header);
   fputs("void ui_unloadtext(void);\n",header);
   fputs("char *ui_filetext(unsigned pos);\n",header);
   fputs("char **ui_filearray(unsigned pos);\n",header);
   fputs("extern char **ui_text;\n\n",header);

   /* start of .ETF (filename+version), checksum and counters */
   fprintf(etf,"%s%s\032",fname,argc==3?argv[2]:"");
   headlen=strlen(fname)+strlen(argc==3?argv[2]:"")+1;
   filpos1=ftell(etf);
   fwrite(&checksum,sizeof(checksum),1,etf);
   fwrite(&memcount,sizeof(memcount),1,etf);
   fwrite(&filcount,sizeof(memcount),1,etf);
   fwrite(&memoffset,sizeof(memoffset),1,etf);

   /* count lines, determine offsets and write to .ETF and UI_TEXT.H */
   while (fgets(buf,255,txt)) {
      l=strlen(buf)-1; if (buf[l]=='\n') buf[l]='\0';
      lines++;
      if (!buf[0]) continue;
      if (buf[0]=='#') { /* comment */
         if (!strcmp(buf+1,"FILE")) {
            if (file) goto fatal;
            file=TRUE; filpos2=ftell(etf);
         } else if (!strncmp(buf+1,"SPACE",5)) {
            p=value(buf); space=*p; if (!space) goto fatal;
         }
         continue;
      }
      p=value(buf);
      len=strlen(p); if (!strcmp(p,"-")) len=0;
      l=strlen(buf)-1;
      if (buf[l]=='[') { /* array identifier */
         if (l>0) { /* first element */
            buf[l]='\0'; array=TRUE; multi=FALSE;
            if (file) fprintf(header,"#define %-30s (ui_filearray(%u))\n",buf,filcount);
            else      fprintf(header,"#define %-30s (ui_text+%u)\n",buf,memcount);
         } else { /* next element */
            if (!array) goto fatal;
         }
         if (file) {
            fwrite(&filoffset,sizeof(filoffset),1,etf);
            filoffset+=len+1; filcount++;
            if (l>0) filoffset+=sizeof(arrsize);
         } else {
            fwrite(&memoffset,sizeof(memoffset),1,etf);
            memoffset+=len+1; memcount++;
         }
      } else if (buf[l]=='/') { /* multi line text */
         if (l>0) { /* first line */
            buf[l]='\0'; multi=TRUE; array=FALSE;
            if (file) {
               fprintf(header,"#define %-30s ui_filetext(%u)\n",buf,filcount);
               fwrite(&filoffset,sizeof(filoffset),1,etf);
               filoffset+=len+1; filcount++;
            } else {
               fprintf(header,"#define %-30s ui_text[%u]\n",buf,memcount);
               fwrite(&memoffset,sizeof(memoffset),1,etf);
               memoffset+=len+1; memcount++;
            }
         } else { /* next line */
            if (file) filoffset+=len+strlen(lf);
                 else memoffset+=len+strlen(lf);
            if (!multi) goto fatal;
         }
      } else { /* normal identifier */
         array=FALSE; multi=FALSE;
         if (file) {
            fprintf(header,"#define %-30s ui_filetext(%u)\n",buf,filcount);
            fwrite(&filoffset,sizeof(filoffset),1,etf);
            filoffset+=len+1; filcount++;
         } else {
            fprintf(header,"#define %-30s ui_text[%u]\n",buf,memcount);
            fwrite(&memoffset,sizeof(memoffset),1,etf);
            memoffset+=len+1; memcount++;
         }
      }
   }
   if (file) fwrite(&filoffset,sizeof(filoffset),1,etf);

   /* encrypt lines and write to .ETF */
   rewind(txt); array=multi=file=FALSE; space='_';
   strcpy(linefeed,lf); for (l=0; linefeed[l]; l++) linefeed[l]^=UIT_ENCRYPT;
   while (fgets(buf,255,txt)) {
      l=strlen(buf)-1; if (buf[l]=='\n') buf[l]='\0';
      if (!buf[0]) continue;
      if (buf[0]=='#') { /* comment */
         if (!strcmp(buf+1,"FILE")) file=TRUE;
         else if (!strncmp(buf+1,"SPACE",5)) {
            p=value(buf); space=*p;
         }
         continue;
      }
      p=value(buf);
      len=strlen(p); if (!strcmp(p,"-")) p[0]='\0';
      for (q=p; *q==space; q++) *q=' ';
      for (q=p+len-1; *q==space; q--) *q=' ';
      l=strlen(buf)-1; len=strlen(p)+1;
      if (buf[l]=='[') { /* array identifier */
         if (file) {
            if (l>0) {
               filpos3=ftell(etf);
               fwrite(&arrsize,sizeof(arrsize),1,etf);
               array=TRUE; arrsize=1;
            } else arrsize++;
         }
         if (multi) putc('\0'^UIT_ENCRYPT,etf);
         multi=FALSE;
      } else if (buf[l]=='/') { /* multi line text */
         if (l==0 && multi) { fputs(linefeed,etf); checksum+=lfchk; }
         if (l>0) {
            if (file && array) {
               checksum+=writesize(etf,filpos3,arrsize);
               array=FALSE;
            }
            if (multi) putc('\0'^UIT_ENCRYPT,etf);
            multi=TRUE;
         }
      } else { /* normal identifier */
         if (file && array) {
            checksum+=writesize(etf,filpos3,arrsize);
            array=FALSE;
         }
         if (multi) putc('\0'^UIT_ENCRYPT,etf);
         multi=FALSE;
      }
      for (q=p; *q; q++) {
         checksum+=(unsigned char)(*q); *q^=UIT_ENCRYPT; putc(*q,etf);
      }
      if (!multi) putc('\0'^UIT_ENCRYPT,etf);
   }
   if (multi) putc('\0'^UIT_ENCRYPT,etf);
   if (file && array) checksum+=writesize(etf,filpos3,arrsize);

   /* write checksum and number of items and bytes to .ETF */
   fseek(etf,filpos1,SEEK_SET);
   fwrite(&checksum,sizeof(checksum),1,etf);
   fwrite(&memcount,sizeof(memcount),1,etf);
   fwrite(&filcount,sizeof(memcount),1,etf);
   fwrite(&memoffset,sizeof(memoffset),1,etf);

   /* correct file item offsets */
   if (filcount) {
      fseek(etf,filpos2,SEEK_SET);
      offset=headlen+sizeof(checksum)+sizeof(memcount)+sizeof(filcount)+
             sizeof(memoffset)+memcount*sizeof(memoffset)+
             (filcount+1)*sizeof(filoffset)+memoffset;
      for (l=0; l<filcount+1; l++) {
         filpos2=ftell(etf);
         fread(&filoffset,sizeof(filoffset),1,etf);
         fseek(etf,filpos2,SEEK_SET); filoffset+=offset;
         fwrite(&filoffset,sizeof(filoffset),1,etf);
         fseek(etf,0,SEEK_CUR); /* to enable read after write ! */
      }
   }

   /* end of UI_TEXT.H */
   fputs("\n#ifdef __cplusplus\n",header);
   fputs("}\n",header);
   fputs("#endif\n\n",header);
   fputs("#endif\n\n",header);

   /* close all files */
   fclose(txt); fclose(etf); fclose(header);
   printf("%u memory items (%lu bytes), ",memcount,memoffset);
   printf("%u file items (%lu bytes)\n",filcount,filoffset-offset);

   return 0;

fatal: printf("fatal error in text file at line %d\n",lines);
   return 3;
}
