#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <fctype.h>
#include <error.h>
#include <dos.h>
#include <exec/types.h>
#include <libraries/dosextens.h>

#include <dlg/DLG.h>
#include <dlg/User.h>
#include <dlg/Misc.h>
#include <dlg/Resman.h>
#include <dlg/PortConfig.h>
#include <dlg/Input.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/dlg.h>

/* command template:

   Extract <indir> <outdir> -L|P|F

   -L == DLG.library module
   -P == Program module
   -F == Link lib function

   Indir and Outdir must be paths that it is legal to append a / to

   To use language files, you need as a global variable:

   char **SA;

   Then, in the program, you enter

   SA = GetLang(NULL);
   if(!SA) error...

   Then use the SA[whatever] construct.

   To extract the language information, in the unaltered source file you need

   '//LANGFLAG'

   just before the line with the string -- it is case sensitive and MUST
   start in column 1 of the source file.

   Extract does dupe checking.  If you want to force dupe checking off, use

   '//LANGFLAG NODUP'

   To run Extract, you must be in the language dir.  The altered file will be
   English.dat.

*/

int  main(int, char **);
int  cmpnumbers(struct QuoteEntry *, struct QuoteEntry *);
int  cmpnames(struct NameStruct *, struct NameStruct *);
void CleanUp(char *);

#define STRINGS "T:Strings"
#define LANG    "English.Lang"

struct QuoteEntry {char  quote[200];
                   short pos;
                  };

BPTR              sout;
FILE             *ifp     = NULL;
FILE             *nfp     = NULL;

struct Library   *DLGBase = NULL;
struct NameStruct Files[1000];

int main(int argc, char **argv)

