home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 1 / Meeting Pearls Vol 1 (1994).iso / installed_progs / dev / flexcat / src / flexcat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-08  |  33.6 KB  |  1,653 lines

  1. /*
  2.     FlexCat.c:    The flexible catalog creator                V 1.3
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.  
  19.  
  20.     Ok, this is nothing special. It grabs a catalog translation and a
  21.     catalog description file and produces catalogs and the source to
  22.     handle 'em. What is it else than lots of other programs?
  23.  
  24.     The difference is, that YOU determine what source FlexCat produces.
  25.     Another file is scanned by FlexCat to produce code. This file contains
  26.     some c-string like special characters (%v for version for example)
  27.     You can edit this file and modify it as you want. So FlexCat can produce
  28.     C source as well as Assembler, Oberon, Modula 2, E, ...
  29.  
  30.     Command line syntax:
  31.  
  32.     FlexCat CDFILE/A,CTFILE,NEWCTFILE/K,CATALOG/K,SOURCES/M
  33.  
  34.     CDFILE    - the name of the catalog description file; see CatComp for
  35.         syntax
  36.     CTFILE    - the name of a catalog translation file; see CatComp for
  37.         syntax
  38.     NEWCTFILE - the name of a catalog transcription file to be created
  39.         (will be a copy of CDFILE except that the strings remain
  40.         empty and will be put as comments behind the string
  41.         definition)
  42.     CATALOG   - the name of the catalog to be created; default is the
  43.         basename of the CDFILE and .catalog appended
  44.     SOURCES   - the sourcefiles to be created. These arguments take a special
  45.         form: sourcefile=templatefile where sourcefile is the
  46.         name of the file to create and templatefile is the name of
  47.         a template file containing some special patterns. The
  48.         template file will be scanned and written to the source
  49.         file with these special patterns replaced by certain
  50.         strings. Possible patterns are:
  51.  
  52.             %b        basename of CDFILE (for example "file", if
  53.                 CDFILE is "file.cd")
  54.             %v        version
  55.             %l        language (of CDFILE)
  56.             %n        number of catalog strings
  57.             %%        the percent sign itself
  58.  
  59.         The following patterns indicate, that the line should be
  60.         repeated for each catalog string.
  61.             %i        the string's ID descriptor
  62.             %d        the string's ID
  63.             %e        the string's number (counting from 0)
  64.             %s        the string itself
  65.             %(...)  indicates that anything between the brackets
  66.                 should appear for any line except the last
  67.                 (Oberon and Modula need a "," to separate array
  68.                 entries, but the last entry must not be
  69.                 terminated by a ",". So you would terminate an
  70.                 array entry by a %(,).)
  71.  
  72.     Example: Let the string description be
  73.  
  74.     MSG_HELLO (5//)
  75.     Hello!
  76.  
  77.     Then the special characters produce
  78.     %i = MSG_HELLO
  79.     %d = 5
  80.     %s = "Hello!"
  81.  
  82.     Additionally the following characters may appear (as well as in the
  83.     catalog description and catalog translation file)
  84.     \b    = Backspace (Ascii 8)
  85.     \c    = Control sequence introducer (Ascii 155)
  86.     \e    = Escape (Ascii 27)
  87.     \f    = Form feed (Ascii 12)
  88.     \g    = Display beep (Ascii 7)
  89.     \n    = line feed, newline (Ascii 10)
  90.     \r    = carriage return (Ascii 13)
  91.     \t    = Tab (Ascii 9)
  92.     \v    = Vertical tab (Ascii 11)
  93.     \)    = the character ')' (Needed inside %(..))
  94.     \\    = the backslash itself
  95.     \xHH  = Ascii code HH (where HH are hex digits)
  96.     \OOO  = Ascii code OOO (where OOO are octal digits)
  97.  
  98.     A backslash at the end of a line indicates that the line should be
  99.     concatenated with the next one.
  100.  
  101.  
  102.     Computer:    Amiga 1200            Compiler: Dice, 2.07.54R
  103.  
  104.     Author:    V 1.0        31.06.1993        Jochen Wiedmann
  105.                         Am Eisteich 9
  106.                       72555 Metzingen
  107.                         Tel. 07123 / 14881
  108.  
  109.                 Internet: wiedmann@mailserv.zdv.uni-tuebingen.de
  110.  
  111.         V1.01        Fixed a bug: The length of the source string
  112.                 was used to check for the stringlen instead of
  113.                 the real stringlen.
  114.  
  115.         V1.1        Fixed two bugs: FlexCat didn't notice, if an
  116.                 ID was defined twice (C-Compiler did later.) and
  117.                 using language strings like français did not work
  118.                 because of the the accented char. Introduced E
  119.                 support. (Thanks Lionel Vintenat)
  120.  
  121.         V1.2        Fixed a bug in the E source generator: " was
  122.                 converted into \" and ' was not converted.
  123.  
  124.         V1.3        Fixed a bug that caused FlexCat to hang if a
  125.                 catalog translation was updated and a string
  126.                 was missing in the catalog description.
  127.  
  128.                 Fixed a bug that caused FlexCat to create
  129.                 invalid catalogs probably. (Seems like the
  130.                 locale.library expects a completely different
  131.                 behaviour in padding version and language
  132.                 strings and the real catalog strings.)
  133.  
  134.                 Added %e to source descriptions.
  135. */
  136.  
  137.  
  138.  
  139. #include <stdlib.h>
  140. #include <stdio.h>
  141. #include <string.h>
  142. #include <ctype.h>
  143. #ifdef AMIGA
  144. #include <exec/types.h>
  145. #include <clib/exec_protos.h>
  146. #include <clib/utility_protos.h>
  147. #include "FlexCat_cat.h"
  148.  
  149. #ifdef AZTEC_C
  150. #include <pragmas/exec_lib.h>
  151. #include <pragmas/utility_lib.h>
  152. #endif
  153.  
  154. #if defined(_DCC)  ||  defined(__SASC)  ||  defined(__MAXON__)
  155. #include <pragmas/exec_pragmas.h>
  156. #include <pragmas/utility_pragmas.h>
  157. #endif
  158.  
  159. #ifdef __GNUC__
  160. #include <inline/exec.h>
  161. #include <inline/utility.h>
  162. #endif
  163.  
  164. #ifdef tolower
  165. #undef tolower
  166. #endif
  167. #define tolower ToLower
  168. #define stricmp Stricmp
  169. #define strnicmp Strnicmp
  170.  
  171. #endif
  172.  
  173.  
  174. #ifndef FALSE
  175. #define FALSE 0
  176. #endif
  177. #ifndef TRUE
  178. #define TRUE (!FALSE)
  179. #endif
  180.  
  181.  
  182. enum StringTypes {
  183.     TYPE_C,        /*    Produce C strings            */
  184.     TYPE_ASSEMBLER, /*    Produce Assembler strings        */
  185.     TYPE_OBERON,    /*    Produce Oberon strings            */
  186.     TYPE_E,        /*    Produce E strings. (Oops, thought   */
  187.             /*    it allows only 32 bit integers? ;-) */
  188.     TYPE_NONE        /*    Simple strings                */
  189. };
  190.  
  191.  
  192. enum OutputModes {
  193.     OutputMode_None,    /*  Nothing written yet         */
  194.     OutputMode_Bin,    /*  Last character written was binary    */
  195.     OutputMode_Ascii    /*  Last character written was Ascii    */
  196. };
  197.  
  198. struct CatString
  199. { struct CatString *Next;
  200.   char *CD_Str;
  201.   char *CT_Str;
  202.   char *ID_Str;
  203.   int MinLen, MaxLen, ID, Nr;
  204. };
  205.  
  206. struct CDLine
  207. { struct CDLine *Next;
  208.   char *Line;
  209. };
  210.  
  211.  
  212. struct CatString *FirstCatString = NULL;  /*  First catalog string    */
  213. struct CDLine *FirstCDLine = NULL;  /*    First catalog description line    */
  214.  
  215. char *BaseName = "";                /*  Basename of catalog description */
  216. char *Language = "english";         /*  Language of catalog description */
  217. int CatVersion = 0;            /*    Version of catalog to be opened */
  218. int LengthBytes = 0;            /*    Number of bytes to preceed a    */
  219.                     /*    created string and containing    */
  220.                     /*    its length.            */
  221. char *CatLanguage = NULL;        /*    Language of catalog translation */
  222. char *CatVersionString = NULL;        /*    version string of catalog    */
  223.                     /*    translation            */
  224. int CodeSet = 0;            /*    Codeset of catalog translation    */
  225. int NumStrings = 0;            /*    Number of catalog strings    */
  226. int LongStrings = TRUE;         /*    Generate long or short strings    */
  227.  
  228.  
  229. char *ScanFile;             /*    File currently scanned        */
  230. int ScanLine;                /*    Line currently scanned        */
  231.  
  232. struct Library *LocaleBase = NULL;
  233. struct Library *UtilityBase = NULL;
  234. extern struct ExecBase *SysBase;
  235.  
  236.  
  237.  
  238.  
  239.  
  240. const UBYTE VERSION[] = "$VER: FlexCat 1.3 (30.05.94)   by  Jochen Wiedmann";
  241.  
  242.  
  243.  
  244.  
  245. /*
  246.     This terminates the program.
  247. */
  248. void Cleanup(int result)
  249.  
  250. {
  251. #ifdef AMIGA
  252.   CloseFlexCatCatalog();
  253.   if (LocaleBase)
  254.   { CloseLibrary(LocaleBase);
  255.   }
  256.   if (UtilityBase)
  257.   { CloseLibrary(UtilityBase);
  258.   }
  259. #endif
  260.   exit(result);
  261. }
  262.  
  263. /*
  264.     This shows an error message and terminates
  265. */
  266. struct RDArgs *Args;
  267. void ShowError(const UBYTE (*msg), ...)
  268.  
  269. { char **ptr = (char **) &msg;
  270.  
  271.   fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  272.   putc('\n', stderr);
  273.   Cleanup(10);
  274. }
  275.  
  276.  
  277.  
  278. /*
  279.     This shows the message: Memory error.
  280. */
  281. void MemError(void)
  282.  
  283. { ShowError(GetFlexCatString(msgMemoryError), NULL);
  284. }
  285.  
  286.  
  287.  
  288.  
  289. /*
  290.     This shows a warning
  291. */
  292. void ShowWarn(const UBYTE (*msg), ...)
  293.  
  294. { char **ptr = (char **) &msg;
  295.  
  296.   fprintf(stderr, (char *) GetFlexCatString(msgWarning), ScanFile, ScanLine);
  297.   fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  298.   putc('\n', stderr);
  299. }
  300.  
  301.  
  302.  
  303.  
  304. /*
  305.     This allocates a string
  306. */
  307. char *AllocString(const char *str)
  308.  
  309. { char *ptr;
  310.  
  311.   if (!(ptr = malloc(strlen(str)+1)))
  312.   { MemError();
  313.   }
  314.   strcpy(ptr, str);
  315.   return(ptr);
  316. }
  317.  
  318.  
  319.  
  320.  
  321. /*
  322.     This translates a hex character.
  323. */
  324. int gethex(int c)
  325.  
  326. {
  327.   if (c >= '0'  &&  c <= '9')
  328.   { return(c - '0');
  329.   }
  330.   else if (c >= 'a'  &&  c <= 'f')
  331.   { return(c - 'a' + 10);
  332.   }
  333.   else if (c >= 'A'  &&  c <= 'F')
  334.   { return(c - 'A' + 10);
  335.   }
  336.   ShowWarn(GetFlexCatString(msgExpectedHex));
  337.   return(0);
  338. }
  339.  
  340.  
  341.  
  342.  
  343. /*
  344.     This translates an octal digit.
  345. */
  346. int getoctal(int c)
  347.  
  348. {
  349.   if (c >= '0'  &&  c <= '7')
  350.   { return(c - '0');
  351.   }
  352.   ShowWarn(GetFlexCatString(msgExpectedOctal));
  353.   return(0);
  354. }
  355.  
  356.  
  357.  
  358.  
  359. /*
  360.     Reading a line is somewhat compicated in order to allow lines of any
  361.     length.
  362.  
  363.     Inputs: fp         - the file, where the input comes from
  364.         AllowComment - TRUE, if a leading semicolon should force to
  365.                interpret the line as a comment line
  366. */
  367. #define BUFSIZE 4096
  368. char *ReadLine(FILE *fp, int AllowComment)
  369.  
  370. { char *OldLine, *NewLine = NULL;
  371.   int c = '\0';
  372.   int Len = 0, LineLen = 0;
  373.   int FirstChar = TRUE;
  374.   int BackslashSeen = FALSE;
  375.  
  376.   while (c != EOF)
  377.   { if (Len+10 > LineLen)
  378.     { OldLine = NewLine;
  379.       if (!(NewLine = malloc(LineLen+BUFSIZE)))
  380.       { MemError();
  381.       }
  382.       strncpy(NewLine, OldLine, LineLen);
  383.       if (OldLine)
  384.       { free(OldLine);
  385.       }
  386.       LineLen += BUFSIZE;
  387.     }
  388.  
  389.     c = getc(fp);
  390.     if (FirstChar)
  391.     { if (c == EOF)
  392.       { free(NewLine);
  393.     return(NULL);
  394.       }
  395.       FirstChar = FALSE;
  396.     }
  397.  
  398.     switch(c)
  399.     { case '\r':
  400.     break;
  401.       case '\n':
  402.     ++ScanLine;
  403.     if (BackslashSeen)
  404.     { NewLine[Len++] = c;
  405.       BackslashSeen = FALSE;
  406.       break;
  407.     }
  408.     c = EOF;
  409.       case EOF:
  410.     break;
  411.       case '\\':
  412.     BackslashSeen = TRUE;
  413.     NewLine[Len++] = c;
  414.     break;
  415.       default:
  416.     BackslashSeen = FALSE;
  417.     NewLine[Len++] = c;
  418.     }
  419.   }
  420.   NewLine[Len] = '\0';
  421.  
  422.   return(NewLine);
  423. }
  424.  
  425.  
  426.  
  427.  
  428. /*
  429.     This removes trailing blanks.
  430. */
  431. void OverSpace(char **strptr)
  432.  
  433. { int c;
  434.  
  435.   while ((c = **strptr) == ' '  ||  c == '\t')
  436.   { (*strptr)++;
  437.   }
  438. }
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447. /*
  448.     ReadChar scans an input line translating the backslash characters.
  449.  
  450.     Inputs: strptr  - a pointer to a stringpointer; the latter points to the
  451.               next character to be read and points behind the read
  452.               bytes after executing ReadChar
  453.         dest    - a pointer to a buffer, where the read bytes should be
  454.               stored
  455.  
  456.     Result: number of bytes that are written to dest (between 0 and 2)
  457. */
  458. int ReadChar(char **strptr, char *dest)
  459.  
  460. { char c;
  461.   int i;
  462.  
  463.   switch(c = *((*strptr)++))
  464.   { case '\\':
  465.       switch(c = tolower((int) *((*strptr)++)))
  466.       { case '\n':
  467.       return(0);
  468.     case 'b':
  469.       *dest = '\b';
  470.       break;
  471.     case 'c':
  472.       *dest = '\233';
  473.       break;
  474.     case 'e':
  475.       *dest = '\033';
  476.       break;
  477.     case 'f':
  478.       *dest = '\f';
  479.       break;
  480.     case 'g':
  481.       *dest = '\007';
  482.       break;
  483.     case 'n':
  484.       *dest = '\n';
  485.       break;
  486.     case 'r':
  487.       *dest = '\r';
  488.       break;
  489.     case 't':
  490.       *dest = '\t';
  491.       break;
  492.     case 'v':
  493.       *dest = '\013';
  494.       break;
  495.     case 'x':
  496.       *dest = gethex((int) **strptr);
  497.       (*strptr)++;
  498.       if (((c = **strptr) >= '0'  &&  c <= '9')  ||
  499.           (c >= 'a'  &&  c <= 'f')  ||  (c >= 'A'  &&  c <= 'F'))
  500.       { *dest = (*dest << 4) + gethex((int) c);
  501.         (*strptr)++;
  502.       }
  503.       break;
  504.     case '0':
  505.     case '1':
  506.     case '2':
  507.     case '3':
  508.     case '4':
  509.     case '5':
  510.     case '6':
  511.     case '7':
  512.       *dest = getoctal((int) **strptr);
  513.       (*strptr)++;
  514.       for (i = 0;  i < 2;  i++)
  515.       { if ((c = **strptr) >= '0'  &&  c <= '7')
  516.         { *dest = (*dest << 3) + getoctal((int) c);
  517.           (*strptr)++;
  518.         }
  519.       }
  520.       break;
  521.     case ')':
  522.     case '\\':
  523.       *(dest++) = '\\';
  524.       *dest = c;
  525.       return(2);
  526.     default:
  527.       *dest = c;
  528.       }
  529.       break;
  530.     default:
  531.       *dest = c;
  532.   }
  533.   return(1);
  534. }
  535.  
  536.  
  537.  
  538.  
  539. /*
  540.     This scans the catalog description file.
  541.  
  542.     Inputs: cdfile  - name of the catalog description file
  543.  
  544.     Result: TRUE, if successfull, FALSE otherwise
  545. */
  546. int ScanCDFile(char *cdfile)
  547.  
  548. { FILE *fp;
  549.   struct CDLine *cdline, **cdptr = &FirstCDLine;
  550.   struct CatString *cs, **csptr = &FirstCatString;
  551.   char *line, *newline;
  552.   char *ptr;
  553.   int NextID = 0, len;
  554.   int Result = TRUE;
  555.  
  556.   ScanFile = cdfile;
  557.   ScanLine = 0;
  558.  
  559.   if (!(fp = fopen(cdfile, "r")))
  560.   { ShowError(GetFlexCatString(msgNoCatalogDescription), cdfile);
  561.   }
  562.  
  563.   /*
  564.       Get the basename
  565.   */
  566.   if ((ptr = strchr(cdfile, ':')))
  567.   { cdfile = ptr;
  568.   }
  569.   if ((ptr = strrchr(cdfile, '/')))
  570.   { cdfile = ptr+1;
  571.   }
  572.   if ((ptr = strrchr(cdfile, '.')))
  573.   { len = ptr-cdfile;
  574.   }
  575.   else
  576.   { len = strlen(cdfile);
  577.   }
  578.   if (!(BaseName = malloc(len+1)))
  579.   { MemError();
  580.   }
  581.   strncpy(BaseName, cdfile, len);
  582.   BaseName[len] = '\0';
  583.  
  584.   while(!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  585.   { if (!(cdline = malloc(sizeof(*cdline))))
  586.     { MemError();
  587.     }
  588.     *cdptr = cdline;
  589.     cdptr = &cdline->Next;
  590.     cdline->Next = NULL;
  591.     cdline->Line = line = AllocString(newline);
  592.     free(newline);
  593.  
  594.     if (*line == ';')
  595.     { continue;
  596.     }
  597.     if (*line == '#')
  598.     { int CheckExtra = TRUE;
  599.  
  600.       if (strnicmp(line+1, "language", 8) == 0)
  601.       { char *ptr;
  602.  
  603.     line += 9;
  604.     OverSpace(&line);
  605.     Language = AllocString(line);
  606.     for (ptr = Language;  *ptr;  ptr++)
  607.     { *ptr = tolower((int) *ptr);
  608.     }
  609.     CheckExtra = FALSE;
  610.       }
  611.       else if (strnicmp(line+1, "version", 7) == 0)
  612.       { CatVersion = strtol(line+8, &line, 10);
  613.       }
  614.       else if (strnicmp(line+1, "lengthbytes", 11) == 0)
  615.       { line += 12;
  616.     if ((LengthBytes = strtol(line, &line, 10))
  617.              > sizeof(long))
  618.     { ShowWarn(GetFlexCatString(msgNoLengthBytes), sizeof(long));
  619.       LengthBytes = sizeof(long);
  620.     }
  621.       }
  622.       else if (strnicmp(line+1, "basename", 8) == 0)
  623.       { line += 9;
  624.     OverSpace(&line);
  625.     free(BaseName);
  626.     BaseName = AllocString(line);
  627.     CheckExtra = FALSE;
  628.       }
  629.       else
  630.       { ShowWarn(GetFlexCatString(msgUnknownCDCommand));
  631.     Result = FALSE;
  632.     CheckExtra = FALSE;
  633.       }
  634.       if (CheckExtra)
  635.       { OverSpace(&line);
  636.     if (*line)
  637.     { ShowWarn(GetFlexCatString(msgExtraCharacters));
  638.       Result = FALSE;
  639.     }
  640.       }
  641.     }
  642.     else
  643.     { char *idstr;
  644.  
  645.       if (*line == ' '  ||  *line == '\t')
  646.       { ShowWarn(GetFlexCatString(msgUnexpectedBlanks));
  647.     Result = FALSE;
  648.     OverSpace(&line);
  649.       }
  650.  
  651.       idstr = line;
  652.       while ((*line >= 'a'  &&  *line <= 'z')  ||
  653.          (*line >= 'A'  &&  *line <= 'Z')  ||
  654.          (*line >= '0'  &&  *line <= '9')  ||
  655.          *line == '_')
  656.       { ++line;
  657.       }
  658.  
  659.       if (idstr == line)
  660.       { ShowWarn(GetFlexCatString(msgNoIdentifier));
  661.     Result = FALSE;
  662.       }
  663.       else
  664.       { int found;
  665.  
  666.     if (!(cs = malloc(sizeof(*cs))))
  667.     { MemError();
  668.     }
  669.  
  670.     do
  671.     { struct CatString *scs;
  672.  
  673.       found = TRUE;
  674.       for (scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  675.       { if (scs->ID == NextID)
  676.         { found = FALSE;
  677.           ++NextID;
  678.           break;
  679.         }
  680.       }
  681.     }
  682.     while (!found);
  683.  
  684.     cs->Next = NULL;
  685.     cs->ID = NextID;
  686.     cs->MinLen = 0;
  687.     cs->MaxLen = -1;
  688.     cs->CD_Str = "";
  689.     cs->CT_Str = NULL;
  690.  
  691.     if (!(cs->ID_Str = malloc((line-idstr)+1)))
  692.     { MemError();
  693.     }
  694.     strncpy(cs->ID_Str, idstr, line-idstr);
  695.     cs->ID_Str[line-idstr] = '\0';
  696.  
  697.     OverSpace(&line);
  698.  
  699.     if (*line != '(')
  700.     { ShowWarn(GetFlexCatString(msgNoLeadingBracket));
  701.       Result = FALSE;
  702.     }
  703.     else
  704.     { char *oldstr;
  705.       struct CatString *scs;
  706.       char bytes[10];
  707.       int bytesread, reallen;
  708.  
  709.       ++line;
  710.       OverSpace(&line);
  711.       if (*line != '/')
  712.       {
  713.         cs->ID = NextID = strtol(line, &line, 10);
  714.         OverSpace(&line);
  715.       }
  716.  
  717.       for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  718.       { if (scs->ID == cs->ID)
  719.         { ShowWarn(GetFlexCatString(msgDoubleID));
  720.           Result = FALSE;
  721.         }
  722.         if (strcmp(cs->ID_Str, scs->ID_Str)  ==  0)
  723.         { ShowWarn(GetFlexCatString(msgDoubleIdentifier));
  724.           Result = FALSE;
  725.         }
  726.       }
  727.  
  728.       if (*line != '/')
  729.       { ShowWarn(GetFlexCatString(msgNoMinLen));
  730.         Result = FALSE;
  731.       }
  732.       else
  733.       { ++line;
  734.         OverSpace(&line);
  735.         if (*line != '/')
  736.         { cs->MinLen = strtol(line, &line, 10);
  737.           OverSpace(&line);
  738.         }
  739.         if (*line != '/')
  740.         { ShowWarn(GetFlexCatString(msgNoMaxLen));
  741.           Result = FALSE;
  742.         }
  743.         else
  744.         { ++line;
  745.           OverSpace(&line);
  746.           if (*line != ')')
  747.           { cs->MaxLen = strtol(line, &line, 10);
  748.         OverSpace(&line);
  749.           }
  750.           if (*line != ')')
  751.           { ShowWarn(GetFlexCatString(msgNoTrailingBracket));
  752.         Result = FALSE;
  753.           }
  754.           else
  755.           { ++line;
  756.         OverSpace(&line);
  757.         if (*line)
  758.         { ShowWarn(GetFlexCatString(msgExtraCharacters));
  759.         }
  760.           }
  761.         }
  762.       }
  763.     if (!(newline = ReadLine(fp, FALSE)))
  764.     { ShowWarn(GetFlexCatString(msgNoString));
  765.       Result = FALSE;
  766.       cs->CD_Str = "";
  767.     }
  768.     else
  769.     { cs->CD_Str = AllocString(newline);
  770.       free(newline);
  771.     }
  772.  
  773.     /*
  774.         Get stringlen
  775.     */
  776.     oldstr = cs->CD_Str;
  777.     reallen = 0;
  778.     while (*oldstr)
  779.     { bytesread = ReadChar(&oldstr, bytes);
  780.       if (bytesread == 2)
  781.       { bytesread--;
  782.       }
  783.       reallen += bytesread;
  784.     }
  785.  
  786.     if (cs->MinLen > 0  &&  reallen < cs->MinLen)
  787.     { ShowWarn(GetFlexCatString(msgShortString));
  788.     }
  789.     if (cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  790.     { ShowWarn(GetFlexCatString(msgLongString));
  791.     }
  792.  
  793.     cs->Nr = NumStrings;
  794.  
  795.     *csptr = cs;
  796.     csptr = &cs->Next;
  797.     ++NumStrings;
  798.     }
  799.       }
  800.     }
  801.   }
  802.   fclose(fp);
  803.   return(Result);
  804. }
  805.  
  806.  
  807.  
  808.  
  809. /*
  810.     This scans a catalog translation file.
  811.  
  812.     Inputs: ctfile    - name of the translation file to scan.
  813.  
  814.     Result: TRUE, if successfull, FALSE otherwise.
  815. */
  816. int ScanCTFile(char *ctfile)
  817.  
  818. { FILE *fp;
  819.   char *newline, *line, *idstr, *newidstr, *newstr;
  820.   struct CatString *cs;
  821.   int Result = TRUE;
  822.  
  823.   ScanFile = ctfile;
  824.   ScanLine = 0;
  825.  
  826.   if (!(fp = fopen(ctfile, "r")))
  827.   { ShowError(GetFlexCatString(msgNoCatalogTranslation), ctfile);
  828.   }
  829.  
  830.  
  831.   while (!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  832.   { switch(*line)
  833.     { case ';':
  834.     break;
  835.       case '#':
  836.     if (*(++line) != '#')
  837.     { ShowWarn(GetFlexCatString(msgNoCTCommand));
  838.     }
  839.     ++line;
  840.     OverSpace(&line);
  841.     if (strnicmp(line, "version", 7) == 0)
  842.     { line += 7;
  843.       OverSpace(&line);
  844.       CatVersionString = AllocString(line);
  845.     }
  846.     else if (strnicmp(line, "codeset", 7) == 0)
  847.     { line += 7;
  848.       CodeSet = strtol(line, &line, 10);
  849.       OverSpace(&line);
  850.       if (*line)
  851.       { ShowWarn(GetFlexCatString(msgExtraCharacters));
  852.       }
  853.     }
  854.     else if (strnicmp(line, "language", 8) == 0)
  855.     { char *ptr;
  856.  
  857.       line += 8;
  858.       OverSpace(&line);
  859.       CatLanguage = AllocString(line);
  860.       for (ptr = CatLanguage;  *ptr;  ptr++)
  861.       { *ptr = tolower((int) *ptr);
  862.       }
  863.     }
  864.     else
  865.     { ShowWarn(GetFlexCatString(msgUnknownCTCommand));
  866.     }
  867.     break;
  868.       default:
  869.     if (*line == ' '  ||  *line == '\t')
  870.     { ShowWarn(GetFlexCatString(msgUnexpectedBlanks));
  871.       OverSpace(&line);
  872.     }
  873.     idstr = line;
  874.     while ((*line >= 'a'  &&  *line <= 'z')  ||
  875.            (*line >= 'A'  &&  *line <= 'Z')  ||
  876.            (*line >= '0'  &&  *line <= '9')  ||
  877.            *line == '_')
  878.     { ++line;
  879.     }
  880.     if (idstr == line)
  881.     { ShowWarn(GetFlexCatString(msgNoIdentifier));
  882.       break;
  883.     }
  884.     if (!(newidstr = malloc(line-idstr+1)))
  885.     { MemError();
  886.     }
  887.     strncpy(newidstr, idstr, line-idstr);
  888.     newidstr[line-idstr] = '\0';
  889.     OverSpace(&line);
  890.     if (*line)
  891.     { ShowWarn(GetFlexCatString(msgExtraCharacters));
  892.     }
  893.     if ((newstr = ReadLine(fp, FALSE)))
  894.     { for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  895.       { if (strcmp(cs->ID_Str, newidstr) == 0)
  896.         { break;
  897.         }
  898.       }
  899.       if (cs == NULL)
  900.       { ShowWarn(GetFlexCatString(msgUnknownIdentifier), newidstr);
  901.       }
  902.       else
  903.       { char *oldstr;
  904.         char bytes[10];
  905.         int bytesread, reallen;
  906.  
  907.         if (cs->CT_Str)
  908.         { ShowWarn(GetFlexCatString(msgDoubleIdentifier));
  909.           Result = FALSE;
  910.           free (cs->CT_Str);
  911.         }
  912.         cs->CT_Str = AllocString(newstr);
  913.  
  914.         /*
  915.         Get stringlen
  916.         */
  917.         oldstr = cs->CT_Str;
  918.         reallen = 0;
  919.         while (*oldstr)
  920.         { bytesread = ReadChar(&oldstr, bytes);
  921.           if (bytesread == 2)
  922.           { bytesread--;
  923.           }
  924.           reallen += bytesread;
  925.         }
  926.  
  927.         if (cs->MinLen > 0  &&  reallen < cs->MinLen)
  928.         { ShowWarn(GetFlexCatString(msgShortString));
  929.         }
  930.         if (cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  931.         { ShowWarn(GetFlexCatString(msgLongString));
  932.         }
  933.       }
  934.       free(newstr);
  935.     }
  936.     else
  937.     { ShowWarn(GetFlexCatString(msgNoString));
  938.       cs->CT_Str = "";
  939.     }
  940.     free(newidstr);
  941.     }
  942.     free(newline);
  943.   }
  944.  
  945.   fclose(fp);
  946.   return(Result);
  947. }
  948. /*
  949.     CatPuts prints a string to a catalog. (The string is preceded by a
  950.     long integer containing its length and probably padded up to word
  951.     boundary or longword boundary, depending on the argument padbytes.)
  952.     The arguments countnul should be TRUE if the NUL byte at the end of
  953.     the string should be counted.
  954. */
  955. int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
  956.  
  957. { unsigned long reallen, virtuallen, chunklen;
  958.   int bytesread;
  959.   char *oldstr;
  960.   char bytes[10];
  961.  
  962.   /*
  963.       Get Length of string.
  964.   */
  965.   oldstr = str;
  966.   reallen = 0;
  967.   while (*oldstr)
  968.   { bytesread = ReadChar(&oldstr, bytes);
  969.     if (bytesread == 2)
  970.     { bytesread--;
  971.     }
  972.     reallen += bytesread;
  973.   }
  974.   virtuallen = chunklen = reallen + LengthBytes;
  975.   if (countnul  ||  chunklen % padbytes == 0)
  976.   { virtuallen++;
  977.   }
  978.  
  979.   fwrite(&virtuallen, sizeof(virtuallen), 1, fp);
  980.   if (LengthBytes)
  981.   { fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes,
  982.        LengthBytes, 1, fp);
  983.   }
  984.   while(*str)
  985.   { bytesread = ReadChar(&str, bytes);
  986.     if (bytesread)
  987.     { fwrite(bytes+bytesread-1, 1, 1, fp);
  988.     }
  989.   }
  990.  
  991.   do
  992.   { putc('\0', fp);
  993.   }
  994.   while(++chunklen % padbytes);
  995.  
  996.   return((int) chunklen+4);
  997. }
  998.  
  999.  
  1000.  
  1001.  
  1002. /*
  1003.     This creates a catalog.
  1004. */
  1005. void CreateCat(char *CatFile)
  1006.  
  1007. { FILE *fp;
  1008.   int CatLen, HeadLen;
  1009.   struct CatString *cs;
  1010.   int i;
  1011.  
  1012.   if (!CatVersionString)
  1013.   { ShowError(GetFlexCatString(msgNoCTVersion));
  1014.   }
  1015.   if (!CatLanguage)
  1016.   { ShowError(GetFlexCatString(msgNoCTLanguage));
  1017.   }
  1018.  
  1019.   if (!(fp = fopen(CatFile, "w")))
  1020.   { ShowError(GetFlexCatString(msgNoCatalog), CatFile);
  1021.   }
  1022.  
  1023.   fputs("FORM0000CTLGFVER", fp);
  1024.   CatLen = 8 + CatPuts(fp, CatVersionString, 2, TRUE);
  1025.   fputs("LANG", fp);
  1026.   CatLen += 4 + CatPuts(fp, CatLanguage, 2, TRUE);
  1027.   fputs("CSET", fp);
  1028.   i = 32;
  1029.   fwrite(&i, sizeof(i), 1, fp);
  1030.   while(i-- > 0)
  1031.   { putc('\0', fp);
  1032.   }
  1033.   CatLen += 48;
  1034.   fprintf(fp, "STRS0000");
  1035.   HeadLen = CatLen;
  1036.  
  1037.   for (cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1038.   { if (strcmp(cs->CT_Str, cs->CD_Str))
  1039.     { fwrite(&cs->ID, sizeof(cs->ID), 1, fp);
  1040.       CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
  1041.     }
  1042.   }
  1043.  
  1044.   fseek(fp, 4, SEEK_SET);
  1045.   fwrite(&CatLen, sizeof(CatLen), 1, fp);
  1046.   fseek(fp, HeadLen-4, SEEK_CUR);
  1047.   CatLen -= HeadLen;
  1048.   fwrite(&CatLen, sizeof(CatLen), 1, fp);
  1049.   fclose(fp);
  1050. }
  1051.  
  1052.  
  1053.  
  1054.  
  1055. /*
  1056.     This creates a new catalog translation file.
  1057. */
  1058. void CreateCTFile(char *NewCTFile)
  1059.  
  1060. { FILE *fp;
  1061.   struct CDLine *cd;
  1062.   struct CatString *cs;
  1063.   char *line;
  1064.  
  1065.   if (!(fp = fopen(NewCTFile, "w")))
  1066.   { ShowError(GetFlexCatString(msgNoNewCTFile));
  1067.   }
  1068.  
  1069.   fprintf(fp, "## version %s\n## language %s\n## codeset %d\n",
  1070.       CatVersionString, CatLanguage, CodeSet);
  1071.  
  1072.   for(cd = FirstCDLine, cs = FirstCatString;
  1073.       cd != NULL;
  1074.       cd = cd->Next)
  1075.   { switch(*cd->Line)
  1076.     { case '#':
  1077.     break;
  1078.       case ';':
  1079.     fprintf(fp, "%s\n", cd->Line);
  1080.     break;
  1081.       default:
  1082.     if(cs)
  1083.     { fprintf(fp, "%s\n", cs->ID_Str);
  1084.       fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
  1085.       putc(';', fp);
  1086.       for (line = cs->CD_Str;  *line;  ++line)
  1087.       { putc((int) *line, fp);
  1088.         if(*line == '\n')
  1089.         { putc(';', fp);
  1090.         }
  1091.       }
  1092.       putc('\n', fp);
  1093.       cs = cs->Next;
  1094.     }
  1095.     }
  1096.   }
  1097.  
  1098.   fclose(fp);
  1099. }
  1100.  
  1101.  
  1102.  
  1103.  
  1104. /*
  1105.     InitCatStringOutput gets called before writing a catalog string as
  1106.     source.
  1107.  
  1108.     Inputs: fp     = file pointer to the output file
  1109.         type = one of   TYPE_C        create C strings
  1110.                 TYPE_ASSEMBLER  create Assembler strings
  1111.                 TYPE_OBERON     create Oberon strings
  1112.                 TYPE_E        create E strings
  1113.                 TYPE_NONE        create simple strings
  1114. */
  1115. int OutputMode = OutputMode_None;
  1116. int OutputType = TYPE_C;
  1117. FILE *OutputFile;
  1118. int OutputLen;
  1119. void InitCatStringOutput(FILE *fp)
  1120.  
  1121. {
  1122.   OutputLen = 0;
  1123.   OutputFile = fp;
  1124.   OutputMode = OutputMode_None;
  1125.   switch(OutputType)
  1126.   { case TYPE_C:
  1127.     case TYPE_OBERON:
  1128.       putc('\"', fp);
  1129.       OutputMode = OutputMode_Ascii;
  1130.       break;
  1131.     case TYPE_E:
  1132.       putc('\'', fp);
  1133.     case TYPE_ASSEMBLER:
  1134.     case TYPE_NONE:
  1135.       break;
  1136.   }
  1137. }
  1138.  
  1139.  
  1140.  
  1141. /*
  1142.     SeparateCatStringOutput gets called to split a catalog into separate
  1143.     lines.
  1144. */
  1145. void SeparateCatStringOutput(void)
  1146.  
  1147. {
  1148.     switch(OutputType)
  1149.     { case TYPE_C:
  1150.     if (!LongStrings)
  1151.     { fputs("\"\\\n\t\"", OutputFile);
  1152.     }
  1153.     break;
  1154.       case TYPE_E:
  1155.     if (!LongStrings)
  1156.     { fputs("\' +\n\t\'", OutputFile);
  1157.     }
  1158.     break;
  1159.       case TYPE_OBERON:
  1160.     if (!LongStrings)
  1161.     { fputs("\"\n\t\"", OutputFile);
  1162.     }
  1163.     break;
  1164.       case TYPE_ASSEMBLER:
  1165.     if (!LongStrings)
  1166.     { if (OutputMode == OutputMode_Ascii)
  1167.       { putc('\'', OutputFile);
  1168.       }
  1169.       putc('\n', OutputFile);
  1170.       OutputMode = OutputMode_None;
  1171.     }
  1172.     break;
  1173.       case TYPE_NONE:
  1174.     break;
  1175.     }
  1176. }
  1177.  
  1178.  
  1179.  
  1180.  
  1181. /*
  1182.     WriteBinChar writes one binary character into the source file
  1183. */
  1184. void WriteBinChar(int c)
  1185.  
  1186. {
  1187.   switch(OutputType)
  1188.   { case TYPE_C:
  1189.     case TYPE_E:
  1190.     case TYPE_OBERON:
  1191.       switch(c)
  1192.       { case '\b':
  1193.       fputs("\\b", OutputFile);
  1194.       break;
  1195.     case '\n':
  1196.       fputs("\\n", OutputFile);
  1197.       break;
  1198.     case '\r':
  1199.       fputs("\\r", OutputFile);
  1200.       break;
  1201.     case '\t':
  1202.       fputs("\\t", OutputFile);
  1203.       break;
  1204.     case '\f':
  1205.       fputs("\\f", OutputFile);
  1206.       break;
  1207.     case '\0':
  1208.       fputs("\\0", OutputFile);
  1209.       break;
  1210.     default:
  1211.       fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
  1212.                   ((c >> 3) & 7) + '0', (c & 7) + '0');
  1213.       break;
  1214.       }
  1215.       ++OutputLen;
  1216.       OutputMode = OutputMode_Bin;
  1217.       break;
  1218.     case TYPE_ASSEMBLER:
  1219.       switch(OutputMode)
  1220.       { case OutputMode_None:
  1221.       fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
  1222.       break;
  1223.     case OutputMode_Ascii:
  1224.       putc('\'', OutputFile);
  1225.     case OutputMode_Bin:
  1226.       fprintf(OutputFile, ",$%02x", c & 0xff);
  1227.       break;
  1228.       }
  1229.       ++OutputLen;
  1230.       OutputMode = OutputMode_Bin;
  1231.       break;
  1232.     case TYPE_NONE:
  1233.       ShowWarn(GetFlexCatString(msgNoBinChars));
  1234.       break;
  1235.   }
  1236. }
  1237.  
  1238.  
  1239.  
  1240.  
  1241. /*
  1242.     WriteAsciiChar writes one ascii character into the source file.
  1243. */
  1244. void WriteAsciiChar(int c)
  1245.  
  1246. {
  1247.   switch(OutputType)
  1248.   { case TYPE_C:
  1249.     case TYPE_OBERON:
  1250.       switch(c)
  1251.       { case '\"':
  1252.       fputs("\\\"", OutputFile);
  1253.       break;
  1254.     default:
  1255.       putc(c, OutputFile);
  1256.       break;
  1257.       }
  1258.       ++OutputLen;
  1259.       OutputMode = OutputMode_Ascii;
  1260.       break;
  1261.     case TYPE_E:
  1262.       switch(c)
  1263.       { case '\'':
  1264.       fputs("''", OutputFile);
  1265.       break;
  1266.     default:
  1267.       putc(c, OutputFile);
  1268.       break;
  1269.       }
  1270.       ++OutputLen;
  1271.       OutputMode = OutputMode_Ascii;
  1272.       break;
  1273.     case TYPE_ASSEMBLER:
  1274.       if (c == '\'')
  1275.       { WriteBinChar(c);
  1276.       }
  1277.       else
  1278.       { switch (OutputMode)
  1279.     { case OutputMode_None:
  1280.         fprintf(OutputFile, "\tdc.b\t\'%c", c);
  1281.         break;
  1282.       case OutputMode_Ascii:
  1283.         putc(c, OutputFile);
  1284.         break;
  1285.       case OutputMode_Bin:
  1286.         fprintf(OutputFile, ",\'%c", c);
  1287.         break;
  1288.     }
  1289.     ++OutputLen;
  1290.     OutputMode = OutputMode_Ascii;
  1291.       }
  1292.       break;
  1293.     case TYPE_NONE:
  1294.       putc(c, OutputFile);
  1295.       break;
  1296.   }
  1297. }
  1298.  
  1299.  
  1300.  
  1301.  
  1302. /*
  1303.     TerminateCatStringOutput finishs the output of a catalog string.
  1304. */
  1305. void TerminateCatStringOutput(void)
  1306.  
  1307. {
  1308.   switch(OutputType)
  1309.   { case TYPE_C:
  1310.     case TYPE_OBERON:
  1311.       putc('\"', OutputFile);
  1312.       break;
  1313.     case TYPE_E:
  1314.       putc('\'', OutputFile);
  1315.       break;
  1316.     case TYPE_ASSEMBLER:
  1317.       switch(OutputMode)
  1318.       { case OutputMode_Ascii:
  1319.       putc('\'', OutputFile);
  1320.     case OutputMode_Bin:
  1321.       break;
  1322.     case OutputMode_None:
  1323.       break;
  1324.       }
  1325.     case TYPE_NONE:
  1326.       break;
  1327.   }
  1328. }
  1329.  
  1330.  
  1331.  
  1332.  
  1333. /*
  1334.     This writes a sourcestring.
  1335. */
  1336. void WriteString(FILE *fpout, char *str, long Len)
  1337.  
  1338. { char bytes[10];
  1339.   int bytesread;
  1340.   int needseparate = FALSE;
  1341.  
  1342.   InitCatStringOutput(fpout);
  1343.   if (Len >= 0)
  1344.   { int i;
  1345.  
  1346.     for(i = LengthBytes;  i >= 1;  i--)
  1347.     { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
  1348.     }
  1349.   }
  1350.  
  1351.   while (*str)
  1352.   { bytesread = ReadChar(&str, bytes);
  1353.     if (bytesread)
  1354.     { unsigned char c;
  1355.  
  1356.       if (needseparate)
  1357.       { SeparateCatStringOutput();
  1358.     needseparate = FALSE;
  1359.       }
  1360.  
  1361.       c = bytes[bytesread-1];
  1362.       if ((c >= 0x20  &&  c < 0x7f)  ||  c >= 0xa0)
  1363.       { WriteAsciiChar((int) c);
  1364.       }
  1365.       else
  1366.       { WriteBinChar((int) c);
  1367.       }
  1368.     }
  1369.     else
  1370.     { needseparate = TRUE;
  1371.     }
  1372.   }
  1373.   TerminateCatStringOutput();
  1374. }
  1375.  
  1376.  
  1377.  
  1378.  
  1379. /*
  1380.     Finally the source creation.
  1381. */
  1382. void CreateSourceFile(char *SourceFile, char *TemplateFile)
  1383.  
  1384. { FILE *fpin, *fpout;
  1385.   char *line;
  1386.  
  1387.   if (!(fpin = fopen(TemplateFile, "r")))
  1388.   { ShowError(GetFlexCatString(msgNoSourceDescription), TemplateFile);
  1389.   }
  1390.   if (!(fpout = fopen(SourceFile, "w")))
  1391.   { ShowError(GetFlexCatString(msgNoSource), SourceFile);
  1392.   }
  1393.  
  1394.   while(!feof(fpin)  &&  (line = ReadLine(fpin, FALSE)))
  1395.   { struct CatString *cs;
  1396.     int NeedRepeat;
  1397.     char bytes[10];
  1398.     int bytesread;
  1399.  
  1400.     cs = FirstCatString;
  1401.     do
  1402.     { char *currentline = line;
  1403.       NeedRepeat = FALSE;
  1404.  
  1405.       if (*currentline == '#'  &&  *(++currentline) == '#')
  1406.       { ++currentline;
  1407.     OverSpace(¤tline);
  1408.     if (strnicmp(currentline, "stringtype", 10) == 0)
  1409.     { currentline += 10;
  1410.       OverSpace(¤tline);
  1411.       if (strnicmp(currentline, "c", 1) == 0)
  1412.       { OutputType = TYPE_C;
  1413.         ++currentline;
  1414.       }
  1415.       else if (strnicmp(currentline, "assembler", 9) == 0)
  1416.       { OutputType = TYPE_ASSEMBLER;
  1417.         currentline += 9;
  1418.       }
  1419.       else if (strnicmp(currentline, "oberon", 6) == 0)
  1420.       { OutputType = TYPE_OBERON;
  1421.         currentline += 6;
  1422.       }
  1423.       else if (strnicmp(currentline, "e", 1)  ==  0)
  1424.       { OutputType = TYPE_E;
  1425.         ++currentline;
  1426.       }
  1427.       else if (strnicmp(currentline, "none", 4)  ==  0)
  1428.       { OutputType = TYPE_NONE;
  1429.         currentline += 4;
  1430.       }
  1431.       else
  1432.       { ShowWarn(GetFlexCatString(msgUnknownStringType));
  1433.         currentline += strlen(currentline);
  1434.       }
  1435.       OverSpace(¤tline);
  1436.       if (*currentline)
  1437.       { ShowWarn(GetFlexCatString(msgExtraCharacters));
  1438.       }
  1439.       continue;
  1440.     }
  1441.     else if (strnicmp(currentline, "shortstrings", 12) == 0)
  1442.     { currentline += 12;
  1443.       LongStrings = FALSE;
  1444.       OverSpace(¤tline);
  1445.       if (*currentline)
  1446.       { ShowWarn(GetFlexCatString(msgExtraCharacters));
  1447.       }
  1448.       continue;
  1449.     }
  1450.       }
  1451.  
  1452.       currentline = line;
  1453.       while(*currentline)
  1454.       { bytesread = ReadChar(¤tline, bytes);
  1455.     if (bytesread)
  1456.     { if (*bytes == '%')
  1457.       { switch(*(currentline++))
  1458.         { case 'b':
  1459.         fputs(BaseName, fpout);
  1460.         break;
  1461.           case 'n':
  1462.         fprintf(fpout, "%d", NumStrings);
  1463.         break;
  1464.           case 'v':
  1465.         fprintf(fpout, "%d", CatVersion);
  1466.         break;
  1467.           case 'l':
  1468.         WriteString(fpout, Language, -1);
  1469.         break;
  1470.           case 'i':
  1471.         NeedRepeat = TRUE;
  1472.         if (cs) fputs(cs->ID_Str, fpout);
  1473.         break;
  1474.           case 'd':
  1475.         NeedRepeat = TRUE;
  1476.         if (cs) fprintf(fpout, "%d", cs->ID);
  1477.         break;
  1478.           case 'e':
  1479.         NeedRepeat = TRUE;
  1480.         if (cs) fprintf(fpout, "%d", cs->Nr);
  1481.         break;
  1482.           case 's':
  1483.         NeedRepeat = TRUE;
  1484.         if (cs)
  1485.         { char *idstr;
  1486.           unsigned long len = 0;
  1487.  
  1488.           if (LengthBytes)
  1489.           { idstr = cs->CD_Str;
  1490.             while(*idstr)
  1491.             { bytesread = ReadChar(&idstr, bytes);
  1492.               if (bytesread)
  1493.               { ++len;
  1494.               }
  1495.             }
  1496.           }
  1497.           WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
  1498.         }
  1499.         break;
  1500.           case '(':
  1501.         NeedRepeat = TRUE;
  1502.         while(*currentline  &&  *currentline != ')')
  1503.         { bytesread = ReadChar(¤tline, bytes);
  1504.           if (bytesread  &&  cs  &&  cs->Next)
  1505.           { putc((int) bytes[bytesread-1], fpout);
  1506.           }
  1507.         }
  1508.         if (!*currentline)
  1509.         { ShowWarn(GetFlexCatString(msgNoTerminateBracket));
  1510.         }
  1511.         else
  1512.         { ++currentline;
  1513.         }
  1514.         break;
  1515.           default:
  1516.         { int c = *currentline++;
  1517.  
  1518.           putc(c, fpout);
  1519.         }
  1520.         }
  1521.       }
  1522.       else
  1523.       { putc((int) bytes[bytesread-1], fpout);
  1524.       }
  1525.     }
  1526.       }
  1527.       putc('\n', fpout);
  1528.     }
  1529.     while(NeedRepeat  &&  cs  &&  (cs = cs->Next));
  1530.  
  1531.     free(line);
  1532.   }
  1533.  
  1534.   fclose(fpin);
  1535.   fclose(fpout);
  1536. }
  1537.  
  1538.  
  1539.  
  1540.  
  1541. /*
  1542.     The Usage function describes the programs calling syntax.
  1543. */
  1544. void Usage(void)
  1545.  
  1546. {
  1547.   fputs((char *) GetFlexCatString(msgUsage), stderr);
  1548.   fprintf(stderr, "\n%s\n", VERSION+6);
  1549.   Cleanup(5);
  1550. }
  1551.  
  1552. /*
  1553.     Finally the main function. Does nothing special except for scanning
  1554.     the arguments.
  1555. */
  1556. void main (int argc, char *argv [])
  1557.  
  1558. { char *cdfile, *ctfile, *newctfile, *catalog;
  1559.   char *source, *template;
  1560.   int i;
  1561.  
  1562.   if (argc == 0)    /*  Aztec's entry point for workbench programs  */
  1563.   { exit(5);
  1564.   }
  1565.  
  1566. #ifdef AMIGA
  1567.   LocaleBase = OpenLibrary((STRPTR) "locale.library", 38);
  1568.   if (!(UtilityBase = OpenLibrary((STRPTR) "utility.library", 37)))
  1569.   { fprintf(stderr, "Need utility.library, V37.\n");
  1570.     exit(20);
  1571.   }
  1572.   OpenFlexCatCatalog(NULL, NULL);
  1573. #endif
  1574.  
  1575.   cdfile = ctfile = newctfile = catalog = NULL;
  1576.  
  1577.   if (argc == 1)
  1578.   { Usage();
  1579.   }
  1580.  
  1581.   for (i = 1;  i < argc;  i++)
  1582.   { if (strnicmp (argv[i], "catalog=", 8) == 0)
  1583.     { catalog = argv[i] + 8;
  1584.     }
  1585.     else if (stricmp (argv[i], "catalog") == 0)
  1586.     { if (i+1 == argc)
  1587.       { Usage();
  1588.       }
  1589.       catalog = argv[++i];
  1590.     }
  1591.     else if (strnicmp (argv[i], "newctfile=", 10) == 0)
  1592.     { newctfile = argv[i] + 10;
  1593.     }
  1594.     else if (strnicmp (argv[i], "newctfile", 10) == 0)
  1595.     { if (i+1 == argc)
  1596.       { Usage();
  1597.       }
  1598.       newctfile = argv[++i];
  1599.     }
  1600.     else if (cdfile == NULL)
  1601.     { if (stricmp(argv[i], "?") == 0  ||  stricmp(argv[i], "-h") == 0  ||
  1602.       stricmp(argv[i], "help") == 0)
  1603.       { Usage();
  1604.       }
  1605.       if (!ScanCDFile(cdfile = argv[i]))
  1606.       { Cleanup(10);
  1607.       }
  1608.     }
  1609.     else if (strchr(argv[i], '='))
  1610.     { source = AllocString(argv[i]);
  1611.       *(template = strchr(source, '=')) = '\0';
  1612.       ++template;
  1613.  
  1614.       CreateSourceFile(source, template);
  1615.     }
  1616.     else
  1617.     { if (ctfile)
  1618.       { Usage();
  1619.       }
  1620.       ctfile = argv[i];
  1621.     }
  1622.   }
  1623.  
  1624.   if (ctfile)
  1625.   { if(!ScanCTFile(ctfile))
  1626.     { Cleanup(10);
  1627.     }
  1628.   }
  1629.   if (catalog)
  1630.   { if (!ctfile)
  1631.     { fprintf(stderr, (char *) GetFlexCatString(msgNoCTArgument));
  1632.       Usage();
  1633.     }
  1634.     CreateCat(catalog);
  1635.   }
  1636.   if (newctfile)
  1637.   { CreateCTFile(newctfile);
  1638.   }
  1639.  
  1640.   Cleanup(0);
  1641. }
  1642.  
  1643.  
  1644.  
  1645.  
  1646. /*
  1647.     Dice's entry point for workbench programs
  1648. */
  1649. void wbmain(struct WBStartup *wbmsg)
  1650.  
  1651. { exit(5);
  1652. }
  1653.