Fix: Re-introduce %B command
[AROS.git] / tools / flexcat / src / createcatsrc.c
blob7fb659ca5af9c25ac328fb3783fd22ec2b302ada
1 /*
2 * $Id$
4 * Copyright (C) 1993-1999 by Jochen Wiedmann and Marcin Orlowski
5 * Copyright (C) 2002-2017 FlexCat Open Source Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "flexcat.h"
24 #include "readprefs.h"
25 #include "swapfuncs.h"
26 #include "showfuncs.h"
27 #include "scancd.h"
28 #include "scanct.h"
29 #include "createcat.h"
30 #include "globals.h"
31 #include "utils.h"
32 #include <inttypes.h>
34 enum StringTypes
36 TYPE_C, /* Produce C strings */
37 TYPE_ASSEMBLER, /* Produce Assembler strings */
38 TYPE_OBERON, /* Produce Oberon strings */
39 TYPE_E, /* Produce E strings. (Oops, thought
40 it allows only 32 bit integers? ;-) */
41 TYPE_NONE /* Simple strings */
44 enum OutputModes
46 OutputMode_None, /* Nothing written yet */
47 OutputMode_Bin, /* Last character written was binary */
48 OutputMode_Ascii /* Last character written was Ascii */
51 int OutputMode = OutputMode_None;
52 int OutputType = TYPE_C;
54 FILE *OutputFile;
55 int OutputLen;
56 int LongStrings = TRUE; /* Generate long or short strings */
58 /// CalcRealLength
60 /* This function measures the real (binary) length of source
61 string. It correctly process 'slash chars' (\n, \000 etc),
62 and gives the real length such source string have.
64 Inputs: source - pointer to NULL terminated source string
65 Result: real length */
67 int CalcRealLength(char *source)
69 int count = 0;
70 int len;
71 char *src = source;
72 char bytes[10];
74 while(*src != '\0')
76 len = ReadChar(&src, bytes);
77 // substract one byte for double backslashes
78 if(len == 2)
79 len--;
81 count += len;
84 /* printf("%ld: '%s'\n", count, source); */
85 return count;
88 ///
89 /// InitCatStringOutput
91 /* InitCatStringOutput gets called before writing a catalog string as source.
92 Inputs: fp = file pointer to the output file
93 type = one of TYPE_C create C strings
94 TYPE_ASSEMBLER create Assembler strings
95 TYPE_OBERON create Oberon strings
96 TYPE_E create E strings
97 TYPE_NONE create simple strings */
99 void InitCatStringOutput(FILE *fp)
101 OutputLen = 0;
102 OutputFile = fp;
103 OutputMode = OutputMode_None;
105 switch(OutputType)
107 case TYPE_C:
108 case TYPE_OBERON:
109 putc('\"', fp);
110 OutputMode = OutputMode_Ascii;
111 break;
113 case TYPE_E:
114 putc('\'', fp);
116 case TYPE_ASSEMBLER:
117 case TYPE_NONE:
118 break;
123 /// SeparateCatStringOutput
125 /* SeparateCatStringOutput gets called to split a catalog into
126 separate lines. */
128 void SeparateCatStringOutput(void)
130 switch(OutputType)
132 case TYPE_C:
133 if(!LongStrings)
135 fputs("\"\\\n\t\"", OutputFile);
137 break;
139 case TYPE_E:
140 if(!LongStrings)
142 fputs("\' +\n\t\'", OutputFile);
144 break;
146 case TYPE_OBERON:
147 if(!LongStrings)
149 fputs("\"\n\t\"", OutputFile);
151 break;
153 case TYPE_ASSEMBLER:
154 if(!LongStrings)
156 if(OutputMode == OutputMode_Ascii)
158 putc('\'', OutputFile);
160 putc('\n', OutputFile);
161 OutputMode = OutputMode_None;
163 break;
165 case TYPE_NONE:
166 break;
171 /// WriteBinChar
173 /* WriteBinChar writes one binary character into the source file. */
175 void WriteBinChar(int c)
177 switch(OutputType)
179 case TYPE_C:
180 case TYPE_E:
181 case TYPE_OBERON:
182 switch(c)
184 case '\b':
185 fputs("\\b", OutputFile);
186 break;
188 case '\n':
189 fputs("\\n", OutputFile);
190 break;
192 case '\r':
193 fputs("\\r", OutputFile);
194 break;
196 case '\t':
197 fputs("\\t", OutputFile);
198 break;
200 case '\f':
201 fputs("\\f", OutputFile);
202 break;
204 case '\0':
205 fputs("\\000", OutputFile);
206 break;
208 default:
209 if(OutputType == TYPE_E && c == '\033')
211 fputs("\\e", OutputFile);
213 else
215 fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0', ((c >> 3) & 7) + '0', (c & 7) + '0');
217 break;
220 ++OutputLen;
221 OutputMode = OutputMode_Bin;
222 break;
224 case TYPE_ASSEMBLER:
225 switch(OutputMode)
227 case OutputMode_None:
228 fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
229 break;
231 case OutputMode_Ascii:
232 putc('\'', OutputFile);
234 case OutputMode_Bin:
235 fprintf(OutputFile, ",$%02x", c & 0xff);
236 break;
238 ++OutputLen;
239 OutputMode = OutputMode_Bin;
240 break;
242 case TYPE_NONE:
243 ShowError(MSG_ERR_NOBINCHARS);
244 break;
249 /// WriteAsciiChar
251 /* WriteAsciiChar writes one ascii character into the source file. */
253 void WriteAsciiChar(int c)
255 switch(OutputType)
257 case TYPE_C:
258 case TYPE_OBERON:
259 switch(c)
261 case '\"':
262 fputs("\\\"", OutputFile);
263 break;
265 default:
266 putc(c, OutputFile);
267 break;
269 ++OutputLen;
270 OutputMode = OutputMode_Ascii;
271 break;
273 case TYPE_E:
274 switch(c)
276 case '\'':
277 fputs("''", OutputFile);
278 break;
280 default:
281 putc(c, OutputFile);
282 break;
284 ++OutputLen;
285 OutputMode = OutputMode_Ascii;
286 break;
288 case TYPE_ASSEMBLER:
289 if(c == '\'')
291 WriteBinChar(c);
293 else
295 switch(OutputMode)
297 case OutputMode_None:
298 fprintf(OutputFile, "\tdc.b\t\'%c", c);
299 break;
301 case OutputMode_Ascii:
302 putc(c, OutputFile);
303 break;
305 case OutputMode_Bin:
306 fprintf(OutputFile, ",\'%c", c);
307 break;
309 ++OutputLen;
310 OutputMode = OutputMode_Ascii;
312 break;
314 case TYPE_NONE:
315 putc(c, OutputFile);
316 break;
321 /// TerminateCatStringOutput
323 /* TerminateCatStringOutput finishes the output of a catalog string. */
325 void TerminateCatStringOutput(void)
327 switch(OutputType)
329 case TYPE_C:
330 case TYPE_OBERON:
331 putc('\"', OutputFile);
332 break;
334 case TYPE_E:
335 putc('\'', OutputFile);
336 break;
338 case TYPE_ASSEMBLER:
339 switch(OutputMode)
341 case OutputMode_Ascii:
342 putc('\'', OutputFile);
343 // fall through...
345 case OutputMode_Bin:
346 break;
348 case OutputMode_None:
349 break;
351 break;
353 case TYPE_NONE:
354 break;
361 /// WriteString
363 /* This writes a source string. */
365 static void WriteString(FILE * fpout, char *str, int32 Len, int lenbytes, int allbytes)
367 char bytes[10];
368 int bytesread;
369 int needseparate = FALSE;
371 InitCatStringOutput(fpout);
372 if(Len >= 0)
374 int i;
376 for(i = lenbytes; i >= 1; i--)
378 WriteBinChar((int)((char *)&Len)[sizeof(Len) - i]);
383 while(*str != '\0')
385 bytesread = ReadChar(&str, bytes);
386 if(bytesread > 0)
388 if(needseparate == TRUE)
390 SeparateCatStringOutput();
391 needseparate = FALSE;
396 unsigned char c = bytes[bytesread - 1];
398 if((c >= 0x20 && c < 0x7f) || c >= 0xa0)
399 WriteAsciiChar((int)c);
400 else
401 WriteBinChar((int)c);
403 if(allbytes == 0)
404 break;
406 while(--bytesread > 0);
408 else
409 needseparate = TRUE;
412 TerminateCatStringOutput();
416 /// CreateSourceFile
418 /* Finally, the source creation. */
420 void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
422 FILE *fpin, *fpout;
423 char *line;
424 char *OrigTemplateFile = TemplateFile;
426 ScanFile = SourceFile;
427 ScanLine = 0;
429 /* Open the source file. This may be found in various places. */
431 if((fpin = fopen(TemplateFile, "r")) == NULL)
433 #ifdef AMIGA
434 if(*prefs_sddir != '\0')
436 TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
437 fpin = fopen(TemplateFile, "r");
439 #endif
442 if(fpin == NULL)
444 #ifdef AMIGA
445 char sddir[80];
447 if(GetVar(FLEXCAT_SDDIR, sddir, 80, 0) != 0)
448 #else
449 char *sddir;
451 if((sddir = getenv(FLEXCAT_SDDIR)) != NULL)
452 #endif
454 TemplateFile = AddFileName(sddir, OrigTemplateFile);
455 fpin = fopen(TemplateFile, "r");
459 if(fpin == NULL)
461 TemplateFile = AddFileName(strdup(DEFAULT_FLEXCAT_SDDIR), OrigTemplateFile);
462 fpin = fopen(TemplateFile, "r");
465 if(fpin == NULL)
467 ShowError(MSG_ERR_NOSOURCEDESCRIPTION, OrigTemplateFile);
468 return;
471 if((fpout = fopen(SourceFile, "w")) == NULL)
473 ShowError(MSG_ERR_NOSOURCE, SourceFile);
474 return;
477 if(!NoBufferedIO)
478 setvbuf(fpin, NULL, _IOFBF, buffer_size);
479 if(!NoBufferedIO)
480 setvbuf(fpout, NULL, _IOFBF, buffer_size);
482 // initialize "line" ahead of the loop
483 // the loop will bail out early for empty files
484 line = NULL;
485 while(!feof(fpin) && (line = ReadLine(fpin, FALSE)) != NULL)
487 struct CatString *cs;
488 int NeedRepeat;
489 char bytes[10];
490 int bytesread;
492 cs = FirstCatString;
496 char *currentline = line;
498 NeedRepeat = FALSE;
499 if(*currentline == '#' && *(++currentline) == '#')
501 ++currentline;
502 OverSpace(&currentline);
503 if(Strnicmp(currentline, "rem", 3) == 0)
505 /* We just skip this line. */
506 continue;
509 if(Strnicmp(currentline, "stringtype", 10) == 0)
511 currentline += 10;
512 OverSpace(&currentline);
513 if(Strnicmp(currentline, "c", 1) == 0)
515 OutputType = TYPE_C;
516 ++currentline;
518 else if(Strnicmp(currentline, "assembler", 9) == 0)
520 OutputType = TYPE_ASSEMBLER;
521 currentline += 9;
523 else if(Strnicmp(currentline, "oberon", 6) == 0)
525 OutputType = TYPE_OBERON;
526 currentline += 6;
528 else if(Strnicmp(currentline, "e", 1) == 0)
530 OutputType = TYPE_E;
531 ++currentline;
533 else if(Strnicmp(currentline, "none", 4) == 0)
535 OutputType = TYPE_NONE;
536 currentline += 4;
538 else
540 ShowWarn(MSG_ERR_UNKNOWNSTRINGTYPE);
541 currentline += strlen(currentline);
543 OverSpace(&currentline);
544 if(*currentline != '\0')
546 ShowError(MSG_ERR_EXTRA_CHARACTERS);
548 continue;
550 else if(Strnicmp(currentline, "shortstrings", 12) == 0)
552 currentline += 12;
553 LongStrings = FALSE;
554 OverSpace(&currentline);
555 if(*currentline != '\0')
557 ShowError(MSG_ERR_EXTRA_CHARACTERS);
559 continue;
562 currentline = line;
563 while(*currentline != '\0')
565 bytesread = ReadChar(&currentline, bytes);
566 if(bytesread > 0)
568 if(*bytes == '%')
570 char c = *currentline++;
572 switch(c)
574 case 'b':
575 fputs(BaseName, fpout);
576 break;
578 case 'B':
580 char *basenamestr = BaseName;
581 int i;
582 for (i = 0; i < strlen(BaseName); i++)
584 c = *basenamestr++;
585 if (c >= '0' && c <= '9')
586 putc(c, fpout);
587 else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
588 putc(c & 0x5F, fpout);
589 else
590 putc('_', fpout);
592 break;
595 case 'n':
596 fprintf(fpout, "%d", NumStrings);
597 break;
599 case 'v':
600 fprintf(fpout, "%d", CatVersion);
601 break;
603 case 'l':
604 WriteString(fpout, Language, -1, cs->LenBytes, cs->POformat);
605 break;
607 case 'f':
609 char *tempstr;
611 if((c = *currentline++) == 'v')
613 fputs(VERS, fpout);
615 else
617 tempstr = AllocFileName(CDFile, c - '0');
618 fputs(tempstr, fpout);
620 free(tempstr);
623 break;
625 case 'o':
627 char *tempstr;
629 tempstr = AllocFileName(SourceFile, *currentline++ - '0');
630 fputs(tempstr, fpout);
632 free(tempstr);
634 break;
636 case 'i':
637 NeedRepeat = TRUE;
638 if(cs != NULL)
639 fputs(cs->ID_Str, fpout);
640 break;
642 case 'a':
643 case 't':
644 case 'd':
645 case 'x':
646 case 'c':
647 case '0':
648 case '1':
649 case '2':
650 case '3':
651 case '4':
652 case '5':
653 case '6':
654 case '7':
655 case '8':
656 case '9':
658 int len = 0;
660 while(c >= '0' && c <= '9')
662 len = (c - '0') + len * 10;
663 c = *currentline++;
666 if(c == 'a')
668 int _len = len ? len : 4;
669 char *start;
670 char _StrLen[20 + 1];
672 snprintf(_StrLen, sizeof(_StrLen), "%020" PRIx32, (uint32)cs->ID);
673 start = &_StrLen[20 - _len * 2];
674 while(_len > 0)
676 fprintf(fpout, "\\x%.2s", start);
677 start += 2;
678 _len--;
681 else if(c == 't')
683 int _len = len ? len : 4;
684 char *start;
685 char _StrLen[20 + 1];
687 snprintf(_StrLen, sizeof(_StrLen), "%020" PRIx32, (uint32)((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
688 start = &_StrLen[20 - _len * 2];
689 while(_len > 0)
691 fprintf(fpout, "\\x%.2s", start);
692 start += 2;
693 _len--;
696 else if(c == 'c' || c == 'd' || c == 'x')
698 char buffer[20];
700 if(c == 'c')
701 c = 'o';
702 if(len)
703 snprintf(buffer, sizeof(buffer), "%%0%d%c", len, c);
704 else
705 snprintf(buffer, sizeof(buffer), "%%%c", c);
707 if(cs != NULL)
708 fprintf(fpout, buffer, cs->ID);
711 NeedRepeat = TRUE;
713 break;
715 case 'e':
716 NeedRepeat = TRUE;
717 if(cs != NULL)
718 fprintf(fpout, "%d", cs->Nr);
719 break;
721 case 's':
722 NeedRepeat = TRUE;
723 if(cs != NULL)
725 char *idstr;
726 uint32 len = 0;
728 if(cs->LenBytes)
730 idstr = cs->CD_Str;
731 while(*idstr != '\0')
733 bytesread = ReadChar(&idstr, bytes);
734 if(bytesread > 0)
736 ++len;
741 WriteString(fpout, cs->CD_Str, cs->LenBytes ? len : (uint32)-1, cs->LenBytes, cs->POformat);
743 break;
745 case '(':
746 NeedRepeat = TRUE;
747 while(*currentline != '\0' && *currentline != ')')
749 bytesread = ReadChar(&currentline, bytes);
750 if(bytesread > 0 && cs != NULL && cs->Next != NULL)
752 putc((int)bytes[bytesread - 1], fpout);
756 if(*currentline == '\0')
758 /* FIXME: reuse MSG_ERR_NOTRAILINGBRACKET here? <tactica> */
759 ShowError(MSG_ERR_NOTERMINATEBRACKET);
761 else
763 ++currentline;
765 break;
767 /* !!!! FIXME !!!! */
768 case 'z':
770 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
772 NeedRepeat = TRUE;
773 while(diff > 0)
775 fprintf(fpout, "\\x00");
776 diff--;
778 break;
781 default:
783 int ch = *currentline++;
785 putc(ch, fpout);
789 else
791 putc((int)bytes[bytesread - 1], fpout);
795 putc('\n', fpout);
797 while(NeedRepeat == TRUE && cs != NULL && (cs = cs->Next) != NULL);
799 free(line);
801 fclose(fpin);
802 fclose(fpout);
804 #ifdef AMIGA
805 SetProtection(SourceFile, FILE_MASK);
806 #endif