fpwidestring.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. unit fpwidestring;
  2. {$mode objfpc}
  3. interface
  4. uses
  5. unicodedata;
  6. function SetActiveCollation(const AName : TCollationName) : Boolean;
  7. function SetActiveCollation(const ACollation : PUCA_DataBook) : Boolean;
  8. function GetActiveCollation() : PUCA_DataBook;
  9. var
  10. DefaultCollationName : TCollationName = '';
  11. implementation
  12. uses
  13. {$ifdef MSWINDOWS}
  14. Windows,
  15. {$endif MSWINDOWS}
  16. {$ifdef Unix}
  17. unixcp,
  18. {$endif}
  19. charset;
  20. procedure fpc_rangeerror; [external name 'FPC_RANGEERROR'];
  21. {$ifdef MSWINDOWS}
  22. function GetACP:UINT; external 'kernel32' name 'GetACP';
  23. {$endif MSWINDOWS}
  24. const
  25. IgnoreInvalidSequenceFlag = True;
  26. var
  27. OldManager : TUnicodeStringManager;
  28. {$ifdef FPC_HAS_FEATURE_THREADING}
  29. ThreadVar
  30. {$else FPC_HAS_FEATURE_THREADING}
  31. Var
  32. {$endif FPC_HAS_FEATURE_THREADING}
  33. current_DefaultSystemCodePage : TSystemCodePage;
  34. current_Map : punicodemap;
  35. current_Collation : PUCA_DataBook;
  36. function SetActiveCollation(const ACollation : PUCA_DataBook) : Boolean;
  37. begin
  38. Result := (ACollation <> nil);
  39. if Result then
  40. current_Collation := ACollation;
  41. end;
  42. function SetActiveCollation(const AName : TCollationName) : Boolean;
  43. var
  44. c : PUCA_DataBook;
  45. begin
  46. c:=FindCollation(AName);
  47. Result := (c <> nil);
  48. if Result then
  49. Result := SetActiveCollation(c);
  50. end;
  51. function GetActiveCollation() : PUCA_DataBook;
  52. begin
  53. Result := current_Collation;
  54. end;
  55. {procedure error_CpNotFound(ACodePage:TSystemCodePage);
  56. begin
  57. System.error(reCodesetConversion);
  58. end;}
  59. procedure InitThread;
  60. var
  61. c : PUCA_DataBook;
  62. begin
  63. current_DefaultSystemCodePage:=DefaultSystemCodePage;
  64. current_Map:=getmap(current_DefaultSystemCodePage);
  65. c:=nil;
  66. if (DefaultCollationName<>'') then
  67. c:=FindCollation(DefaultCollationName);
  68. if (c=nil) and (GetCollationCount()>0) then
  69. c:=FindCollation(0);
  70. current_Collation:=c;
  71. end;
  72. procedure FiniThread;
  73. begin
  74. current_Map:=nil;
  75. end;
  76. function FindMap(const cp: TSystemCodePage): punicodemap;inline;
  77. begin
  78. if (cp=DefaultSystemCodePage) then
  79. begin
  80. { update current_Map in case the DefaultSystemCodePage has been changed }
  81. if (current_DefaultSystemCodePage<>DefaultSystemCodePage) or not Assigned(current_Map) then
  82. begin
  83. FiniThread;
  84. InitThread;
  85. end;
  86. Result:=current_Map;
  87. end
  88. else
  89. Result:=getmap(cp);
  90. end;
  91. { return value:
  92. -1 if incomplete or invalid code point
  93. 0 if NULL character,
  94. > 0 if that's the length in bytes of the code point }
  95. function UTF8CodePointLength(const Str: PAnsiChar; MaxLookAead: PtrInt): Ptrint;
  96. {... taken from ustrings.inc}
  97. var
  98. p: PByte;
  99. TempBYTE: Byte;
  100. CharLen: SizeUint;
  101. LookAhead: SizeUInt;
  102. UC: SizeUInt;
  103. begin
  104. if (Str=nil) then
  105. exit(0);
  106. p:=PByte(Str);
  107. if (p^=0) then
  108. exit(0);
  109. p:=PByte(Str);
  110. if (p^ and $80) = 0 then //One character US-ASCII,
  111. exit(1);
  112. TempByte:=p^;
  113. CharLen:=0;
  114. while (TempByte and $80)<>0 do
  115. begin
  116. TempByte:=(TempByte shl 1) and $FE;
  117. Inc(CharLen);
  118. end;
  119. //Test for the "CharLen" conforms UTF-8 string
  120. //This means the 10xxxxxx pattern.
  121. if SizeUInt(CharLen-1)>MaxLookAead then //Insuficient chars in string to decode UTF-8 array
  122. exit(-1);
  123. for LookAhead := 1 to CharLen-1 do
  124. begin
  125. if ((p[LookAhead] and $80)<>$80) or
  126. ((p[LookAhead] and $40)<>$00)
  127. then
  128. begin
  129. //Invalid UTF-8 sequence, fallback.
  130. exit(-1);
  131. end;
  132. end;
  133. Result:=CharLen;
  134. case CharLen of
  135. 1: begin
  136. //Not valid UTF-8 sequence
  137. Result:=-1;
  138. end;
  139. 2: begin
  140. //Two bytes UTF, convert it
  141. UC:=(p^ and $1F) shl 6;
  142. UC:=UC or (p[1] and $3F);
  143. if UC <= $7F then
  144. begin
  145. //Invalid UTF sequence.
  146. Result:=-1;
  147. end;
  148. end;
  149. 3: begin
  150. //Three bytes, convert it to unicode
  151. UC:= (p^ and $0F) shl 12;
  152. UC:= UC or ((p[1] and $3F) shl 6);
  153. UC:= UC or ((p[2] and $3F));
  154. if (UC <= $7FF) or (UC >= $FFFE) or ((UC >= $D800) and (UC <= $DFFF)) then
  155. begin
  156. //Invalid UTF-8 sequence
  157. Result:=-1;
  158. End;
  159. end;
  160. 4: begin
  161. //Four bytes, convert it to two unicode characters
  162. UC:= (p^ and $07) shl 18;
  163. UC:= UC or ((p[1] and $3F) shl 12);
  164. UC:= UC or ((p[2] and $3F) shl 6);
  165. UC:= UC or ((p[3] and $3F));
  166. if (UC < $10000) or (UC > $10FFFF) then
  167. begin
  168. Result:=-1;
  169. end
  170. end;
  171. 5,6,7: begin
  172. //Invalid UTF8 to unicode conversion,
  173. //mask it as invalid UNICODE too.
  174. Result:=-1;
  175. end;
  176. end;
  177. end;
  178. { return value:
  179. -1 if incomplete or invalid code point
  180. 0 if NULL character,
  181. > 0 if that's the length in bytes of the code point }
  182. function CodePointLength(const Str: PAnsiChar; MaxLookAead: PtrInt): PtrInt;
  183. var
  184. p : PByte;
  185. begin
  186. if (current_DefaultSystemCodePage=CP_UTF8) then
  187. exit(UTF8CodePointLength(Str,MaxLookAead));
  188. if (Str=nil) then
  189. exit(0);
  190. p:=PByte(Str);
  191. if (p^=0) then
  192. exit(0);
  193. if (current_Map=nil) then
  194. exit(1);
  195. if (p^>current_Map^.lastchar) then
  196. exit(-1);
  197. case current_Map^.map[p^].flag of
  198. umf_undefined : Result:=-1;
  199. umf_leadbyte :
  200. begin
  201. if (MaxLookAead>0) then
  202. Result:=2
  203. else
  204. Result:=-1;
  205. end;
  206. else
  207. Result:=1;
  208. end;
  209. end;
  210. procedure Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  211. var
  212. locSource : punicodechar;
  213. locMap : punicodemap;
  214. destBuffer : PAnsiChar;
  215. destLen,actualLen, i : SizeInt;
  216. blockLen : SizeInt;
  217. begin
  218. if (len=0) then
  219. begin
  220. SetLength(dest,0);
  221. exit;
  222. end;
  223. if (cp=CP_UTF8) then
  224. begin
  225. destLen:=UnicodeToUtf8(nil,High(SizeUInt),source,len);
  226. SetLength(dest,destLen);
  227. UnicodeToUtf8(@dest[1],destLen,source,len);
  228. SetCodePage(dest,cp,False);
  229. exit;
  230. end;
  231. if (cp=CP_UTF16) then
  232. begin
  233. destLen:=len*SizeOf(UnicodeChar);
  234. SetLength(dest,destLen);
  235. Move(source^,dest[1],destLen);
  236. SetCodePage(dest,cp,False);
  237. exit;
  238. end;
  239. locMap:=FindMap(cp);
  240. if (locMap=nil) then
  241. begin
  242. DefaultUnicode2AnsiMove(source,dest,DefaultSystemCodePage,len);
  243. exit;
  244. end;
  245. destLen:=3*len;
  246. SetLength(dest,destLen);
  247. destBuffer:=@dest[1];
  248. actualLen:=0;
  249. locSource:=source;
  250. for i:=1 to len do
  251. begin
  252. blockLen:=getascii(tunicodechar(locSource^),locMap,destBuffer,(destLen-actualLen));
  253. if (blockLen<0) then
  254. begin
  255. destLen:=destLen + 3*(1+len-i);
  256. SetLength(dest,destLen);
  257. destBuffer:=@dest[1];
  258. blockLen:=getascii(tunicodechar(locSource^),locMap,destBuffer,(destLen-actualLen));
  259. end;
  260. Inc(destBuffer,blockLen);
  261. actualLen:=actualLen+blockLen;
  262. Inc(locSource);
  263. end;
  264. if (actualLen<>Length(dest)) then
  265. SetLength(dest,actualLen);
  266. if (Length(dest)>0) then
  267. SetCodePage(dest,cp,False);
  268. end;
  269. procedure Ansi2UnicodeMove(source:PAnsiChar; cp:TSystemCodePage; var dest:UnicodeString; len:SizeInt);
  270. var
  271. locMap : punicodemap;
  272. destLen : SizeInt;
  273. begin
  274. if (len<=0) then
  275. begin
  276. SetLength(dest,0);
  277. exit;
  278. end;
  279. if (cp=CP_UTF8) then
  280. begin
  281. destLen:=Utf8ToUnicode(nil,source,len);
  282. if destLen > 0 then
  283. SetLength(dest,destLen-1)
  284. else
  285. SetLength(dest,0);
  286. Utf8ToUnicode(@dest[1],source,len);
  287. exit;
  288. end;
  289. if (cp=CP_UTF16) then
  290. begin
  291. //what if (len mod 2) > 0 ?
  292. destLen:=len div SizeOf(UnicodeChar);
  293. SetLength(dest,destLen);
  294. Move(source^,dest[1],(destLen*SizeOf(UnicodeChar)));
  295. exit;
  296. end;
  297. locMap:=FindMap(cp);
  298. if (locMap=nil) then
  299. begin
  300. DefaultAnsi2UnicodeMove(source,DefaultSystemCodePage,dest,len);
  301. exit;
  302. end;
  303. destLen:=getunicode(source,len,locMap,nil);
  304. SetLength(dest,destLen);
  305. getunicode(source,len,locMap,tunicodestring(@dest[1]));
  306. end;
  307. {$ifdef MSWINDOWS}
  308. procedure Ansi2WideMove(source:PAnsiChar; cp:TSystemCodePage; var dest:WideString; len:SizeInt);
  309. var
  310. locMap : punicodemap;
  311. destLen : SizeInt;
  312. begin
  313. if (len<=0) then
  314. begin
  315. SetLength(dest,0);
  316. exit;
  317. end;
  318. locMap:=FindMap(cp);
  319. if (locMap=nil) then
  320. begin
  321. DefaultAnsi2WideMove(source,DefaultSystemCodePage,dest,len);
  322. exit;
  323. end;
  324. destLen:=getunicode(source,len,locMap,nil);
  325. SetLength(dest,destLen);
  326. getunicode(source,len,locMap,tunicodestring(@dest[1]));
  327. end;
  328. {$endif MSWINDOWS}
  329. function UpperUnicodeString(const S: UnicodeString): UnicodeString;
  330. begin
  331. if (UnicodeToUpper(S,IgnoreInvalidSequenceFlag,Result) <> 0) then
  332. system.error(reRangeError);
  333. end;
  334. function UpperWideString(const S: WideString): WideString;
  335. var
  336. u : UnicodeString;
  337. begin
  338. u:=s;
  339. Result:=UpperUnicodeString(u);
  340. end;
  341. function LowerUnicodeString(const S: UnicodeString): UnicodeString;
  342. begin
  343. if (UnicodeToLower(S,IgnoreInvalidSequenceFlag,Result) <> 0) then
  344. system.error(reRangeError);
  345. end;
  346. function LowerWideString(const S: WideString): WideString;
  347. var
  348. u : UnicodeString;
  349. begin
  350. u:=s;
  351. Result:=LowerUnicodeString(u);
  352. end;
  353. function CompareUnicodeStringUCA(p1,p2:PUnicodeChar; l1,l2:PtrInt) : PtrInt;inline;
  354. begin
  355. Result := IncrementalCompareString(p1,l1,p2,l2,current_Collation);
  356. end;
  357. function CompareUnicodeString(p1,p2:PUnicodeChar; l1,l2:PtrInt) : PtrInt;inline;
  358. begin
  359. if (Pointer(p1)=Pointer(p2)) then
  360. exit(0);
  361. if (l1=0) then
  362. exit(-l2);
  363. if (l2=0) then
  364. exit(l1);
  365. Result := CompareUnicodeStringUCA(p1,p2,l1,l2);
  366. end;
  367. function CompareUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  368. begin
  369. if (current_Collation=nil) then
  370. exit(OldManager.CompareUnicodeStringProc(s1,s2));
  371. Result:=CompareUnicodeString(
  372. PUnicodeChar(Pointer(s1)),
  373. PUnicodeChar(Pointer(s2)),
  374. Length(s1),Length(s2)
  375. );
  376. end;
  377. function CompareWideString(const s1, s2 : WideString) : PtrInt;
  378. begin
  379. if (current_Collation=nil) then
  380. exit(OldManager.CompareWideStringProc(s1,s2));
  381. Result:=CompareUnicodeString(
  382. PUnicodeChar(Pointer(s1)),
  383. PUnicodeChar(Pointer(s2)),
  384. Length(s1),Length(s2)
  385. );
  386. end;
  387. function CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  388. begin
  389. Result:=CompareUnicodeString(UpperUnicodeString(s1),UpperUnicodeString(s2));
  390. end;
  391. function CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  392. begin
  393. Result:=CompareWideString(UpperWideString(s1),UpperWideString(s2));
  394. end;
  395. procedure EnsureAnsiLen(var S: AnsiString; const len: SizeInt); inline;
  396. begin
  397. if (len>length(s)) then
  398. if (length(s) < 10*256) then
  399. setlength(s,length(s)+10)
  400. else
  401. setlength(s,length(s)+length(s) shr 8);
  402. end;
  403. procedure ConcatCharToAnsiStr(const c: AnsiChar; var S: AnsiString; var index: SizeInt);
  404. begin
  405. EnsureAnsiLen(s,index);
  406. pansichar(@s[index])^:=c;
  407. inc(index);
  408. end;
  409. function UpperAnsiString(const s : ansistring) : ansistring;
  410. var
  411. p : PAnsiChar;
  412. i, slen,
  413. resindex : SizeInt;
  414. mblen : SizeInt;
  415. us,usl : UnicodeString;
  416. locMap : punicodemap;
  417. ulen,k,
  418. aalen,ai : SizeInt;
  419. aa : array[0..8] of AnsiChar;
  420. begin
  421. if (Length(s)=0) then
  422. exit('');
  423. if (DefaultSystemCodePage=CP_UTF8) then
  424. begin
  425. //convert to UnicodeString,uppercase,convert back to utf8
  426. ulen:=Utf8ToUnicode(nil,@s[1],Length(s));
  427. if ulen>0 then
  428. SetLength(us,ulen-1);
  429. Utf8ToUnicode(@us[1],@s[1],Length(s));
  430. us:=UpperUnicodeString(us);
  431. ulen:=Length(us);
  432. slen:=UnicodeToUtf8(nil,0,@us[1],ulen);
  433. SetLength(Result,slen);
  434. UnicodeToUtf8(@Result[1],slen,@us[1],ulen);
  435. exit;
  436. end;
  437. locMap:=FindMap(DefaultSystemCodePage);
  438. if (locMap=nil) then
  439. exit(System.UpCase(s));
  440. SetLength(us,2);
  441. p:=@s[1];
  442. slen:=length(s);
  443. SetLength(result,slen+10);
  444. i:=1;
  445. resindex:=1;
  446. while (i<=slen) do
  447. begin
  448. mblen:=CodePointLength(p,slen-i);
  449. if (mblen<=0) then
  450. begin
  451. ConcatCharToAnsiStr(p^,result,resindex);
  452. mblen:=1;
  453. end
  454. else
  455. begin
  456. SetLength(us,2);
  457. ulen:=getunicode(p,mblen,locMap,@us[1]);
  458. if (Length(us)<>ulen) then
  459. SetLength(us,ulen);
  460. usl:=UpperUnicodeString(us);
  461. for k:=1 to Length(usl) do
  462. begin
  463. aalen:=getascii(tunicodechar(us[k]),locMap,@aa[Low(aa)],Length(aa));
  464. for ai:=0 to aalen-1 do
  465. ConcatCharToAnsiStr(aa[ai],result,resindex);
  466. end;
  467. end;
  468. Inc(p,mblen);
  469. end;
  470. SetLength(result,resindex-1);
  471. end;
  472. function LowerAnsiString(const s : ansistring) : ansistring;
  473. var
  474. p : PAnsiChar;
  475. i, slen,
  476. resindex : SizeInt;
  477. mblen : SizeInt;
  478. us,usl : UnicodeString;
  479. locMap : punicodemap;
  480. ulen,k,
  481. aalen,ai : SizeInt;
  482. aa : array[0..8] of AnsiChar;
  483. begin
  484. if (Length(s)=0) then
  485. exit('');
  486. if (DefaultSystemCodePage=CP_UTF8) then
  487. begin
  488. //convert to UnicodeString,lowercase,convert back to utf8
  489. ulen:=Utf8ToUnicode(nil,@s[1],Length(s));
  490. if ulen>0 then
  491. SetLength(us,ulen-1);
  492. Utf8ToUnicode(@us[1],@s[1],Length(s));
  493. us:=LowerUnicodeString(us);
  494. ulen:=Length(us);
  495. slen:=UnicodeToUtf8(nil,0,@us[1],ulen);
  496. SetLength(Result,slen);
  497. UnicodeToUtf8(@Result[1],slen,@us[1],ulen);
  498. exit;
  499. end;
  500. locMap:=FindMap(DefaultSystemCodePage);
  501. if (locMap=nil) then
  502. exit(System.LowerCase(s));
  503. SetLength(us,2);
  504. p:=@s[1];
  505. slen:=length(s);
  506. SetLength(result,slen+10);
  507. i:=1;
  508. resindex:=1;
  509. while (i<=slen) do
  510. begin
  511. mblen:=CodePointLength(p,slen-i);
  512. if (mblen<=0) then
  513. begin
  514. ConcatCharToAnsiStr(p^,result,resindex);
  515. mblen:=1;
  516. end
  517. else
  518. begin
  519. SetLength(us,2);
  520. ulen:=getunicode(p,mblen,locMap,@us[1]);
  521. if (Length(us)<>ulen) then
  522. SetLength(us,ulen);
  523. usl:=LowerUnicodeString(us);
  524. for k:=1 to Length(usl) do
  525. begin
  526. aalen:=getascii(tunicodechar(us[k]),locMap,@aa[Low(aa)],Length(aa));
  527. for ai:=0 to aalen-1 do
  528. ConcatCharToAnsiStr(aa[ai],result,resindex);
  529. end;
  530. end;
  531. Inc(p,mblen);
  532. end;
  533. SetLength(result,resindex-1);
  534. end;
  535. procedure ansi2pchar(const s: ansistring; const orgp: pansichar; out p: pansichar);
  536. var
  537. newlen: sizeint;
  538. begin
  539. newlen:=length(s);
  540. if newlen>strlen(orgp) then
  541. fpc_rangeerror;
  542. p:=orgp;
  543. if (newlen>0) then
  544. move(s[1],p[0],newlen);
  545. p[newlen]:=#0;
  546. end;
  547. function AnsiStrLower(Str: PAnsiChar): PAnsiChar;
  548. var
  549. temp: ansistring;
  550. begin
  551. temp:=LowerAnsiString(str);
  552. ansi2pchar(temp,str,result);
  553. end;
  554. function AnsiStrUpper(Str: PAnsiChar): PAnsiChar;
  555. var
  556. temp: ansistring;
  557. begin
  558. temp:=UpperAnsiString(str);
  559. ansi2pchar(temp,str,result);
  560. end;
  561. function CharLengthPChar(const Str: PAnsiChar): PtrInt;
  562. var
  563. len:PtrInt;
  564. nextlen: ptrint;
  565. s: PAnsiChar;
  566. begin
  567. Result:=0;
  568. if (Str=nil) or (Byte(Str^)=0) then
  569. exit;
  570. s:=str;
  571. len:=strlen(s);
  572. repeat
  573. nextlen:=CodePointLength(s,len);
  574. { skip invalid/incomplete sequences }
  575. if (nextlen<0) then
  576. nextlen:=1;
  577. Inc(result,nextlen);
  578. Inc(s,nextlen);
  579. Dec(len,nextlen);
  580. until (nextlen=0);
  581. end;
  582. function InternalCompareStrAnsiString(
  583. const S1, S2 : PAnsiChar;
  584. const Len1, Len2 : PtrUInt
  585. ) : PtrInt;inline;
  586. var
  587. a, b : UnicodeString;
  588. begin
  589. a := '';
  590. Ansi2UnicodeMove(S1,DefaultSystemCodePage,a,Len1);
  591. b := '';
  592. Ansi2UnicodeMove(S2,DefaultSystemCodePage,b,Len2);
  593. Result := CompareUnicodeString(a,b);
  594. end;
  595. function StrLCompAnsiString(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  596. begin
  597. if (MaxLen=0) then
  598. exit(0);
  599. Result := InternalCompareStrAnsiString(S1,S2,MaxLen,MaxLen);
  600. end;
  601. function CompareStrAnsiString(const S1, S2: ansistring): PtrInt;
  602. var
  603. l1, l2 : PtrInt;
  604. begin
  605. if (Pointer(S1)=Pointer(S2)) then
  606. exit(0);
  607. l1:=Length(S1);
  608. l2:=Length(S2);
  609. if (l1=0) then begin
  610. if (l2=0) then
  611. exit(0);
  612. exit(-l2);
  613. end;
  614. if (l2=0) then
  615. exit(-l1);
  616. Result := InternalCompareStrAnsiString(@S1[1],@S2[2],l1,l2);
  617. end;
  618. function CompareTextAnsiString(const S1, S2: ansistring): PtrInt;
  619. var
  620. a,b : ansistring;
  621. begin
  622. a:=UpperAnsistring(s1);
  623. b:=UpperAnsistring(s2);
  624. Result:=CompareStrAnsiString(a,b);
  625. end;
  626. function StrCompAnsiString(S1, S2: PChar): PtrInt;
  627. var
  628. l1,l2 : PtrInt;
  629. begin
  630. l1:=strlen(S1);
  631. l2:=strlen(S2);
  632. Result := InternalCompareStrAnsiString(S1,S2,l1,l2);
  633. end;
  634. function StrLICompAnsiString(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  635. var
  636. a, b: ansistring;
  637. begin
  638. if (MaxLen=0) then
  639. exit(0);
  640. SetLength(a,MaxLen);
  641. Move(s1^,a[1],MaxLen);
  642. SetLength(b,MaxLen);
  643. Move(s2^,b[1],MaxLen);
  644. Result:=CompareTextAnsiString(a,b);
  645. end;
  646. function StrICompAnsiString(S1, S2: PChar): PtrInt;
  647. begin
  648. Result:=CompareTextAnsiString(ansistring(s1),ansistring(s2));
  649. end;
  650. function StrLowerAnsiString(Str: PChar): PChar;
  651. var
  652. temp: ansistring;
  653. begin
  654. temp:=LowerAnsiString(str);
  655. ansi2pchar(temp,str,result);
  656. end;
  657. function StrUpperAnsiString(Str: PChar): PChar;
  658. var
  659. temp: ansistring;
  660. begin
  661. temp:=UpperAnsiString(str);
  662. ansi2pchar(temp,str,result);
  663. end;
  664. //------------------------------------------------------------------------------
  665. procedure SetPascalWideStringManager();
  666. var
  667. locWideStringManager : TUnicodeStringManager;
  668. begin
  669. OldManager := widestringmanager;
  670. locWideStringManager:=widestringmanager;
  671. With locWideStringManager do
  672. begin
  673. Wide2AnsiMoveProc:=@Unicode2AnsiMove;
  674. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  675. Ansi2WideMoveProc:=@Ansi2WideMove;
  676. UpperWideStringProc:=@UpperWideString;
  677. LowerWideStringProc:=@LowerWideString;
  678. CompareWideStringProc:=@CompareWideString;
  679. CompareTextWideStringProc:=@CompareTextWideString;
  680. {$else FPC_WIDESTRING_EQUAL_UNICODESTRING}
  681. Ansi2WideMoveProc:=@Ansi2UnicodeMove;
  682. UpperWideStringProc:=@UpperUnicodeString;
  683. LowerWideStringProc:=@LowerUnicodeString;
  684. CompareWideStringProc:=@CompareUnicodeString;
  685. CompareTextWideStringProc:=@CompareTextUnicodeString;
  686. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  687. CharLengthPCharProc:=@CharLengthPChar;
  688. CodePointLengthProc:=@CodePointLength;
  689. UpperAnsiStringProc:=@UpperAnsiString;
  690. LowerAnsiStringProc:=@LowerAnsiString;
  691. CompareStrAnsiStringProc:=@CompareStrAnsiString;
  692. CompareTextAnsiStringProc:=@CompareTextAnsiString;
  693. StrCompAnsiStringProc:=@StrCompAnsiString;
  694. StrICompAnsiStringProc:=@StrICompAnsiString;
  695. StrLCompAnsiStringProc:=@StrLCompAnsiString;
  696. StrLICompAnsiStringProc:=@StrLICompAnsiString;
  697. StrLowerAnsiStringProc:=@StrLowerAnsiString;
  698. StrUpperAnsiStringProc:=@StrUpperAnsiString;
  699. ThreadInitProc:=@InitThread;
  700. ThreadFiniProc:=@FiniThread;
  701. { Unicode }
  702. Unicode2AnsiMoveProc:=@Unicode2AnsiMove;
  703. Ansi2UnicodeMoveProc:=@Ansi2UnicodeMove;
  704. UpperUnicodeStringProc:=@UpperUnicodeString;
  705. LowerUnicodeStringProc:=@LowerUnicodeString;
  706. CompareUnicodeStringProc:=@CompareUnicodeString;
  707. CompareTextUnicodeStringProc:=@CompareTextUnicodeString;
  708. end;
  709. SetUnicodeStringManager(locWideStringManager);
  710. DefaultUnicodeCodePage:=CP_UTF16;
  711. {$ifdef MSWINDOWS}
  712. DefaultSystemCodePage:=GetACP();
  713. {$endif MSWINDOWS}
  714. {$ifdef UNIX}
  715. DefaultSystemCodePage:=GetSystemCodepage;
  716. if (DefaultSystemCodePage = CP_NONE) then
  717. DefaultSystemCodePage:=CP_UTF8;
  718. {$endif UNIX}
  719. end;
  720. initialization
  721. current_Collation := nil;
  722. SetPascalWideStringManager();
  723. InitThread();
  724. finalization
  725. FiniThread();
  726. end.