Fixes for compiling on 64bit and outside the source dir
[AROS.git] / tools / FlexCat / flexcat.c
blob5c6fee845cdbaf6026842fa255bc5731dd5eb47d
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)", name, version, revision, day, month, year);
1725 cc.ID = MAKE_ID('F','V','E','R');
1726 cc.ID = SwapLong( cc.ID );
1727 cc.ChunkStr = verStr;
1728 CatLen += PutCatalogChunk(fp, &cc);
1732 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1734 CatLen += PutCatalogChunk(fp, cc);
1737 i = 32;
1738 fputs("CSET", fp);
1741 int i_tmp = SwapLong( i );
1743 fwrite(&i_tmp, sizeof(i_tmp), 1, fp);
1746 while(i-- > 0)
1748 putc('\0', fp);
1751 CatLen += 48;
1752 fprintf(fp, "STRS0000");
1753 HeadLen = CatLen;
1756 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1758 int FillUsed = FALSE;
1759 int tmp_ID = SwapLong( cs->ID );
1761 if(Fill)
1764 if(cs->CT_Str)
1766 if(strlen(cs->CT_Str) == 0)
1768 fwrite(&tmp_ID, sizeof(tmp_ID), 1, fp);
1769 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1770 FillUsed = TRUE;
1773 else
1775 fwrite(&tmp_ID, sizeof(cs->ID), 1, fp);
1776 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1777 FillUsed = TRUE;
1781 if((!FillUsed) && cs->CT_Str && (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
1783 fwrite(&tmp_ID, sizeof( tmp_ID ), 1, fp);
1784 CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
1790 int tmp_Len;
1792 fseek(fp, 4, SEEK_SET);
1794 tmp_Len = SwapLong( CatLen );
1795 fwrite(&tmp_Len, sizeof(tmp_Len), 1, fp);
1796 fseek(fp, HeadLen-4, SEEK_CUR);
1798 CatLen -= HeadLen;
1799 tmp_Len = SwapLong( CatLen );
1800 fwrite(&tmp_Len, sizeof(CatLen), 1, fp);
1803 fclose(fp);
1805 Expunge();
1809 /// FUNC: CreateCTFile
1812 This creates a new catalog translation file.
1814 void CreateCTFile(char *NewCTFile)
1816 FILE *fp;
1817 struct CDLine *cd;
1818 struct CatString *cs;
1819 struct CatalogChunk *cc;
1820 char *line;
1822 if(!CatVersionString && !CatRcsId)
1824 ScanLine = 1;
1825 ShowWarn(msgNoCTVersion);
1828 if(!(fp = fopen(NewCTFile, "w")))
1830 ShowError(msgNoNewCTFile);
1834 if(!NoBufferedIO)
1835 setvbuf(fp, NULL, _IOFBF, buffer_size);
1838 if(CatRcsId)
1840 fprintf(fp, "## rcsid %s\n",
1841 CatRcsId ? CatRcsId : "");
1842 if(CatName)
1843 fprintf(fp, "## name %s\n", CatName);
1845 else
1847 if(CatVersionString)
1848 fprintf(fp, "## version %s\n", CatVersionString);
1849 else
1851 fprintf(fp, "## version $V");
1852 fprintf(fp, "%c", 50+19); // E
1853 fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
1859 char *lang = NULL;
1861 if(CatLanguage == NULL)
1862 if(lang = getenv("ENV:language"))
1864 int i;
1866 for(i=0;i<strlen(lang); i++)
1867 if(lang[i] == '\n')
1869 lang[i] = 0;
1870 break;
1873 CatLanguage = lang;
1876 fprintf(fp, "## language %s\n## codeset %d\n;\n",
1877 CatLanguage ? CatLanguage : "X", CodeSet);
1879 if(lang)
1881 free(lang);
1882 CatLanguage = NULL;
1888 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1890 if (cc->ChunkStr != CatLanguage)
1892 fprintf(fp, "## chunk ");
1893 fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
1894 fprintf(fp, " %s\n", cc->ChunkStr);
1898 for(cd = FirstCDLine, cs = FirstCatString;
1899 cd != NULL;
1900 cd = cd->Next)
1902 switch(*cd->Line)
1904 case '#':
1905 break;
1907 case ';':
1908 fprintf(fp, "%s\n", cd->Line);
1909 break;
1911 default:
1912 if(cs)
1915 fprintf(fp, "%s\n", cs->ID_Str);
1916 fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
1917 putc(';', fp);
1918 putc(' ', fp);
1920 fprintf(fp, "%s\n%s\n;", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
1922 if( !NoSpace )
1923 putc(' ', fp);
1927 for (line = cs->CD_Str; *line; ++line)
1929 putc((int) *line, fp);
1930 if(*line == '\n')
1932 putc(';', fp);
1933 if( !NoSpace )
1934 putc(' ', fp);
1937 putc('\n', fp);
1939 if(cs->NotInCT && CT_Scanned)
1940 fprintf(fp, ";\n; %s\n", Msg_New);
1942 cs = cs->Next;
1947 fclose(fp);
1951 /// FUNC: InitCatStringOutput
1954 InitCatStringOutput gets called before writing a catalog string as
1955 source.
1957 Inputs: fp = file pointer to the output file
1958 type = one of TYPE_C create C strings
1959 TYPE_ASSEMBLER create Assembler strings
1960 TYPE_OBERON create Oberon strings
1961 TYPE_E create E strings
1962 TYPE_NONE create simple strings
1964 int OutputMode = OutputMode_None;
1965 int OutputType = TYPE_C;
1966 FILE *OutputFile;
1967 int OutputLen;
1969 void InitCatStringOutput(FILE *fp)
1971 OutputLen = 0;
1972 OutputFile = fp;
1973 OutputMode = OutputMode_None;
1974 switch(OutputType)
1975 { case TYPE_C:
1976 case TYPE_OBERON:
1977 putc('\"', fp);
1978 OutputMode = OutputMode_Ascii;
1979 break;
1980 case TYPE_E:
1981 putc('\'', fp);
1982 case TYPE_ASSEMBLER:
1983 case TYPE_NONE:
1984 break;
1988 /// FUNC: SeparateCatStringOutput
1991 SeparateCatStringOutput gets called to split a catalog into separate
1992 lines.
1994 void SeparateCatStringOutput(void)
1996 switch(OutputType)
1997 { case TYPE_C:
1998 if (!LongStrings)
1999 { fputs("\"\\\n\t\"", OutputFile);
2001 break;
2002 case TYPE_E:
2003 if (!LongStrings)
2004 { fputs("\' +\n\t\'", OutputFile);
2006 break;
2007 case TYPE_OBERON:
2008 if (!LongStrings)
2009 { fputs("\"\n\t\"", OutputFile);
2011 break;
2012 case TYPE_ASSEMBLER:
2013 if (!LongStrings)
2014 { if (OutputMode == OutputMode_Ascii)
2015 { putc('\'', OutputFile);
2017 putc('\n', OutputFile);
2018 OutputMode = OutputMode_None;
2020 break;
2021 case TYPE_NONE:
2022 break;
2026 /// FUNC: WriteBinChar
2029 WriteBinChar writes one binary character into the source file
2031 void WriteBinChar(int c)
2034 switch(OutputType)
2035 { case TYPE_C:
2036 case TYPE_E:
2037 case TYPE_OBERON:
2038 switch(c)
2039 { case '\b':
2040 fputs("\\b", OutputFile);
2041 break;
2042 case '\n':
2043 fputs("\\n", OutputFile);
2044 break;
2045 case '\r':
2046 fputs("\\r", OutputFile);
2047 break;
2048 case '\t':
2049 fputs("\\t", OutputFile);
2050 break;
2051 case '\f':
2052 fputs("\\f", OutputFile);
2053 break;
2054 case '\0':
2055 fputs("\\000", OutputFile);
2056 break;
2057 default:
2058 if(OutputType == TYPE_E && c == '\033')
2060 fputs("\\e", OutputFile);
2062 else
2064 fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
2065 ((c >> 3) & 7) + '0', (c & 7) + '0');
2067 break;
2069 ++OutputLen;
2070 OutputMode = OutputMode_Bin;
2071 break;
2072 case TYPE_ASSEMBLER:
2073 switch(OutputMode)
2074 { case OutputMode_None:
2075 fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
2076 break;
2077 case OutputMode_Ascii:
2078 putc('\'', OutputFile);
2079 case OutputMode_Bin:
2080 fprintf(OutputFile, ",$%02x", c & 0xff);
2081 break;
2083 ++OutputLen;
2084 OutputMode = OutputMode_Bin;
2085 break;
2086 case TYPE_NONE:
2087 ShowWarn(msgNoBinChars);
2088 break;
2092 /// FUNC: WriteAsciiChar
2095 WriteAsciiChar writes one ascii character into the source file.
2097 void WriteAsciiChar(int c)
2100 switch(OutputType)
2101 { case TYPE_C:
2102 case TYPE_OBERON:
2103 switch(c)
2104 { case '\"':
2105 fputs("\\\"", OutputFile);
2106 break;
2107 default:
2108 putc(c, OutputFile);
2109 break;
2111 ++OutputLen;
2112 OutputMode = OutputMode_Ascii;
2113 break;
2114 case TYPE_E:
2115 switch(c)
2116 { case '\'':
2117 fputs("''", OutputFile);
2118 break;
2119 default:
2120 putc(c, OutputFile);
2121 break;
2123 ++OutputLen;
2124 OutputMode = OutputMode_Ascii;
2125 break;
2126 case TYPE_ASSEMBLER:
2127 if (c == '\'')
2128 { WriteBinChar(c);
2130 else
2131 { switch (OutputMode)
2132 { case OutputMode_None:
2133 fprintf(OutputFile, "\tdc.b\t\'%c", c);
2134 break;
2135 case OutputMode_Ascii:
2136 putc(c, OutputFile);
2137 break;
2138 case OutputMode_Bin:
2139 fprintf(OutputFile, ",\'%c", c);
2140 break;
2142 ++OutputLen;
2143 OutputMode = OutputMode_Ascii;
2145 break;
2146 case TYPE_NONE:
2147 putc(c, OutputFile);
2148 break;
2152 /// FUNC: TerminateCatStringOutput
2155 TerminateCatStringOutput finishs the output of a catalog string.
2157 void TerminateCatStringOutput(void)
2159 switch(OutputType)
2160 { case TYPE_C:
2161 case TYPE_OBERON:
2162 putc('\"', OutputFile);
2163 break;
2164 case TYPE_E:
2165 putc('\'', OutputFile);
2166 break;
2167 case TYPE_ASSEMBLER:
2168 switch(OutputMode)
2169 { case OutputMode_Ascii:
2170 putc('\'', OutputFile);
2171 case OutputMode_Bin:
2172 break;
2173 case OutputMode_None:
2174 break;
2176 case TYPE_NONE:
2177 break;
2182 /// FUNC: WriteString
2184 This writes a sourcestring.
2186 void WriteString(FILE *fpout, char *str, long Len)
2188 char bytes[10];
2189 int bytesread;
2190 int needseparate = FALSE;
2192 InitCatStringOutput(fpout);
2193 if (Len >= 0)
2194 { int i;
2196 for(i = LengthBytes; i >= 1; i--)
2197 { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
2201 while (*str)
2202 { bytesread = ReadChar(&str, bytes);
2203 if (bytesread)
2204 { unsigned char c;
2206 if (needseparate)
2207 { SeparateCatStringOutput();
2208 needseparate = FALSE;
2211 c = bytes[bytesread-1];
2212 if ((c >= 0x20 && c < 0x7f) || c >= 0xa0)
2213 { WriteAsciiChar((int) c);
2215 else
2216 { WriteBinChar((int) c);
2219 else
2220 { needseparate = TRUE;
2223 TerminateCatStringOutput();
2226 /// FUNC: AllocFileName
2228 This function creates a copy of a filename, removes an
2229 optional ending and pathname components, if desired.
2231 Inputs: filename - the filename to copy
2232 howto - a set of bits
2233 bit 0: 1 = remove ending, 0 = leave it
2234 bit 1: 1 = remove pathname, 0 = leave it
2236 Result: The copy of the filename
2238 char *AllocFileName(char *filename, int howto)
2240 char *tempstr, *ptr;
2242 if (!(tempstr = strdup(filename)))
2243 { MemError();
2244 MyExit(10);
2247 /* Remove pathname components, if desired */
2248 if (howto & 2)
2249 { if ((ptr = strchr(tempstr, ':')))
2250 { tempstr = ptr+1;
2252 if ((ptr = strrchr(tempstr, '/')))
2253 { tempstr = ptr+1;
2257 /* Remove ending, if desired. */
2258 if (howto & 1)
2259 { if ((ptr = strrchr(tempstr, '.')))
2260 { *ptr = '\0';
2264 return(tempstr);
2267 /// FUNC: AddFileName
2269 This function adds a pathname and a filename to a full
2270 filename.
2272 Inputs: pathname - the leading pathname
2273 filename - the filename
2275 Result: The new filename
2277 char *AddFileName(char *pathname, char *filename)
2279 char *buffer;
2280 int size = strlen(pathname) + strlen(filename) + 2;
2282 if (!(buffer = malloc(size)))
2283 { MemError();
2284 MyExit(10);
2287 #if defined(__amigados)
2288 strcpy(buffer, pathname);
2289 AddPart((char *) buffer, (char *) filename, size);
2290 #else
2291 sprintf(buffer, "%s/%s", pathname, filename);
2292 #endif
2294 return(buffer);
2298 /// FUNC: CreateSourceFile
2301 Finally the source creation.
2303 void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
2306 FILE *fpin, *fpout;
2307 char *line;
2308 char *OrigTemplateFile = TemplateFile;
2310 ScanFile = SourceFile;
2311 ScanLine = 0;
2314 Open the source file. This may be found in various places
2316 if(!(fpin = fopen(TemplateFile, "r")))
2318 #ifdef __amigados
2319 if(*prefs_sddir != 0)
2321 TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
2322 fpin = fopen(TemplateFile, "r");
2324 #endif
2327 if(!fpin)
2329 char *sddir;
2331 if((sddir = getenv(FLEXCAT_SDDIR)))
2333 TemplateFile = AddFileName(sddir, OrigTemplateFile);
2334 fpin = fopen(TemplateFile, "r");
2338 if (!fpin)
2339 { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
2340 fpin = fopen(TemplateFile, "r");
2343 if (!fpin)
2345 ShowError(msgNoSourceDescription, OrigTemplateFile);
2346 return;
2349 if (!(fpout = fopen(SourceFile, "w")))
2351 ShowError(msgNoSource, SourceFile);
2352 return;
2355 if(!NoBufferedIO)
2356 setvbuf(fpin, NULL, _IOFBF, buffer_size);
2357 if(!NoBufferedIO)
2358 setvbuf(fpout, NULL, _IOFBF, buffer_size);
2361 while(!feof(fpin) && (line = ReadLine(fpin, FALSE)))
2362 { struct CatString *cs;
2363 int NeedRepeat;
2364 char bytes[10];
2365 int bytesread;
2367 cs = FirstCatString;
2369 { char *currentline = line;
2370 NeedRepeat = FALSE;
2372 if (*currentline == '#' && *(++currentline) == '#')
2373 { ++currentline;
2374 OverSpace(&currentline);
2376 if(strnicmp( currentline, "rem", 3 ) == 0)
2378 // we just skip this line
2379 continue;
2382 if (strnicmp(currentline, "stringtype", 10) == 0)
2383 { currentline += 10;
2384 OverSpace(&currentline);
2385 if (strnicmp(currentline, "c", 1) == 0)
2386 { OutputType = TYPE_C;
2387 ++currentline;
2389 else if (strnicmp(currentline, "assembler", 9) == 0)
2390 { OutputType = TYPE_ASSEMBLER;
2391 currentline += 9;
2393 else if (strnicmp(currentline, "oberon", 6) == 0)
2394 { OutputType = TYPE_OBERON;
2395 currentline += 6;
2397 else if (strnicmp(currentline, "e", 1) == 0)
2398 { OutputType = TYPE_E;
2399 ++currentline;
2401 else if (strnicmp(currentline, "none", 4) == 0)
2402 { OutputType = TYPE_NONE;
2403 currentline += 4;
2405 else
2406 { ShowWarn(msgUnknownStringType);
2407 currentline += strlen(currentline);
2409 OverSpace(&currentline);
2410 if (*currentline)
2411 { ShowWarn(msgExtraCharacters);
2413 continue;
2415 else if (strnicmp(currentline, "shortstrings", 12) == 0)
2416 { currentline += 12;
2417 LongStrings = FALSE;
2418 OverSpace(&currentline);
2419 if (*currentline)
2420 { ShowWarn(msgExtraCharacters);
2422 continue;
2426 currentline = line;
2427 while(*currentline)
2428 { bytesread = ReadChar(&currentline, bytes);
2429 if (bytesread)
2430 { if (*bytes == '%')
2431 { char c;
2433 switch(c = *(currentline++))
2434 { case 'b':
2435 fputs(BaseName, fpout);
2436 break;
2437 case 'n':
2438 fprintf(fpout, "%d", NumStrings);
2439 break;
2440 case 'v':
2441 fprintf(fpout, "%d", CatVersion);
2442 break;
2443 case 'l':
2444 WriteString(fpout, Language, -1);
2445 break;
2446 case 'f':
2447 { char *tempstr;
2449 if ((c = *currentline++) == 'v')
2450 { fputs(VERS, fpout);
2452 else
2453 { tempstr = AllocFileName(CDFile, c - '0');
2454 fputs(tempstr, fpout);
2457 break;
2458 case 'o':
2459 { char *tempstr;
2461 tempstr = AllocFileName(SourceFile, *currentline++ - '0');
2462 fputs(tempstr, fpout);
2464 break;
2465 case 'i':
2466 NeedRepeat = TRUE;
2467 if (cs) fputs(cs->ID_Str, fpout);
2468 break;
2470 case 'a':
2471 case 't':
2473 case 'd':
2474 case 'x':
2475 case 'c':
2476 case '0':
2477 case '1':
2478 case '2':
2479 case '3':
2480 case '4':
2481 case '5':
2482 case '6':
2483 case '7':
2484 case '8':
2485 case '9':
2487 int len = 0;
2489 while(c >= '0' && c <= '9')
2491 len = (c - '0') + len * 10;
2492 c = *currentline++;
2496 if(c == 'a')
2498 int _len = len ? len : 4;
2499 char *start;
2500 char _StrLen[20 + 1];
2502 sprintf(_StrLen, "%020lx", cs->ID);
2504 start = &_StrLen[20-_len*2];
2505 while(_len>0)
2507 fprintf(fpout, "\\x%.2s", start);
2508 start+=2;
2509 _len--;
2513 if(c == 't')
2515 int _len = len ? len : 4;
2516 char *start;
2517 char _StrLen[20 + 1];
2519 sprintf(_StrLen, "%020lx", ((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
2521 start = &_StrLen[20-_len*2];
2522 while(_len>0)
2524 fprintf(fpout, "\\x%.2s", start);
2525 start+=2;
2526 _len--;
2530 if(c == 'c' || c == 'd' || c == 'x')
2532 char buffer[20];
2534 if(c == 'c') c = 'o';
2536 if(len)
2537 sprintf(buffer, "%%0%d%c", len, c);
2538 else
2539 sprintf(buffer, "%%%c", c);
2541 if(cs) fprintf(fpout, buffer, cs->ID);
2545 NeedRepeat = TRUE;
2547 break;
2549 case 'e':
2550 NeedRepeat = TRUE;
2551 if (cs) fprintf(fpout, "%d", cs->Nr);
2552 break;
2553 case 's':
2554 NeedRepeat = TRUE;
2555 if (cs)
2556 { char *idstr;
2557 unsigned long len = 0;
2559 if (LengthBytes)
2560 { idstr = cs->CD_Str;
2561 while(*idstr)
2562 { bytesread = ReadChar(&idstr, bytes);
2563 if (bytesread)
2564 { ++len;
2568 WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
2570 break;
2571 case '(':
2572 NeedRepeat = TRUE;
2573 while(*currentline && *currentline != ')')
2574 { bytesread = ReadChar(&currentline, bytes);
2575 if (bytesread && cs && cs->Next)
2576 { putc((int) bytes[bytesread-1], fpout);
2579 if (!*currentline)
2580 { ShowWarn(msgNoTerminateBracket);
2582 else
2583 { ++currentline;
2585 break;
2587 // !!!! FIX !!!!
2589 case 'z':
2591 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
2593 NeedRepeat = TRUE;
2595 while(diff > 0)
2597 fprintf(fpout, "\\x00");
2598 diff--;
2601 break;
2604 default:
2605 { int c = *currentline++;
2607 putc(c, fpout);
2611 else
2612 { putc((int) bytes[bytesread-1], fpout);
2616 putc('\n', fpout);
2618 while(NeedRepeat && cs && (cs = cs->Next));
2620 free(line);
2623 fclose(fpin);
2624 fclose(fpout);
2628 /// FUNC: Usage
2630 The Usage function describes the programs calling syntax.
2632 void Usage(void)
2635 fputs((char *) msgUsageHead, stderr);
2636 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);
2637 fprintf(stderr, "%s\n%s\n%s\n%s\n", msgUsage, msgUsage_2, msgUsage_3, msgUsage_4 );
2638 fprintf(stderr, "\n\n%s"
2640 #ifdef _M68040
2641 " [040]"
2642 #else
2643 #ifdef _M68060
2644 " [060]"
2645 #else
2646 #ifdef _M68030
2647 " [030]"
2648 #else
2649 #ifdef _M68020
2650 " [020]"
2651 #else
2652 #ifdef _M68010
2653 " [010]"
2654 #endif
2655 #endif
2656 #endif
2657 #endif
2658 #endif
2660 "\n", VString);
2663 fprintf(stderr, "%s\n", EString);
2664 MyExit(5);
2667 /// FUNC: main
2669 Finally the main function. Does nothing special except for scanning
2670 the arguments.
2672 int main(int argc, char *argv [])
2674 char *cdfile, *ctfile, *newctfile, *catalog;
2675 char *source, *template;
2676 int i;
2678 if(argc == 0) /* Aztec's entry point for workbench programs */
2680 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2681 fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
2682 fprintf(stderr, "for more information\n");
2683 exit(5);
2686 cdfile = ctfile = newctfile = catalog = NULL;
2689 /* let's open catalog files by hand if necessary */
2690 /* should be done automatically anyway for most */
2691 /* cases, but, that depends on compiler... */
2693 #if defined(_DCC)
2694 // STATIC __autoinit VOID _STIOpenFlexCatCatalog(VOID)
2695 #elif defined(__SASC)
2696 // VOID _STIOpenFlexCatCatalog(VOID)
2697 #elif defined(__GNUC__)
2698 // VOID _STIOpenFlexCatCatalog(VOID)
2699 #elif defined(__INTEL_COMPILER)
2700 // VOID _STIOpenFlexCatCatalog(VOID)
2701 #else
2702 OpenFlexCatCatalog(); /* no autoopen. we do it then */
2703 #endif
2706 // Big Endian vs Little Endian (both supported ;-)
2707 if( !SwapChoose() )
2709 fprintf(stderr, "FlexCat is unable to determine the\n");
2710 fprintf(stderr, "the byte order used by your system.\n");
2711 fprintf(stderr, "It's neither Little nor Big Endian?!.\n");
2712 exit(5);
2717 #if defined(__amigados)
2718 ReadPrefs();
2719 #endif
2721 if(argc == 1)
2723 Usage();
2726 for (i = 1; i < argc; i++)
2728 if(strnicmp (argv[i], "catalog=", 8) == 0)
2730 catalog = argv[i] + 8;
2732 else
2733 if(stricmp (argv[i], "catalog") == 0)
2735 if(i+1 == argc)
2736 Usage();
2737 catalog = argv[++i];
2739 else
2740 if(stricmp(argv[i], "nooptim") == 0)
2742 NoOptim = TRUE;
2744 else
2745 if(stricmp(argv[i], "fill") == 0)
2747 Fill = TRUE;
2749 else
2750 if(stricmp(argv[i], "quiet") == 0)
2752 Quiet = TRUE;
2754 else
2755 if(stricmp(argv[i], "flush") == 0)
2757 DoExpunge = TRUE;
2759 else
2760 if(stricmp(argv[i], "nobeep") == 0)
2762 NoBeep = TRUE;
2764 else
2765 if(stricmp(argv[i], "nobufferedio") == 0)
2767 NoBufferedIO = TRUE;
2769 else
2770 if (strnicmp (argv[i], "newctfile=", 10) == 0)
2772 newctfile = argv[i] + 10;
2774 else
2775 if(strnicmp (argv[i], "newctfile", 9) == 0)
2777 if (i+1 == argc)
2778 Usage();
2779 newctfile = argv[++i];
2781 else
2782 if(stricmp(argv[i], "nolangtolower") == 0)
2784 LANGToLower = FALSE;
2786 else
2787 if(stricmp(argv[i], "modified") == 0)
2789 Modified = TRUE;
2791 else
2792 if(stricmp(argv[i], "warnctgaps") == 0)
2794 WarnCTGaps = TRUE;
2796 else
2797 if(stricmp(argv[i], "copymsgnew") == 0)
2799 CopyNEWs = TRUE;
2801 else
2802 if(stricmp(argv[i], "nospace") == 0)
2804 NoSpace = TRUE;
2806 else
2807 if(stricmp(argv[i], "oldmsgnew") == 0)
2809 sprintf( Old_Msg_New, "; %s", argv[++i] );
2811 else
2812 if(cdfile == NULL)
2814 if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
2816 Usage();
2818 if(!ScanCDFile(cdfile = argv[i]))
2820 MyExit(10);
2823 else
2824 if(strchr(argv[i], '='))
2826 source = AllocString(argv[i]);
2827 *(template = strchr(source, '=')) = '\0';
2828 ++template;
2830 CreateSourceFile(source, template, cdfile);
2832 else
2834 if (ctfile)
2836 Usage();
2838 ctfile = argv[i];
2843 #if defined(__amigados)
2844 if(Modified)
2846 if(cdfile && ctfile && catalog)
2848 long cd_time, ct_time, cat_time;
2850 if((cd_time = getft(cdfile)) != -1)
2852 if((ct_time = getft(ctfile)) != -1)
2854 if((cat_time = getft(catalog)) == -1)
2855 cat_time = 0;
2857 if((cat_time > ct_time) &&
2858 (cat_time > cd_time))
2860 if(!Quiet)
2862 fprintf(stderr, (char *) msgUpToDate, catalog);
2863 putc('\n', stderr);
2866 MyExit(GlobalReturnCode);
2868 else
2870 if(!Quiet)
2872 fprintf(stderr, "--> %s", catalog);
2873 putc('\n', stderr);
2877 else
2879 ShowError(msgCantCheckDate, ctfile);
2882 else
2884 ShowError(msgCantCheckDate, cdfile);
2888 #endif
2890 if(ctfile)
2892 if(!ScanCTFile(ctfile))
2893 MyExit(10);
2896 if(catalog)
2898 if(!ctfile)
2900 fprintf(stderr, (char *) msgNoCTArgument);
2901 Usage();
2903 CreateCat(catalog);
2906 if(newctfile)
2908 CreateCTFile(newctfile);
2911 MyExit(GlobalReturnCode);
2914 /// FUNC: wbmain
2917 Dice's entry point for workbench programs
2919 #if defined(__amigados) && defined(_DCC)
2920 void wbmain(struct WBStartup *wbmsg)
2922 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2923 fprintf(stderr, "Open a Shell session and type FlexCat\n");
2924 fprintf(stderr, "for syntax and more information\n");
2926 exit(5);
2928 #endif