mirror of https://gitlab.com/rnger/amath
789 lines
17 KiB
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(¤tline);
|
|
if(Strnicmp(currentline, "rem", 3) == 0)
|
|
{
|
|
/* We just skip this line. */
|
|
continue;
|
|
}
|
|
|
|
if(Strnicmp(currentline, "stringtype", 10) == 0)
|
|
{
|
|
currentline += 10;
|
|
OverSpace(¤tline);
|
|
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(¤tline);
|
|
if(*currentline != '\0')
|
|
{
|
|
ShowError(MSG_ERR_EXTRA_CHARACTERS);
|
|
}
|
|
continue;
|
|
}
|
|
else if(Strnicmp(currentline, "shortstrings", 12) == 0)
|
|
{
|
|
currentline += 12;
|
|
LongStrings = FALSE;
|
|
OverSpace(¤tline);
|
|
if(*currentline != '\0')
|
|
{
|
|
ShowError(MSG_ERR_EXTRA_CHARACTERS);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
currentline = line;
|
|
while(*currentline != '\0')
|
|
{
|
|
bytesread = ReadChar(¤tline, 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(¤tline, 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
|
|
}
|
|
|
|
///
|