wstrings.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2001 by Florian Klaempfl,
  5. member of the Free Pascal development team.
  6. This file implements support routines for WideStrings with FPC
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {
  14. This file contains the implementation of the WideString type,
  15. and all things that are needed for it.
  16. WideString is defined as a 'silent' pwidechar :
  17. a pwidechar that points to :
  18. @-12 : Longint for maximum size;
  19. @-8 : Longint for size;
  20. @-4 : Longint for reference count;
  21. @ : String + Terminating #0;
  22. Pwidechar(Widestring) is a valid typecast.
  23. So WS[i] is converted to the address @WS+i-1.
  24. Constants should be assigned a reference count of -1
  25. Meaning that they can't be disposed of.
  26. }
  27. Type
  28. PWideRec = ^TWideRec;
  29. TWideRec = Packed Record
  30. Maxlen,
  31. len,
  32. ref : Longint;
  33. First : WideChar;
  34. end;
  35. Const
  36. WideRecLen = SizeOf(TWideRec);
  37. WideFirstOff = SizeOf(TWideRec)-1;
  38. (*
  39. Procedure UniqueWideString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE'];
  40. {
  41. Make sure reference count of S is 1,
  42. using copy-on-write semantics.
  43. }
  44. begin
  45. end;
  46. *)
  47. {****************************************************************************
  48. Internal functions, not in interface.
  49. ****************************************************************************}
  50. {$ifdef WideStrDebug}
  51. Procedure DumpWideRec(S : Pointer);
  52. begin
  53. If S=Nil then
  54. Writeln ('String is nil')
  55. Else
  56. Begin
  57. With PWideRec(S-WideFirstOff)^ do
  58. begin
  59. Write ('(Maxlen: ',maxlen);
  60. Write (' Len:',len);
  61. Writeln (' Ref: ',ref,')');
  62. end;
  63. end;
  64. end;
  65. {$endif}
  66. Function NewWideString(Len : Longint) : Pointer;
  67. {
  68. Allocate a new WideString on the heap.
  69. initialize it to zero length and reference count 1.
  70. }
  71. Var
  72. P : Pointer;
  73. begin
  74. { Also add +1 for a terminating zero }
  75. GetMem(P,Len+Len+WideRecLen);
  76. If P<>Nil then
  77. begin
  78. PWideRec(P)^.Maxlen:=Len; { Maximal length }
  79. PWideRec(P)^.Len:=0; { Initial length }
  80. PWideRec(P)^.Ref:=1; { Set reference count }
  81. PWideRec(P)^.First:=#0; { Terminating #0 }
  82. P:=P+WideFirstOff; { Points to string now }
  83. end;
  84. NewWideString:=P;
  85. end;
  86. Procedure DisposeWideString(Var S : Pointer);
  87. {
  88. Deallocates a WideString From the heap.
  89. }
  90. begin
  91. If S=Nil then
  92. exit;
  93. Dec (Longint(S),WideFirstOff);
  94. FreeMem (S);
  95. S:=Nil;
  96. end;
  97. Procedure WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF'];
  98. {
  99. Decreases the ReferenceCount of a non constant widestring;
  100. If the reference count is zero, deallocate the string;
  101. }
  102. Type
  103. plongint = ^longint;
  104. Var
  105. l : plongint;
  106. Begin
  107. { Zero string }
  108. If S=Nil then exit;
  109. { check for constant strings ...}
  110. l:=@PWIDEREC(S-WideFirstOff)^.Ref;
  111. If l^<0 then exit;
  112. { declocked does a MT safe dec and returns true, if the counter is 0 }
  113. If declocked(l^) then
  114. { Ref count dropped to zero }
  115. DisposeWideString (S); { Remove...}
  116. { this pointer is not valid anymore, so set it to zero }
  117. S:=nil;
  118. end;
  119. Procedure WideStr_Incr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF'];
  120. Begin
  121. If S=Nil then
  122. exit;
  123. { Let's be paranoid : Constant string ??}
  124. If PWideRec(S-WideFirstOff)^.Ref<0 then exit;
  125. inclocked(PWideRec(S-WideFirstOff)^.Ref);
  126. end;
  127. Procedure WideStr_To_ShortStr (Var S1 : ShortString;S2 : Pointer);[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR'];
  128. {
  129. Converts a WideString to a ShortString;
  130. }
  131. Var
  132. Size : Longint;
  133. begin
  134. if S2=nil then
  135. S1:=''
  136. else
  137. begin
  138. {!!!!! FIXME
  139. Size:=PAnsiRec(S2-FirstOff)^.Len;
  140. If Size>high(S1) then
  141. Size:=high(S1);
  142. Move (S2^,S1[1],Size);
  143. byte(S1[0]):=Size;
  144. }
  145. end;
  146. end;
  147. Procedure ShortStr_To_WideStr (Var S1 : Pointer; Const S2 : ShortString);[Public, alias: 'FPC_SHORTSTR_TO_WIDESTR'];
  148. {
  149. Converts a ShortString to a WideString;
  150. }
  151. Var
  152. Size : Longint;
  153. begin
  154. Size:=Length(S2);
  155. Setlength (WideString(S1),Size);
  156. if Size>0 then
  157. begin
  158. {!!!! FIXME
  159. Move (S2[1],Pointer(S1)^,Size);
  160. Terminating Zero
  161. PByte(Pointer(S1)+Size)^:=0;
  162. }
  163. end;
  164. end;
  165. Procedure WideStr_To_AnsiStr (Var S1 : Pointer;S2 : Pointer);[Public, alias: 'FPC_WIDESTR_TO_ANSISTR'];
  166. {
  167. Converts a WideString to an AnsiString
  168. }
  169. begin
  170. if s2=nil then
  171. s1:=nil
  172. else
  173. begin
  174. {!!!!! FIXME }
  175. end;
  176. end;
  177. Procedure AnsiStr_To_WideStr (Var S1 : Pointer; Const S2 : Pointer);[Public, alias: 'FPC_ANSISTR_TO_WIDESTR'];
  178. {
  179. Converts an AnsiString to a WideString;
  180. }
  181. Var
  182. Size : Longint;
  183. begin
  184. if s2=nil then
  185. s1:=nil
  186. else
  187. begin
  188. {!!!! FIXME }
  189. end;
  190. end;
  191. { checked against the ansistring routine, 2001-05-27 (FK) }
  192. Procedure WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN'];
  193. {
  194. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  195. }
  196. begin
  197. If S2<>nil then
  198. If PWideRec(S2-WideFirstOff)^.Ref>0 then
  199. Inc(PWideRec(S2-WideFirstOff)^.ref);
  200. { Decrease the reference count on the old S1 }
  201. widestr_decr_ref (S1);
  202. { And finally, have S1 pointing to S2 (or its copy) }
  203. S1:=S2;
  204. end;
  205. { checked against the ansistring routine, 2001-05-27 (FK) }
  206. Procedure WideStr_Concat (S1,S2 : Pointer;var S3 : Pointer);[Public, alias: 'FPC_WIDESTR_CONCAT'];
  207. {
  208. Concatenates 2 WideStrings : S1+S2.
  209. Result Goes to S3;
  210. }
  211. Var
  212. Size,Location : Longint;
  213. begin
  214. { create new result }
  215. if S3<>nil then
  216. WideStr_Decr_Ref(S3);
  217. { only assign if s1 or s2 is empty }
  218. if (S1=Nil) then
  219. WideStr_Assign(S3,S2)
  220. else
  221. if (S2=Nil) then
  222. WideStr_Assign(S3,S1)
  223. else
  224. begin
  225. Size:=PWideRec(S2-WideFirstOff)^.Len;
  226. Location:=Length(WideString(S1));
  227. SetLength (WideString(S3),Size+Location);
  228. Move (S1^,S3^,Location*2);
  229. Move (S2^,(S3+location*2)^,(Size+1)*2);
  230. end;
  231. end;
  232. Procedure Char_To_WideStr(var S1 : Pointer; c : Char);[Public, alias: 'FPC_CHAR_TO_WIDESTR'];
  233. {
  234. Converts a Char to a WideString;
  235. }
  236. begin
  237. Setlength (WideString(S1),1);
  238. PByte(Pointer(S1))^:=byte(c);
  239. { Terminating Zero }
  240. PByte(Pointer(S1)+1)^:=0;
  241. end;
  242. Procedure PChar_To_WideStr(var a : widestring;p : pchar);[Public,Alias : 'FPC_PCHAR_TO_WIDESTR'];
  243. Var
  244. L : Longint;
  245. begin
  246. if pointer(a)<>nil then
  247. begin
  248. WideStr_Decr_Ref(Pointer(a));
  249. pointer(a):=nil;
  250. end;
  251. if (not assigned(p)) or (p[0]=#0) Then
  252. Pointer(a):=nil
  253. else
  254. begin
  255. //!! Horribly inneficient, but I see no other way...
  256. L:=1;
  257. While P[l]<>#0 do
  258. inc (l);
  259. Pointer(a):=NewWidestring(L);
  260. SetLength(A,L);
  261. Move (P[0],Pointer(A)^,L)
  262. end;
  263. end;
  264. Procedure CharArray_To_WideStr(var a : widestring;p : pchar;l:longint);[Public,Alias : 'FPC_CHARARRAY_TO_WIDESTR'];
  265. var
  266. i : longint;
  267. hp : pchar;
  268. begin
  269. if p[0]=#0 Then
  270. Pointer(a):=nil
  271. else
  272. begin
  273. Pointer(a):=NewWidestring(L);
  274. hp:=p;
  275. i:=0;
  276. while (i<l) and (hp^<>#0) do
  277. begin
  278. inc(hp);
  279. inc(i);
  280. end;
  281. SetLength(A,i);
  282. Move (P[0],Pointer(A)^,i)
  283. end;
  284. end;
  285. Function WideStr_Compare(S1,S2 : Pointer): Longint;[Public,Alias : 'FPC_WIDESTR_COMPARE'];
  286. {
  287. Compares 2 WideStrings;
  288. The result is
  289. <0 if S1<S2
  290. 0 if S1=S2
  291. >0 if S1>S2
  292. }
  293. Var
  294. i,MaxI,Temp : Longint;
  295. begin
  296. i:=0;
  297. Maxi:=Length(WideString(S1));
  298. temp:=Length(WideString(S2));
  299. If MaxI>Temp then
  300. MaxI:=Temp;
  301. Temp:=0;
  302. While (i<MaxI) and (Temp=0) do
  303. begin
  304. Temp:= PWord(S1+I)^ - PWord(S2+i)^;
  305. inc(i);
  306. end;
  307. if temp=0 then
  308. temp:=Length(WideString(S1))-Length(WideString(S2));
  309. WideStr_Compare:=Temp;
  310. end;
  311. Procedure WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO'];
  312. begin
  313. if p=nil then
  314. HandleErrorFrame(201,get_frame);
  315. end;
  316. Procedure WideStr_CheckRange(len,index : longint);[Public,Alias : 'FPC_WIDESTR_RANGECHECK'];
  317. begin
  318. if (index>len) or (Index<1) then
  319. HandleErrorFrame(201,get_frame);
  320. end;
  321. {$ifndef INTERNSETLENGTH}
  322. Procedure SetLength (Var S : WideString; l : Longint);
  323. {$else INTERNSETLENGTH}
  324. Procedure WideStr_SetLength (Var S : WideString; l : Longint);[Public,Alias : 'FPC_WIDESTR_SETLENGTH'];
  325. {$endif INTERNSETLENGTH}
  326. {
  327. Sets The length of string S to L.
  328. Makes sure S is unique, and contains enough room.
  329. }
  330. Var
  331. Temp : Pointer;
  332. begin
  333. if (l>0) then
  334. begin
  335. if Pointer(S)=nil then
  336. begin
  337. { Need a complete new string...}
  338. Pointer(s):=NewWideString(l);
  339. end
  340. else
  341. If (PWideRec(Pointer(S)-WideFirstOff)^.Maxlen < L) or
  342. (PWideRec(Pointer(S)-WideFirstOff)^.Ref <> 1) then
  343. begin
  344. { Reallocation is needed... }
  345. Temp:=Pointer(NewWideString(L));
  346. if Length(S)>0 then
  347. Move(Pointer(S)^,Temp^,L+L);
  348. ansistr_decr_ref(Pointer(S));
  349. Pointer(S):=Temp;
  350. end;
  351. { Force nil termination in case it gets shorter }
  352. PByte(Pointer(S)+l)^:=0;
  353. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l;
  354. end
  355. else
  356. begin
  357. { Length=0 }
  358. if Pointer(S)<>nil then
  359. ansistr_decr_ref (Pointer(S));
  360. Pointer(S):=Nil;
  361. end;
  362. end;
  363. {*****************************************************************************
  364. Public functions, In interface.
  365. *****************************************************************************}
  366. Function Length (Const S : WideString) : Longint;
  367. {
  368. Returns the length of an WideString.
  369. Takes in acount that zero strings are NIL;
  370. }
  371. begin
  372. If Pointer(S)=Nil then
  373. Length:=0
  374. else
  375. Length:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  376. end;
  377. Procedure UniqueString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE'];
  378. {
  379. Make sure reference count of S is 1,
  380. using copy-on-write semantics.
  381. }
  382. Var
  383. SNew : Pointer;
  384. begin
  385. If Pointer(S)=Nil then
  386. exit;
  387. if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then
  388. begin
  389. SNew:=NewWideString (PWideRec(Pointer(S)-WideFirstOff)^.len);
  390. Move (Pointer(S)^,SNew^,(PWideRec(Pointer(S)-WideFirstOff)^.len+1)*2);
  391. PWideRec(SNew-WideFirstOff)^.len:=PWideRec(Pointer(S)-WideFirstOff)^.len;
  392. ansistr_decr_ref (Pointer(S)); { Thread safe }
  393. Pointer(S):=SNew;
  394. end;
  395. end;
  396. Function Copy (Const S : WideString; Index,Size : Longint) : WideString;
  397. var
  398. ResultAddress : Pointer;
  399. begin
  400. ResultAddress:=Nil;
  401. dec(index);
  402. if Index < 0 then
  403. Index := 0;
  404. { Check Size. Accounts for Zero-length S, the double check is needed because
  405. Size can be maxint and will get <0 when adding index }
  406. if (Size>Length(S)) or
  407. (Index+Size>Length(S)) then
  408. Size:=Length(S)-Index;
  409. If Size>0 then
  410. begin
  411. If Index<0 Then
  412. Index:=0;
  413. ResultAddress:=Pointer(NewWideString (Size));
  414. if ResultAddress<>Nil then
  415. begin
  416. Move (Pointer(Pointer(S)+index)^,ResultAddress^,Size*2);
  417. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size;
  418. PWord(ResultAddress+Size*2)^:=0;
  419. end;
  420. end;
  421. Pointer(Copy):=ResultAddress;
  422. end;
  423. Function Pos (Const Substr : WideString; Const Source : WideString) : Longint;
  424. var
  425. substrlen,
  426. maxi,
  427. i,j : longint;
  428. e : boolean;
  429. { S : WideString;
  430. se : Pointer; }
  431. begin
  432. i := 0;
  433. j := 0;
  434. substrlen:=Length(SubStr);
  435. maxi:=length(source)-substrlen;
  436. e:=(substrlen>0);
  437. while (e) and (i <= maxi) do
  438. begin
  439. inc (i);
  440. {!!!: if Source[i]=SubStr[1] then
  441. begin
  442. S:=copy(Source,i,substrlen);
  443. Se:=pointer(SubStr);
  444. if WideStr_Compare(se,Pointer(S))=0 then
  445. begin
  446. j := i;
  447. break;
  448. end;
  449. end;}
  450. end;
  451. pos := j;
  452. end;
  453. Procedure Delete (Var S : WideString; Index,Size: Longint);
  454. Var
  455. LS : Longint;
  456. begin
  457. If Length(S)=0 then
  458. exit;
  459. if index<=0 then
  460. begin
  461. inc(Size,index-1);
  462. index:=1;
  463. end;
  464. LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  465. if (Index<=LS) and (Size>0) then
  466. begin
  467. UniqueString (S);
  468. if Size+Index>LS then
  469. Size:=LS-Index+1;
  470. if Index+Size<=LS then
  471. begin
  472. Dec(Index);
  473. Move(PByte(Pointer(S))[Index+Size],PByte(Pointer(S))[Index],(LS-Index+1)*2);
  474. end;
  475. Setlength(s,LS-Size);
  476. end;
  477. end;
  478. Procedure Insert (Const Source : WideString; Var S : WideString; Index : Longint);
  479. var
  480. Temp : WideString;
  481. LS : Longint;
  482. begin
  483. If Length(Source)=0 then
  484. exit;
  485. if index <= 0 then
  486. index := 1;
  487. Ls:=Length(S);
  488. if index > LS then
  489. index := LS+1;
  490. Dec(Index);
  491. Pointer(Temp) := NewWideString(Length(Source)+LS);
  492. SetLength(Temp,Length(Source)+LS);
  493. If Index>0 then
  494. move (Pointer(S)^,Pointer(Temp)^,Index*2);
  495. Move (Pointer(Source)^,PByte(Temp)[Index],Length(Source)*2);
  496. If (LS-Index)>0 then
  497. Move(PByte(Pointer(S))[Index],PByte(temp)[Length(Source)+index],(LS-Index)*2);
  498. S:=Temp;
  499. end;
  500. {!!!:Procedure SetString (Var S : WideString; Buf : PWideChar; Len : Longint);
  501. begin
  502. SetLength(S,Len);
  503. Move (Buf[0],S[1],Len*2);
  504. end;}
  505. {
  506. $Log$
  507. Revision 1.7 2001-05-27 14:28:03 florian
  508. + some procedures added
  509. Revision 1.6 2000/11/06 23:17:15 peter
  510. * removed some warnings
  511. Revision 1.5 2000/11/06 20:34:24 peter
  512. * changed ver1_0 defines to temporary defs
  513. Revision 1.4 2000/10/21 18:20:17 florian
  514. * a lot of small changes:
  515. - setlength is internal
  516. - win32 graph unit extended
  517. ....
  518. Revision 1.3 2000/08/08 22:12:36 sg
  519. * Implemented WideString helper functions (but they are not tested yet
  520. due to the lack of full compiler support for WideString/WideChar!)
  521. Revision 1.2 2000/07/13 11:33:46 michael
  522. + removed logs
  523. }