Some indentation changes
[AROS.git] / tools / FlexCat / flexcat.c
blob18420c606aa93275e234765047743687d09e21c3
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 vfprintf(stderr, msg, ptr);
552 putc('\n', stderr);
554 va_end(ptr);
556 NumberOfWarnings++;
557 GlobalReturnCode = 5;
560 /// FUNC: AllocString
563 This allocates a string
565 char *AllocString(const char *str)
567 { char *ptr;
569 if (!(ptr = malloc(strlen(str)+1)))
570 { MemError();
572 strcpy(ptr, str);
573 return(ptr);
576 /// FUNC: Add catalog chunk
579 This adds a new catalog chunk to the list of catalog
580 chunks.
582 char *AddCatalogChunk(char *ID, const char *string)
584 struct CatalogChunk *cc, **ccptr;
586 if (!(cc = malloc(sizeof(*cc))))
587 { MemError();
589 cc->Next = NULL;
590 cc->ID = *((ULONG *) ID);
591 cc->ChunkStr = AllocString(string);
594 Put the new chunk to the end of the chunk list.
596 for (ccptr = &FirstChunk; *ccptr != NULL; ccptr = &(*ccptr)->Next)
599 *ccptr = cc;
600 return(cc->ChunkStr);
603 /// FUNC: gethex
605 This translates a hex character.
607 int gethex(int c)
609 if (c >= '0' && c <= '9')
610 { return(c - '0');
612 else if (c >= 'a' && c <= 'f')
613 { return(c - 'a' + 10);
615 else if (c >= 'A' && c <= 'F')
616 { return(c - 'A' + 10);
618 ShowWarn(msgExpectedHex);
619 return(0);
622 /// FUNC: getoctal
625 This translates an octal digit.
627 int getoctal(int c)
630 if (c >= '0' && c <= '7')
632 return(c - '0');
635 ShowWarn(msgExpectedOctal);
636 return(0);
640 /// FUNC: ReadLine
643 Reading a line is somewhat complicated in order to allow lines of any
644 length.
646 Inputs: fp - the file, where the input comes from
647 AllowComment - TRUE, if a leading semicolon should force to
648 interpret the line as a comment line
650 #define BUFSIZE 4096
651 char *ReadLine(FILE *fp, int AllowComment)
654 char *OldLine, *NewLine = NULL;
655 int c = '\0';
656 int Len = 0, LineLen = 0;
657 int FirstChar = TRUE;
658 int BackslashSeen = FALSE;
659 int BackslashSeenOn = 0; /* position the last backslash was seen on */
660 int CommentLine = FALSE; /* if TRUE we should ignore normally treat trailing \'s */
662 while(c != EOF)
664 if(Len+10 > LineLen)
666 OldLine = NewLine;
667 if(!(NewLine = malloc(LineLen+BUFSIZE)))
668 MemError();
670 strncpy(NewLine, OldLine, LineLen);
671 if(OldLine)
672 free(OldLine);
674 LineLen += BUFSIZE;
677 c = getc(fp);
679 if(FirstChar)
681 if(c == EOF)
683 free(NewLine);
684 return(NULL);
687 if(c == ';')
689 CommentLine = TRUE;
692 FirstChar = FALSE;
695 switch(c)
697 case '\r':
698 break;
700 case '\n':
701 ++ScanLine;
702 if(BackslashSeen)
704 NewLine[Len++] = c;
705 BackslashSeen = FALSE;
706 break;
708 c = EOF;
710 case EOF:
711 break;
713 /* Let's check for trailing \\ */
714 case '\\':
716 if(!CommentLine)
718 if(BackslashSeen)
720 if(BackslashSeenOn == (Len-1))
722 BackslashSeen = FALSE;
723 NewLine[Len++] = c;
724 break;
728 BackslashSeen = TRUE;
729 BackslashSeenOn = Len;
732 NewLine[Len++] = c;
733 break;
737 default:
738 BackslashSeen = FALSE;
739 NewLine[Len++] = c;
743 NewLine[Len] = '\0';
745 return(NewLine);
749 /// FUNC: OverSpace
752 This removes trailing blanks.
754 void OverSpace(char **strptr)
756 { int c;
758 while ((c = **strptr) == ' ' || c == '\t')
759 { (*strptr)++;
764 /// FUNC: Expunge
766 void Expunge(void)
768 #if defined(__amigados)
771 if(DoExpunge)
773 #ifdef __EXPUNGE_ALL__
774 APTR Memory;
776 if(Memory = AllocMem(-1, NULL))
777 FreeMem(Memory, -1); // just in case ;-)
778 #else
780 #pragma libcall LocaleBase localeExpunge 12 00
781 VOID localeExpunge(VOID);
783 struct Library *LocaleBase;
785 if(LocaleBase = OpenLibrary("locale.library", 0))
787 localeExpunge();
788 CloseLibrary(LocaleBase);
791 #endif
793 #endif
799 /// FUNC: ReadChar
802 ReadChar scans an input line translating the backslash characters.
804 Inputs: char * - a pointer to a stringpointer; the latter points to the
805 next character to be read and points behind the read
806 bytes after executing ReadChar
807 dest - a pointer to a buffer, where the read bytes should be
808 stored
810 Result: number of bytes that are written to dest (between 0 and 2)
812 int ReadChar(char **strptr, char *dest)
814 char c;
815 int i;
817 switch(c = *((*strptr)++))
819 case '\\':
821 switch(c = tolower((int) *((*strptr)++)))
823 case '\n':
824 return(0);
825 case 'b':
826 *dest = '\b';
827 break;
828 case 'c':
829 *dest = '\233';
830 break;
831 case 'e':
832 *dest = '\033';
833 break;
834 case 'f':
835 *dest = '\f';
836 break;
837 case 'g':
838 *dest = '\007';
839 break;
840 case 'n':
841 *dest = '\n';
842 break;
843 case 'r':
844 *dest = '\r';
845 break;
846 case 't':
847 *dest = '\t';
848 break;
849 case 'v':
850 *dest = '\013';
851 break;
852 case 'x':
853 *dest = gethex((int) **strptr);
854 (*strptr)++;
855 if (((c = **strptr) >= '0' && c <= '9') ||
856 (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
857 { *dest = (*dest << 4) + gethex((int) c);
858 (*strptr)++;
860 break;
861 case '0':
862 case '1':
863 case '2':
864 case '3':
865 case '4':
866 case '5':
867 case '6':
868 case '7':
870 *dest = getoctal((int)c);
872 for(i = 0; i < 2; i++)
874 if((c = **strptr) >= '0' && c <= '7')
876 *dest = (*dest << 3) + getoctal((int) c);
877 (*strptr)++;
880 break;
881 case ')':
882 case '\\':
883 *(dest++) = '\\';
884 *dest = c;
885 return(2);
886 default:
887 *dest = c;
889 break;
891 default:
892 *dest = c;
894 return(1);
897 /// FUNC: ScanCDFile
900 This scans the catalog description file.
902 Inputs: cdfile - name of the catalog description file
904 Result: TRUE, if successful, FALSE otherwise
906 int ScanCDFile(char *cdfile)
908 FILE *fp;
909 struct CDLine *cdline, **cdptr = &FirstCDLine;
910 struct CatString *cs, **csptr = &FirstCatString;
911 char *line, *newline;
912 char *ptr;
913 int NextID = 0, len;
914 int Result = TRUE;
916 ScanFile = cdfile;
917 ScanLine = 0;
919 if(!(fp = fopen(cdfile, "r")))
921 ShowError(msgNoCatalogDescription, cdfile);
924 if(!NoBufferedIO)
925 setvbuf(fp, NULL, _IOFBF, buffer_size);
928 Get the basename
930 if ((ptr = strchr(cdfile, ':')))
931 { cdfile = ptr+1;
933 if ((ptr = strrchr(cdfile, '/')))
934 { cdfile = ptr+1;
936 if ((ptr = strrchr(cdfile, '.')))
937 { len = ptr-cdfile;
939 else
940 { len = strlen(cdfile);
942 if (!(BaseName = malloc(len+1)))
943 { MemError();
945 strncpy(BaseName, cdfile, len);
946 BaseName[len] = '\0';
948 while(!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
950 if(!(cdline = malloc(sizeof(*cdline))))
952 MemError();
955 *cdptr = cdline;
956 cdptr = &cdline->Next;
957 cdline->Next = NULL;
958 cdline->Line = line = AllocString(newline);
959 free(newline);
961 if (*line == ';')
963 continue;
966 if(*line == '#')
968 int CheckExtra = TRUE;
970 if (strnicmp(line+1, "language", 8) == 0)
972 char *ptr;
974 line += 9;
975 OverSpace(&line);
976 Language = AllocString(line);
978 if(LANGToLower)
980 for (ptr = Language; *ptr; ptr++)
982 *ptr = tolower((int) *ptr);
984 CheckExtra = FALSE;
988 else
989 if(strnicmp(line+1, "version", 7) == 0)
991 CatVersion = strtol(line+8, &line, 0);
993 else
995 if(strnicmp(line+1, "basename", 8) == 0)
997 line += 9;
998 OverSpace(&line);
999 free(BaseName);
1000 BaseName = AllocString(line);
1001 CheckExtra = FALSE;
1003 else
1005 ShowWarn(msgUnknownCDCommand);
1006 Result = FALSE;
1007 CheckExtra = FALSE;
1011 if(CheckExtra)
1013 OverSpace(&line);
1014 if(*line)
1016 ShowWarn(msgExtraCharacters);
1017 Result = FALSE;
1021 else
1023 char *idstr;
1025 if(*line == ' ' || *line == '\t')
1027 ShowWarn(msgUnexpectedBlanks);
1028 Result = FALSE;
1029 OverSpace(&line);
1032 idstr = line;
1033 while ((*line >= 'a' && *line <= 'z') ||
1034 (*line >= 'A' && *line <= 'Z') ||
1035 (*line >= '0' && *line <= '9') ||
1036 *line == '_')
1038 ++line;
1041 if(idstr == line)
1043 ShowWarn(msgNoIdentifier);
1044 Result = FALSE;
1046 else
1048 int found;
1050 if(!(cs = malloc(sizeof(*cs))))
1052 MemError();
1057 struct CatString *scs;
1059 found = TRUE;
1060 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1062 if(scs->ID == NextID)
1064 found = FALSE;
1065 ++NextID;
1066 break;
1070 while(!found);
1072 cs->Next = NULL;
1073 cs->ID = NextID;
1074 cs->MinLen = 0;
1075 cs->MaxLen = -1;
1076 cs->CD_Str = "";
1077 cs->CT_Str = NULL;
1078 cs->NotInCT= TRUE;
1080 if(!(cs->ID_Str = malloc((line-idstr)+1)))
1082 MemError();
1084 strncpy(cs->ID_Str, idstr, line-idstr);
1085 cs->ID_Str[line-idstr] = '\0';
1087 OverSpace(&line);
1089 if(*line != '(')
1091 ShowWarn(msgNoLeadingBracket);
1092 Result = FALSE;
1094 else
1096 char *oldstr;
1097 struct CatString *scs;
1098 char bytes[10];
1099 int bytesread, reallen;
1101 ++line;
1102 OverSpace(&line);
1103 if(*line != '/')
1105 if(*line == '+')
1107 NextID = cs->ID = NextID + strtol(line, &line, 0);
1109 else
1111 cs->ID = NextID = strtol(line, &line, 0);
1114 OverSpace(&line);
1117 for(scs = FirstCatString; scs != NULL; scs = scs->Next)
1118 { if (scs->ID == cs->ID)
1119 { ShowWarn(msgDoubleID);
1120 Result = FALSE;
1122 if (strcmp(cs->ID_Str, scs->ID_Str) == 0)
1123 { ShowWarn(msgDoubleIdentifier);
1124 Result = FALSE;
1128 if (*line != '/')
1129 { ShowWarn(msgNoMinLen);
1130 Result = FALSE;
1132 else
1133 { ++line;
1134 OverSpace(&line);
1135 if (*line != '/')
1136 { cs->MinLen = strtol(line, &line, 0);
1137 OverSpace(&line);
1139 if (*line != '/')
1140 { ShowWarn(msgNoMaxLen);
1141 Result = FALSE;
1143 else
1144 { ++line;
1145 OverSpace(&line);
1146 if (*line != ')')
1147 { cs->MaxLen = strtol(line, &line, 0);
1148 OverSpace(&line);
1150 if (*line != ')')
1151 { ShowWarn(msgNoTrailingBracket);
1152 Result = FALSE;
1154 else
1155 { ++line;
1156 OverSpace(&line);
1157 if (*line)
1158 { ShowWarn(msgExtraCharacters);
1163 if (!(newline = ReadLine(fp, FALSE)))
1164 { ShowWarn(msgNoString);
1165 Result = FALSE;
1166 cs->CD_Str = "";
1168 else
1169 { cs->CD_Str = AllocString(newline);
1170 free(newline);
1174 Get stringlen
1176 oldstr = cs->CD_Str;
1177 reallen = 0;
1178 while (*oldstr)
1179 { bytesread = ReadChar(&oldstr, bytes);
1180 if (bytesread == 2)
1181 { bytesread--;
1183 reallen += bytesread;
1186 if (cs->MinLen > 0 && reallen < cs->MinLen)
1187 { ShowWarn(msgShortString);
1189 if (cs->MaxLen > 0 && reallen > cs->MaxLen)
1190 { ShowWarn(msgLongString);
1193 cs->Nr = NumStrings;
1195 *csptr = cs;
1196 csptr = &cs->Next;
1197 ++NumStrings;
1202 fclose(fp);
1203 return(Result);
1206 /// FUNC: ScanCTFile
1209 This scans a catalog translation file.
1211 Inputs: ctfile - name of the translation file to scan.
1213 Result: TRUE, if successful, FALSE otherwise.
1215 int ScanCTFile(char *ctfile)
1217 FILE *fp;
1218 char *newline, *line, *idstr, *newidstr, *newstr;
1219 struct CatString *cs=NULL;
1220 int Result = TRUE;
1222 ScanFile = ctfile;
1223 ScanLine = 0;
1225 if (!(fp = fopen(ctfile, "r")))
1227 ShowError(msgNoCatalogTranslation, ctfile);
1230 if(!NoBufferedIO)
1231 setvbuf(fp, NULL, _IOFBF, buffer_size);
1234 while (!feof(fp) && (line = newline = ReadLine(fp, TRUE)))
1236 switch(*line)
1238 case ';':
1239 if( CopyNEWs == TRUE )
1241 if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
1243 cs->NotInCT = TRUE;
1246 break;
1248 case '#':
1249 /// looking for command;
1250 if(*(++line) != '#')
1252 ShowWarn(msgNoCTCommand);
1254 ++line;
1255 OverSpace(&line);
1256 if (strnicmp(line, "version", 7) == 0)
1257 { if (CatVersionString || CatRcsId || CatName)
1258 { ShowWarn(msgDoubleCTVersion);
1260 line += 7;
1261 OverSpace(&line);
1262 CatVersionString = AllocString(line);
1264 else if (strnicmp(line, "codeset", 7) == 0)
1265 { line += 7;
1266 CodeSet = strtol(line, &line, 0);
1267 OverSpace(&line);
1268 if (*line)
1269 { ShowWarn(msgExtraCharacters);
1272 else if (strnicmp(line, "language", 8) == 0)
1273 { char *ptr;
1275 if (CatLanguage)
1276 { ShowWarn(msgDoubleCTLanguage);
1278 line += 8;
1279 OverSpace(&line);
1280 CatLanguage = AddCatalogChunk("LANG", line);
1282 if(LANGToLower)
1283 for (ptr = CatLanguage; *ptr; ptr++)
1284 *ptr = tolower((int) *ptr);
1286 else if (strnicmp(line, "chunk", 5) == 0)
1287 { char *ID;
1289 line += 5;
1290 OverSpace(&line);
1291 ID = line;
1292 line += sizeof(ULONG);
1293 OverSpace(&line);
1295 AddCatalogChunk(ID, AllocString(line));
1297 else if (strnicmp(line, "rcsid", 5) == 0)
1298 { if (CatVersionString || CatRcsId)
1299 { ShowWarn(msgDoubleCTVersion);
1301 line += 5;
1302 OverSpace(&line);
1303 CatRcsId = AllocString(line);
1305 else if (strnicmp(line, "name", 5) == 0)
1306 { if (CatVersionString || CatName)
1307 { ShowWarn(msgDoubleCTVersion);
1309 line += 4;
1310 OverSpace(&line);
1311 CatName = AllocString(line);
1313 else if (strnicmp(line+1, "lengthbytes", 11) == 0)
1314 { line += 12;
1315 if ((LengthBytes = strtol(line, &line, 0))
1316 > sizeof(long))
1317 { ShowWarn(msgNoLengthBytes, sizeof(long));
1318 LengthBytes = sizeof(long);
1321 else
1323 ShowWarn(msgUnknownCTCommand);
1326 break;
1328 default:
1329 if(*line == ' ' || *line == '\t')
1331 ShowWarn( msgUnexpectedBlanks );
1332 OverSpace( &line );
1334 idstr = line;
1336 while ((*line >= 'a' && *line <= 'z') ||
1337 (*line >= 'A' && *line <= 'Z') ||
1338 (*line >= '0' && *line <= '9') ||
1339 *line == '_')
1340 { ++line;
1342 if (idstr == line)
1344 ShowWarn(msgNoIdentifier);
1345 break;
1348 if(!(newidstr = malloc(line-idstr+1)))
1350 MemError();
1353 strncpy(newidstr, idstr, line-idstr);
1354 newidstr[line-idstr] = '\0';
1355 OverSpace(&line);
1357 if(*line)
1359 ShowWarn(msgExtraCharacters);
1362 if((newstr = ReadLine(fp, FALSE)))
1364 for(cs = FirstCatString; cs != NULL; cs = cs->Next)
1366 if(strcmp(cs->ID_Str, newidstr) == 0)
1368 break;
1371 if(cs == NULL)
1373 ShowWarn(msgUnknownIdentifier, newidstr);
1375 else
1377 char *oldstr;
1378 char bytes[10];
1379 int bytesread, reallen;
1381 if(cs->CT_Str)
1383 ShowWarn(msgDoubleIdentifier);
1384 Result = FALSE;
1385 free(cs->CT_Str);
1387 cs->CT_Str = AllocString(newstr);
1388 cs->NotInCT = FALSE;
1391 Get stringlen
1393 oldstr = cs->CT_Str;
1394 reallen = 0;
1395 while(*oldstr)
1397 bytesread = ReadChar(&oldstr, bytes);
1398 if(bytesread == 2)
1400 bytesread--;
1402 reallen += bytesread;
1405 if(cs->MinLen > 0 && reallen < cs->MinLen)
1407 ShowWarn(msgShortString);
1409 if(cs->MaxLen > 0 && reallen > cs->MaxLen)
1411 ShowWarn(msgLongString);
1415 // checking for trailing ellipsis...
1417 if( reallen >= 3 )
1419 long cd_len = strlen( cs->CD_Str );
1421 if( cd_len >= 3 )
1423 if( strcmp( &cs->CD_Str[ cd_len - 2 ], "..." ) == 0 )
1424 if( strcmp( &cs->CT_Str[ reallen - 2 ], "..." ) != 0 )
1426 // printf("ORG: '%s'\nNEW: '%s'\n", cs->CD_Str, cs->CT_Str);
1427 ShowWarn(msgTrailingEllipsis);
1433 // checking for trailing spaces
1435 if( reallen >= 1 )
1437 long cd_len = strlen( cs->CD_Str );
1439 if( cd_len >= 1 )
1441 if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
1442 if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
1443 ShowWarn(msgTrailingSpaces);
1449 free(newstr);
1451 else
1453 ShowWarn(msgNoString);
1454 if(cs)
1455 cs->CT_Str = "";
1457 free(newidstr);
1459 free(newline);
1462 fclose(fp);
1464 if (WarnCTGaps)
1465 { for (cs = FirstCatString; cs != NULL; cs = cs->Next)
1466 { if (cs->CT_Str == NULL)
1467 { ShowWarn(msgCTGap, cs->ID_Str);
1472 if(Result)
1473 CT_Scanned = TRUE;
1475 return(Result);
1478 /// FUNC: CatPuts
1482 CatPuts prints a string to a catalog. (The string is preceded by a
1483 long integer containing its length and probably padded up to word
1484 boundary or longword boundary, depending on the argument padbytes.)
1485 The arguments countnul should be TRUE if the NUL byte at the end of
1486 the string should be counted.
1488 int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
1490 unsigned int reallen, virtuallen, chunklen, swapped_long;
1491 int bytesread;
1492 char *oldstr;
1493 char bytes[10];
1495 /* Get Length of string.
1498 oldstr = str;
1499 reallen = 0;
1501 while(*oldstr)
1503 bytesread = ReadChar(&oldstr, bytes);
1504 if(bytesread == 2)
1506 bytesread--;
1508 reallen += bytesread;
1511 virtuallen = chunklen = reallen + LengthBytes;
1512 if(countnul || chunklen % padbytes == 0)
1514 virtuallen++;
1517 swapped_long = SwapLong( virtuallen );
1519 fwrite(&swapped_long, sizeof(virtuallen), 1, fp);
1520 if(LengthBytes)
1522 fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
1525 while(*str)
1527 bytesread = ReadChar(&str, bytes);
1528 if(bytesread)
1530 fwrite(bytes+bytesread-1, 1, 1, fp);
1536 putc('\0', fp);
1538 while(++chunklen % padbytes);
1540 return((int) chunklen+4);
1543 /// FUNC: PutCatalogChunk
1546 This puts a string chunk into the catalog
1548 int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
1550 fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
1551 return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
1554 /// FUNC: CalcRealLength
1556 This function measures the real (binary) length of source
1557 string. It correctly process 'slash chars' (\n, \000 etc),
1558 and gives the real length such source string have.
1560 Inputs: source - pointer to null terminated source string
1562 Result: real length
1565 int CalcRealLength(char *source)
1567 int count = 0;
1568 char *src = source;
1569 char bytes[10];
1571 while(*src)
1573 count += ReadChar(&src, bytes);
1576 // printf("%ld: '%s'\n", count, source);
1578 return(count);
1583 /// FUNC: CreateCatalog
1586 This creates a catalog.
1588 void CreateCat(char *CatFile)
1590 FILE *fp;
1591 int CatLen, HeadLen;
1592 struct CatString *cs;
1593 struct CatalogChunk *cc;
1594 int i;
1596 if(!CatVersionString && !CatRcsId)
1598 ShowError(msgNoCTVersion);
1601 if(!CatLanguage)
1603 ShowError(msgNoCTLanguage);
1606 if(strlen(CatLanguage) == 0)
1608 ShowError(msgNoCTLanguage);
1611 if(!(fp = fopen(CatFile, "w")))
1613 ShowError(msgNoCatalog, CatFile);
1616 if(!NoBufferedIO)
1617 setvbuf(fp, NULL, _IOFBF, buffer_size);
1620 fputs("FORM0000CTLG", fp);
1621 CatLen = 4;
1623 if(CatVersionString)
1625 struct CatalogChunk cc;
1626 char *verStr = NULL;
1628 cc.ID = MAKE_ID('F','V','E','R');
1630 if( strstr(CatVersionString, "$TODAY") )
1633 if(verStr = malloc(strlen(CatVersionString)+128))
1635 char *found = strstr(CatVersionString, "$TODAY");
1636 char dateStr[10];
1638 long tim;
1639 struct tm *t;
1641 time(&tim);
1642 t = gmtime(&tim);
1644 *found = 0;
1645 strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
1647 sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
1648 cc.ChunkStr = verStr;
1650 else
1651 MemError();
1654 else
1656 cc.ChunkStr = CatVersionString;
1659 cc.ID = SwapLong( cc.ID );
1660 CatLen += PutCatalogChunk(fp, &cc);
1662 if( verStr )
1663 free(verStr);
1665 else
1667 struct CatalogChunk cc;
1668 char* verStr;
1669 int year = 0, month = 0, day = 0;
1670 int version = 0, revision = 0;
1671 char* name = NULL;
1672 char* ptr;
1674 if(!CatRcsId)
1676 ShowError(msgNoCTVersion);
1678 else
1680 if(!(ptr = strstr(CatRcsId, "$Date:"))
1681 || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
1682 || !(ptr = strstr(CatRcsId, "$Revision:"))
1683 || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
1685 ShowError(msgWrongRcsId);
1687 if ((ptr = strstr(CatRcsId, "$Id:")))
1688 { int len = 0;
1689 char* found;
1691 ptr += 4;
1692 OverSpace(&ptr);
1693 found = ptr;
1695 while(*ptr && *ptr != '$' && *ptr != ' ' && *ptr != '\t')
1697 ++len;
1698 ++ptr;
1700 if(!(name = malloc(len+1)))
1702 MemError();
1704 strncpy(name, found, len);
1705 name[len] = '\0';
1708 if (CatName)
1709 { name = CatName;
1711 else if (!name)
1713 ShowError(msgNoCTVersion);
1714 name = "";
1716 if (!(verStr = malloc(strlen(name) + 256)))
1718 MemError();
1721 sprintf( verStr, "$V");
1722 sprintf( verStr, "ER: %s %ld.%ld (%ld.%ld.%ld)"
1723 , name, (long)version, (long)revision, (long)day, (long)month, (long)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", (long)(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", (long)((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");
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, "%s\n", (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