amath/build/flexcat/createcatsrc.c

789 lines
17 KiB
C

/*
* $Id$
*
* Copyright (C) 1993-1999 by Jochen Wiedmann and Marcin Orlowski
* Copyright (C) 2002-2015 FlexCat Open Source Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "flexcat.h"
#include "readprefs.h"
#include "swapfuncs.h"
#include "showfuncs.h"
#include "scancd.h"
#include "scanct.h"
#include "createcat.h"
#include "globals.h"
#include "utils.h"
enum StringTypes
{
TYPE_C, /* Produce C strings */
TYPE_ASSEMBLER, /* Produce Assembler strings */
TYPE_OBERON, /* Produce Oberon strings */
TYPE_E, /* Produce E strings. (Oops, thought
it allows only 32 bit integers? ;-) */
TYPE_NONE /* Simple strings */
};
enum OutputModes
{
OutputMode_None, /* Nothing written yet */
OutputMode_Bin, /* Last character written was binary */
OutputMode_Ascii /* Last character written was Ascii */
};
int OutputMode = OutputMode_None;
int OutputType = TYPE_C;
FILE *OutputFile;
int OutputLen;
int LongStrings = TRUE; /* Generate long or short strings */
/// CalcRealLength
/* This function measures the real (binary) length of source
string. It correctly process 'slash chars' (\n, \000 etc),
and gives the real length such source string have.
Inputs: source - pointer to NULL terminated source string
Result: real length */
int CalcRealLength(char *source)
{
int count = 0;
int len;
char *src = source;
char bytes[10];
while(*src != '\0')
{
len = ReadChar(&src, bytes);
// substract one byte for double backslashes
if(len == 2)
len--;
count += len;
}
/* printf("%ld: '%s'\n", count, source); */
return count;
}
///
/// InitCatStringOutput
/* InitCatStringOutput gets called before writing a catalog string as source.
Inputs: fp = file pointer to the output file
type = one of TYPE_C create C strings
TYPE_ASSEMBLER create Assembler strings
TYPE_OBERON create Oberon strings
TYPE_E create E strings
TYPE_NONE create simple strings */
void InitCatStringOutput(FILE *fp)
{
OutputLen = 0;
OutputFile = fp;
OutputMode = OutputMode_None;
switch(OutputType)
{
case TYPE_C:
case TYPE_OBERON:
putc('\"', fp);
OutputMode = OutputMode_Ascii;
break;
case TYPE_E:
putc('\'', fp);
case TYPE_ASSEMBLER:
case TYPE_NONE:
break;
}
}
///
/// SeparateCatStringOutput
/* SeparateCatStringOutput gets called to split a catalog into
separate lines. */
void SeparateCatStringOutput(void)
{
switch(OutputType)
{
case TYPE_C:
if(!LongStrings)
{
fputs("\"\\\n\t\"", OutputFile);
}
break;
case TYPE_E:
if(!LongStrings)
{
fputs("\' +\n\t\'", OutputFile);
}
break;
case TYPE_OBERON:
if(!LongStrings)
{
fputs("\"\n\t\"", OutputFile);
}
break;
case TYPE_ASSEMBLER:
if(!LongStrings)
{
if(OutputMode == OutputMode_Ascii)
{
putc('\'', OutputFile);
}
putc('\n', OutputFile);
OutputMode = OutputMode_None;
}
break;
case TYPE_NONE:
break;
}
}
///
/// WriteBinChar
/* WriteBinChar writes one binary character into the source file. */
void WriteBinChar(int c)
{
switch(OutputType)
{
case TYPE_C:
case TYPE_E:
case TYPE_OBERON:
switch(c)
{
case '\b':
fputs("\\b", OutputFile);
break;
case '\n':
fputs("\\n", OutputFile);
break;
case '\r':
fputs("\\r", OutputFile);
break;
case '\t':
fputs("\\t", OutputFile);
break;
case '\f':
fputs("\\f", OutputFile);
break;
case '\0':
fputs("\\000", OutputFile);
break;
default:
if(OutputType == TYPE_E && c == '\033')
{
fputs("\\e", OutputFile);
}
else
{
fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0', ((c >> 3) & 7) + '0', (c & 7) + '0');
}
break;
}
++OutputLen;
OutputMode = OutputMode_Bin;
break;
case TYPE_ASSEMBLER:
switch(OutputMode)
{
case OutputMode_None:
fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
break;
case OutputMode_Ascii:
putc('\'', OutputFile);
case OutputMode_Bin:
fprintf(OutputFile, ",$%02x", c & 0xff);
break;
}
++OutputLen;
OutputMode = OutputMode_Bin;
break;
case TYPE_NONE:
ShowError(MSG_ERR_NOBINCHARS);
break;
}
}
///
/// WriteAsciiChar
/* WriteAsciiChar writes one ascii character into the source file. */
void WriteAsciiChar(int c)
{
switch(OutputType)
{
case TYPE_C:
case TYPE_OBERON:
switch(c)
{
case '\"':
fputs("\\\"", OutputFile);
break;
default:
putc(c, OutputFile);
break;
}
++OutputLen;
OutputMode = OutputMode_Ascii;
break;
case TYPE_E:
switch(c)
{
case '\'':
fputs("''", OutputFile);
break;
default:
putc(c, OutputFile);
break;
}
++OutputLen;
OutputMode = OutputMode_Ascii;
break;
case TYPE_ASSEMBLER:
if(c == '\'')
{
WriteBinChar(c);
}
else
{
switch(OutputMode)
{
case OutputMode_None:
fprintf(OutputFile, "\tdc.b\t\'%c", c);
break;
case OutputMode_Ascii:
putc(c, OutputFile);
break;
case OutputMode_Bin:
fprintf(OutputFile, ",\'%c", c);
break;
}
++OutputLen;
OutputMode = OutputMode_Ascii;
}
break;
case TYPE_NONE:
putc(c, OutputFile);
break;
}
}
///
/// TerminateCatStringOutput
/* TerminateCatStringOutput finishes the output of a catalog string. */
void TerminateCatStringOutput(void)
{
switch(OutputType)
{
case TYPE_C:
case TYPE_OBERON:
putc('\"', OutputFile);
break;
case TYPE_E:
putc('\'', OutputFile);
break;
case TYPE_ASSEMBLER:
switch(OutputMode)
{
case OutputMode_Ascii:
putc('\'', OutputFile);
// fall through...
case OutputMode_Bin:
break;
case OutputMode_None:
break;
}
break;
case TYPE_NONE:
break;
}
}
///
/// WriteString
/* This writes a source string. */
static void WriteString(FILE * fpout, char *str, int32 Len, int lenbytes, int allbytes)
{
char bytes[10];
int bytesread;
int needseparate = FALSE;
InitCatStringOutput(fpout);
if(Len >= 0)
{
int i;
for(i = lenbytes; i >= 1; i--)
{
WriteBinChar((int)((char *)&Len)[sizeof(Len) - i]);
}
}
while(*str != '\0')
{
bytesread = ReadChar(&str, bytes);
if(bytesread > 0)
{
if(needseparate == TRUE)
{
SeparateCatStringOutput();
needseparate = FALSE;
}
do
{
unsigned char c = bytes[bytesread - 1];
if((c >= 0x20 && c < 0x7f) || c >= 0xa0)
WriteAsciiChar((int)c);
else
WriteBinChar((int)c);
if(allbytes == 0)
break;
}
while(--bytesread > 0);
}
else
needseparate = TRUE;
}
TerminateCatStringOutput();
}
///
/// CreateSourceFile
/* Finally, the source creation. */
void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
{
FILE *fpin, *fpout;
char *line;
char *OrigTemplateFile = TemplateFile;
ScanFile = SourceFile;
ScanLine = 0;
/* Open the source file. This may be found in various places. */
if((fpin = fopen(TemplateFile, "r")) == NULL)
{
#ifdef AMIGA
if(*prefs_sddir != '\0')
{
TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
fpin = fopen(TemplateFile, "r");
}
#endif
}
if(fpin == NULL)
{
#ifdef AMIGA
char sddir[80];
if(GetVar(FLEXCAT_SDDIR, sddir, 80, 0) != 0)
#else
char *sddir;
if((sddir = getenv(FLEXCAT_SDDIR)) != NULL)
#endif
{
TemplateFile = AddFileName(sddir, OrigTemplateFile);
fpin = fopen(TemplateFile, "r");
}
}
if(fpin == NULL)
{
TemplateFile = AddFileName(strdup(DEFAULT_FLEXCAT_SDDIR), OrigTemplateFile);
fpin = fopen(TemplateFile, "r");
}
if(fpin == NULL)
{
ShowError(MSG_ERR_NOSOURCEDESCRIPTION, OrigTemplateFile);
return;
}
if((fpout = fopen(SourceFile, "w")) == NULL)
{
ShowError(MSG_ERR_NOSOURCE, SourceFile);
return;
}
if(!NoBufferedIO)
setvbuf(fpin, NULL, _IOFBF, buffer_size);
if(!NoBufferedIO)
setvbuf(fpout, NULL, _IOFBF, buffer_size);
while(!feof(fpin) && (line = ReadLine(fpin, FALSE)) != NULL)
{
struct CatString *cs;
int NeedRepeat;
char bytes[10];
int bytesread;
cs = FirstCatString;
do
{
char *currentline = line;
NeedRepeat = FALSE;
if(*currentline == '#' && *(++currentline) == '#')
{
++currentline;
OverSpace(&currentline);
if(Strnicmp(currentline, "rem", 3) == 0)
{
/* We just skip this line. */
continue;
}
if(Strnicmp(currentline, "stringtype", 10) == 0)
{
currentline += 10;
OverSpace(&currentline);
if(Strnicmp(currentline, "c", 1) == 0)
{
OutputType = TYPE_C;
++currentline;
}
else if(Strnicmp(currentline, "assembler", 9) == 0)
{
OutputType = TYPE_ASSEMBLER;
currentline += 9;
}
else if(Strnicmp(currentline, "oberon", 6) == 0)
{
OutputType = TYPE_OBERON;
currentline += 6;
}
else if(Strnicmp(currentline, "e", 1) == 0)
{
OutputType = TYPE_E;
++currentline;
}
else if(Strnicmp(currentline, "none", 4) == 0)
{
OutputType = TYPE_NONE;
currentline += 4;
}
else
{
ShowWarn(MSG_ERR_UNKNOWNSTRINGTYPE);
currentline += strlen(currentline);
}
OverSpace(&currentline);
if(*currentline != '\0')
{
ShowError(MSG_ERR_EXTRA_CHARACTERS);
}
continue;
}
else if(Strnicmp(currentline, "shortstrings", 12) == 0)
{
currentline += 12;
LongStrings = FALSE;
OverSpace(&currentline);
if(*currentline != '\0')
{
ShowError(MSG_ERR_EXTRA_CHARACTERS);
}
continue;
}
}
currentline = line;
while(*currentline != '\0')
{
bytesread = ReadChar(&currentline, bytes);
if(bytesread > 0)
{
if(*bytes == '%')
{
char c = *currentline++;
switch(c)
{
case 'b':
fputs(BaseName, fpout);
break;
case 'n':
fprintf(fpout, "%d", NumStrings);
break;
case 'v':
fprintf(fpout, "%d", CatVersion);
break;
case 'l':
WriteString(fpout, Language, -1, cs->LenBytes, cs->POformat);
break;
case 'f':
{
char *tempstr;
if((c = *currentline++) == 'v')
{
fputs(VERS, fpout);
}
else
{
tempstr = AllocFileName(CDFile, c - '0');
fputs(tempstr, fpout);
free(tempstr);
}
}
break;
case 'o':
{
char *tempstr;
tempstr = AllocFileName(SourceFile, *currentline++ - '0');
fputs(tempstr, fpout);
free(tempstr);
}
break;
case 'i':
NeedRepeat = TRUE;
if(cs != NULL)
fputs(cs->ID_Str, fpout);
break;
case 'a':
case 't':
case 'd':
case 'x':
case 'c':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
int len = 0;
while(c >= '0' && c <= '9')
{
len = (c - '0') + len * 10;
c = *currentline++;
}
if(c == 'a')
{
int _len = len ? len : 4;
char *start;
char _StrLen[20 + 1];
snprintf(_StrLen, sizeof(_StrLen), "%020lx", (uint32)cs->ID);
start = &_StrLen[20 - _len * 2];
while(_len > 0)
{
fprintf(fpout, "\\x%.2s", start);
start += 2;
_len--;
}
}
else if(c == 't')
{
int _len = len ? len : 4;
char *start;
char _StrLen[20 + 1];
snprintf(_StrLen, sizeof(_StrLen), "%020lx", (uint32)((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
start = &_StrLen[20 - _len * 2];
while(_len > 0)
{
fprintf(fpout, "\\x%.2s", start);
start += 2;
_len--;
}
}
else if(c == 'c' || c == 'd' || c == 'x')
{
char buffer[20];
if(c == 'c')
c = 'o';
if(len)
snprintf(buffer, sizeof(buffer), "%%0%d%c", len, c);
else
snprintf(buffer, sizeof(buffer), "%%%c", c);
if(cs != NULL)
fprintf(fpout, buffer, cs->ID);
}
NeedRepeat = TRUE;
}
break;
case 'e':
NeedRepeat = TRUE;
if(cs != NULL)
fprintf(fpout, "%d", cs->Nr);
break;
case 's':
NeedRepeat = TRUE;
if(cs != NULL)
{
char *idstr;
uint32 len = 0;
if(cs->LenBytes)
{
idstr = cs->CD_Str;
while(*idstr != '\0')
{
bytesread = ReadChar(&idstr, bytes);
if(bytesread > 0)
{
++len;
}
}
}
WriteString(fpout, cs->CD_Str, cs->LenBytes ? len : (uint32)-1, cs->LenBytes, cs->POformat);
}
break;
case '(':
NeedRepeat = TRUE;
while(*currentline != '\0' && *currentline != ')')
{
bytesread = ReadChar(&currentline, bytes);
if(bytesread > 0 && cs != NULL && cs->Next != NULL)
{
putc((int)bytes[bytesread - 1], fpout);
}
}
if(*currentline == '\0')
{
/* FIXME: reuse MSG_ERR_NOTRAILINGBRACKET here? <tactica> */
ShowError(MSG_ERR_NOTERMINATEBRACKET);
}
else
{
++currentline;
}
break;
/* !!!! FIXME !!!! */
case 'z':
{
int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
NeedRepeat = TRUE;
while(diff > 0)
{
fprintf(fpout, "\\x00");
diff--;
}
break;
}
default:
{
int ch = *currentline++;
putc(ch, fpout);
}
}
}
else
{
putc((int)bytes[bytesread - 1], fpout);
}
}
}
putc('\n', fpout);
}
while(NeedRepeat == TRUE && cs != NULL && (cs = cs->Next) != NULL);
free(line);
}
fclose(fpin);
fclose(fpout);
#ifdef AMIGA
SetProtection(SourceFile, FILE_MASK);
#endif
}
///