wstrings.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. {*****************************************************************************
  258. Public functions, In interface.
  259. *****************************************************************************}
  260. Function Length (Const S : WideString) : Longint;
  261. {
  262. Returns the length of an WideString.
  263. Takes in acount that zero strings are NIL;
  264. }
  265. begin
  266. If Pointer(S)=Nil then
  267. Length:=0
  268. else
  269. Length:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  270. end;
  271. Procedure SetLength (Var S : WideString; l : Longint);
  272. {
  273. Sets The length of string S to L.
  274. Makes sure S is unique, and contains enough room.
  275. }
  276. Var
  277. Temp : Pointer;
  278. begin
  279. if (l>0) then
  280. begin
  281. if Pointer(S)=nil then
  282. begin
  283. { Need a complete new string...}
  284. Pointer(s):=NewWideString(l);
  285. end
  286. else
  287. If (PWideRec(Pointer(S)-WideFirstOff)^.Maxlen < L) or
  288. (PWideRec(Pointer(S)-WideFirstOff)^.Ref <> 1) then
  289. begin
  290. { Reallocation is needed... }
  291. Temp:=Pointer(NewWideString(L));
  292. if Length(S)>0 then
  293. Move(Pointer(S)^,Temp^,L+L);
  294. ansistr_decr_ref(Pointer(S));
  295. Pointer(S):=Temp;
  296. end;
  297. { Force nil termination in case it gets shorter }
  298. PByte(Pointer(S)+l)^:=0;
  299. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l;
  300. end
  301. else
  302. begin
  303. { Length=0 }
  304. if Pointer(S)<>nil then
  305. ansistr_decr_ref (Pointer(S));
  306. Pointer(S):=Nil;
  307. end;
  308. end;
  309. Procedure UniqueString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE'];
  310. {
  311. Make sure reference count of S is 1,
  312. using copy-on-write semantics.
  313. }
  314. Var
  315. SNew : Pointer;
  316. begin
  317. If Pointer(S)=Nil then
  318. exit;
  319. if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then
  320. begin
  321. SNew:=NewWideString (PWideRec(Pointer(S)-WideFirstOff)^.len);
  322. Move (Pointer(S)^,SNew^,(PWideRec(Pointer(S)-WideFirstOff)^.len+1)*2);
  323. PWideRec(SNew-WideFirstOff)^.len:=PWideRec(Pointer(S)-WideFirstOff)^.len;
  324. ansistr_decr_ref (Pointer(S)); { Thread safe }
  325. Pointer(S):=SNew;
  326. end;
  327. end;
  328. Function Copy (Const S : WideString; Index,Size : Longint) : WideString;
  329. var
  330. ResultAddress : Pointer;
  331. begin
  332. ResultAddress:=Nil;
  333. dec(index);
  334. if Index < 0 then
  335. Index := 0;
  336. { Check Size. Accounts for Zero-length S, the double check is needed because
  337. Size can be maxint and will get <0 when adding index }
  338. if (Size>Length(S)) or
  339. (Index+Size>Length(S)) then
  340. Size:=Length(S)-Index;
  341. If Size>0 then
  342. begin
  343. If Index<0 Then
  344. Index:=0;
  345. ResultAddress:=Pointer(NewWideString (Size));
  346. if ResultAddress<>Nil then
  347. begin
  348. Move (Pointer(Pointer(S)+index)^,ResultAddress^,Size*2);
  349. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size;
  350. PWord(ResultAddress+Size*2)^:=0;
  351. end;
  352. end;
  353. Pointer(Copy):=ResultAddress;
  354. end;
  355. Function Pos (Const Substr : WideString; Const Source : WideString) : Longint;
  356. var
  357. substrlen,
  358. maxi,
  359. i,j : longint;
  360. e : boolean;
  361. S : WideString;
  362. se : Pointer;
  363. begin
  364. i := 0;
  365. j := 0;
  366. substrlen:=Length(SubStr);
  367. maxi:=length(source)-substrlen;
  368. e:=(substrlen>0);
  369. while (e) and (i <= maxi) do
  370. begin
  371. inc (i);
  372. {!!!: if Source[i]=SubStr[1] then
  373. begin
  374. S:=copy(Source,i,substrlen);
  375. Se:=pointer(SubStr);
  376. if WideStr_Compare(se,Pointer(S))=0 then
  377. begin
  378. j := i;
  379. break;
  380. end;
  381. end;}
  382. end;
  383. pos := j;
  384. end;
  385. Procedure Delete (Var S : WideString; Index,Size: Longint);
  386. Var
  387. LS : Longint;
  388. begin
  389. If Length(S)=0 then
  390. exit;
  391. if index<=0 then
  392. begin
  393. inc(Size,index-1);
  394. index:=1;
  395. end;
  396. LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len;
  397. if (Index<=LS) and (Size>0) then
  398. begin
  399. UniqueString (S);
  400. if Size+Index>LS then
  401. Size:=LS-Index+1;
  402. if Index+Size<=LS then
  403. begin
  404. Dec(Index);
  405. Move(PByte(Pointer(S))[Index+Size],PByte(Pointer(S))[Index],(LS-Index+1)*2);
  406. end;
  407. Setlength(s,LS-Size);
  408. end;
  409. end;
  410. Procedure Insert (Const Source : WideString; Var S : WideString; Index : Longint);
  411. var
  412. Temp : WideString;
  413. LS : Longint;
  414. begin
  415. If Length(Source)=0 then
  416. exit;
  417. if index <= 0 then
  418. index := 1;
  419. Ls:=Length(S);
  420. if index > LS then
  421. index := LS+1;
  422. Dec(Index);
  423. Pointer(Temp) := NewWideString(Length(Source)+LS);
  424. SetLength(Temp,Length(Source)+LS);
  425. If Index>0 then
  426. move (Pointer(S)^,Pointer(Temp)^,Index*2);
  427. Move (Pointer(Source)^,PByte(Temp)[Index],Length(Source)*2);
  428. If (LS-Index)>0 then
  429. Move(PByte(Pointer(S))[Index],PByte(temp)[Length(Source)+index],(LS-Index)*2);
  430. S:=Temp;
  431. end;
  432. {!!!:Procedure SetString (Var S : WideString; Buf : PWideChar; Len : Longint);
  433. begin
  434. SetLength(S,Len);
  435. Move (Buf[0],S[1],Len*2);
  436. end;}
  437. {
  438. $Log$
  439. Revision 1.3 2000-08-08 22:12:36 sg
  440. * Implemented WideString helper functions (but they are not tested yet
  441. due to the lack of full compiler support for WideString/WideChar!)
  442. Revision 1.2 2000/07/13 11:33:46 michael
  443. + removed logs
  444. }