mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 22:08:11 +02:00
891 lines
22 KiB
ObjectPascal
891 lines
22 KiB
ObjectPascal
{
|
|
Copyright (c) 1999-2000 by Peter Vreman (msg2inc) and
|
|
Marco van de Voort (data2inc)
|
|
Placed under LGPL (See the file COPYING.FPC, included in this
|
|
distribution, for details about the copyright)
|
|
|
|
E-Mail Marco : Marcov@stack.nl
|
|
Homepage Marco: www.stack.nl/~marcov/xtdlib.htm
|
|
|
|
Data2Inc is a heavily modified version of msg2inc.pp which compiles the
|
|
inputfile to include files containing array of char( or byte) typed
|
|
constants.
|
|
|
|
(e.g. CONST xxx : ARRAY[0..xxx] OF CHAR =( aa,bb,cc,dd,ee); ,
|
|
or the same but ARRAY OF BYTE )
|
|
|
|
Two types of input file are allowed:
|
|
|
|
1 A special kind of textfile. Records start with '!'name and all following
|
|
non empty and non comment (starting with '#',':' or '%') lines until
|
|
the next line starting with '!' or EOF are the data. Data are either
|
|
plain text (with \xxx ordinal constants) lines or a kinbd of
|
|
Basic DATA command (these lines start with DATA).
|
|
See demo.txt included with this package for a commented example.
|
|
|
|
2 (special parameter -b)
|
|
An arbitrary binary file can get converted to constants. In this mode
|
|
only one constant per include file is possible.
|
|
|
|
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.
|
|
|
|
**********************************************************************}
|
|
program data2inc;
|
|
uses strings;
|
|
|
|
CONST
|
|
version='1.00';
|
|
|
|
maxbufsize = 1024*1024; { 1 mb buffer }
|
|
|
|
type
|
|
TOutputMode=(OutByte,OutChar,OutString);
|
|
|
|
|
|
{*****************************************************************************
|
|
Simple service routines. These are copied from EPasStr.
|
|
*****************************************************************************}
|
|
|
|
TYPE CHARSET=SET OF ANSICHAR;
|
|
|
|
FUNCTION NextCharPos(CONST S : AnsiString;C:AnsiCHAR;Count:LONGINT):LONGINT;
|
|
|
|
VAR I,J:LONGINT;
|
|
|
|
BEGIN
|
|
I:=Length(S);
|
|
IF I=0 THEN
|
|
J:=0
|
|
ELSE
|
|
BEGIN
|
|
J:=Count;
|
|
IF J>I THEN
|
|
BEGIN
|
|
NextCharPos:=0;
|
|
EXIT
|
|
END;
|
|
WHILE (S[J]<>C) AND (J<=I) DO INC(J);
|
|
IF (J>I) THEN
|
|
J:=0;
|
|
END;
|
|
NextCharPos:=J;
|
|
END;
|
|
|
|
FUNCTION NextCharPosSet(CONST S : AnsiString;CONST C:CHARSET;Count:LONGINT):LONGINT;
|
|
|
|
VAR I,J:LONGINT;
|
|
|
|
BEGIN
|
|
I:=Length(S);
|
|
IF I=0 THEN
|
|
J:=0
|
|
ELSE
|
|
BEGIN
|
|
J:=Count;
|
|
IF J>I THEN
|
|
BEGIN
|
|
NextCharPosSet:=0;
|
|
EXIT;
|
|
END;
|
|
WHILE (j<=i) AND (NOT (S[J] IN C)) DO INC(J);
|
|
IF (J>I) THEN
|
|
J:=0; // NOT found.
|
|
END;
|
|
NextCharPosSet:=J;
|
|
END;
|
|
|
|
|
|
PROCEDURE RTrim(VAR P : AnsiString;Ch:AnsiChar);
|
|
|
|
VAR I,J : LONGINT;
|
|
|
|
BEGIN
|
|
I:=Length(P); { Keeping length in local data eases optimalisations}
|
|
IF (I>0) THEN
|
|
BEGIN
|
|
J:=I;
|
|
WHILE (P[J]=Ch) AND (J>0) DO DEC(J);
|
|
IF J<>I THEN
|
|
Delete(P,J+1,I-J+1);
|
|
END;
|
|
END;
|
|
|
|
PROCEDURE UpperCase(VAR S : AnsiString);
|
|
|
|
VAR L,I : LONGINT;
|
|
|
|
BEGIN
|
|
L:=Length(S);
|
|
IF L>0 THEN
|
|
FOR I:=1 TO L DO
|
|
IF (S[I]>CHR(96)) AND (S[I]<CHR(123)) THEN
|
|
S[I]:=CHR(ORD(S[I])-32);
|
|
END;
|
|
|
|
PROCEDURE LTrim(VAR P : AnsiString;Ch:ansiChar);
|
|
|
|
VAR I,J : LONGINT;
|
|
|
|
BEGIN
|
|
I:=Length(P); { Keeping length in local data eases optimalisations}
|
|
IF (I>0) THEN
|
|
BEGIN
|
|
J:=1;
|
|
WHILE (P[J]=Ch) AND (J<=I) DO INC(J);
|
|
IF J>1 THEN
|
|
Delete(P,1,J-1);
|
|
END;
|
|
END;
|
|
|
|
|
|
{*****************************************************************************
|
|
Parsing helpers
|
|
*****************************************************************************}
|
|
|
|
FUNCTION XlatString(Var S : AnsiString):BOOLEAN;
|
|
{replaces \xxx in string S with #x, and \\ with \ (escaped)
|
|
which can reduce size of string.
|
|
|
|
Returns false when an error in the line exists}
|
|
|
|
|
|
Function GetNumber(Position:LONGINT):LONGINT;
|
|
|
|
VAR C,
|
|
Value,
|
|
I : LONGINT;
|
|
|
|
BEGIN
|
|
I:=0; Value:=0;
|
|
WHILE I<3 DO
|
|
BEGIN
|
|
C:=ORD(S[Position+I]);
|
|
IF (C>47) AND (C<56) THEN
|
|
C:=C-48
|
|
ELSE
|
|
BEGIN
|
|
GetNumber:=-1;
|
|
EXIT;
|
|
END;
|
|
IF I=0 THEN
|
|
C:=C SHL 6;
|
|
IF I=1 THEN
|
|
C:=C SHL 3;
|
|
Value:=Value + C;
|
|
INC(I);
|
|
END;
|
|
GetNumber:=Value;
|
|
END;
|
|
|
|
VAR S2:AnsiString;
|
|
A,B : LONGINT;
|
|
Value : LONGINT;
|
|
|
|
BEGIN
|
|
A:=1; B:=1;
|
|
WHILE A<=Length(S) DO
|
|
BEGIN
|
|
IF S[A]='\' THEN
|
|
IF S[A+1]='\' THEN
|
|
BEGIN
|
|
S2[B]:='\';
|
|
INC (A,2); INC(B);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
Value:=GetNumber(A+1);
|
|
IF Value=-1 THEN
|
|
BEGIN
|
|
XlatString:=FALSE;
|
|
EXIT;
|
|
END;
|
|
S2[B]:=CHR(Value);
|
|
INC(B); INC(A,4);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
S2[B]:=S[A];
|
|
INC (A);
|
|
INC (B);
|
|
END;
|
|
END;
|
|
SetLength(S2,B-1);
|
|
S:=S2;
|
|
XlatString:=TRUE;
|
|
END;
|
|
|
|
{Global equates}
|
|
|
|
VAR
|
|
Inname, { Name of input file }
|
|
OutName, { Name of output (.inc) file }
|
|
BinConstName : Ansistring; { (-b only) commandline name of constant }
|
|
OutputMode : TOutputMode; { Output mode (char,byte,string) }
|
|
I_Binary : BOOLEAN; { TRUE is binary input, FALSE textual }
|
|
MsgTxt : pAnsichar; { Temporary storage of data }
|
|
msgsize : longint; { Bytes used in MsgTxt }
|
|
C : AnsiCHAR;
|
|
|
|
|
|
{*****************************************************************************
|
|
WriteCharFile
|
|
*****************************************************************************}
|
|
|
|
{Dump the contents of MsgTxt (msgsize bytes) to file T (which has been opened),
|
|
using CONSTNAME as the name of the ARRAY OF CHAR constant}
|
|
procedure WriteCharFile(var t:text;constname:ansistring);
|
|
|
|
function createconst(b:byte):string;
|
|
{decides whether to use the #xxx code or 'c' style for each char}
|
|
begin
|
|
if (b in [32..127]) and (b<>39) then
|
|
createconst:=''''+chr(b)+''''
|
|
else
|
|
createconst:='#'+chr(b div 100+48)+chr((b mod 100) div 10+48)+chr(b mod 10+48)
|
|
end;
|
|
|
|
var
|
|
cidx,i : longint;
|
|
p : PAnsiCHAR;
|
|
begin
|
|
Writeln('Writing constant: ',constname,' to file '#39,outname,#39);
|
|
{Open textfile}
|
|
write(t,'const ',constname,' : array[0..'); Writeln(t,msgsize-1,'] of char=(');
|
|
p:=msgtxt;
|
|
cidx:=0;
|
|
for i:=0 to msgsize-1 do
|
|
begin
|
|
if cidx=15 then
|
|
begin
|
|
if cidx>0 then
|
|
writeln(t,',')
|
|
else
|
|
writeln(t,'');
|
|
write(t,' ');
|
|
cidx:=0;
|
|
end
|
|
else
|
|
IF cidx>0 THEN
|
|
write(t,',')
|
|
ELSE
|
|
Write(T,' ');
|
|
write(t,createconst(ord(p^)));
|
|
inc(cidx);
|
|
inc(p);
|
|
end;
|
|
writeln(t,');');
|
|
Writeln(T);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
WriteByteFile
|
|
*****************************************************************************}
|
|
|
|
{Dump the contents of MsgTxt (msgsize bytes) to file T (which has been opened),
|
|
using CONSTNAME as the name of the ARRAY OF BYTE constant}
|
|
procedure WriteByteFile(var t:text;constname:ansistring);
|
|
|
|
function createconst(b:byte):ansistring;
|
|
{Translates byte B to a $xx hex constant}
|
|
VAR l : Byte;
|
|
begin
|
|
createconst[1]:='$'; SetLength(createconst,3);
|
|
l:=ORD(B SHR 4) +48;
|
|
IF l>57 THEN
|
|
l:=L+7;
|
|
createconst[2]:=CHR(l);
|
|
l:=ORD(B and 15) +48;
|
|
IF l>57 THEN
|
|
INC(L,7);
|
|
createconst[3]:=CHR(l);
|
|
end;
|
|
|
|
var
|
|
cidx,i : longint;
|
|
p : pansichar;
|
|
begin
|
|
Writeln('Writing constant: ',constname,' to file '#39,outname,#39);
|
|
{Open textfile}
|
|
write(t,'const ',constname,' : array[0..'); Writeln(t,msgsize-1,'] of byte=(');
|
|
p:=msgtxt;
|
|
cidx:=0;
|
|
for i:=0 to msgsize-1 do
|
|
begin
|
|
if cidx=15 then
|
|
begin
|
|
if cidx>0 then
|
|
writeln(t,',')
|
|
else
|
|
writeln(t,'');
|
|
write(t,' ');
|
|
cidx:=0;
|
|
end
|
|
else
|
|
IF cidx>0 THEN
|
|
write(t,',')
|
|
ELSE
|
|
Write(T,' ');
|
|
write(t,createconst(ord(p^)));
|
|
inc(cidx);
|
|
inc(p);
|
|
end;
|
|
writeln(t,');');
|
|
Writeln(T);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
WriteStringFile
|
|
*****************************************************************************}
|
|
|
|
procedure WriteStringFile(var t:text;constname:ansistring);
|
|
const
|
|
maxslen=240; { to overcome aligning problems }
|
|
|
|
function l0(l:longint):ansistring;
|
|
var
|
|
s : string[16];
|
|
begin
|
|
str(l,s);
|
|
while (length(s)<5) do
|
|
s:='0'+s;
|
|
l0:=s;
|
|
end;
|
|
|
|
var
|
|
slen,
|
|
len,i : longint;
|
|
p : pansichar;
|
|
start,
|
|
quote : boolean;
|
|
begin
|
|
Writeln('Writing constant: ',constname,' to file '#39,outname,#39);
|
|
{Open textfile}
|
|
writeln(t,'{$ifdef Delphi}');
|
|
writeln(t,'const '+constname+' : array[0..',(msgsize-1) div maxslen,'] of string[',maxslen,']=(');
|
|
writeln(t,'{$else Delphi}');
|
|
writeln(t,'const '+constname+' : array[0..',(msgsize-1) div maxslen,',1..',maxslen,'] of char=(');
|
|
write(t,'{$endif Delphi}');
|
|
{Parse buffer in msgbuf and create indexs}
|
|
p:=msgtxt;
|
|
slen:=0;
|
|
len:=0;
|
|
quote:=false;
|
|
start:=true;
|
|
for i:=1 to msgsize do
|
|
begin
|
|
if slen>=maxslen then
|
|
begin
|
|
if quote then
|
|
begin
|
|
write(t,'''');
|
|
quote:=false;
|
|
end;
|
|
write(t,',');
|
|
slen:=0;
|
|
inc(len);
|
|
end;
|
|
if (len>70) or (start) then
|
|
begin
|
|
if quote then
|
|
begin
|
|
write(t,'''');
|
|
quote:=false;
|
|
end;
|
|
if slen>0 then
|
|
writeln(t,'+')
|
|
else
|
|
writeln(t);
|
|
len:=0;
|
|
start:=false;
|
|
end;
|
|
if (len=0) then
|
|
write(t,' ');
|
|
if (ord(p^)>=32) and (p^<>#39) then
|
|
begin
|
|
if not quote then
|
|
begin
|
|
write(t,'''');
|
|
quote:=true;
|
|
inc(len);
|
|
end;
|
|
write(t,p^);
|
|
inc(len);
|
|
end
|
|
else
|
|
begin
|
|
if quote then
|
|
begin
|
|
write(t,'''');
|
|
inc(len);
|
|
quote:=false;
|
|
end;
|
|
write(t,'#'+chr(ord(p^) div 100+48)+chr((ord(p^) mod 100) div 10+48)+chr(ord(p^) mod 10+48));
|
|
inc(len,3);
|
|
end;
|
|
{ start a new line when a #0 or #10 is found }
|
|
if p^ in [#0,#10] then
|
|
start:=true;
|
|
inc(slen);
|
|
inc(p);
|
|
end;
|
|
if quote then
|
|
write(t,'''');
|
|
writeln(t,'');
|
|
writeln(t,');');
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Parser
|
|
*****************************************************************************}
|
|
|
|
FUNCTION SpecialItem(S : AnsiString):LONGINT;
|
|
{ This procedure finds the next comma, (or the end of the string)
|
|
but comma's within single or double quotes should be ignored.
|
|
Single quotes within double quotes and vice versa are also ignored.}
|
|
|
|
VAR DataItem : LONGINT;
|
|
|
|
CONST xFcl : CHARSET = [',',#39,'"'];
|
|
|
|
BEGIN
|
|
|
|
DataItem:=0;
|
|
REPEAT
|
|
DataItem:=NextCharPosSet(S,xFcl,DataItem+1); {Find first " ' or ,}
|
|
IF (DataItem<>0) AND ((S[DataItem]='"') OR (S[DataItem]=#39)) THEN { (double)Quote found?}
|
|
DataItem:=NextCharPos(S,S[DataItem],DataItem+1); { then find other one}
|
|
UNTIL (DataItem=0) OR (S[DataItem]=',');
|
|
IF DataItem=0 THEN {Last data field of this line?}
|
|
DataItem:=Length(S);
|
|
SpecialItem:=DataItem;
|
|
END;
|
|
|
|
|
|
{ Handles reading and processing of a textual file}
|
|
procedure DoFile;
|
|
var
|
|
Infile,
|
|
Outfile : text; {in and output textfiles}
|
|
line, DataItem, {line number, position in DATA line}
|
|
I1,I2, {4 temporary counters}
|
|
I3,I4 : longint;
|
|
s,S1 : Ansistring; {S is string after reading, S1 is temporary string or
|
|
current DATA-item being processed }
|
|
VarName : AnsiString; { Variable name of constant to be written}
|
|
|
|
PROCEDURE ParseError;
|
|
{Extremely simple errorhandler}
|
|
BEGIN
|
|
Writeln('Error in line : ',Line, ' Somewhere near :',#39,S1,#39);
|
|
Close(InfIle); Close(Outfile);
|
|
HALT;
|
|
END;
|
|
|
|
PROCEDURE FixDec;
|
|
{ Reads decimal value starting at S1[1].
|
|
Value in I3, number of digits found in I1}
|
|
var I1,I2,i3 : longint;
|
|
|
|
BEGIN
|
|
I1:=1;
|
|
WHILE ((S1[I1]>#47) AND (S1[I1]<#58)) AND (I1<=Length(S1)) DO
|
|
INC(I1);
|
|
DEC(I1);
|
|
IF I1=0 THEN
|
|
ParseError;
|
|
I3:=0;
|
|
FOR I2:=1 TO I1 DO
|
|
I3:=(I3*10)+ ORD(S1[I2])-48;
|
|
{Calc no of bytes(1,2 or 4) required from no of digits found}
|
|
IF (I1<3) THEN
|
|
I2:=1
|
|
ELSE
|
|
IF (I1=3) AND (I3<256) THEN
|
|
I2:=1
|
|
ELSE
|
|
BEGIN
|
|
IF I1<5 THEN
|
|
I2:=2
|
|
ELSE
|
|
IF (I1=5) AND (i3<65536) THEN
|
|
I2:=2
|
|
ELSE
|
|
I2:=4;
|
|
END;
|
|
END;
|
|
|
|
PROCEDURE DoChar;
|
|
{ Reads a #xxx constant at S1[1], and puts it in msgtxt array.
|
|
Deletes #xxx constant from S1}
|
|
BEGIN
|
|
Delete(S1,1,1);
|
|
FixDec;
|
|
msgtxt[Msgsize]:=CHR(I3);
|
|
inc(msgsize);
|
|
Delete(S1,1,I1);
|
|
END;
|
|
|
|
PROCEDURE DoQuote;
|
|
{ Reads a quoted text-string ('xxx' or "xxx"). Quotechar is in S1[1]
|
|
(always ' or "), any char except the quotechar is allowed between two
|
|
quotechars.
|
|
Deletes quoted textstring incl quotes from S1}
|
|
VAR
|
|
C : AnsiChar;
|
|
BEGIN
|
|
C:=S1[1];
|
|
Delete(S1,1,1);
|
|
I1:=Pos(C,S1); {Find other quote}
|
|
IF I1=0 THEN
|
|
ParseError; {Quotes have to be matched}
|
|
Dec(I1);
|
|
IF I1<>0 THEN
|
|
BEGIN
|
|
Move(S1[1],Msgtxt[Msgsize],I1);
|
|
INC(msgsize,I1);
|
|
END;
|
|
Delete(S1,1,I1+1);
|
|
LTrim(S1,' ');
|
|
END;
|
|
|
|
PROCEDURE FixHex(base2:LONGINT);
|
|
{ Reads a base 2,8 or 16 constant from S1.
|
|
Parameter = 2Log of base (1,3 or 4 corresponding to base 2,8 and 16)
|
|
Constant is processed, the number of digits estimated (1,2 or 4 bytes) and
|
|
the value is appended to msgtxt accordingly}
|
|
BEGIN
|
|
I3:=0;
|
|
I2:=1;
|
|
WHILE (S1[I2] IN ['0'..'9','A'..'F','a'..'f']) AND (I2<=Length(S1)) DO
|
|
BEGIN
|
|
IF (S1[I2]>#47) AND (S1[I2]<#58) THEN
|
|
I3:=(I3 SHL base2)+ ORD(S1[I2])-48
|
|
ELSE
|
|
IF (S1[I2]>#64) AND (S1[I2]<#71) THEN
|
|
I3:=(I3 SHL base2)+ ORD(S1[I2])-55
|
|
ELSE
|
|
IF (S1[I2]>#96) AND (S1[I2]<#103) THEN
|
|
I3:=(I3 SHL base2)+ ORD(S1[I2])-87
|
|
ELSE
|
|
ParseError;
|
|
INC(I2);
|
|
END;
|
|
DEC(I2);
|
|
CASE Base2 OF
|
|
4 : BEGIN
|
|
I4:=(I2 SHR 1);
|
|
IF ODD(I2) THEN
|
|
INC(I4);
|
|
IF I4=3 THEN I4:=4
|
|
END;
|
|
3 : I4:=(I2*3 DIV 8)+1;
|
|
1 : BEGIN
|
|
IF I2<9 THEN
|
|
I4:=1
|
|
ELSE
|
|
IF I2<17 THEN
|
|
I4:=2
|
|
ELSE
|
|
I4:=4;
|
|
END;
|
|
ELSE
|
|
BEGIN
|
|
Writeln(' severe internal error ');
|
|
ParseError;
|
|
END; {else}
|
|
END; {Case}
|
|
move(I3,msgtxt[Msgsize],i4);
|
|
inc(msgsize,i4);
|
|
END;
|
|
|
|
PROCEDURE DoTextual;
|
|
{ processes aggregates of textual data like 'xxx'+#39"2143124"+'1234'#123}
|
|
|
|
BEGIN
|
|
REPEAT
|
|
CASE S1[1] OF
|
|
'#' : DoChar;
|
|
'"',#39 : DoQuote; {Should I support octal codes here?}
|
|
ELSE
|
|
ParseError;
|
|
END;
|
|
LTrim(S1,' ');
|
|
IF (S1[1]='+') THEN
|
|
Delete(S1,1,1);
|
|
LTrim(S1,' ');
|
|
UNTIL Length(S1)=0;
|
|
END;
|
|
|
|
PROCEDURE FlushMsgTxt; {Flush MsgTxt array}
|
|
BEGIN
|
|
IF msgsize>0 THEN {In memory? Then flush}
|
|
BEGIN
|
|
case outputmode of
|
|
OutByte :
|
|
WriteByteFile(outfile,Varname);
|
|
OutChar :
|
|
WriteCharFile(outfile,varname);
|
|
OutString :
|
|
WriteStringFile(outfile,varname);
|
|
end;
|
|
msgsize:=0;
|
|
END;
|
|
END;
|
|
|
|
{Actual DoFile}
|
|
begin
|
|
Getmem(msgtxt,maxbufsize);
|
|
Writeln('processing file : ',inname);
|
|
{Read the message file}
|
|
assign(infile,inname);
|
|
{$I-}
|
|
reset(infile);
|
|
{$I+}
|
|
if ioresult<>0 then
|
|
begin
|
|
WriteLn('file '+inname+' not found');
|
|
exit;
|
|
end;
|
|
{Create output file}
|
|
assign (outfile,outname);
|
|
rewrite(outfile);
|
|
msgsize:=0;
|
|
Line:=0;
|
|
while not eof(infile) do
|
|
begin
|
|
readln(infile,s); {Read a line}
|
|
INC(Line);
|
|
S1:=Copy(S,1,5);
|
|
Uppercase(S1);
|
|
IF S1='DATA ' THEN {DATA keyword?}
|
|
BEGIN
|
|
Delete(S,1,5);
|
|
REPEAT
|
|
DataItem:=SpecialItem(S); {Yes. Determine size of DATA field.}
|
|
IF DataItem<>0 THEN
|
|
BEGIN
|
|
I1:=DataItem;
|
|
IF DataItem=Length(S) THEN
|
|
INC(i1); {DataItem fix for last field}
|
|
S1:=Copy(S,1,I1-1); { copy field to S1}
|
|
Delete(S,1,I1); {Delete field from S}
|
|
LTrim(S1,' ');
|
|
RTrim(S1,' ');
|
|
LTrim(S,' ');
|
|
CASE S1[1] OF {Select field type}
|
|
#39,'"','#' : DoTextual; { handles textual aggregates
|
|
e.g. #124"142"#123'sdgf''ads'}
|
|
'$' : BEGIN {Handle $xxxx hex codes}
|
|
Delete(S1,1,1);
|
|
RTrim(S1,' ');
|
|
IF Length(S1)>0 THEN
|
|
FixHex(4)
|
|
ELSE
|
|
ParseError;
|
|
END;
|
|
'0'..'9' : BEGIN { handles 0x124,124124,124124H,234h,666o,353d,24b}
|
|
IF (Length(S1)>1) AND (S1[2]='x') THEN {C style 0xABCD hex}
|
|
BEGIN
|
|
Delete(S1,1,2);
|
|
FixHex(4);
|
|
END
|
|
ELSE {other types (HP notation suffix h,o,d and b (and upcase versions,
|
|
and no suffix) }
|
|
BEGIN
|
|
CASE S1[Length(S1)] OF
|
|
'H','h' : FixHex(4); {Hex}
|
|
'o','O' : FixHex(3); {octal}
|
|
'B','b' : BEGIN {Binary}
|
|
SetLength(S1,Length(S1)-1); {avoid 'b' char being treated as hex B }
|
|
FixHex(1);
|
|
END;
|
|
'0'..'9','d','D' : BEGIN {decimal versions}
|
|
FixDec; {Fixdec is safe for trailing chars}
|
|
{I1 =no of digits, I3=value, I2= no bytes needed}
|
|
move(I3,msgtxt[Msgsize],i2);
|
|
inc(msgsize,i2)
|
|
END
|
|
ELSE
|
|
ParseError; {otherwise wrong suffix}
|
|
END {Nested case}
|
|
END; { IF S1[2]='x'}
|
|
END; { '0'..'9'}
|
|
'%' : BEGIN {%101010 binary constants}
|
|
Delete(S1,1,1);
|
|
FixHex(1);
|
|
END;
|
|
'\' : BEGIN {\xxx octal constants}
|
|
Delete(S1,1,1);
|
|
FixHex(3);
|
|
END;
|
|
END; {Case}
|
|
END; {IF <>0}
|
|
UNTIL {(DataItem:=Length(S)) OR} (DataItem=0); {parse until String is empty}
|
|
END {S1='DATA'}
|
|
ELSE
|
|
BEGIN {Non DATA line}
|
|
IF (Length(S)<>0) AND NOT (S[1] IN ['#',';','%']) THEN
|
|
BEGIN
|
|
C:=S[1];
|
|
IF NOT XlatString(S) THEN {Expand \xxx octal constants}
|
|
BEGIN
|
|
Writeln('Some error with a \xxx constant or a stale (unescaped) backslash');
|
|
ParseError;
|
|
END;
|
|
IF C='!' THEN { New variable}
|
|
BEGIN
|
|
FlushMsgTxt;
|
|
I1:=1;
|
|
OutputMode:=OutChar;
|
|
IF S[2]='$' THEN {Flag for ARRAY OF BYTE?}
|
|
BEGIN
|
|
INC(I1);
|
|
OutputMode:=OutByte;
|
|
END;
|
|
Delete(S,1,I1);
|
|
VarName:=S;
|
|
END
|
|
ELSE
|
|
BEGIN {Normal line}
|
|
i1:=Length(S);
|
|
move(s[1],msgtxt[Msgsize],i1);
|
|
inc(msgsize,i1);
|
|
END;
|
|
END;
|
|
END;
|
|
end;
|
|
close(infile);
|
|
FlushMsgTxt; {Flush variable if msgtxt is occupied}
|
|
Close(Outfile);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Binary File
|
|
*****************************************************************************}
|
|
|
|
procedure DoBinary;
|
|
var
|
|
Infile : File;
|
|
Outfile : text;
|
|
i : longint;
|
|
begin
|
|
Writeln('processing file : ',inname);
|
|
{ Read the file }
|
|
assign(infile,inname);
|
|
{$I-}
|
|
reset(infile,1);
|
|
{$I+}
|
|
if ioresult<>0 then
|
|
begin
|
|
WriteLn('file '+inname+' not found');
|
|
exit;
|
|
end;
|
|
{ First parse the file and count bytes needed }
|
|
msgsize:=FileSize(InFile);
|
|
Getmem(msgtxt,msgsize);
|
|
BlockRead(InFile,msgTxt[0],msgsize,i);
|
|
close(infile);
|
|
IF I<>msgsize THEN
|
|
BEGIN
|
|
Writeln('Error while reading file',inName);
|
|
HALT(1);
|
|
END;
|
|
{ Output }
|
|
assign (outfile,outname);
|
|
rewrite(outfile);
|
|
case outputmode of
|
|
OutByte :
|
|
WriteByteFile(outfile,BinconstName);
|
|
OutChar :
|
|
WriteCharFile(outfile,BinconstName);
|
|
OutString :
|
|
WriteStringFile(outfile,BinconstName);
|
|
end;
|
|
Close(Outfile);
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
Main Program
|
|
*****************************************************************************}
|
|
|
|
procedure getpara;
|
|
var
|
|
ch : char;
|
|
para : string;
|
|
files,i : word;
|
|
|
|
procedure helpscreen;
|
|
begin
|
|
writeln('usage : data2inc [Options] <msgfile> [incfile] [constname]');
|
|
Writeln(' The constname parameter is only valid in combination');
|
|
writeln(' with -b, otherwise the constname must be specified in the inputfile');
|
|
Writeln;
|
|
writeln('<Options> can be :');
|
|
writeln(' -B File to read is binary.');
|
|
writeln(' -A array of byte output (default is array of char)');
|
|
writeln(' -S array of string output');
|
|
writeln(' -V Show version');
|
|
writeln(' -? or -H This HelpScreen');
|
|
writeln;
|
|
Writeln(' See data2inc.exm for a demonstration source');
|
|
halt(1);
|
|
end;
|
|
|
|
|
|
begin
|
|
I_binary:=FALSE;
|
|
OutputMode:=OutChar;
|
|
FIles:=0;
|
|
for i:=1to paramcount do
|
|
begin
|
|
para:=paramstr(i);
|
|
if (para[1]='-') then
|
|
begin
|
|
ch:=upcase(para[2]);
|
|
delete(para,1,2);
|
|
case ch of
|
|
'B' : I_Binary:=TRUE;
|
|
'A' : OutputMode:=OutByte;
|
|
'S' : OutputMode:=OutString;
|
|
'V' : begin
|
|
Writeln('Data2Inc ',version,' (C) 1999 Peter Vreman and Marco van de Voort');
|
|
Writeln;
|
|
Halt;
|
|
end;
|
|
'?','H' : Helpscreen;
|
|
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
inc(Files);
|
|
if Files>3 then
|
|
HelpScreen;
|
|
case Files of
|
|
1 : InName:=Para;
|
|
2 : OutName:=Para;
|
|
3 : BinConstName:=Para;
|
|
end;
|
|
end;
|
|
END;
|
|
if (FIles<3) AND I_Binary then
|
|
HelpScreen;
|
|
IF Files<2 THEN
|
|
HelpScreen;
|
|
end;
|
|
|
|
begin
|
|
GetPara;
|
|
IF I_Binary THEN
|
|
DoBinary
|
|
ELSE
|
|
DoFile;
|
|
end.
|