sysucode.inc 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2014-2015 by Tomas Hajny and other members
  4. of the Free Pascal development team.
  5. OS/2 UnicodeStrings support
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. (* The implementation is based on native Unicode support available under
  13. OS/2 Warp 4 and above; if running under OS/2 Warp 3 and UCONV.DLL
  14. library is not available, this implementation will resort to dummy
  15. routines. This still allows providing 3rd party implementation based
  16. e.g. on the ICONV library as an external unit.
  17. *)
  18. const
  19. MaxSpecialCPTranslation = 2;
  20. MaxNonEqualCPMapping = 35;
  21. MaxCPMapping = 76;
  22. CpxAll = 0;
  23. CpxSpecial = 1;
  24. CpxMappingOnly = 2;
  25. Uls_Success = 0;
  26. Uls_API_Error_Base = $20400;
  27. Uls_Other = $20401;
  28. Uls_IllegalSequence = $20402;
  29. Uls_MaxFilesPerProc = $20403;
  30. Uls_MaxFiles = $20404;
  31. Uls_NoOp = $20405;
  32. Uls_TooManyKbd = $20406;
  33. Uls_KbdNotFound = $20407;
  34. Uls_BadHandle = $204008;
  35. Uls_NoDead = $20409;
  36. Uls_NoScan = $2040A;
  37. Uls_InvalidScan = $2040B;
  38. Uls_NotImplemented = $2040C;
  39. Uls_NoMemory = $2040D;
  40. Uls_Invalid = $2040E;
  41. Uls_BadObject = $2040F;
  42. Uls_NoToken = $20410;
  43. Uls_NoMatch = $20411;
  44. Uls_BufferFull = $20412;
  45. Uls_Range = $20413;
  46. Uls_Unsupported = $20414;
  47. Uls_BadAttr = $20415;
  48. Uls_Version = $20416;
  49. UConvName: array [0..5] of char = 'UCONV'#0;
  50. OrdUniCreateUconvObject = 1;
  51. OrdUniUconvToUcs = 2;
  52. OrdUniUconvFromUcs = 3;
  53. OrdUniFreeUconvObject = 4;
  54. OrdUniQueryUconvObject = 7;
  55. OrdUniSetUconvObject = 8;
  56. OrdUniQueryUconvCp = 9;
  57. OrdUniMapCpToUcsCp = 10;
  58. OrdUniStrFromUcs = 11;
  59. OrdUniStrToUcs = 12;
  60. Ord_UniMalloc = 13;
  61. Ord_UniFree = 14;
  62. LibUniName: array [0..6] of char = 'LIBUNI'#0;
  63. OrdUniQueryXdigit = 1;
  64. OrdUniQuerySpace = 2;
  65. OrdUniQueryPrint = 3;
  66. OrdUniQueryGraph = 4;
  67. OrdUniQueryCntrl = 5;
  68. OrdUniQueryAlpha = 6;
  69. OrdUniFreeAttrObject = 7;
  70. OrdUniQueryCharAttr = 8;
  71. OrdUniQueryUpper = 9;
  72. OrdUniQueryPunct = 10;
  73. OrdUniQueryLower = 11;
  74. OrdUniQueryDigit = 12;
  75. OrdUniQueryBlank = 13;
  76. OrdUniQueryAlnum = 14;
  77. OrdUniScanForAttr = 15;
  78. OrdUniCreateAttrObject = 16;
  79. OrdUniCreateTransformObject = 17;
  80. OrdUniFreeTransformObject = 18;
  81. OrdUniQueryLocaleObject = 19;
  82. OrdUniCreateLocaleObject = 20;
  83. OrdUniFreeLocaleObject = 21;
  84. OrdUniFreeMem = 22;
  85. OrdUniFreeLocaleInfo = 28;
  86. OrdUniQueryLocaleInfo = 29;
  87. OrdUniQueryLocaleItem = 30;
  88. OrdUniStrcat = 31;
  89. OrdUniStrchr = 32;
  90. OrdUniStrcmp = 33;
  91. OrdUniStrcmpi = 34;
  92. OrdUniStrColl = 35;
  93. OrdUniStrcpy = 36;
  94. OrdUniStrcspn = 37;
  95. OrdUniStrfmon = 38;
  96. OrdUniStrftime = 39;
  97. OrdUniStrlen = 40;
  98. OrdUniStrncat = 41;
  99. OrdUniStrncmp = 42;
  100. OrdUniStrncmpi = 43;
  101. OrdUniStrncpy = 44;
  102. OrdUniStrpbrk = 45;
  103. OrdUniStrptime = 46;
  104. OrdUniStrrchr = 47;
  105. OrdUniStrspn = 48;
  106. OrdUniStrstr = 49;
  107. OrdUniStrtod = 50;
  108. OrdUniStrtol = 51;
  109. OrdUniStrtoul = 52;
  110. OrdUniStrxfrm = 53;
  111. OrdUniLocaleStrToToken = 54;
  112. OrdUniLocaleTokenToStr = 55;
  113. OrdUniTransformStr = 56;
  114. OrdUniTransLower = 57;
  115. OrdUniTransUpper = 58;
  116. OrdUniTolower = 59;
  117. OrdUniToupper = 60;
  118. OrdUniStrupr = 61;
  119. OrdUniStrlwr = 62;
  120. OrdUniStrtok = 63;
  121. OrdUniMapCtryToLocale = 67;
  122. OrdUniMakeKey = 70;
  123. OrdUniQueryChar = 71;
  124. OrdUniGetOverride = 72;
  125. OrdUniGetColval = 73;
  126. OrdUniQueryAttr = 74;
  127. OrdUniQueryStringType = 75;
  128. OrdUniQueryCharType = 76;
  129. OrdUniQueryNumericValue = 77;
  130. OrdUniQueryCharTypeTable = 78;
  131. OrdUniProcessUconv = 80;
  132. OrdLocale = 151;
  133. OrdUniMakeUserLocale = 152;
  134. OrdUniSetUserLocaleItem = 153;
  135. OrdUniDeleteUserLocale = 154;
  136. OrdUniCompleteUserLocale = 155;
  137. OrdUniQueryLocaleValue = 156;
  138. OrdUniQueryLocaleList = 157;
  139. OrdUniQueryLanguageName = 158;
  140. OrdUniQueryCountryName = 159;
  141. Uni_Token_Pointer = 1;
  142. Uni_MBS_String_Pointer = 2;
  143. Uni_UCS_String_Pointer = 3;
  144. Uni_System_Locales = 1;
  145. Uni_User_Locales = 2;
  146. WNull: WideChar = #0;
  147. type
  148. (* CP_UTF16 should be in exceptions too, because OS/2 supports only UCS2 *)
  149. (* rather than UTF-16 - ignored at least for now. *)
  150. (* ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE});
  151. SpecialWinCodepages = (CP_UTF8, CP_ASCII);*)
  152. TCpRec = record
  153. WinCP: TSystemCodepage;
  154. OS2CP: word;
  155. UConvObj: TUConvObject;
  156. end;
  157. TCpXList = array [1..MaxCPMapping] of TCpRec;
  158. TDummyUConvObject = record
  159. CP: cardinal;
  160. CPNameLen: byte;
  161. CPName: record end;
  162. end;
  163. PDummyUConvObject = ^TDummyUConvObject;
  164. const
  165. DefCpRec: TCpRec = (WinCP: 0; OS2CP: 0; UConvObj: nil);
  166. InInitDefaultCP: boolean = false;
  167. DefLocObj: TLocaleObject = nil;
  168. IBMPrefix: packed array [1..4] of WideChar = 'IBM-';
  169. CachedDefFSCodepage: TSystemCodepage = 0;
  170. threadvar
  171. (* Temporary allocations may be performed in parallel in different threads *)
  172. TempCpRec: TCpRec;
  173. function OS2GetStandardCodePage (const stdcp: TStandardCodePageEnum): TSystemCodePage;
  174. var
  175. RC, C, RetSize: cardinal;
  176. NoUConvObject: TUConvObject;
  177. begin
  178. RC := DosQueryCP (SizeOf (C), @C, RetSize);
  179. if (RC <> 0) and (RC <> 473) then
  180. begin
  181. OSErrorWatch (RC);
  182. C := 850;
  183. end
  184. else
  185. if RetSize < SizeOf (C) then
  186. C := 850;
  187. OS2GetStandardCodePage := OS2CpToRtlCp (C, cpxMappingOnly, NoUConvObject);
  188. end;
  189. function DummyUniCreateUConvObject (const CpName: PWideChar;
  190. var UConv_Object: TUConvObject): longint; cdecl;
  191. var
  192. P: pointer;
  193. PW, PCPN: PWideChar;
  194. S: string [20];
  195. C: cardinal;
  196. L: PtrInt;
  197. I: longint;
  198. A: array [0..7] of char;
  199. CPN2: UnicodeString;
  200. RC, RetSize: cardinal;
  201. begin
  202. UConv_Object := nil;
  203. if (CpName = nil) or (CpName^ = #0) then
  204. begin
  205. RC := DosQueryCP (SizeOf (C), @C, RetSize);
  206. if (RC <> 0) and (RC <> 473) then
  207. begin
  208. C := 850;
  209. OSErrorWatch (RC);
  210. end;
  211. Str (C, CPN2); (* Str should hopefully not use this function recurrently *)
  212. L := Length (CPN2);
  213. Insert (IBMPrefix, CPN2, 1);
  214. PCPN := @CPN2 [1];
  215. end
  216. else
  217. begin
  218. PCPN := CpName;
  219. for I := 0 to 7 do
  220. if I mod 2 = 0 then
  221. A [I] := UpCase (PChar (@PCPN [0]) [I])
  222. else
  223. A [I] := PChar (@PCPN [0]) [I];
  224. if PQWord (@A)^ <> PQWord (@IBMPrefix)^ then
  225. begin
  226. DummyUniCreateUConvObject := Uls_Invalid;
  227. Exit;
  228. end;
  229. L := 0;
  230. PW := PCPN + 4;
  231. while ((PW + L)^ <> #0) and (L <= SizeOf (S)) do
  232. begin
  233. S [Succ (L)] := char (Ord ((PW + L)^));
  234. Inc (L);
  235. end;
  236. if L > SizeOf (S) then
  237. begin
  238. DummyUniCreateUConvObject := Uls_Other;
  239. Exit;
  240. end;
  241. SetLength (S, L);
  242. Val (S, C, I);
  243. if I <> 0 then
  244. begin
  245. DummyUniCreateUConvObject := Uls_Invalid;
  246. Exit;
  247. end;
  248. end;
  249. Inc (L);
  250. GetMem (P, SizeOf (TDummyUConvObject) + (L + 4) * 2);
  251. if P = nil then
  252. DummyUniCreateUConvObject := Uls_NoMemory
  253. else
  254. begin
  255. DummyUniCreateUConvObject := Uls_Success;
  256. PDummyUConvObject (P)^.CP := C;
  257. PDummyUConvObject (P)^.CpNameLen := Pred (L) + 4;
  258. Move (PCPN [0], PDummyUConvObject (P)^.CpName, (L + 4) * 2);
  259. UConv_Object := TUConvObject (P);
  260. end;
  261. end;
  262. function DummyUniFreeUConvObject (UConv_Object: TUConvObject): longint; cdecl;
  263. begin
  264. if UConv_Object <> nil then
  265. FreeMem (UConv_Object, SizeOf (TDummyUConvObject) +
  266. Succ (PDummyUConvObject (UConv_Object)^.CpNameLen) * 2);
  267. DummyUniFreeUConvObject := Uls_Success;
  268. end;
  269. function DummyUniMapCpToUcsCp (const Codepage: cardinal;
  270. CodepageName: PWideChar; const N: cardinal): longint; cdecl;
  271. var
  272. S: UnicodeString;
  273. RC, CP, RetSize: cardinal;
  274. begin
  275. if Codepage = 0 then
  276. begin
  277. RC := DosQueryCP (SizeOf (CP), @CP, RetSize);
  278. if (RC <> 0) and (RC <> 473) then
  279. begin
  280. CP := 850;
  281. OSErrorWatch (RC);
  282. end;
  283. Str (CP, S);
  284. end
  285. else
  286. Str (Codepage, S);
  287. if (N <= Length (S) + 4) or (CodepageName = nil) then
  288. DummyUniMapCptoUcsCp := Uls_Invalid
  289. else
  290. begin
  291. Move (IBMPrefix, CodepageName^, SizeOf (IBMPrefix));
  292. Move (S [1], CodepageName [4], Length (S) * SizeOf (WideChar));
  293. CodepageName [Length (S) + 4] := #0;
  294. DummyUniMapCpToUcsCp := Uls_Success;
  295. end;
  296. end;
  297. function DummyUniUConvFromUcs (UConv_Object: TUConvObject;
  298. var UcsBuf: PWideChar; var UniCharsLeft: longint; var OutBuf: PChar;
  299. var OutBytesLeft: longint; var NonIdentical: longint): longint; cdecl;
  300. var
  301. Dest, Dest2: RawByteString;
  302. NoUConvObj: TUConvObject;
  303. RtlCp: TSystemCodepage;
  304. UcsLen: PtrInt;
  305. begin
  306. if UConv_Object = nil then
  307. RtlCp := OS2GetStandardCodePage (scpAnsi)
  308. else
  309. RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
  310. NoUConvObj);
  311. DefaultUnicode2AnsiMove (UcsBuf, Dest, RtlCp, UniCharsLeft);
  312. NonIdentical := 1; { Assume at least one substitution with dummy implementation }
  313. if Length (Dest) > OutBytesLeft then
  314. begin
  315. UcsLen := 1;
  316. repeat
  317. DefaultUnicode2AnsiMove (UcsBuf, Dest2, RtlCp, UcsLen);
  318. if Length (Dest2) <= OutBytesLeft then
  319. begin
  320. Dest := Dest2;
  321. end;
  322. Inc (UcsLen);
  323. until Length (Dest2) > OutBytesLeft;
  324. Dec (UcsLen);
  325. Inc (UcsBuf, UcsLen);
  326. Dec (UniCharsLeft, UcsLen);
  327. DummyUniUConvFromUcs := Uls_BufferFull;
  328. end
  329. else
  330. begin
  331. Inc (UcsBuf, UniCharsLeft);
  332. UniCharsLeft := 0;
  333. DummyUniUConvFromUcs := Uls_Success;
  334. end;
  335. Move (Dest [1], OutBuf^, Length (Dest));
  336. Inc (OutBuf, Length (Dest));
  337. Dec (OutBytesLeft, Length (Dest));
  338. end;
  339. function DummyUniUConvToUcs (UConv_Object: TUConvObject; var InBuf: PChar;
  340. var InBytesLeft: longint; var UcsBuf: PWideChar; var UniCharsLeft: longint;
  341. var NonIdentical: longint): longint; cdecl;
  342. var
  343. Dest, Dest2: UnicodeString;
  344. NoUConvObj: TUConvObject;
  345. RtlCp: TSystemCodepage;
  346. SrcLen: PtrInt;
  347. begin
  348. if UConv_Object = nil then
  349. RtlCp := OS2GetStandardCodePage (scpAnsi)
  350. else
  351. RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
  352. NoUConvObj);
  353. DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest, InBytesLeft);
  354. NonIdentical := 0; { Assume no need for substitutions in this direction }
  355. if Length (Dest) > UniCharsLeft then
  356. begin
  357. SrcLen := 1;
  358. repeat
  359. DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest2, SrcLen);
  360. if Length (Dest2) <= UniCharsLeft then
  361. begin
  362. Dest := Dest2;
  363. end;
  364. Inc (SrcLen);
  365. until Length (Dest2) > UniCharsLeft;
  366. Dec (SrcLen);
  367. Inc (InBuf, SrcLen);
  368. Dec (InBytesLeft, SrcLen);
  369. DummyUniUConvToUcs := Uls_BufferFull; { According to IBM documentation Uls_Invalid and not Uls_BufferFull as returned by UniUConvFromUcs?! }
  370. end
  371. else
  372. begin
  373. Inc (InBuf, InBytesLeft); { Shall it be increased in case of success too??? }
  374. InBytesLeft := 0;
  375. DummyUniUConvToUcs := Uls_Success;
  376. end;
  377. Move (Dest [1], UcsBuf^, Length (Dest) * 2);
  378. Inc (UcsBuf, Length (Dest)); { Shall it be increased in case of success too??? }
  379. Dec (UniCharsLeft, Length (Dest));
  380. end;
  381. function DummyUniToLower (UniCharIn: WideChar): WideChar; cdecl;
  382. begin
  383. DummyUniToLower := UniCharIn;
  384. end;
  385. function DummyUniToUpper (UniCharIn: WideChar): WideChar; cdecl;
  386. begin
  387. DummyUniToUpper := UniCharIn;
  388. end;
  389. function DummyUniStrColl (Locale_Object: TLocaleObject;
  390. const UCS1, UCS2: PWideChar): longint; cdecl;
  391. var
  392. S1, S2: ansistring;
  393. begin
  394. S1 := UCS1;
  395. S2 := UCS2;
  396. if S1 = S2 then
  397. DummyUniStrColl := 0
  398. else if S1 < S2 then
  399. DummyUniStrColl := -1
  400. else
  401. DummyUniStrColl := 1;
  402. end;
  403. function DummyUniCreateLocaleObject (LocaleSpecType: longint;
  404. const LocaleSpec: pointer; var Locale_Object: TLocaleObject): longint; cdecl;
  405. begin
  406. DummyUniCreateLocaleObject := ULS_Unsupported;
  407. end;
  408. function DummyUniFreeLocaleObject (Locale_Object: TLocaleObject): longint;
  409. cdecl;
  410. begin
  411. DummyUniFreeLocaleObject := ULS_BadObject;
  412. end;
  413. const
  414. CpXList: TCpXList = (
  415. (WinCP: CP_UTF8; OS2CP: 1208; UConvObj: nil),
  416. (WinCP: CP_ASCII; OS2CP: 367; UConvObj: nil),
  417. (WinCP: 28597; OS2CP: 813; UConvObj: nil),
  418. (WinCP: 28591; OS2CP: 819; UConvObj: nil),
  419. (WinCP: 28592; OS2CP: 912; UConvObj: nil),
  420. (WinCP: 28593; OS2CP: 913; UConvObj: nil),
  421. (WinCP: 28594; OS2CP: 914; UConvObj: nil),
  422. (WinCP: 28595; OS2CP: 915; UConvObj: nil),
  423. (WinCP: 28598; OS2CP: 916; UConvObj: nil),
  424. (WinCP: 28599; OS2CP: 920; UConvObj: nil),
  425. (WinCP: 28603; OS2CP: 921; UConvObj: nil),
  426. (WinCP: 28605; OS2CP: 923; UConvObj: nil),
  427. (WinCP: 10000; OS2CP: 1275; UConvObj: nil),
  428. (WinCP: 10006; OS2CP: 1280; UConvObj: nil),
  429. (WinCP: 10081; OS2CP: 1281; UConvObj: nil),
  430. (WinCP: 10029; OS2CP: 1282; UConvObj: nil),
  431. (WinCP: 10007; OS2CP: 1283; UConvObj: nil),
  432. (WinCP: 20273; OS2CP: 273; UConvObj: nil),
  433. (WinCP: 20277; OS2CP: 277; UConvObj: nil),
  434. (WinCP: 20278; OS2CP: 278; UConvObj: nil),
  435. (WinCP: 20280; OS2CP: 280; UConvObj: nil),
  436. (WinCP: 20284; OS2CP: 284; UConvObj: nil),
  437. (WinCP: 20285; OS2CP: 285; UConvObj: nil),
  438. (WinCP: 20290; OS2CP: 290; UConvObj: nil),
  439. (WinCP: 20297; OS2CP: 297; UConvObj: nil),
  440. (WinCP: 20420; OS2CP: 420; UConvObj: nil),
  441. (WinCP: 20424; OS2CP: 424; UConvObj: nil),
  442. (WinCP: 20833; OS2CP: 833; UConvObj: nil),
  443. (WinCP: 20838; OS2CP: 838; UConvObj: nil),
  444. (WinCP: 20866; OS2CP: 878; UConvObj: nil),
  445. (WinCP: 737; OS2CP: 851; UConvObj: nil),
  446. (WinCP: 20924; OS2CP: 924; UConvObj: nil),
  447. (WinCP: 20932; OS2CP: 932; UConvObj: nil),
  448. (WinCP: 20936; OS2CP: 936; UConvObj: nil),
  449. (WinCP: 21025; OS2CP: 1025; UConvObj: nil),
  450. (WinCP: CP_UTF16; OS2CP: CP_UTF16; UConvObj: nil),
  451. (WinCP: 37; OS2CP: 37; UConvObj: nil),
  452. (WinCP: 437; OS2CP: 437; UConvObj: nil),
  453. (WinCP: 500; OS2CP: 500; UConvObj: nil),
  454. (WinCP: 850; OS2CP: 850; UConvObj: nil),
  455. (WinCP: 852; OS2CP: 852; UConvObj: nil),
  456. (WinCP: 855; OS2CP: 855; UConvObj: nil),
  457. (WinCP: 857; OS2CP: 857; UConvObj: nil),
  458. (WinCP: 860; OS2CP: 860; UConvObj: nil),
  459. (WinCP: 861; OS2CP: 861; UConvObj: nil),
  460. (WinCP: 862; OS2CP: 862; UConvObj: nil),
  461. (WinCP: 863; OS2CP: 863; UConvObj: nil),
  462. (WinCP: 864; OS2CP: 864; UConvObj: nil),
  463. (WinCP: 865; OS2CP: 865; UConvObj: nil),
  464. (WinCP: 866; OS2CP: 866; UConvObj: nil),
  465. (WinCP: 869; OS2CP: 869; UConvObj: nil),
  466. (WinCP: 870; OS2CP: 870; UConvObj: nil),
  467. (WinCP: 874; OS2CP: 874; UConvObj: nil),
  468. (WinCP: 875; OS2CP: 875; UConvObj: nil),
  469. (WinCP: 949; OS2CP: 949; UConvObj: nil),
  470. (WinCP: 950; OS2CP: 950; UConvObj: nil),
  471. (WinCP: 1026; OS2CP: 1026; UConvObj: nil),
  472. (WinCP: 1047; OS2CP: 1047; UConvObj: nil),
  473. (WinCP: 1140; OS2CP: 1140; UConvObj: nil),
  474. (WinCP: 1141; OS2CP: 1141; UConvObj: nil),
  475. (WinCP: 1142; OS2CP: 1142; UConvObj: nil),
  476. (WinCP: 1143; OS2CP: 1143; UConvObj: nil),
  477. (WinCP: 1144; OS2CP: 1144; UConvObj: nil),
  478. (WinCP: 1145; OS2CP: 1145; UConvObj: nil),
  479. (WinCP: 1146; OS2CP: 1146; UConvObj: nil),
  480. (WinCP: 1147; OS2CP: 1147; UConvObj: nil),
  481. (WinCP: 1148; OS2CP: 1148; UConvObj: nil),
  482. (WinCP: 1149; OS2CP: 1149; UConvObj: nil),
  483. (WinCP: 1250; OS2CP: 1250; UConvObj: nil),
  484. (WinCP: 1251; OS2CP: 1251; UConvObj: nil),
  485. (WinCP: 1252; OS2CP: 1252; UConvObj: nil),
  486. (WinCP: 1253; OS2CP: 1253; UConvObj: nil),
  487. (WinCP: 1254; OS2CP: 1254; UConvObj: nil),
  488. (WinCP: 1255; OS2CP: 1255; UConvObj: nil),
  489. (WinCP: 1256; OS2CP: 1256; UConvObj: nil),
  490. (WinCP: 1257; OS2CP: 1257; UConvObj: nil)
  491. );
  492. (* Possibly add index tables for both directions and binary search??? *)
  493. {
  494. function GetRtlCpFromCpRec (const CpRec: TCpRec): TSystemCodepage; inline;
  495. begin
  496. if RtlUsesWinCp then
  497. GetRtlCp := CpRec.WinCP
  498. else
  499. GetRtlCp := TSystemCodepage (CpRec.Os2Cp);
  500. end;
  501. }
  502. function UConvObjectForCP (CP: cardinal; var UConvObj: TUConvObject): longint;
  503. var
  504. RC: longint;
  505. A: array [0..12] of WideChar;
  506. begin
  507. UConvObj := nil;
  508. RC := Sys_UniMapCpToUcsCp (CP, @A, 12);
  509. if RC = 0 then
  510. RC := Sys_UniCreateUconvObject (@A, UConvObj);
  511. {$WARNING: TODO: Deallocate some previously allocated UConvObj and try again if failed}
  512. UConvObjectForCP := RC;
  513. if RC <> 0 then
  514. OSErrorWatch (RC);
  515. end;
  516. procedure InitDefaultCP;
  517. var
  518. OS2CP, I: cardinal;
  519. NoUConvObj: TUConvObject;
  520. RCI: longint;
  521. RC: cardinal;
  522. CPArr: TCPArray;
  523. ReturnedSize: cardinal;
  524. begin
  525. InInitDefaultCP := true;
  526. if DefCpRec.UConvObj <> nil then
  527. begin
  528. (* Do not free the UConv object from DefCpRec, because it is also stored in
  529. the respective CPXList record! *)
  530. {
  531. RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
  532. if RCI <> 0 then
  533. OSErrorWatch (cardinal (RCI));
  534. }
  535. DefCpRec.UConvObj := nil;
  536. end;
  537. RC := DosQueryCP (SizeOf (CPArr), @CPArr, ReturnedSize);
  538. if (RC <> 0) and (RC <> 473) then
  539. begin
  540. OSErrorWatch (RC);
  541. CPArr [0] := 850;
  542. end
  543. else if (ReturnedSize < 4) then
  544. CPArr [0] := 850;
  545. DefaultFileSystemCodePage := OS2CPtoRtlCP (CPArr [0], cpxAll,
  546. DefCpRec.UConvObj);
  547. CachedDefFSCodepage := DefaultFileSystemCodePage;
  548. DefCpRec.OS2CP := CPArr [0];
  549. (* Find out WinCP _without_ considering RtlUsesWinCP *)
  550. I := 1;
  551. while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> OS2CP) do
  552. Inc (I);
  553. if CpXList [I].OS2CP = CPArr [0] then
  554. DefCpRec.WinCP := CpXList [I].WinCP
  555. else
  556. DefCpRec.WinCP := CPArr [0];
  557. if DefLocObj <> nil then
  558. begin
  559. RCI := Sys_UniFreeLocaleObject (DefLocObj);
  560. if RCI <> 0 then
  561. OSErrorWatch (cardinal (RCI));
  562. end;
  563. RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WNull, DefLocObj);
  564. if RCI <> 0 then
  565. OSErrorWatch (cardinal (RCI));
  566. InInitDefaultCP := false;
  567. end;
  568. function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte;
  569. var UConvObj: TUConvObject): TSystemCodepage;
  570. var
  571. I, I2: cardinal;
  572. RCI: longint;
  573. function CheckDefaultOS2CP: boolean;
  574. begin
  575. if CP = DefCpRec.OS2CP then
  576. begin
  577. CheckDefaultOS2CP := true;
  578. if RTLUsesWinCP then
  579. OS2CPtoRtlCP := DefCpRec.WinCP;
  580. if ReqFlags and CpxMappingOnly = 0 then
  581. UConvObj := DefCpRec.UConvObj;
  582. end
  583. else
  584. CheckDefaultOS2CP := false;
  585. end;
  586. begin
  587. OS2CPtoRtlCP := TSystemCodePage (CP);
  588. UConvObj := nil;
  589. if not UniAPI then (* No UniAPI => no need for UConvObj *)
  590. ReqFlags := ReqFlags or CpxMappingOnly;
  591. if CheckDefaultOS2CP then
  592. Exit;
  593. if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
  594. not (InInitDefaultCP) then
  595. begin
  596. InitDefaultCP;
  597. if CheckDefaultOS2CP then
  598. Exit;
  599. end;
  600. I := 1;
  601. if ReqFlags and CpxSpecial = CpxSpecial then
  602. I2 := 2
  603. else
  604. if ReqFlags and CpxMappingOnly = CpxMappingOnly then
  605. I2 := MaxNonEqualCPMapping
  606. else
  607. I2 := MaxCPMapping;
  608. while I <= I2 do
  609. begin
  610. if CP = CpXList [I].OS2CP then
  611. begin
  612. if RTLUsesWinCP then
  613. OS2CPtoRtlCP := CpXList [I].WinCP;
  614. if ReqFlags and CpxMappingOnly = 0 then
  615. begin
  616. if CpXList [I].UConvObj = nil then
  617. begin
  618. if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success then
  619. CpXList [I].UConvObj := UConvObj
  620. else
  621. UConvObj := nil;
  622. end
  623. else
  624. UConvObj := CpXList [I].UConvObj;
  625. end;
  626. Exit;
  627. end;
  628. Inc (I);
  629. end;
  630. (* If codepage was not found in the translation table and UConvObj is
  631. requested, allocate one in the temporary record. *)
  632. if ReqFlags and CpxMappingOnly = 0 then
  633. begin
  634. if TempCpRec.OS2CP = CP then
  635. UConvObj := TempCpRec.UConvObj
  636. else
  637. begin
  638. if TempCpRec.UConvObj <> nil then
  639. begin
  640. RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
  641. if RCI <> 0 then
  642. OSErrorWatch (cardinal (RCI));
  643. end;
  644. if UConvObjectForCP (CP, UConvObj) = Uls_Success then
  645. begin
  646. TempCpRec.UConvObj := UConvObj;
  647. TempCpRec.OS2CP := CP;
  648. end
  649. else
  650. UConvObj := nil;
  651. end;
  652. end;
  653. end;
  654. function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte;
  655. var UConvObj: TUConvObject): cardinal;
  656. var
  657. I, I2: cardinal;
  658. function CheckDefaultWinCP: boolean;
  659. begin
  660. if RtlCP = DefCpRec.WinCP then
  661. begin
  662. CheckDefaultWinCP := true;
  663. RtlCPtoOS2CP := DefCpRec.WinCP;
  664. if ReqFlags and CpxMappingOnly = 0 then
  665. UConvObj := DefCpRec.UConvObj;
  666. end
  667. else
  668. CheckDefaultWinCP := false;
  669. end;
  670. begin
  671. RtlCPtoOS2CP := RtlCP;
  672. UConvObj := nil;
  673. if not UniAPI then (* No UniAPI => no need for UConvObj *)
  674. ReqFlags := ReqFlags or CpxMappingOnly;
  675. if not (RTLUsesWinCP) then
  676. begin
  677. if ReqFlags and CpxMappingOnly = 0 then
  678. OS2CPtoRtlCP (cardinal (RtlCp), ReqFlags, UConvObj);
  679. end
  680. else if CheckDefaultWinCp then
  681. Exit
  682. else
  683. begin
  684. if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
  685. not (InInitDefaultCP) then
  686. begin
  687. InitDefaultCP;
  688. if CheckDefaultWinCP then
  689. Exit;
  690. end;
  691. I := 1;
  692. if ReqFlags and CpxSpecial = CpxSpecial then
  693. I2 := 2
  694. else
  695. if ReqFlags and CpxMappingOnly = CpxMappingOnly then
  696. I2 := MaxNonEqualCPMapping
  697. else
  698. I2 := MaxCPMapping;
  699. while I <= I2 do
  700. begin
  701. if RtlCP = CpXList [I].WinCP then
  702. begin
  703. RtlCPtoOS2CP := CpXList [I].OS2CP;
  704. if ReqFlags and CpxMappingOnly = 0 then
  705. begin
  706. begin
  707. if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success then
  708. CpXList [I].UConvObj := UConvObj
  709. else
  710. UConvObj := nil;
  711. end
  712. end;
  713. Exit;
  714. end;
  715. Inc (I);
  716. end;
  717. (*
  718. Special processing for
  719. ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE})
  720. might be added here...or not ;-)
  721. if (TempCpRec.OS2CP <> High (TempCpRec.OS2CP)) or
  722. (TempCpRec.WinCP <> RtlCp) then
  723. begin
  724. if TempCpRec.UConvObj <> nil then
  725. begin
  726. RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
  727. if RCI <> 0 then
  728. OSErrorWatch (cardinal (RCI));
  729. end;
  730. TempCpRec.OS2CP := High (TempCpRec.OS2CP);
  731. TempCpRec.WinCP := RtlCp;
  732. end;
  733. Map to CP_ASCII aka OS2CP=367 if RtlCP not recognized and UConvObject
  734. is requested???
  735. *)
  736. (* Signalize unrecognized (untranslatable) MS Windows codepage *)
  737. OSErrorWatch (Uls_Invalid);
  738. end;
  739. end;
  740. function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte): TSystemCodepage;
  741. var
  742. NoUConvObj: TUConvObject;
  743. begin
  744. if RtlUsesWinCP then
  745. OS2CPtoRtlCP := OS2CPtoRtlCP (CP, ReqFlags or CpxMappingOnly, NoUConvObj)
  746. else
  747. OS2CPtoRtlCP := TSystemCodepage (CP);
  748. end;
  749. function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte): cardinal;
  750. var
  751. NoUConvObj: TUConvObject;
  752. begin
  753. if RtlUsesWinCP then
  754. RtlCPtoOS2CP := RtlCPtoOS2CP (RtlCP, ReqFlags or CpxMappingOnly, NoUConvObj)
  755. else
  756. RtlCPtoOS2CP := RtlCP;
  757. end;
  758. procedure OS2Unicode2AnsiMove (Source: PUnicodeChar; var Dest: RawByteString;
  759. CP: TSystemCodePage; Len: SizeInt);
  760. var
  761. RCI: longint;
  762. UConvObj: TUConvObject;
  763. OS2CP: cardinal;
  764. Src2: PUnicodeChar;
  765. Len2, LenOut, OutOffset, NonIdentical: longint;
  766. Dest2: PChar;
  767. begin
  768. OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
  769. { if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
  770. if UConvObj = nil then
  771. begin
  772. {$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
  773. DefaultUnicode2AnsiMove (Source, Dest, CP, Len);
  774. Exit;
  775. end;
  776. LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
  777. SetLength (Dest, LenOut);
  778. SetCodePage (Dest, CP, false);
  779. Src2 := Source;
  780. Len2 := Len;
  781. Dest2 := PChar (Dest);
  782. RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
  783. NonIdentical);
  784. repeat
  785. case RCI of
  786. Uls_Success:
  787. begin
  788. if LenOut > 0 then
  789. SetLength (Dest, Length (Dest) - LenOut);
  790. Break;
  791. end;
  792. Uls_IllegalSequence:
  793. begin
  794. OSErrorWatch (Uls_IllegalSequence);
  795. { skip and set to '?' }
  796. Inc (Src2);
  797. Dec (Len2);
  798. Dest2^ := '?';
  799. Inc (Dest2);
  800. Dec (LenOut);
  801. end;
  802. Uls_BufferFull:
  803. begin
  804. OutOffset := Dest2 - PChar (Dest);
  805. (* Use Len2 or Len decreased by difference between Source and Src2? *)
  806. (* Extend more this time - target is probably a DBCS or UTF-8 *)
  807. SetLength (Dest, Length (Dest) + Succ (Len2 * 2));
  808. { string could have been moved }
  809. Dest2 := PChar (Dest) + OutOffset;
  810. Inc (LenOut, Succ (Len2 * 2));
  811. end
  812. else
  813. begin
  814. SetLength (Dest, 0);
  815. OSErrorWatch (cardinal (RCI));
  816. { Break }
  817. RunError (231);
  818. end;
  819. end;
  820. RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
  821. NonIdentical);
  822. until false;
  823. end;
  824. procedure OS2Ansi2UnicodeMove (Source: PChar; CP: TSystemCodePage;
  825. var Dest: UnicodeString; Len: SizeInt);
  826. var
  827. RCI: longint;
  828. UConvObj: TUConvObject;
  829. OS2CP: cardinal;
  830. Src2: PChar;
  831. Len2, LenOut, OutOffset, NonIdentical: longint;
  832. Dest2: PWideChar;
  833. begin
  834. OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
  835. { if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
  836. if UConvObj = nil then
  837. begin
  838. {$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
  839. DefaultAnsi2UnicodeMove (Source, CP, Dest, Len);
  840. Exit;
  841. end;
  842. LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
  843. SetLength (Dest, LenOut);
  844. Src2 := Source;
  845. Len2 := Len;
  846. Dest2 := PWideChar (Dest);
  847. RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut, NonIdentical);
  848. repeat
  849. case RCI of
  850. Uls_Success:
  851. begin
  852. if LenOut > 0 then
  853. SetLength (Dest, Length (Dest) - LenOut);
  854. Break;
  855. end;
  856. Uls_IllegalSequence:
  857. begin
  858. OSErrorWatch (Uls_IllegalSequence);
  859. { skip and set to '?' }
  860. Inc (Src2);
  861. Dec (Len2);
  862. Dest2^ := '?';
  863. Inc (Dest2);
  864. Dec (LenOut);
  865. end;
  866. Uls_BufferFull:
  867. begin
  868. OutOffset := Dest2 - PWideChar (Dest);
  869. (* Use Len2 or Len decreased by difference between Source and Src2? *)
  870. SetLength (Dest, Length (Dest) + Succ (Len2));
  871. { string could have been moved }
  872. Dest2 := PWideChar (Dest) + OutOffset;
  873. Inc (LenOut, Succ (Len2));
  874. end
  875. else
  876. begin
  877. SetLength (Dest, 0);
  878. OSErrorWatch (cardinal (RCI));
  879. { Break }
  880. RunError (231);
  881. end;
  882. end;
  883. RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut,
  884. NonIdentical);
  885. until false;
  886. end;
  887. function RtlChangeCP (CP: TSystemCodePage): longint;
  888. var
  889. OS2CP, I: cardinal;
  890. NoUConvObj: TUConvObject;
  891. RCI: longint;
  892. begin
  893. OS2CP := RtlCpToOS2Cp (CP, cpxMappingOnly, NoUConvObj);
  894. RtlChangeCP := longint (DosSetProcessCP (OS2CP));
  895. if RtlChangeCP <> 0 then
  896. OSErrorWatch (RtlChangeCP)
  897. else
  898. begin
  899. DefaultSystemCodePage := CP;
  900. DefaultRTLFileSystemCodePage := DefaultSystemCodePage;
  901. DefaultFileSystemCodePage := DefaultSystemCodePage;
  902. if OS2CP <> DefCpRec.OS2CP then
  903. begin
  904. if DefCpRec.UConvObj <> nil then
  905. begin
  906. (* Do not free the UConv object from DefCpRec, because it is also stored in
  907. the respective CpXList record! *)
  908. {
  909. RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
  910. if RCI <> 0 then
  911. OSErrorWatch (cardinal (RCI));
  912. }
  913. DefCpRec.UConvObj := nil;
  914. end;
  915. DefCPRec.OS2CP := OS2CP;
  916. RCI := Sys_UniCreateUConvObject (@WNull, DefCpRec.UConvObj);
  917. if RCI <> 0 then
  918. OSErrorWatch (cardinal (RCI));
  919. (* Find out WinCP _without_ considering RtlUsesWinCP *)
  920. I := 1;
  921. while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> OS2CP) do
  922. Inc (I);
  923. if CpXList [I].OS2CP = OS2CP then
  924. DefCpRec.WinCP := CpXList [I].WinCP
  925. else
  926. DefCpRec.WinCP := OS2CP;
  927. end;
  928. end;
  929. end;
  930. function OS2UpperUnicodeString (const S: UnicodeString): UnicodeString;
  931. var
  932. I: cardinal;
  933. begin
  934. SetLength (Result, Length (S));
  935. for I := 0 to Pred (Length (S)) do
  936. PWideChar (Result) [I] := Sys_UniToUpper (S [Succ (I)]);
  937. end;
  938. function OS2LowerUnicodeString (const S: UnicodeString): UnicodeString;
  939. var
  940. I: cardinal;
  941. begin
  942. SetLength (Result, Length (S));
  943. for I := 0 to Pred (Length (S)) do
  944. PWideChar (Result) [I] := Sys_UniToLower (S [Succ (I)]);
  945. end;
  946. function NoNullsUnicodeString (const S: UnicodeString): UnicodeString;
  947. var
  948. I: cardinal;
  949. begin
  950. Result := S;
  951. UniqueString (Result);
  952. for I := 1 to Length (S) do
  953. if Result [I] = WNull then
  954. Result [I] := ' ';
  955. end;
  956. function OS2CompareUnicodeString (const S1, S2: UnicodeString): PtrInt;
  957. var
  958. HS1, HS2: UnicodeString;
  959. begin
  960. { UniStrColl interprets null chars as end-of-string -> filter out }
  961. HS1 := NoNullsUnicodeString (S1);
  962. HS2 := NoNullsUnicodeString (S2);
  963. Result := Sys_UniStrColl (DefLocObj, PWideChar (HS1), PWideChar (HS2));
  964. if Result < -1 then
  965. Result := -1
  966. else if Result > 1 then
  967. Result := 1;
  968. end;
  969. function OS2CompareTextUnicodeString (const S1, S2: UnicodeString): PtrInt;
  970. begin
  971. Result := OS2CompareUnicodeString (OS2UpperUnicodeString (S1),
  972. OS2UpperUnicodeString (S2));
  973. {$WARNING Language independent uppercase routine may not be appropriate for language dependent case insensitive comparison!}
  974. end;
  975. function OS2UpperAnsiString (const S: AnsiString): AnsiString;
  976. var
  977. CC: TCountryCode;
  978. RC: cardinal;
  979. begin
  980. Result := S;
  981. UniqueString (Result);
  982. FillChar (CC, SizeOf (CC), 0);
  983. RC := DosMapCase (Length (Result), CC, PChar (Result));
  984. { What to do in case of a failure??? }
  985. if RC <> 0 then
  986. Result := UpCase (S); { Use a fallback? }
  987. end;
  988. function OS2LowerAnsiString (const S: AnsiString): AnsiString;
  989. {
  990. var
  991. CC: TCountryCode;
  992. RC: cardinal;
  993. }
  994. begin
  995. (*
  996. OS/2 provides no direct solution for lowercase conversion of MBCS strings.
  997. If the current codepage is SBCS (which may be found using DosQueryDBCSEnv),
  998. simplified translation table may be built using translation of the full
  999. character set to uppercase and using that for creation of a lookup table
  1000. (as already done in sysutils). In theory, the same approach might be
  1001. possible for DBCS as well using lead byte ranges returned by DosQueryDBCSEnv,
  1002. but that would be very inefficient and thus the fallback solution via
  1003. conversion to Unicode and back is probably better anyway. For now, let's
  1004. stick just to the Unicode solution - with the disadvantage that it wouldn't
  1005. do much useful with old OS/2 versions.
  1006. RC := DosQueryDBCSEnv...
  1007. FillChar (CC, SizeOf (CC), 0);
  1008. RC := DosMapCase (Length (Result), CC, PChar (Result));
  1009. *)
  1010. Result := OS2LowerUnicodeString (S);
  1011. { Two implicit conversions... ;-) }
  1012. end;
  1013. {
  1014. CompareStrAnsiStringProc:=@CompareStrAnsiString;
  1015. CompareTextAnsiStringProc:=@AnsiCompareText;
  1016. StrCompAnsiStringProc:=@StrCompAnsi;
  1017. StrICompAnsiStringProc:=@AnsiStrIComp;
  1018. StrLCompAnsiStringProc:=@AnsiStrLComp;
  1019. StrLICompAnsiStringProc:=@AnsiStrLIComp;
  1020. StrLowerAnsiStringProc:=@AnsiStrLower;
  1021. StrUpperAnsiStringProc:=@AnsiStrUpper;
  1022. }
  1023. (*
  1024. CWSTRING:
  1025. procedure EnsureAnsiLen(var S: AnsiString; const len: SizeInt); inline;
  1026. begin
  1027. if (len>length(s)) then
  1028. if (length(s) < 10*256) then
  1029. setlength(s,length(s)+10)
  1030. else
  1031. setlength(s,length(s)+length(s) shr 8);
  1032. end;
  1033. procedure ConcatCharToAnsiStr(const c: char; var S: AnsiString; var index: SizeInt);
  1034. begin
  1035. EnsureAnsiLen(s,index);
  1036. pchar(@s[index])^:=c;
  1037. inc(index);
  1038. end;
  1039. { concatenates an utf-32 char to a widestring. S *must* be unique when entering. }
  1040. {$ifndef beos}
  1041. procedure ConcatUTF32ToAnsiStr(const nc: wint_t; var S: AnsiString; var index: SizeInt; var mbstate: mbstate_t);
  1042. {$else not beos}
  1043. procedure ConcatUTF32ToAnsiStr(const nc: wint_t; var S: AnsiString; var index: SizeInt);
  1044. {$endif beos}
  1045. var
  1046. p : pchar;
  1047. mblen : size_t;
  1048. begin
  1049. { we know that s is unique -> avoid uniquestring calls}
  1050. p:=@s[index];
  1051. if (nc<=127) then
  1052. ConcatCharToAnsiStr(char(nc),s,index)
  1053. else
  1054. begin
  1055. EnsureAnsiLen(s,index+MB_CUR_MAX);
  1056. {$ifndef beos}
  1057. mblen:=wcrtomb(p,wchar_t(nc),@mbstate);
  1058. {$else not beos}
  1059. mblen:=wctomb(p,wchar_t(nc));
  1060. {$endif not beos}
  1061. if (mblen<>size_t(-1)) then
  1062. inc(index,mblen)
  1063. else
  1064. begin
  1065. { invalid wide char }
  1066. p^:='?';
  1067. inc(index);
  1068. end;
  1069. end;
  1070. end;
  1071. function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; external name 'FPC_UTF16TOUTF32';
  1072. { return value: number of code points in the string. Whenever an invalid
  1073. code point is encountered, all characters part of this invalid code point
  1074. are considered to form one "character" and the next character is
  1075. considered to be the start of a new (possibly also invalid) code point }
  1076. function CharLengthPChar(const Str: PChar): PtrInt;
  1077. var
  1078. nextlen: ptrint;
  1079. s: pchar;
  1080. {$ifndef beos}
  1081. mbstate: mbstate_t;
  1082. {$endif not beos}
  1083. begin
  1084. result:=0;
  1085. s:=str;
  1086. {$ifndef beos}
  1087. fillchar(mbstate,sizeof(mbstate),0);
  1088. {$endif not beos}
  1089. repeat
  1090. {$ifdef beos}
  1091. nextlen:=ptrint(mblen(s,MB_CUR_MAX));
  1092. {$else beos}
  1093. nextlen:=ptrint(mbrlen(s,MB_CUR_MAX,@mbstate));
  1094. {$endif beos}
  1095. { skip invalid/incomplete sequences }
  1096. if (nextlen<0) then
  1097. nextlen:=1;
  1098. inc(result,1);
  1099. inc(s,nextlen);
  1100. until (nextlen=0);
  1101. end;
  1102. function CodePointLength(const Str: PChar; maxlookahead: ptrint): PtrInt;
  1103. var
  1104. nextlen: ptrint;
  1105. {$ifndef beos}
  1106. mbstate: mbstate_t;
  1107. {$endif not beos}
  1108. begin
  1109. {$ifdef beos}
  1110. result:=ptrint(mblen(str,maxlookahead));
  1111. {$else beos}
  1112. fillchar(mbstate,sizeof(mbstate),0);
  1113. result:=ptrint(mbrlen(str,maxlookahead,@mbstate));
  1114. { mbrlen can also return -2 for "incomplete but potially valid character
  1115. and data has been processed" }
  1116. if result<0 then
  1117. result:=-1;
  1118. {$endif beos}
  1119. end;
  1120. function StrCompAnsiIntern(s1,s2 : PChar; len1, len2: PtrInt; canmodifys1, canmodifys2: boolean): PtrInt;
  1121. var
  1122. a,b: pchar;
  1123. i: PtrInt;
  1124. begin
  1125. if not(canmodifys1) then
  1126. getmem(a,len1+1)
  1127. else
  1128. a:=s1;
  1129. for i:=0 to len1-1 do
  1130. if s1[i]<>#0 then
  1131. a[i]:=s1[i]
  1132. else
  1133. a[i]:=#32;
  1134. a[len1]:=#0;
  1135. if not(canmodifys2) then
  1136. getmem(b,len2+1)
  1137. else
  1138. b:=s2;
  1139. for i:=0 to len2-1 do
  1140. if s2[i]<>#0 then
  1141. b[i]:=s2[i]
  1142. else
  1143. b[i]:=#32;
  1144. b[len2]:=#0;
  1145. result:=strcoll(a,b);
  1146. if not(canmodifys1) then
  1147. freemem(a);
  1148. if not(canmodifys2) then
  1149. freemem(b);
  1150. end;
  1151. function CompareStrAnsiString(const s1, s2: ansistring): PtrInt;
  1152. begin
  1153. result:=StrCompAnsiIntern(pchar(s1),pchar(s2),length(s1),length(s2),false,false);
  1154. end;
  1155. function StrCompAnsi(s1,s2 : PChar): PtrInt;
  1156. begin
  1157. result:=strcoll(s1,s2);
  1158. end;
  1159. function AnsiCompareText(const S1, S2: ansistring): PtrInt;
  1160. var
  1161. a, b: AnsiString;
  1162. begin
  1163. a:=UpperAnsistring(s1);
  1164. b:=UpperAnsistring(s2);
  1165. result:=StrCompAnsiIntern(pchar(a),pchar(b),length(a),length(b),true,true);
  1166. end;
  1167. function AnsiStrIComp(S1, S2: PChar): PtrInt;
  1168. begin
  1169. result:=AnsiCompareText(ansistring(s1),ansistring(s2));
  1170. end;
  1171. function AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1172. var
  1173. a, b: pchar;
  1174. begin
  1175. if (maxlen=0) then
  1176. exit(0);
  1177. if (s1[maxlen]<>#0) then
  1178. begin
  1179. getmem(a,maxlen+1);
  1180. move(s1^,a^,maxlen);
  1181. a[maxlen]:=#0;
  1182. end
  1183. else
  1184. a:=s1;
  1185. if (s2[maxlen]<>#0) then
  1186. begin
  1187. getmem(b,maxlen+1);
  1188. move(s2^,b^,maxlen);
  1189. b[maxlen]:=#0;
  1190. end
  1191. else
  1192. b:=s2;
  1193. result:=StrCompAnsiIntern(a,b,maxlen,maxlen,a<>s1,b<>s2);
  1194. if (a<>s1) then
  1195. freemem(a);
  1196. if (b<>s2) then
  1197. freemem(b);
  1198. end;
  1199. function AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  1200. var
  1201. a, b: ansistring;
  1202. begin
  1203. if (maxlen=0) then
  1204. exit(0);
  1205. setlength(a,maxlen);
  1206. move(s1^,a[1],maxlen);
  1207. setlength(b,maxlen);
  1208. move(s2^,b[1],maxlen);
  1209. result:=AnsiCompareText(a,b);
  1210. end;
  1211. procedure ansi2pchar(const s: ansistring; const orgp: pchar; out p: pchar);
  1212. var
  1213. newlen: sizeint;
  1214. begin
  1215. newlen:=length(s);
  1216. if newlen>strlen(orgp) then
  1217. fpc_rangeerror;
  1218. p:=orgp;
  1219. if (newlen>0) then
  1220. move(s[1],p[0],newlen);
  1221. p[newlen]:=#0;
  1222. end;
  1223. function AnsiStrLower(Str: PChar): PChar;
  1224. var
  1225. temp: ansistring;
  1226. begin
  1227. temp:=loweransistring(str);
  1228. ansi2pchar(temp,str,result);
  1229. end;
  1230. function AnsiStrUpper(Str: PChar): PChar;
  1231. var
  1232. temp: ansistring;
  1233. begin
  1234. temp:=upperansistring(str);
  1235. ansi2pchar(temp,str,result);
  1236. end;
  1237. {$ifdef FPC_HAS_CPSTRING}
  1238. {$i textrec.inc}
  1239. procedure SetStdIOCodePage(var T: Text); inline;
  1240. begin
  1241. case TextRec(T).Mode of
  1242. fmInput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleInput);
  1243. fmOutput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleOutput);
  1244. end;
  1245. end;
  1246. procedure SetStdIOCodePages; inline;
  1247. begin
  1248. SetStdIOCodePage(Input);
  1249. SetStdIOCodePage(Output);
  1250. SetStdIOCodePage(ErrOutput);
  1251. SetStdIOCodePage(StdOut);
  1252. SetStdIOCodePage(StdErr);
  1253. end;
  1254. {$endif FPC_HAS_CPSTRING}
  1255. *)
  1256. procedure InitOS2WideStringManager; inline;
  1257. var
  1258. RC: cardinal;
  1259. ErrName: array [0..MaxPathLen] of char;
  1260. P: pointer;
  1261. begin
  1262. RC := DosLoadModule (@ErrName [0], SizeOf (ErrName), @UConvName [0],
  1263. UConvHandle);
  1264. if RC = 0 then
  1265. begin
  1266. RC := DosQueryProcAddr (UConvHandle, OrdUniCreateUConvObject, nil, P);
  1267. if RC = 0 then
  1268. begin
  1269. Sys_UniCreateUConvObject := TUniCreateUConvObject (P);
  1270. RC := DosQueryProcAddr (UConvHandle, OrdUniMapCpToUcsCp, nil, P);
  1271. if RC = 0 then
  1272. begin
  1273. Sys_UniMapCpToUcsCp := TUniMapCpToUcsCp (P);
  1274. RC := DosQueryProcAddr (UConvHandle, OrdUniFreeUConvObject, nil, P);
  1275. if RC = 0 then
  1276. begin
  1277. Sys_UniFreeUConvObject := TUniFreeUConvObject (P);
  1278. RC := DosQueryProcAddr (UConvHandle, OrdUniUConvFromUcs, nil, P);
  1279. if RC = 0 then
  1280. begin
  1281. Sys_UniUConvFromUcs := TUniUConvFromUcs (P);
  1282. RC := DosQueryProcAddr (UConvHandle, OrdUniUConvToUcs, nil, P);
  1283. if RC = 0 then
  1284. begin
  1285. Sys_UniUConvToUcs := TUniUConvToUcs (P);
  1286. RC := DosLoadModule (@ErrName [0], SizeOf (ErrName),
  1287. @LibUniName [0], LibUniHandle);
  1288. if RC = 0 then
  1289. begin
  1290. RC := DosQueryProcAddr (LibUniHandle, OrdUniToLower, nil, P);
  1291. if RC = 0 then
  1292. begin
  1293. Sys_UniToLower := TUniToLower (P);
  1294. RC := DosQueryProcAddr (LibUniHandle, OrdUniToUpper, nil, P);
  1295. if RC = 0 then
  1296. begin
  1297. Sys_UniToUpper := TUniToUpper (P);
  1298. RC := DosQueryProcAddr (LibUniHandle, OrdUniStrColl, nil,
  1299. P);
  1300. if RC = 0 then
  1301. begin
  1302. Sys_UniStrColl := TUniStrColl (P);
  1303. RC := DosQueryProcAddr (LibUniHandle,
  1304. OrdUniCreateLocaleObject, nil, P);
  1305. if RC = 0 then
  1306. begin
  1307. Sys_UniCreateLocaleObject := TUniCreateLocaleObject
  1308. (P);
  1309. RC := DosQueryProcAddr (LibUniHandle,
  1310. OrdUniFreeLocaleObject, nil, P);
  1311. if RC = 0 then
  1312. begin
  1313. Sys_UniFreeLocaleObject := TUniFreeLocaleObject (P);
  1314. UniAPI := true;
  1315. end;
  1316. end;
  1317. end;
  1318. end;
  1319. end;
  1320. end;
  1321. end;
  1322. end;
  1323. end;
  1324. end;
  1325. end;
  1326. end;
  1327. if RC <> 0 then
  1328. OSErrorWatch (RC);
  1329. if not (UniAPI) then
  1330. begin
  1331. Sys_UniCreateUConvObject := @DummyUniCreateUConvObject;
  1332. Sys_UniMapCpToUcsCp := @DummyUniMapCpToUcsCp;
  1333. Sys_UniFreeUConvObject := @DummyUniFreeUConvObject;
  1334. Sys_UniUConvFromUcs := @DummyUniUConvFromUcs;
  1335. Sys_UniUConvToUcs := @DummyUniUConvToUcs;
  1336. Sys_UniToLower := @DummyUniToLower;
  1337. Sys_UniToUpper := @DummyUniToUpper;
  1338. Sys_UniStrColl := @DummyUniStrColl;
  1339. Sys_UniCreateLocaleObject := @DummyUniCreateLocaleObject;
  1340. Sys_UniFreeLocaleObject := @DummyUniFreeLocaleObject;
  1341. end;
  1342. { Widestring }
  1343. WideStringManager.Wide2AnsiMoveProc := @OS2Unicode2AnsiMove;
  1344. WideStringManager.Ansi2WideMoveProc := @OS2Ansi2UnicodeMove;
  1345. WideStringManager.UpperWideStringProc := @OS2UpperUnicodeString;
  1346. WideStringManager.LowerWideStringProc := @OS2LowerUnicodeString;
  1347. WideStringManager.CompareWideStringProc := @OS2CompareUnicodeString;
  1348. WideStringManager.CompareTextWideStringProc := @OS2CompareTextUnicodeString;
  1349. { Unicode }
  1350. WideStringManager.Unicode2AnsiMoveProc := @OS2Unicode2AnsiMove;
  1351. WideStringManager.Ansi2UnicodeMoveProc := @OS2Ansi2UnicodeMove;
  1352. WideStringManager.UpperUnicodeStringProc := @OS2UpperUnicodeString;
  1353. WideStringManager.LowerUnicodeStringProc := @OS2LowerUnicodeString;
  1354. WideStringManager.CompareUnicodeStringProc := @OS2CompareUnicodeString;
  1355. WideStringManager.CompareTextUnicodeStringProc :=
  1356. @OS2CompareTextUnicodeString;
  1357. { Codepage }
  1358. WideStringManager.GetStandardCodePageProc := @OS2GetStandardCodePage;
  1359. (*
  1360. CharLengthPCharProc:=@CharLengthPChar;
  1361. CodePointLengthProc:=@CodePointLength;
  1362. *)
  1363. WideStringManager.UpperAnsiStringProc := @OS2UpperAnsiString;
  1364. WideStringManager.LowerAnsiStringProc := @OS2LowerAnsiString;
  1365. (*
  1366. WideStringManager.CompareStrAnsiStringProc := @OS2CompareStrAnsiString;
  1367. WideStringManager.CompareTextAnsiStringProc := @OS2AnsiCompareTextAnsiString;
  1368. StrCompAnsiStringProc:=@StrCompAnsi;
  1369. StrICompAnsiStringProc:=@AnsiStrIComp;
  1370. StrLCompAnsiStringProc:=@AnsiStrLComp;
  1371. StrLICompAnsiStringProc:=@AnsiStrLIComp;
  1372. StrLowerAnsiStringProc:=@AnsiStrLower;
  1373. StrUpperAnsiStringProc:=@AnsiStrUpper;
  1374. *)
  1375. end;