home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / flexcat / flexcat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-27  |  64.1 KB  |  2,916 lines

  1.  
  2. /*****************************************************************
  3. **                                                              **
  4. ** If you use GoldED or any other text editor featuring folding **
  5. ** you may want to set up "///" as fold opening phrase, and     **
  6. ** "//|" as closing one, as this source is using it.            **
  7. **                                                              **
  8. **                                                Marcin        **
  9. **                                                              **
  10. *****************************************************************/
  11.  
  12. /* $Id: flexcat.c,v 1.2 1999/11/28 03:36:38 carlos Exp $ */
  13.  
  14.  
  15. #define __amigados
  16.  
  17. /// README
  18. /*
  19.  
  20.     FlexCat.c:  The flexible catalog creator
  21.  
  22.     This program is distributed in the hope that it will be useful,
  23.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  24.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  25.  
  26.     Ok, this is nothing special. It grabs a catalog translation and a
  27.     catalog description file and produces catalogs and the source to
  28.     handle them. What is it else than lots of other programs?
  29.  
  30.     The difference is, that YOU determine what source FlexCat produces.
  31.     Another file is scanned by FlexCat to produce code. This file contains
  32.     some c-string like special characters (%v for version for example)
  33.     You can edit this file and modify it as you want. So FlexCat can produce
  34.     C source as well as Assembler, Oberon, Modula 2, E, ...
  35.  
  36. */
  37. //|
  38.  
  39. #define VERSION 2
  40. #define REVISION 4
  41. #define VERS       "FlexCat 2.4"
  42.  
  43. #ifdef __amigados
  44.  
  45.  #ifdef _M68060
  46.    #define _CPU "[68060]"
  47.  #else
  48.    #ifdef _M68040
  49.      #define _CPU "[68040]"
  50.    #else
  51.      #ifdef _M68030
  52.        #define _CPU "[68030]"
  53.      #else
  54.        #ifdef _M68020
  55.          #define _CPU "[68020]"
  56.        #else
  57.          #ifdef _M68010
  58.            #define _CPU "[68010]"
  59.          #else
  60.            #define _CPU "[680x0]"
  61.          #endif
  62.        #endif
  63.      #endif
  64.    #endif
  65.  #endif
  66.  
  67. #define VSTRING  VERS " " _CPU " " __AMIGADATE__
  68. #else
  69. #define VSTRING  VERS
  70. #endif
  71.  
  72. #define VERSTAG  "$VER: " VSTRING
  73.  
  74. /// Includes and defines
  75.  
  76. #include <stdlib.h>
  77. #include <stdio.h>
  78. #include <string.h>
  79. #include <ctype.h>
  80. #include <time.h>
  81. #ifdef __amigados
  82.         #include <dos.h>
  83. #endif
  84. #include "flexcat_cat.h"
  85.  
  86. #if ((defined(_DCC) && defined(AMIGA))       ||     \
  87.      (defined(__SASC) && defined(_AMIGA)))      &&  \
  88.     !defined(__amigados)
  89. #define __amigados
  90. #endif
  91.  
  92. #if defined(__amigados)
  93. #include <exec/types.h>
  94. #if defined(_DCC) || defined(__SASC) || defined(__GNUC__)
  95. #include <proto/exec.h>
  96. #include <proto/dos.h>
  97. #include <proto/intuition.h>
  98. #include <proto/utility.h>
  99. #else
  100. #include <clib/exec_protos.h>
  101. #include <clib/dos_protos.h>
  102. #include <clib/utility_protos.h>
  103. #endif
  104.  
  105. #ifdef tolower
  106. #undef tolower
  107. #endif
  108. #define tolower         ToLower
  109. #define stricmp(s,t)    Stricmp((char *) (s), (char *) (t))
  110. #define strnicmp(s,t,l) Strnicmp((char *) (s), (char *) (t), l)
  111.  
  112. #endif
  113.  
  114.  
  115. #ifndef FALSE
  116. #define FALSE 0
  117. #endif
  118. #ifndef TRUE
  119. #define TRUE (!FALSE)
  120. #endif
  121.  
  122.  
  123. #define MAXPATHLEN 512
  124. #define FLEXCAT_SDDIR "FLEXCAT_SDDIR"
  125. #if defined(__amigados)
  126. #define DEFAULT_FLEXCAT_SDDIR "PROGDIR:lib"
  127. #else
  128. #define DEFAULT_FLEXCAT_SDDIR "lib"
  129. #endif
  130.  
  131. #if defined(__amigados)
  132. #define MAX_PREFS_LEN 512
  133. #define FLEXCAT_PREFS "flexcat.prefs"
  134. char    prefs_sddir[MAXPATHLEN] = "\0";
  135. #endif
  136.  
  137.  
  138. #ifndef MAKE_ID
  139. #define MAKE_ID(a,b,c,d)        \
  140.         ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  141. #endif
  142.  
  143. #ifndef ULONG
  144. #define ULONG unsigned long
  145. #endif
  146.  
  147. //|
  148. /// Structs
  149.  
  150. enum StringTypes {
  151.     TYPE_C,         /*  Produce C strings                   */
  152.     TYPE_ASSEMBLER, /*  Produce Assembler strings           */
  153.     TYPE_OBERON,    /*  Produce Oberon strings              */
  154.     TYPE_E,         /*  Produce E strings. (Oops, thought   */
  155.                     /*  it allows only 32 bit integers? ;-) */
  156.     TYPE_NONE       /*  Simple strings                      */
  157. };
  158.  
  159.  
  160. enum OutputModes {
  161.     OutputMode_None,    /*  Nothing written yet                 */
  162.     OutputMode_Bin,     /*  Last character written was binary   */
  163.     OutputMode_Ascii    /*  Last character written was Ascii    */
  164. };
  165.  
  166. struct CatString
  167. { struct CatString *Next;
  168.   char *CD_Str;
  169.   char *CT_Str;
  170.   char *ID_Str;
  171.   int MinLen, MaxLen, ID, Nr;
  172.   int NotInCT;          /* If string is not present we write NEW    */
  173.                         /* while updating CT file, for easier work. */
  174.  
  175. };
  176.  
  177. struct CDLine
  178. { struct CDLine *Next;
  179.   char *Line;
  180. };
  181.  
  182. struct CatalogChunk
  183. { struct CatalogChunk *Next;            /* struct CatalogChunk *Next */
  184.   ULONG ID;
  185.   char *ChunkStr;
  186. };
  187.  
  188. struct CatString *FirstCatString = NULL;  /*  First catalog string            */
  189. struct CDLine *FirstCDLine = NULL;        /*  First catalog description line  */
  190. struct CatalogChunk *FirstChunk = NULL;   /*  List of catalog chunks          */
  191.  
  192. char *BaseName   = "";              /*  Basename of catalog description */
  193. char *Language   = "english";       /*  Language of catalog description */
  194. int  CatVersion  = 0;               /*  Version of catalog to be opened */
  195. int  LengthBytes = 0;               /*  Number of bytes to preceed a    */
  196.                                     /*  created string and containing   */
  197.                                     /*  its length.                     */
  198. char *CatLanguage      = NULL;      /*  Language of catalog translation */
  199. char *CatVersionString = NULL;      /*  version string of catalog       */
  200.                                     /*  translation (## version)        */
  201. char *CatRcsId = NULL;              /*  rcs ID of catalog translation   */
  202.                                     /*  (## rcsid)                      */
  203. char *CatName = NULL;               /*  name of catalog translation     */
  204. int  CodeSet = 0;                   /*  Codeset of catalog translation  */
  205. int  NumStrings = 0;                /*  Number of catalog strings       */
  206. int  LongStrings = TRUE;            /*  Generate long or short strings  */
  207.  
  208. char *ScanFile;                     /*  File currently scanned          */
  209. int  ScanLine;                      /*  Line currently scanned          */
  210.  
  211. int  GlobalReturnCode = 0;          /*  Will be 5, if warnings appear    */
  212. int  WarnCTGaps = FALSE;            /*  Warn missing symbols in CT       */
  213.                                     /*  file.                            */
  214. int  NoOptim = FALSE;               /*  Put string into catalog even     */
  215.                                     /*  if translation is equal to       */
  216.                                     /*  description.                     */
  217. int  Fill    = FALSE;               /*  It translation of given string   */
  218.                                     /*  is missing or it's empty, write  */
  219.                                     /*  string descriptor from #?.cd     */
  220.                                     /*  file instead.                    */
  221. int  DoExpunge = FALSE;             /*  If TRUE FlexCat will do AVAIL    */
  222.                                     /*  FLUSH alike after catalog save   */
  223. int  NoBeep = FALSE;                /*  if TRUE, FlexCat won't call      */
  224.                                     /*  DisplayBeep() any longer         */
  225. int  Quiet   = FALSE;               /*  Forces FlexCat to shut up        */
  226.  
  227. int  NumberOfWarnings = 0;          /* We count warnings to be smart     */
  228.                                     /* and not to do Beep bombing, but   */
  229.                                     /* call DisplayBeep() only once      */
  230. int  CT_Scanned = FALSE;            /* If TRUE, and we are going to      */
  231.                                     /* write new #?.ct file, then user   */
  232.                                     /* surely updates own #?.ct file     */
  233.                                     /* so we should write ***NEW***      */
  234.                                     /* whenever necessary.               */
  235. int  LANGToLower = TRUE;            /* Shall we do ToLower() on lang's   */
  236.                                     /* name? Some #?.language seems to   */
  237.                                     /* be broken, so we allow workaround */
  238. int  NoBufferedIO = FALSE;          /* Shall we do buffered IO           */
  239. int  buffer_size = 2048;            /* Size of the IO buffer             */
  240. int  Modified = FALSE;              /* Shall we write the catalog ONLY   */
  241.                                     /* if #?.catalog is younger than     */
  242.                                     /* #?.c(d|t) files?                  */
  243.  
  244. #define MAX_NEW_STR_LEN 25
  245. char Msg_New[MAX_NEW_STR_LEN]    = "***NEW***";
  246.                                     /*  new strings in updated #?.ct    */
  247.  
  248. int  CopyNEWs = FALSE;
  249. char Old_Msg_New[MAX_NEW_STR_LEN] = "; ***NEW***";
  250.  
  251.                                     /*  old newstring (above) used in old   */
  252.                                     /* CT file. Now we look if it's present */
  253.                                     /* and copy it into new CT if user does */
  254.                                     /* upgrade (flexcat CD CT newctfile CT  */
  255.  
  256. int  NoSpace = FALSE;               /* do want to strip the space usually  */
  257.                                     /* placed between ';' and original     */
  258.                                     /* string?                             */
  259.  
  260.  
  261. char VersTag[] = VERSTAG;
  262. char VString[] = VSTRING " by Jochen Wiedmann and Marcin Orlowski";
  263. char EString[] = "E-mail: carlos@amiga.com.pl  WWW: http://amiga.com.pl/flexcat/";
  264. //|
  265.  
  266. /// FUNC: ReadPrefs
  267. #if defined(__amigados)
  268.  
  269. char ReadPrefs(void)
  270. {
  271. enum{ SDDIR,
  272.       MSG_NEW,
  273.       WARNCTGAPS,
  274.       NOOPTIM,
  275.       FILL,
  276.       FLUSH,
  277.       NOBEEP,
  278.       QUIET,
  279.       NOLANGTOLOWER,
  280.       NOBUFFEREDIO,
  281.       MODIFIED,
  282.       COPYMSGNEW,
  283.       OLDMSGNEW,
  284.       NOSPACE,
  285.  
  286.       ARGS_COUNT
  287.     };
  288.  
  289. char   template[] = "SDDIR/K,MSG_NEW/K,WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K,NOSPACE/S";
  290. LONG   Results[ARGS_COUNT] = {0};
  291. char   result = FALSE;
  292. char   *prefs;
  293. struct RDArgs *rda;
  294. struct RDArgs *rdargs;
  295.  
  296.   if(prefs = getenv(FLEXCAT_PREFS))
  297.     {
  298.     prefs = realloc(prefs, strlen(prefs)+1);
  299.     strcat(prefs, "\n");
  300.  
  301.     if(rda = AllocDosObject(DOS_RDARGS, TAG_DONE))
  302.        {
  303.        rda->RDA_Source.CS_Buffer = prefs;
  304.        rda->RDA_Source.CS_Length = strlen(prefs);
  305.        rda->RDA_Source.CS_CurChr = 0;
  306.        rda->RDA_Flags |= RDAF_NOPROMPT;
  307.  
  308.        if(rdargs = ReadArgs(template, Results, rda))
  309.          {
  310.          if(Results[SDDIR])
  311.            strncpy(prefs_sddir, (char *)Results[SDDIR], MAXPATHLEN);
  312.  
  313.          if(Results[MSG_NEW])
  314.            strncpy(Msg_New, (char *)Results[MSG_NEW], MAX_NEW_STR_LEN);
  315.  
  316.          WarnCTGaps   = Results[WARNCTGAPS];
  317.          NoOptim      = Results[NOOPTIM];
  318.          Fill         = Results[FILL];
  319.          DoExpunge    = Results[FLUSH];
  320.          NoBeep       = Results[NOBEEP];
  321.          Quiet        = Results[QUIET];
  322.          LANGToLower  = Results[NOLANGTOLOWER];
  323.          Modified     = Results[MODIFIED];
  324.          NoBufferedIO = Results[NOBUFFEREDIO];
  325.          CopyNEWs     = Results[COPYMSGNEW];
  326.          NoSpace      = Results[NOSPACE];
  327.          if(Results[OLDMSGNEW])
  328.            sprintf(Old_Msg_New, "; %s", (char *)Results[OLDMSGNEW]);
  329.  
  330.          FreeArgs(rdargs);
  331.  
  332.          result = TRUE;
  333.          }
  334.        else
  335.          {
  336.          fputs((char *)msgPrefsError, stderr);
  337.          fputs((char *)template, stderr);
  338.          fputs((char *)"\n", stderr);
  339.          DisplayBeep(NULL);
  340.          }
  341.  
  342.        FreeDosObject(DOS_RDARGS, rda);
  343.        }
  344.      else
  345.        {
  346.        fputs("Error processing prefs.\nCan't AllocDosObject()\n", stderr);
  347.        }
  348.  
  349.     free(prefs);
  350.     }
  351.  
  352.   return(result);
  353. }
  354.  
  355. #endif
  356. //|
  357.  
  358. /// FUNC: MyExit
  359. void MyExit (int Code)
  360. {
  361.  
  362. #if defined(__amigados)
  363.  
  364.   if(((NumberOfWarnings > 0) ||(Code !=0)) && (!NoBeep))
  365.      DisplayBeep(NULL);
  366.  
  367. #endif
  368.  
  369.  
  370. #if defined(_DCC)
  371.   //STATIC __autoexit VOID _STDCloseFlexCatCatalog(VOID)
  372. #elif defined(__SASC)
  373.   //VOID _STDCloseFlexCatCatalog(VOID)
  374. #elif defined(__GNUC__)
  375.   //STATIC VOID _STDCloseFlexCatCatalog(VOID)
  376. #else
  377.   CloseFlexCatCatalog();      /* we need to close something... */
  378. #endif
  379.  
  380.  
  381.     exit(Code);
  382. }
  383. //|
  384.  
  385. /// FUNC: stricmp
  386.  
  387. // quick stricmp
  388.  
  389. #ifndef __amigados
  390. int stricmp( char *str1, char *str2 )
  391. {
  392. int i;
  393.  
  394.     for(i = 0;; i++)
  395.        {
  396.        int a = tolower( (int)*str1 );
  397.        int b = tolower( (int)*str2 );
  398.  
  399.        if( !a || !b )
  400.            break;
  401.  
  402.        if( a != b )
  403.            return( 1 );
  404.  
  405.        str1++;
  406.        str2++;
  407.        }
  408.  
  409.     return( 0 );
  410. }
  411. #endif
  412.  
  413. //|
  414. /// FUNC: strnicmp
  415.  
  416. // quick strnicmp
  417.  
  418. #ifndef __amigados
  419. int strnicmp( char *str1, char *str2, int len )
  420. {
  421. int i;
  422.  
  423.     for(i = 0; i < len; i++)
  424.        {
  425.        int a = tolower( (int)*str1 );
  426.        int b = tolower( (int)*str2 );
  427.  
  428.        if( !a || !b )
  429.            break;
  430.  
  431.        if( a != b )
  432.            return( 1 );
  433.  
  434.        str1++;
  435.        str2++;
  436.        }
  437.  
  438.     return( 0 );
  439. }
  440. #endif
  441.  
  442. //|
  443.  
  444. /// FUNC: Swappers...
  445.  
  446.  
  447. unsigned short (*SwapWord)(unsigned short r) = NULL;
  448. unsigned long  (*SwapLong)(unsigned long r)  = NULL;
  449.  
  450.  
  451. unsigned short SwapWord21(unsigned short r)
  452. {
  453.     return (unsigned short)((r>>8) + (r<<8));
  454. }
  455. unsigned short SwapWord12(unsigned short r)
  456. {
  457.     return r;
  458. }
  459. unsigned long SwapLong4321(unsigned long r)
  460. {
  461.     return  ((r>>24) & 0xFF) + (r<<24) + ((r>>8) & 0xFF00) + ((r<<8) & 0xFF0000);
  462. }
  463. unsigned long SwapLong1234(unsigned long r)
  464. {
  465.     return r;
  466. }
  467.  
  468. //|
  469. /// FUNC: SwapChoose
  470. int SwapChoose(void)
  471. {
  472. unsigned short w;
  473. unsigned long  d;
  474.  
  475.   strncpy((char *)&w, "\1\2", 2);
  476.   strncpy((char *)&d, "\1\2\3\4", 4);
  477.  
  478.   if (w == 0x0201)
  479.     SwapWord = SwapWord21;
  480.   else if (w == 0x0102)
  481.     SwapWord = SwapWord12;
  482.   else
  483.     return 0;
  484.  
  485.   if (d == 0x04030201)
  486.     SwapLong = SwapLong4321;
  487.   else if (d == 0x01020304)
  488.     SwapLong = SwapLong1234;
  489.   else
  490.     return 0;
  491.  
  492.   return 1;
  493. }
  494. //|
  495.  
  496. /// FUNC: ShowError
  497.  
  498. /*
  499.     This shows an error message and terminates
  500. */
  501. void ShowError(const char *msg, ...)
  502. {
  503. char **ptr = (char **) &msg;
  504.  
  505. //  if(!Quiet)
  506.     {
  507.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  508.     putc('\n', stderr);
  509.     }
  510.  
  511. #if defined(__amigados)
  512.   NumberOfWarnings++;
  513. #endif
  514.  
  515.   MyExit(10);
  516. }
  517. //|
  518. /// FUNC: MemError
  519.  
  520. /*
  521.     This shows the message: Memory error.
  522. */
  523. void MemError(void)
  524.  
  525. {
  526.   ShowError(msgMemoryError, NULL);
  527. }
  528. //|
  529. /// FUNC: ShowWarn
  530.  
  531. /*
  532.     This shows a warning
  533. */
  534. void ShowWarn(const char *msg, ...)
  535.  
  536. { char **ptr = (char **) &msg;
  537.  
  538.   if(!Quiet)
  539.     {
  540.     fprintf(stderr, (char *) msgWarning, ScanFile, ScanLine);
  541.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  542.     putc('\n', stderr);
  543.     }
  544.  
  545.   NumberOfWarnings++;
  546.   GlobalReturnCode = 5;
  547. }
  548. //|
  549. /// FUNC: AllocString
  550.  
  551. /*
  552.     This allocates a string
  553. */
  554. char *AllocString(const char *str)
  555.  
  556. { char *ptr;
  557.  
  558.   if (!(ptr = malloc(strlen(str)+1)))
  559.   { MemError();
  560.   }
  561.   strcpy(ptr, str);
  562.   return(ptr);
  563. }
  564. //|
  565. /// FUNC: Add catalog chunk
  566.  
  567. /*
  568.     This adds a new catalog chunk to the list of catalog
  569.     chunks.
  570. */
  571. char *AddCatalogChunk(char *ID, const char *string)
  572. {
  573.   struct CatalogChunk *cc, **ccptr;
  574.  
  575.   if (!(cc = malloc(sizeof(*cc))))
  576.   { MemError();
  577.   }
  578.   cc->Next = NULL;
  579.   cc->ID = *((ULONG *) ID);
  580.   cc->ChunkStr = AllocString(string);
  581.  
  582.   /*
  583.       Put the new chunk to the end of the chunk list.
  584.   */
  585.   for (ccptr = &FirstChunk;  *ccptr != NULL;  ccptr = &(*ccptr)->Next)
  586.   {
  587.   }
  588.   *ccptr = cc;
  589.   return(cc->ChunkStr);
  590. }
  591. //|
  592. /// FUNC: gethex
  593. /*
  594.     This translates a hex character.
  595. */
  596. int gethex(int c)
  597. {
  598.   if (c >= '0'  &&  c <= '9')
  599.   { return(c - '0');
  600.   }
  601.   else if (c >= 'a'  &&  c <= 'f')
  602.   { return(c - 'a' + 10);
  603.   }
  604.   else if (c >= 'A'  &&  c <= 'F')
  605.   { return(c - 'A' + 10);
  606.   }
  607.   ShowWarn(msgExpectedHex);
  608.   return(0);
  609. }
  610. //|
  611. /// FUNC: getoctal
  612.  
  613. /*
  614.     This translates an octal digit.
  615. */
  616. int getoctal(int c)
  617. {
  618.  
  619.   if (c >= '0'  &&  c <= '7')
  620.     {
  621.     return(c - '0');
  622.     }
  623.  
  624.   ShowWarn(msgExpectedOctal);
  625.   return(0);
  626.  
  627. }
  628. //|
  629. /// FUNC: ReadLine
  630.  
  631. /*
  632.     Reading a line is somewhat complicated in order to allow lines of any
  633.     length.
  634.  
  635.     Inputs: fp           - the file, where the input comes from
  636.             AllowComment - TRUE, if a leading semicolon should force to
  637.                            interpret the line as a comment line
  638. */
  639. #define BUFSIZE 4096
  640. char *ReadLine(FILE *fp, int AllowComment)
  641. {
  642.  
  643.   char *OldLine, *NewLine = NULL;
  644.   int c = '\0';
  645.   int Len = 0, LineLen = 0;
  646.   int FirstChar = TRUE;
  647.   int BackslashSeen   = FALSE;
  648.   int BackslashSeenOn = 0;     /* position the last backslash was seen on */
  649.   int CommentLine = FALSE;     /* if TRUE we should ignore normally treat trailing \'s */
  650.  
  651.   while(c != EOF)
  652.     {
  653.     if(Len+10 > LineLen)
  654.       {
  655.       OldLine = NewLine;
  656.       if(!(NewLine = malloc(LineLen+BUFSIZE)))
  657.         MemError();
  658.  
  659.       strncpy(NewLine, OldLine, LineLen);
  660.       if(OldLine)
  661.         free(OldLine);
  662.  
  663.       LineLen += BUFSIZE;
  664.       }
  665.  
  666.     c = getc(fp);
  667.  
  668.     if(FirstChar)
  669.       {
  670.       if(c == EOF)
  671.         {
  672.         free(NewLine);
  673.         return(NULL);
  674.         }
  675.  
  676.       if(c == ';')
  677.         {
  678.         CommentLine = TRUE;
  679.         }
  680.  
  681.       FirstChar = FALSE;
  682.       }
  683.  
  684.     switch(c)
  685.       {
  686.       case '\r':
  687.         break;
  688.  
  689.       case '\n':
  690.         ++ScanLine;
  691.         if(BackslashSeen)
  692.           {
  693.           NewLine[Len++] = c;
  694.           BackslashSeen = FALSE;
  695.           break;
  696.           }
  697.         c = EOF;
  698.  
  699.       case EOF:
  700.         break;
  701.  
  702.                                  /*  Let's check for trailing \\ */
  703.       case '\\':
  704.         {
  705.         if(!CommentLine)
  706.           {
  707.           if(BackslashSeen)
  708.             {
  709.             if(BackslashSeenOn == (Len-1))
  710.               {
  711.               BackslashSeen = FALSE;
  712.               NewLine[Len++] = c;
  713.               break;
  714.               }
  715.             }
  716.  
  717.           BackslashSeen = TRUE;
  718.           BackslashSeenOn = Len;
  719.           }
  720.  
  721.         NewLine[Len++] = c;
  722.         break;
  723.         }
  724.  
  725.  
  726.       default:
  727.         BackslashSeen = FALSE;
  728.         NewLine[Len++] = c;
  729.       }
  730.     }
  731.  
  732.   NewLine[Len] = '\0';
  733.  
  734.   return(NewLine);
  735.  
  736. }
  737. //|
  738. /// FUNC: OverSpace
  739.  
  740. /*
  741.     This removes trailing blanks.
  742. */
  743. void OverSpace(char **strptr)
  744.  
  745. { int c;
  746.  
  747.   while ((c = **strptr) == ' '  ||  c == '\t')
  748.   { (*strptr)++;
  749.   }
  750. }
  751. //|
  752.  
  753. /// FUNC: Expunge
  754.  
  755. void Expunge(void)
  756. {
  757. #if defined(__amigados)
  758.  
  759.  
  760.   if(DoExpunge)
  761.     {
  762. #ifdef __EXPUNGE_ALL__
  763.     APTR Memory;
  764.  
  765.     if(Memory = AllocMem(-1, NULL))
  766.        FreeMem(Memory, -1);                // just in case ;-)
  767. #else
  768.  
  769. #pragma libcall LocaleBase localeExpunge 12 00
  770. VOID localeExpunge(VOID);
  771.  
  772.     struct Library    *LocaleBase;
  773.  
  774.     if(LocaleBase = OpenLibrary("locale.library", 0))
  775.        {
  776.        localeExpunge();
  777.        CloseLibrary(LocaleBase);
  778.        }
  779.  
  780. #endif
  781.     }
  782. #endif
  783.  
  784. }
  785.  
  786. //|
  787.  
  788. /// FUNC: ReadChar
  789.  
  790. /*
  791.     ReadChar scans an input line translating the backslash characters.
  792.  
  793.     Inputs: char *  - a pointer to a stringpointer; the latter points to the
  794.                       next character to be read and points behind the read
  795.                       bytes after executing ReadChar
  796.             dest    - a pointer to a buffer, where the read bytes should be
  797.                       stored
  798.  
  799.     Result: number of bytes that are written to dest (between 0 and 2)
  800. */
  801. int ReadChar(char **strptr, char *dest)
  802. {
  803.   char c;
  804.   int i;
  805.  
  806.   switch(c = *((*strptr)++))
  807.     {
  808.     case '\\':
  809.  
  810.       switch(c = tolower((int) *((*strptr)++)))
  811.         {
  812.         case '\n':
  813.           return(0);
  814.         case 'b':
  815.           *dest = '\b';
  816.           break;
  817.         case 'c':
  818.           *dest = '\233';
  819.           break;
  820.         case 'e':
  821.           *dest = '\033';
  822.           break;
  823.         case 'f':
  824.           *dest = '\f';
  825.           break;
  826.         case 'g':
  827.           *dest = '\007';
  828.           break;
  829.         case 'n':
  830.           *dest = '\n';
  831.           break;
  832.         case 'r':
  833.           *dest = '\r';
  834.           break;
  835.         case 't':
  836.           *dest = '\t';
  837.           break;
  838.         case 'v':
  839.           *dest = '\013';
  840.           break;
  841.         case 'x':
  842.           *dest = gethex((int) **strptr);
  843.           (*strptr)++;
  844.           if (((c = **strptr) >= '0'  &&  c <= '9')  ||
  845.               (c >= 'a'  &&  c <= 'f')  ||  (c >= 'A'  &&  c <= 'F'))
  846.           { *dest = (*dest << 4) + gethex((int) c);
  847.             (*strptr)++;
  848.           }
  849.           break;
  850.         case '0':
  851.         case '1':
  852.         case '2':
  853.         case '3':
  854.         case '4':
  855.         case '5':
  856.         case '6':
  857.         case '7':
  858.  
  859.           *dest = getoctal((int)c);
  860.  
  861.           for(i = 0;  i < 2;  i++)
  862.             {
  863.             if((c = **strptr) >= '0'  &&  c <= '7')
  864.               {
  865.               *dest = (*dest << 3) + getoctal((int) c);
  866.               (*strptr)++;
  867.               }
  868.             }
  869.           break;
  870.         case ')':
  871.         case '\\':
  872.           *(dest++) = '\\';
  873.           *dest = c;
  874.           return(2);
  875.         default:
  876.           *dest = c;
  877.       }
  878.       break;
  879.  
  880.     default:
  881.       *dest = c;
  882.   }
  883.   return(1);
  884. }
  885. //|
  886. /// FUNC: ScanCDFile
  887.  
  888. /*
  889.     This scans the catalog description file.
  890.  
  891.     Inputs: cdfile  - name of the catalog description file
  892.  
  893.     Result: TRUE, if successful, FALSE otherwise
  894. */
  895. int ScanCDFile(char *cdfile)
  896. {
  897.   FILE *fp;
  898.   struct CDLine *cdline, **cdptr = &FirstCDLine;
  899.   struct CatString *cs, **csptr = &FirstCatString;
  900.   char *line, *newline;
  901.   char *ptr;
  902.   int NextID = 0, len;
  903.   int Result = TRUE;
  904.  
  905.   ScanFile = cdfile;
  906.   ScanLine = 0;
  907.  
  908.   if(!(fp = fopen(cdfile, "r")))
  909.     {
  910.     ShowError(msgNoCatalogDescription, cdfile);
  911.     }
  912.  
  913.   if(!NoBufferedIO)
  914.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  915.  
  916.   /*
  917.       Get the basename
  918.   */
  919.   if ((ptr = strchr(cdfile, ':')))
  920.   { cdfile = ptr+1;
  921.   }
  922.   if ((ptr = strrchr(cdfile, '/')))
  923.   { cdfile = ptr+1;
  924.   }
  925.   if ((ptr = strrchr(cdfile, '.')))
  926.   { len = ptr-cdfile;
  927.   }
  928.   else
  929.   { len = strlen(cdfile);
  930.   }
  931.   if (!(BaseName = malloc(len+1)))
  932.   { MemError();
  933.   }
  934.   strncpy(BaseName, cdfile, len);
  935.   BaseName[len] = '\0';
  936.  
  937.   while(!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  938.   {
  939.     if(!(cdline = malloc(sizeof(*cdline))))
  940.       {
  941.       MemError();
  942.       }
  943.  
  944.     *cdptr = cdline;
  945.     cdptr = &cdline->Next;
  946.     cdline->Next = NULL;
  947.     cdline->Line = line = AllocString(newline);
  948.     free(newline);
  949.  
  950.     if (*line == ';')
  951.       {
  952.       continue;
  953.       }
  954.  
  955.     if(*line == '#')
  956.       {
  957.       int CheckExtra = TRUE;
  958.  
  959.       if (strnicmp(line+1, "language", 8) == 0)
  960.         {
  961.         char *ptr;
  962.  
  963.         line += 9;
  964.         OverSpace(&line);
  965.         Language = AllocString(line);
  966.  
  967.         if(LANGToLower)
  968.            {
  969.            for (ptr = Language;  *ptr;  ptr++)
  970.              {
  971.              *ptr = tolower((int) *ptr);
  972.              }
  973.            CheckExtra = FALSE;
  974.            }
  975.  
  976.         }
  977.       else
  978.         if(strnicmp(line+1, "version", 7) == 0)
  979.           {
  980.           CatVersion = strtol(line+8, &line, 0);
  981.           }
  982.         else
  983.           {
  984.           if(strnicmp(line+1, "basename", 8) == 0)
  985.            {
  986.            line += 9;
  987.            OverSpace(&line);
  988.            free(BaseName);
  989.            BaseName = AllocString(line);
  990.            CheckExtra = FALSE;
  991.            }
  992.           else
  993.            {
  994.            ShowWarn(msgUnknownCDCommand);
  995.            Result = FALSE;
  996.            CheckExtra = FALSE;
  997.            }
  998.          }
  999.  
  1000.       if(CheckExtra)
  1001.         {
  1002.         OverSpace(&line);
  1003.           if(*line)
  1004.             {
  1005.             ShowWarn(msgExtraCharacters);
  1006.             Result = FALSE;
  1007.             }
  1008.         }
  1009.       }
  1010.     else
  1011.       {
  1012.       char *idstr;
  1013.  
  1014.       if(*line == ' '  ||  *line == '\t')
  1015.         {
  1016.         ShowWarn(msgUnexpectedBlanks);
  1017.         Result = FALSE;
  1018.         OverSpace(&line);
  1019.         }
  1020.  
  1021.       idstr = line;
  1022.       while ((*line >= 'a'  &&  *line <= 'z')  ||
  1023.              (*line >= 'A'  &&  *line <= 'Z')  ||
  1024.              (*line >= '0'  &&  *line <= '9')  ||
  1025.              *line == '_')
  1026.         {
  1027.         ++line;
  1028.         }
  1029.  
  1030.       if(idstr == line)
  1031.         {
  1032.         ShowWarn(msgNoIdentifier);
  1033.         Result = FALSE;
  1034.         }
  1035.       else
  1036.         {
  1037.         int found;
  1038.  
  1039.         if(!(cs = malloc(sizeof(*cs))))
  1040.           {
  1041.           MemError();
  1042.           }
  1043.  
  1044.         do
  1045.           {
  1046.           struct CatString *scs;
  1047.  
  1048.           found = TRUE;
  1049.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  1050.             {
  1051.             if(scs->ID == NextID)
  1052.               {
  1053.               found = FALSE;
  1054.               ++NextID;
  1055.               break;
  1056.               }
  1057.             }
  1058.           }
  1059.         while(!found);
  1060.  
  1061.         cs->Next = NULL;
  1062.         cs->ID = NextID;
  1063.         cs->MinLen = 0;
  1064.         cs->MaxLen = -1;
  1065.         cs->CD_Str = "";
  1066.         cs->CT_Str = NULL;
  1067.         cs->NotInCT= TRUE;
  1068.  
  1069.         if(!(cs->ID_Str = malloc((line-idstr)+1)))
  1070.           {
  1071.           MemError();
  1072.           }
  1073.         strncpy(cs->ID_Str, idstr, line-idstr);
  1074.         cs->ID_Str[line-idstr] = '\0';
  1075.  
  1076.         OverSpace(&line);
  1077.  
  1078.         if(*line != '(')
  1079.           {
  1080.           ShowWarn(msgNoLeadingBracket);
  1081.           Result = FALSE;
  1082.           }
  1083.         else
  1084.           {
  1085.           char *oldstr;
  1086.           struct CatString *scs;
  1087.           char bytes[10];
  1088.           int bytesread, reallen;
  1089.  
  1090.           ++line;
  1091.           OverSpace(&line);
  1092.           if(*line != '/')
  1093.             {
  1094.             if(*line == '+')
  1095.               {
  1096.               NextID = cs->ID = NextID + strtol(line, &line, 0);
  1097.               }
  1098.             else
  1099.               {
  1100.               cs->ID = NextID = strtol(line, &line, 0);
  1101.               }
  1102.  
  1103.             OverSpace(&line);
  1104.             }
  1105.  
  1106.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  1107.           { if (scs->ID == cs->ID)
  1108.             { ShowWarn(msgDoubleID);
  1109.               Result = FALSE;
  1110.             }
  1111.             if (strcmp(cs->ID_Str, scs->ID_Str)  ==  0)
  1112.             { ShowWarn(msgDoubleIdentifier);
  1113.               Result = FALSE;
  1114.             }
  1115.           }
  1116.  
  1117.           if (*line != '/')
  1118.           { ShowWarn(msgNoMinLen);
  1119.             Result = FALSE;
  1120.           }
  1121.           else
  1122.           { ++line;
  1123.             OverSpace(&line);
  1124.             if (*line != '/')
  1125.             { cs->MinLen = strtol(line, &line, 0);
  1126.               OverSpace(&line);
  1127.             }
  1128.             if (*line != '/')
  1129.             { ShowWarn(msgNoMaxLen);
  1130.               Result = FALSE;
  1131.             }
  1132.             else
  1133.             { ++line;
  1134.               OverSpace(&line);
  1135.               if (*line != ')')
  1136.               { cs->MaxLen = strtol(line, &line, 0);
  1137.                 OverSpace(&line);
  1138.               }
  1139.               if (*line != ')')
  1140.               { ShowWarn(msgNoTrailingBracket);
  1141.                 Result = FALSE;
  1142.               }
  1143.               else
  1144.               { ++line;
  1145.                 OverSpace(&line);
  1146.                 if (*line)
  1147.                 { ShowWarn(msgExtraCharacters);
  1148.                 }
  1149.               }
  1150.             }
  1151.           }
  1152.         if (!(newline = ReadLine(fp, FALSE)))
  1153.         { ShowWarn(msgNoString);
  1154.           Result = FALSE;
  1155.           cs->CD_Str = "";
  1156.         }
  1157.         else
  1158.         { cs->CD_Str = AllocString(newline);
  1159.           free(newline);
  1160.         }
  1161.  
  1162.         /*
  1163.             Get stringlen
  1164.         */
  1165.         oldstr = cs->CD_Str;
  1166.         reallen = 0;
  1167.         while (*oldstr)
  1168.         { bytesread = ReadChar(&oldstr, bytes);
  1169.           if (bytesread == 2)
  1170.           { bytesread--;
  1171.           }
  1172.           reallen += bytesread;
  1173.         }
  1174.  
  1175.         if (cs->MinLen > 0  &&  reallen < cs->MinLen)
  1176.         { ShowWarn(msgShortString);
  1177.         }
  1178.         if (cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1179.         { ShowWarn(msgLongString);
  1180.         }
  1181.  
  1182.         cs->Nr = NumStrings;
  1183.  
  1184.         *csptr = cs;
  1185.         csptr = &cs->Next;
  1186.         ++NumStrings;
  1187.         }
  1188.       }
  1189.     }
  1190.   }
  1191.   fclose(fp);
  1192.   return(Result);
  1193. }
  1194. //|
  1195. /// FUNC: ScanCTFile
  1196.  
  1197. /*
  1198.     This scans a catalog translation file.
  1199.  
  1200.     Inputs: ctfile      - name of the translation file to scan.
  1201.  
  1202.     Result: TRUE, if successful, FALSE otherwise.
  1203. */
  1204. int ScanCTFile(char *ctfile)
  1205. {
  1206.   FILE *fp;
  1207.   char *newline, *line, *idstr, *newidstr, *newstr;
  1208.   struct CatString *cs=NULL;
  1209.   int Result = TRUE;
  1210.  
  1211.   ScanFile = ctfile;
  1212.   ScanLine = 0;
  1213.  
  1214.   if (!(fp = fopen(ctfile, "r")))
  1215.     {
  1216.     ShowError(msgNoCatalogTranslation, ctfile);
  1217.     }
  1218.  
  1219.   if(!NoBufferedIO)
  1220.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1221.  
  1222.  
  1223.   while (!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  1224.     {
  1225.     switch(*line)
  1226.       {
  1227.       case ';':
  1228.         if( CopyNEWs == TRUE )
  1229.            {
  1230.            if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
  1231.              {
  1232.              cs->NotInCT = TRUE;
  1233.              }
  1234.            }
  1235.       break;
  1236.  
  1237.       case '#':
  1238. ///       looking for command;
  1239.         if(*(++line) != '#')
  1240.           {
  1241.           ShowWarn(msgNoCTCommand);
  1242.           }
  1243.         ++line;
  1244.         OverSpace(&line);
  1245.         if (strnicmp(line, "version", 7) == 0)
  1246.         { if (CatVersionString || CatRcsId || CatName)
  1247.           { ShowWarn(msgDoubleCTVersion);
  1248.           }
  1249.           line += 7;
  1250.           OverSpace(&line);
  1251.           CatVersionString = AllocString(line);
  1252.         }
  1253.         else if (strnicmp(line, "codeset", 7) == 0)
  1254.         { line += 7;
  1255.           CodeSet = strtol(line, &line, 0);
  1256.           OverSpace(&line);
  1257.           if (*line)
  1258.           { ShowWarn(msgExtraCharacters);
  1259.           }
  1260.         }
  1261.         else if (strnicmp(line, "language", 8) == 0)
  1262.         { char *ptr;
  1263.  
  1264.           if (CatLanguage)
  1265.           { ShowWarn(msgDoubleCTLanguage);
  1266.           }
  1267.           line += 8;
  1268.           OverSpace(&line);
  1269.           CatLanguage = AddCatalogChunk("LANG", line);
  1270.  
  1271.           if(LANGToLower)
  1272.             for (ptr = CatLanguage;  *ptr;  ptr++)
  1273.               *ptr = tolower((int) *ptr);
  1274.         }
  1275.         else if (strnicmp(line, "chunk", 5) == 0)
  1276.         { char *ID;
  1277.  
  1278.           line += 5;
  1279.           OverSpace(&line);
  1280.           ID = line;
  1281.           line += sizeof(ULONG);
  1282.           OverSpace(&line);
  1283.  
  1284.           AddCatalogChunk(ID, AllocString(line));
  1285.         }
  1286.         else if (strnicmp(line, "rcsid", 5) == 0)
  1287.         { if (CatVersionString || CatRcsId)
  1288.           { ShowWarn(msgDoubleCTVersion);
  1289.           }
  1290.           line += 5;
  1291.           OverSpace(&line);
  1292.           CatRcsId = AllocString(line);
  1293.         }
  1294.         else if (strnicmp(line, "name", 5) == 0)
  1295.         { if (CatVersionString || CatName)
  1296.           { ShowWarn(msgDoubleCTVersion);
  1297.           }
  1298.           line += 4;
  1299.           OverSpace(&line);
  1300.           CatName = AllocString(line);
  1301.         }
  1302.         else if (strnicmp(line+1, "lengthbytes", 11) == 0)
  1303.         { line += 12;
  1304.           if ((LengthBytes = strtol(line, &line, 0))
  1305.                            > sizeof(long))
  1306.           { ShowWarn(msgNoLengthBytes, sizeof(long));
  1307.             LengthBytes = sizeof(long);
  1308.           }
  1309.         }
  1310.         else
  1311.         {
  1312.         ShowWarn(msgUnknownCTCommand);
  1313.         }
  1314. //|
  1315.         break;
  1316.  
  1317.       default:
  1318.         if(*line == ' '  ||  *line == '\t')
  1319.           {
  1320.           ShowWarn( msgUnexpectedBlanks );
  1321.           OverSpace( &line );
  1322.           }
  1323.         idstr = line;
  1324.  
  1325.         while ((*line >= 'a'  &&  *line <= 'z')  ||
  1326.                (*line >= 'A'  &&  *line <= 'Z')  ||
  1327.                (*line >= '0'  &&  *line <= '9')  ||
  1328.                *line == '_')
  1329.         { ++line;
  1330.         }
  1331.         if (idstr == line)
  1332.           {
  1333.           ShowWarn(msgNoIdentifier);
  1334.           break;
  1335.           }
  1336.  
  1337.         if(!(newidstr = malloc(line-idstr+1)))
  1338.           {
  1339.           MemError();
  1340.           }
  1341.  
  1342.         strncpy(newidstr, idstr, line-idstr);
  1343.         newidstr[line-idstr] = '\0';
  1344.         OverSpace(&line);
  1345.  
  1346.         if(*line)
  1347.           {
  1348.           ShowWarn(msgExtraCharacters);
  1349.           }
  1350.  
  1351.         if((newstr = ReadLine(fp, FALSE)))
  1352.           {
  1353.           for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1354.             {
  1355.             if(strcmp(cs->ID_Str, newidstr) == 0)
  1356.               {
  1357.               break;
  1358.               }
  1359.             }
  1360.           if(cs == NULL)
  1361.             {
  1362.             ShowWarn(msgUnknownIdentifier, newidstr);
  1363.             }
  1364.           else
  1365.             {
  1366.             char *oldstr;
  1367.             char bytes[10];
  1368.             int bytesread, reallen;
  1369.  
  1370.             if(cs->CT_Str)
  1371.               {
  1372.               ShowWarn(msgDoubleIdentifier);
  1373.               Result = FALSE;
  1374.               free(cs->CT_Str);
  1375.               }
  1376.             cs->CT_Str = AllocString(newstr);
  1377.             cs->NotInCT = FALSE;
  1378.  
  1379.             /*
  1380.                 Get stringlen
  1381.             */
  1382.             oldstr = cs->CT_Str;
  1383.             reallen = 0;
  1384.             while(*oldstr)
  1385.               {
  1386.               bytesread = ReadChar(&oldstr, bytes);
  1387.               if(bytesread == 2)
  1388.                 {
  1389.                 bytesread--;
  1390.                 }
  1391.               reallen += bytesread;
  1392.               }
  1393.  
  1394.             if(cs->MinLen > 0  &&  reallen < cs->MinLen)
  1395.               {
  1396.               ShowWarn(msgShortString);
  1397.               }
  1398.             if(cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1399.               {
  1400.               ShowWarn(msgLongString);
  1401.               }
  1402.  
  1403.  
  1404.             // checking for trailing ellipsis...
  1405.  
  1406.             if( reallen >= 3 )
  1407.                {
  1408.                long cd_len = strlen( cs->CD_Str );
  1409.  
  1410.                if( cd_len >= 3 )
  1411.                    {
  1412.                    if( strcmp( &cs->CD_Str[ cd_len - 2 ], "..." ) == 0 )
  1413.                        if( strcmp( &cs->CT_Str[ reallen - 2 ], "..." ) != 0 )
  1414.                          {
  1415. //                         printf("ORG: '%s'\nNEW: '%s'\n", cs->CD_Str, cs->CT_Str);
  1416.                          ShowWarn(msgTrailingEllipsis);
  1417.                          }
  1418.                    }
  1419.                }    
  1420.  
  1421.  
  1422.             // checking for trailing spaces
  1423.  
  1424.             if( reallen >= 1 )
  1425.                {
  1426.                long cd_len = strlen( cs->CD_Str );
  1427.  
  1428.                if( cd_len >= 1 )
  1429.                    {
  1430.                    if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
  1431.                        if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
  1432.                          ShowWarn(msgTrailingSpaces);
  1433.                    }
  1434.                }
  1435.  
  1436.  
  1437.             }
  1438.           free(newstr);
  1439.           }
  1440.         else
  1441.           {
  1442.           ShowWarn(msgNoString);
  1443.           if(cs)
  1444.               cs->CT_Str = "";
  1445.           }
  1446.         free(newidstr);
  1447.     }
  1448.     free(newline);
  1449.   }
  1450.  
  1451.   fclose(fp);
  1452.  
  1453.   if (WarnCTGaps)
  1454.   { for (cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1455.     { if (cs->CT_Str == NULL)
  1456.       { ShowWarn(msgCTGap, cs->ID_Str);
  1457.       }
  1458.     }
  1459.   }
  1460.  
  1461.   if(Result)
  1462.     CT_Scanned = TRUE;
  1463.  
  1464.   return(Result);
  1465. }
  1466. //|
  1467. /// FUNC: CatPuts
  1468.  
  1469.  
  1470. /*
  1471.     CatPuts prints a string to a catalog. (The string is preceded by a
  1472.     long integer containing its length and probably padded up to word
  1473.     boundary or longword boundary, depending on the argument padbytes.)
  1474.     The arguments countnul should be TRUE if the NUL byte at the end of
  1475.     the string should be counted.
  1476. */
  1477. int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
  1478. {
  1479.   unsigned long reallen, virtuallen, chunklen, swapped_long;
  1480.   int bytesread;
  1481.   char *oldstr;
  1482.   char bytes[10];
  1483.  
  1484.   /*      Get Length of string.
  1485.   */
  1486.  
  1487.   oldstr = str;
  1488.   reallen = 0;
  1489.  
  1490.   while(*oldstr)
  1491.     {
  1492.     bytesread = ReadChar(&oldstr, bytes);
  1493.     if(bytesread == 2)
  1494.       {
  1495.       bytesread--;
  1496.       }
  1497.     reallen += bytesread;
  1498.     }
  1499.  
  1500.   virtuallen = chunklen = reallen + LengthBytes;
  1501.   if(countnul || chunklen % padbytes == 0)
  1502.     {
  1503.     virtuallen++;
  1504.     }
  1505.  
  1506.   swapped_long = SwapLong( virtuallen );
  1507.  
  1508.   fwrite(&swapped_long, sizeof(virtuallen), 1, fp);
  1509.   if(LengthBytes)
  1510.     {
  1511.     fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
  1512.     }
  1513.  
  1514.   while(*str)
  1515.     {
  1516.     bytesread = ReadChar(&str, bytes);
  1517.     if(bytesread)
  1518.       {
  1519.       fwrite(bytes+bytesread-1, 1, 1, fp);
  1520.       }
  1521.     }
  1522.  
  1523.   do
  1524.     {
  1525.     putc('\0', fp);
  1526.     }
  1527.   while(++chunklen % padbytes);
  1528.  
  1529.   return((int) chunklen+4);
  1530. }
  1531. //|
  1532. /// FUNC: PutCatalogChunk
  1533.  
  1534. /*
  1535.     This puts a string chunk into the catalog
  1536. */
  1537. int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
  1538. {
  1539.   fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
  1540.   return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
  1541. }
  1542. //|
  1543. /// FUNC: CalcRealLength
  1544. /*
  1545.     This function measures the real (binary) length of source
  1546.     string. It correctly process 'slash chars' (\n, \000 etc),
  1547.     and gives the real length such source string have.
  1548.  
  1549.     Inputs: source - pointer to null terminated source string
  1550.  
  1551.     Result: real length
  1552. */
  1553.  
  1554. int CalcRealLength(char *source)
  1555. {
  1556. int  count = 0;
  1557. char *src = source;
  1558. char bytes[10];
  1559.  
  1560.   while(*src)
  1561.     {
  1562.     count += ReadChar(&src, bytes);
  1563.     }
  1564.  
  1565. //  printf("%ld: '%s'\n", count, source);
  1566.  
  1567.   return(count);
  1568.  
  1569. }
  1570. //|
  1571.  
  1572. /// FUNC: CreateCatalog
  1573.  
  1574. /*
  1575.     This creates a catalog.
  1576. */
  1577. void CreateCat(char *CatFile)
  1578. {
  1579.   FILE *fp;
  1580.   int CatLen, HeadLen;
  1581.   struct CatString *cs;
  1582.   struct CatalogChunk *cc;
  1583.   int i;
  1584.  
  1585.   if(!CatVersionString && !CatRcsId)
  1586.     {
  1587.     ShowError(msgNoCTVersion);
  1588.     }
  1589.  
  1590.   if(!CatLanguage)
  1591.     {
  1592.     ShowError(msgNoCTLanguage);
  1593.     }
  1594.  
  1595.   if(strlen(CatLanguage) == 0)
  1596.     {
  1597.     ShowError(msgNoCTLanguage);
  1598.     }
  1599.  
  1600.   if(!(fp = fopen(CatFile, "w")))
  1601.     {
  1602.     ShowError(msgNoCatalog, CatFile);
  1603.     }
  1604.  
  1605.   if(!NoBufferedIO)
  1606.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1607.  
  1608.  
  1609.   fputs("FORM0000CTLG", fp);
  1610.   CatLen = 4;
  1611.  
  1612.   if(CatVersionString)
  1613.     {
  1614.     struct CatalogChunk cc;
  1615.     char *verStr = NULL;
  1616.  
  1617.     cc.ID = MAKE_ID('F','V','E','R');
  1618.  
  1619.     if( strstr(CatVersionString, "$TODAY") )
  1620.        {
  1621.  
  1622.        if(verStr = malloc(strlen(CatVersionString)+128))
  1623.            {
  1624.            char *found = strstr(CatVersionString, "$TODAY");
  1625.            char dateStr[10];
  1626.  
  1627.            long tim;
  1628.            struct tm *t;
  1629.  
  1630.            time(&tim);
  1631.            t = gmtime(&tim);
  1632.  
  1633.            *found = 0;
  1634.            strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
  1635.  
  1636.            sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
  1637.            cc.ChunkStr = verStr;
  1638.            }
  1639.        else
  1640.           MemError();
  1641.  
  1642.        }
  1643.     else
  1644.        {
  1645.        cc.ChunkStr = CatVersionString;
  1646.        }
  1647.  
  1648.     cc.ID = SwapLong( cc.ID );
  1649.     CatLen += PutCatalogChunk(fp, &cc);
  1650.  
  1651.     if( verStr )
  1652.        free(verStr);
  1653.     }
  1654.   else
  1655.     {
  1656.     struct CatalogChunk cc;
  1657.     char* verStr;
  1658.     int year = 0, month = 0, day = 0;
  1659.     int version = 0, revision = 0;
  1660.     char* name = NULL;
  1661.     char* ptr;
  1662.  
  1663.     if(!CatRcsId)
  1664.       {
  1665.       ShowError(msgNoCTVersion);
  1666.       }
  1667.     else
  1668.       {
  1669.       if(!(ptr = strstr(CatRcsId, "$Date:"))
  1670.           || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
  1671.           || !(ptr = strstr(CatRcsId, "$Revision:"))
  1672.           || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
  1673.       {
  1674.       ShowError(msgWrongRcsId);
  1675.       }
  1676.       if ((ptr = strstr(CatRcsId, "$Id:")))
  1677.       { int len = 0;
  1678.         char* found;
  1679.  
  1680.         ptr += 4;
  1681.         OverSpace(&ptr);
  1682.         found = ptr;
  1683.  
  1684.         while(*ptr  &&  *ptr != '$'  &&  *ptr != ' '  &&  *ptr != '\t')
  1685.           {
  1686.           ++len;
  1687.           ++ptr;
  1688.           }
  1689.         if(!(name = malloc(len+1)))
  1690.           {
  1691.           MemError();
  1692.          }
  1693.         strncpy(name, found, len);
  1694.         name[len] = '\0';
  1695.       }
  1696.     }
  1697.     if (CatName)
  1698.     { name = CatName;
  1699.     }
  1700.     else if (!name)
  1701.       {
  1702.       ShowError(msgNoCTVersion);
  1703.       name = "";
  1704.       }
  1705.     if (!(verStr = malloc(strlen(name) + 256)))
  1706.       {
  1707.       MemError();
  1708.       }
  1709.  
  1710.     sprintf(verStr, "$V");
  1711.     sprintf(verStr, "ER: %s %ld.%ld (%ld.%ld.%ld)", name, version, revision, day, month, year);
  1712.  
  1713.     cc.ID = MAKE_ID('F','V','E','R');
  1714.     cc.ID = SwapLong( cc.ID );
  1715.     cc.ChunkStr = verStr;
  1716.     CatLen += PutCatalogChunk(fp, &cc);
  1717.   }
  1718.  
  1719.  
  1720.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1721.     {
  1722.     CatLen += PutCatalogChunk(fp, cc);
  1723.     }
  1724.  
  1725.   i = 32;
  1726.   fputs("CSET", fp);
  1727.  
  1728.   {
  1729.   int i_tmp = SwapLong( i );
  1730.  
  1731.   fwrite(&i_tmp, sizeof(i_tmp), 1, fp);
  1732.   }
  1733.  
  1734.   while(i-- > 0)
  1735.     {
  1736.     putc('\0', fp);
  1737.     }
  1738.  
  1739.   CatLen += 48;
  1740.   fprintf(fp, "STRS0000");
  1741.   HeadLen = CatLen;
  1742.  
  1743.  
  1744.   for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1745.     {
  1746.     int FillUsed = FALSE;
  1747.     int tmp_ID = SwapLong( cs->ID );
  1748.  
  1749.     if(Fill)
  1750.       {
  1751.  
  1752.       if(cs->CT_Str)
  1753.         {
  1754.         if(strlen(cs->CT_Str) == 0)
  1755.           {
  1756.           fwrite(&tmp_ID, sizeof(tmp_ID), 1, fp);
  1757.           CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1758.           FillUsed = TRUE;
  1759.           }
  1760.         }
  1761.       else
  1762.         {
  1763.         fwrite(&tmp_ID, sizeof(cs->ID), 1, fp);
  1764.         CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1765.         FillUsed = TRUE;
  1766.         }
  1767.       }
  1768.  
  1769.     if((!FillUsed) && cs->CT_Str  &&  (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
  1770.       {
  1771.       fwrite(&tmp_ID, sizeof( tmp_ID ), 1, fp);
  1772.       CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
  1773.       }
  1774.     }
  1775.  
  1776.  
  1777.   {
  1778.   int tmp_Len;
  1779.  
  1780.   fseek(fp, 4, SEEK_SET);
  1781.  
  1782.   tmp_Len = SwapLong( CatLen );
  1783.   fwrite(&tmp_Len, sizeof(tmp_Len), 1, fp);
  1784.   fseek(fp, HeadLen-4, SEEK_CUR);
  1785.  
  1786.   CatLen -= HeadLen;
  1787.   tmp_Len = SwapLong( CatLen );
  1788.   fwrite(&tmp_Len, sizeof(CatLen), 1, fp);
  1789.   }
  1790.  
  1791.   fclose(fp);
  1792.  
  1793.   Expunge();
  1794.  
  1795. }
  1796. //|
  1797. /// FUNC: CreateCTFile
  1798.  
  1799. /*
  1800.     This creates a new catalog translation file.
  1801. */
  1802. void CreateCTFile(char *NewCTFile)
  1803. {
  1804.   FILE   *fp;
  1805.   struct CDLine *cd;
  1806.   struct CatString *cs;
  1807.   struct CatalogChunk *cc;
  1808.   char   *line;
  1809.  
  1810.   if(!CatVersionString && !CatRcsId)
  1811.     {
  1812.     ScanLine = 1;
  1813.     ShowWarn(msgNoCTVersion);
  1814.     }
  1815.  
  1816.   if(!(fp = fopen(NewCTFile, "w")))
  1817.     {
  1818.     ShowError(msgNoNewCTFile);
  1819.     }
  1820.  
  1821.  
  1822.   if(!NoBufferedIO)
  1823.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1824.  
  1825.  
  1826.   if(CatRcsId)
  1827.     {
  1828.     fprintf(fp, "## rcsid %s\n",
  1829.           CatRcsId ? CatRcsId : "");
  1830.     if(CatName)
  1831.        fprintf(fp, "## name %s\n", CatName);
  1832.     }
  1833.   else
  1834.     {
  1835.     if(CatVersionString)
  1836.       fprintf(fp, "## version %s\n", CatVersionString);
  1837.     else
  1838.       {
  1839.       fprintf(fp, "## version $V");
  1840.       fprintf(fp, "%c", 50+19);  // E
  1841.       fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
  1842.       }
  1843.     }
  1844.  
  1845.  
  1846.   {
  1847.   char *lang = NULL;
  1848.  
  1849.   if(CatLanguage == NULL)
  1850.     if(lang = getenv("ENV:language"))
  1851.       {
  1852.       int i;
  1853.  
  1854.       for(i=0;i<strlen(lang); i++)
  1855.         if(lang[i] == '\n')
  1856.           {
  1857.           lang[i] = 0;
  1858.           break;
  1859.           }
  1860.  
  1861.       CatLanguage = lang;
  1862.       }
  1863.  
  1864.   fprintf(fp, "## language %s\n## codeset %d\n;\n",
  1865.        CatLanguage ? CatLanguage : "X", CodeSet);
  1866.  
  1867.   if(lang)
  1868.     {
  1869.     free(lang);
  1870.     CatLanguage = NULL;
  1871.     }
  1872.   }
  1873.  
  1874.  
  1875.  
  1876.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1877.     {
  1878.     if (cc->ChunkStr != CatLanguage)
  1879.       {
  1880.       fprintf(fp, "## chunk ");
  1881.       fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
  1882.       fprintf(fp, " %s\n", cc->ChunkStr);
  1883.       }
  1884.     }
  1885.  
  1886.   for(cd = FirstCDLine, cs = FirstCatString;
  1887.       cd != NULL;
  1888.       cd = cd->Next)
  1889.      {
  1890.      switch(*cd->Line)
  1891.        {
  1892.        case '#':
  1893.           break;
  1894.  
  1895.        case ';':
  1896.           fprintf(fp, "%s\n", cd->Line);
  1897.           break;
  1898.  
  1899.        default:
  1900.           if(cs)
  1901.             {
  1902. /*
  1903.             fprintf(fp, "%s\n", cs->ID_Str);
  1904.             fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
  1905.             putc(';', fp);
  1906.             putc(' ', fp);
  1907. */
  1908.             fprintf(fp, "%s\n%s\n;", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
  1909.  
  1910.             if( !NoSpace )
  1911.                 putc(' ', fp);
  1912.  
  1913.  
  1914.  
  1915.             for (line = cs->CD_Str;  *line;  ++line)
  1916.               {
  1917.               putc((int) *line, fp);
  1918.               if(*line == '\n')
  1919.                 {
  1920.                 putc(';', fp);
  1921.                 if( !NoSpace )
  1922.                    putc(' ', fp);
  1923.                 }
  1924.               }
  1925.             putc('\n', fp);
  1926.  
  1927.             if(cs->NotInCT && CT_Scanned)
  1928.               fprintf(fp, ";\n; %s\n", Msg_New);
  1929.  
  1930.             cs = cs->Next;
  1931.             }
  1932.        }
  1933.      }
  1934.  
  1935.   fclose(fp);
  1936. }
  1937. //|
  1938.  
  1939. /// FUNC: InitCatStringOutput
  1940.  
  1941. /*
  1942.     InitCatStringOutput gets called before writing a catalog string as
  1943.     source.
  1944.  
  1945.     Inputs: fp   = file pointer to the output file
  1946.             type = one of   TYPE_C          create C strings
  1947.                             TYPE_ASSEMBLER  create Assembler strings
  1948.                             TYPE_OBERON     create Oberon strings
  1949.                             TYPE_E          create E strings
  1950.                             TYPE_NONE       create simple strings
  1951. */
  1952. int  OutputMode = OutputMode_None;
  1953. int  OutputType = TYPE_C;
  1954. FILE *OutputFile;
  1955. int  OutputLen;
  1956.  
  1957. void InitCatStringOutput(FILE *fp)
  1958. {
  1959.   OutputLen = 0;
  1960.   OutputFile = fp;
  1961.   OutputMode = OutputMode_None;
  1962.   switch(OutputType)
  1963.   { case TYPE_C:
  1964.     case TYPE_OBERON:
  1965.       putc('\"', fp);
  1966.       OutputMode = OutputMode_Ascii;
  1967.       break;
  1968.     case TYPE_E:
  1969.       putc('\'', fp);
  1970.     case TYPE_ASSEMBLER:
  1971.     case TYPE_NONE:
  1972.       break;
  1973.   }
  1974. }
  1975. //|
  1976. /// FUNC: SeparateCatStringOutput
  1977.  
  1978. /*
  1979.     SeparateCatStringOutput gets called to split a catalog into separate
  1980.     lines.
  1981. */
  1982. void SeparateCatStringOutput(void)
  1983. {
  1984.     switch(OutputType)
  1985.     { case TYPE_C:
  1986.         if (!LongStrings)
  1987.         { fputs("\"\\\n\t\"", OutputFile);
  1988.         }
  1989.         break;
  1990.       case TYPE_E:
  1991.         if (!LongStrings)
  1992.         { fputs("\' +\n\t\'", OutputFile);
  1993.         }
  1994.         break;
  1995.       case TYPE_OBERON:
  1996.         if (!LongStrings)
  1997.         { fputs("\"\n\t\"", OutputFile);
  1998.         }
  1999.         break;
  2000.       case TYPE_ASSEMBLER:
  2001.         if (!LongStrings)
  2002.         { if (OutputMode == OutputMode_Ascii)
  2003.           { putc('\'', OutputFile);
  2004.           }
  2005.           putc('\n', OutputFile);
  2006.           OutputMode = OutputMode_None;
  2007.         }
  2008.         break;
  2009.       case TYPE_NONE:
  2010.         break;
  2011.     }
  2012. }
  2013. //|
  2014. /// FUNC: WriteBinChar
  2015.  
  2016. /*
  2017.     WriteBinChar writes one binary character into the source file
  2018. */
  2019. void WriteBinChar(int c)
  2020. {
  2021.  
  2022.   switch(OutputType)
  2023.   { case TYPE_C:
  2024.     case TYPE_E:
  2025.     case TYPE_OBERON:
  2026.       switch(c)
  2027.       { case '\b':
  2028.           fputs("\\b", OutputFile);
  2029.           break;
  2030.         case '\n':
  2031.           fputs("\\n", OutputFile);
  2032.           break;
  2033.         case '\r':
  2034.           fputs("\\r", OutputFile);
  2035.           break;
  2036.         case '\t':
  2037.           fputs("\\t", OutputFile);
  2038.           break;
  2039.         case '\f':
  2040.           fputs("\\f", OutputFile);
  2041.           break;
  2042.         case '\0':
  2043.           fputs("\\000", OutputFile);
  2044.           break;
  2045.         default:
  2046.           if(OutputType == TYPE_E  &&  c == '\033')
  2047.             {
  2048.             fputs("\\e", OutputFile);
  2049.             }
  2050.           else
  2051.            {
  2052.            fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
  2053.                     ((c >> 3) & 7) + '0', (c & 7) + '0');
  2054.            }
  2055.           break;
  2056.       }
  2057.       ++OutputLen;
  2058.       OutputMode = OutputMode_Bin;
  2059.       break;
  2060.     case TYPE_ASSEMBLER:
  2061.       switch(OutputMode)
  2062.       { case OutputMode_None:
  2063.           fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
  2064.           break;
  2065.         case OutputMode_Ascii:
  2066.           putc('\'', OutputFile);
  2067.         case OutputMode_Bin:
  2068.           fprintf(OutputFile, ",$%02x", c & 0xff);
  2069.           break;
  2070.       }
  2071.       ++OutputLen;
  2072.       OutputMode = OutputMode_Bin;
  2073.       break;
  2074.     case TYPE_NONE:
  2075.       ShowWarn(msgNoBinChars);
  2076.       break;
  2077.   }
  2078. }
  2079. //|
  2080. /// FUNC: WriteAsciiChar
  2081.  
  2082. /*
  2083.     WriteAsciiChar writes one ascii character into the source file.
  2084. */
  2085. void WriteAsciiChar(int c)
  2086. {
  2087.  
  2088.   switch(OutputType)
  2089.   { case TYPE_C:
  2090.     case TYPE_OBERON:
  2091.       switch(c)
  2092.       { case '\"':
  2093.           fputs("\\\"", OutputFile);
  2094.           break;
  2095.         default:
  2096.           putc(c, OutputFile);
  2097.           break;
  2098.       }
  2099.       ++OutputLen;
  2100.       OutputMode = OutputMode_Ascii;
  2101.       break;
  2102.     case TYPE_E:
  2103.       switch(c)
  2104.       { case '\'':
  2105.           fputs("''", OutputFile);
  2106.           break;
  2107.         default:
  2108.           putc(c, OutputFile);
  2109.           break;
  2110.       }
  2111.       ++OutputLen;
  2112.       OutputMode = OutputMode_Ascii;
  2113.       break;
  2114.     case TYPE_ASSEMBLER:
  2115.       if (c == '\'')
  2116.       { WriteBinChar(c);
  2117.       }
  2118.       else
  2119.       { switch (OutputMode)
  2120.         { case OutputMode_None:
  2121.             fprintf(OutputFile, "\tdc.b\t\'%c", c);
  2122.             break;
  2123.           case OutputMode_Ascii:
  2124.             putc(c, OutputFile);
  2125.             break;
  2126.           case OutputMode_Bin:
  2127.             fprintf(OutputFile, ",\'%c", c);
  2128.             break;
  2129.         }
  2130.         ++OutputLen;
  2131.         OutputMode = OutputMode_Ascii;
  2132.       }
  2133.       break;
  2134.     case TYPE_NONE:
  2135.       putc(c, OutputFile);
  2136.       break;
  2137.   }
  2138. }
  2139. //|
  2140. /// FUNC: TerminateCatStringOutput
  2141.  
  2142. /*
  2143.     TerminateCatStringOutput finishs the output of a catalog string.
  2144. */
  2145. void TerminateCatStringOutput(void)
  2146. {
  2147.   switch(OutputType)
  2148.   { case TYPE_C:
  2149.     case TYPE_OBERON:
  2150.       putc('\"', OutputFile);
  2151.       break;
  2152.     case TYPE_E:
  2153.       putc('\'', OutputFile);
  2154.       break;
  2155.     case TYPE_ASSEMBLER:
  2156.       switch(OutputMode)
  2157.       { case OutputMode_Ascii:
  2158.           putc('\'', OutputFile);
  2159.         case OutputMode_Bin:
  2160.           break;
  2161.         case OutputMode_None:
  2162.           break;
  2163.       }
  2164.     case TYPE_NONE:
  2165.       break;
  2166.   }
  2167. }
  2168. //|
  2169.  
  2170. /// FUNC: WriteString
  2171. /*
  2172.     This writes a sourcestring.
  2173. */
  2174. void WriteString(FILE *fpout, char *str, long Len)
  2175. {
  2176.   char bytes[10];
  2177.   int bytesread;
  2178.   int needseparate = FALSE;
  2179.  
  2180.   InitCatStringOutput(fpout);
  2181.   if (Len >= 0)
  2182.   { int i;
  2183.  
  2184.     for(i = LengthBytes;  i >= 1;  i--)
  2185.     { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
  2186.     }
  2187.   }
  2188.  
  2189.   while (*str)
  2190.   { bytesread = ReadChar(&str, bytes);
  2191.     if (bytesread)
  2192.     { unsigned char c;
  2193.  
  2194.       if (needseparate)
  2195.       { SeparateCatStringOutput();
  2196.         needseparate = FALSE;
  2197.       }
  2198.  
  2199.       c = bytes[bytesread-1];
  2200.       if ((c >= 0x20  &&  c < 0x7f)  ||  c >= 0xa0)
  2201.       { WriteAsciiChar((int) c);
  2202.       }
  2203.       else
  2204.       { WriteBinChar((int) c);
  2205.       }
  2206.     }
  2207.     else
  2208.     { needseparate = TRUE;
  2209.     }
  2210.   }
  2211.   TerminateCatStringOutput();
  2212. }
  2213. //|
  2214. /// FUNC: AllocFileName
  2215. /*
  2216.     This function creates a copy of a filename, removes an
  2217.     optional ending and pathname components, if desired.
  2218.  
  2219.     Inputs: filename - the filename to copy
  2220.             howto - a set of bits
  2221.                         bit 0: 1 = remove ending, 0 = leave it
  2222.                         bit 1: 1 = remove pathname, 0 = leave it
  2223.  
  2224.     Result: The copy of the filename
  2225. */
  2226. char *AllocFileName(char *filename, int howto)
  2227. {
  2228.   char *tempstr, *ptr;
  2229.  
  2230.   if (!(tempstr = strdup(filename)))
  2231.   { MemError();
  2232.     MyExit(10);
  2233.   }
  2234.  
  2235.   /*  Remove pathname components, if desired    */
  2236.   if (howto & 2)
  2237.   { if ((ptr = strchr(tempstr, ':')))
  2238.     { tempstr = ptr+1;
  2239.     }
  2240.     if ((ptr = strrchr(tempstr, '/')))
  2241.     { tempstr = ptr+1;
  2242.     }
  2243.   }
  2244.  
  2245.   /*  Remove ending, if desired.                */
  2246.   if (howto & 1)
  2247.   { if ((ptr = strrchr(tempstr, '.')))
  2248.     { *ptr = '\0';
  2249.     }
  2250.   }
  2251.  
  2252.   return(tempstr);
  2253. }
  2254. //|
  2255. /// FUNC: AddFileName
  2256. /*
  2257.     This function adds a pathname and a filename to a full
  2258.     filename.
  2259.  
  2260.     Inputs: pathname - the leading pathname
  2261.             filename - the filename
  2262.  
  2263.     Result: The new filename
  2264. */
  2265. char *AddFileName(char *pathname, char *filename)
  2266. {
  2267.   char *buffer;
  2268.   int size = strlen(pathname) + strlen(filename) + 2;
  2269.  
  2270.   if (!(buffer = malloc(size)))
  2271.   { MemError();
  2272.     MyExit(10);
  2273.   }
  2274.  
  2275. #if defined(__amigados)
  2276.   strcpy(buffer, pathname);
  2277.   AddPart((char *) buffer, (char *) filename, size);
  2278. #else
  2279.   sprintf(buffer, "%s/%s", pathname, filename);
  2280. #endif
  2281.  
  2282.   return(buffer);
  2283. }
  2284. //|
  2285.  
  2286. /// FUNC: CreateSourceFile
  2287.  
  2288. /*
  2289.     Finally the source creation.
  2290. */
  2291. void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
  2292. {
  2293.  
  2294.   FILE *fpin, *fpout;
  2295.   char *line;
  2296.   char *OrigTemplateFile = TemplateFile;
  2297.  
  2298.   ScanFile = SourceFile;
  2299.   ScanLine = 0;
  2300.  
  2301.   /*
  2302.     Open the source file. This may be found in various places
  2303.   */
  2304.   if(!(fpin = fopen(TemplateFile, "r")))
  2305.     {
  2306. #ifdef __amigados
  2307.     if(*prefs_sddir != 0)
  2308.       {
  2309.       TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
  2310.       fpin = fopen(TemplateFile, "r");
  2311.       }
  2312. #endif
  2313.     }
  2314.  
  2315.   if(!fpin)
  2316.     {
  2317.     char *sddir;
  2318.  
  2319.     if((sddir = getenv(FLEXCAT_SDDIR)))
  2320.       {
  2321.       TemplateFile = AddFileName(sddir, OrigTemplateFile);
  2322.       fpin = fopen(TemplateFile, "r");
  2323.       }
  2324.     }
  2325.  
  2326.   if (!fpin)
  2327.   { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
  2328.     fpin = fopen(TemplateFile, "r");
  2329.   }
  2330.  
  2331.   if (!fpin)
  2332.     {
  2333.       ShowError(msgNoSourceDescription, OrigTemplateFile);
  2334.       return;
  2335.     }
  2336.  
  2337.   if (!(fpout = fopen(SourceFile, "w")))
  2338.   {
  2339.     ShowError(msgNoSource, SourceFile);
  2340.     return;
  2341.   }
  2342.  
  2343.   if(!NoBufferedIO)
  2344.     setvbuf(fpin, NULL, _IOFBF, buffer_size);
  2345.   if(!NoBufferedIO)
  2346.     setvbuf(fpout, NULL, _IOFBF, buffer_size);
  2347.  
  2348.  
  2349.   while(!feof(fpin)  &&  (line = ReadLine(fpin, FALSE)))
  2350.   { struct CatString *cs;
  2351.     int NeedRepeat;
  2352.     char bytes[10];
  2353.     int bytesread;
  2354.  
  2355.     cs = FirstCatString;
  2356.     do
  2357.     { char *currentline = line;
  2358.       NeedRepeat = FALSE;
  2359.  
  2360.       if (*currentline == '#'  &&  *(++currentline) == '#')
  2361.       { ++currentline;
  2362.         OverSpace(¤tline);
  2363.  
  2364.         if(strnicmp( currentline, "rem", 3 ) == 0)
  2365.            {
  2366.            // we just skip this line
  2367.            continue;
  2368.            }
  2369.  
  2370.         if (strnicmp(currentline, "stringtype", 10) == 0)
  2371.         { currentline += 10;
  2372.           OverSpace(¤tline);
  2373.           if (strnicmp(currentline, "c", 1) == 0)
  2374.           { OutputType = TYPE_C;
  2375.             ++currentline;
  2376.           }
  2377.           else if (strnicmp(currentline, "assembler", 9) == 0)
  2378.           { OutputType = TYPE_ASSEMBLER;
  2379.             currentline += 9;
  2380.           }
  2381.           else if (strnicmp(currentline, "oberon", 6) == 0)
  2382.           { OutputType = TYPE_OBERON;
  2383.             currentline += 6;
  2384.           }
  2385.           else if (strnicmp(currentline, "e", 1)  ==  0)
  2386.           { OutputType = TYPE_E;
  2387.             ++currentline;
  2388.           }
  2389.           else if (strnicmp(currentline, "none", 4)  ==  0)
  2390.           { OutputType = TYPE_NONE;
  2391.             currentline += 4;
  2392.           }
  2393.           else
  2394.           { ShowWarn(msgUnknownStringType);
  2395.             currentline += strlen(currentline);
  2396.           }
  2397.           OverSpace(¤tline);
  2398.           if (*currentline)
  2399.           { ShowWarn(msgExtraCharacters);
  2400.           }
  2401.           continue;
  2402.         }
  2403.         else if (strnicmp(currentline, "shortstrings", 12) == 0)
  2404.         { currentline += 12;
  2405.           LongStrings = FALSE;
  2406.           OverSpace(¤tline);
  2407.           if (*currentline)
  2408.           { ShowWarn(msgExtraCharacters);
  2409.           }
  2410.           continue;
  2411.         }
  2412.       }
  2413.  
  2414.       currentline = line;
  2415.       while(*currentline)
  2416.       { bytesread = ReadChar(¤tline, bytes);
  2417.         if (bytesread)
  2418.         { if (*bytes == '%')
  2419.           { char c;
  2420.  
  2421.             switch(c = *(currentline++))
  2422.             { case 'b':
  2423.                 fputs(BaseName, fpout);
  2424.                 break;
  2425.               case 'n':
  2426.                 fprintf(fpout, "%d", NumStrings);
  2427.                 break;
  2428.               case 'v':
  2429.                 fprintf(fpout, "%d", CatVersion);
  2430.                 break;
  2431.               case 'l':
  2432.                 WriteString(fpout, Language, -1);
  2433.                 break;
  2434.               case 'f':
  2435.                 { char *tempstr;
  2436.  
  2437.                   if ((c = *currentline++) == 'v')
  2438.                   { fputs(VERS, fpout);
  2439.                   }
  2440.                   else
  2441.                   { tempstr = AllocFileName(CDFile, c - '0');
  2442.                     fputs(tempstr, fpout);
  2443.                   }
  2444.                 }
  2445.                 break;
  2446.               case 'o':
  2447.                 { char *tempstr;
  2448.  
  2449.                   tempstr = AllocFileName(SourceFile, *currentline++ - '0');
  2450.                   fputs(tempstr, fpout);
  2451.                 }
  2452.                 break;
  2453.               case 'i':
  2454.                 NeedRepeat = TRUE;
  2455.                 if (cs) fputs(cs->ID_Str, fpout);
  2456.                 break;
  2457.  
  2458.               case 'a':
  2459.               case 't':
  2460.  
  2461.               case 'd':
  2462.               case 'x':
  2463.               case 'c':
  2464.               case '0':
  2465.               case '1':
  2466.               case '2':
  2467.               case '3':
  2468.               case '4':
  2469.               case '5':
  2470.               case '6':
  2471.               case '7':
  2472.               case '8':
  2473.               case '9':
  2474.                   {
  2475.                   int len = 0;
  2476.  
  2477.                   while(c >= '0'  &&  c <= '9')
  2478.                     {
  2479.                     len = (c - '0') + len * 10;
  2480.                     c = *currentline++;
  2481.                     }
  2482.  
  2483.  
  2484.                   if(c ==  'a')
  2485.                     {
  2486.                     int _len = len ? len : 4;
  2487.                     char *start;
  2488.                     char _StrLen[20 + 1];
  2489.  
  2490.                     sprintf(_StrLen, "%020lx", cs->ID);
  2491.  
  2492.                     start = &_StrLen[20-_len*2];
  2493.                     while(_len>0)
  2494.                        {
  2495.                        fprintf(fpout, "\\x%.2s", start);
  2496.                        start+=2;
  2497.                        _len--;
  2498.                        }
  2499.                     }
  2500.  
  2501.                   if(c ==  't')
  2502.                     {
  2503.                     int _len = len ? len : 4;
  2504.                     char *start;
  2505.                     char _StrLen[20 + 1];
  2506.  
  2507.                     sprintf(_StrLen, "%020lx", ((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
  2508.  
  2509.                     start = &_StrLen[20-_len*2];
  2510.                     while(_len>0)
  2511.                        {
  2512.                        fprintf(fpout, "\\x%.2s", start);
  2513.                        start+=2;
  2514.                        _len--;
  2515.                        }
  2516.                     }
  2517.  
  2518.                   if(c == 'c' || c == 'd' || c == 'x')
  2519.                     {
  2520.                     char buffer[20];
  2521.  
  2522.                     if(c == 'c') c = 'o';
  2523.  
  2524.                     if(len)
  2525.                       sprintf(buffer, "%%0%d%c", len, c);
  2526.                     else
  2527.                       sprintf(buffer, "%%%c", c);
  2528.  
  2529.                     if(cs) fprintf(fpout, buffer, cs->ID);
  2530.                     }
  2531.  
  2532.  
  2533.                   NeedRepeat = TRUE;
  2534.                   }
  2535.                   break;
  2536.  
  2537.               case 'e':
  2538.                 NeedRepeat = TRUE;
  2539.                 if (cs) fprintf(fpout, "%d", cs->Nr);
  2540.                 break;
  2541.               case 's':
  2542.                 NeedRepeat = TRUE;
  2543.                 if (cs)
  2544.                 { char *idstr;
  2545.                   unsigned long len = 0;
  2546.  
  2547.                   if (LengthBytes)
  2548.                   { idstr = cs->CD_Str;
  2549.                     while(*idstr)
  2550.                     { bytesread = ReadChar(&idstr, bytes);
  2551.                       if (bytesread)
  2552.                       { ++len;
  2553.                       }
  2554.                     }
  2555.                   }
  2556.                   WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
  2557.                 }
  2558.                 break;
  2559.               case '(':
  2560.                 NeedRepeat = TRUE;
  2561.                 while(*currentline  &&  *currentline != ')')
  2562.                 { bytesread = ReadChar(¤tline, bytes);
  2563.                   if (bytesread  &&  cs  &&  cs->Next)
  2564.                   { putc((int) bytes[bytesread-1], fpout);
  2565.                   }
  2566.                 }
  2567.                 if (!*currentline)
  2568.                 { ShowWarn(msgNoTerminateBracket);
  2569.                 }
  2570.                 else
  2571.                 { ++currentline;
  2572.                 }
  2573.                 break;
  2574.  
  2575. // !!!! FIX !!!!
  2576.  
  2577.               case 'z':
  2578.                 {
  2579.                 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
  2580.  
  2581.                 NeedRepeat = TRUE;
  2582.  
  2583.                 while(diff > 0)
  2584.                    {
  2585.                    fprintf(fpout, "\\x00");
  2586.                    diff--;
  2587.                    }
  2588.  
  2589.                 break;
  2590.                 }
  2591.  
  2592.               default:
  2593.                 { int c = *currentline++;
  2594.  
  2595.                   putc(c, fpout);
  2596.                 }
  2597.             }
  2598.           }
  2599.           else
  2600.           { putc((int) bytes[bytesread-1], fpout);
  2601.           }
  2602.         }
  2603.       }
  2604.       putc('\n', fpout);
  2605.     }
  2606.     while(NeedRepeat  &&  cs  &&  (cs = cs->Next));
  2607.  
  2608.     free(line);
  2609.   }
  2610.  
  2611.   fclose(fpin);
  2612.   fclose(fpout);
  2613. }
  2614. //|
  2615.  
  2616. /// FUNC: Usage
  2617. /*
  2618.     The Usage function describes the programs calling syntax.
  2619. */
  2620. void Usage(void)
  2621.  
  2622. {
  2623.   fputs((char *) msgUsageHead, stderr);
  2624.   fprintf(stderr, ": FlexCat CDFILE/A,CTFILE,CATALOG/K,NEWCTFILE/K,SOURCES/M,\n                WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,\n                QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,\n                MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K, NOSPACE/S\n\n", VString);
  2625.   fprintf(stderr, "%s\n%s\n%s\n%s\n", msgUsage, msgUsage_2, msgUsage_3, msgUsage_4 );
  2626.   fprintf(stderr, "\n\n%s"
  2627. /*
  2628.   #ifdef _M68040
  2629.     " [040]"
  2630.   #else
  2631.     #ifdef _M68060
  2632.       " [060]"
  2633.     #else
  2634.       #ifdef _M68030
  2635.         " [030]"
  2636.       #else
  2637.         #ifdef _M68020
  2638.           " [020]"
  2639.         #else
  2640.           #ifdef _M68010
  2641.             " [010]"
  2642.           #endif
  2643.         #endif
  2644.       #endif
  2645.     #endif
  2646.   #endif
  2647. */
  2648.   "\n", VString);
  2649.  
  2650.  
  2651.   fprintf(stderr, "%s\n", EString);
  2652.   MyExit(5);
  2653. }
  2654. //|
  2655. /// FUNC: main
  2656. /*
  2657.     Finally the main function. Does nothing special except for scanning
  2658.     the arguments.
  2659. */
  2660. int main(int argc, char *argv [])
  2661. {
  2662.   char *cdfile, *ctfile, *newctfile, *catalog;
  2663.   char *source, *template;
  2664.   int i;
  2665.  
  2666.   if(argc == 0)    /*  Aztec's entry point for workbench programs  */
  2667.    {
  2668.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2669.    fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
  2670.    fprintf(stderr, "for more information\n");
  2671.    exit(5);
  2672.    }
  2673.  
  2674.   cdfile = ctfile = newctfile = catalog = NULL;
  2675.  
  2676.  
  2677.   /* let's open catalog files by hand if necessary */
  2678.   /* should be done automatically anyway for most  */
  2679.   /* cases, but, that depends on compiler...       */
  2680.  
  2681. #if defined(_DCC)
  2682.   // STATIC __autoinit VOID _STIOpenFlexCatCatalog(VOID)
  2683. #elif defined(__SASC)
  2684.   // VOID _STIOpenFlexCatCatalog(VOID)
  2685. #elif defined(__GNUC__)
  2686.   // VOID _STIOpenFlexCatCatalog(VOID)
  2687. #else
  2688.    OpenFlexCatCatalog();   /* no autoopen. we do it then */
  2689. #endif
  2690.  
  2691.  
  2692.     // Big Endian vs Little Endian (both supported ;-)
  2693.     if( !SwapChoose() )
  2694.        {
  2695.        fprintf(stderr, "FlexCat is unable to determine the\n");
  2696.        fprintf(stderr, "the byte order used by your system.\n");
  2697.        fprintf(stderr, "It's neither Little nor Big Endian?!.\n");
  2698.        exit(5);
  2699.        }
  2700.  
  2701.  
  2702.  
  2703. #if defined(__amigados)
  2704.   ReadPrefs();
  2705. #endif
  2706.  
  2707.   if(argc == 1)
  2708.     {
  2709.     Usage();
  2710.     }
  2711.  
  2712.   for (i = 1;  i < argc;  i++)
  2713.     {
  2714.     if(strnicmp (argv[i], "catalog=", 8) == 0)
  2715.       {
  2716.       catalog = argv[i] + 8;
  2717.       }
  2718.     else
  2719.     if(stricmp (argv[i], "catalog") == 0)
  2720.       {
  2721.       if(i+1 == argc)
  2722.         Usage();
  2723.       catalog = argv[++i];
  2724.       }
  2725.     else
  2726.     if(stricmp(argv[i], "nooptim") == 0)
  2727.      {
  2728.      NoOptim = TRUE;
  2729.      }
  2730.     else
  2731.     if(stricmp(argv[i], "fill") == 0)
  2732.      {
  2733.      Fill = TRUE;
  2734.      }
  2735.     else
  2736.     if(stricmp(argv[i], "quiet") == 0)
  2737.      {
  2738.      Quiet = TRUE;
  2739.      }
  2740.     else
  2741.     if(stricmp(argv[i], "flush") == 0)
  2742.      {
  2743.      DoExpunge = TRUE;
  2744.      }
  2745.     else
  2746.     if(stricmp(argv[i], "nobeep") == 0)
  2747.      {
  2748.      NoBeep = TRUE;
  2749.      }
  2750.     else
  2751.     if(stricmp(argv[i], "nobufferedio") == 0)
  2752.      {
  2753.      NoBufferedIO = TRUE;
  2754.      }
  2755.     else
  2756.     if (strnicmp (argv[i], "newctfile=", 10) == 0)
  2757.       {
  2758.       newctfile = argv[i] + 10;
  2759.       }
  2760.     else
  2761.     if(strnicmp (argv[i], "newctfile", 10) == 0)
  2762.       {
  2763.       if (i+1 == argc)
  2764.         Usage();
  2765.       newctfile = argv[++i];
  2766.       }
  2767.     else
  2768.     if(stricmp(argv[i], "nolangtolower") == 0)
  2769.       {
  2770.       LANGToLower = FALSE;
  2771.       }
  2772.     else
  2773.     if(stricmp(argv[i], "modified") == 0)
  2774.       {
  2775.       Modified = TRUE;
  2776.       }
  2777.     else
  2778.     if(stricmp(argv[i], "warnctgaps") == 0)
  2779.       {
  2780.       WarnCTGaps = TRUE;
  2781.       }
  2782.     else
  2783.     if(stricmp(argv[i], "copymsgnew") == 0)
  2784.       {
  2785.       CopyNEWs = TRUE;
  2786.       }
  2787.     else
  2788.     if(stricmp(argv[i], "nospace") == 0)
  2789.       {
  2790.       NoSpace = TRUE;
  2791.       }
  2792.     else
  2793.     if(stricmp(argv[i], "oldmsgnew") == 0)
  2794.       {
  2795.       sprintf( Old_Msg_New, "; %s", argv[++i] );
  2796.       }
  2797.     else
  2798.       if(cdfile == NULL)
  2799.         {
  2800.         if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
  2801.           {
  2802.           Usage();
  2803.           }
  2804.         if(!ScanCDFile(cdfile = argv[i]))
  2805.           {
  2806.           MyExit(10);
  2807.           }
  2808.         }
  2809.     else
  2810.     if(strchr(argv[i], '='))
  2811.       {
  2812.       source = AllocString(argv[i]);
  2813.       *(template = strchr(source, '=')) = '\0';
  2814.       ++template;
  2815.  
  2816.       CreateSourceFile(source, template, cdfile);
  2817.       }
  2818.     else
  2819.       {
  2820.       if (ctfile)
  2821.         {
  2822.         Usage();
  2823.         }
  2824.       ctfile = argv[i];
  2825.       }
  2826.     }
  2827.  
  2828. #if defined(__amigados)
  2829.   if(Modified)
  2830.     {
  2831.     if(cdfile && ctfile && catalog)
  2832.        {
  2833.        long cd_time, ct_time, cat_time;
  2834.  
  2835.        if((cd_time = getft(cdfile)) != -1)
  2836.            {
  2837.            if((ct_time = getft(ctfile)) != -1)
  2838.               {
  2839.               if((cat_time = getft(catalog)) == -1)
  2840.                 cat_time = 0;
  2841.  
  2842.                 if((cat_time > ct_time) &&
  2843.                    (cat_time > cd_time))
  2844.                        {
  2845.                        if(!Quiet)
  2846.                          {
  2847.                          fprintf(stderr, (char *) msgUpToDate, catalog);
  2848.                          putc('\n', stderr);
  2849.                          }
  2850.  
  2851.                        MyExit(GlobalReturnCode);
  2852.                        }
  2853.                   else
  2854.                     {
  2855.                     if(!Quiet)
  2856.                       {
  2857.                       fprintf(stderr, "--> %s", catalog);
  2858.                       putc('\n', stderr);
  2859.                       }
  2860.                     }
  2861.               }
  2862.             else
  2863.               {
  2864.               ShowError(msgCantCheckDate, ctfile);
  2865.               }
  2866.            }
  2867.         else
  2868.            {
  2869.            ShowError(msgCantCheckDate, cdfile);
  2870.            }
  2871.        }
  2872.     }
  2873. #endif
  2874.  
  2875.   if(ctfile)
  2876.     {
  2877.     if(!ScanCTFile(ctfile))
  2878.       MyExit(10);
  2879.     }
  2880.  
  2881.   if(catalog)
  2882.     {
  2883.     if(!ctfile)
  2884.       {
  2885.       fprintf(stderr, (char *) msgNoCTArgument);
  2886.       Usage();
  2887.       }
  2888.     CreateCat(catalog);
  2889.     }
  2890.  
  2891.   if(newctfile)
  2892.     {
  2893.     CreateCTFile(newctfile);
  2894.     }
  2895.  
  2896.   MyExit(GlobalReturnCode);
  2897. }
  2898. //|
  2899. /// FUNC: wbmain
  2900.  
  2901. /*
  2902.     Dice's entry point for workbench programs
  2903. */
  2904. #if defined(__amigados)  &&  defined(_DCC)
  2905. void wbmain(struct WBStartup *wbmsg)
  2906. {
  2907.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2908.    fprintf(stderr, "Open a Shell session and type FlexCat\n");
  2909.    fprintf(stderr, "for syntax and more information\n");
  2910.  
  2911.    exit(5);
  2912. }
  2913. #endif
  2914. //|
  2915.  
  2916.