astrings.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by Michael Van Canneyt,
  5. member of the Free Pascal development team.
  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. { ---------------------------------------------------------------------
  13. This file implements AnsiStrings for FPC
  14. ---------------------------------------------------------------------}
  15. {
  16. This file contains the implementation of the LongString type,
  17. and all things that are needed for it.
  18. AnsiSTring is defined as a 'silent' pchar :
  19. a pchar that points to :
  20. @-12 : Longint for maximum size;
  21. @-8 : Longint for size;
  22. @-4 : Longint for reference count;
  23. @ : String + Terminating #0;
  24. Pchar(Ansistring) is a valid typecast.
  25. So AS[i] is converted to the address @AS+i-1.
  26. Constants should be assigned a reference count of -1
  27. Meaning that they can't be disposed of.
  28. }
  29. Type shortstring=string;
  30. Function NewAnsiString (Len : Longint) : AnsiString; forward;
  31. Procedure DisposeAnsiString (Var S : AnsiString); forward;
  32. Procedure Decr_Ansi_Ref (Var S : AnsiString); forward;
  33. Procedure Incr_Ansi_Ref (Var S : AnsiString); forward;
  34. Procedure AssignAnsiString (Var S1 : AnsiString; S2 : AnsiString);
  35. Procedure Ansi_String_Concat (Var S1 : AnsiString; Const S2 : AnsiString); forward;
  36. Procedure Ansi_ShortString_Concat (Var S1: AnsiString; Const S2 : ShortString); forward;
  37. Procedure Ansi_To_ShortString (Var S1 : ShortString; Const S2 : AnsiString; maxlen : longint); forward;
  38. Procedure Short_To_AnsiString (Var S1 : AnsiString; Const S2 : ShortString); forward;
  39. Function AnsiCompare (Const S1,S2 : AnsiString): Longint; forward;
  40. Function AnsiCompare (Const S1 : AnsiString; Const S2 : ShortString): Longint; forward;
  41. Procedure SetCharAtIndex (Var S : AnsiString; Index : Longint; C : CHar); forward;
  42. { Public functions, Will end up in systemh.inc }
  43. {$PACKRECORDS 1}
  44. Type TAnsiRec = Record
  45. Maxlen, len, ref : Longint;
  46. First : Char;
  47. end;
  48. PAnsiRec = ^TAnsiRec;
  49. PLongint = ^Longint;
  50. PByte = ^Byte;
  51. Const AnsiRecLen = SizeOf(TAnsiRec);
  52. FirstOff = SizeOf(TAnsiRec)-1;
  53. { ---------------------------------------------------------------------
  54. Internal functions, not in interface.
  55. ---------------------------------------------------------------------}
  56. Procedure DumpAnsiRec ( S : Ansistring);
  57. begin
  58. If Pointer(S)=Nil then
  59. Writeln ('String is nil')
  60. Else
  61. Begin
  62. Dec (Longint(S),FirstOff);
  63. With PansiRec(S)^ do
  64. begin
  65. Writeln ('MAxlen : ',maxlen);
  66. Writeln ('Len : ',len);
  67. Writeln ('Ref : ',ref);
  68. end;
  69. end;
  70. end;
  71. Function NewAnsiString (Len : Longint) : AnsiString;
  72. {
  73. Allocate a new AnsiString on the heap.
  74. initialize it to zero length and reference count 1.
  75. }
  76. Var P : Pointer;
  77. begin
  78. GetMem(P,Len+AnsiRecLen);
  79. If P<>Nil then
  80. begin
  81. PAnsiRec(P)^.Maxlen:=Len; { Maximal length }
  82. PAnsiRec(P)^.Len:=0; { Initial length }
  83. PAnsiRec(P)^.Ref:=1; { Set reference count }
  84. PAnsiRec(P)^.First:=#0; { Terminating #0 }
  85. P:=P+FirstOff; { Points to string now }
  86. end;
  87. //!! NewAnsiString:=P;
  88. end;
  89. Procedure DisposeAnsiString (Var S : AnsiString);
  90. {
  91. Deallocates a AnsiString From the heap.
  92. }
  93. begin
  94. If Pointer(S)=Nil then exit;
  95. Dec (Longint(S),FirstOff);
  96. //!! FreeMem (S,PAnsiRec(Pointer(S))^.Maxlen+AnsiRecLen);
  97. //!! Pointer(S):=Nil;
  98. end;
  99. Procedure Decr_Ansi_Ref (Var S : AnsiString);[Alias : 'DECR_ANSI_REF'];
  100. {
  101. Decreases the ReferenceCount of a non constant ansistring;
  102. If the reference count is zero, deallocate the string;
  103. }
  104. Begin
  105. If Pointer(S)=Nil then exit; { Zero string }
  106. { check for constant strings ...}
  107. If PansiRec(Pointer(S)-FirstOff)^.Ref<0 then exit;
  108. Dec(PAnsiRec(Pointer(S)-FirstOff)^.Ref);
  109. If PAnsiRec(Pointer(S)-FirstOff)^.Ref=0 then
  110. { Ref count dropped to zero }
  111. DisposeAnsiString (S); { Remove...}
  112. end;
  113. Procedure Incr_Ansi_Ref (Var S : AnsiString);[Alias : 'INCR_ANSI_REF'];
  114. Begin
  115. If Pointer(S)=Nil then exit;
  116. { Let's be paranoid : Constant string ??}
  117. If PansiRec(Pointer(S)-FirstOff)^.Ref<0 then exit;
  118. inc(PAnsiRec(Pointer(S)-FirstOff)^.Ref);
  119. end;
  120. Procedure UniqueAnsiString (Var S : AnsiString);
  121. {
  122. Make sure reference count of S is 1,
  123. using copy-on-write semantics.
  124. }
  125. Var SNew : Pointer;
  126. begin
  127. If Pointer(S)=Nil then exit;
  128. if PAnsiRec(Pointer(S)-Firstoff)^.Ref>1 then
  129. begin
  130. SNew:=Pointer(NewAnsiString (PAnsiRec(Pointer(S)-FirstOff)^.len));
  131. Move (Pointer(S)^,SNew^,PAnsiRec(Pointer(S)-FirstOff)^.len+1);
  132. PAnsiRec(SNew-8)^.len:=PAnsiRec(Pchar(S)-FirstOff)^.len;
  133. Decr_Ansi_Ref (S); { Thread safe }
  134. Pchar(S):=Pchar(SNew);
  135. end;
  136. end;
  137. Procedure AssignAnsiString (Var S1 : AnsiString; S2 : AnsiString); [Public, Alias : 'ASSIGN_ANSI_STRING'];
  138. {
  139. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  140. If S2 is a constant string, a new S1 is allocated on the heap.
  141. }
  142. Var Temp : Pointer;
  143. begin
  144. If Pointer(S2)<>nil then
  145. begin
  146. If PAnsiRec(Pointer(S2)-FirstOff)^.Ref<0 then
  147. begin
  148. { S2 is a constant string, Create new string with copy. }
  149. Temp:=Pointer(NewAnsiString(PansiRec(Pointer(S2)-FirstOff)^.Len));
  150. Move (Pointer(S2)^,Temp^,PAnsiRec(Pointer(S2)-FirstOff)^.len+1);
  151. PAnsiRec(Temp-FirstOff)^.Len:=PAnsiRec(Pointer(S2)-FirstOff)^.len;
  152. //!! S2:=Temp;
  153. end
  154. else
  155. Inc(PAnsiRec(Pointer(S2)-FirstOff)^.ref)
  156. end;
  157. { Decrease the reference count on the old S1 }
  158. Decr_Ansi_Ref (S1);
  159. { And finally, have S1 pointing to S2 (or its copy) }
  160. //!! Pointer(S1):=Pointer(S2);
  161. end;
  162. Procedure Ansi_String_Concat (Var S1 : AnsiString; Const S2 : AnsiString);
  163. {
  164. Concatenates 2 AnsiStrings : S1+S2.
  165. Result Goes to S1;
  166. }
  167. Var Size,Location : Longint;
  168. begin
  169. if Pointer(S2)=Nil then exit;
  170. if (Pointer(S1)=Nil) then
  171. AssignAnsiString(S1,S2)
  172. else
  173. begin
  174. Size:=PAnsiRec(Pointer(S2)-FirstOff)^.Len;
  175. Location:=Length(S1);
  176. { Setlength takes case of uniqueness
  177. and allocated memory. We need to use length,
  178. to take into account possibility of S1=Nil }
  179. //!! SetLength (S1,Size+Location);
  180. Move (Pointer(S2)^,Pointer(Pointer(S1)+location)^,Size+1);
  181. end;
  182. end;
  183. Procedure Ansi_ShortString_Concat (Var S1: AnsiString; Const S2 : ShortString);
  184. {
  185. Concatenates a Ansi with a short string; : S2 + S2
  186. }
  187. Var Size,Location : Longint;
  188. begin
  189. Size:=byte(S2[0]);
  190. Location:=Length(S1);
  191. If Size=0 then exit;
  192. { Setlength takes case of uniqueness
  193. and alllocated memory. We need to use length,
  194. to take into account possibility of S1=Nil }
  195. SetLength (S1,Size+Length(S1));
  196. Move (S2[1],Pointer(Pointer(S1)+Location)^,Size);
  197. PByte( Pointer(S1)+length(S1) )^:=0; { Terminating Zero }
  198. end;
  199. Procedure Ansi_To_ShortString (Var S1 : ShortString; Const S2 : AnsiString; Maxlen : Longint);
  200. {
  201. Converts a AnsiString to a ShortString;
  202. if maxlen<>-1, the resulting string has maximal length maxlen
  203. else a default length of 255 is taken.
  204. }
  205. Var Size : Longint;
  206. begin
  207. Size:=PAnsiRec(Pointer(S2)-FirstOff)^.Len;
  208. if maxlen=-1 then maxlen:=255;
  209. If Size>maxlen then Size:=maxlen;
  210. Move (Pointer(S2)^,S1[1],Size);
  211. byte(S1[0]):=Size;
  212. end;
  213. Procedure Short_To_AnsiString (Var S1 : AnsiString; Const S2 : ShortString);
  214. {
  215. Converts a ShortString to a AnsiString;
  216. }
  217. Var Size : Longint;
  218. begin
  219. Size:=Byte(S2[0]);
  220. Setlength (S1,Size);
  221. Move (S2[1],Pointer(S1)^,Size);
  222. PByte(Pointer(S1)+Size)^:=0; { Terminating Zero }
  223. end;
  224. Function AnsiCompare (Const S1,S2 : AnsiString): Longint;
  225. {
  226. Compares 2 AnsiStrings;
  227. The result is
  228. <0 if S1<S2
  229. 0 if S1=S2
  230. >0 if S1>S2
  231. }
  232. Var i,MaxI,Temp : Longint;
  233. begin
  234. Temp:=0;
  235. i:=0;
  236. MaxI:=Length(S1);
  237. if MaxI>Length(S2) then MaxI:=Length(S2);
  238. While (i<MaxI) and (Temp=0) do
  239. begin
  240. Temp:= PByte(Pointer(S1)+I)^ - PByte(Pointer(S2)+i)^;
  241. inc(i);
  242. end;
  243. if temp=0 then temp:=Length(S1)-Length(S2);
  244. AnsiCompare:=Temp;
  245. end;
  246. Function AnsiCompare (Const S1 : AnsiString; Const S2 : ShortString): Longint;
  247. {
  248. Compares a AnsiString with a ShortString;
  249. The result is
  250. <0 if S1<S2
  251. 0 if S1=S2
  252. >0 if S1>S2
  253. }
  254. Var i,MaxI,Temp : Longint;
  255. begin
  256. Temp:=0;
  257. i:=0;
  258. MaxI:=Length(S1);
  259. if MaxI>byte(S2[0]) then MaxI:=Byte(S2[0]);
  260. While (i<MaxI) and (Temp=0) do
  261. begin
  262. Temp:= PByte(Pointer(S1)+I)^ - Byte(S2[i+1]);
  263. inc(i);
  264. end;
  265. AnsiCompare:=Temp;
  266. end;
  267. Procedure Write_Text_AnsiString (Len : Longint; T : TextRec; Var S : AnsiString);[Public, alias 'WRITE_TEXT_ANSISTRING'];
  268. {
  269. Writes a AnsiString to the Text file T
  270. }
  271. begin
  272. end;
  273. Procedure SetCharAtIndex (Var S : AnsiString; Index : Longint; C : CHar);
  274. begin
  275. if Index<=Length(S) then
  276. begin
  277. UniqueAnsiString(S);
  278. Pbyte(Pointer(S)+index-1)^:=Byte(C);
  279. end;
  280. end;
  281. { ---------------------------------------------------------------------
  282. Public functions, In interface.
  283. ---------------------------------------------------------------------}
  284. Function Length (Const S : AnsiString) : Longint;
  285. {
  286. Returns the length of an AnsiString.
  287. Takes in acount that zero strings are NIL;
  288. }
  289. begin
  290. If Pointer(S)=Nil then
  291. Length:=0
  292. else
  293. Length:=PAnsiRec(Pointer(S)-FirstOff)^.Len;
  294. end;
  295. Procedure SetLength (Var S : AnsiString; l : Longint);
  296. {
  297. Sets The length of string S to L.
  298. Makes sure S is unique, and contains enough room.
  299. }
  300. Var Temp : Pointer;
  301. begin
  302. If (S=Nil) and (l>0) then
  303. begin
  304. { Need a complete new string...}
  305. S:=NewAnsiString(l);
  306. PAnsiRec(Pointer(S)-FirstOff)^.Len:=l;
  307. PAnsiRec(Pointer(S)-FirstOff)^.Len:=l;
  308. PByte (Pointer(S)+l)^:=0;
  309. end
  310. else if l>0 then
  311. begin
  312. If (PAnsiRec(Pointer(S)-FirstOff)^.Maxlen < L) or
  313. (PAnsiRec(Pointer(S)-FirstOff)^.Ref <> 1) then
  314. begin
  315. { Reallocation is needed... }
  316. Temp:=Pointer(NewAnsiString(L));
  317. if Length(S)>0 then
  318. Move (S^,Temp^,Length(S)+1);
  319. Decr_Ansi_ref (S);
  320. S:=Temp;
  321. end;
  322. PAnsiRec(Pointer(S)-FirstOff)^.Len:=l
  323. end
  324. else
  325. { Length=0 }
  326. begin
  327. Decr_Ansi_Ref (S);
  328. S:=Nil;
  329. end;
  330. end;
  331. Function Copy (Const S : AnsiString; Index,Size : Longint) : AnsiString;
  332. var ResultAddress : Pointer;
  333. begin
  334. ResultAddress:=Nil;
  335. dec(index);
  336. { Check Size. Accounts for Zero-length S }
  337. if Length(S)<Index+Size then
  338. Size:=Length(S)-Index;
  339. If Size>0 then
  340. begin
  341. ResultAddress:=Pointer(NewAnsiString (Size));
  342. if ResultAddress<>Nil then
  343. begin
  344. Move (Pointer(Pointer(S)+index)^,ResultAddress^,Size);
  345. PAnsiRec(ResultAddress-FirstOff)^.Len:=Size;
  346. PByte(ResultAddress+Size)^:=0;
  347. end;
  348. end;
  349. Copy:=ResultAddress;
  350. end;
  351. Function Pos (Const Substr : AnsiString; Const Source : AnsiString) : Longint;
  352. var i,j : longint;
  353. e : boolean;
  354. s : Pointer;
  355. begin
  356. i := 0;
  357. j := 0;
  358. e := true;
  359. if Plongint(substr)^=0 then e := false;
  360. while (e) and (i <= length (Source) - length (substr)) do
  361. begin
  362. inc (i);
  363. S:=Pointer(copy(Source,i,length(Substr)));
  364. if AnsiCompare(substr,s)=0 then
  365. begin
  366. j := i;
  367. e := false;
  368. end;
  369. DisposeAnsiString(AnsiString(S));
  370. end;
  371. pos := j;
  372. end;
  373. Procedure Val (Const S : AnsiString; var R : real; Var Code : Integer);
  374. Var SS : String;
  375. begin
  376. Ansi_To_ShortString (SS,S,255);
  377. System.Val(SS,R,Code);
  378. end;
  379. {
  380. Procedure Val (Const S : AnsiString; var D : Double; Var Code : Integer);
  381. Var SS : ShortString;
  382. begin
  383. Ansi_To_ShortString (SS,S,255);
  384. Val(SS,D,Code);
  385. end;
  386. }
  387. Procedure Val (Const S : AnsiString; var E : Extended; Code : Integer);
  388. Var SS : ShortString;
  389. begin
  390. Ansi_To_ShortString (SS,S,255);
  391. System.Val(SS,E,Code);
  392. end;
  393. Procedure Val (Const S : AnsiString; var C : Cardinal; Code : Integer);
  394. Var SS : ShortString;
  395. begin
  396. Ansi_To_ShortString (SS,S,255);
  397. System.Val(SS,C,Code);
  398. end;
  399. Procedure Val (Const S : AnsiString; var L : Longint; Var Code : Integer);
  400. Var SS : ShortString;
  401. begin
  402. Ansi_To_ShortString (SS,S,255);
  403. System.Val(SS,L,Code);
  404. end;
  405. Procedure Val (Const S : AnsiString; var W : Word; Var Code : Integer);
  406. Var SS : ShortString;
  407. begin
  408. Ansi_To_ShortString (SS,S,255);
  409. System.Val(SS,W,Code);
  410. end;
  411. Procedure Val (Const S : AnsiString; var I : Integer; Var Code : Integer);
  412. Var SS : ShortString;
  413. begin
  414. Ansi_To_ShortString (SS,S,255);
  415. System.Val(SS,I,Code);
  416. end;
  417. Procedure Val (Const S : AnsiString; var B : Byte; Var Code : Integer);
  418. Var SS : ShortString;
  419. begin
  420. Ansi_To_ShortString (SS,S,255);
  421. System.Val(SS,B,Code);
  422. end;
  423. Procedure Val (Const S : AnsiString; var SI : ShortInt; Var Code : Integer);
  424. Var SS : ShortString;
  425. begin
  426. Ansi_To_ShortString (SS,S,255);
  427. System.Val(SS,SI,Code);
  428. end;
  429. Procedure Str (Const R : Real;Len,fr : Longint; Var S : AnsiString);
  430. Var SS : ShortString;
  431. begin
  432. {int_Str_Real (R,Len,fr,SS);}
  433. Short_To_AnsiString (S,SS);
  434. end;
  435. {
  436. Procedure Str (Const D : Double;Len,fr: Longint; Var S : AnsiString);
  437. Var SS : ShortString;
  438. begin
  439. {int_Str_Double (D,Len,fr,SS);}
  440. Short_To_AnsiString (S,SS);
  441. end;
  442. }
  443. Procedure Str (Const E : Extended;Lenf,Fr: Longint; Var S : AnsiString);
  444. Var SS : ShortString;
  445. begin
  446. {int_Str_Extended (E,Len,fr,SS);}
  447. Short_To_AnsiString (S,SS);
  448. end;
  449. Procedure Str (Const C : Cardinal;Len : Longint; Var S : AnsiString);
  450. begin
  451. end;
  452. Procedure Str (Const L : Longint; Len : Longint; Var S : AnsiString);
  453. Var SS : ShortString;
  454. begin
  455. {int_Str_Longint (L,Len,fr,SS);}
  456. Short_To_AnsiString (S,SS);
  457. end;
  458. Procedure Str (Const W : Word;Len : Longint; Var S : AnsiString);
  459. begin
  460. end;
  461. Procedure Str (Const I : Integer;Len : Longint; Var S : AnsiString);
  462. begin
  463. end;
  464. Procedure Str (Const B : Byte; Len : Longint; Var S : AnsiString);
  465. begin
  466. end;
  467. Procedure Str (Const SI : ShortInt; Len : Longint; Var S : AnsiString);
  468. begin
  469. end;
  470. Procedure Delete (Var S : AnsiString; Index,Size: Longint);
  471. begin
  472. if index<=0 then
  473. begin
  474. Size:=Size+index-1;
  475. index:=1;
  476. end;
  477. if (Index<=length(s)) and (Size>0) then
  478. begin
  479. UniqueAnsiString (S);
  480. if Size+Index>Length(S) then
  481. Size:=Length(s)-Index+1;
  482. Setlength(s,Length(s)-Size);
  483. if Index<=Length(s) then
  484. Move(Pointer(Pointer(S)+Index+Size-1)^,
  485. Pointer(Pointer(s)+Index-1)^,Length(s)-Index+2)
  486. else
  487. Pbyte(Pointer(S)+Length(S))^:=0;
  488. end;
  489. end;
  490. Procedure Insert (Const Source : AnsiString; Var S : AnsiString; Index : Longint);
  491. var s3,s4 : Pointer;
  492. begin
  493. If Length(Source)=0 then exit;
  494. if index <= 0 then index := 1;
  495. s3 := Pointer(copy(s,index,length(s)));
  496. if index > Length(s) then
  497. index := Length(S)+1;
  498. SetLength(s,index - 1);
  499. s4 := Pointer ( NewAnsiString(PansiRec(Pointer(Source)-Firstoff)^.len) );
  500. Ansi_String_Concat(AnsiString(s4),Source);
  501. if S4<>Nil then
  502. Ansi_String_Concat(AnsiString(S4),AnsiString(s3));
  503. Ansi_String_Concat(S,AnsiString(S4));
  504. Decr_ansi_ref (AnsiString(S3));
  505. Decr_ansi_ref (AnsiString(S4));
  506. end;
  507. {
  508. $Log$
  509. Revision 1.7 1998-07-06 14:29:08 michael
  510. + Added Public,Alias directives for some calls
  511. Revision 1.6 1998/06/25 08:41:44 florian
  512. * better rtti
  513. Revision 1.5 1998/06/12 07:39:13 michael
  514. + Added aliases for Incr/Decr ref.
  515. Revision 1.4 1998/06/08 19:35:02 michael
  516. Some changes to integrate in system unit
  517. Revision 1.3 1998/06/08 12:38:22 michael
  518. Implemented rtti, inserted ansistrings again
  519. Revision 1.2 1998/05/12 10:42:44 peter
  520. * moved getopts to inc/, all supported OS's need argc,argv exported
  521. + strpas, strlen are now exported in the systemunit
  522. * removed logs
  523. * removed $ifdef ver_above
  524. }