{ This file is part of the Free Pascal run time library. Copyright (c) 1999-2000 by the Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. **********************************************************************} {**************************************************************************** subroutines for string handling ****************************************************************************} procedure fpc_Shortstr_SetLength(var s:shortstring;len:SizeInt);[Public,Alias : 'FPC_SHORTSTR_SETLENGTH']; compilerproc; begin if Len>255 then Len:=255; s[0]:=chr(len); end; function fpc_shortstr_copy(const s : shortstring;index : SizeInt;count : SizeInt): shortstring;compilerproc; begin if count<0 then count:=0; if index>1 then dec(index) else index:=0; if index>length(s) then count:=0 else if count>length(s)-index then count:=length(s)-index; fpc_shortstr_Copy[0]:=chr(Count); Move(s[Index+1],fpc_shortstr_Copy[1],Count); end; procedure delete(var s : shortstring;index : SizeInt;count : SizeInt); begin if index<=0 then exit; if (Index<=Length(s)) and (Count>0) then begin if Count>length(s)-Index then Count:=length(s)-Index+1; s[0]:=Chr(length(s)-Count); if Index<=Length(s) then Move(s[Index+Count],s[Index],Length(s)-Index+1); end; end; procedure insert(const source : shortstring;var s : shortstring;index : SizeInt); var cut,srclen,indexlen : SizeInt; begin if index<1 then index:=1; if index>length(s) then index:=length(s)+1; indexlen:=Length(s)-Index+1; srclen:=length(Source); if SizeInt(length(source)+length(s))>=sizeof(s) then begin cut:=SizeInt(length(source)+length(s))-sizeof(s)+1; if cut>indexlen then begin dec(srclen,cut-indexlen); indexlen:=0; end else dec(indexlen,cut); end; move(s[Index],s[Index+srclen],indexlen); move(Source[1],s[Index],srclen); s[0]:=chr(index+srclen+indexlen-1); end; procedure insert(source : Char;var s : shortstring;index : SizeInt); var indexlen : SizeInt; begin if index<1 then index:=1; if index>length(s) then index:=length(s)+1; indexlen:=Length(s)-Index+1; if (length(s)+1=sizeof(s)) and (indexlen>0) then dec(indexlen); move(s[Index],s[Index+1],indexlen); s[Index]:=Source; s[0]:=chr(index+indexlen); end; function pos(const substr : shortstring;const s : shortstring):SizeInt; var i,MaxLen : SizeInt; pc : pchar; begin Pos:=0; if Length(SubStr)>0 then begin MaxLen:=Length(s)-Length(SubStr); i:=0; pc:=@s[1]; while (i<=MaxLen) do begin inc(i); if (SubStr[1]=pc^) and (CompareChar(Substr[1],pc^,Length(SubStr))=0) then begin Pos:=i; exit; end; inc(pc); end; end; end; {Faster when looking for a single char...} function pos(c:char;const s:shortstring):SizeInt; var i : SizeInt; pc : pchar; begin pc:=@s[1]; for i:=1 to length(s) do begin if pc^=c then begin pos:=i; exit; end; inc(pc); end; pos:=0; end; function fpc_char_copy(c:char;index : SizeInt;count : SizeInt): shortstring;compilerproc; begin if (index=1) and (Count>0) then fpc_char_Copy:=c else fpc_char_Copy:=''; end; function pos(const substr : shortstring;c:char): SizeInt; begin if (length(substr)=1) and (substr[1]=c) then Pos:=1 else Pos:=0; end; {$ifdef IBM_CHAR_SET} const UpCaseTbl : shortstring[7]=#154#142#153#144#128#143#165; LoCaseTbl : shortstring[7]=#129#132#148#130#135#134#164; {$endif} function upcase(c : char) : char; {$IFDEF IBM_CHAR_SET} var i : longint; {$ENDIF} begin if (c in ['a'..'z']) then upcase:=char(byte(c)-32) else {$IFDEF IBM_CHAR_SET} begin i:=Pos(c,LoCaseTbl); if i>0 then upcase:=UpCaseTbl[i] else upcase:=c; end; {$ELSE} upcase:=c; {$ENDIF} end; function upcase(const s : shortstring) : shortstring; var i : longint; begin upcase[0]:=s[0]; for i := 1 to length (s) do upcase[i] := upcase (s[i]); end; function lowercase(c : char) : char;overload; {$IFDEF IBM_CHAR_SET} var i : longint; {$ENDIF} begin if (c in ['A'..'Z']) then lowercase:=char(byte(c)+32) else {$IFDEF IBM_CHAR_SET} begin i:=Pos(c,UpCaseTbl); if i>0 then lowercase:=LoCaseTbl[i] else lowercase:=c; end; {$ELSE} lowercase:=c; {$ENDIF} end; function lowercase(const s : shortstring) : shortstring; overload; var i : longint; begin lowercase [0]:=s[0]; for i:=1 to length(s) do lowercase[i]:=lowercase (s[i]); end; const HexTbl : array[0..15] of char='0123456789ABCDEF'; function hexstr(val : longint;cnt : byte) : shortstring; var i : longint; begin hexstr[0]:=char(cnt); for i:=cnt downto 1 do begin hexstr[i]:=hextbl[val and $f]; val:=val shr 4; end; end; function octstr(val : longint;cnt : byte) : shortstring; var i : longint; begin octstr[0]:=char(cnt); for i:=cnt downto 1 do begin octstr[i]:=hextbl[val and 7]; val:=val shr 3; end; end; function binstr(val : longint;cnt : byte) : shortstring; var i : longint; begin binstr[0]:=char(cnt); for i:=cnt downto 1 do begin binstr[i]:=char(48+val and 1); val:=val shr 1; end; end; function hexstr(val : int64;cnt : byte) : shortstring; var i : longint; begin hexstr[0]:=char(cnt); for i:=cnt downto 1 do begin hexstr[i]:=hextbl[val and $f]; val:=val shr 4; end; end; function octstr(val : int64;cnt : byte) : shortstring; var i : longint; begin octstr[0]:=char(cnt); for i:=cnt downto 1 do begin octstr[i]:=hextbl[val and 7]; val:=val shr 3; end; end; function binstr(val : int64;cnt : byte) : shortstring; var i : longint; begin binstr[0]:=char(cnt); for i:=cnt downto 1 do begin binstr[i]:=char(48+val and 1); val:=val shr 1; end; end; function hexstr(val : pointer) : shortstring; var i : longint; v : ptrint; begin v:=ptrint(val); hexstr[0]:=chr(sizeof(pointer)*2); for i:=sizeof(pointer)*2 downto 1 do begin hexstr[i]:=hextbl[v and $f]; v:=v shr 4; end; end; function space (b : byte): shortstring; begin space[0] := chr(b); FillChar (Space[1],b,' '); end; {***************************************************************************** Str() Helpers *****************************************************************************} procedure fpc_shortstr_SInt(v : valSInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SINT']; compilerproc; begin int_str(v,s); if length(s)length(s) then exit; maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base); if (base = 10) then maxNewValue := MaxSIntValue + ord(negative) else maxNewValue := MaxUIntValue; while Code<=Length(s) do begin case s[Code] of '0'..'9' : u:=Ord(S[Code])-Ord('0'); 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10); 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10); else u:=16; end; Prev := Temp; Temp := Temp*ValUInt(base); If (u >= base) or (ValUInt(maxNewValue-u) < Temp) or (prev > maxPrevValue) Then Begin fpc_Val_SInt_ShortStr := 0; Exit End; Temp:=Temp+u; inc(code); end; code := 0; fpc_Val_SInt_ShortStr := ValSInt(Temp); If Negative Then fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr; If Not(Negative) and (base <> 10) Then {sign extend the result to allow proper range checking} Case DestSize of 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr); 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr); { Uncomment the folling once full 64bit support is in place 4: fpc_Val_SInt_ShortStr := SizeInt(fpc_Val_SInt_ShortStr);} End; end; { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because } { we have to pass the DestSize parameter on (JM) } Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR']; Function fpc_Val_UInt_Shortstr(Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc; var u, prev : ValUInt; base : byte; negative : boolean; begin fpc_Val_UInt_Shortstr:=0; Code:=InitVal(s,negative,base); If Negative or (Code>length(s)) Then Exit; while Code<=Length(s) do begin case s[Code] of '0'..'9' : u:=Ord(S[Code])-Ord('0'); 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10); 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10); else u:=16; end; prev := fpc_Val_UInt_Shortstr; If (u>=base) or (ValUInt(MaxUIntValue-u) div ValUInt(Base)length(s) then exit; { high(int64) produces 0 in version 1.0 (JM) } with qwordrec(maxint64) do begin {$ifdef ENDIAN_LITTLE} l1 := longint($ffffffff); l2 := $7fffffff; {$else ENDIAN_LITTLE} l1 := $7fffffff; l2 := longint($ffffffff); {$endif ENDIAN_LITTLE} end; with qwordrec(maxqword) do begin l1 := longint($ffffffff); l2 := longint($ffffffff); end; while Code<=Length(s) do begin case s[Code] of '0'..'9' : u:=Ord(S[Code])-Ord('0'); 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10); 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10); else u:=16; end; Prev:=Temp; Temp:=Temp*Int64(base); If (u >= base) or ((base = 10) and (maxint64-temp+ord(negative) < u)) or ((base <> 10) and (qword(maxqword-temp) < u)) or (prev > maxqword div qword(base)) Then Begin fpc_val_int64_shortstr := 0; Exit End; Temp:=Temp+u; inc(code); end; code:=0; fpc_val_int64_shortstr:=int64(Temp); If Negative Then fpc_val_int64_shortstr:=-fpc_val_int64_shortstr; end; Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc; type qwordrec = packed record l1,l2: longint; end; var u, prev, maxqword: QWord; base : byte; negative : boolean; begin fpc_val_qword_shortstr:=0; Code:=InitVal(s,negative,base); If Negative or (Code>length(s)) Then Exit; with qwordrec(maxqword) do begin l1 := longint($ffffffff); l2 := longint($ffffffff); end; while Code<=Length(s) do begin case s[Code] of '0'..'9' : u:=Ord(S[Code])-Ord('0'); 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10); 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10); else u:=16; end; prev := fpc_val_qword_shortstr; If (u>=base) or ((QWord(maxqword-u) div QWord(base))=code) and (s[code]='.') then begin hd:=1.0; inc(code); while (length(s)>=code) and (s[code] in ['0'..'9']) do begin { Read fractional part. } flags:=flags or 2; fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0')); hd:=hd*10.0; inc(code); end; fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd; end; { Again, read integer and fractional part} if flags=0 then begin fpc_Val_Real_ShortStr:=0.0; exit; end; { Exponent ? } if (length(s)>=code) and (upcase(s[code])='E') then begin inc(code); if Length(s) >= code then if s[code]='+' then inc(code) else if s[code]='-' then begin esign:=-1; inc(code); end; if (length(s)=code) and (s[code] in ['0'..'9']) do begin exponent:=exponent*10; exponent:=exponent+ord(s[code])-ord('0'); inc(code); end; end; { Calculate Exponent } { if esign>0 then for i:=1 to exponent do fpc_Val_Real_ShortStr:=Val_Real_ShortStr*10 else for i:=1 to exponent do fpc_Val_Real_ShortStr:=Val_Real_ShortStr/10; } hd:=1.0; for i:=1 to exponent do hd:=hd*10.0; if esign>0 then fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd else fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd; { Not all characters are read ? } if length(s)>=code then begin fpc_Val_Real_ShortStr:=0.0; exit; end; { evaluate sign } fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign; { success ! } code:=0; end; Procedure SetString (Out S : Shortstring; Buf : PChar; Len : SizeInt); begin If Len > High(S) then Len := High(S); SetLength(S,Len); If Buf<>Nil then begin Move (Buf[0],S[1],Len); end; end;