sysucode.inc 42 KB

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