wstrings.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 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. Dec(l^);
  113. If l^=0 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. Inc(PWideRec(S-WideFirstOff)^.Ref);
  126. end;
  127. Procedure WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN'];
  128. {
  129. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  130. }
  131. begin
  132. If S2<>nil then
  133. If PWideRec(S2-WideFirstOff)^.Ref>0 then
  134. Inc(PWideRec(S2-WideFirstOff)^.ref);
  135. { Decrease the reference count on the old S1 }
  136. widestr_decr_ref (S1);
  137. { And finally, have S1 pointing to S2 (or its copy) }
  138. S1:=S2;
  139. end;
  140. Procedure WideStr_Concat (S1,S2 : Pointer;var S3 : Pointer);[Public, alias: 'FPC_WIDESTR_CONCAT'];
  141. {
  142. Concatenates 2 WideStrings : S1+S2.
  143. Result Goes to S3;
  144. }
  145. Var
  146. Size,Location : Longint;
  147. begin
  148. { create new result }
  149. if S3<>nil then
  150. WideStr_Decr_Ref(S3);
  151. { only assign if s1 or s2 is empty }
  152. if (S1=Nil) then
  153. WideStr_Assign(S3,S2)
  154. else
  155. if (S2=Nil) then
  156. WideStr_Assign(S3,S1)
  157. else
  158. begin
  159. Size:=PWideRec(S2-WideFirstOff)^.Len;
  160. Location:=Length(WideString(S1));
  161. SetLength (WideString(S3),Size+Location);
  162. Move (S1^,S3^,Location);
  163. Move (S2^,(S3+location)^,Size+1);
  164. end;
  165. end;
  166. (* !!!:
  167. Procedure Char_To_WideStr(var S1 : Pointer; c : Char);[Public, alias: 'FPC_CHAR_TO_WIDESTR'];
  168. {
  169. Converts a ShortString to a WideString;
  170. }
  171. begin
  172. Setlength (WideString(S1),1);
  173. PByte(Pointer(S1))^:=byte(c);
  174. { Terminating Zero }
  175. PByte(Pointer(S1)+1)^:=0;
  176. end;
  177. Procedure PChar_To_WideStr(var a : widestring;p : pchar);[Public,Alias : 'FPC_PCHAR_TO_WIDESTR'];
  178. Var
  179. L : Longint;
  180. begin
  181. if pointer(a)<>nil then
  182. begin
  183. WideStr_Decr_Ref(Pointer(a));
  184. pointer(a):=nil;
  185. end;
  186. if (not assigned(p)) or (p[0]=#0) Then
  187. Pointer(a):=nil
  188. else
  189. begin
  190. //!! Horribly inneficient, but I see no other way...
  191. L:=1;
  192. While P[l]<>#0 do
  193. inc (l);
  194. Pointer(a):=NewWidestring(L);
  195. SetLength(A,L);
  196. Move (P[0],Pointer(A)^,L)
  197. end;
  198. end;
  199. Procedure CharArray_To_WideStr(var a : widestring;p : pchar;l:longint);[Public,Alias : 'FPC_CHARARRAY_TO_WIDESTR'];
  200. var
  201. i : longint;
  202. hp : pchar;
  203. begin
  204. if p[0]=#0 Then
  205. Pointer(a):=nil
  206. else
  207. begin
  208. Pointer(a):=NewWidestring(L);
  209. hp:=p;
  210. i:=0;
  211. while (i<l) and (hp^<>#0) do
  212. begin
  213. inc(hp);
  214. inc(i);
  215. end;
  216. SetLength(A,i);
  217. Move (P[0],Pointer(A)^,i)
  218. end;
  219. end;
  220. *)
  221. Function WideStr_Compare(S1,S2 : Pointer): Longint;[Public,Alias : 'FPC_WIDESTR_COMPARE'];
  222. {
  223. Compares 2 WideStrings;
  224. The result is
  225. <0 if S1<S2
  226. 0 if S1=S2
  227. >0 if S1>S2
  228. }
  229. Var
  230. i,MaxI,Temp : Longint;
  231. begin
  232. i:=0;
  233. Maxi:=Length(WideString(S1));
  234. temp:=Length(WideString(S2));
  235. If MaxI>Temp then
  236. MaxI:=Temp;
  237. Temp:=0;
  238. While (i<MaxI) and (Temp=0) do
  239. begin
  240. Temp:= PWord(S1+I)^ - PWord(S2+i)^;
  241. inc(i);
  242. end;
  243. if temp=0 then
  244. temp:=Length(WideString(S1))-Length(WideString(S2));
  245. WideStr_Compare:=Temp;
  246. end;
  247. Procedure WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO'];
  248. begin
  249. if p=nil then
  250. HandleErrorFrame(201,get_frame);
  251. end;
  252. Procedure WideStr_CheckRange(len,index : longint);[Public,Alias : 'FPC_WIDESTR_RANGECHECK'];
  253. begin
  254. if (index>len) or (Index<1) then
  255. HandleErrorFrame(201,get_frame);
  256. end;
  257. {$ifndef INTERNSETLENGTH}
  258. Procedure SetLength (Var S : WideString; l : Longint);
  259. {$else INTERNSETLENGTH}
  260. Procedure WideStr_SetLength (Var S : WideString; l : Longint);[Public,Alias : 'FPC_WIDESTR_SETLENGTH'];
  261. {$endif INTERNSETLENGTH}
  262. {
  263. Sets The length of string S to L.
  264. Makes sure S is unique, and contains enough room.
  265. }
  266. Var
  267. Temp : Pointer;
  268. begin
  269. if (l>0) then
  270. begin
  271. if Pointer(S)=nil then
  272. begin
  273. { Need a complete new string...}
  274. Pointer(s):=NewWideString(l);
  275. end
  276. else
  277. If (PWideRec(Pointer(S)-WideFirstOff)^.Maxlen < L) or
  278. (PWideRec(Pointer(S)-WideFirstOff)^.Ref <> 1) then
  279. begin
  280. { Reallocation is needed... }
  281. Temp:=Pointer(NewWideString(L));
  282. if Length(S)>0 then
  283. Move(Pointer(S)^,Temp^,L+L);
  284. ansistr_decr_ref(Pointer(S));
  285. Pointer(S):=Temp;
  286. end;
  287. { Force nil termination in case it gets shorter }
  288. PByte(Pointer(S)+l)^:=0;
  289. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l;
  290. end
  291. else
  292. begin
  293. { Length=0 }
  294. if Pointer(S)<>nil then
  295. ansistr_decr_ref (Pointer(S));
  296. Pointer(S):=Nil;
  297. end;
  298. end;
  299. {*****************************************************************************
  300. Public functions, In interface.
  301. *****************************************************************************}
  302. Function Length (Const S : WideString) : Longint;
  303. {
  304. Returns the length of an WideString.
  305. Takes in acount that zero strings are NIL;
  306. }
  307. begin
  308. If Pointer(S)=Nil then
  309. Length:=0
  310. else
  311. Length:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  312. end;
  313. Procedure UniqueString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE'];
  314. {
  315. Make sure reference count of S is 1,
  316. using copy-on-write semantics.
  317. }
  318. Var
  319. SNew : Pointer;
  320. begin
  321. If Pointer(S)=Nil then
  322. exit;
  323. if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then
  324. begin
  325. SNew:=NewWideString (PWideRec(Pointer(S)-WideFirstOff)^.len);
  326. Move (Pointer(S)^,SNew^,(PWideRec(Pointer(S)-WideFirstOff)^.len+1)*2);
  327. PWideRec(SNew-WideFirstOff)^.len:=PWideRec(Pointer(S)-WideFirstOff)^.len;
  328. ansistr_decr_ref (Pointer(S)); { Thread safe }
  329. Pointer(S):=SNew;
  330. end;
  331. end;
  332. Function Copy (Const S : WideString; Index,Size : Longint) : WideString;
  333. var
  334. ResultAddress : Pointer;
  335. begin
  336. ResultAddress:=Nil;
  337. dec(index);
  338. if Index < 0 then
  339. Index := 0;
  340. { Check Size. Accounts for Zero-length S, the double check is needed because
  341. Size can be maxint and will get <0 when adding index }
  342. if (Size>Length(S)) or
  343. (Index+Size>Length(S)) then
  344. Size:=Length(S)-Index;
  345. If Size>0 then
  346. begin
  347. If Index<0 Then
  348. Index:=0;
  349. ResultAddress:=Pointer(NewWideString (Size));
  350. if ResultAddress<>Nil then
  351. begin
  352. Move (Pointer(Pointer(S)+index)^,ResultAddress^,Size*2);
  353. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size;
  354. PWord(ResultAddress+Size*2)^:=0;
  355. end;
  356. end;
  357. Pointer(Copy):=ResultAddress;
  358. end;
  359. Function Pos (Const Substr : WideString; Const Source : WideString) : Longint;
  360. var
  361. substrlen,
  362. maxi,
  363. i,j : longint;
  364. e : boolean;
  365. { S : WideString;
  366. se : Pointer; }
  367. begin
  368. i := 0;
  369. j := 0;
  370. substrlen:=Length(SubStr);
  371. maxi:=length(source)-substrlen;
  372. e:=(substrlen>0);
  373. while (e) and (i <= maxi) do
  374. begin
  375. inc (i);
  376. {!!!: if Source[i]=SubStr[1] then
  377. begin
  378. S:=copy(Source,i,substrlen);
  379. Se:=pointer(SubStr);
  380. if WideStr_Compare(se,Pointer(S))=0 then
  381. begin
  382. j := i;
  383. break;
  384. end;
  385. end;}
  386. end;
  387. pos := j;
  388. end;
  389. Procedure Delete (Var S : WideString; Index,Size: Longint);
  390. Var
  391. LS : Longint;
  392. begin
  393. If Length(S)=0 then
  394. exit;
  395. if index<=0 then
  396. begin
  397. inc(Size,index-1);
  398. index:=1;
  399. end;
  400. LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  401. if (Index<=LS) and (Size>0) then
  402. begin
  403. UniqueString (S);
  404. if Size+Index>LS then
  405. Size:=LS-Index+1;
  406. if Index+Size<=LS then
  407. begin
  408. Dec(Index);
  409. Move(PByte(Pointer(S))[Index+Size],PByte(Pointer(S))[Index],(LS-Index+1)*2);
  410. end;
  411. Setlength(s,LS-Size);
  412. end;
  413. end;
  414. Procedure Insert (Const Source : WideString; Var S : WideString; Index : Longint);
  415. var
  416. Temp : WideString;
  417. LS : Longint;
  418. begin
  419. If Length(Source)=0 then
  420. exit;
  421. if index <= 0 then
  422. index := 1;
  423. Ls:=Length(S);
  424. if index > LS then
  425. index := LS+1;
  426. Dec(Index);
  427. Pointer(Temp) := NewWideString(Length(Source)+LS);
  428. SetLength(Temp,Length(Source)+LS);
  429. If Index>0 then
  430. move (Pointer(S)^,Pointer(Temp)^,Index*2);
  431. Move (Pointer(Source)^,PByte(Temp)[Index],Length(Source)*2);
  432. If (LS-Index)>0 then
  433. Move(PByte(Pointer(S))[Index],PByte(temp)[Length(Source)+index],(LS-Index)*2);
  434. S:=Temp;
  435. end;
  436. {!!!:Procedure SetString (Var S : WideString; Buf : PWideChar; Len : Longint);
  437. begin
  438. SetLength(S,Len);
  439. Move (Buf[0],S[1],Len*2);
  440. end;}
  441. {
  442. $Log$
  443. Revision 1.6 2000-11-06 23:17:15 peter
  444. * removed some warnings
  445. Revision 1.5 2000/11/06 20:34:24 peter
  446. * changed ver1_0 defines to temporary defs
  447. Revision 1.4 2000/10/21 18:20:17 florian
  448. * a lot of small changes:
  449. - setlength is internal
  450. - win32 graph unit extended
  451. ....
  452. Revision 1.3 2000/08/08 22:12:36 sg
  453. * Implemented WideString helper functions (but they are not tested yet
  454. due to the lack of full compiler support for WideString/WideChar!)
  455. Revision 1.2 2000/07/13 11:33:46 michael
  456. + removed logs
  457. }