| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722 | {    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;  WUniv: array [0..4] of WideChar = 'UNIV'#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); (* US with ISO 8859-1 *)  (* 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 is 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;function DummyUniMapCtryToLocale (CountryCode: cardinal; LocaleName: PWideChar;                                             BufSize: longint): longint; cdecl;begin  if BufSize = 0 then   DummyUniMapCtryToLocale := Uls_Invalid  else   begin    LocaleName^ := #0;    DummyUniMapCtryToLocale := Uls_Unsupported;   end;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 := Cend;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;  WA: array [0..9] of WideChar; (* Even just 6 WideChars should be enough *)  CI: TCountryInfo;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));    DefLocObj := nil;   end;  if UniAPI then (* Do not bother with the locale object otherwise *)   begin    RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WNull, DefLocObj);    if RCI <> 0 then     begin      OSErrorWatch (cardinal (RCI));      DefLocObj := nil;(* The locale dependent routines like comparison require a valid locale *)(* setting, but the locale set using environment variable LANG is not *)(* recognized by OS/2 -> let's try to derive the locale from country *)      RC := DosQueryCtryInfo (SizeOf (CI), EmptyCC, CI, ReturnedSize);      if RC = 0 then       begin        RCI := Sys_UniMapCtryToLocale (CI.Country, @WA [0],                                            SizeOf (WA) div SizeOf (WideChar));        if RCI = 0 then         begin          RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WA [0],                                                                    DefLocObj);          if RCI <> 0 then           begin            OSErrorWatch (cardinal (RCI));            DefLocObj := nil;           end;         end        else         OSErrorWatch (cardinal (RCI));       end      else       OSErrorWatch (RC);      if DefLocObj = nil then(* Still no success -> let's use the "Universal" locale as a fallback. *)       begin        RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WUniv [0],                                                                    DefLocObj);        if RCI <> 0 then         begin          OSErrorWatch (cardinal (RCI));          DefLocObj := nil;         end;       end;     end;   end  else (* not UniAPI *)   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));        TempCpRec.UConvObj := nil;       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));  if Length (S) > 0 then   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));  if Length (S) > 0 then   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);  if Length (S) > 0 then   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);                          RC := DosQueryProcAddr (LibUniHandle,                                                OrdUniMapCtryToLocale, nil, P);                          if RC = 0 then                           begin                            Sys_UniMapCtryToLocale := TUniMapCtryToLocale (P);                            UniAPI := true;                           end;                         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;    Sys_UniMapCtryToLocale := @DummyUniMapCtryToLocale;    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;
 |