astrings.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt,
  4. member of the Free Pascal development team.
  5. This file implements AnsiStrings for FPC
  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. { This will release some functions for special shortstring support }
  13. { define EXTRAANSISHORT}
  14. {
  15. This file contains the implementation of the AnsiString type,
  16. and all things that are needed for it.
  17. AnsiString is defined as a 'silent' pchar :
  18. a pchar that points to :
  19. @-8 : SizeInt for reference count;
  20. @-4 : SizeInt for size;
  21. @ : String + Terminating #0;
  22. Pchar(Ansistring) is a valid typecast.
  23. So AS[i] is converted to the address @AS+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. PAnsiRec = ^TAnsiRec;
  29. TAnsiRec = Packed Record
  30. Ref,
  31. Len : SizeInt;
  32. First : Char;
  33. end;
  34. Const
  35. AnsiRecLen = SizeOf(TAnsiRec);
  36. FirstOff = SizeOf(TAnsiRec)-1;
  37. {****************************************************************************
  38. Internal functions, not in interface.
  39. ****************************************************************************}
  40. Function NewAnsiString(Len : SizeInt) : Pointer;
  41. {
  42. Allocate a new AnsiString on the heap.
  43. initialize it to zero length and reference count 1.
  44. }
  45. Var
  46. P : Pointer;
  47. begin
  48. { request a multiple of 16 because the heap manager alloctes anyways chunks of 16 bytes }
  49. GetMem(P,Len+AnsiRecLen);
  50. If P<>Nil then
  51. begin
  52. PAnsiRec(P)^.Ref:=1; { Set reference count }
  53. PAnsiRec(P)^.Len:=0; { Initial length }
  54. PAnsiRec(P)^.First:=#0; { Terminating #0 }
  55. inc(p,firstoff); { Points to string now }
  56. end;
  57. NewAnsiString:=P;
  58. end;
  59. Procedure DisposeAnsiString(Var S : Pointer); {$IFNDEF VER2_0} Inline; {$ENDIF}
  60. {
  61. Deallocates a AnsiString From the heap.
  62. }
  63. begin
  64. If S=Nil then
  65. exit;
  66. Dec (S,FirstOff);
  67. FreeMem (S);
  68. S:=Nil;
  69. end;
  70. {$ifndef FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  71. Procedure fpc_ansistr_decr_ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc;
  72. {
  73. Decreases the ReferenceCount of a non constant ansistring;
  74. If the reference count is zero, deallocate the string;
  75. }
  76. Type
  77. pSizeInt = ^SizeInt;
  78. Var
  79. l : pSizeInt;
  80. Begin
  81. { Zero string }
  82. If S=Nil then exit;
  83. { check for constant strings ...}
  84. l:=@PAnsiRec(S-FirstOff)^.Ref;
  85. If l^<0 then exit;
  86. { declocked does a MT safe dec and returns true, if the counter is 0 }
  87. If declocked(l^) then
  88. { Ref count dropped to zero }
  89. DisposeAnsiString (S); { Remove...}
  90. end;
  91. {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  92. { also define alias for internal use in the system unit }
  93. Procedure fpc_ansistr_decr_ref (Var S : Pointer); [external name 'FPC_ANSISTR_DECR_REF'];
  94. Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  95. Begin
  96. If S=Nil then
  97. exit;
  98. { Let's be paranoid : Constant string ??}
  99. If PAnsiRec(S-FirstOff)^.Ref<0 then exit;
  100. inclocked(PAnsiRec(S-FirstOff)^.Ref);
  101. end;
  102. { also define alias which can be used inside the system unit }
  103. Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [external name 'FPC_ANSISTR_INCR_REF'];
  104. Procedure fpc_AnsiStr_Assign (Var DestS : Pointer;S2 : Pointer);[Public,Alias:'FPC_ANSISTR_ASSIGN']; compilerproc;
  105. {
  106. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  107. }
  108. begin
  109. if DestS=S2 then
  110. exit;
  111. If S2<>nil then
  112. If PAnsiRec(S2-FirstOff)^.Ref>0 then
  113. inclocked(PAnsiRec(S2-FirstOff)^.ref);
  114. { Decrease the reference count on the old S1 }
  115. fpc_ansistr_decr_ref (DestS);
  116. { And finally, have DestS pointing to S2 (or its copy) }
  117. DestS:=S2;
  118. end;
  119. { alias for internal use }
  120. Procedure fpc_AnsiStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_ANSISTR_ASSIGN'];
  121. {$ifndef STR_CONCAT_PROCS}
  122. function fpc_AnsiStr_Concat (const S1,S2 : AnsiString): ansistring; compilerproc;
  123. Var
  124. Size,Location : SizeInt;
  125. pc : pchar;
  126. begin
  127. { only assign if s1 or s2 is empty }
  128. if (S1='') then
  129. begin
  130. result:=s2;
  131. exit;
  132. end;
  133. if (S2='') then
  134. begin
  135. result:=s1;
  136. exit;
  137. end;
  138. Location:=Length(S1);
  139. Size:=length(S2);
  140. SetLength(result,Size+Location);
  141. pc:=pchar(result);
  142. Move(S1[1],pc^,Location);
  143. inc(pc,location);
  144. Move(S2[1],pc^,Size+1);
  145. end;
  146. function fpc_AnsiStr_Concat_multi (const sarr:array of Ansistring): ansistring; compilerproc;
  147. Var
  148. i : Longint;
  149. p : pointer;
  150. pc : pchar;
  151. Size,NewLen : SizeInt;
  152. begin
  153. { First calculate size of the result so we can do
  154. a single call to SetLength() }
  155. NewLen:=0;
  156. for i:=low(sarr) to high(sarr) do
  157. inc(NewLen,length(sarr[i]));
  158. SetLength(result,NewLen);
  159. pc:=pchar(result);
  160. for i:=low(sarr) to high(sarr) do
  161. begin
  162. p:=pointer(sarr[i]);
  163. if assigned(p) then
  164. begin
  165. Size:=length(ansistring(p));
  166. Move(pchar(p)^,pc^,Size+1);
  167. inc(pc,size);
  168. end;
  169. end;
  170. end;
  171. {$else STR_CONCAT_PROCS}
  172. procedure fpc_AnsiStr_Concat (var DestS:ansistring;const S1,S2 : AnsiString); compilerproc;
  173. Var
  174. Size,Location : SizeInt;
  175. begin
  176. { only assign if s1 or s2 is empty }
  177. if (S1='') then
  178. begin
  179. DestS:=s2;
  180. exit;
  181. end;
  182. if (S2='') then
  183. begin
  184. DestS:=s1;
  185. exit;
  186. end;
  187. Location:=Length(S1);
  188. Size:=length(S2);
  189. { Use Pointer() typecasts to prevent extra conversion code }
  190. if Pointer(DestS)=Pointer(S1) then
  191. begin
  192. SetLength(DestS,Size+Location);
  193. Move(Pointer(S2)^,(Pointer(DestS)+Location)^,Size+1);
  194. end
  195. else if Pointer(DestS)=Pointer(S2) then
  196. begin
  197. SetLength(DestS,Size+Location);
  198. Move(Pointer(DestS)^,(Pointer(DestS)+Location)^,Size+1);
  199. Move(Pointer(S1)^,Pointer(DestS)^,Location);
  200. end
  201. else
  202. begin
  203. DestS:='';
  204. SetLength(DestS,Size+Location);
  205. Move(Pointer(S1)^,Pointer(DestS)^,Location);
  206. Move(Pointer(S2)^,(Pointer(DestS)+Location)^,Size+1);
  207. end;
  208. end;
  209. procedure fpc_AnsiStr_Concat_multi (var DestS:ansistring;const sarr:array of Ansistring); compilerproc;
  210. Var
  211. lowstart,i : Longint;
  212. p,pc : pointer;
  213. Size,NewLen,
  214. OldDestLen : SizeInt;
  215. destcopy : ansistring;
  216. begin
  217. if high(sarr)=0 then
  218. begin
  219. DestS:='';
  220. exit;
  221. end;
  222. lowstart:=low(sarr);
  223. if Pointer(DestS)=Pointer(sarr[lowstart]) then
  224. inc(lowstart);
  225. { Check for another reuse, then we can't use
  226. the append optimization }
  227. for i:=lowstart to high(sarr) do
  228. begin
  229. if Pointer(DestS)=Pointer(sarr[i]) then
  230. begin
  231. { if DestS is used somewhere in the middle of the expression,
  232. we need to make sure the original string still exists after
  233. we empty/modify DestS }
  234. destcopy:=dests;
  235. lowstart:=low(sarr);
  236. break;
  237. end;
  238. end;
  239. { Start with empty DestS if we start with concatting
  240. the first array element }
  241. if lowstart=low(sarr) then
  242. DestS:='';
  243. OldDestLen:=length(DestS);
  244. { Calculate size of the result so we can do
  245. a single call to SetLength() }
  246. NewLen:=0;
  247. for i:=low(sarr) to high(sarr) do
  248. inc(NewLen,length(sarr[i]));
  249. SetLength(DestS,NewLen);
  250. { Concat all strings, except the string we already
  251. copied in DestS }
  252. pc:=Pointer(DestS)+OldDestLen;
  253. for i:=lowstart to high(sarr) do
  254. begin
  255. p:=pointer(sarr[i]);
  256. if assigned(p) then
  257. begin
  258. Size:=length(ansistring(p));
  259. Move(p^,pc^,Size+1);
  260. inc(pc,size);
  261. end;
  262. end;
  263. end;
  264. {$endif STR_CONCAT_PROCS}
  265. {$ifdef EXTRAANSISHORT}
  266. Procedure AnsiStr_ShortStr_Concat (Var S1: AnsiString; Var S2 : ShortString);
  267. {
  268. Concatenates a Ansi with a short string; : S2 + S2
  269. }
  270. Var
  271. Size,Location : SizeInt;
  272. begin
  273. Size:=Length(S2);
  274. Location:=Length(S1);
  275. If Size=0 then
  276. exit;
  277. { Setlength takes case of uniqueness
  278. and alllocated memory. We need to use length,
  279. to take into account possibility of S1=Nil }
  280. SetLength (S1,Size+Length(S1));
  281. Move (S2[1],Pointer(Pointer(S1)+Location)^,Size);
  282. PByte( Pointer(S1)+length(S1) )^:=0; { Terminating Zero }
  283. end;
  284. {$endif EXTRAANSISHORT}
  285. { the following declaration has exactly the same effect as }
  286. { procedure fpc_AnsiStr_To_ShortStr (Var S1 : ShortString;S2 : Pointer); }
  287. { which is what the old helper was, so we don't need an extra implementation }
  288. { of the old helper (JM) }
  289. function fpc_AnsiStr_To_ShortStr (high_of_res: SizeInt;const S2 : Ansistring): shortstring;[Public, alias: 'FPC_ANSISTR_TO_SHORTSTR']; compilerproc;
  290. {
  291. Converts a AnsiString to a ShortString;
  292. }
  293. Var
  294. Size : SizeInt;
  295. begin
  296. if S2='' then
  297. fpc_AnsiStr_To_ShortStr:=''
  298. else
  299. begin
  300. Size:=Length(S2);
  301. If Size>high_of_res then
  302. Size:=high_of_res;
  303. Move (S2[1],fpc_AnsiStr_To_ShortStr[1],Size);
  304. byte(fpc_AnsiStr_To_ShortStr[0]):=byte(Size);
  305. end;
  306. end;
  307. Function fpc_ShortStr_To_AnsiStr (Const S2 : ShortString): ansistring; compilerproc;
  308. {
  309. Converts a ShortString to a AnsiString;
  310. }
  311. Var
  312. Size : SizeInt;
  313. begin
  314. Size:=Length(S2);
  315. Setlength (fpc_ShortStr_To_AnsiStr,Size);
  316. if Size>0 then
  317. Move(S2[1],Pointer(fpc_ShortStr_To_AnsiStr)^,Size);
  318. end;
  319. Function fpc_Char_To_AnsiStr(const c : Char): AnsiString; compilerproc;
  320. {
  321. Converts a Char to a AnsiString;
  322. }
  323. begin
  324. Setlength (fpc_Char_To_AnsiStr,1);
  325. PByte(Pointer(fpc_Char_To_AnsiStr))^:=byte(c);
  326. { Terminating Zero }
  327. PByte(Pointer(fpc_Char_To_AnsiStr)+1)^:=0;
  328. end;
  329. Function fpc_PChar_To_AnsiStr(const p : pchar): ansistring; compilerproc;
  330. Var
  331. L : SizeInt;
  332. begin
  333. if (not assigned(p)) or (p[0]=#0) Then
  334. { result is automatically set to '' }
  335. exit;
  336. l:=IndexChar(p^,-1,#0);
  337. SetLength(fpc_PChar_To_AnsiStr,L);
  338. Move (P[0],Pointer(fpc_PChar_To_AnsiStr)^,L)
  339. end;
  340. Function fpc_CharArray_To_AnsiStr(const arr: array of char; zerobased: boolean = true): ansistring; compilerproc;
  341. var
  342. i : SizeInt;
  343. begin
  344. if (zerobased) then
  345. begin
  346. if (arr[0]=#0) Then
  347. { result is automatically set to '' }
  348. exit;
  349. i:=IndexChar(arr,high(arr)+1,#0);
  350. if i = -1 then
  351. i := high(arr)+1;
  352. end
  353. else
  354. i := high(arr)+1;
  355. SetLength(fpc_CharArray_To_AnsiStr,i);
  356. Move (arr[0],Pointer(fpc_CharArray_To_AnsiStr)^,i);
  357. end;
  358. { note: inside the compiler, the resulttype is modified to be the length }
  359. { of the actual chararray to which we convert (JM) }
  360. function fpc_ansistr_to_chararray(arraysize: SizeInt; const src: ansistring): fpc_big_chararray; [public, alias: 'FPC_ANSISTR_TO_CHARARRAY']; compilerproc;
  361. var
  362. len: SizeInt;
  363. begin
  364. len := length(src);
  365. if len > arraysize then
  366. len := arraysize;
  367. { make sure we don't try to access element 1 of the ansistring if it's nil }
  368. if len > 0 then
  369. move(src[1],fpc_ansistr_to_chararray[0],len);
  370. fillchar(fpc_ansistr_to_chararray[len],arraysize-len,0);
  371. end;
  372. Function fpc_AnsiStr_Compare(const S1,S2 : AnsiString): SizeInt;[Public,Alias : 'FPC_ANSISTR_COMPARE']; compilerproc;
  373. {
  374. Compares 2 AnsiStrings;
  375. The result is
  376. <0 if S1<S2
  377. 0 if S1=S2
  378. >0 if S1>S2
  379. }
  380. Var
  381. MaxI,Temp : SizeInt;
  382. begin
  383. if pointer(S1)=pointer(S2) then
  384. begin
  385. result:=0;
  386. exit;
  387. end;
  388. Maxi:=Length(S1);
  389. temp:=Length(S2);
  390. If MaxI>Temp then
  391. MaxI:=Temp;
  392. if MaxI>0 then
  393. begin
  394. result:=CompareByte(S1[1],S2[1],MaxI);
  395. if result=0 then
  396. result:=Length(S1)-Length(S2);
  397. end
  398. else
  399. result:=Length(S1)-Length(S2);
  400. end;
  401. Procedure fpc_AnsiStr_CheckZero(p : pointer);[Public,Alias : 'FPC_ANSISTR_CHECKZERO']; compilerproc;
  402. begin
  403. if p=nil then
  404. HandleErrorFrame(201,get_frame);
  405. end;
  406. Procedure fpc_AnsiStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_ANSISTR_RANGECHECK']; compilerproc;
  407. begin
  408. if (index>len) or (Index<1) then
  409. HandleErrorFrame(201,get_frame);
  410. end;
  411. Procedure fpc_AnsiStr_SetLength (Var S : AnsiString; l : SizeInt);[Public,Alias : 'FPC_ANSISTR_SETLENGTH']; compilerproc;
  412. {
  413. Sets The length of string S to L.
  414. Makes sure S is unique, and contains enough room.
  415. }
  416. Var
  417. Temp : Pointer;
  418. lens,
  419. movelen : SizeInt;
  420. begin
  421. if (l>0) then
  422. begin
  423. if Pointer(S)=nil then
  424. begin
  425. GetMem(Pointer(S),AnsiRecLen+L);
  426. PAnsiRec(S)^.Ref:=1;
  427. inc(Pointer(S),firstoff);
  428. end
  429. else if PAnsiRec(Pointer(S)-FirstOff)^.Ref=1 then
  430. begin
  431. Dec(Pointer(S),FirstOff);
  432. if AnsiRecLen+L>MemSize(Pointer(s)) then
  433. reallocmem(pointer(S),AnsiRecLen+L);
  434. Inc(Pointer(S),FirstOff);
  435. end
  436. else
  437. begin
  438. { Reallocation is needed... }
  439. Temp:=Pointer(NewAnsiString(L));
  440. { also move terminating null }
  441. lens:=succ(length(s));
  442. if l < lens then
  443. movelen := l
  444. else
  445. movelen := lens;
  446. Move(Pointer(S)^,Temp^,movelen);
  447. { ref count dropped to zero in the mean time? }
  448. If (PAnsiRec(Pointer(S)-FirstOff)^.Ref > 0) and
  449. declocked(PAnsiRec(Pointer(S)-FirstOff)^.Ref) then
  450. freemem(PAnsiRec(Pointer(s)-FirstOff));
  451. Pointer(S):=Temp;
  452. end;
  453. { Force nil termination in case it gets shorter }
  454. PByte(Pointer(S)+l)^:=0;
  455. PAnsiRec(Pointer(S)-FirstOff)^.Len:=l;
  456. end
  457. else
  458. begin
  459. { Length=0 }
  460. if Pointer(S)<>nil then
  461. fpc_ansistr_decr_ref (Pointer(S));
  462. Pointer(S):=Nil;
  463. end;
  464. end;
  465. {$ifdef EXTRAANSISHORT}
  466. Function fpc_AnsiStr_ShortStr_Compare (Var S1 : Pointer; Var S2 : ShortString): SizeInt; compilerproc;
  467. {
  468. Compares a AnsiString with a ShortString;
  469. The result is
  470. <0 if S1<S2
  471. 0 if S1=S2
  472. >0 if S1>S2
  473. }
  474. Var
  475. i,MaxI,Temp : SizeInt;
  476. begin
  477. Temp:=0;
  478. i:=0;
  479. MaxI:=Length(AnsiString(S1));
  480. if MaxI>byte(S2[0]) then
  481. MaxI:=Byte(S2[0]);
  482. While (i<MaxI) and (Temp=0) do
  483. begin
  484. Temp:= PByte(S1+I)^ - Byte(S2[i+1]);
  485. inc(i);
  486. end;
  487. AnsiStr_ShortStr_Compare:=Temp;
  488. end;
  489. {$endif EXTRAANSISHORT}
  490. {*****************************************************************************
  491. Public functions, In interface.
  492. *****************************************************************************}
  493. function fpc_truely_ansistr_unique(Var S : Pointer): Pointer;
  494. Var
  495. SNew : Pointer;
  496. L : SizeInt;
  497. begin
  498. L:=PAnsiRec(Pointer(S)-FirstOff)^.len;
  499. SNew:=NewAnsiString (L);
  500. Move (Pointer(S)^,SNew^,L+1);
  501. PAnsiRec(SNew-FirstOff)^.len:=L;
  502. fpc_ansistr_decr_ref (Pointer(S)); { Thread safe }
  503. pointer(S):=SNew;
  504. pointer(result):=SNew;
  505. end;
  506. {$ifndef FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  507. // MV: inline the basic checks for case that S is already unique.
  508. // Rest is too complex to inline, so factor that out as a call.
  509. Function fpc_ansistr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_ANSISTR_UNIQUE']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  510. {
  511. Make sure reference count of S is 1,
  512. using copy-on-write semantics.
  513. }
  514. begin
  515. pointer(result) := pointer(s);
  516. If Pointer(S)=Nil then
  517. exit;
  518. if PAnsiRec(Pointer(S)-Firstoff)^.Ref<>1 then
  519. result:=fpc_truely_ansistr_unique(s);
  520. end;
  521. {$endif FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  522. Procedure fpc_ansistr_append_char(Var S : AnsiString;c : char); [Public,Alias : 'FPC_ANSISTR_APPEND_CHAR']; compilerproc;
  523. begin
  524. SetLength(S,length(S)+1);
  525. // avoid unique call
  526. PChar(Pointer(S)+length(S)-1)^:=c;
  527. PByte(Pointer(S)+length(S))^:=0; { Terminating Zero }
  528. end;
  529. Procedure fpc_ansistr_append_shortstring(Var S : AnsiString;const Str : ShortString); [Public,Alias : 'FPC_ANSISTR_APPEND_SHORTSTRING']; compilerproc;
  530. var
  531. ofs : SizeInt;
  532. begin
  533. if Str='' then
  534. exit;
  535. ofs:=Length(S);
  536. SetLength(S,ofs+length(Str));
  537. { the pbyte cast avoids an unique call which isn't necessary because SetLength was just called }
  538. move(Str[1],(pointer(S)+ofs)^,length(Str));
  539. PByte(Pointer(S)+length(S))^:=0; { Terminating Zero }
  540. end;
  541. Procedure fpc_ansistr_append_ansistring(Var S : AnsiString;const Str : AnsiString); [Public,Alias : 'FPC_ANSISTR_APPEND_ANSISTRING']; compilerproc;
  542. var
  543. ofs, strlength: SizeInt;
  544. samestring: boolean;
  545. begin
  546. if Str='' then
  547. exit;
  548. samestring := pointer(s) = pointer(str);
  549. { needed in case s and str are the same string }
  550. strlength := length(str);
  551. ofs:=Length(S);
  552. SetLength(S,ofs+strlength);
  553. { the pbyte cast avoids an unique call which isn't necessary because SetLength was just called }
  554. if not(samestring) then
  555. move(Str[1],(pointer(S)+ofs)^,strlength+1)
  556. else
  557. { the setlength may have relocated the string, so str may no longer be valid }
  558. move(S[1],(pointer(S)+ofs)^,strlength+1)
  559. end;
  560. Function Fpc_Ansistr_Copy (Const S : AnsiString; Index,Size : SizeInt) : AnsiString;compilerproc;
  561. var
  562. ResultAddress : Pointer;
  563. begin
  564. ResultAddress:=Nil;
  565. dec(index);
  566. if Index < 0 then
  567. Index := 0;
  568. { Check Size. Accounts for Zero-length S, the double check is needed because
  569. Size can be maxint and will get <0 when adding index }
  570. if (Size>Length(S)) or
  571. (Index+Size>Length(S)) then
  572. Size:=Length(S)-Index;
  573. If Size>0 then
  574. begin
  575. If Index<0 Then
  576. Index:=0;
  577. ResultAddress:=Pointer(NewAnsiString (Size));
  578. if ResultAddress<>Nil then
  579. begin
  580. Move (Pointer(Pointer(S)+index)^,ResultAddress^,Size);
  581. PAnsiRec(ResultAddress-FirstOff)^.Len:=Size;
  582. PByte(ResultAddress+Size)^:=0;
  583. end;
  584. end;
  585. Pointer(fpc_ansistr_Copy):=ResultAddress;
  586. end;
  587. Function Pos (Const Substr : ShortString; Const Source : AnsiString) : SizeInt;
  588. var
  589. i,MaxLen : SizeInt;
  590. pc : pchar;
  591. begin
  592. Pos:=0;
  593. if Length(SubStr)>0 then
  594. begin
  595. MaxLen:=Length(source)-Length(SubStr);
  596. i:=0;
  597. pc:=@source[1];
  598. while (i<=MaxLen) do
  599. begin
  600. inc(i);
  601. if (SubStr[1]=pc^) and
  602. (CompareByte(Substr[1],pc^,Length(SubStr))=0) then
  603. begin
  604. Pos:=i;
  605. exit;
  606. end;
  607. inc(pc);
  608. end;
  609. end;
  610. end;
  611. Function Pos (Const Substr : AnsiString; Const Source : AnsiString) : SizeInt;
  612. var
  613. i,MaxLen : SizeInt;
  614. pc : pchar;
  615. begin
  616. Pos:=0;
  617. if Length(SubStr)>0 then
  618. begin
  619. MaxLen:=Length(source)-Length(SubStr);
  620. i:=0;
  621. pc:=@source[1];
  622. while (i<=MaxLen) do
  623. begin
  624. inc(i);
  625. if (SubStr[1]=pc^) and
  626. (CompareByte(Substr[1],pc^,Length(SubStr))=0) then
  627. begin
  628. Pos:=i;
  629. exit;
  630. end;
  631. inc(pc);
  632. end;
  633. end;
  634. end;
  635. { Faster version for a char alone. Must be implemented because }
  636. { pos(c: char; const s: shortstring) also exists, so otherwise }
  637. { using pos(char,pchar) will always call the shortstring version }
  638. { (exact match for first argument), also with $h+ (JM) }
  639. Function Pos (c : Char; Const s : AnsiString) : SizeInt;
  640. var
  641. i: SizeInt;
  642. pc : pchar;
  643. begin
  644. pc:=@s[1];
  645. for i:=1 to length(s) do
  646. begin
  647. if pc^=c then
  648. begin
  649. pos:=i;
  650. exit;
  651. end;
  652. inc(pc);
  653. end;
  654. pos:=0;
  655. end;
  656. Function fpc_Val_Real_AnsiStr(Const S : AnsiString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_ANSISTR']; compilerproc;
  657. Var
  658. SS : String;
  659. begin
  660. fpc_Val_Real_AnsiStr := 0;
  661. if length(S) > 255 then
  662. code := 256
  663. else
  664. begin
  665. SS := S;
  666. Val(SS,fpc_Val_Real_AnsiStr,code);
  667. end;
  668. end;
  669. Function fpc_Val_Currency_AnsiStr(Const S : AnsiString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_ANSISTR']; compilerproc;
  670. Var
  671. SS : String;
  672. begin
  673. if length(S) > 255 then
  674. begin
  675. fpc_Val_Currency_AnsiStr := 0;
  676. code := 256;
  677. end
  678. else
  679. begin
  680. SS := S;
  681. Val(SS,fpc_Val_Currency_AnsiStr,code);
  682. end;
  683. end;
  684. Function fpc_Val_UInt_AnsiStr (Const S : AnsiString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_ANSISTR']; compilerproc;
  685. Var
  686. SS : ShortString;
  687. begin
  688. fpc_Val_UInt_AnsiStr := 0;
  689. if length(S) > 255 then
  690. code := 256
  691. else
  692. begin
  693. SS := S;
  694. Val(SS,fpc_Val_UInt_AnsiStr,code);
  695. end;
  696. end;
  697. Function fpc_Val_SInt_AnsiStr (DestSize: SizeInt; Const S : AnsiString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_ANSISTR']; compilerproc;
  698. Var
  699. SS : ShortString;
  700. begin
  701. fpc_Val_SInt_AnsiStr:=0;
  702. if length(S)>255 then
  703. code:=256
  704. else
  705. begin
  706. SS := S;
  707. fpc_Val_SInt_AnsiStr := int_Val_SInt_ShortStr(DestSize,SS,Code);
  708. end;
  709. end;
  710. {$ifndef CPU64}
  711. Function fpc_Val_qword_AnsiStr (Const S : AnsiString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_ANSISTR']; compilerproc;
  712. Var
  713. SS : ShortString;
  714. begin
  715. fpc_Val_qword_AnsiStr:=0;
  716. if length(S)>255 then
  717. code:=256
  718. else
  719. begin
  720. SS := S;
  721. Val(SS,fpc_Val_qword_AnsiStr,Code);
  722. end;
  723. end;
  724. Function fpc_Val_int64_AnsiStr (Const S : AnsiString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_ANSISTR']; compilerproc;
  725. Var
  726. SS : ShortString;
  727. begin
  728. fpc_Val_int64_AnsiStr:=0;
  729. if length(S)>255 then
  730. code:=256
  731. else
  732. begin
  733. SS := s;
  734. Val(SS,fpc_Val_int64_AnsiStr,Code);
  735. end;
  736. end;
  737. {$endif CPU64}
  738. procedure fpc_AnsiStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : ansistring);[public,alias:'FPC_ANSISTR_FLOAT']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  739. var
  740. ss: ShortString;
  741. begin
  742. str_real(len,fr,d,treal_type(rt),ss);
  743. s:=ss;
  744. end;
  745. procedure fpc_AnsiStr_Currency(c : currency;len,fr : SizeInt;out s : ansistring);[public,alias:'FPC_ANSISTR_CURRENCY']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  746. var
  747. ss: ShortString;
  748. begin
  749. str(c:len:fr,ss);
  750. s:=ss;
  751. end;
  752. Procedure fpc_AnsiStr_UInt(v : ValUInt;Len : SizeInt; out S : AnsiString);[Public,Alias : 'FPC_ANSISTR_VALUINT']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  753. Var
  754. SS : ShortString;
  755. begin
  756. str(v:Len,SS);
  757. S:=SS;
  758. end;
  759. Procedure fpc_AnsiStr_SInt(v : ValSInt;Len : SizeInt; out S : AnsiString);[Public,Alias : 'FPC_ANSISTR_VALSINT']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  760. Var
  761. SS : ShortString;
  762. begin
  763. str (v:Len,SS);
  764. S:=SS;
  765. end;
  766. {$ifndef CPU64}
  767. Procedure fpc_AnsiStr_QWord(v : QWord;Len : SizeInt; out S : AnsiString);[Public,Alias : 'FPC_ANSISTR_QWORD']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  768. Var
  769. SS : ShortString;
  770. begin
  771. str(v:Len,SS);
  772. S:=SS;
  773. end;
  774. Procedure fpc_AnsiStr_Int64(v : Int64; Len : SizeInt; out S : AnsiString);[Public,Alias : 'FPC_ANSISTR_INT64']; compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
  775. Var
  776. SS : ShortString;
  777. begin
  778. str (v:Len,SS);
  779. S:=SS;
  780. end;
  781. {$endif CPU64}
  782. Procedure Delete (Var S : AnsiString; Index,Size: SizeInt);
  783. Var
  784. LS : SizeInt;
  785. begin
  786. ls:=Length(S);
  787. If (Index>LS) or (Index<=0) or (Size<=0) then
  788. exit;
  789. UniqueString (S);
  790. If (Size>LS-Index) then // Size+Index gives overflow ??
  791. Size:=LS-Index+1;
  792. If (Size<=LS-Index) then
  793. begin
  794. Dec(Index);
  795. Move(PByte(Pointer(S))[Index+Size],PByte(Pointer(S))[Index],LS-Index-Size+1);
  796. end;
  797. Setlength(S,LS-Size);
  798. end;
  799. Procedure Insert (Const Source : AnsiString; Var S : AnsiString; Index : SizeInt);
  800. var
  801. Temp : AnsiString;
  802. LS : SizeInt;
  803. begin
  804. If Length(Source)=0 then
  805. exit;
  806. if index <= 0 then
  807. index := 1;
  808. Ls:=Length(S);
  809. if index > LS then
  810. index := LS+1;
  811. Dec(Index);
  812. Pointer(Temp) := NewAnsiString(Length(Source)+LS);
  813. SetLength(Temp,Length(Source)+LS);
  814. If Index>0 then
  815. move (Pointer(S)^,Pointer(Temp)^,Index);
  816. Move (Pointer(Source)^,PByte(Temp)[Index],Length(Source));
  817. If (LS-Index)>0 then
  818. Move(PByte(Pointer(S))[Index],PByte(temp)[Length(Source)+index],LS-Index);
  819. S:=Temp;
  820. end;
  821. Function StringOfChar(c : char;l : SizeInt) : AnsiString;
  822. begin
  823. SetLength(StringOfChar,l);
  824. FillChar(Pointer(StringOfChar)^,Length(StringOfChar),c);
  825. end;
  826. Procedure SetString (Out S : AnsiString; Buf : PChar; Len : SizeInt); {$IFNDEF VER2_0} Inline; {$ENDIF}
  827. begin
  828. SetLength(S,Len);
  829. If (Buf<>Nil) then
  830. Move (Buf^,Pointer(S)^,Len);
  831. end;
  832. function upcase(const s : ansistring) : ansistring;
  833. var
  834. i : SizeInt;
  835. begin
  836. Setlength(result,length(s));
  837. for i := 1 to length (s) do
  838. result[i] := upcase(s[i]);
  839. end;
  840. function lowercase(const s : ansistring) : ansistring;
  841. var
  842. i : SizeInt;
  843. begin
  844. Setlength(result,length(s));
  845. for i := 1 to length (s) do
  846. result[i] := lowercase(s[i]);
  847. end;