Synchronized icu patch from contrib, now builds again for me, updated README.
[AROS.git] / tools / FlexCat / flexcat.c
blob6c203bc0a104675909d7ba6b7f6a4554a12e4eae
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 *****************************************************************/
12 /* $Id$ */
15 //#define __amigados
17 /// README
20 FlexCat.c: The flexible catalog creator
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.
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?
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, ...
37 //|
39 #define VERSION 2
40 #define REVISION 4
41 #define VERS "FlexCat 2.4"
43 #ifdef __amigados
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
67 #define VSTRING VERS " " _CPU " " __AMIGADATE__
68 #else
69 #define VSTRING VERS
70 #endif
72 #define VERSTAG "$VER: " VSTRING
74 /// Includes and defines
76 #include <stdlib.h>
77 #include <stdio.h>
78 #include <string.h>
79 #include <ctype.h>
80 #include <time.h>
81 #include <stdarg.h>
82 #ifdef __amigados
83 #include <dos.h>
84 #endif
85 #include "flexcat_cat.h"
87 #if ((defined(_DCC) && defined(AMIGA)) || \
88 (defined(__SASC) && defined(_AMIGA))) && \
89 !defined(__amigados)
90 #define __amigados
91 #endif
93 #if defined(__amigados)
94 #include <exec/types.h>
95 #if defined(_DCC) || defined(__SASC) || defined(__GNUC__)
96 #include <proto/exec.h>
97 #include <proto/dos.h>
98 #include <proto/intuition.h>
99 #include <proto/utility.h>
100 #else
101 #include <clib/exec_protos.h>
102 #include <clib/dos_protos.h>
103 #include <clib/utility_protos.h>
104 #endif
106 #ifdef tolower
107 #undef tolower
108 #endif
109 #define tolower ToLower
110 #define stricmp(s,t) Stricmp((char *) (s), (char *) (t))
111 #define strnicmp(s,t,l) Strnicmp((char *) (s), (char *) (t), l)
113 #endif
116 #ifndef FALSE
117 #define FALSE 0
118 #endif
119 #ifndef TRUE
120 #define TRUE (!FALSE)
121 #endif
124 #define MAXPATHLEN 512
125 #define FLEXCAT_SDDIR "FLEXCAT_SDDIR"
126 #if defined(__amigados)
127 #define DEFAULT_FLEXCAT_SDDIR "PROGDIR:lib"
128 #else
129 #define DEFAULT_FLEXCAT_SDDIR "lib"
130 #endif
132 #if defined(__amigados)
133 #define MAX_PREFS_LEN 512
134 #define FLEXCAT_PREFS "flexcat.prefs"
135 char prefs_sddir[MAXPATHLEN] = "\0";
136 #endif
139 #ifndef MAKE_ID
140 #define MAKE_ID(a,b,c,d) \
141 ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
142 #endif
144 #ifndef ULONG
145 #define ULONG unsigned int
146 #endif
149 /// Structs
151 enum StringTypes {
152 TYPE_C, /* Produce C strings */
153 TYPE_ASSEMBLER, /* Produce Assembler strings */
154 TYPE_OBERON, /* Produce Oberon strings */
155 TYPE_E, /* Produce E strings. (Oops, thought */
156 /* it allows only 32 bit integers? ;-) */
157 TYPE_NONE /* Simple strings */
161 enum OutputModes {
162 OutputMode_None, /* Nothing written yet */
163 OutputMode_Bin, /* Last character written was binary */
164 OutputMode_Ascii /* Last character written was Ascii */
167 struct CatString
168 { struct CatString *Next;
169 char *CD_Str;
170 char *CT_Str;
171 char *ID_Str;
172 int MinLen, MaxLen, ID, Nr;
173 int NotInCT; /* If string is not present we write NEW */
174 /* while updating CT file, for easier work. */
178 struct CDLine
179 { struct CDLine *Next;
180 char *Line;
183 struct CatalogChunk
184 { struct CatalogChunk *Next; /* struct CatalogChunk *Next */
185 ULONG ID;
186 char *ChunkStr;
189 struct CatString *FirstCatString = NULL; /* First catalog string */
190 struct CDLine *FirstCDLine = NULL; /* First catalog description line */
191 struct CatalogChunk *FirstChunk = NULL; /* List of catalog chunks */
193 char *BaseName = ""; /* Basename of catalog description */
194 char *Language = "english"; /* Language of catalog description */
195 int CatVersion = 0; /* Version of catalog to be opened */
196 int LengthBytes = 0; /* Number of bytes to preceed a */
197 /* created string and containing */
198 /* its length. */
199 char *CatLanguage = NULL; /* Language of catalog translation */
200 char *CatVersionString = NULL; /* version string of catalog */
201 /* translation (## version) */
202 char *CatRcsId = NULL; /* rcs ID of catalog translation */
203 /* (## rcsid) */
204 char *CatName = NULL; /* name of catalog translation */
205 int CodeSet = 0; /* Codeset of catalog translation */
206 int NumStrings = 0; /* Number of catalog strings */
207 int LongStrings = TRUE; /* Generate long or short strings */
209 char *ScanFile; /* File currently scanned */
210 int ScanLine; /* Line currently scanned */
212 int GlobalReturnCode = 0; /* Will be 5, if warnings appear */
213 int WarnCTGaps = FALSE; /* Warn missing symbols in CT */
214 /* file. */
215 int NoOptim = FALSE; /* Put string into catalog even */
216 /* if translation is equal to */
217 /* description. */
218 int Fill = FALSE; /* It translation of given string */
219 /* is missing or it's empty, write */
220 /* string descriptor from #?.cd */
221 /* file instead. */
222 int DoExpunge = FALSE; /* If TRUE FlexCat will do AVAIL */
223 /* FLUSH alike after catalog save */
224 int NoBeep = FALSE; /* if TRUE, FlexCat won't call */
225 /* DisplayBeep() any longer */
226 int Quiet = FALSE; /* Forces FlexCat to shut up */
228 int NumberOfWarnings = 0; /* We count warnings to be smart */
229 /* and not to do Beep bombing, but */
230 /* call DisplayBeep() only once */
231 int CT_Scanned = FALSE; /* If TRUE, and we are going to */
232 /* write new #?.ct file, then user */
233 /* surely updates own #?.ct file */
234 /* so we should write ***NEW*** */
235 /* whenever necessary. */
236 int LANGToLower = TRUE; /* Shall we do ToLower() on lang's */
237 /* name? Some #?.language seems to */
238 /* be broken, so we allow workaround */
239 int NoBufferedIO = FALSE; /* Shall we do buffered IO */
240 int buffer_size = 2048; /* Size of the IO buffer */
241 int Modified = FALSE; /* Shall we write the catalog ONLY */
242 /* if #?.catalog is younger than */
243 /* #?.c(d|t) files? */
245 #define MAX_NEW_STR_LEN 25
246 char Msg_New[MAX_NEW_STR_LEN] = "***NEW***";
247 /* new strings in updated #?.ct */
249 int CopyNEWs = FALSE;
250 char Old_Msg_New[MAX_NEW_STR_LEN] = "; ***NEW***";
252 /* old newstring (above) used in old */
253 /* CT file. Now we look if it's present */
254 /* and copy it into new CT if user does */
255 /* upgrade (flexcat CD CT newctfile CT */
257 int NoSpace = FALSE; /* do want to strip the space usually */
258 /* placed between ';' and original */
259 /* string? */
262 char VersTag[] = VERSTAG;
263 char VString[] = VSTRING " by Jochen Wiedmann and Marcin Orlowski";
264 char EString[] = "E-mail: carlos@amiga.com.pl WWW: http://amiga.com.pl/flexcat/";
267 /// FUNC: ReadPrefs
268 #if defined(__amigados)
270 char ReadPrefs(void)
272 enum{ SDDIR,
273 MSG_NEW,
274 WARNCTGAPS,
275 NOOPTIM,
276 FILL,
277 FLUSH,
278 NOBEEP,
279 QUIET,
280 NOLANGTOLOWER,
281 NOBUFFEREDIO,
282 MODIFIED,
283 COPYMSGNEW,
284 OLDMSGNEW,
285 NOSPACE,
287 ARGS_COUNT
290 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";
291 LONG Results[ARGS_COUNT] = {0};
292 char result = FALSE;
293 char *prefs;
294 struct RDArgs *rda;
295 struct RDArgs *rdargs;
297 if(prefs = getenv(FLEXCAT_PREFS))
299 prefs = realloc(prefs, strlen(prefs)+1);
300 strcat(prefs, "\n");
302 if(rda = AllocDosObject(DOS_RDARGS, TAG_DONE))
304 rda->RDA_Source.CS_Buffer = prefs;
305 rda->RDA_Source.CS_Length = strlen(prefs);
306 rda->RDA_Source.CS_CurChr = 0;
307 rda->RDA_Flags |= RDAF_NOPROMPT;
309 if(rdargs = ReadArgs(template, Results, rda))
311 if(Results[SDDIR])
312 strncpy(prefs_sddir, (char *)Results[SDDIR], MAXPATHLEN);
314 if(Results[MSG_NEW])
315 strncpy(Msg_New, (char *)Results[MSG_NEW], MAX_NEW_STR_LEN);
317 WarnCTGaps = Results[WARNCTGAPS];
318 NoOptim = Results[NOOPTIM];
319 Fill = Results[FILL];
320 DoExpunge = Results[FLUSH];
321 NoBeep = Results[NOBEEP];
322 Quiet = Results[QUIET];
323 LANGToLower = Results[NOLANGTOLOWER];
324 Modified = Results[MODIFIED];
325 NoBufferedIO = Results[NOBUFFEREDIO];
326 CopyNEWs = Results[COPYMSGNEW];
327 NoSpace = Results[NOSPACE];
328 if(Results[OLDMSGNEW])
329 sprintf(Old_Msg_New, "; %s", (char *)Results[OLDMSGNEW]);
331 FreeArgs(rdargs);
333 result = TRUE;
335 else
337 fputs((char *)msgPrefsError, stderr);
338 fputs((char *)template, stderr);
339 fputs((char *)"\n", stderr);
340 DisplayBeep(NULL);
343 FreeDosObject(DOS_RDARGS, rda);
345 else
347 fputs("Error processing prefs.\nCan't AllocDosObject()\n", stderr);
350 free(prefs);
353 return(result);
356 #endif
359 /// FUNC: MyExit
360 void MyExit (int Code)
363 #if defined(__amigados)
365 if(((NumberOfWarnings > 0) ||(Code !=0)) && (!NoBeep))
366 DisplayBeep(NULL);
368 #endif
371 #if defined(_DCC)
372 //STATIC __autoexit VOID _STDCloseFlexCatCatalog(VOID)
373 #elif defined(__SASC)
374 //VOID _STDCloseFlexCatCatalog(VOID)
375 #elif defined(__GNUC__)
376 //STATIC VOID _STDCloseFlexCatCatalog(VOID)
377 #elif defined(__INTEL_COMPILER)
378 //STATIC VOID _STDCloseFlexCatCatalog(VOID)
379 #else
380 CloseFlexCatCatalog(); /* we need to close something... */
381 #endif
384 exit(Code);
388 /// FUNC: stricmp
390 // quick stricmp
392 #if !defined(__amigados) && !defined(__CYGWIN32__)
393 # define stricmp strcasecmp
394 #endif
396 #if 0
397 int stricmp( const char *str1, const char *str2 )
399 int i;
401 for(i = 0;; i++)
403 int a = tolower( (int)*str1 );
404 int b = tolower( (int)*str2 );
406 if( !a || !b )
407 break;
409 if( a != b )
410 return( 1 );
412 str1++;
413 str2++;
416 return( 0 );
418 #endif
421 /// FUNC: strnicmp
423 // quick strnicmp
425 #if !defined(__amigados) && !defined(__CYGWIN32__)
426 int strnicmp( const char *str1, const char *str2, size_t len )
428 size_t i;
430 for(i = 0; i < len; i++)
432 int a = tolower( (int)*str1 );
433 int b = tolower( (int)*str2 );
435 if( !a || !b )
436 return( 1 );
438 if( a != b )
439 return( 1 );
441 str1++;
442 str2++;
445 return( 0 );
447 #endif
451 /// FUNC: Swappers...
454 unsigned short (*SwapWord)(unsigned short r) = NULL;
455 unsigned long (*SwapLong)(unsigned long r) = NULL;
458 unsigned short SwapWord21(unsigned short r)
460 return (unsigned short)((r>>8) + (r<<8));
462 unsigned short SwapWord12(unsigned short r)
464 return r;
466 unsigned long SwapLong4321(unsigned long r)
468 return ((r>>24) & 0xFF) + (r<<24) + ((r>>8) & 0xFF00) + ((r<<8) & 0xFF0000);
470 unsigned long SwapLong1234(unsigned long r)
472 return r;
476 /// FUNC: SwapChoose
477 int SwapChoose(void)
479 unsigned short w;
480 unsigned int d;
482 strncpy((char *)&w, "\1\2", 2);
483 strncpy((char *)&d, "\1\2\3\4", 4);
485 if (w == 0x0201)
486 SwapWord = SwapWord21;
487 else if (w == 0x0102)
488 SwapWord = SwapWord12;
489 else
490 return 0;
492 if (d == 0x04030201)
493 SwapLong = SwapLong4321;
494 else if (d == 0x01020304)
495 SwapLong = SwapLong1234;
496 else
497 return 0;
499 return 1;
503 /// FUNC: ShowError
506 This shows an error message and terminates
508 void ShowError(const char *msg, ...)
510 va_list ptr;
511 va_start(ptr, msg);
513 // if(!Quiet)
515 vfprintf(stderr, msg, ptr);
516 putc('\n', stderr);
519 va_end(ptr);
520 #if defined(__amigados)
521 NumberOfWarnings++;
522 #endif
524 MyExit(10);
527 /// FUNC: MemError
530 This shows the message: Memory error.
532 void MemError(void)
535 ShowError(msgMemoryError, NULL);
538 /// FUNC: ShowWarn
541 This shows a warning
543 void ShowWarn(const char *msg, ...)
545 { va_list ptr;
546 va_start(ptr, msg);
548 if(!Quiet)
550 fprintf(stderr, (char *) msgWarning, ScanFile, ScanLine);
551 #warning the following line produces segfault on x86_64
552 vfprintf(stderr, msg, ptr);
553 putc('\n', stderr);
555 va_end(ptr);
557 NumberOfWarnings++;
558 GlobalReturnCode = 5;
561 /// FUNC: AllocString
564 This allocates a string
566 char *AllocString(const char *str)
568 { char *ptr;
570 if (!(ptr = malloc(strlen(str)+1)))
571 { MemError();
573 strcpy(ptr, str);
574 return(ptr);
577 /// FUNC: Add catalog chunk
580 This adds a new catalog chunk to the list of catalog
581 chunks.
583 char *AddCatalogChunk(char *ID, const char *string)
585 struct CatalogChunk *cc, **ccptr;
587 if (!(cc = malloc(sizeof(*cc))))
588 { MemError();
590 cc->Next = NULL;
591 cc->ID = *((ULONG *) ID);
592 cc->ChunkStr = AllocString(string);
595 Put the new chunk to the end of the chunk list.
597 for (ccptr = &FirstChunk; *ccptr != NULL; ccptr = &(*ccptr)->Next)
600 *ccptr = cc;
601 return(cc->ChunkStr);
604 /// FUNC: gethex
606 This translates a hex character.
608 int gethex(int c)
610 if (c >= '0' && c <= '9')
611 { return(c - '0');
613 else if (c >= 'a' && c <= 'f')
614 { return(c - 'a' + 10);
616 else if (c >= 'A' && c <= 'F')
617 { return(c - 'A' + 10);
619 ShowWarn(msgExpectedHex);
620 return(0);
623 /// FUNC: getoctal
626 This translates an octal digit.
628 int getoctal(int c)
631 if (c >= '0' && c <= '7')
633 return(c - '0');
636 ShowWarn(msgExpectedOctal);
637 return(0);
641 /// FUNC: ReadLine
644 Reading a line is somewhat complicated in order to allow lines of any
645 length.
647 Inputs: fp - the file, where the input comes from
648 AllowComment - TRUE, if a leading semicolon should force to
649 interpret the line as a comment line
651 #define BUFSIZE 4096
652 char *ReadLine(FILE *fp, int AllowComment)
655 char *OldLine, *NewLine = NULL;
656 int c = '\0';
657 int Len = 0, LineLen = 0;
658 int FirstChar = TRUE;
659 int BackslashSeen = FALSE;
660 int BackslashSeenOn = 0; /* position the last backslash was seen on */
661 int CommentLine = FALSE; /* if TRUE we should ignore normally treat trailing \'s */
663 while(c != EOF)
665 if(Len+10 > LineLen)
667 OldLine = NewLine;
668 if(!(NewLine = malloc(LineLen+BUFSIZE)))
669 MemError();
671 strncpy(NewLine, OldLine, LineLen);
672 if(OldLine)
673 free(OldLine);
675 LineLen += BUFSIZE;
678 c = getc(fp);
680 if(FirstChar)
682 if(c == EOF)
684 free(NewLine);
685 return(NULL);
688 if(c == ';')
690 CommentLine = TRUE;
693 FirstChar = FALSE;
696 switch(c)
698 case '\r':
699 break;
701 case '\n':
702 ++ScanLine;
703 if(BackslashSeen)
705 NewLine[Len++] = c;
706 BackslashSeen = FALSE;
707 break;
709 c = EOF;
711 case EOF:
712 break;
714 /* Let's check for trailing \\ */
715 case '\\':
717 if(!CommentLine)
719 if(BackslashSeen)
721 if(BackslashSeenOn == (Len-1))
723 BackslashSeen = FALSE;
724 NewLine[Len++] = c;
725 break;
729 BackslashSeen = TRUE;
730 BackslashSeenOn = Len;
733 NewLine[Len++] = c;
734 break;
738 default:
739 BackslashSeen = FALSE;
740 NewLine[Len++] = c;
744 NewLine[Len] = '\0';
746 return(NewLine);
750 /// FUNC: OverSpace
753 This removes trailing blanks.
755 void OverSpace(char **strptr)
757 { int c;
759 while ((c = **strptr) == ' ' || c == '\t')
760 { (*strptr)++;
765 /// FUNC: Expunge
767 void Expunge(void)
769 #if defined(__amigados)
772 if(DoExpunge)
774 #ifdef __EXPUNGE_ALL__
775 APTR Memory;
777 if(Memory = AllocMem(-1, NULL))
778 FreeMem(Memory, -1); // just in case ;-)
779 #else
781 #pragma libcall LocaleBase localeExpunge 12 00
782 VOID localeExpunge(VOID);
784 struct Library *LocaleBase;
786 if(LocaleBase = OpenLibrary("locale.library", 0))
788 localeExpunge();
789 CloseLibrary(LocaleBase);
792 #endif
794 #endif
800 /// FUNC: ReadChar
803 ReadChar scans an input line translating the backslash characters.
805 Inputs: char * - a pointer to a stringpointer; the latter points to the
806 next character to be read and points behind the read
807 bytes after executing ReadChar
808 dest - a pointer to a buffer, where the read bytes should be
809 stored
811 Result: number of bytes that are written to dest (between 0 and 2)
813 int ReadChar(char **strptr, char *dest)
815 char c;
816 int i;
818 switch(c = *((*strptr)++))
820 case '\\':
822 switch(c = tolower((int) *((*strptr)++)))
824 case '\n':
825 return(0);
826 case 'b':
827 *dest = '\b';
828 break;
829 case 'c':
830 *dest = '\233';
831 break;
832 case 'e':
833 *dest = '\033';
834 break;
835 case 'f':
836 *dest = '\f';
837 break;
838 case 'g':
839 *dest = '\007';
840 break;
841 case 'n':
842 *dest = '\n';
843 break;
844 case 'r':
845 *dest = '\r';
846 break;
847 case 't':
848 *dest = '\t';
849 break;
850 case 'v':
851 *dest = '\013';
852 break;
853 case 'x':
854 *dest = gethex((int) **strptr);
855 (*strptr)++;
856 if (((c = **strptr) >= '0' && c <= '9') ||
857 (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
858 { *dest = (*dest << 4) + gethex((int) c);
859 (*strptr)++;
861 break;
862 case '0':
863 case '1':
864 case '2':
865 case '3':
866 case '4':
867 case '5':
868 case '6':
869 case '7':
871 *dest = getoctal((int)c);
873 for(i = 0; i < 2; i++)
875 if((c = **strptr) >= '0' && c <= '7')
877 *dest = (*dest << 3) + getoctal((int) c);
878 (*strptr)++;
881 break;
882 case ')':
883 case '\\':
884 *(dest++) = '\\';
885 *dest = c;
886 return(2);
887 default:
888 *dest = c;
890 break;
892 default:
893 *dest = c;
895 return(1);
898 /// FUNC: ScanCDFile
901 This scans the catalog description file.
903 Inputs: cdfile - name of the catalog description file
905 Result: TRUE, if successful, FALSE otherwise
907 int ScanCDFile(char *cdfile)
909 FILE *fp;
910 struct CDLine *cdline, **cdptr = &FirstCDLine;
911 struct CatString *cs, **csptr = &FirstCatString;
912 char *line, *newline;
913 char *ptr;
914 int NextID = 0, len;
915 int Result = TRUE;
917 ScanFile = cdfile;
918 ScanLine = 0;
920 if(!(fp = fopen(cdfile, "r")))
922 ShowError(msgNoCatalogDescription, cdfile);
925 if(!NoBufferedIO)
926 setvbuf(fp, NULL, _IOFBF, buffer_size);
929 Get the basename
931 if ((ptr = strchr(cdfile, ':')))
932 { cdfile = ptr+1;
934 if ((ptr = strrchr(cdfile, '/')))
935 { cdfile = ptr+1;
937 if ((ptr = strrchr(cdfile, '.')))
938 { len = ptr-cdfile;
940 else
941 { len = strlen(cdfile);
943 if (!(BaseName = malloc(len+1)))
944 { MemError();
946 strncpy(BaseName, cdfile, len);
947 BaseName[len] = '\0';
949 while(!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
951 if(!(cdline = malloc(sizeof(*cdline))))
953 MemError();
956 *cdptr = cdline;
957 cdptr = &cdline->Next;
958 cdline->Next = NULL;
959 cdline->Line = line = AllocString(newline);
960 free(newline);
962 if (*line == ';')
964 continue;
967 if(*line == '#')
969 int CheckExtra = TRUE;
971 if (strnicmp(line+1, "language", 8) == 0)
973 char *ptr;
975 line += 9;
976 OverSpace(&line);
977 Language = AllocString(line);
979 if(LANGToLower)
981 for (ptr = Language; *ptr; ptr++)
983 *ptr = tolower((int) *ptr);
985 CheckExtra = FALSE;
989 else
990 if(strnicmp(line+1, "version", 7) == 0)
992 CatVersion = strtol(line+8, &line, 0);
994 else
996 if(strnicmp(line+1, "basename", 8) == 0)
998 line += 9;
999 OverSpace(&line);
1000 free(BaseName);
1001 BaseName = AllocString(line);
1002 CheckExtra = FALSE;
1004 else
1006 ShowWarn(msgUnknownCDCommand);
1007 Result = FALSE;
1008 CheckExtra = FALSE;
1012 if(CheckExtra)
1014 OverSpace(&line);
1015 if(*line)
1017 ShowWarn(msgExtraCharacters);
1018 Result = FALSE;
1022 else
1024 char *idstr;
1026 if(*line == ' ' || *line == '\t')
1028 ShowWarn(msgUnexpectedBlanks);
1029 Result = FALSE;
1030 OverSpace(&line);
1033 idstr = line;
1034 while ((*line >= 'a' && *line <= 'z') ||
1035 (*line >= 'A' && *line <= 'Z') ||
1036 (*line >= '0' && *line <= '9') ||
1037 *line == '_')
1039 ++line;
1042 if(idstr == line)
1044 ShowWarn(msgNoIdentifier);
1045 Result = FALSE;
1047 else
1049 int found;
1051 if(!(cs = malloc(sizeof(*cs))))
1053 MemError();
1058 struct CatString *scs;
1060 found = TRUE;
1061 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1063 if(scs->ID == NextID)
1065 found = FALSE;
1066 ++NextID;
1067 break;
1071 while(!found);
1073 cs->Next = NULL;
1074 cs->ID = NextID;
1075 cs->MinLen = 0;
1076 cs->MaxLen = -1;
1077 cs->CD_Str = "";
1078 cs->CT_Str = NULL;
1079 cs->NotInCT= TRUE;
1081 if(!(cs->ID_Str = malloc((line-idstr)+1)))
1083 MemError();
1085 strncpy(cs->ID_Str, idstr, line-idstr);
1086 cs->ID_Str[line-idstr] = '\0';
1088 OverSpace(&line);
1090 if(*line != '(')
1092 ShowWarn(msgNoLeadingBracket);
1093 Result = FALSE;
1095 else
1097 char *oldstr;
1098 struct CatString *scs;
1099 char bytes[10];
1100 int bytesread, reallen;
1102 ++line;
1103 OverSpace(&line);
1104 if(*line != '/')
1106 if(*line == '+')
1108 NextID = cs->ID = NextID + strtol(line, &line, 0);
1110 else
1112 cs->ID = NextID = strtol(line, &line, 0);
1115 OverSpace(&line);
1118 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1119 { if (scs->ID == cs->ID)
1120 { ShowWarn(msgDoubleID);
1121 Result = FALSE;
1123 if (strcmp(cs->ID_Str, scs->ID_Str) == 0)
1124 { ShowWarn(msgDoubleIdentifier);
1125 Result = FALSE;
1129 if (*line != '/')
1130 { ShowWarn(msgNoMinLen);
1131 Result = FALSE;
1133 else
1134 { ++line;
1135 OverSpace(&line);
1136 if (*line != '/')
1137 { cs->MinLen = strtol(line, &line, 0);
1138 OverSpace(&line);
1140 if (*line != '/')
1141 { ShowWarn(msgNoMaxLen);
1142 Result = FALSE;
1144 else
1145 { ++line;
1146 OverSpace(&line);
1147 if (*line != ')')
1148 { cs->MaxLen = strtol(line, &line, 0);
1149 OverSpace(&line);
1151 if (*line != ')')
1152 { ShowWarn(msgNoTrailingBracket);
1153 Result = FALSE;
1155 else
1156 { ++line;
1157 OverSpace(&line);
1158 if (*line)
1159 { ShowWarn(msgExtraCharacters);
1164 if (!(newline = ReadLine(fp, FALSE)))
1165 { ShowWarn(msgNoString);
1166 Result = FALSE;
1167 cs->CD_Str = "";
1169 else
1170 { cs->CD_Str = AllocString(newline);
1171 free(newline);
1175 Get stringlen
1177 oldstr = cs->CD_Str;
1178 reallen = 0;
1179 while (*oldstr)
1180 { bytesread = ReadChar(&oldstr, bytes);
1181 if (bytesread == 2)
1182 { bytesread--;
1184 reallen += bytesread;
1187 if (cs->MinLen > 0 && reallen < cs->MinLen)
1188 { ShowWarn(msgShortString);
1190 if (cs->MaxLen > 0 && reallen > cs->MaxLen)
1191 { ShowWarn(msgLongString);
1194 cs->Nr = NumStrings;
1196 *csptr = cs;
1197 csptr = &cs->Next;
1198 ++NumStrings;
1203 fclose(fp);
1204 return(Result);
1207 /// FUNC: ScanCTFile
1210 This scans a catalog translation file.
1212 Inputs: ctfile - name of the translation file to scan.
1214 Result: TRUE, if successful, FALSE otherwise.
1216 int ScanCTFile(char *ctfile)
1218 FILE *fp;
1219 char *newline, *line, *idstr, *newidstr, *newstr;
1220 struct CatString *cs=NULL;
1221 int Result = TRUE;
1223 ScanFile = ctfile;
1224 ScanLine = 0;
1226 if (!(fp = fopen(ctfile, "r")))
1228 ShowError(msgNoCatalogTranslation, ctfile);
1231 if(!NoBufferedIO)
1232 setvbuf(fp, NULL, _IOFBF, buffer_size);
1235 while (!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
1237 switch(*line)
1239 case ';':
1240 if( CopyNEWs == TRUE )
1242 if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
1244 cs->NotInCT = TRUE;
1247 break;
1249 case '#':
1250 /// looking for command;
1251 if(*(++line) != '#')
1253 ShowWarn(msgNoCTCommand);
1255 ++line;
1256 OverSpace(&line);
1257 if (strnicmp(line, "version", 7) == 0)
1258 { if (CatVersionString || CatRcsId || CatName)
1259 { ShowWarn(msgDoubleCTVersion);
1261 line += 7;
1262 OverSpace(&line);
1263 CatVersionString = AllocString(line);
1265 else if (strnicmp(line, "codeset", 7) == 0)
1266 { line += 7;
1267 CodeSet = strtol(line, &line, 0);
1268 OverSpace(&line);
1269 if (*line)
1270 { ShowWarn(msgExtraCharacters);
1273 else if (strnicmp(line, "language", 8) == 0)
1274 { char *ptr;
1276 if (CatLanguage)
1277 { ShowWarn(msgDoubleCTLanguage);
1279 line += 8;
1280 OverSpace(&line);
1281 CatLanguage = AddCatalogChunk("LANG", line);
1283 if(LANGToLower)
1284 for (ptr = CatLanguage; *ptr; ptr++)
1285 *ptr = tolower((int) *ptr);
1287 else if (strnicmp(line, "chunk", 5) == 0)
1288 { char *ID;
1290 line += 5;
1291 OverSpace(&line);
1292 ID = line;
1293 line += sizeof(ULONG);
1294 OverSpace(&line);
1296 AddCatalogChunk(ID, AllocString(line));
1298 else if (strnicmp(line, "rcsid", 5) == 0)
1299 { if (CatVersionString || CatRcsId)
1300 { ShowWarn(msgDoubleCTVersion);
1302 line += 5;
1303 OverSpace(&line);
1304 CatRcsId = AllocString(line);
1306 else if (strnicmp(line, "name", 5) == 0)
1307 { if (CatVersionString || CatName)
1308 { ShowWarn(msgDoubleCTVersion);
1310 line += 4;
1311 OverSpace(&line);
1312 CatName = AllocString(line);
1314 else if (strnicmp(line+1, "lengthbytes", 11) == 0)
1315 { line += 12;
1316 if ((LengthBytes = strtol(line, &line, 0))
1317 > sizeof(long))
1318 { ShowWarn(msgNoLengthBytes, sizeof(long));
1319 LengthBytes = sizeof(long);
1322 else
1324 ShowWarn(msgUnknownCTCommand);
1327 break;
1329 default:
1330 if(*line == ' ' || *line == '\t')
1332 ShowWarn( msgUnexpectedBlanks );
1333 OverSpace( &line );
1335 idstr = line;
1337 while ((*line >= 'a' && *line <= 'z') ||
1338 (*line >= 'A' && *line <= 'Z') ||
1339 (*line >= '0' && *line <= '9') ||
1340 *line == '_')
1341 { ++line;
1343 if (idstr == line)
1345 ShowWarn(msgNoIdentifier);
1346 break;
1349 if(!(newidstr = malloc(line-idstr+1)))
1351 MemError();
1354 strncpy(newidstr, idstr, line-idstr);
1355 newidstr[line-idstr] = '\0';
1356 OverSpace(&line);
1358 if(*line)
1360 ShowWarn(msgExtraCharacters);
1363 if((newstr = ReadLine(fp, FALSE)))
1365 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1367 if(strcmp(cs->ID_Str, newidstr) == 0)
1369 break;
1372 if(cs == NULL)
1374 ShowWarn(msgUnknownIdentifier, newidstr);
1376 else
1378 char *oldstr;
1379 char bytes[10];
1380 int bytesread, reallen;
1382 if(cs->CT_Str)
1384 ShowWarn(msgDoubleIdentifier);
1385 Result = FALSE;
1386 free(cs->CT_Str);
1388 cs->CT_Str = AllocString(newstr);
1389 cs->NotInCT = FALSE;
1392 Get stringlen
1394 oldstr = cs->CT_Str;
1395 reallen = 0;
1396 while(*oldstr)
1398 bytesread = ReadChar(&oldstr, bytes);
1399 if(bytesread == 2)
1401 bytesread--;
1403 reallen += bytesread;
1406 if(cs->MinLen > 0 && reallen < cs->MinLen)
1408 ShowWarn(msgShortString);
1410 if(cs->MaxLen > 0 && reallen > cs->MaxLen)
1412 ShowWarn(msgLongString);
1416 // checking for trailing ellipsis...
1418 if( reallen >= 3 )
1420 long cd_len = strlen( cs->CD_Str );
1422 if( cd_len >= 3 )
1424 if( strcmp( &cs->CD_Str[ cd_len - 2 ], "..." ) == 0 )
1425 if( strcmp( &cs->CT_Str[ reallen - 2 ], "..." ) != 0 )
1427 // printf("ORG: '%s'\nNEW: '%s'\n", cs->CD_Str, cs->CT_Str);
1428 ShowWarn(msgTrailingEllipsis);
1434 // checking for trailing spaces
1436 if( reallen >= 1 )
1438 long cd_len = strlen( cs->CD_Str );
1440 if( cd_len >= 1 )
1442 if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
1443 if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
1444 ShowWarn(msgTrailingSpaces);
1450 free(newstr);
1452 else
1454 ShowWarn(msgNoString);
1455 if(cs)
1456 cs->CT_Str = "";
1458 free(newidstr);
1460 free(newline);
1463 fclose(fp);
1465 if (WarnCTGaps)
1466 { for (cs = FirstCatString; cs != NULL; cs = cs->Next)
1467 { if (cs->CT_Str == NULL)
1468 { ShowWarn(msgCTGap, cs->ID_Str);
1473 if(Result)
1474 CT_Scanned = TRUE;
1476 return(Result);
1479 /// FUNC: CatPuts
1483 CatPuts prints a string to a catalog. (The string is preceded by a
1484 long integer containing its length and probably padded up to word
1485 boundary or longword boundary, depending on the argument padbytes.)
1486 The arguments countnul should be TRUE if the NUL byte at the end of
1487 the string should be counted.
1489 int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
1491 unsigned int reallen, virtuallen, chunklen, swapped_long;
1492 int bytesread;
1493 char *oldstr;
1494 char bytes[10];
1496 /* Get Length of string.
1499 oldstr = str;
1500 reallen = 0;
1502 while(*oldstr)
1504 bytesread = ReadChar(&oldstr, bytes);
1505 if(bytesread == 2)
1507 bytesread--;
1509 reallen += bytesread;
1512 virtuallen = chunklen = reallen + LengthBytes;
1513 if(countnul || chunklen % padbytes == 0)
1515 virtuallen++;
1518 swapped_long = SwapLong( virtuallen );
1520 fwrite(&swapped_long, sizeof(virtuallen), 1, fp);
1521 if(LengthBytes)
1523 fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
1526 while(*str)
1528 bytesread = ReadChar(&str, bytes);
1529 if(bytesread)
1531 fwrite(bytes+bytesread-1, 1, 1, fp);
1537 putc('\0', fp);
1539 while(++chunklen % padbytes);
1541 return((int) chunklen+4);
1544 /// FUNC: PutCatalogChunk
1547 This puts a string chunk into the catalog
1549 int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
1551 fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
1552 return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
1555 /// FUNC: CalcRealLength
1557 This function measures the real (binary) length of source
1558 string. It correctly process 'slash chars' (\n, \000 etc),
1559 and gives the real length such source string have.
1561 Inputs: source - pointer to null terminated source string
1563 Result: real length
1566 int CalcRealLength(char *source)
1568 int count = 0;
1569 char *src = source;
1570 char bytes[10];
1572 while(*src)
1574 count += ReadChar(&src, bytes);
1577 // printf("%ld: '%s'\n", count, source);
1579 return(count);
1584 /// FUNC: CreateCatalog
1587 This creates a catalog.
1589 void CreateCat(char *CatFile)
1591 FILE *fp;
1592 int CatLen, HeadLen;
1593 struct CatString *cs;
1594 struct CatalogChunk *cc;
1595 int i;
1597 if(!CatVersionString && !CatRcsId)
1599 ShowError(msgNoCTVersion);
1602 if(!CatLanguage)
1604 ShowError(msgNoCTLanguage);
1607 if(strlen(CatLanguage) == 0)
1609 ShowError(msgNoCTLanguage);
1612 if(!(fp = fopen(CatFile, "w")))
1614 ShowError(msgNoCatalog, CatFile);
1617 if(!NoBufferedIO)
1618 setvbuf(fp, NULL, _IOFBF, buffer_size);
1621 fputs("FORM0000CTLG", fp);
1622 CatLen = 4;
1624 if(CatVersionString)
1626 struct CatalogChunk cc;
1627 char *verStr = NULL;
1629 cc.ID = MAKE_ID('F','V','E','R');
1631 if( strstr(CatVersionString, "$TODAY") )
1634 if(verStr = malloc(strlen(CatVersionString)+128))
1636 char *found = strstr(CatVersionString, "$TODAY");
1637 char dateStr[10];
1639 long tim;
1640 struct tm *t;
1642 time(&tim);
1643 t = gmtime(&tim);
1645 *found = 0;
1646 strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
1648 sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
1649 cc.ChunkStr = verStr;
1651 else
1652 MemError();
1655 else
1657 cc.ChunkStr = CatVersionString;
1660 cc.ID = SwapLong( cc.ID );
1661 CatLen += PutCatalogChunk(fp, &cc);
1663 if( verStr )
1664 free(verStr);
1666 else
1668 struct CatalogChunk cc;
1669 char* verStr;
1670 int year = 0, month = 0, day = 0;
1671 int version = 0, revision = 0;
1672 char* name = NULL;
1673 char* ptr;
1675 if(!CatRcsId)
1677 ShowError(msgNoCTVersion);
1679 else
1681 if(!(ptr = strstr(CatRcsId, "$Date:"))
1682 || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
1683 || !(ptr = strstr(CatRcsId, "$Revision:"))
1684 || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
1686 ShowError(msgWrongRcsId);
1688 if ((ptr = strstr(CatRcsId, "$Id:")))
1689 { int len = 0;
1690 char* found;
1692 ptr += 4;
1693 OverSpace(&ptr);
1694 found = ptr;
1696 while(*ptr && *ptr != '$' && *ptr != ' ' && *ptr != '\t')
1698 ++len;
1699 ++ptr;
1701 if(!(name = malloc(len+1)))
1703 MemError();
1705 strncpy(name, found, len);
1706 name[len] = '\0';
1709 if (CatName)
1710 { name = CatName;
1712 else if (!name)
1714 ShowError(msgNoCTVersion);
1715 name = "";
1717 if (!(verStr = malloc(strlen(name) + 256)))
1719 MemError();
1722 sprintf( verStr, "$V");
1723 sprintf( verStr, "ER: %s %ld.%ld (%ld.%ld.%ld)"
1724 , name, (long)version, (long)revision, (long)day, (long)month, (long)year);
1726 cc.ID = MAKE_ID('F','V','E','R');
1727 cc.ID = SwapLong( cc.ID );
1728 cc.ChunkStr = verStr;
1729 CatLen += PutCatalogChunk(fp, &cc);
1733 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1735 CatLen += PutCatalogChunk(fp, cc);
1738 i = 32;
1739 fputs("CSET", fp);
1742 int i_tmp = SwapLong( i );
1744 fwrite(&i_tmp, sizeof(i_tmp), 1, fp);
1747 while(i-- > 0)
1749 putc('\0', fp);
1752 CatLen += 48;
1753 fprintf(fp, "STRS0000");
1754 HeadLen = CatLen;
1757 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1759 int FillUsed = FALSE;
1760 int tmp_ID = SwapLong( cs->ID );
1762 if(Fill)
1765 if(cs->CT_Str)
1767 if(strlen(cs->CT_Str) == 0)
1769 fwrite(&tmp_ID, sizeof(tmp_ID), 1, fp);
1770 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1771 FillUsed = TRUE;
1774 else
1776 fwrite(&tmp_ID, sizeof(cs->ID), 1, fp);
1777 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1778 FillUsed = TRUE;
1782 if((!FillUsed) && cs->CT_Str && (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
1784 fwrite(&tmp_ID, sizeof( tmp_ID ), 1, fp);
1785 CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
1791 int tmp_Len;
1793 fseek(fp, 4, SEEK_SET);
1795 tmp_Len = SwapLong( CatLen );
1796 fwrite(&tmp_Len, sizeof(tmp_Len), 1, fp);
1797 fseek(fp, HeadLen-4, SEEK_CUR);
1799 CatLen -= HeadLen;
1800 tmp_Len = SwapLong( CatLen );
1801 fwrite(&tmp_Len, sizeof(CatLen), 1, fp);
1804 fclose(fp);
1806 Expunge();
1810 /// FUNC: CreateCTFile
1813 This creates a new catalog translation file.
1815 void CreateCTFile(char *NewCTFile)
1817 FILE *fp;
1818 struct CDLine *cd;
1819 struct CatString *cs;
1820 struct CatalogChunk *cc;
1821 char *line;
1823 if(!CatVersionString && !CatRcsId)
1825 ScanLine = 1;
1826 ShowWarn(msgNoCTVersion);
1829 if(!(fp = fopen(NewCTFile, "w")))
1831 ShowError(msgNoNewCTFile);
1835 if(!NoBufferedIO)
1836 setvbuf(fp, NULL, _IOFBF, buffer_size);
1839 if(CatRcsId)
1841 fprintf(fp, "## rcsid %s\n",
1842 CatRcsId ? CatRcsId : "");
1843 if(CatName)
1844 fprintf(fp, "## name %s\n", CatName);
1846 else
1848 if(CatVersionString)
1849 fprintf(fp, "## version %s\n", CatVersionString);
1850 else
1852 fprintf(fp, "## version $V");
1853 fprintf(fp, "%c", 50+19); // E
1854 fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
1860 char *lang = NULL;
1862 if(CatLanguage == NULL)
1863 if(lang = getenv("ENV:language"))
1865 int i;
1867 for(i=0;i<strlen(lang); i++)
1868 if(lang[i] == '\n')
1870 lang[i] = 0;
1871 break;
1874 CatLanguage = lang;
1877 fprintf(fp, "## language %s\n## codeset %d\n;\n",
1878 CatLanguage ? CatLanguage : "X", CodeSet);
1880 if(lang)
1882 free(lang);
1883 CatLanguage = NULL;
1889 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1891 if (cc->ChunkStr != CatLanguage)
1893 fprintf(fp, "## chunk ");
1894 fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
1895 fprintf(fp, " %s\n", cc->ChunkStr);
1899 for(cd = FirstCDLine, cs = FirstCatString;
1900 cd != NULL;
1901 cd = cd->Next)
1903 switch(*cd->Line)
1905 case '#':
1906 break;
1908 case ';':
1909 fprintf(fp, "%s\n", cd->Line);
1910 break;
1912 default:
1913 if(cs)
1916 fprintf(fp, "%s\n", cs->ID_Str);
1917 fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
1918 putc(';', fp);
1919 putc(' ', fp);
1921 fprintf(fp, "%s\n%s\n;", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
1923 if( !NoSpace )
1924 putc(' ', fp);
1928 for (line = cs->CD_Str; *line; ++line)
1930 putc((int) *line, fp);
1931 if(*line == '\n')
1933 putc(';', fp);
1934 if( !NoSpace )
1935 putc(' ', fp);
1938 putc('\n', fp);
1940 if(cs->NotInCT && CT_Scanned)
1941 fprintf(fp, ";\n; %s\n", Msg_New);
1943 cs = cs->Next;
1948 fclose(fp);
1952 /// FUNC: InitCatStringOutput
1955 InitCatStringOutput gets called before writing a catalog string as
1956 source.
1958 Inputs: fp = file pointer to the output file
1959 type = one of TYPE_C create C strings
1960 TYPE_ASSEMBLER create Assembler strings
1961 TYPE_OBERON create Oberon strings
1962 TYPE_E create E strings
1963 TYPE_NONE create simple strings
1965 int OutputMode = OutputMode_None;
1966 int OutputType = TYPE_C;
1967 FILE *OutputFile;
1968 int OutputLen;
1970 void InitCatStringOutput(FILE *fp)
1972 OutputLen = 0;
1973 OutputFile = fp;
1974 OutputMode = OutputMode_None;
1975 switch(OutputType)
1976 { case TYPE_C:
1977 case TYPE_OBERON:
1978 putc('\"', fp);
1979 OutputMode = OutputMode_Ascii;
1980 break;
1981 case TYPE_E:
1982 putc('\'', fp);
1983 case TYPE_ASSEMBLER:
1984 case TYPE_NONE:
1985 break;
1989 /// FUNC: SeparateCatStringOutput
1992 SeparateCatStringOutput gets called to split a catalog into separate
1993 lines.
1995 void SeparateCatStringOutput(void)
1997 switch(OutputType)
1998 { case TYPE_C:
1999 if (!LongStrings)
2000 { fputs("\"\\\n\t\"", OutputFile);
2002 break;
2003 case TYPE_E:
2004 if (!LongStrings)
2005 { fputs("\' +\n\t\'", OutputFile);
2007 break;
2008 case TYPE_OBERON:
2009 if (!LongStrings)
2010 { fputs("\"\n\t\"", OutputFile);
2012 break;
2013 case TYPE_ASSEMBLER:
2014 if (!LongStrings)
2015 { if (OutputMode == OutputMode_Ascii)
2016 { putc('\'', OutputFile);
2018 putc('\n', OutputFile);
2019 OutputMode = OutputMode_None;
2021 break;
2022 case TYPE_NONE:
2023 break;
2027 /// FUNC: WriteBinChar
2030 WriteBinChar writes one binary character into the source file
2032 void WriteBinChar(int c)
2035 switch(OutputType)
2036 { case TYPE_C:
2037 case TYPE_E:
2038 case TYPE_OBERON:
2039 switch(c)
2040 { case '\b':
2041 fputs("\\b", OutputFile);
2042 break;
2043 case '\n':
2044 fputs("\\n", OutputFile);
2045 break;
2046 case '\r':
2047 fputs("\\r", OutputFile);
2048 break;
2049 case '\t':
2050 fputs("\\t", OutputFile);
2051 break;
2052 case '\f':
2053 fputs("\\f", OutputFile);
2054 break;
2055 case '\0':
2056 fputs("\\000", OutputFile);
2057 break;
2058 default:
2059 if(OutputType == TYPE_E && c == '\033')
2061 fputs("\\e", OutputFile);
2063 else
2065 fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
2066 ((c >> 3) & 7) + '0', (c & 7) + '0');
2068 break;
2070 ++OutputLen;
2071 OutputMode = OutputMode_Bin;
2072 break;
2073 case TYPE_ASSEMBLER:
2074 switch(OutputMode)
2075 { case OutputMode_None:
2076 fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
2077 break;
2078 case OutputMode_Ascii:
2079 putc('\'', OutputFile);
2080 case OutputMode_Bin:
2081 fprintf(OutputFile, ",$%02x", c & 0xff);
2082 break;
2084 ++OutputLen;
2085 OutputMode = OutputMode_Bin;
2086 break;
2087 case TYPE_NONE:
2088 ShowWarn(msgNoBinChars);
2089 break;
2093 /// FUNC: WriteAsciiChar
2096 WriteAsciiChar writes one ascii character into the source file.
2098 void WriteAsciiChar(int c)
2101 switch(OutputType)
2102 { case TYPE_C:
2103 case TYPE_OBERON:
2104 switch(c)
2105 { case '\"':
2106 fputs("\\\"", OutputFile);
2107 break;
2108 default:
2109 putc(c, OutputFile);
2110 break;
2112 ++OutputLen;
2113 OutputMode = OutputMode_Ascii;
2114 break;
2115 case TYPE_E:
2116 switch(c)
2117 { case '\'':
2118 fputs("''", OutputFile);
2119 break;
2120 default:
2121 putc(c, OutputFile);
2122 break;
2124 ++OutputLen;
2125 OutputMode = OutputMode_Ascii;
2126 break;
2127 case TYPE_ASSEMBLER:
2128 if (c == '\'')
2129 { WriteBinChar(c);
2131 else
2132 { switch (OutputMode)
2133 { case OutputMode_None:
2134 fprintf(OutputFile, "\tdc.b\t\'%c", c);
2135 break;
2136 case OutputMode_Ascii:
2137 putc(c, OutputFile);
2138 break;
2139 case OutputMode_Bin:
2140 fprintf(OutputFile, ",\'%c", c);
2141 break;
2143 ++OutputLen;
2144 OutputMode = OutputMode_Ascii;
2146 break;
2147 case TYPE_NONE:
2148 putc(c, OutputFile);
2149 break;
2153 /// FUNC: TerminateCatStringOutput
2156 TerminateCatStringOutput finishs the output of a catalog string.
2158 void TerminateCatStringOutput(void)
2160 switch(OutputType)
2161 { case TYPE_C:
2162 case TYPE_OBERON:
2163 putc('\"', OutputFile);
2164 break;
2165 case TYPE_E:
2166 putc('\'', OutputFile);
2167 break;
2168 case TYPE_ASSEMBLER:
2169 switch(OutputMode)
2170 { case OutputMode_Ascii:
2171 putc('\'', OutputFile);
2172 case OutputMode_Bin:
2173 break;
2174 case OutputMode_None:
2175 break;
2177 case TYPE_NONE:
2178 break;
2183 /// FUNC: WriteString
2185 This writes a sourcestring.
2187 void WriteString(FILE *fpout, char *str, long Len)
2189 char bytes[10];
2190 int bytesread;
2191 int needseparate = FALSE;
2193 InitCatStringOutput(fpout);
2194 if (Len >= 0)
2195 { int i;
2197 for(i = LengthBytes; i >= 1; i--)
2198 { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
2202 while (*str)
2203 { bytesread = ReadChar(&str, bytes);
2204 if (bytesread)
2205 { unsigned char c;
2207 if (needseparate)
2208 { SeparateCatStringOutput();
2209 needseparate = FALSE;
2212 c = bytes[bytesread-1];
2213 if ((c >= 0x20 && c < 0x7f) || c >= 0xa0)
2214 { WriteAsciiChar((int) c);
2216 else
2217 { WriteBinChar((int) c);
2220 else
2221 { needseparate = TRUE;
2224 TerminateCatStringOutput();
2227 /// FUNC: AllocFileName
2229 This function creates a copy of a filename, removes an
2230 optional ending and pathname components, if desired.
2232 Inputs: filename - the filename to copy
2233 howto - a set of bits
2234 bit 0: 1 = remove ending, 0 = leave it
2235 bit 1: 1 = remove pathname, 0 = leave it
2237 Result: The copy of the filename
2239 char *AllocFileName(char *filename, int howto)
2241 char *tempstr, *ptr;
2243 if (!(tempstr = strdup(filename)))
2244 { MemError();
2245 MyExit(10);
2248 /* Remove pathname components, if desired */
2249 if (howto & 2)
2250 { if ((ptr = strchr(tempstr, ':')))
2251 { tempstr = ptr+1;
2253 if ((ptr = strrchr(tempstr, '/')))
2254 { tempstr = ptr+1;
2258 /* Remove ending, if desired. */
2259 if (howto & 1)
2260 { if ((ptr = strrchr(tempstr, '.')))
2261 { *ptr = '\0';
2265 return(tempstr);
2268 /// FUNC: AddFileName
2270 This function adds a pathname and a filename to a full
2271 filename.
2273 Inputs: pathname - the leading pathname
2274 filename - the filename
2276 Result: The new filename
2278 char *AddFileName(char *pathname, char *filename)
2280 char *buffer;
2281 int size = strlen(pathname) + strlen(filename) + 2;
2283 if (!(buffer = malloc(size)))
2284 { MemError();
2285 MyExit(10);
2288 #if defined(__amigados)
2289 strcpy(buffer, pathname);
2290 AddPart((char *) buffer, (char *) filename, size);
2291 #else
2292 sprintf(buffer, "%s/%s", pathname, filename);
2293 #endif
2295 return(buffer);
2299 /// FUNC: CreateSourceFile
2302 Finally the source creation.
2304 void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
2307 FILE *fpin, *fpout;
2308 char *line;
2309 char *OrigTemplateFile = TemplateFile;
2311 ScanFile = SourceFile;
2312 ScanLine = 0;
2315 Open the source file. This may be found in various places
2317 if(!(fpin = fopen(TemplateFile, "r")))
2319 #ifdef __amigados
2320 if(*prefs_sddir != 0)
2322 TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
2323 fpin = fopen(TemplateFile, "r");
2325 #endif
2328 if(!fpin)
2330 char *sddir;
2332 if((sddir = getenv(FLEXCAT_SDDIR)))
2334 TemplateFile = AddFileName(sddir, OrigTemplateFile);
2335 fpin = fopen(TemplateFile, "r");
2339 if (!fpin)
2340 { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
2341 fpin = fopen(TemplateFile, "r");
2344 if (!fpin)
2346 ShowError(msgNoSourceDescription, OrigTemplateFile);
2347 return;
2350 if (!(fpout = fopen(SourceFile, "w")))
2352 ShowError(msgNoSource, SourceFile);
2353 return;
2356 if(!NoBufferedIO)
2357 setvbuf(fpin, NULL, _IOFBF, buffer_size);
2358 if(!NoBufferedIO)
2359 setvbuf(fpout, NULL, _IOFBF, buffer_size);
2362 while(!feof(fpin) && (line = ReadLine(fpin, FALSE)))
2363 { struct CatString *cs;
2364 int NeedRepeat;
2365 char bytes[10];
2366 int bytesread;
2368 cs = FirstCatString;
2370 { char *currentline = line;
2371 NeedRepeat = FALSE;
2373 if (*currentline == '#' && *(++currentline) == '#')
2374 { ++currentline;
2375 OverSpace(&currentline);
2377 if(strnicmp( currentline, "rem", 3 ) == 0)
2379 // we just skip this line
2380 continue;
2383 if (strnicmp(currentline, "stringtype", 10) == 0)
2384 { currentline += 10;
2385 OverSpace(&currentline);
2386 if (strnicmp(currentline, "c", 1) == 0)
2387 { OutputType = TYPE_C;
2388 ++currentline;
2390 else if (strnicmp(currentline, "assembler", 9) == 0)
2391 { OutputType = TYPE_ASSEMBLER;
2392 currentline += 9;
2394 else if (strnicmp(currentline, "oberon", 6) == 0)
2395 { OutputType = TYPE_OBERON;
2396 currentline += 6;
2398 else if (strnicmp(currentline, "e", 1) == 0)
2399 { OutputType = TYPE_E;
2400 ++currentline;
2402 else if (strnicmp(currentline, "none", 4) == 0)
2403 { OutputType = TYPE_NONE;
2404 currentline += 4;
2406 else
2407 { ShowWarn(msgUnknownStringType);
2408 currentline += strlen(currentline);
2410 OverSpace(&currentline);
2411 if (*currentline)
2412 { ShowWarn(msgExtraCharacters);
2414 continue;
2416 else if (strnicmp(currentline, "shortstrings", 12) == 0)
2417 { currentline += 12;
2418 LongStrings = FALSE;
2419 OverSpace(&currentline);
2420 if (*currentline)
2421 { ShowWarn(msgExtraCharacters);
2423 continue;
2427 currentline = line;
2428 while(*currentline)
2429 { bytesread = ReadChar(&currentline, bytes);
2430 if (bytesread)
2431 { if (*bytes == '%')
2432 { char c;
2434 switch(c = *(currentline++))
2435 { case 'b':
2436 fputs(BaseName, fpout);
2437 break;
2438 case 'n':
2439 fprintf(fpout, "%d", NumStrings);
2440 break;
2441 case 'v':
2442 fprintf(fpout, "%d", CatVersion);
2443 break;
2444 case 'l':
2445 WriteString(fpout, Language, -1);
2446 break;
2447 case 'f':
2448 { char *tempstr;
2450 if ((c = *currentline++) == 'v')
2451 { fputs(VERS, fpout);
2453 else
2454 { tempstr = AllocFileName(CDFile, c - '0');
2455 fputs(tempstr, fpout);
2458 break;
2459 case 'o':
2460 { char *tempstr;
2462 tempstr = AllocFileName(SourceFile, *currentline++ - '0');
2463 fputs(tempstr, fpout);
2465 break;
2466 case 'i':
2467 NeedRepeat = TRUE;
2468 if (cs) fputs(cs->ID_Str, fpout);
2469 break;
2471 case 'a':
2472 case 't':
2474 case 'd':
2475 case 'x':
2476 case 'c':
2477 case '0':
2478 case '1':
2479 case '2':
2480 case '3':
2481 case '4':
2482 case '5':
2483 case '6':
2484 case '7':
2485 case '8':
2486 case '9':
2488 int len = 0;
2490 while(c >= '0' && c <= '9')
2492 len = (c - '0') + len * 10;
2493 c = *currentline++;
2497 if(c == 'a')
2499 int _len = len ? len : 4;
2500 char *start;
2501 char _StrLen[20 + 1];
2503 sprintf(_StrLen, "%020lx", (long)(cs->ID));
2505 start = &_StrLen[20-_len*2];
2506 while(_len>0)
2508 fprintf(fpout, "\\x%.2s", start);
2509 start+=2;
2510 _len--;
2514 if(c == 't')
2516 int _len = len ? len : 4;
2517 char *start;
2518 char _StrLen[20 + 1];
2520 sprintf(_StrLen, "%020lx", (long)((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
2522 start = &_StrLen[20-_len*2];
2523 while(_len>0)
2525 fprintf(fpout, "\\x%.2s", start);
2526 start+=2;
2527 _len--;
2531 if(c == 'c' || c == 'd' || c == 'x')
2533 char buffer[20];
2535 if(c == 'c') c = 'o';
2537 if(len)
2538 sprintf(buffer, "%%0%d%c", len, c);
2539 else
2540 sprintf(buffer, "%%%c", c);
2542 if(cs) fprintf(fpout, buffer, cs->ID);
2546 NeedRepeat = TRUE;
2548 break;
2550 case 'e':
2551 NeedRepeat = TRUE;
2552 if (cs) fprintf(fpout, "%d", cs->Nr);
2553 break;
2554 case 's':
2555 NeedRepeat = TRUE;
2556 if (cs)
2557 { char *idstr;
2558 unsigned long len = 0;
2560 if (LengthBytes)
2561 { idstr = cs->CD_Str;
2562 while(*idstr)
2563 { bytesread = ReadChar(&idstr, bytes);
2564 if (bytesread)
2565 { ++len;
2569 WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
2571 break;
2572 case '(':
2573 NeedRepeat = TRUE;
2574 while(*currentline && *currentline != ')')
2575 { bytesread = ReadChar(&currentline, bytes);
2576 if (bytesread && cs && cs->Next)
2577 { putc((int) bytes[bytesread-1], fpout);
2580 if (!*currentline)
2581 { ShowWarn(msgNoTerminateBracket);
2583 else
2584 { ++currentline;
2586 break;
2588 // !!!! FIX !!!!
2590 case 'z':
2592 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
2594 NeedRepeat = TRUE;
2596 while(diff > 0)
2598 fprintf(fpout, "\\x00");
2599 diff--;
2602 break;
2605 default:
2606 { int c = *currentline++;
2608 putc(c, fpout);
2612 else
2613 { putc((int) bytes[bytesread-1], fpout);
2617 putc('\n', fpout);
2619 while(NeedRepeat && cs && (cs = cs->Next));
2621 free(line);
2624 fclose(fpin);
2625 fclose(fpout);
2629 /// FUNC: Usage
2631 The Usage function describes the programs calling syntax.
2633 void Usage(void)
2636 fputs((char *) msgUsageHead, stderr);
2637 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);
2638 fprintf(stderr, "%s\n%s\n%s\n%s\n", msgUsage, msgUsage_2, msgUsage_3, msgUsage_4 );
2639 fprintf(stderr, "\n\n%s"
2641 #ifdef _M68040
2642 " [040]"
2643 #else
2644 #ifdef _M68060
2645 " [060]"
2646 #else
2647 #ifdef _M68030
2648 " [030]"
2649 #else
2650 #ifdef _M68020
2651 " [020]"
2652 #else
2653 #ifdef _M68010
2654 " [010]"
2655 #endif
2656 #endif
2657 #endif
2658 #endif
2659 #endif
2661 "\n", VString);
2664 fprintf(stderr, "%s\n", EString);
2665 MyExit(5);
2668 /// FUNC: main
2670 Finally the main function. Does nothing special except for scanning
2671 the arguments.
2673 int main(int argc, char *argv [])
2675 char *cdfile, *ctfile, *newctfile, *catalog;
2676 char *source, *template;
2677 int i;
2679 if(argc == 0) /* Aztec's entry point for workbench programs */
2681 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2682 fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
2683 fprintf(stderr, "for more information\n");
2684 exit(5);
2687 cdfile = ctfile = newctfile = catalog = NULL;
2690 /* let's open catalog files by hand if necessary */
2691 /* should be done automatically anyway for most */
2692 /* cases, but, that depends on compiler... */
2694 #if defined(_DCC)
2695 // STATIC __autoinit VOID _STIOpenFlexCatCatalog(VOID)
2696 #elif defined(__SASC)
2697 // VOID _STIOpenFlexCatCatalog(VOID)
2698 #elif defined(__GNUC__)
2699 // VOID _STIOpenFlexCatCatalog(VOID)
2700 #elif defined(__INTEL_COMPILER)
2701 // VOID _STIOpenFlexCatCatalog(VOID)
2702 #else
2703 OpenFlexCatCatalog(); /* no autoopen. we do it then */
2704 #endif
2707 // Big Endian vs Little Endian (both supported ;-)
2708 if( !SwapChoose() )
2710 fprintf(stderr, "FlexCat is unable to determine the\n");
2711 fprintf(stderr, "the byte order used by your system.\n");
2712 fprintf(stderr, "It's neither Little nor Big Endian?!.\n");
2713 exit(5);
2718 #if defined(__amigados)
2719 ReadPrefs();
2720 #endif
2722 if(argc == 1)
2724 Usage();
2727 for (i = 1; i < argc; i++)
2729 if(strnicmp (argv[i], "catalog=", 8) == 0)
2731 catalog = argv[i] + 8;
2733 else
2734 if(stricmp (argv[i], "catalog") == 0)
2736 if(i+1 == argc)
2737 Usage();
2738 catalog = argv[++i];
2740 else
2741 if(stricmp(argv[i], "nooptim") == 0)
2743 NoOptim = TRUE;
2745 else
2746 if(stricmp(argv[i], "fill") == 0)
2748 Fill = TRUE;
2750 else
2751 if(stricmp(argv[i], "quiet") == 0)
2753 Quiet = TRUE;
2755 else
2756 if(stricmp(argv[i], "flush") == 0)
2758 DoExpunge = TRUE;
2760 else
2761 if(stricmp(argv[i], "nobeep") == 0)
2763 NoBeep = TRUE;
2765 else
2766 if(stricmp(argv[i], "nobufferedio") == 0)
2768 NoBufferedIO = TRUE;
2770 else
2771 if (strnicmp (argv[i], "newctfile=", 10) == 0)
2773 newctfile = argv[i] + 10;
2775 else
2776 if(strnicmp (argv[i], "newctfile", 9) == 0)
2778 if (i+1 == argc)
2779 Usage();
2780 newctfile = argv[++i];
2782 else
2783 if(stricmp(argv[i], "nolangtolower") == 0)
2785 LANGToLower = FALSE;
2787 else
2788 if(stricmp(argv[i], "modified") == 0)
2790 Modified = TRUE;
2792 else
2793 if(stricmp(argv[i], "warnctgaps") == 0)
2795 WarnCTGaps = TRUE;
2797 else
2798 if(stricmp(argv[i], "copymsgnew") == 0)
2800 CopyNEWs = TRUE;
2802 else
2803 if(stricmp(argv[i], "nospace") == 0)
2805 NoSpace = TRUE;
2807 else
2808 if(stricmp(argv[i], "oldmsgnew") == 0)
2810 sprintf( Old_Msg_New, "; %s", argv[++i] );
2812 else
2813 if(cdfile == NULL)
2815 if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
2817 Usage();
2819 if(!ScanCDFile(cdfile = argv[i]))
2821 MyExit(10);
2824 else
2825 if(strchr(argv[i], '='))
2827 source = AllocString(argv[i]);
2828 *(template = strchr(source, '=')) = '\0';
2829 ++template;
2831 CreateSourceFile(source, template, cdfile);
2833 else
2835 if (ctfile)
2837 Usage();
2839 ctfile = argv[i];
2844 #if defined(__amigados)
2845 if(Modified)
2847 if(cdfile && ctfile && catalog)
2849 long cd_time, ct_time, cat_time;
2851 if((cd_time = getft(cdfile)) != -1)
2853 if((ct_time = getft(ctfile)) != -1)
2855 if((cat_time = getft(catalog)) == -1)
2856 cat_time = 0;
2858 if((cat_time > ct_time) &&
2859 (cat_time > cd_time))
2861 if(!Quiet)
2863 fprintf(stderr, (char *) msgUpToDate, catalog);
2864 putc('\n', stderr);
2867 MyExit(GlobalReturnCode);
2869 else
2871 if(!Quiet)
2873 fprintf(stderr, "--> %s", catalog);
2874 putc('\n', stderr);
2878 else
2880 ShowError(msgCantCheckDate, ctfile);
2883 else
2885 ShowError(msgCantCheckDate, cdfile);
2889 #endif
2891 if(ctfile)
2893 if(!ScanCTFile(ctfile))
2894 MyExit(10);
2897 if(catalog)
2899 if(!ctfile)
2901 fprintf(stderr, "%s\n", (char *) msgNoCTArgument);
2902 Usage();
2904 CreateCat(catalog);
2907 if(newctfile)
2909 CreateCTFile(newctfile);
2912 MyExit(GlobalReturnCode);
2915 /// FUNC: wbmain
2918 Dice's entry point for workbench programs
2920 #if defined(__amigados) && defined(_DCC)
2921 void wbmain(struct WBStartup *wbmsg)
2923 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2924 fprintf(stderr, "Open a Shell session and type FlexCat\n");
2925 fprintf(stderr, "for syntax and more information\n");
2927 exit(5);
2929 #endif