mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-16 17:40:33 +01:00
1349 lines
37 KiB
PHP
1349 lines
37 KiB
PHP
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2014 by Tomas Hajny,
|
|
member of the Free Pascal development team.
|
|
|
|
OS/2 UnicodeStrings support
|
|
|
|
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.
|
|
|
|
**********************************************************************}
|
|
|
|
(* The implementation is based on native Unicode support available under
|
|
OS/2 Warp 4 and above; if running under OS/2 Warp 3 and UCONV.DLL
|
|
library is not available, this implementation will resort to dummy
|
|
routines. This still allows providing 3rd party implementation based
|
|
e.g. on the ICONV library as an external unit.
|
|
*)
|
|
|
|
const
|
|
MaxSpecialCPTranslation = 2;
|
|
MaxNonEqualCPMapping = 35;
|
|
MaxCPMapping = 76;
|
|
CpxAll = 0;
|
|
CpxSpecial = 1;
|
|
CpxMappingOnly = 2;
|
|
Uls_Success = 0;
|
|
Uls_Other = $20401;
|
|
Uls_IllegalSequence = $20402;
|
|
Uls_MaxFilesPerProc = $20403;
|
|
Uls_MaxFiles = $20404;
|
|
Uls_NoOp = $20405;
|
|
Uls_TooManyKbd = $20406;
|
|
Uls_KbdNotFound = $20407;
|
|
Uls_BadHandle = $204008;
|
|
Uls_NoDead = $20409;
|
|
Uls_NoScan = $2040A;
|
|
Uls_InvalidScan = $2040B;
|
|
Uls_NotImplemented = $2040C;
|
|
Uls_NoMemory = $2040D;
|
|
Uls_Invalid = $2040E;
|
|
Uls_BadObject = $2040F;
|
|
Uls_NoToken = $20410;
|
|
Uls_NoMatch = $20411;
|
|
Uls_BufferFull = $20412;
|
|
Uls_Range = $20413;
|
|
Uls_Unsupported = $20414;
|
|
Uls_BadAttr = $20415;
|
|
Uls_Version = $20416;
|
|
UConvName: array [0..5] of char = 'UCONV'#0;
|
|
OrdUniCreateUconvObject = 1;
|
|
OrdUniUconvToUcs = 2;
|
|
OrdUniUconvFromUcs = 3;
|
|
OrdUniFreeUconvObject = 4;
|
|
OrdUniQueryUconvObject = 7;
|
|
OrdUniSetUconvObject = 8;
|
|
OrdUniQueryUconvCp = 9;
|
|
OrdUniMapCpToUcsCp = 10;
|
|
OrdUniStrFromUcs = 11;
|
|
OrdUniStrToUcs = 12;
|
|
Ord_UniMalloc = 13;
|
|
Ord_UniFree = 14;
|
|
LibUniName: array [0..6] of char = 'LIBUNI'#0;
|
|
WNull: WideChar = #0;
|
|
|
|
|
|
|
|
type
|
|
(* CP_UTF16 should be in exceptions too, because OS/2 supports only UCS2 *)
|
|
(* rather than UTF-16 - ignored at least for now. *)
|
|
(* ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE});
|
|
SpecialWinCodepages = (CP_UTF8, CP_ASCII);*)
|
|
TCpRec = record
|
|
WinCP: TSystemCodepage;
|
|
OS2CP: word;
|
|
UConvObj: TUConvObject;
|
|
end;
|
|
TCpXList = array [1..MaxCPMapping] of TCpRec;
|
|
TLocaleObject = pointer;
|
|
TDummyUConvObject = record
|
|
CP: cardinal;
|
|
CPNameLen: byte;
|
|
CPName: record end;
|
|
end;
|
|
PDummyUConvObject = ^TDummyUConvObject;
|
|
|
|
const
|
|
DefCpRec: TCpRec = (WinCP: 0; OS2CP: 0; UConvObj: nil);
|
|
IBMPrefix: packed array [1..4] of WideChar = 'IBM-';
|
|
|
|
threadvar
|
|
(* Temporary allocations may be performed in parallel in different threads *)
|
|
TempCpRec: TCpRec;
|
|
|
|
|
|
function OS2GetStandardCodePage (const stdcp: TStandardCodePageEnum): TSystemCodePage;
|
|
var
|
|
RC, C, RetSize: cardinal;
|
|
NoUConvObject: TUConvObject;
|
|
begin
|
|
RC := DosQueryCP (SizeOf (C), @C, RetSize);
|
|
if (RC <> 0) and (RC <> 473) then
|
|
begin
|
|
OSErrorWatch (RC);
|
|
C := 850;
|
|
end;
|
|
OS2GetStandardCodePage := OS2CpToRtlCp (C, cpxMappingOnly, NoUConvObject);
|
|
end;
|
|
|
|
|
|
function DummyUniCreateUConvObject (const CpName: PWideChar;
|
|
var UConv_Object: TUConvObject): longint; cdecl;
|
|
var
|
|
P: pointer;
|
|
PW, PCPN: PWideChar;
|
|
S: string [20];
|
|
C: cardinal;
|
|
L: PtrInt;
|
|
I: longint;
|
|
A: array [0..7] of char;
|
|
CPN2: UnicodeString;
|
|
RC, RetSize: cardinal;
|
|
begin
|
|
UConv_Object := nil;
|
|
if (CpName = nil) or (CpName^ = #0) then
|
|
begin
|
|
RC := DosQueryCP (SizeOf (C), @C, RetSize);
|
|
if (RC <> 0) and (RC <> 473) then
|
|
begin
|
|
C := 850;
|
|
OSErrorWatch (RC);
|
|
end;
|
|
Str (C, CPN2); (* Str should hopefully not use this function recurrently *)
|
|
L := Length (CPN2);
|
|
Insert (IBMPrefix, CPN2, 1);
|
|
PCPN := @CPN2 [1];
|
|
end
|
|
else
|
|
begin
|
|
PCPN := CpName;
|
|
for I := 0 to 7 do
|
|
if I mod 2 = 0 then
|
|
A [I] := UpCase (PChar (@PCPN [0]) [I])
|
|
else
|
|
A [I] := PChar (@PCPN [0]) [I];
|
|
if PQWord (@A)^ <> PQWord (@IBMPrefix)^ then
|
|
begin
|
|
DummyUniCreateUConvObject := Uls_Invalid;
|
|
Exit;
|
|
end;
|
|
L := 0;
|
|
PW := PCPN + 4;
|
|
while ((PW + L)^ <> #0) and (L <= SizeOf (S)) do
|
|
begin
|
|
S [Succ (L)] := char (Ord ((PW + L)^));
|
|
Inc (L);
|
|
end;
|
|
if L > SizeOf (S) then
|
|
begin
|
|
DummyUniCreateUConvObject := Uls_Other;
|
|
Exit;
|
|
end;
|
|
SetLength (S, L);
|
|
Val (S, C, I);
|
|
if I <> 0 then
|
|
begin
|
|
DummyUniCreateUConvObject := Uls_Invalid;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Inc (L);
|
|
GetMem (P, SizeOf (TDummyUConvObject) + (L + 4) * 2);
|
|
if P = nil then
|
|
DummyUniCreateUConvObject := Uls_NoMemory
|
|
else
|
|
begin
|
|
DummyUniCreateUConvObject := Uls_Success;
|
|
PDummyUConvObject (P)^.CP := C;
|
|
PDummyUConvObject (P)^.CpNameLen := Pred (L) + 4;
|
|
Move (PCPN [0], PDummyUConvObject (P)^.CpName, (L + 4) * 2);
|
|
UConv_Object := TUConvObject (P);
|
|
end;
|
|
end;
|
|
|
|
|
|
function DummyUniFreeUConvObject (UConv_Object: TUConvObject): longint; cdecl;
|
|
begin
|
|
if UConv_Object <> nil then
|
|
FreeMem (UConv_Object, SizeOf (TDummyUConvObject) +
|
|
Succ (PDummyUConvObject (UConv_Object)^.CpNameLen) * 2);
|
|
DummyUniFreeUConvObject := Uls_Success;
|
|
end;
|
|
|
|
|
|
function DummyUniMapCpToUcsCp (const Codepage: cardinal;
|
|
CodepageName: PWideChar; const N: cardinal): longint; cdecl;
|
|
var
|
|
S: UnicodeString;
|
|
RC, CP, RetSize: cardinal;
|
|
begin
|
|
if Codepage = 0 then
|
|
begin
|
|
RC := DosQueryCP (SizeOf (CP), @CP, RetSize);
|
|
if (RC <> 0) and (RC <> 473) then
|
|
begin
|
|
CP := 850;
|
|
OSErrorWatch (RC);
|
|
end;
|
|
Str (CP, S);
|
|
end
|
|
else
|
|
Str (Codepage, S);
|
|
if (N <= Length (S) + 4) or (CodepageName = nil) then
|
|
DummyUniMapCptoUcsCp := Uls_Invalid
|
|
else
|
|
begin
|
|
Move (IBMPrefix, CodepageName^, SizeOf (IBMPrefix));
|
|
Move (S [1], CodepageName [4], Length (S) * SizeOf (WideChar));
|
|
CodepageName [Length (S) + 4] := #0;
|
|
DummyUniMapCpToUcsCp := Uls_Success;
|
|
end;
|
|
end;
|
|
|
|
|
|
function DummyUniUConvFromUcs (UConv_Object: TUConvObject;
|
|
var UcsBuf: PWideChar; var UniCharsLeft: longint; var OutBuf: PChar;
|
|
var OutBytesLeft: longint; var NonIdentical: longint): longint; cdecl;
|
|
var
|
|
Dest, Dest2: RawByteString;
|
|
NoUConvObj: TUConvObject;
|
|
RtlCp: TSystemCodepage;
|
|
UcsLen: PtrInt;
|
|
begin
|
|
if UConv_Object = nil then
|
|
RtlCp := OS2GetStandardCodePage (scpAnsi)
|
|
else
|
|
RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
|
|
NoUConvObj);
|
|
DefaultUnicode2AnsiMove (UcsBuf, Dest, RtlCp, UniCharsLeft);
|
|
NonIdentical := 1; { Assume at least one substitution with dummy implementation }
|
|
if Length (Dest) > OutBytesLeft then
|
|
begin
|
|
UcsLen := 1;
|
|
repeat
|
|
DefaultUnicode2AnsiMove (UcsBuf, Dest2, RtlCp, UcsLen);
|
|
if Length (Dest2) <= OutBytesLeft then
|
|
begin
|
|
Dest := Dest2;
|
|
end;
|
|
Inc (UcsLen);
|
|
until Length (Dest2) > OutBytesLeft;
|
|
Dec (UcsLen);
|
|
Inc (UcsBuf, UcsLen);
|
|
Dec (UniCharsLeft, UcsLen);
|
|
DummyUniUConvFromUcs := Uls_BufferFull;
|
|
end
|
|
else
|
|
begin
|
|
Inc (UcsBuf, UniCharsLeft);
|
|
UniCharsLeft := 0;
|
|
DummyUniUConvFromUcs := Uls_Success;
|
|
end;
|
|
Move (Dest [1], OutBuf^, Length (Dest));
|
|
Inc (OutBuf, Length (Dest));
|
|
Dec (OutBytesLeft, Length (Dest));
|
|
end;
|
|
|
|
|
|
function DummyUniUConvToUcs (UConv_Object: TUConvObject; var InBuf: PChar;
|
|
var InBytesLeft: longint; var UcsBuf: PWideChar; var UniCharsLeft: longint;
|
|
var NonIdentical: longint): longint; cdecl;
|
|
var
|
|
Dest, Dest2: UnicodeString;
|
|
NoUConvObj: TUConvObject;
|
|
RtlCp: TSystemCodepage;
|
|
SrcLen: PtrInt;
|
|
begin
|
|
if UConv_Object = nil then
|
|
RtlCp := OS2GetStandardCodePage (scpAnsi)
|
|
else
|
|
RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
|
|
NoUConvObj);
|
|
DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest, InBytesLeft);
|
|
NonIdentical := 0; { Assume no need for substitutions in this direction }
|
|
if Length (Dest) > UniCharsLeft then
|
|
begin
|
|
SrcLen := 1;
|
|
repeat
|
|
DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest2, SrcLen);
|
|
if Length (Dest2) <= UniCharsLeft then
|
|
begin
|
|
Dest := Dest2;
|
|
end;
|
|
Inc (SrcLen);
|
|
until Length (Dest2) > UniCharsLeft;
|
|
Dec (SrcLen);
|
|
Inc (InBuf, SrcLen);
|
|
Dec (InBytesLeft, SrcLen);
|
|
DummyUniUConvToUcs := Uls_BufferFull; { According to IBM documentation Uls_Invalid and not Uls_BufferFull as returned by UniUConvFromUcs?! }
|
|
end
|
|
else
|
|
begin
|
|
Inc (InBuf, InBytesLeft); { Shall it be increased in case of success too??? }
|
|
InBytesLeft := 0;
|
|
DummyUniUConvToUcs := Uls_Success;
|
|
end;
|
|
Move (Dest [1], UcsBuf^, Length (Dest) * 2);
|
|
Inc (UcsBuf, Length (Dest)); { Shall it be increased in case of success too??? }
|
|
Dec (UniCharsLeft, Length (Dest));
|
|
end;
|
|
|
|
|
|
|
|
const
|
|
CpXList: TCpXList = (
|
|
(WinCP: CP_UTF8; OS2CP: 1208; UConvObj: nil),
|
|
(WinCP: CP_ASCII; OS2CP: 367; UConvObj: nil),
|
|
(WinCP: 28597; OS2CP: 813; UConvObj: nil),
|
|
(WinCP: 28591; OS2CP: 819; UConvObj: nil),
|
|
(WinCP: 28592; OS2CP: 912; UConvObj: nil),
|
|
(WinCP: 28593; OS2CP: 913; UConvObj: nil),
|
|
(WinCP: 28594; OS2CP: 914; UConvObj: nil),
|
|
(WinCP: 28595; OS2CP: 915; UConvObj: nil),
|
|
(WinCP: 28598; OS2CP: 916; UConvObj: nil),
|
|
(WinCP: 28599; OS2CP: 920; UConvObj: nil),
|
|
(WinCP: 28603; OS2CP: 921; UConvObj: nil),
|
|
(WinCP: 28605; OS2CP: 923; UConvObj: nil),
|
|
(WinCP: 10000; OS2CP: 1275; UConvObj: nil),
|
|
(WinCP: 10006; OS2CP: 1280; UConvObj: nil),
|
|
(WinCP: 10081; OS2CP: 1281; UConvObj: nil),
|
|
(WinCP: 10029; OS2CP: 1282; UConvObj: nil),
|
|
(WinCP: 10007; OS2CP: 1283; UConvObj: nil),
|
|
(WinCP: 20273; OS2CP: 273; UConvObj: nil),
|
|
(WinCP: 20277; OS2CP: 277; UConvObj: nil),
|
|
(WinCP: 20278; OS2CP: 278; UConvObj: nil),
|
|
(WinCP: 20280; OS2CP: 280; UConvObj: nil),
|
|
(WinCP: 20284; OS2CP: 284; UConvObj: nil),
|
|
(WinCP: 20285; OS2CP: 285; UConvObj: nil),
|
|
(WinCP: 20290; OS2CP: 290; UConvObj: nil),
|
|
(WinCP: 20297; OS2CP: 297; UConvObj: nil),
|
|
(WinCP: 20420; OS2CP: 420; UConvObj: nil),
|
|
(WinCP: 20424; OS2CP: 424; UConvObj: nil),
|
|
(WinCP: 20833; OS2CP: 833; UConvObj: nil),
|
|
(WinCP: 20838; OS2CP: 838; UConvObj: nil),
|
|
(WinCP: 20866; OS2CP: 878; UConvObj: nil),
|
|
(WinCP: 737; OS2CP: 851; UConvObj: nil),
|
|
(WinCP: 20924; OS2CP: 924; UConvObj: nil),
|
|
(WinCP: 20932; OS2CP: 932; UConvObj: nil),
|
|
(WinCP: 20936; OS2CP: 936; UConvObj: nil),
|
|
(WinCP: 21025; OS2CP: 1025; UConvObj: nil),
|
|
(WinCP: CP_UTF16; OS2CP: CP_UTF16; UConvObj: nil),
|
|
(WinCP: 37; OS2CP: 37; UConvObj: nil),
|
|
(WinCP: 437; OS2CP: 437; UConvObj: nil),
|
|
(WinCP: 500; OS2CP: 500; UConvObj: nil),
|
|
(WinCP: 850; OS2CP: 850; UConvObj: nil),
|
|
(WinCP: 852; OS2CP: 852; UConvObj: nil),
|
|
(WinCP: 855; OS2CP: 855; UConvObj: nil),
|
|
(WinCP: 857; OS2CP: 857; UConvObj: nil),
|
|
(WinCP: 860; OS2CP: 860; UConvObj: nil),
|
|
(WinCP: 861; OS2CP: 861; UConvObj: nil),
|
|
(WinCP: 862; OS2CP: 862; UConvObj: nil),
|
|
(WinCP: 863; OS2CP: 863; UConvObj: nil),
|
|
(WinCP: 864; OS2CP: 864; UConvObj: nil),
|
|
(WinCP: 865; OS2CP: 865; UConvObj: nil),
|
|
(WinCP: 866; OS2CP: 866; UConvObj: nil),
|
|
(WinCP: 869; OS2CP: 869; UConvObj: nil),
|
|
(WinCP: 870; OS2CP: 870; UConvObj: nil),
|
|
(WinCP: 874; OS2CP: 874; UConvObj: nil),
|
|
(WinCP: 875; OS2CP: 875; UConvObj: nil),
|
|
(WinCP: 949; OS2CP: 949; UConvObj: nil),
|
|
(WinCP: 950; OS2CP: 950; UConvObj: nil),
|
|
(WinCP: 1026; OS2CP: 1026; UConvObj: nil),
|
|
(WinCP: 1047; OS2CP: 1047; UConvObj: nil),
|
|
(WinCP: 1140; OS2CP: 1140; UConvObj: nil),
|
|
(WinCP: 1141; OS2CP: 1141; UConvObj: nil),
|
|
(WinCP: 1142; OS2CP: 1142; UConvObj: nil),
|
|
(WinCP: 1143; OS2CP: 1143; UConvObj: nil),
|
|
(WinCP: 1144; OS2CP: 1144; UConvObj: nil),
|
|
(WinCP: 1145; OS2CP: 1145; UConvObj: nil),
|
|
(WinCP: 1146; OS2CP: 1146; UConvObj: nil),
|
|
(WinCP: 1147; OS2CP: 1147; UConvObj: nil),
|
|
(WinCP: 1148; OS2CP: 1148; UConvObj: nil),
|
|
(WinCP: 1149; OS2CP: 1149; UConvObj: nil),
|
|
(WinCP: 1250; OS2CP: 1250; UConvObj: nil),
|
|
(WinCP: 1251; OS2CP: 1251; UConvObj: nil),
|
|
(WinCP: 1252; OS2CP: 1252; UConvObj: nil),
|
|
(WinCP: 1253; OS2CP: 1253; UConvObj: nil),
|
|
(WinCP: 1254; OS2CP: 1254; UConvObj: nil),
|
|
(WinCP: 1255; OS2CP: 1255; UConvObj: nil),
|
|
(WinCP: 1256; OS2CP: 1256; UConvObj: nil),
|
|
(WinCP: 1257; OS2CP: 1257; UConvObj: nil)
|
|
);
|
|
|
|
(* Possibly add index tables for both directions and binary search??? *)
|
|
|
|
|
|
function UConvObjectForCP (CP: cardinal; var UConvObj: TUConvObject): longint;
|
|
var
|
|
RC: longint;
|
|
A: array [0..12] of WideChar;
|
|
begin
|
|
UConvObj := nil;
|
|
RC := Sys_UniMapCpToUcsCp (CP, @A, 12);
|
|
if RC = 0 then
|
|
RC := Sys_UniCreateUconvObject (@A, UConvObj);
|
|
{$WARNING: TODO: Deallocate some previously allocated UConvObj and try again if failed}
|
|
UConvObjectForCP := RC;
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
end;
|
|
|
|
|
|
function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte;
|
|
var UConvObj: TUConvObject): TSystemCodepage;
|
|
var
|
|
I, I2: cardinal;
|
|
RCI: longint;
|
|
begin
|
|
OS2CPtoRtlCP := TSystemCodePage (CP);
|
|
UConvObj := nil;
|
|
if not UniAPI then (* No UniAPI => no need for UConvObj *)
|
|
ReqFlags := ReqFlags or CpxMappingOnly;
|
|
if CP = DefCpRec.OS2CP then
|
|
begin
|
|
if RTLUsesWinCP then
|
|
OS2CPtoRtlCP := DefCpRec.WinCP;
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
UConvObj := DefCpRec.UConvObj;
|
|
end
|
|
else
|
|
begin
|
|
I := 1;
|
|
if ReqFlags and CpxSpecial = CpxSpecial then
|
|
I2 := 2
|
|
else
|
|
if ReqFlags and CpxMappingOnly = CpxMappingOnly then
|
|
I2 := MaxNonEqualCPMapping
|
|
else
|
|
I2 := MaxCPMapping;
|
|
while I <= I2 do
|
|
begin
|
|
if CP = CpXList [I].OS2CP then
|
|
begin
|
|
if RTLUsesWinCP then
|
|
OS2CPtoRtlCP := CpXList [I].WinCP;
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
begin
|
|
if CpXList [I].UConvObj = nil then
|
|
begin
|
|
if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success
|
|
then
|
|
CpXList [I].UConvObj := UConvObj
|
|
else
|
|
UConvObj := nil;
|
|
end
|
|
else
|
|
UConvObj := CpXList [I].UConvObj;
|
|
end;
|
|
Exit;
|
|
end;
|
|
Inc (I);
|
|
end;
|
|
(* If codepage was not found in the translation table and UConvObj is
|
|
requested, allocate one in the temporary record. *)
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
begin
|
|
if TempCpRec.OS2CP = CP then
|
|
UConvObj := TempCpRec.UConvObj
|
|
else
|
|
begin
|
|
if TempCpRec.UConvObj <> nil then
|
|
begin
|
|
RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
|
|
if RCI <> 0 then
|
|
OSErrorWatch (cardinal (RCI));
|
|
end;
|
|
if UConvObjectForCP (CP, UConvObj) = Uls_Success then
|
|
begin
|
|
TempCpRec.UConvObj := UConvObj;
|
|
TempCpRec.OS2CP := CP;
|
|
end
|
|
else
|
|
UConvObj := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte;
|
|
var UConvObj: TUConvObject): cardinal;
|
|
var
|
|
I, I2: cardinal;
|
|
begin
|
|
RtlCPtoOS2CP := RtlCP;
|
|
UConvObj := nil;
|
|
if not UniAPI then (* No UniAPI => no need for UConvObj *)
|
|
ReqFlags := ReqFlags or CpxMappingOnly;
|
|
if not (RTLUsesWinCP) then
|
|
begin
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
OS2CPtoRtlCP (cardinal (RtlCp), ReqFlags, UConvObj);
|
|
end
|
|
else if RtlCP = DefCpRec.WinCP then
|
|
begin
|
|
RtlCPtoOS2CP := DefCpRec.WinCP;
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
UConvObj := DefCpRec.UConvObj;
|
|
end
|
|
else
|
|
begin
|
|
I := 1;
|
|
if ReqFlags and CpxSpecial = CpxSpecial then
|
|
I2 := 2
|
|
else
|
|
if ReqFlags and CpxMappingOnly = CpxMappingOnly then
|
|
I2 := MaxNonEqualCPMapping
|
|
else
|
|
I2 := MaxCPMapping;
|
|
while I <= I2 do
|
|
begin
|
|
if RtlCP = CpXList [I].WinCP then
|
|
begin
|
|
RtlCPtoOS2CP := CpXList [I].OS2CP;
|
|
if ReqFlags and CpxMappingOnly = 0 then
|
|
begin
|
|
begin
|
|
if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success then
|
|
CpXList [I].UConvObj := UConvObj
|
|
else
|
|
UConvObj := nil;
|
|
end
|
|
end;
|
|
Exit;
|
|
end;
|
|
Inc (I);
|
|
end;
|
|
(*
|
|
Special processing for
|
|
ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE})
|
|
might be added here...or not ;-)
|
|
|
|
if (TempCpRec.OS2CP <> High (TempCpRec.OS2CP)) or
|
|
(TempCpRec.WinCP <> RtlCp) then
|
|
begin
|
|
if TempCpRec.UConvObj <> nil then
|
|
begin
|
|
RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
|
|
if RCI <> 0 then
|
|
OSErrorWatch (cardinal (RCI));
|
|
end;
|
|
TempCpRec.OS2CP := High (TempCpRec.OS2CP);
|
|
TempCpRec.WinCP := RtlCp;
|
|
end;
|
|
|
|
Map to CP_ASCII aka OS2CP=367 if RtlCP not recognized and UConvObject
|
|
is requested???
|
|
*)
|
|
|
|
(* Signalize unrecognized (untranslatable) MS Windows codepage *)
|
|
OSErrorWatch (Uls_Invalid);
|
|
end;
|
|
end;
|
|
|
|
|
|
function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte): TSystemCodepage;
|
|
var
|
|
NoUConvObj: TUConvObject;
|
|
begin
|
|
if RtlUsesWinCP then
|
|
OS2CPtoRtlCP := OS2CPtoRtlCP (CP, ReqFlags or CpxMappingOnly, NoUConvObj)
|
|
else
|
|
OS2CPtoRtlCP := TSystemCodepage (CP);
|
|
end;
|
|
|
|
|
|
function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte): cardinal;
|
|
var
|
|
NoUConvObj: TUConvObject;
|
|
begin
|
|
if RtlUsesWinCP then
|
|
RtlCPtoOS2CP := RtlCPtoOS2CP (RtlCP, ReqFlags or CpxMappingOnly, NoUConvObj)
|
|
else
|
|
RtlCPtoOS2CP := RtlCP;
|
|
end;
|
|
|
|
|
|
procedure OS2Unicode2AnsiMove (Source: PUnicodeChar; var Dest: RawByteString;
|
|
CP: TSystemCodePage; Len: SizeInt);
|
|
var
|
|
RCI: longint;
|
|
UConvObj: TUConvObject;
|
|
OS2CP: cardinal;
|
|
Src2: PUnicodeChar;
|
|
Len2, LenOut, OutOffset, NonIdentical: longint;
|
|
Dest2: PChar;
|
|
begin
|
|
OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
|
|
{ if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
|
|
if UConvObj = nil then
|
|
begin
|
|
{$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
|
|
|
|
DefaultUnicode2AnsiMove (Source, Dest, CP, Len);
|
|
Exit;
|
|
end;
|
|
LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
|
|
SetLength (Dest, LenOut);
|
|
SetCodePage (Dest, CP, false);
|
|
Src2 := Source;
|
|
Len2 := Len;
|
|
Dest2 := PChar (Dest);
|
|
RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
|
|
NonIdentical);
|
|
repeat
|
|
case RCI of
|
|
Uls_Success:
|
|
begin
|
|
if LenOut > 0 then
|
|
SetLength (Dest, Length (Dest) - LenOut);
|
|
Break;
|
|
end;
|
|
Uls_IllegalSequence:
|
|
begin
|
|
OSErrorWatch (Uls_IllegalSequence);
|
|
{ skip and set to '?' }
|
|
Inc (Src2);
|
|
Dec (Len2);
|
|
Dest2^ := '?';
|
|
Inc (Dest2);
|
|
Dec (LenOut);
|
|
end;
|
|
Uls_BufferFull:
|
|
begin
|
|
OutOffset := Dest2 - PChar (Dest);
|
|
(* Use Len2 or Len decreased by difference between Source and Src2? *)
|
|
(* Extend more this time - target is probably a DBCS or UTF-8 *)
|
|
SetLength (Dest, Length (Dest) + Succ (Len2 * 2));
|
|
{ string could have been moved }
|
|
Dest2 := PChar (Dest) + OutOffset;
|
|
Inc (LenOut, Succ (Len2 * 2));
|
|
end
|
|
else
|
|
begin
|
|
SetLength (Dest, 0);
|
|
OSErrorWatch (cardinal (RCI));
|
|
{ Break }
|
|
RunError (231);
|
|
end;
|
|
end;
|
|
RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
|
|
NonIdentical);
|
|
until false;
|
|
end;
|
|
|
|
procedure OS2Ansi2UnicodeMove (Source: PChar; CP: TSystemCodePage;
|
|
var Dest: UnicodeString; Len: SizeInt);
|
|
var
|
|
RCI: longint;
|
|
UConvObj: TUConvObject;
|
|
OS2CP: cardinal;
|
|
Src2: PChar;
|
|
Len2, LenOut, OutOffset, NonIdentical: longint;
|
|
Dest2: PWideChar;
|
|
begin
|
|
OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
|
|
{ if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
|
|
if UConvObj = nil then
|
|
begin
|
|
{$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
|
|
|
|
DefaultAnsi2UnicodeMove (Source, CP, Dest, Len);
|
|
Exit;
|
|
end;
|
|
|
|
LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
|
|
SetLength (Dest, LenOut);
|
|
Src2 := Source;
|
|
Len2 := Len;
|
|
Dest2 := PWideChar (Dest);
|
|
|
|
RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut, NonIdentical);
|
|
repeat
|
|
case RCI of
|
|
Uls_Success:
|
|
begin
|
|
if LenOut > 0 then
|
|
SetLength (Dest, Length (Dest) - LenOut);
|
|
Break;
|
|
end;
|
|
Uls_IllegalSequence:
|
|
begin
|
|
OSErrorWatch (Uls_IllegalSequence);
|
|
{ skip and set to '?' }
|
|
Inc (Src2);
|
|
Dec (Len2);
|
|
Dest2^ := '?';
|
|
Inc (Dest2);
|
|
Dec (LenOut);
|
|
end;
|
|
Uls_BufferFull:
|
|
begin
|
|
OutOffset := Dest2 - PWideChar (Dest);
|
|
(* Use Len2 or Len decreased by difference between Source and Src2? *)
|
|
SetLength (Dest, Length (Dest) + Succ (Len2));
|
|
{ string could have been moved }
|
|
Dest2 := PWideChar (Dest) + OutOffset;
|
|
Inc (LenOut, Succ (Len2));
|
|
end
|
|
else
|
|
begin
|
|
SetLength (Dest, 0);
|
|
OSErrorWatch (cardinal (RCI));
|
|
{ Break }
|
|
RunError (231);
|
|
end;
|
|
end;
|
|
RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut,
|
|
NonIdentical);
|
|
until false;
|
|
|
|
{???
|
|
PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
|
|
}
|
|
end;
|
|
|
|
|
|
function RtlChangeCP (CP: TSystemCodePage): longint;
|
|
var
|
|
OS2CP, I: cardinal;
|
|
NoUConvObj: TUConvObject;
|
|
RCI: longint;
|
|
begin
|
|
OS2CP := RtlCpToOS2Cp (CP, cpxMappingOnly, NoUConvObj);
|
|
RtlChangeCP := longint (DosSetProcessCP (OS2CP));
|
|
if RtlChangeCP <> 0 then
|
|
OSErrorWatch (RtlChangeCP)
|
|
else
|
|
begin
|
|
DefaultSystemCodePage := CP;
|
|
DefaultRTLFileSystemCodePage := DefaultSystemCodePage;
|
|
DefaultFileSystemCodePage := DefaultSystemCodePage;
|
|
|
|
if OS2CP <> DefCpRec.OS2CP then
|
|
begin
|
|
if DefCpRec.UConvObj <> nil then
|
|
begin
|
|
RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
|
|
if RCI <> 0 then
|
|
OSErrorWatch (cardinal (RCI));
|
|
DefCpRec.UConvObj := nil;
|
|
end;
|
|
DefCPRec.OS2CP := OS2CP;
|
|
RCI := Sys_UniCreateUConvObject (@WNull, DefCpRec.UConvObj);
|
|
if RCI <> 0 then
|
|
OSErrorWatch (cardinal (RCI));
|
|
(* Find out WinCP _without_ considering RtlUsesWinCP *)
|
|
I := 1;
|
|
while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> OS2CP) do
|
|
Inc (I);
|
|
if CpXList [I].OS2CP = OS2CP then
|
|
DefCpRec.WinCP := CpXList [I].WinCP
|
|
else
|
|
DefCpRec.WinCP := OS2CP;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{
|
|
function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
|
|
begin
|
|
result:=s;
|
|
UniqueString(result);
|
|
if length(result)>0 then
|
|
CharUpperBuff(LPWSTR(result),length(result));
|
|
end;
|
|
|
|
|
|
function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
|
|
begin
|
|
result:=s;
|
|
UniqueString(result);
|
|
if length(result)>0 then
|
|
CharLowerBuff(LPWSTR(result),length(result));
|
|
end;
|
|
}
|
|
|
|
|
|
(*
|
|
CWSTRING:
|
|
|
|
function LowerWideString(const s : WideString) : WideString;
|
|
var
|
|
i : SizeInt;
|
|
begin
|
|
SetLength(result,length(s));
|
|
for i:=0 to length(s)-1 do
|
|
pwidechar(result)[i]:=WideChar(towlower(wint_t(s[i+1])));
|
|
end;
|
|
|
|
|
|
function UpperWideString(const s : WideString) : WideString;
|
|
var
|
|
i : SizeInt;
|
|
begin
|
|
SetLength(result,length(s));
|
|
for i:=0 to length(s)-1 do
|
|
pwidechar(result)[i]:=WideChar(towupper(wint_t(s[i+1])));
|
|
end;
|
|
|
|
|
|
procedure EnsureAnsiLen(var S: AnsiString; const len: SizeInt); inline;
|
|
begin
|
|
if (len>length(s)) then
|
|
if (length(s) < 10*256) then
|
|
setlength(s,length(s)+10)
|
|
else
|
|
setlength(s,length(s)+length(s) shr 8);
|
|
end;
|
|
|
|
|
|
procedure ConcatCharToAnsiStr(const c: char; var S: AnsiString; var index: SizeInt);
|
|
begin
|
|
EnsureAnsiLen(s,index);
|
|
pchar(@s[index])^:=c;
|
|
inc(index);
|
|
end;
|
|
|
|
|
|
{ concatenates an utf-32 char to a widestring. S *must* be unique when entering. }
|
|
{$ifndef beos}
|
|
procedure ConcatUTF32ToAnsiStr(const nc: wint_t; var S: AnsiString; var index: SizeInt; var mbstate: mbstate_t);
|
|
{$else not beos}
|
|
procedure ConcatUTF32ToAnsiStr(const nc: wint_t; var S: AnsiString; var index: SizeInt);
|
|
{$endif beos}
|
|
var
|
|
p : pchar;
|
|
mblen : size_t;
|
|
begin
|
|
{ we know that s is unique -> avoid uniquestring calls}
|
|
p:=@s[index];
|
|
if (nc<=127) then
|
|
ConcatCharToAnsiStr(char(nc),s,index)
|
|
else
|
|
begin
|
|
EnsureAnsiLen(s,index+MB_CUR_MAX);
|
|
{$ifndef beos}
|
|
mblen:=wcrtomb(p,wchar_t(nc),@mbstate);
|
|
{$else not beos}
|
|
mblen:=wctomb(p,wchar_t(nc));
|
|
{$endif not beos}
|
|
if (mblen<>size_t(-1)) then
|
|
inc(index,mblen)
|
|
else
|
|
begin
|
|
{ invalid wide char }
|
|
p^:='?';
|
|
inc(index);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function LowerAnsiString(const s : AnsiString) : AnsiString;
|
|
var
|
|
i, slen,
|
|
resindex : SizeInt;
|
|
mblen : size_t;
|
|
{$ifndef beos}
|
|
ombstate,
|
|
nmbstate : mbstate_t;
|
|
{$endif beos}
|
|
wc : wchar_t;
|
|
begin
|
|
{$ifndef beos}
|
|
fillchar(ombstate,sizeof(ombstate),0);
|
|
fillchar(nmbstate,sizeof(nmbstate),0);
|
|
{$endif beos}
|
|
slen:=length(s);
|
|
SetLength(result,slen+10);
|
|
i:=1;
|
|
resindex:=1;
|
|
while (i<=slen) do
|
|
begin
|
|
if (s[i]<=#127) then
|
|
begin
|
|
wc:=wchar_t(s[i]);
|
|
mblen:= 1;
|
|
end
|
|
else
|
|
{$ifndef beos}
|
|
mblen:=mbrtowc(@wc, pchar(@s[i]), slen-i+1, @ombstate);
|
|
{$else not beos}
|
|
mblen:=mbtowc(@wc, pchar(@s[i]), slen-i+1);
|
|
{$endif not beos}
|
|
case mblen of
|
|
size_t(-2):
|
|
begin
|
|
{ partial invalid character, copy literally }
|
|
while (i<=slen) do
|
|
begin
|
|
ConcatCharToAnsiStr(s[i],result,resindex);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
size_t(-1), 0:
|
|
begin
|
|
{ invalid or null character }
|
|
ConcatCharToAnsiStr(s[i],result,resindex);
|
|
inc(i);
|
|
end;
|
|
else
|
|
begin
|
|
{ a valid sequence }
|
|
{ even if mblen = 1, the lowercase version may have a }
|
|
{ different length }
|
|
{ We can't do anything special if wchar_t is 16 bit... }
|
|
{$ifndef beos}
|
|
ConcatUTF32ToAnsiStr(towlower(wint_t(wc)),result,resindex,nmbstate);
|
|
{$else not beos}
|
|
ConcatUTF32ToAnsiStr(towlower(wint_t(wc)),result,resindex);
|
|
{$endif not beos}
|
|
inc(i,mblen);
|
|
end;
|
|
end;
|
|
end;
|
|
SetLength(result,resindex-1);
|
|
end;
|
|
|
|
|
|
function UpperAnsiString(const s : AnsiString) : AnsiString;
|
|
var
|
|
i, slen,
|
|
resindex : SizeInt;
|
|
mblen : size_t;
|
|
{$ifndef beos}
|
|
ombstate,
|
|
nmbstate : mbstate_t;
|
|
{$endif beos}
|
|
wc : wchar_t;
|
|
begin
|
|
{$ifndef beos}
|
|
fillchar(ombstate,sizeof(ombstate),0);
|
|
fillchar(nmbstate,sizeof(nmbstate),0);
|
|
{$endif beos}
|
|
slen:=length(s);
|
|
SetLength(result,slen+10);
|
|
i:=1;
|
|
resindex:=1;
|
|
while (i<=slen) do
|
|
begin
|
|
if (s[i]<=#127) then
|
|
begin
|
|
wc:=wchar_t(s[i]);
|
|
mblen:= 1;
|
|
end
|
|
else
|
|
{$ifndef beos}
|
|
mblen:=mbrtowc(@wc, pchar(@s[i]), slen-i+1, @ombstate);
|
|
{$else not beos}
|
|
mblen:=mbtowc(@wc, pchar(@s[i]), slen-i+1);
|
|
{$endif beos}
|
|
case mblen of
|
|
size_t(-2):
|
|
begin
|
|
{ partial invalid character, copy literally }
|
|
while (i<=slen) do
|
|
begin
|
|
ConcatCharToAnsiStr(s[i],result,resindex);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
size_t(-1), 0:
|
|
begin
|
|
{ invalid or null character }
|
|
ConcatCharToAnsiStr(s[i],result,resindex);
|
|
inc(i);
|
|
end;
|
|
else
|
|
begin
|
|
{ a valid sequence }
|
|
{ even if mblen = 1, the uppercase version may have a }
|
|
{ different length }
|
|
{ We can't do anything special if wchar_t is 16 bit... }
|
|
{$ifndef beos}
|
|
ConcatUTF32ToAnsiStr(towupper(wint_t(wc)),result,resindex,nmbstate);
|
|
{$else not beos}
|
|
ConcatUTF32ToAnsiStr(towupper(wint_t(wc)),result,resindex);
|
|
{$endif not beos}
|
|
inc(i,mblen);
|
|
end;
|
|
end;
|
|
end;
|
|
SetLength(result,resindex-1);
|
|
end;
|
|
|
|
|
|
function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; external name 'FPC_UTF16TOUTF32';
|
|
|
|
function WideStringToUCS4StringNoNulls(const s : WideString) : UCS4String;
|
|
var
|
|
i, slen,
|
|
destindex : SizeInt;
|
|
len : longint;
|
|
uch : UCS4Char;
|
|
begin
|
|
slen:=length(s);
|
|
setlength(result,slen+1);
|
|
i:=1;
|
|
destindex:=0;
|
|
while (i<=slen) do
|
|
begin
|
|
uch:=utf16toutf32(s,i,len);
|
|
if (uch=UCS4Char(0)) then
|
|
uch:=UCS4Char(32);
|
|
result[destindex]:=uch;
|
|
inc(destindex);
|
|
inc(i,len);
|
|
end;
|
|
result[destindex]:=UCS4Char(0);
|
|
{ destindex <= slen }
|
|
setlength(result,destindex+1);
|
|
end;
|
|
|
|
|
|
function CompareWideString(const s1, s2 : WideString) : PtrInt;
|
|
var
|
|
hs1,hs2 : UCS4String;
|
|
begin
|
|
{ wcscoll interprets null chars as end-of-string -> filter out }
|
|
hs1:=WideStringToUCS4StringNoNulls(s1);
|
|
hs2:=WideStringToUCS4StringNoNulls(s2);
|
|
result:=wcscoll(pwchar_t(hs1),pwchar_t(hs2));
|
|
end;
|
|
|
|
|
|
function CompareTextWideString(const s1, s2 : WideString): PtrInt;
|
|
begin
|
|
result:=CompareWideString(UpperWideString(s1),UpperWideString(s2));
|
|
end;
|
|
|
|
|
|
function CharLengthPChar(const Str: PChar): PtrInt;
|
|
var
|
|
nextlen: ptrint;
|
|
s: pchar;
|
|
{$ifndef beos}
|
|
mbstate: mbstate_t;
|
|
{$endif not beos}
|
|
begin
|
|
result:=0;
|
|
s:=str;
|
|
{$ifndef beos}
|
|
fillchar(mbstate,sizeof(mbstate),0);
|
|
{$endif not beos}
|
|
repeat
|
|
{$ifdef beos}
|
|
nextlen:=ptrint(mblen(str,MB_CUR_MAX));
|
|
{$else beos}
|
|
nextlen:=ptrint(mbrlen(str,MB_CUR_MAX,@mbstate));
|
|
{$endif beos}
|
|
{ skip invalid/incomplete sequences }
|
|
if (nextlen<0) then
|
|
nextlen:=1;
|
|
inc(result,nextlen);
|
|
inc(s,nextlen);
|
|
until (nextlen=0);
|
|
end;
|
|
|
|
|
|
function CodePointLength(const Str: PChar; maxlookahead: ptrint): PtrInt;
|
|
var
|
|
nextlen: ptrint;
|
|
{$ifndef beos}
|
|
mbstate: mbstate_t;
|
|
{$endif not beos}
|
|
begin
|
|
{$ifdef beos}
|
|
result:=ptrint(mblen(str,maxlookahead));
|
|
{$else beos}
|
|
fillchar(mbstate,sizeof(mbstate),0);
|
|
result:=ptrint(mbrlen(str,maxlookahead,@mbstate));
|
|
{ mbrlen can also return -2 for "incomplete but potially valid character
|
|
and data has been processed" }
|
|
if result<0 then
|
|
result:=-1;
|
|
{$endif beos}
|
|
end;
|
|
|
|
|
|
function StrCompAnsiIntern(s1,s2 : PChar; len1, len2: PtrInt; canmodifys1, canmodifys2: boolean): PtrInt;
|
|
var
|
|
a,b: pchar;
|
|
i: PtrInt;
|
|
begin
|
|
if not(canmodifys1) then
|
|
getmem(a,len1+1)
|
|
else
|
|
a:=s1;
|
|
for i:=0 to len1-1 do
|
|
if s1[i]<>#0 then
|
|
a[i]:=s1[i]
|
|
else
|
|
a[i]:=#32;
|
|
a[len1]:=#0;
|
|
|
|
if not(canmodifys2) then
|
|
getmem(b,len2+1)
|
|
else
|
|
b:=s2;
|
|
for i:=0 to len2-1 do
|
|
if s2[i]<>#0 then
|
|
b[i]:=s2[i]
|
|
else
|
|
b[i]:=#32;
|
|
b[len2]:=#0;
|
|
result:=strcoll(a,b);
|
|
if not(canmodifys1) then
|
|
freemem(a);
|
|
if not(canmodifys2) then
|
|
freemem(b);
|
|
end;
|
|
|
|
|
|
function CompareStrAnsiString(const s1, s2: ansistring): PtrInt;
|
|
begin
|
|
result:=StrCompAnsiIntern(pchar(s1),pchar(s2),length(s1),length(s2),false,false);
|
|
end;
|
|
|
|
|
|
function StrCompAnsi(s1,s2 : PChar): PtrInt;
|
|
begin
|
|
result:=strcoll(s1,s2);
|
|
end;
|
|
|
|
|
|
function AnsiCompareText(const S1, S2: ansistring): PtrInt;
|
|
var
|
|
a, b: AnsiString;
|
|
begin
|
|
a:=UpperAnsistring(s1);
|
|
b:=UpperAnsistring(s2);
|
|
result:=StrCompAnsiIntern(pchar(a),pchar(b),length(a),length(b),true,true);
|
|
end;
|
|
|
|
|
|
function AnsiStrIComp(S1, S2: PChar): PtrInt;
|
|
begin
|
|
result:=AnsiCompareText(ansistring(s1),ansistring(s2));
|
|
end;
|
|
|
|
|
|
function AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
|
|
var
|
|
a, b: pchar;
|
|
begin
|
|
if (maxlen=0) then
|
|
exit(0);
|
|
if (s1[maxlen]<>#0) then
|
|
begin
|
|
getmem(a,maxlen+1);
|
|
move(s1^,a^,maxlen);
|
|
a[maxlen]:=#0;
|
|
end
|
|
else
|
|
a:=s1;
|
|
if (s2[maxlen]<>#0) then
|
|
begin
|
|
getmem(b,maxlen+1);
|
|
move(s2^,b^,maxlen);
|
|
b[maxlen]:=#0;
|
|
end
|
|
else
|
|
b:=s2;
|
|
result:=StrCompAnsiIntern(a,b,maxlen,maxlen,a<>s1,b<>s2);
|
|
if (a<>s1) then
|
|
freemem(a);
|
|
if (b<>s2) then
|
|
freemem(b);
|
|
end;
|
|
|
|
|
|
function AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
|
|
var
|
|
a, b: ansistring;
|
|
begin
|
|
if (maxlen=0) then
|
|
exit(0);
|
|
setlength(a,maxlen);
|
|
move(s1^,a[1],maxlen);
|
|
setlength(b,maxlen);
|
|
move(s2^,b[1],maxlen);
|
|
result:=AnsiCompareText(a,b);
|
|
end;
|
|
|
|
|
|
procedure ansi2pchar(const s: ansistring; const orgp: pchar; out p: pchar);
|
|
var
|
|
newlen: sizeint;
|
|
begin
|
|
newlen:=length(s);
|
|
if newlen>strlen(orgp) then
|
|
fpc_rangeerror;
|
|
p:=orgp;
|
|
if (newlen>0) then
|
|
move(s[1],p[0],newlen);
|
|
p[newlen]:=#0;
|
|
end;
|
|
|
|
|
|
function AnsiStrLower(Str: PChar): PChar;
|
|
var
|
|
temp: ansistring;
|
|
begin
|
|
temp:=loweransistring(str);
|
|
ansi2pchar(temp,str,result);
|
|
end;
|
|
|
|
|
|
function AnsiStrUpper(Str: PChar): PChar;
|
|
var
|
|
temp: ansistring;
|
|
begin
|
|
temp:=upperansistring(str);
|
|
ansi2pchar(temp,str,result);
|
|
end;
|
|
|
|
{$ifdef FPC_HAS_CPSTRING}
|
|
{$i textrec.inc}
|
|
procedure SetStdIOCodePage(var T: Text); inline;
|
|
begin
|
|
case TextRec(T).Mode of
|
|
fmInput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleInput);
|
|
fmOutput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleOutput);
|
|
end;
|
|
end;
|
|
|
|
procedure SetStdIOCodePages; inline;
|
|
begin
|
|
SetStdIOCodePage(Input);
|
|
SetStdIOCodePage(Output);
|
|
SetStdIOCodePage(ErrOutput);
|
|
SetStdIOCodePage(StdOut);
|
|
SetStdIOCodePage(StdErr);
|
|
end;
|
|
{$endif FPC_HAS_CPSTRING}
|
|
*)
|
|
|
|
procedure InitOS2WideStringManager; inline;
|
|
var
|
|
RC: cardinal;
|
|
ErrName: array [0..MaxPathLen] of char;
|
|
P: pointer;
|
|
begin
|
|
RC := DosLoadModule (@ErrName [0], SizeOf (ErrName), @UConvName [0],
|
|
UConvHandle);
|
|
if RC = 0 then
|
|
begin
|
|
RC := DosQueryProcAddr (UConvHandle, OrdUniCreateUConvObject, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_UniCreateUConvObject := TUniCreateUConvObject (P);
|
|
RC := DosQueryProcAddr (UConvHandle, OrdUniMapCpToUcsCp, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_UniMapCpToUcsCp := TUniMapCpToUcsCp (P);
|
|
RC := DosQueryProcAddr (UConvHandle, OrdUniFreeUConvObject, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_UniFreeUConvObject := TUniFreeUConvObject (P);
|
|
RC := DosQueryProcAddr (UConvHandle, OrdUniUConvFromUcs, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_UniUConvFromUcs := TUniUConvFromUcs (P);
|
|
RC := DosQueryProcAddr (UConvHandle, OrdUniUConvToUcs, nil, P);
|
|
if RC = 0 then
|
|
begin
|
|
Sys_UniUConvToUcs := TUniUConvToUcs (P);
|
|
|
|
UniAPI := true;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if RC <> 0 then
|
|
OSErrorWatch (RC);
|
|
if not (UniAPI) then
|
|
begin
|
|
Sys_UniCreateUConvObject := @DummyUniCreateUConvObject;
|
|
Sys_UniMapCpToUcsCp := @DummyUniMapCpToUcsCp;
|
|
Sys_UniFreeUConvObject := @DummyUniFreeUConvObject;
|
|
Sys_UniUConvFromUcs := @DummyUniUConvFromUcs;
|
|
Sys_UniUConvToUcs := @DummyUniUConvToUcs;
|
|
|
|
end;
|
|
|
|
{ Widestring }
|
|
WideStringManager.Wide2AnsiMoveProc := @OS2Unicode2AnsiMove;
|
|
WideStringManager.Ansi2WideMoveProc := @OS2Ansi2UnicodeMove;
|
|
{ WideStringManager.UpperWideStringProc := @OS2UnicodeUpper;
|
|
WideStringManager.LowerWideStringProc := @OS2UnicodeLower;}
|
|
{ Unicode }
|
|
WideStringManager.Unicode2AnsiMoveProc := @OS2Unicode2AnsiMove;
|
|
WideStringManager.Ansi2UnicodeMoveProc := @OS2Ansi2UnicodeMove;
|
|
{ WideStringManager.UpperUnicodeStringProc := @OS2UnicodeUpper;
|
|
WideStringManager.LowerUnicodeStringProc := @OS2UnicodeLower;}
|
|
{ Codepage }
|
|
WideStringManager.GetStandardCodePageProc := @OS2GetStandardCodePage;
|
|
(*
|
|
Wide2AnsiMoveProc:=@Wide2AnsiMove;
|
|
Ansi2WideMoveProc:=@Ansi2WideMove;
|
|
|
|
UpperWideStringProc:=@UpperWideString;
|
|
LowerWideStringProc:=@LowerWideString;
|
|
|
|
CompareWideStringProc:=@CompareWideString;
|
|
CompareTextWideStringProc:=@CompareTextWideString;
|
|
|
|
CharLengthPCharProc:=@CharLengthPChar;
|
|
CodePointLengthProc:=@CodePointLength;
|
|
|
|
UpperAnsiStringProc:=@UpperAnsiString;
|
|
LowerAnsiStringProc:=@LowerAnsiString;
|
|
CompareStrAnsiStringProc:=@CompareStrAnsiString;
|
|
CompareTextAnsiStringProc:=@AnsiCompareText;
|
|
StrCompAnsiStringProc:=@StrCompAnsi;
|
|
StrICompAnsiStringProc:=@AnsiStrIComp;
|
|
StrLCompAnsiStringProc:=@AnsiStrLComp;
|
|
StrLICompAnsiStringProc:=@AnsiStrLIComp;
|
|
StrLowerAnsiStringProc:=@AnsiStrLower;
|
|
StrUpperAnsiStringProc:=@AnsiStrUpper;
|
|
ThreadInitProc:=@InitThread;
|
|
ThreadFiniProc:=@FiniThread;
|
|
{ Unicode }
|
|
Unicode2AnsiMoveProc:=@Wide2AnsiMove;
|
|
Ansi2UnicodeMoveProc:=@Ansi2WideMove;
|
|
UpperUnicodeStringProc:=@UpperWideString;
|
|
LowerUnicodeStringProc:=@LowerWideString;
|
|
CompareUnicodeStringProc:=@CompareWideString;
|
|
CompareTextUnicodeStringProc:=@CompareTextWideString;
|
|
*)
|
|
end;
|