added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / tools / FlexCat / flexcat.c
blobeba61fe36a9fe3f830cce97d1893312d16f8f241
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 #ifdef __amigados
82 #include <dos.h>
83 #endif
84 #include "flexcat_cat.h"
86 #if ((defined(_DCC) && defined(AMIGA)) || \
87 (defined(__SASC) && defined(_AMIGA))) && \
88 !defined(__amigados)
89 #define __amigados
90 #endif
92 #if defined(__amigados)
93 #include <exec/types.h>
94 #if defined(_DCC) || defined(__SASC) || defined(__GNUC__)
95 #include <proto/exec.h>
96 #include <proto/dos.h>
97 #include <proto/intuition.h>
98 #include <proto/utility.h>
99 #else
100 #include <clib/exec_protos.h>
101 #include <clib/dos_protos.h>
102 #include <clib/utility_protos.h>
103 #endif
105 #ifdef tolower
106 #undef tolower
107 #endif
108 #define tolower ToLower
109 #define stricmp(s,t) Stricmp((char *) (s), (char *) (t))
110 #define strnicmp(s,t,l) Strnicmp((char *) (s), (char *) (t), l)
112 #endif
115 #ifndef FALSE
116 #define FALSE 0
117 #endif
118 #ifndef TRUE
119 #define TRUE (!FALSE)
120 #endif
123 #define MAXPATHLEN 512
124 #define FLEXCAT_SDDIR "FLEXCAT_SDDIR"
125 #if defined(__amigados)
126 #define DEFAULT_FLEXCAT_SDDIR "PROGDIR:lib"
127 #else
128 #define DEFAULT_FLEXCAT_SDDIR "lib"
129 #endif
131 #if defined(__amigados)
132 #define MAX_PREFS_LEN 512
133 #define FLEXCAT_PREFS "flexcat.prefs"
134 char prefs_sddir[MAXPATHLEN] = "\0";
135 #endif
138 #ifndef MAKE_ID
139 #define MAKE_ID(a,b,c,d) \
140 ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
141 #endif
143 #ifndef ULONG
144 #define ULONG unsigned long
145 #endif
148 /// Structs
150 enum StringTypes {
151 TYPE_C, /* Produce C strings */
152 TYPE_ASSEMBLER, /* Produce Assembler strings */
153 TYPE_OBERON, /* Produce Oberon strings */
154 TYPE_E, /* Produce E strings. (Oops, thought */
155 /* it allows only 32 bit integers? ;-) */
156 TYPE_NONE /* Simple strings */
160 enum OutputModes {
161 OutputMode_None, /* Nothing written yet */
162 OutputMode_Bin, /* Last character written was binary */
163 OutputMode_Ascii /* Last character written was Ascii */
166 struct CatString
167 { struct CatString *Next;
168 char *CD_Str;
169 char *CT_Str;
170 char *ID_Str;
171 int MinLen, MaxLen, ID, Nr;
172 int NotInCT; /* If string is not present we write NEW */
173 /* while updating CT file, for easier work. */
177 struct CDLine
178 { struct CDLine *Next;
179 char *Line;
182 struct CatalogChunk
183 { struct CatalogChunk *Next; /* struct CatalogChunk *Next */
184 ULONG ID;
185 char *ChunkStr;
188 struct CatString *FirstCatString = NULL; /* First catalog string */
189 struct CDLine *FirstCDLine = NULL; /* First catalog description line */
190 struct CatalogChunk *FirstChunk = NULL; /* List of catalog chunks */
192 char *BaseName = ""; /* Basename of catalog description */
193 char *Language = "english"; /* Language of catalog description */
194 int CatVersion = 0; /* Version of catalog to be opened */
195 int LengthBytes = 0; /* Number of bytes to preceed a */
196 /* created string and containing */
197 /* its length. */
198 char *CatLanguage = NULL; /* Language of catalog translation */
199 char *CatVersionString = NULL; /* version string of catalog */
200 /* translation (## version) */
201 char *CatRcsId = NULL; /* rcs ID of catalog translation */
202 /* (## rcsid) */
203 char *CatName = NULL; /* name of catalog translation */
204 int CodeSet = 0; /* Codeset of catalog translation */
205 int NumStrings = 0; /* Number of catalog strings */
206 int LongStrings = TRUE; /* Generate long or short strings */
208 char *ScanFile; /* File currently scanned */
209 int ScanLine; /* Line currently scanned */
211 int GlobalReturnCode = 0; /* Will be 5, if warnings appear */
212 int WarnCTGaps = FALSE; /* Warn missing symbols in CT */
213 /* file. */
214 int NoOptim = FALSE; /* Put string into catalog even */
215 /* if translation is equal to */
216 /* description. */
217 int Fill = FALSE; /* It translation of given string */
218 /* is missing or it's empty, write */
219 /* string descriptor from #?.cd */
220 /* file instead. */
221 int DoExpunge = FALSE; /* If TRUE FlexCat will do AVAIL */
222 /* FLUSH alike after catalog save */
223 int NoBeep = FALSE; /* if TRUE, FlexCat won't call */
224 /* DisplayBeep() any longer */
225 int Quiet = FALSE; /* Forces FlexCat to shut up */
227 int NumberOfWarnings = 0; /* We count warnings to be smart */
228 /* and not to do Beep bombing, but */
229 /* call DisplayBeep() only once */
230 int CT_Scanned = FALSE; /* If TRUE, and we are going to */
231 /* write new #?.ct file, then user */
232 /* surely updates own #?.ct file */
233 /* so we should write ***NEW*** */
234 /* whenever necessary. */
235 int LANGToLower = TRUE; /* Shall we do ToLower() on lang's */
236 /* name? Some #?.language seems to */
237 /* be broken, so we allow workaround */
238 int NoBufferedIO = FALSE; /* Shall we do buffered IO */
239 int buffer_size = 2048; /* Size of the IO buffer */
240 int Modified = FALSE; /* Shall we write the catalog ONLY */
241 /* if #?.catalog is younger than */
242 /* #?.c(d|t) files? */
244 #define MAX_NEW_STR_LEN 25
245 char Msg_New[MAX_NEW_STR_LEN] = "***NEW***";
246 /* new strings in updated #?.ct */
248 int CopyNEWs = FALSE;
249 char Old_Msg_New[MAX_NEW_STR_LEN] = "; ***NEW***";
251 /* old newstring (above) used in old */
252 /* CT file. Now we look if it's present */
253 /* and copy it into new CT if user does */
254 /* upgrade (flexcat CD CT newctfile CT */
256 int NoSpace = FALSE; /* do want to strip the space usually */
257 /* placed between ';' and original */
258 /* string? */
261 char VersTag[] = VERSTAG;
262 char VString[] = VSTRING " by Jochen Wiedmann and Marcin Orlowski";
263 char EString[] = "E-mail: carlos@amiga.com.pl WWW: http://amiga.com.pl/flexcat/";
266 /// FUNC: ReadPrefs
267 #if defined(__amigados)
269 char ReadPrefs(void)
271 enum{ SDDIR,
272 MSG_NEW,
273 WARNCTGAPS,
274 NOOPTIM,
275 FILL,
276 FLUSH,
277 NOBEEP,
278 QUIET,
279 NOLANGTOLOWER,
280 NOBUFFEREDIO,
281 MODIFIED,
282 COPYMSGNEW,
283 OLDMSGNEW,
284 NOSPACE,
286 ARGS_COUNT
289 char template[] = "SDDIR/K,MSG_NEW/K,WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K,NOSPACE/S";
290 LONG Results[ARGS_COUNT] = {0};
291 char result = FALSE;
292 char *prefs;
293 struct RDArgs *rda;
294 struct RDArgs *rdargs;
296 if(prefs = getenv(FLEXCAT_PREFS))
298 prefs = realloc(prefs, strlen(prefs)+1);
299 strcat(prefs, "\n");
301 if(rda = AllocDosObject(DOS_RDARGS, TAG_DONE))
303 rda->RDA_Source.CS_Buffer = prefs;
304 rda->RDA_Source.CS_Length = strlen(prefs);
305 rda->RDA_Source.CS_CurChr = 0;
306 rda->RDA_Flags |= RDAF_NOPROMPT;
308 if(rdargs = ReadArgs(template, Results, rda))
310 if(Results[SDDIR])
311 strncpy(prefs_sddir, (char *)Results[SDDIR], MAXPATHLEN);
313 if(Results[MSG_NEW])
314 strncpy(Msg_New, (char *)Results[MSG_NEW], MAX_NEW_STR_LEN);
316 WarnCTGaps = Results[WARNCTGAPS];
317 NoOptim = Results[NOOPTIM];
318 Fill = Results[FILL];
319 DoExpunge = Results[FLUSH];
320 NoBeep = Results[NOBEEP];
321 Quiet = Results[QUIET];
322 LANGToLower = Results[NOLANGTOLOWER];
323 Modified = Results[MODIFIED];
324 NoBufferedIO = Results[NOBUFFEREDIO];
325 CopyNEWs = Results[COPYMSGNEW];
326 NoSpace = Results[NOSPACE];
327 if(Results[OLDMSGNEW])
328 sprintf(Old_Msg_New, "; %s", (char *)Results[OLDMSGNEW]);
330 FreeArgs(rdargs);
332 result = TRUE;
334 else
336 fputs((char *)msgPrefsError, stderr);
337 fputs((char *)template, stderr);
338 fputs((char *)"\n", stderr);
339 DisplayBeep(NULL);
342 FreeDosObject(DOS_RDARGS, rda);
344 else
346 fputs("Error processing prefs.\nCan't AllocDosObject()\n", stderr);
349 free(prefs);
352 return(result);
355 #endif
358 /// FUNC: MyExit
359 void MyExit (int Code)
362 #if defined(__amigados)
364 if(((NumberOfWarnings > 0) ||(Code !=0)) && (!NoBeep))
365 DisplayBeep(NULL);
367 #endif
370 #if defined(_DCC)
371 //STATIC __autoexit VOID _STDCloseFlexCatCatalog(VOID)
372 #elif defined(__SASC)
373 //VOID _STDCloseFlexCatCatalog(VOID)
374 #elif defined(__GNUC__)
375 //STATIC VOID _STDCloseFlexCatCatalog(VOID)
376 #elif defined(__INTEL_COMPILER)
377 //STATIC VOID _STDCloseFlexCatCatalog(VOID)
378 #else
379 CloseFlexCatCatalog(); /* we need to close something... */
380 #endif
383 exit(Code);
387 /// FUNC: stricmp
389 // quick stricmp
391 #if !defined(__amigados) && !defined(__CYGWIN32__)
392 # define stricmp strcasecmp
393 #endif
395 #if 0
396 int stricmp( const char *str1, const char *str2 )
398 int i;
400 for(i = 0;; i++)
402 int a = tolower( (int)*str1 );
403 int b = tolower( (int)*str2 );
405 if( !a || !b )
406 break;
408 if( a != b )
409 return( 1 );
411 str1++;
412 str2++;
415 return( 0 );
417 #endif
420 /// FUNC: strnicmp
422 // quick strnicmp
424 #if !defined(__amigados) && !defined(__CYGWIN32__)
425 int strnicmp( const char *str1, const char *str2, size_t len )
427 size_t i;
429 for(i = 0; i < len; i++)
431 int a = tolower( (int)*str1 );
432 int b = tolower( (int)*str2 );
434 if( !a || !b )
435 return( 1 );
437 if( a != b )
438 return( 1 );
440 str1++;
441 str2++;
444 return( 0 );
446 #endif
450 /// FUNC: Swappers...
453 unsigned short (*SwapWord)(unsigned short r) = NULL;
454 unsigned long (*SwapLong)(unsigned long r) = NULL;
457 unsigned short SwapWord21(unsigned short r)
459 return (unsigned short)((r>>8) + (r<<8));
461 unsigned short SwapWord12(unsigned short r)
463 return r;
465 unsigned long SwapLong4321(unsigned long r)
467 return ((r>>24) & 0xFF) + (r<<24) + ((r>>8) & 0xFF00) + ((r<<8) & 0xFF0000);
469 unsigned long SwapLong1234(unsigned long r)
471 return r;
475 /// FUNC: SwapChoose
476 int SwapChoose(void)
478 unsigned short w;
479 unsigned int d;
481 strncpy((char *)&w, "\1\2", 2);
482 strncpy((char *)&d, "\1\2\3\4", 4);
484 if (w == 0x0201)
485 SwapWord = SwapWord21;
486 else if (w == 0x0102)
487 SwapWord = SwapWord12;
488 else
489 return 0;
491 if (d == 0x04030201)
492 SwapLong = SwapLong4321;
493 else if (d == 0x01020304)
494 SwapLong = SwapLong1234;
495 else
496 return 0;
498 return 1;
502 /// FUNC: ShowError
505 This shows an error message and terminates
507 void ShowError(const char *msg, ...)
509 char **ptr = (char **) &msg;
511 // if(!Quiet)
513 fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
514 putc('\n', stderr);
517 #if defined(__amigados)
518 NumberOfWarnings++;
519 #endif
521 MyExit(10);
524 /// FUNC: MemError
527 This shows the message: Memory error.
529 void MemError(void)
532 ShowError(msgMemoryError, NULL);
535 /// FUNC: ShowWarn
538 This shows a warning
540 void ShowWarn(const char *msg, ...)
542 { char **ptr = (char **) &msg;
544 if(!Quiet)
546 fprintf(stderr, (char *) msgWarning, ScanFile, ScanLine);
547 fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
548 putc('\n', stderr);
551 NumberOfWarnings++;
552 GlobalReturnCode = 5;
555 /// FUNC: AllocString
558 This allocates a string
560 char *AllocString(const char *str)
562 { char *ptr;
564 if (!(ptr = malloc(strlen(str)+1)))
565 { MemError();
567 strcpy(ptr, str);
568 return(ptr);
571 /// FUNC: Add catalog chunk
574 This adds a new catalog chunk to the list of catalog
575 chunks.
577 char *AddCatalogChunk(char *ID, const char *string)
579 struct CatalogChunk *cc, **ccptr;
581 if (!(cc = malloc(sizeof(*cc))))
582 { MemError();
584 cc->Next = NULL;
585 cc->ID = *((ULONG *) ID);
586 cc->ChunkStr = AllocString(string);
589 Put the new chunk to the end of the chunk list.
591 for (ccptr = &FirstChunk; *ccptr != NULL; ccptr = &(*ccptr)->Next)
594 *ccptr = cc;
595 return(cc->ChunkStr);
598 /// FUNC: gethex
600 This translates a hex character.
602 int gethex(int c)
604 if (c >= '0' && c <= '9')
605 { return(c - '0');
607 else if (c >= 'a' && c <= 'f')
608 { return(c - 'a' + 10);
610 else if (c >= 'A' && c <= 'F')
611 { return(c - 'A' + 10);
613 ShowWarn(msgExpectedHex);
614 return(0);
617 /// FUNC: getoctal
620 This translates an octal digit.
622 int getoctal(int c)
625 if (c >= '0' && c <= '7')
627 return(c - '0');
630 ShowWarn(msgExpectedOctal);
631 return(0);
635 /// FUNC: ReadLine
638 Reading a line is somewhat complicated in order to allow lines of any
639 length.
641 Inputs: fp - the file, where the input comes from
642 AllowComment - TRUE, if a leading semicolon should force to
643 interpret the line as a comment line
645 #define BUFSIZE 4096
646 char *ReadLine(FILE *fp, int AllowComment)
649 char *OldLine, *NewLine = NULL;
650 int c = '\0';
651 int Len = 0, LineLen = 0;
652 int FirstChar = TRUE;
653 int BackslashSeen = FALSE;
654 int BackslashSeenOn = 0; /* position the last backslash was seen on */
655 int CommentLine = FALSE; /* if TRUE we should ignore normally treat trailing \'s */
657 while(c != EOF)
659 if(Len+10 > LineLen)
661 OldLine = NewLine;
662 if(!(NewLine = malloc(LineLen+BUFSIZE)))
663 MemError();
665 strncpy(NewLine, OldLine, LineLen);
666 if(OldLine)
667 free(OldLine);
669 LineLen += BUFSIZE;
672 c = getc(fp);
674 if(FirstChar)
676 if(c == EOF)
678 free(NewLine);
679 return(NULL);
682 if(c == ';')
684 CommentLine = TRUE;
687 FirstChar = FALSE;
690 switch(c)
692 case '\r':
693 break;
695 case '\n':
696 ++ScanLine;
697 if(BackslashSeen)
699 NewLine[Len++] = c;
700 BackslashSeen = FALSE;
701 break;
703 c = EOF;
705 case EOF:
706 break;
708 /* Let's check for trailing \\ */
709 case '\\':
711 if(!CommentLine)
713 if(BackslashSeen)
715 if(BackslashSeenOn == (Len-1))
717 BackslashSeen = FALSE;
718 NewLine[Len++] = c;
719 break;
723 BackslashSeen = TRUE;
724 BackslashSeenOn = Len;
727 NewLine[Len++] = c;
728 break;
732 default:
733 BackslashSeen = FALSE;
734 NewLine[Len++] = c;
738 NewLine[Len] = '\0';
740 return(NewLine);
744 /// FUNC: OverSpace
747 This removes trailing blanks.
749 void OverSpace(char **strptr)
751 { int c;
753 while ((c = **strptr) == ' ' || c == '\t')
754 { (*strptr)++;
759 /// FUNC: Expunge
761 void Expunge(void)
763 #if defined(__amigados)
766 if(DoExpunge)
768 #ifdef __EXPUNGE_ALL__
769 APTR Memory;
771 if(Memory = AllocMem(-1, NULL))
772 FreeMem(Memory, -1); // just in case ;-)
773 #else
775 #pragma libcall LocaleBase localeExpunge 12 00
776 VOID localeExpunge(VOID);
778 struct Library *LocaleBase;
780 if(LocaleBase = OpenLibrary("locale.library", 0))
782 localeExpunge();
783 CloseLibrary(LocaleBase);
786 #endif
788 #endif
794 /// FUNC: ReadChar
797 ReadChar scans an input line translating the backslash characters.
799 Inputs: char * - a pointer to a stringpointer; the latter points to the
800 next character to be read and points behind the read
801 bytes after executing ReadChar
802 dest - a pointer to a buffer, where the read bytes should be
803 stored
805 Result: number of bytes that are written to dest (between 0 and 2)
807 int ReadChar(char **strptr, char *dest)
809 char c;
810 int i;
812 switch(c = *((*strptr)++))
814 case '\\':
816 switch(c = tolower((int) *((*strptr)++)))
818 case '\n':
819 return(0);
820 case 'b':
821 *dest = '\b';
822 break;
823 case 'c':
824 *dest = '\233';
825 break;
826 case 'e':
827 *dest = '\033';
828 break;
829 case 'f':
830 *dest = '\f';
831 break;
832 case 'g':
833 *dest = '\007';
834 break;
835 case 'n':
836 *dest = '\n';
837 break;
838 case 'r':
839 *dest = '\r';
840 break;
841 case 't':
842 *dest = '\t';
843 break;
844 case 'v':
845 *dest = '\013';
846 break;
847 case 'x':
848 *dest = gethex((int) **strptr);
849 (*strptr)++;
850 if (((c = **strptr) >= '0' && c <= '9') ||
851 (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
852 { *dest = (*dest << 4) + gethex((int) c);
853 (*strptr)++;
855 break;
856 case '0':
857 case '1':
858 case '2':
859 case '3':
860 case '4':
861 case '5':
862 case '6':
863 case '7':
865 *dest = getoctal((int)c);
867 for(i = 0; i < 2; i++)
869 if((c = **strptr) >= '0' && c <= '7')
871 *dest = (*dest << 3) + getoctal((int) c);
872 (*strptr)++;
875 break;
876 case ')':
877 case '\\':
878 *(dest++) = '\\';
879 *dest = c;
880 return(2);
881 default:
882 *dest = c;
884 break;
886 default:
887 *dest = c;
889 return(1);
892 /// FUNC: ScanCDFile
895 This scans the catalog description file.
897 Inputs: cdfile - name of the catalog description file
899 Result: TRUE, if successful, FALSE otherwise
901 int ScanCDFile(char *cdfile)
903 FILE *fp;
904 struct CDLine *cdline, **cdptr = &FirstCDLine;
905 struct CatString *cs, **csptr = &FirstCatString;
906 char *line, *newline;
907 char *ptr;
908 int NextID = 0, len;
909 int Result = TRUE;
911 ScanFile = cdfile;
912 ScanLine = 0;
914 if(!(fp = fopen(cdfile, "r")))
916 ShowError(msgNoCatalogDescription, cdfile);
919 if(!NoBufferedIO)
920 setvbuf(fp, NULL, _IOFBF, buffer_size);
923 Get the basename
925 if ((ptr = strchr(cdfile, ':')))
926 { cdfile = ptr+1;
928 if ((ptr = strrchr(cdfile, '/')))
929 { cdfile = ptr+1;
931 if ((ptr = strrchr(cdfile, '.')))
932 { len = ptr-cdfile;
934 else
935 { len = strlen(cdfile);
937 if (!(BaseName = malloc(len+1)))
938 { MemError();
940 strncpy(BaseName, cdfile, len);
941 BaseName[len] = '\0';
943 while(!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
945 if(!(cdline = malloc(sizeof(*cdline))))
947 MemError();
950 *cdptr = cdline;
951 cdptr = &cdline->Next;
952 cdline->Next = NULL;
953 cdline->Line = line = AllocString(newline);
954 free(newline);
956 if (*line == ';')
958 continue;
961 if(*line == '#')
963 int CheckExtra = TRUE;
965 if (strnicmp(line+1, "language", 8) == 0)
967 char *ptr;
969 line += 9;
970 OverSpace(&line);
971 Language = AllocString(line);
973 if(LANGToLower)
975 for (ptr = Language; *ptr; ptr++)
977 *ptr = tolower((int) *ptr);
979 CheckExtra = FALSE;
983 else
984 if(strnicmp(line+1, "version", 7) == 0)
986 CatVersion = strtol(line+8, &line, 0);
988 else
990 if(strnicmp(line+1, "basename", 8) == 0)
992 line += 9;
993 OverSpace(&line);
994 free(BaseName);
995 BaseName = AllocString(line);
996 CheckExtra = FALSE;
998 else
1000 ShowWarn(msgUnknownCDCommand);
1001 Result = FALSE;
1002 CheckExtra = FALSE;
1006 if(CheckExtra)
1008 OverSpace(&line);
1009 if(*line)
1011 ShowWarn(msgExtraCharacters);
1012 Result = FALSE;
1016 else
1018 char *idstr;
1020 if(*line == ' ' || *line == '\t')
1022 ShowWarn(msgUnexpectedBlanks);
1023 Result = FALSE;
1024 OverSpace(&line);
1027 idstr = line;
1028 while ((*line >= 'a' && *line <= 'z') ||
1029 (*line >= 'A' && *line <= 'Z') ||
1030 (*line >= '0' && *line <= '9') ||
1031 *line == '_')
1033 ++line;
1036 if(idstr == line)
1038 ShowWarn(msgNoIdentifier);
1039 Result = FALSE;
1041 else
1043 int found;
1045 if(!(cs = malloc(sizeof(*cs))))
1047 MemError();
1052 struct CatString *scs;
1054 found = TRUE;
1055 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1057 if(scs->ID == NextID)
1059 found = FALSE;
1060 ++NextID;
1061 break;
1065 while(!found);
1067 cs->Next = NULL;
1068 cs->ID = NextID;
1069 cs->MinLen = 0;
1070 cs->MaxLen = -1;
1071 cs->CD_Str = "";
1072 cs->CT_Str = NULL;
1073 cs->NotInCT= TRUE;
1075 if(!(cs->ID_Str = malloc((line-idstr)+1)))
1077 MemError();
1079 strncpy(cs->ID_Str, idstr, line-idstr);
1080 cs->ID_Str[line-idstr] = '\0';
1082 OverSpace(&line);
1084 if(*line != '(')
1086 ShowWarn(msgNoLeadingBracket);
1087 Result = FALSE;
1089 else
1091 char *oldstr;
1092 struct CatString *scs;
1093 char bytes[10];
1094 int bytesread, reallen;
1096 ++line;
1097 OverSpace(&line);
1098 if(*line != '/')
1100 if(*line == '+')
1102 NextID = cs->ID = NextID + strtol(line, &line, 0);
1104 else
1106 cs->ID = NextID = strtol(line, &line, 0);
1109 OverSpace(&line);
1112 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1113 { if (scs->ID == cs->ID)
1114 { ShowWarn(msgDoubleID);
1115 Result = FALSE;
1117 if (strcmp(cs->ID_Str, scs->ID_Str) == 0)
1118 { ShowWarn(msgDoubleIdentifier);
1119 Result = FALSE;
1123 if (*line != '/')
1124 { ShowWarn(msgNoMinLen);
1125 Result = FALSE;
1127 else
1128 { ++line;
1129 OverSpace(&line);
1130 if (*line != '/')
1131 { cs->MinLen = strtol(line, &line, 0);
1132 OverSpace(&line);
1134 if (*line != '/')
1135 { ShowWarn(msgNoMaxLen);
1136 Result = FALSE;
1138 else
1139 { ++line;
1140 OverSpace(&line);
1141 if (*line != ')')
1142 { cs->MaxLen = strtol(line, &line, 0);
1143 OverSpace(&line);
1145 if (*line != ')')
1146 { ShowWarn(msgNoTrailingBracket);
1147 Result = FALSE;
1149 else
1150 { ++line;
1151 OverSpace(&line);
1152 if (*line)
1153 { ShowWarn(msgExtraCharacters);
1158 if (!(newline = ReadLine(fp, FALSE)))
1159 { ShowWarn(msgNoString);
1160 Result = FALSE;
1161 cs->CD_Str = "";
1163 else
1164 { cs->CD_Str = AllocString(newline);
1165 free(newline);
1169 Get stringlen
1171 oldstr = cs->CD_Str;
1172 reallen = 0;
1173 while (*oldstr)
1174 { bytesread = ReadChar(&oldstr, bytes);
1175 if (bytesread == 2)
1176 { bytesread--;
1178 reallen += bytesread;
1181 if (cs->MinLen > 0 && reallen < cs->MinLen)
1182 { ShowWarn(msgShortString);
1184 if (cs->MaxLen > 0 && reallen > cs->MaxLen)
1185 { ShowWarn(msgLongString);
1188 cs->Nr = NumStrings;
1190 *csptr = cs;
1191 csptr = &cs->Next;
1192 ++NumStrings;
1197 fclose(fp);
1198 return(Result);
1201 /// FUNC: ScanCTFile
1204 This scans a catalog translation file.
1206 Inputs: ctfile - name of the translation file to scan.
1208 Result: TRUE, if successful, FALSE otherwise.
1210 int ScanCTFile(char *ctfile)
1212 FILE *fp;
1213 char *newline, *line, *idstr, *newidstr, *newstr;
1214 struct CatString *cs=NULL;
1215 int Result = TRUE;
1217 ScanFile = ctfile;
1218 ScanLine = 0;
1220 if (!(fp = fopen(ctfile, "r")))
1222 ShowError(msgNoCatalogTranslation, ctfile);
1225 if(!NoBufferedIO)
1226 setvbuf(fp, NULL, _IOFBF, buffer_size);
1229 while (!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
1231 switch(*line)
1233 case ';':
1234 if( CopyNEWs == TRUE )
1236 if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
1238 cs->NotInCT = TRUE;
1241 break;
1243 case '#':
1244 /// looking for command;
1245 if(*(++line) != '#')
1247 ShowWarn(msgNoCTCommand);
1249 ++line;
1250 OverSpace(&line);
1251 if (strnicmp(line, "version", 7) == 0)
1252 { if (CatVersionString || CatRcsId || CatName)
1253 { ShowWarn(msgDoubleCTVersion);
1255 line += 7;
1256 OverSpace(&line);
1257 CatVersionString = AllocString(line);
1259 else if (strnicmp(line, "codeset", 7) == 0)
1260 { line += 7;
1261 CodeSet = strtol(line, &line, 0);
1262 OverSpace(&line);
1263 if (*line)
1264 { ShowWarn(msgExtraCharacters);
1267 else if (strnicmp(line, "language", 8) == 0)
1268 { char *ptr;
1270 if (CatLanguage)
1271 { ShowWarn(msgDoubleCTLanguage);
1273 line += 8;
1274 OverSpace(&line);
1275 CatLanguage = AddCatalogChunk("LANG", line);
1277 if(LANGToLower)
1278 for (ptr = CatLanguage; *ptr; ptr++)
1279 *ptr = tolower((int) *ptr);
1281 else if (strnicmp(line, "chunk", 5) == 0)
1282 { char *ID;
1284 line += 5;
1285 OverSpace(&line);
1286 ID = line;
1287 line += sizeof(ULONG);
1288 OverSpace(&line);
1290 AddCatalogChunk(ID, AllocString(line));
1292 else if (strnicmp(line, "rcsid", 5) == 0)
1293 { if (CatVersionString || CatRcsId)
1294 { ShowWarn(msgDoubleCTVersion);
1296 line += 5;
1297 OverSpace(&line);
1298 CatRcsId = AllocString(line);
1300 else if (strnicmp(line, "name", 5) == 0)
1301 { if (CatVersionString || CatName)
1302 { ShowWarn(msgDoubleCTVersion);
1304 line += 4;
1305 OverSpace(&line);
1306 CatName = AllocString(line);
1308 else if (strnicmp(line+1, "lengthbytes", 11) == 0)
1309 { line += 12;
1310 if ((LengthBytes = strtol(line, &line, 0))
1311 > sizeof(long))
1312 { ShowWarn(msgNoLengthBytes, sizeof(long));
1313 LengthBytes = sizeof(long);
1316 else
1318 ShowWarn(msgUnknownCTCommand);
1321 break;
1323 default:
1324 if(*line == ' ' || *line == '\t')
1326 ShowWarn( msgUnexpectedBlanks );
1327 OverSpace( &line );
1329 idstr = line;
1331 while ((*line >= 'a' && *line <= 'z') ||
1332 (*line >= 'A' && *line <= 'Z') ||
1333 (*line >= '0' && *line <= '9') ||
1334 *line == '_')
1335 { ++line;
1337 if (idstr == line)
1339 ShowWarn(msgNoIdentifier);
1340 break;
1343 if(!(newidstr = malloc(line-idstr+1)))
1345 MemError();
1348 strncpy(newidstr, idstr, line-idstr);
1349 newidstr[line-idstr] = '\0';
1350 OverSpace(&line);
1352 if(*line)
1354 ShowWarn(msgExtraCharacters);
1357 if((newstr = ReadLine(fp, FALSE)))
1359 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1361 if(strcmp(cs->ID_Str, newidstr) == 0)
1363 break;
1366 if(cs == NULL)
1368 ShowWarn(msgUnknownIdentifier, newidstr);
1370 else
1372 char *oldstr;
1373 char bytes[10];
1374 int bytesread, reallen;
1376 if(cs->CT_Str)
1378 ShowWarn(msgDoubleIdentifier);
1379 Result = FALSE;
1380 free(cs->CT_Str);
1382 cs->CT_Str = AllocString(newstr);
1383 cs->NotInCT = FALSE;
1386 Get stringlen
1388 oldstr = cs->CT_Str;
1389 reallen = 0;
1390 while(*oldstr)
1392 bytesread = ReadChar(&oldstr, bytes);
1393 if(bytesread == 2)
1395 bytesread--;
1397 reallen += bytesread;
1400 if(cs->MinLen > 0 && reallen < cs->MinLen)
1402 ShowWarn(msgShortString);
1404 if(cs->MaxLen > 0 && reallen > cs->MaxLen)
1406 ShowWarn(msgLongString);
1410 // checking for trailing ellipsis...
1412 if( reallen >= 3 )
1414 long cd_len = strlen( cs->CD_Str );
1416 if( cd_len >= 3 )
1418 if( strcmp( &cs->CD_Str[ cd_len - 2 ], "..." ) == 0 )
1419 if( strcmp( &cs->CT_Str[ reallen - 2 ], "..." ) != 0 )
1421 // printf("ORG: '%s'\nNEW: '%s'\n", cs->CD_Str, cs->CT_Str);
1422 ShowWarn(msgTrailingEllipsis);
1428 // checking for trailing spaces
1430 if( reallen >= 1 )
1432 long cd_len = strlen( cs->CD_Str );
1434 if( cd_len >= 1 )
1436 if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
1437 if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
1438 ShowWarn(msgTrailingSpaces);
1444 free(newstr);
1446 else
1448 ShowWarn(msgNoString);
1449 if(cs)
1450 cs->CT_Str = "";
1452 free(newidstr);
1454 free(newline);
1457 fclose(fp);
1459 if (WarnCTGaps)
1460 { for (cs = FirstCatString; cs != NULL; cs = cs->Next)
1461 { if (cs->CT_Str == NULL)
1462 { ShowWarn(msgCTGap, cs->ID_Str);
1467 if(Result)
1468 CT_Scanned = TRUE;
1470 return(Result);
1473 /// FUNC: CatPuts
1477 CatPuts prints a string to a catalog. (The string is preceded by a
1478 long integer containing its length and probably padded up to word
1479 boundary or longword boundary, depending on the argument padbytes.)
1480 The arguments countnul should be TRUE if the NUL byte at the end of
1481 the string should be counted.
1483 int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
1485 unsigned long reallen, virtuallen, chunklen, swapped_long;
1486 int bytesread;
1487 char *oldstr;
1488 char bytes[10];
1490 /* Get Length of string.
1493 oldstr = str;
1494 reallen = 0;
1496 while(*oldstr)
1498 bytesread = ReadChar(&oldstr, bytes);
1499 if(bytesread == 2)
1501 bytesread--;
1503 reallen += bytesread;
1506 virtuallen = chunklen = reallen + LengthBytes;
1507 if(countnul || chunklen % padbytes == 0)
1509 virtuallen++;
1512 swapped_long = SwapLong( virtuallen );
1514 fwrite(&swapped_long, sizeof(virtuallen), 1, fp);
1515 if(LengthBytes)
1517 fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
1520 while(*str)
1522 bytesread = ReadChar(&str, bytes);
1523 if(bytesread)
1525 fwrite(bytes+bytesread-1, 1, 1, fp);
1531 putc('\0', fp);
1533 while(++chunklen % padbytes);
1535 return((int) chunklen+4);
1538 /// FUNC: PutCatalogChunk
1541 This puts a string chunk into the catalog
1543 int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
1545 fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
1546 return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
1549 /// FUNC: CalcRealLength
1551 This function measures the real (binary) length of source
1552 string. It correctly process 'slash chars' (\n, \000 etc),
1553 and gives the real length such source string have.
1555 Inputs: source - pointer to null terminated source string
1557 Result: real length
1560 int CalcRealLength(char *source)
1562 int count = 0;
1563 char *src = source;
1564 char bytes[10];
1566 while(*src)
1568 count += ReadChar(&src, bytes);
1571 // printf("%ld: '%s'\n", count, source);
1573 return(count);
1578 /// FUNC: CreateCatalog
1581 This creates a catalog.
1583 void CreateCat(char *CatFile)
1585 FILE *fp;
1586 int CatLen, HeadLen;
1587 struct CatString *cs;
1588 struct CatalogChunk *cc;
1589 int i;
1591 if(!CatVersionString && !CatRcsId)
1593 ShowError(msgNoCTVersion);
1596 if(!CatLanguage)
1598 ShowError(msgNoCTLanguage);
1601 if(strlen(CatLanguage) == 0)
1603 ShowError(msgNoCTLanguage);
1606 if(!(fp = fopen(CatFile, "w")))
1608 ShowError(msgNoCatalog, CatFile);
1611 if(!NoBufferedIO)
1612 setvbuf(fp, NULL, _IOFBF, buffer_size);
1615 fputs("FORM0000CTLG", fp);
1616 CatLen = 4;
1618 if(CatVersionString)
1620 struct CatalogChunk cc;
1621 char *verStr = NULL;
1623 cc.ID = MAKE_ID('F','V','E','R');
1625 if( strstr(CatVersionString, "$TODAY") )
1628 if(verStr = malloc(strlen(CatVersionString)+128))
1630 char *found = strstr(CatVersionString, "$TODAY");
1631 char dateStr[10];
1633 long tim;
1634 struct tm *t;
1636 time(&tim);
1637 t = gmtime(&tim);
1639 *found = 0;
1640 strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
1642 sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
1643 cc.ChunkStr = verStr;
1645 else
1646 MemError();
1649 else
1651 cc.ChunkStr = CatVersionString;
1654 cc.ID = SwapLong( cc.ID );
1655 CatLen += PutCatalogChunk(fp, &cc);
1657 if( verStr )
1658 free(verStr);
1660 else
1662 struct CatalogChunk cc;
1663 char* verStr;
1664 int year = 0, month = 0, day = 0;
1665 int version = 0, revision = 0;
1666 char* name = NULL;
1667 char* ptr;
1669 if(!CatRcsId)
1671 ShowError(msgNoCTVersion);
1673 else
1675 if(!(ptr = strstr(CatRcsId, "$Date:"))
1676 || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
1677 || !(ptr = strstr(CatRcsId, "$Revision:"))
1678 || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
1680 ShowError(msgWrongRcsId);
1682 if ((ptr = strstr(CatRcsId, "$Id:")))
1683 { int len = 0;
1684 char* found;
1686 ptr += 4;
1687 OverSpace(&ptr);
1688 found = ptr;
1690 while(*ptr && *ptr != '$' && *ptr != ' ' && *ptr != '\t')
1692 ++len;
1693 ++ptr;
1695 if(!(name = malloc(len+1)))
1697 MemError();
1699 strncpy(name, found, len);
1700 name[len] = '\0';
1703 if (CatName)
1704 { name = CatName;
1706 else if (!name)
1708 ShowError(msgNoCTVersion);
1709 name = "";
1711 if (!(verStr = malloc(strlen(name) + 256)))
1713 MemError();
1716 sprintf(verStr, "$V");
1717 sprintf(verStr, "ER: %s %ld.%ld (%ld.%ld.%ld)", name, version, revision, day, month, year);
1719 cc.ID = MAKE_ID('F','V','E','R');
1720 cc.ID = SwapLong( cc.ID );
1721 cc.ChunkStr = verStr;
1722 CatLen += PutCatalogChunk(fp, &cc);
1726 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1728 CatLen += PutCatalogChunk(fp, cc);
1731 i = 32;
1732 fputs("CSET", fp);
1735 int i_tmp = SwapLong( i );
1737 fwrite(&i_tmp, sizeof(i_tmp), 1, fp);
1740 while(i-- > 0)
1742 putc('\0', fp);
1745 CatLen += 48;
1746 fprintf(fp, "STRS0000");
1747 HeadLen = CatLen;
1750 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1752 int FillUsed = FALSE;
1753 int tmp_ID = SwapLong( cs->ID );
1755 if(Fill)
1758 if(cs->CT_Str)
1760 if(strlen(cs->CT_Str) == 0)
1762 fwrite(&tmp_ID, sizeof(tmp_ID), 1, fp);
1763 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1764 FillUsed = TRUE;
1767 else
1769 fwrite(&tmp_ID, sizeof(cs->ID), 1, fp);
1770 CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
1771 FillUsed = TRUE;
1775 if((!FillUsed) && cs->CT_Str && (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
1777 fwrite(&tmp_ID, sizeof( tmp_ID ), 1, fp);
1778 CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
1784 int tmp_Len;
1786 fseek(fp, 4, SEEK_SET);
1788 tmp_Len = SwapLong( CatLen );
1789 fwrite(&tmp_Len, sizeof(tmp_Len), 1, fp);
1790 fseek(fp, HeadLen-4, SEEK_CUR);
1792 CatLen -= HeadLen;
1793 tmp_Len = SwapLong( CatLen );
1794 fwrite(&tmp_Len, sizeof(CatLen), 1, fp);
1797 fclose(fp);
1799 Expunge();
1803 /// FUNC: CreateCTFile
1806 This creates a new catalog translation file.
1808 void CreateCTFile(char *NewCTFile)
1810 FILE *fp;
1811 struct CDLine *cd;
1812 struct CatString *cs;
1813 struct CatalogChunk *cc;
1814 char *line;
1816 if(!CatVersionString && !CatRcsId)
1818 ScanLine = 1;
1819 ShowWarn(msgNoCTVersion);
1822 if(!(fp = fopen(NewCTFile, "w")))
1824 ShowError(msgNoNewCTFile);
1828 if(!NoBufferedIO)
1829 setvbuf(fp, NULL, _IOFBF, buffer_size);
1832 if(CatRcsId)
1834 fprintf(fp, "## rcsid %s\n",
1835 CatRcsId ? CatRcsId : "");
1836 if(CatName)
1837 fprintf(fp, "## name %s\n", CatName);
1839 else
1841 if(CatVersionString)
1842 fprintf(fp, "## version %s\n", CatVersionString);
1843 else
1845 fprintf(fp, "## version $V");
1846 fprintf(fp, "%c", 50+19); // E
1847 fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
1853 char *lang = NULL;
1855 if(CatLanguage == NULL)
1856 if(lang = getenv("ENV:language"))
1858 int i;
1860 for(i=0;i<strlen(lang); i++)
1861 if(lang[i] == '\n')
1863 lang[i] = 0;
1864 break;
1867 CatLanguage = lang;
1870 fprintf(fp, "## language %s\n## codeset %d\n;\n",
1871 CatLanguage ? CatLanguage : "X", CodeSet);
1873 if(lang)
1875 free(lang);
1876 CatLanguage = NULL;
1882 for (cc = FirstChunk; cc != NULL; cc = cc->Next)
1884 if (cc->ChunkStr != CatLanguage)
1886 fprintf(fp, "## chunk ");
1887 fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
1888 fprintf(fp, " %s\n", cc->ChunkStr);
1892 for(cd = FirstCDLine, cs = FirstCatString;
1893 cd != NULL;
1894 cd = cd->Next)
1896 switch(*cd->Line)
1898 case '#':
1899 break;
1901 case ';':
1902 fprintf(fp, "%s\n", cd->Line);
1903 break;
1905 default:
1906 if(cs)
1909 fprintf(fp, "%s\n", cs->ID_Str);
1910 fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
1911 putc(';', fp);
1912 putc(' ', fp);
1914 fprintf(fp, "%s\n%s\n;", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
1916 if( !NoSpace )
1917 putc(' ', fp);
1921 for (line = cs->CD_Str; *line; ++line)
1923 putc((int) *line, fp);
1924 if(*line == '\n')
1926 putc(';', fp);
1927 if( !NoSpace )
1928 putc(' ', fp);
1931 putc('\n', fp);
1933 if(cs->NotInCT && CT_Scanned)
1934 fprintf(fp, ";\n; %s\n", Msg_New);
1936 cs = cs->Next;
1941 fclose(fp);
1945 /// FUNC: InitCatStringOutput
1948 InitCatStringOutput gets called before writing a catalog string as
1949 source.
1951 Inputs: fp = file pointer to the output file
1952 type = one of TYPE_C create C strings
1953 TYPE_ASSEMBLER create Assembler strings
1954 TYPE_OBERON create Oberon strings
1955 TYPE_E create E strings
1956 TYPE_NONE create simple strings
1958 int OutputMode = OutputMode_None;
1959 int OutputType = TYPE_C;
1960 FILE *OutputFile;
1961 int OutputLen;
1963 void InitCatStringOutput(FILE *fp)
1965 OutputLen = 0;
1966 OutputFile = fp;
1967 OutputMode = OutputMode_None;
1968 switch(OutputType)
1969 { case TYPE_C:
1970 case TYPE_OBERON:
1971 putc('\"', fp);
1972 OutputMode = OutputMode_Ascii;
1973 break;
1974 case TYPE_E:
1975 putc('\'', fp);
1976 case TYPE_ASSEMBLER:
1977 case TYPE_NONE:
1978 break;
1982 /// FUNC: SeparateCatStringOutput
1985 SeparateCatStringOutput gets called to split a catalog into separate
1986 lines.
1988 void SeparateCatStringOutput(void)
1990 switch(OutputType)
1991 { case TYPE_C:
1992 if (!LongStrings)
1993 { fputs("\"\\\n\t\"", OutputFile);
1995 break;
1996 case TYPE_E:
1997 if (!LongStrings)
1998 { fputs("\' +\n\t\'", OutputFile);
2000 break;
2001 case TYPE_OBERON:
2002 if (!LongStrings)
2003 { fputs("\"\n\t\"", OutputFile);
2005 break;
2006 case TYPE_ASSEMBLER:
2007 if (!LongStrings)
2008 { if (OutputMode == OutputMode_Ascii)
2009 { putc('\'', OutputFile);
2011 putc('\n', OutputFile);
2012 OutputMode = OutputMode_None;
2014 break;
2015 case TYPE_NONE:
2016 break;
2020 /// FUNC: WriteBinChar
2023 WriteBinChar writes one binary character into the source file
2025 void WriteBinChar(int c)
2028 switch(OutputType)
2029 { case TYPE_C:
2030 case TYPE_E:
2031 case TYPE_OBERON:
2032 switch(c)
2033 { case '\b':
2034 fputs("\\b", OutputFile);
2035 break;
2036 case '\n':
2037 fputs("\\n", OutputFile);
2038 break;
2039 case '\r':
2040 fputs("\\r", OutputFile);
2041 break;
2042 case '\t':
2043 fputs("\\t", OutputFile);
2044 break;
2045 case '\f':
2046 fputs("\\f", OutputFile);
2047 break;
2048 case '\0':
2049 fputs("\\000", OutputFile);
2050 break;
2051 default:
2052 if(OutputType == TYPE_E && c == '\033')
2054 fputs("\\e", OutputFile);
2056 else
2058 fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
2059 ((c >> 3) & 7) + '0', (c & 7) + '0');
2061 break;
2063 ++OutputLen;
2064 OutputMode = OutputMode_Bin;
2065 break;
2066 case TYPE_ASSEMBLER:
2067 switch(OutputMode)
2068 { case OutputMode_None:
2069 fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
2070 break;
2071 case OutputMode_Ascii:
2072 putc('\'', OutputFile);
2073 case OutputMode_Bin:
2074 fprintf(OutputFile, ",$%02x", c & 0xff);
2075 break;
2077 ++OutputLen;
2078 OutputMode = OutputMode_Bin;
2079 break;
2080 case TYPE_NONE:
2081 ShowWarn(msgNoBinChars);
2082 break;
2086 /// FUNC: WriteAsciiChar
2089 WriteAsciiChar writes one ascii character into the source file.
2091 void WriteAsciiChar(int c)
2094 switch(OutputType)
2095 { case TYPE_C:
2096 case TYPE_OBERON:
2097 switch(c)
2098 { case '\"':
2099 fputs("\\\"", OutputFile);
2100 break;
2101 default:
2102 putc(c, OutputFile);
2103 break;
2105 ++OutputLen;
2106 OutputMode = OutputMode_Ascii;
2107 break;
2108 case TYPE_E:
2109 switch(c)
2110 { case '\'':
2111 fputs("''", OutputFile);
2112 break;
2113 default:
2114 putc(c, OutputFile);
2115 break;
2117 ++OutputLen;
2118 OutputMode = OutputMode_Ascii;
2119 break;
2120 case TYPE_ASSEMBLER:
2121 if (c == '\'')
2122 { WriteBinChar(c);
2124 else
2125 { switch (OutputMode)
2126 { case OutputMode_None:
2127 fprintf(OutputFile, "\tdc.b\t\'%c", c);
2128 break;
2129 case OutputMode_Ascii:
2130 putc(c, OutputFile);
2131 break;
2132 case OutputMode_Bin:
2133 fprintf(OutputFile, ",\'%c", c);
2134 break;
2136 ++OutputLen;
2137 OutputMode = OutputMode_Ascii;
2139 break;
2140 case TYPE_NONE:
2141 putc(c, OutputFile);
2142 break;
2146 /// FUNC: TerminateCatStringOutput
2149 TerminateCatStringOutput finishs the output of a catalog string.
2151 void TerminateCatStringOutput(void)
2153 switch(OutputType)
2154 { case TYPE_C:
2155 case TYPE_OBERON:
2156 putc('\"', OutputFile);
2157 break;
2158 case TYPE_E:
2159 putc('\'', OutputFile);
2160 break;
2161 case TYPE_ASSEMBLER:
2162 switch(OutputMode)
2163 { case OutputMode_Ascii:
2164 putc('\'', OutputFile);
2165 case OutputMode_Bin:
2166 break;
2167 case OutputMode_None:
2168 break;
2170 case TYPE_NONE:
2171 break;
2176 /// FUNC: WriteString
2178 This writes a sourcestring.
2180 void WriteString(FILE *fpout, char *str, long Len)
2182 char bytes[10];
2183 int bytesread;
2184 int needseparate = FALSE;
2186 InitCatStringOutput(fpout);
2187 if (Len >= 0)
2188 { int i;
2190 for(i = LengthBytes; i >= 1; i--)
2191 { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
2195 while (*str)
2196 { bytesread = ReadChar(&str, bytes);
2197 if (bytesread)
2198 { unsigned char c;
2200 if (needseparate)
2201 { SeparateCatStringOutput();
2202 needseparate = FALSE;
2205 c = bytes[bytesread-1];
2206 if ((c >= 0x20 && c < 0x7f) || c >= 0xa0)
2207 { WriteAsciiChar((int) c);
2209 else
2210 { WriteBinChar((int) c);
2213 else
2214 { needseparate = TRUE;
2217 TerminateCatStringOutput();
2220 /// FUNC: AllocFileName
2222 This function creates a copy of a filename, removes an
2223 optional ending and pathname components, if desired.
2225 Inputs: filename - the filename to copy
2226 howto - a set of bits
2227 bit 0: 1 = remove ending, 0 = leave it
2228 bit 1: 1 = remove pathname, 0 = leave it
2230 Result: The copy of the filename
2232 char *AllocFileName(char *filename, int howto)
2234 char *tempstr, *ptr;
2236 if (!(tempstr = strdup(filename)))
2237 { MemError();
2238 MyExit(10);
2241 /* Remove pathname components, if desired */
2242 if (howto & 2)
2243 { if ((ptr = strchr(tempstr, ':')))
2244 { tempstr = ptr+1;
2246 if ((ptr = strrchr(tempstr, '/')))
2247 { tempstr = ptr+1;
2251 /* Remove ending, if desired. */
2252 if (howto & 1)
2253 { if ((ptr = strrchr(tempstr, '.')))
2254 { *ptr = '\0';
2258 return(tempstr);
2261 /// FUNC: AddFileName
2263 This function adds a pathname and a filename to a full
2264 filename.
2266 Inputs: pathname - the leading pathname
2267 filename - the filename
2269 Result: The new filename
2271 char *AddFileName(char *pathname, char *filename)
2273 char *buffer;
2274 int size = strlen(pathname) + strlen(filename) + 2;
2276 if (!(buffer = malloc(size)))
2277 { MemError();
2278 MyExit(10);
2281 #if defined(__amigados)
2282 strcpy(buffer, pathname);
2283 AddPart((char *) buffer, (char *) filename, size);
2284 #else
2285 sprintf(buffer, "%s/%s", pathname, filename);
2286 #endif
2288 return(buffer);
2292 /// FUNC: CreateSourceFile
2295 Finally the source creation.
2297 void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
2300 FILE *fpin, *fpout;
2301 char *line;
2302 char *OrigTemplateFile = TemplateFile;
2304 ScanFile = SourceFile;
2305 ScanLine = 0;
2308 Open the source file. This may be found in various places
2310 if(!(fpin = fopen(TemplateFile, "r")))
2312 #ifdef __amigados
2313 if(*prefs_sddir != 0)
2315 TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
2316 fpin = fopen(TemplateFile, "r");
2318 #endif
2321 if(!fpin)
2323 char *sddir;
2325 if((sddir = getenv(FLEXCAT_SDDIR)))
2327 TemplateFile = AddFileName(sddir, OrigTemplateFile);
2328 fpin = fopen(TemplateFile, "r");
2332 if (!fpin)
2333 { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
2334 fpin = fopen(TemplateFile, "r");
2337 if (!fpin)
2339 ShowError(msgNoSourceDescription, OrigTemplateFile);
2340 return;
2343 if (!(fpout = fopen(SourceFile, "w")))
2345 ShowError(msgNoSource, SourceFile);
2346 return;
2349 if(!NoBufferedIO)
2350 setvbuf(fpin, NULL, _IOFBF, buffer_size);
2351 if(!NoBufferedIO)
2352 setvbuf(fpout, NULL, _IOFBF, buffer_size);
2355 while(!feof(fpin) && (line = ReadLine(fpin, FALSE)))
2356 { struct CatString *cs;
2357 int NeedRepeat;
2358 char bytes[10];
2359 int bytesread;
2361 cs = FirstCatString;
2363 { char *currentline = line;
2364 NeedRepeat = FALSE;
2366 if (*currentline == '#' && *(++currentline) == '#')
2367 { ++currentline;
2368 OverSpace(&currentline);
2370 if(strnicmp( currentline, "rem", 3 ) == 0)
2372 // we just skip this line
2373 continue;
2376 if (strnicmp(currentline, "stringtype", 10) == 0)
2377 { currentline += 10;
2378 OverSpace(&currentline);
2379 if (strnicmp(currentline, "c", 1) == 0)
2380 { OutputType = TYPE_C;
2381 ++currentline;
2383 else if (strnicmp(currentline, "assembler", 9) == 0)
2384 { OutputType = TYPE_ASSEMBLER;
2385 currentline += 9;
2387 else if (strnicmp(currentline, "oberon", 6) == 0)
2388 { OutputType = TYPE_OBERON;
2389 currentline += 6;
2391 else if (strnicmp(currentline, "e", 1) == 0)
2392 { OutputType = TYPE_E;
2393 ++currentline;
2395 else if (strnicmp(currentline, "none", 4) == 0)
2396 { OutputType = TYPE_NONE;
2397 currentline += 4;
2399 else
2400 { ShowWarn(msgUnknownStringType);
2401 currentline += strlen(currentline);
2403 OverSpace(&currentline);
2404 if (*currentline)
2405 { ShowWarn(msgExtraCharacters);
2407 continue;
2409 else if (strnicmp(currentline, "shortstrings", 12) == 0)
2410 { currentline += 12;
2411 LongStrings = FALSE;
2412 OverSpace(&currentline);
2413 if (*currentline)
2414 { ShowWarn(msgExtraCharacters);
2416 continue;
2420 currentline = line;
2421 while(*currentline)
2422 { bytesread = ReadChar(&currentline, bytes);
2423 if (bytesread)
2424 { if (*bytes == '%')
2425 { char c;
2427 switch(c = *(currentline++))
2428 { case 'b':
2429 fputs(BaseName, fpout);
2430 break;
2431 case 'n':
2432 fprintf(fpout, "%d", NumStrings);
2433 break;
2434 case 'v':
2435 fprintf(fpout, "%d", CatVersion);
2436 break;
2437 case 'l':
2438 WriteString(fpout, Language, -1);
2439 break;
2440 case 'f':
2441 { char *tempstr;
2443 if ((c = *currentline++) == 'v')
2444 { fputs(VERS, fpout);
2446 else
2447 { tempstr = AllocFileName(CDFile, c - '0');
2448 fputs(tempstr, fpout);
2451 break;
2452 case 'o':
2453 { char *tempstr;
2455 tempstr = AllocFileName(SourceFile, *currentline++ - '0');
2456 fputs(tempstr, fpout);
2458 break;
2459 case 'i':
2460 NeedRepeat = TRUE;
2461 if (cs) fputs(cs->ID_Str, fpout);
2462 break;
2464 case 'a':
2465 case 't':
2467 case 'd':
2468 case 'x':
2469 case 'c':
2470 case '0':
2471 case '1':
2472 case '2':
2473 case '3':
2474 case '4':
2475 case '5':
2476 case '6':
2477 case '7':
2478 case '8':
2479 case '9':
2481 int len = 0;
2483 while(c >= '0' && c <= '9')
2485 len = (c - '0') + len * 10;
2486 c = *currentline++;
2490 if(c == 'a')
2492 int _len = len ? len : 4;
2493 char *start;
2494 char _StrLen[20 + 1];
2496 sprintf(_StrLen, "%020lx", cs->ID);
2498 start = &_StrLen[20-_len*2];
2499 while(_len>0)
2501 fprintf(fpout, "\\x%.2s", start);
2502 start+=2;
2503 _len--;
2507 if(c == 't')
2509 int _len = len ? len : 4;
2510 char *start;
2511 char _StrLen[20 + 1];
2513 sprintf(_StrLen, "%020lx", ((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
2515 start = &_StrLen[20-_len*2];
2516 while(_len>0)
2518 fprintf(fpout, "\\x%.2s", start);
2519 start+=2;
2520 _len--;
2524 if(c == 'c' || c == 'd' || c == 'x')
2526 char buffer[20];
2528 if(c == 'c') c = 'o';
2530 if(len)
2531 sprintf(buffer, "%%0%d%c", len, c);
2532 else
2533 sprintf(buffer, "%%%c", c);
2535 if(cs) fprintf(fpout, buffer, cs->ID);
2539 NeedRepeat = TRUE;
2541 break;
2543 case 'e':
2544 NeedRepeat = TRUE;
2545 if (cs) fprintf(fpout, "%d", cs->Nr);
2546 break;
2547 case 's':
2548 NeedRepeat = TRUE;
2549 if (cs)
2550 { char *idstr;
2551 unsigned long len = 0;
2553 if (LengthBytes)
2554 { idstr = cs->CD_Str;
2555 while(*idstr)
2556 { bytesread = ReadChar(&idstr, bytes);
2557 if (bytesread)
2558 { ++len;
2562 WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
2564 break;
2565 case '(':
2566 NeedRepeat = TRUE;
2567 while(*currentline && *currentline != ')')
2568 { bytesread = ReadChar(&currentline, bytes);
2569 if (bytesread && cs && cs->Next)
2570 { putc((int) bytes[bytesread-1], fpout);
2573 if (!*currentline)
2574 { ShowWarn(msgNoTerminateBracket);
2576 else
2577 { ++currentline;
2579 break;
2581 // !!!! FIX !!!!
2583 case 'z':
2585 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
2587 NeedRepeat = TRUE;
2589 while(diff > 0)
2591 fprintf(fpout, "\\x00");
2592 diff--;
2595 break;
2598 default:
2599 { int c = *currentline++;
2601 putc(c, fpout);
2605 else
2606 { putc((int) bytes[bytesread-1], fpout);
2610 putc('\n', fpout);
2612 while(NeedRepeat && cs && (cs = cs->Next));
2614 free(line);
2617 fclose(fpin);
2618 fclose(fpout);
2622 /// FUNC: Usage
2624 The Usage function describes the programs calling syntax.
2626 void Usage(void)
2629 fputs((char *) msgUsageHead, stderr);
2630 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);
2631 fprintf(stderr, "%s\n%s\n%s\n%s\n", msgUsage, msgUsage_2, msgUsage_3, msgUsage_4 );
2632 fprintf(stderr, "\n\n%s"
2634 #ifdef _M68040
2635 " [040]"
2636 #else
2637 #ifdef _M68060
2638 " [060]"
2639 #else
2640 #ifdef _M68030
2641 " [030]"
2642 #else
2643 #ifdef _M68020
2644 " [020]"
2645 #else
2646 #ifdef _M68010
2647 " [010]"
2648 #endif
2649 #endif
2650 #endif
2651 #endif
2652 #endif
2654 "\n", VString);
2657 fprintf(stderr, "%s\n", EString);
2658 MyExit(5);
2661 /// FUNC: main
2663 Finally the main function. Does nothing special except for scanning
2664 the arguments.
2666 int main(int argc, char *argv [])
2668 char *cdfile, *ctfile, *newctfile, *catalog;
2669 char *source, *template;
2670 int i;
2672 if(argc == 0) /* Aztec's entry point for workbench programs */
2674 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2675 fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
2676 fprintf(stderr, "for more information\n");
2677 exit(5);
2680 cdfile = ctfile = newctfile = catalog = NULL;
2683 /* let's open catalog files by hand if necessary */
2684 /* should be done automatically anyway for most */
2685 /* cases, but, that depends on compiler... */
2687 #if defined(_DCC)
2688 // STATIC __autoinit VOID _STIOpenFlexCatCatalog(VOID)
2689 #elif defined(__SASC)
2690 // VOID _STIOpenFlexCatCatalog(VOID)
2691 #elif defined(__GNUC__)
2692 // VOID _STIOpenFlexCatCatalog(VOID)
2693 #elif defined(__INTEL_COMPILER)
2694 // VOID _STIOpenFlexCatCatalog(VOID)
2695 #else
2696 OpenFlexCatCatalog(); /* no autoopen. we do it then */
2697 #endif
2700 // Big Endian vs Little Endian (both supported ;-)
2701 if( !SwapChoose() )
2703 fprintf(stderr, "FlexCat is unable to determine the\n");
2704 fprintf(stderr, "the byte order used by your system.\n");
2705 fprintf(stderr, "It's neither Little nor Big Endian?!.\n");
2706 exit(5);
2711 #if defined(__amigados)
2712 ReadPrefs();
2713 #endif
2715 if(argc == 1)
2717 Usage();
2720 for (i = 1; i < argc; i++)
2722 if(strnicmp (argv[i], "catalog=", 8) == 0)
2724 catalog = argv[i] + 8;
2726 else
2727 if(stricmp (argv[i], "catalog") == 0)
2729 if(i+1 == argc)
2730 Usage();
2731 catalog = argv[++i];
2733 else
2734 if(stricmp(argv[i], "nooptim") == 0)
2736 NoOptim = TRUE;
2738 else
2739 if(stricmp(argv[i], "fill") == 0)
2741 Fill = TRUE;
2743 else
2744 if(stricmp(argv[i], "quiet") == 0)
2746 Quiet = TRUE;
2748 else
2749 if(stricmp(argv[i], "flush") == 0)
2751 DoExpunge = TRUE;
2753 else
2754 if(stricmp(argv[i], "nobeep") == 0)
2756 NoBeep = TRUE;
2758 else
2759 if(stricmp(argv[i], "nobufferedio") == 0)
2761 NoBufferedIO = TRUE;
2763 else
2764 if (strnicmp (argv[i], "newctfile=", 10) == 0)
2766 newctfile = argv[i] + 10;
2768 else
2769 if(strnicmp (argv[i], "newctfile", 9) == 0)
2771 if (i+1 == argc)
2772 Usage();
2773 newctfile = argv[++i];
2775 else
2776 if(stricmp(argv[i], "nolangtolower") == 0)
2778 LANGToLower = FALSE;
2780 else
2781 if(stricmp(argv[i], "modified") == 0)
2783 Modified = TRUE;
2785 else
2786 if(stricmp(argv[i], "warnctgaps") == 0)
2788 WarnCTGaps = TRUE;
2790 else
2791 if(stricmp(argv[i], "copymsgnew") == 0)
2793 CopyNEWs = TRUE;
2795 else
2796 if(stricmp(argv[i], "nospace") == 0)
2798 NoSpace = TRUE;
2800 else
2801 if(stricmp(argv[i], "oldmsgnew") == 0)
2803 sprintf( Old_Msg_New, "; %s", argv[++i] );
2805 else
2806 if(cdfile == NULL)
2808 if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
2810 Usage();
2812 if(!ScanCDFile(cdfile = argv[i]))
2814 MyExit(10);
2817 else
2818 if(strchr(argv[i], '='))
2820 source = AllocString(argv[i]);
2821 *(template = strchr(source, '=')) = '\0';
2822 ++template;
2824 CreateSourceFile(source, template, cdfile);
2826 else
2828 if (ctfile)
2830 Usage();
2832 ctfile = argv[i];
2837 #if defined(__amigados)
2838 if(Modified)
2840 if(cdfile && ctfile && catalog)
2842 long cd_time, ct_time, cat_time;
2844 if((cd_time = getft(cdfile)) != -1)
2846 if((ct_time = getft(ctfile)) != -1)
2848 if((cat_time = getft(catalog)) == -1)
2849 cat_time = 0;
2851 if((cat_time > ct_time) &&
2852 (cat_time > cd_time))
2854 if(!Quiet)
2856 fprintf(stderr, (char *) msgUpToDate, catalog);
2857 putc('\n', stderr);
2860 MyExit(GlobalReturnCode);
2862 else
2864 if(!Quiet)
2866 fprintf(stderr, "--> %s", catalog);
2867 putc('\n', stderr);
2871 else
2873 ShowError(msgCantCheckDate, ctfile);
2876 else
2878 ShowError(msgCantCheckDate, cdfile);
2882 #endif
2884 if(ctfile)
2886 if(!ScanCTFile(ctfile))
2887 MyExit(10);
2890 if(catalog)
2892 if(!ctfile)
2894 fprintf(stderr, (char *) msgNoCTArgument);
2895 Usage();
2897 CreateCat(catalog);
2900 if(newctfile)
2902 CreateCTFile(newctfile);
2905 MyExit(GlobalReturnCode);
2908 /// FUNC: wbmain
2911 Dice's entry point for workbench programs
2913 #if defined(__amigados) && defined(_DCC)
2914 void wbmain(struct WBStartup *wbmsg)
2916 fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
2917 fprintf(stderr, "Open a Shell session and type FlexCat\n");
2918 fprintf(stderr, "for syntax and more information\n");
2920 exit(5);
2922 #endif