home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / misc / flexcat / src / flexcat.c < prev    next >
C/C++ Source or Header  |  1994-12-12  |  40KB  |  1,934 lines

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