home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / dev / flexcat-1.2.lha / FlexCat / src / FlexCat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-19  |  32.9 KB  |  1,618 lines

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