summaryrefslogtreecommitdiff
path: root/rtl/os2/sysucode.inc
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/os2/sysucode.inc')
-rw-r--r--rtl/os2/sysucode.inc1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/rtl/os2/sysucode.inc b/rtl/os2/sysucode.inc
new file mode 100644
index 0000000000..422a3d1ea7
--- /dev/null
+++ b/rtl/os2/sysucode.inc
@@ -0,0 +1,1654 @@
+{
+ This file is part of the Free Pascal run time library.
+ Copyright (c) 2014-2015 by Tomas Hajny and other members
+ 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_API_Error_Base = $20400;
+ 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;
+ OrdUniQueryXdigit = 1;
+ OrdUniQuerySpace = 2;
+ OrdUniQueryPrint = 3;
+ OrdUniQueryGraph = 4;
+ OrdUniQueryCntrl = 5;
+ OrdUniQueryAlpha = 6;
+ OrdUniFreeAttrObject = 7;
+ OrdUniQueryCharAttr = 8;
+ OrdUniQueryUpper = 9;
+ OrdUniQueryPunct = 10;
+ OrdUniQueryLower = 11;
+ OrdUniQueryDigit = 12;
+ OrdUniQueryBlank = 13;
+ OrdUniQueryAlnum = 14;
+ OrdUniScanForAttr = 15;
+ OrdUniCreateAttrObject = 16;
+ OrdUniCreateTransformObject = 17;
+ OrdUniFreeTransformObject = 18;
+ OrdUniQueryLocaleObject = 19;
+ OrdUniCreateLocaleObject = 20;
+ OrdUniFreeLocaleObject = 21;
+ OrdUniFreeMem = 22;
+ OrdUniFreeLocaleInfo = 28;
+ OrdUniQueryLocaleInfo = 29;
+ OrdUniQueryLocaleItem = 30;
+ OrdUniStrcat = 31;
+ OrdUniStrchr = 32;
+ OrdUniStrcmp = 33;
+ OrdUniStrcmpi = 34;
+ OrdUniStrColl = 35;
+ OrdUniStrcpy = 36;
+ OrdUniStrcspn = 37;
+ OrdUniStrfmon = 38;
+ OrdUniStrftime = 39;
+ OrdUniStrlen = 40;
+ OrdUniStrncat = 41;
+ OrdUniStrncmp = 42;
+ OrdUniStrncmpi = 43;
+ OrdUniStrncpy = 44;
+ OrdUniStrpbrk = 45;
+ OrdUniStrptime = 46;
+ OrdUniStrrchr = 47;
+ OrdUniStrspn = 48;
+ OrdUniStrstr = 49;
+ OrdUniStrtod = 50;
+ OrdUniStrtol = 51;
+ OrdUniStrtoul = 52;
+ OrdUniStrxfrm = 53;
+ OrdUniLocaleStrToToken = 54;
+ OrdUniLocaleTokenToStr = 55;
+ OrdUniTransformStr = 56;
+ OrdUniTransLower = 57;
+ OrdUniTransUpper = 58;
+ OrdUniTolower = 59;
+ OrdUniToupper = 60;
+ OrdUniStrupr = 61;
+ OrdUniStrlwr = 62;
+ OrdUniStrtok = 63;
+ OrdUniMapCtryToLocale = 67;
+ OrdUniMakeKey = 70;
+ OrdUniQueryChar = 71;
+ OrdUniGetOverride = 72;
+ OrdUniGetColval = 73;
+ OrdUniQueryAttr = 74;
+ OrdUniQueryStringType = 75;
+ OrdUniQueryCharType = 76;
+ OrdUniQueryNumericValue = 77;
+ OrdUniQueryCharTypeTable = 78;
+ OrdUniProcessUconv = 80;
+ OrdLocale = 151;
+ OrdUniMakeUserLocale = 152;
+ OrdUniSetUserLocaleItem = 153;
+ OrdUniDeleteUserLocale = 154;
+ OrdUniCompleteUserLocale = 155;
+ OrdUniQueryLocaleValue = 156;
+ OrdUniQueryLocaleList = 157;
+ OrdUniQueryLanguageName = 158;
+ OrdUniQueryCountryName = 159;
+ Uni_Token_Pointer = 1;
+ Uni_MBS_String_Pointer = 2;
+ Uni_UCS_String_Pointer = 3;
+ Uni_System_Locales = 1;
+ Uni_User_Locales = 2;
+ 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;
+ TDummyUConvObject = record
+ CP: cardinal;
+ CPNameLen: byte;
+ CPName: record end;
+ end;
+ PDummyUConvObject = ^TDummyUConvObject;
+
+
+var
+ DBCSLeadRanges: array [0..11] of char;
+ CollationSequence: array [char] of char;
+
+
+const
+ DefCpRec: TCpRec = (WinCP: 0; OS2CP: 0; UConvObj: nil);
+ InInitDefaultCP: int64 = -1; (* Range is bigger than TThreadID to avoid conflict *)
+ DefLocObj: TLocaleObject = nil;
+ IBMPrefix: packed array [1..4] of WideChar = 'IBM-';
+ CachedDefFSCodepage: TSystemCodepage = 0;
+ EmptyCC: TCountryCode = (Country: 0; Codepage: 0); (* Empty = current *)
+ (* 819 = IBM codepage number for ISO 8859-1 used in FPC default *)
+ (* dummy translation between UnicodeString and AnsiString. *)
+ IsoCC: TCountryCode = (Country: 1; Codepage: 819); (* Empty = current *)
+ (* The following two arrays are initialized on startup in case that *)
+ (* Dummy* routines must be used. First for current codepage... *)
+ DBCSLeadRangesEnd: byte = 0;
+ LowerChars: array [char] of char =
+ (#0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16,
+ #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30, #31,
+ #32, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42, #43, #44, #45, #46,
+ #47, #48, #49, #50, #51, #52, #53, #54, #55, #56, #57, #58, #59, #60, #61,
+ #62, #63, #64, #65, #66, #67, #68, #69, #70, #71, #72, #73, #74, #75, #76,
+ #77, #78, #79, #80, #81, #82, #83, #84, #85, #86, #87, #88, #89, #90, #91,
+ #92, #93, #94, #95, #96, #97, #98, #99, #100, #101, #102, #103, #104, #105,
+ #106, #107, #108, #109, #110, #111, #112, #113, #114, #115, #116, #117,
+ #118, #119, #120, #121, #122, #123, #124, #125, #126, #127, #128, #129,
+ #130, #131, #132, #133, #134, #135, #136, #137, #138, #139, #140, #141,
+ #142, #143, #144, #145, #146, #147, #148, #149, #150, #151, #152, #153,
+ #154, #155, #156, #157, #158, #159, #160, #161, #162, #163, #164, #165,
+ #166, #167, #168, #169, #170, #171, #172, #173, #174, #175, #176, #177,
+ #178, #179, #180, #181, #182, #183, #184, #185, #186, #187, #188, #189,
+ #190, #191, #192, #193, #194, #195, #196, #197, #198, #199, #200, #201,
+ #202, #203, #204, #205, #206, #207, #208, #209, #210, #211, #212, #213,
+ #214, #215, #216, #217, #218, #219, #220, #221, #222, #223, #224, #225,
+ #226, #227, #228, #229, #230, #231, #232, #233, #234, #235, #236, #237,
+ #238, #239, #240, #241, #242, #243, #244, #245, #246, #247, #248, #249,
+ #250, #251, #252, #253, #254, #255);
+ (* ...and now for ISO 8859-1 aka IBM codepage 819 *)
+ LowerCharsISO88591: array [char] of char =
+ (#0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16,
+ #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30, #31,
+ #32, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42, #43, #44, #45, #46,
+ #47, #48, #49, #50, #51, #52, #53, #54, #55, #56, #57, #58, #59, #60, #61,
+ #62, #63, #64, #65, #66, #67, #68, #69, #70, #71, #72, #73, #74, #75, #76,
+ #77, #78, #79, #80, #81, #82, #83, #84, #85, #86, #87, #88, #89, #90, #91,
+ #92, #93, #94, #95, #96, #97, #98, #99, #100, #101, #102, #103, #104, #105,
+ #106, #107, #108, #109, #110, #111, #112, #113, #114, #115, #116, #117,
+ #118, #119, #120, #121, #122, #123, #124, #125, #126, #127, #128, #129,
+ #130, #131, #132, #133, #134, #135, #136, #137, #138, #139, #140, #141,
+ #142, #143, #144, #145, #146, #147, #148, #149, #150, #151, #152, #153,
+ #154, #155, #156, #157, #158, #159, #160, #161, #162, #163, #164, #165,
+ #166, #167, #168, #169, #170, #171, #172, #173, #174, #175, #176, #177,
+ #178, #179, #180, #181, #182, #183, #184, #185, #186, #187, #188, #189,
+ #190, #191, #192, #193, #194, #195, #196, #197, #198, #199, #200, #201,
+ #202, #203, #204, #205, #206, #207, #208, #209, #210, #211, #212, #213,
+ #214, #215, #216, #217, #218, #219, #220, #221, #222, #223, #224, #225,
+ #226, #227, #228, #229, #230, #231, #232, #233, #234, #235, #236, #237,
+ #238, #239, #240, #241, #242, #243, #244, #245, #246, #247, #248, #249,
+ #250, #251, #252, #253, #254, #255);
+ NoIso88591Support: boolean = false;
+
+
+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
+ else
+ if RetSize < SizeOf (C) then
+ C := 850;
+ 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;
+
+
+procedure InitDBCSLeadRanges;
+var
+ RC: cardinal;
+begin
+ RC := DosQueryDBCSEnv (SizeOf (DBCSLeadRanges), EmptyCC,
+ @DBCSLeadRanges [0]);
+ DBCSLeadRangesEnd := 0;
+ if RC <> 0 then
+ while (DBCSLeadRangesEnd < SizeOf (DBCSLeadRanges)) and
+ ((DBCSLeadRanges [DBCSLeadRangesEnd] <> #0) or
+ (DBCSLeadRanges [Succ (DBCSLeadRangesEnd)] <> #0)) do
+ Inc (DBCSLeadRangesEnd, 2);
+end;
+
+
+procedure InitDummyAnsiSupport;
+var
+ C: char;
+ AllChars: array [char] of char;
+ RetSize: cardinal;
+begin
+ if DosQueryCollate (SizeOf (CollationSequence), EmptyCC, @CollationSequence,
+ RetSize) <> 0 then
+ Move (LowerChars, CollationSequence, SizeOf (CollationSequence));
+ Move (LowerChars, AllChars, SizeOf (AllChars));
+ if DosMapCase (SizeOf (AllChars), IsoCC, @AllChars [#0]) <> 0 then
+(* Codepage 819 may not be supported in all old OS/2 versions. *)
+ begin
+ Move (LowerCharsIso88591, AllChars, SizeOf (AllChars));
+ DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
+ NoIso88591Support := true;
+ end;
+ for C := Low (char) to High (char) do
+ if AllChars [C] <> C then
+ LowerCharsIso88591 [AllChars [C]] := C;
+ if NoIso88591Support then
+ Move (LowerCharsIso88591, LowerChars, SizeOf (LowerChars))
+ else
+ begin
+ Move (LowerChars, AllChars, SizeOf (AllChars));
+ DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
+ for C := Low (char) to High (char) do
+ if AllChars [C] <> C then
+ LowerChars [AllChars [C]] := C;
+ end;
+ InitDBCSLeadRanges;
+end;
+
+
+procedure ReInitDummyAnsiSupport;
+var
+ C: char;
+ AllChars: array [char] of char;
+ RetSize: cardinal;
+begin
+ for C := Low (char) to High (char) do
+ AllChars [C] := C;
+ if DosQueryCollate (SizeOf (CollationSequence), EmptyCC, @CollationSequence,
+ RetSize) <> 0 then
+ Move (AllChars, CollationSequence, SizeOf (CollationSequence));
+ DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
+ for C := Low (char) to High (char) do
+ if AllChars [C] <> C then
+ LowerChars [AllChars [C]] := C;
+ InitDBCSLeadRanges;
+end;
+
+
+function DummyUniToLower (UniCharIn: WideChar): WideChar; cdecl;
+var
+ C: char;
+begin
+ C := UniCharIn;
+ DummyUniToLower := LowerCharsIso88591 [C];
+end;
+
+
+function DummyUniToUpper (UniCharIn: WideChar): WideChar; cdecl;
+var
+ C: char;
+begin
+ DummyUniToUpper := UniCharIn;
+ C := UniCharIn;
+ if NoIso88591Support then
+ begin
+ if DosMapCase (1, EmptyCC, @C) = 0 then
+ DummyUniToUpper := C;
+ end
+ else
+ if DosMapCase (1, IsoCC, @C) = 0 then
+ DummyUniToUpper := C
+end;
+
+
+function DummyUniStrColl (Locale_Object: TLocaleObject;
+ const UCS1, UCS2: PWideChar): longint; cdecl;
+var
+ S1, S2: ansistring;
+begin
+ S1 := UCS1;
+ S2 := UCS2;
+ if S1 = S2 then
+ DummyUniStrColl := 0
+ else if S1 < S2 then
+ DummyUniStrColl := -1
+ else
+ DummyUniStrColl := 1;
+end;
+
+
+function DummyUniCreateLocaleObject (LocaleSpecType: longint;
+ const LocaleSpec: pointer; var Locale_Object: TLocaleObject): longint; cdecl;
+begin
+ DummyUniCreateLocaleObject := ULS_Unsupported;
+end;
+
+
+function DummyUniFreeLocaleObject (Locale_Object: TLocaleObject): longint;
+ cdecl;
+begin
+ DummyUniFreeLocaleObject := ULS_BadObject;
+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 GetRtlCpFromCpRec (const CpRec: TCpRec): TSystemCodepage; inline;
+begin
+ if RtlUsesWinCp then
+ GetRtlCp := CpRec.WinCP
+ else
+ GetRtlCp := TSystemCodepage (CpRec.Os2Cp);
+end;
+}
+
+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;
+
+
+procedure InitDefaultCP;
+var
+ OS2CP, I: cardinal;
+ NoUConvObj: TUConvObject;
+ RCI: longint;
+ RC: cardinal;
+ CPArr: TCPArray;
+ ReturnedSize: cardinal;
+begin
+ if InInitDefaultCP <> -1 then
+ begin
+ repeat
+ DosSleep (5);
+ until InInitDefaultCP <> -1;
+ Exit;
+ end;
+ InInitDefaultCP := ThreadID;
+ if DefCpRec.UConvObj <> nil then
+ begin
+(* Do not free the UConv object from DefCpRec, because it is also stored in
+ the respective CPXList record! *)
+{
+ RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
+ if RCI <> 0 then
+ OSErrorWatch (cardinal (RCI));
+}
+ DefCpRec.UConvObj := nil;
+ end;
+ RC := DosQueryCP (SizeOf (CPArr), @CPArr, ReturnedSize);
+ if (RC <> 0) and (RC <> 473) then
+ begin
+ OSErrorWatch (RC);
+ CPArr [0] := 850;
+ end
+ else if (ReturnedSize < 4) then
+ CPArr [0] := 850;
+ DefaultFileSystemCodePage := OS2CPtoRtlCP (CPArr [0], cpxAll,
+ DefCpRec.UConvObj);
+ CachedDefFSCodepage := DefaultFileSystemCodePage;
+ DefCpRec.OS2CP := CPArr [0];
+(* Find out WinCP _without_ considering RtlUsesWinCP *)
+ I := 1;
+ while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> OS2CP) do
+ Inc (I);
+ if CpXList [I].OS2CP = CPArr [0] then
+ DefCpRec.WinCP := CpXList [I].WinCP
+ else
+ DefCpRec.WinCP := CPArr [0];
+
+ if DefLocObj <> nil then
+ begin
+ RCI := Sys_UniFreeLocaleObject (DefLocObj);
+ if RCI <> 0 then
+ OSErrorWatch (cardinal (RCI));
+ end;
+ RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WNull, DefLocObj);
+ if RCI <> 0 then
+ OSErrorWatch (cardinal (RCI));
+ if not (UniAPI) then
+ ReInitDummyAnsiSupport;
+ InInitDefaultCP := -1;
+end;
+
+
+function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte;
+ var UConvObj: TUConvObject): TSystemCodepage;
+var
+ I, I2: cardinal;
+ RCI: longint;
+
+ function CheckDefaultOS2CP: boolean;
+ begin
+ if CP = DefCpRec.OS2CP then
+ begin
+ CheckDefaultOS2CP := true;
+ if RTLUsesWinCP then
+ OS2CPtoRtlCP := DefCpRec.WinCP;
+ if ReqFlags and CpxMappingOnly = 0 then
+ UConvObj := DefCpRec.UConvObj;
+ end
+ else
+ CheckDefaultOS2CP := false;
+ end;
+
+begin
+ OS2CPtoRtlCP := TSystemCodePage (CP);
+ UConvObj := nil;
+ if not UniAPI then (* No UniAPI => no need for UConvObj *)
+ ReqFlags := ReqFlags or CpxMappingOnly;
+ if CheckDefaultOS2CP then
+ Exit;
+ if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
+ (InInitDefaultCP <> ThreadID) then
+(* InInitDefaultCP = ThreadID -> this thread is already re-initializing the cached information *)
+ begin
+ if InInitDefaultCP <> -1 then
+ repeat
+ DosSleep (5) (* Let's wait until the other thread finishes re-initialization of the cache *)
+ until InInitDefaultCP = -1
+ else
+ InitDefaultCP;
+ if CheckDefaultOS2CP then
+ Exit;
+ end;
+ 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;
+
+
+function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte;
+ var UConvObj: TUConvObject): cardinal;
+var
+ I, I2: cardinal;
+
+ function CheckDefaultWinCP: boolean;
+ begin
+ if RtlCP = DefCpRec.WinCP then
+ begin
+ CheckDefaultWinCP := true;
+ RtlCPtoOS2CP := DefCpRec.WinCP;
+ if ReqFlags and CpxMappingOnly = 0 then
+ UConvObj := DefCpRec.UConvObj;
+ end
+ else
+ CheckDefaultWinCP := false;
+ end;
+
+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 CheckDefaultWinCp then
+ Exit
+ else
+ begin
+ if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
+ (InInitDefaultCP <> ThreadID) then
+(* InInitDefaultCP = ThreadID -> this thread is already re-initializing the cached information *)
+ begin
+ if InInitDefaultCP <> -1 then
+ repeat
+(* Let's wait until the other thread finishes re-initialization of the cache *)
+ DosSleep (5)
+ until InInitDefaultCP = -1
+ else
+ InitDefaultCP;
+ if CheckDefaultWinCP then
+ Exit;
+ end;
+ 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;
+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
+(* Do not free the UConv object from DefCpRec, because it is also stored in
+ the respective CpXList record! *)
+{
+ 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 OS2UpperUnicodeString (const S: UnicodeString): UnicodeString;
+var
+ I: cardinal;
+begin
+ SetLength (Result, Length (S));
+ for I := 0 to Pred (Length (S)) do
+ PWideChar (Result) [I] := Sys_UniToUpper (S [Succ (I)]);
+end;
+
+
+function OS2LowerUnicodeString (const S: UnicodeString): UnicodeString;
+var
+ I: cardinal;
+begin
+ SetLength (Result, Length (S));
+ for I := 0 to Pred (Length (S)) do
+ PWideChar (Result) [I] := Sys_UniToLower (S [Succ (I)]);
+end;
+
+
+function NoNullsUnicodeString (const S: UnicodeString): UnicodeString;
+var
+ I: cardinal;
+begin
+ Result := S;
+ UniqueString (Result);
+ for I := 1 to Length (S) do
+ if Result [I] = WNull then
+ Result [I] := ' ';
+end;
+
+
+function OS2CompareUnicodeString (const S1, S2: UnicodeString): PtrInt;
+var
+ HS1, HS2: UnicodeString;
+begin
+ { UniStrColl interprets null chars as end-of-string -> filter out }
+ HS1 := NoNullsUnicodeString (S1);
+ HS2 := NoNullsUnicodeString (S2);
+ Result := Sys_UniStrColl (DefLocObj, PWideChar (HS1), PWideChar (HS2));
+ if Result < -1 then
+ Result := -1
+ else if Result > 1 then
+ Result := 1;
+end;
+
+
+function OS2CompareTextUnicodeString (const S1, S2: UnicodeString): PtrInt;
+begin
+ Result := OS2CompareUnicodeString (OS2UpperUnicodeString (S1),
+ OS2UpperUnicodeString (S2));
+{$WARNING Language independent uppercase routine may not be appropriate for language dependent case insensitive comparison!}
+end;
+
+
+function OS2UpperAnsiString (const S: AnsiString): AnsiString;
+var
+ RC: cardinal;
+begin
+ Result := S;
+ UniqueString (Result);
+ FillChar (EmptyCC, SizeOf (EmptyCC), 0);
+ RC := DosMapCase (Length (Result), EmptyCC, PChar (Result));
+{ What to do in case of a failure??? }
+ if RC <> 0 then
+ Result := UpCase (S); { Use a fallback? }
+end;
+
+
+function OS2LowerAnsiString (const S: AnsiString): AnsiString;
+var
+ I: PtrUInt;
+
+ function IsDBCSLeadChar (C: char): boolean;
+ var
+ D: byte;
+ begin
+ IsDBCSLeadChar := false;
+ D := 0;
+ while D < DBCSLeadRangesEnd do
+ begin
+ if (C >= DBCSLeadRanges [D]) and (C <= DBCSLeadRanges [Succ (D)]) then
+ begin
+ IsDBCSLeadChar := true;
+ Exit;
+ end;
+ Inc (D, 2);
+ end;
+ end;
+
+begin
+(*
+ OS/2 provides no direct solution for lowercase conversion of MBCS strings.
+ If Unicode support is available, using Unicode routines is the best solution.
+ If not, we use a translation table built at startup by translating the full
+ character set to uppercase and using that for creation of a lookup table
+ (as already done in sysutils). However, we need to check for DBCS (MBCS)
+ codepages and avoid translating the DBCS lead bytes and the following
+ character.
+*)
+ if UniAPI then
+ Result := OS2LowerUnicodeString (S)
+{ Two implicit conversions... ;-) }
+ else
+ begin
+ Result := S;
+ if Length (Result) > 0 then
+ begin
+ UniqueString (Result);
+ if DBCSLeadRangesEnd > 0 then
+ begin
+ I := 1;
+ while I <= Length (Result) do
+ begin
+ if IsDBCSLeadChar (Result [I]) then
+ Inc (I, 2)
+ else
+ begin
+ Result [I] := LowerChars [Result [I]];
+ Inc (I);
+ end;
+ end;
+ end
+ else
+ for I := 1 to Length (Result) do
+ Result [I] := LowerChars [Result [I]];
+ end;
+ end;
+end;
+
+
+function OS2CompareStrAnsiString (const S1, S2: AnsiString): PtrInt;
+var
+ I, MaxLen: PtrUInt;
+begin
+ if UniAPI then
+ Result := OS2CompareUnicodeString (S1, S2) (* implicit conversions *)
+ else
+(* Older OS/2 versions without Unicode support do not provide direct means *)
+(* for case sensitive and codepage and language-aware string comparison. *)
+(* We have to resort to manual comparison of the original strings together *)
+(* with strings translated using the case insensitive collation sequence. *)
+ begin
+ if Length (S1) = 0 then
+ begin
+ if Length (S2) = 0 then
+ Result := 0
+ else
+ Result := -1;
+ Exit;
+ end
+ else
+ if Length (S2) = 0 then
+ begin
+ Result := 1;
+ Exit;
+ end;
+ I := 1;
+ MaxLen := Length (S1);
+ if Length (S2) < MaxLen then
+ MaxLen := Length (S2);
+ repeat
+ if CollationSequence [S1 [I]] = CollationSequence [S2 [I]] then
+ begin
+ if S1 [I] < S2 [I] then
+ begin
+ Result := -1;
+ Exit;
+ end
+ else if S1 [I] > S2 [I] then
+ begin
+ Result := 1;
+ Exit;
+ end;
+ end
+ else
+ begin
+ if CollationSequence [S1 [I]] < CollationSequence [S2 [I]] then
+ Result := -1
+ else
+ Result := 1;
+ Exit;
+ end;
+ Inc (I);
+ until (I > MaxLen);
+ if Length (S2) > MaxLen then
+ Result := -1
+ else if Length (S1) > MaxLen then
+ Result := 1
+ else
+ Result := 0;
+ end;
+end;
+
+
+function OS2StrCompAnsiString (S1, S2: PChar): PtrInt;
+var
+ HSA1, HSA2: AnsiString;
+ HSU1, HSU2: UnicodeString;
+begin
+(* Do not call OS2CompareUnicodeString to skip scanning for #0. *)
+ HSA1 := AnsiString (S1);
+ HSA2 := AnsiString (S2);
+ if UniApi then
+ begin
+ HSU1 := HSA1; (* implicit conversion *)
+ HSU2 := HSA2; (* implicit conversion *)
+ Result := Sys_UniStrColl (DefLocObj, PWideChar (HSU1), PWideChar (HSU2));
+ if Result < -1 then
+ Result := -1
+ else if Result > 1 then
+ Result := 1;
+ end
+ else
+ Result := OS2CompareStrAnsiString (HSA1, HSA2);
+end;
+
+
+function OS2CompareTextAnsiString (const S1, S2: AnsiString): PtrInt;
+var
+ HSA1, HSA2: AnsiString;
+ I: PtrUInt;
+begin
+ if UniAPI then
+ Result := OS2CompareTextUnicodeString (S1, S2) (* implicit conversions *)
+ else
+ begin
+(* Let's use collation strings here as a fallback *)
+ SetLength (HSA1, Length (S1));
+ if Length (HSA1) > 0 then
+(* Using assembler would be much faster, but never mind... *)
+ for I := 1 to Length (HSA1) do
+ HSA1 [I] := CollationSequence [S1 [I]];
+{$WARNING Results of using collation sequence with DBCS not known/tested!}
+ SetLength (HSA2, Length (S2));
+ if Length (HSA2) > 0 then
+ for I := 1 to Length (HSA2) do
+ HSA2 [I] := CollationSequence [S2 [I]];
+ if HSA1 = HSA2 then
+ Result := 0
+ else if HSA1 < HSA2 then
+ Result := -1
+ else
+ Result := 1;
+ end;
+end;
+
+
+function OS2StrICompAnsiString (S1, S2: PChar): PtrInt;
+begin
+ Result := OS2CompareTextAnsiString (AnsiString (S1), AnsiString (S2));
+end;
+
+
+function OS2StrLCompAnsiString (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 := OS2CompareStrAnsiString (A, B);
+end;
+
+
+function OS2StrLICompAnsiString (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 := OS2CompareTextAnsiString (A, B);
+end;
+
+
+procedure FPC_RangeError; [external name 'FPC_RANGEERROR'];
+
+
+procedure Ansi2PChar (const S: AnsiString; const OrgP: PChar; out P: Pchar);
+var
+ NewLen: SizeUInt;
+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 OS2StrUpperAnsiString (Str: PChar): PChar;
+var
+ Temp: AnsiString;
+begin
+ Temp := OS2UpperAnsiString (Str);
+ Ansi2PChar (Temp, Str, Result);
+end;
+
+
+function OS2StrLowerAnsiString (Str: PChar): PChar;
+var
+ Temp: AnsiString;
+begin
+ Temp := OS2LowerAnsiString (Str);
+ Ansi2PChar (Temp, Str, Result);
+end;
+
+
+(*
+CWSTRING:
+{ return value: number of code points in the string. Whenever an invalid
+ code point is encountered, all characters part of this invalid code point
+ are considered to form one "character" and the next character is
+ considered to be the start of a new (possibly also invalid) code point }
+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(s,MB_CUR_MAX));
+{$else beos}
+ nextlen:=ptrint(mbrlen(s,MB_CUR_MAX,@mbstate));
+{$endif beos}
+ { skip invalid/incomplete sequences }
+ if (nextlen<0) then
+ nextlen:=1;
+ inc(result,1);
+ 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;
+*)
+
+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);
+
+ RC := DosLoadModule (@ErrName [0], SizeOf (ErrName),
+ @LibUniName [0], LibUniHandle);
+ if RC = 0 then
+ begin
+ RC := DosQueryProcAddr (LibUniHandle, OrdUniToLower, nil, P);
+ if RC = 0 then
+ begin
+ Sys_UniToLower := TUniToLower (P);
+ RC := DosQueryProcAddr (LibUniHandle, OrdUniToUpper, nil, P);
+ if RC = 0 then
+ begin
+ Sys_UniToUpper := TUniToUpper (P);
+ RC := DosQueryProcAddr (LibUniHandle, OrdUniStrColl, nil,
+ P);
+ if RC = 0 then
+ begin
+ Sys_UniStrColl := TUniStrColl (P);
+ RC := DosQueryProcAddr (LibUniHandle,
+ OrdUniCreateLocaleObject, nil, P);
+ if RC = 0 then
+ begin
+ Sys_UniCreateLocaleObject := TUniCreateLocaleObject
+ (P);
+ RC := DosQueryProcAddr (LibUniHandle,
+ OrdUniFreeLocaleObject, nil, P);
+ if RC = 0 then
+ begin
+ Sys_UniFreeLocaleObject := TUniFreeLocaleObject (P);
+
+ UniAPI := true;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ 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;
+ Sys_UniToLower := @DummyUniToLower;
+ Sys_UniToUpper := @DummyUniToUpper;
+ Sys_UniStrColl := @DummyUniStrColl;
+ Sys_UniCreateLocaleObject := @DummyUniCreateLocaleObject;
+ Sys_UniFreeLocaleObject := @DummyUniFreeLocaleObject;
+ InitDummyAnsiSupport;
+ end;
+
+ { Widestring }
+ WideStringManager.Wide2AnsiMoveProc := @OS2Unicode2AnsiMove;
+ WideStringManager.Ansi2WideMoveProc := @OS2Ansi2UnicodeMove;
+ WideStringManager.UpperWideStringProc := @OS2UpperUnicodeString;
+ WideStringManager.LowerWideStringProc := @OS2LowerUnicodeString;
+ WideStringManager.CompareWideStringProc := @OS2CompareUnicodeString;
+ WideStringManager.CompareTextWideStringProc := @OS2CompareTextUnicodeString;
+ { Unicode }
+ WideStringManager.Unicode2AnsiMoveProc := @OS2Unicode2AnsiMove;
+ WideStringManager.Ansi2UnicodeMoveProc := @OS2Ansi2UnicodeMove;
+ WideStringManager.UpperUnicodeStringProc := @OS2UpperUnicodeString;
+ WideStringManager.LowerUnicodeStringProc := @OS2LowerUnicodeString;
+ WideStringManager.CompareUnicodeStringProc := @OS2CompareUnicodeString;
+ WideStringManager.CompareTextUnicodeStringProc :=
+ @OS2CompareTextUnicodeString;
+ { Codepage }
+ WideStringManager.GetStandardCodePageProc := @OS2GetStandardCodePage;
+(*
+ CharLengthPCharProc:=@CharLengthPChar;
+ CodePointLengthProc:=@CodePointLength;
+*)
+ WideStringManager.UpperAnsiStringProc := @OS2UpperAnsiString;
+ WideStringManager.LowerAnsiStringProc := @OS2LowerAnsiString;
+ WideStringManager.CompareStrAnsiStringProc := @OS2CompareStrAnsiString;
+ WideStringManager.CompareTextAnsiStringProc := @OS2CompareTextAnsiString;
+ WideStringManager.StrCompAnsiStringProc := @OS2StrCompAnsiString;
+ WideStringManager.StrICompAnsiStringProc := @OS2StrICompAnsiString;
+ WideStringManager.StrLCompAnsiStringProc := @OS2StrLCompAnsiString;
+ WideStringManager.StrLICompAnsiStringProc := @OS2StrLICompAnsiString;
+ WideStringManager.StrLowerAnsiStringProc := @OS2StrLowerAnsiString;
+ WideStringManager.StrUpperAnsiStringProc := @OS2StrUpperAnsiString;
+end;