{char                *s;
 char                *idir     = NULL;
 char                *odir     = NULL;

 char                *qstart;
 char                *ptr;
 long                 count;
 long                 spares;
 long                 nfile = 0;
 long                 cfile = 0;
 ULONG                size;

 UBYTE                inquote;
 UBYTE                nodup;

 UBYTE                program  = FALSE;
 UBYTE                library  = FALSE;
 UBYTE                function = FALSE;

 struct SearchCookie *sc;
 struct QuoteEntry   *qs;
 struct QuoteEntry   *qc;
 struct QuoteEntry    qe;
 char                 buf  [1024];
 char                 err  [256];
 char                 ifile[128];
 char                 ofile[128];

 sout = Output();
 if (argc < 4)  CleanUp("Not enough args  Extract <Input Dir> <Output Dir> -[P|L|F]");

 while(--argc>0)
      {s = *++argv;

       if (*s++ == '-')
          {while(*s)
                {switch(toupper(*s))
                       {case 'P': program++;
                                  break;

                        case 'L': library++;
                                  break;

                        case 'F': function++;
                                  break;
                       }
                 s++;
                }
          }
        else
          {if (!idir)
              {idir = *argv;
               continue;
              }
           if (!odir)
              {odir = *argv;
               continue;
              }
          }
      }

 if (!(program + library + function))
     CleanUp("Invalid Source Type [-P|-L|-F]");
 if ((program + library + function) != 1)
     CleanUp("Too many Source Type [-P|-L|-F] -- only one allowed");
 if (!(DLGBase = OpenLibrary(DLGNAME, DLGVERSION)))
     CleanUp("Can't open dlg.library");

 if (!(sc = SearchStart(idir, "*")))
    {ASPrintf(NULL, err, "No files in [%s]", idir);
     CleanUp(err);
    }

 while((s = SearchNext(sc)))
      {strcpy(Files[nfile].name, s);
       nfile++;
      }
 SearchEnd(sc);
 qsort(Files, nfile, sizeof(struct NameStruct), cmpnames);

 while(cfile < nfile)
      {s = Files[cfile].name;
       cfile++;

       ASPrintf(NULL, ifile, "%s/%s", idir, s);
       ASPrintf(NULL, ofile, "%s/%s", odir, s);

       AFPrintf(NULL, sout, "File %s...", s);
       if (DLGPatternMatch("*.o", s))
          {AFPrintf(NULL, sout, "Skipped\n");
           DeleteFile(ofile);
           continue;
          }

       if (!DLGPatternMatch("*.c", s))
          {Copy(ifile, ofile);
           AFPrintf(NULL, sout, "Copied\n");
           continue;
          }

       count = 0;
       if ((ifp = fopen(LANG, "r")))
          {while(fgets(buf, 1024, ifp))
                 if (buf[0] != ';')  count++;

           AFPrintf(NULL, sout, "Found %d Language Strings...", count);
           fclose(ifp);
          }

       ifp = fopen(ifile, "r");
       if (!ifp)
          {ASPrintf(NULL, err, "Unable to open input [%s]", ifile);
           CleanUp(err);
          }

       nfp = fopen(ofile, "w");
       if (!nfp)
          {fclose(ifp);
           ASPrintf(NULL, err, "Unable to open output [%s]", ofile);
           CleanUp(err);
          }

       inquote = FALSE;
       qstart  =   0;
       while(fgets(buf, 1024, ifp))
            {if (strncmp(buf, "//LANGFLAG", 10))
                {fputs(buf, nfp);
                 continue;
                }
             if (strstr(buf, "NODUP"))
                 nodup = 1;
               else
                 nodup = 0;

             if (!fgets(buf, 1024, ifp))  break;

             fputs("// ",nfp);
             fputs(buf,nfp);

             for(ptr = buf; *ptr; ptr++)
                {if (*ptr == 34)
                    {if (inquote)
                        {*ptr    = 0;
                         inquote = FALSE;

                         memset(qe.quote, 0, 200);

                         if (nodup)
                            {ASPrintf(NULL, qe.quote, "%c%s%c%d", 34, qstart+1, 34, count);
                             qe.pos = count;
                            }
                          else
                            {ASPrintf(NULL, qe.quote, "%c%s%c", 34, qstart+1, 34);
                             qe.pos = count;
                            }

                         if (GetStruct(STRINGS, (char *)&qe, sizeof(struct QuoteEntry), 200)!=-1)
                            {fprintf(nfp, "SA[%d]", qe.pos);
                             continue;
                            }

                         AddStruct(STRINGS, (char *)&qe, sizeof(struct QuoteEntry), 200);
                         fprintf(nfp, "SA[%d]", count);
                         count++;
                         continue;
                        }
                      else
                        {inquote = TRUE;
                         qstart  = ptr;
                         continue;
                        }
                    }

                 if (!inquote)  putc(*ptr, nfp);
                }
            }

       fclose(ifp);
       fclose(nfp);

       if (!FileSize(STRINGS, &size))
          {if (size)
              {count  = (long)(size / sizeof(struct QuoteEntry));
               spares =  count / 5;
               if (spares < 5)  spares = (count / 3) + 1;
               if (spares < 5)  spares = (count / 2) + 1;
               if (spares < 5)  spares =  5;
               AFPrintf(NULL, sout, "Adding %d Strings...Spares %d...", count, spares);

               qs = malloc(size);
               if (!qs)  CleanUp("Can't Allocate Language String Table");

               ifp = fopen(STRINGS, "r");
               if (!ifp) CleanUp("Can't Open Temporary Language Strings");

               fread(qs, size, 1, ifp);
               fclose(ifp);
               qsort(qs, count, sizeof(struct QuoteEntry), cmpnumbers);

               if (Exists(LANG))
                  {nfp = fopen(LANG, "r+");
                   fseek(nfp, 0, SEEK_END);
                  }
                else
                   nfp = fopen(LANG, "w+");

               if (program)
                  {size        = strlen(s);
                   s[size - 2] = 0;
                   fprintf(nfp, ";\n;Strings for DLG:%s\n;\n", s);
                  }

               if (library)
                  {fprintf(nfp, ";\n;Strings for DLG.Library\n;\n");
                   library = FALSE;
                  }

               if (function)
                  {fprintf(nfp, ";\n;Strings for Common Functions\n;\n");
                   function = FALSE;
                  }

               for(qc = qs, size = 0; size < count; qc++, size++)
                  {for(s = qc->quote + strlen(qc->quote) - 1; *s != '"'; *s-- = 0);
                   fwrite(qc->quote, strlen(qc->quote), 1, nfp);
                   fwrite("\n",      1,                 1, nfp);
                  }

               count = (count / 5) + 1;
               for(size = 0; size < spares; size++)
                   fwrite("\"SPARE\"\n", 8, 1, nfp);

               fclose(nfp);
               free(qs);
              }
          }

       AFPrintf(NULL, sout, "Done\n");
       DeleteFile(STRINGS);
      }

 CleanUp(NULL);
}


int cmpnumbers(struct QuoteEntry *q1, struct QuoteEntry *q2)

{return(q1->pos - q2->pos);
}


int cmpnames(struct NameStruct *st1, struct NameStruct *st2)

{return(Stricmp(st1->name, st2->name));
}


void CleanUp(char *s)

{if (DLGBase)  CloseLibrary(DLGBase);

 if (s)
    {Write(sout,"\n Error: ", 9);
     Write(sout, s,    strlen(s));
     Write(sout, "\n\n",      2);
    }

 exit(s?5:0);
}
