astrings.inc 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435
  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. {$ifndef FPC_ANSISTRING_TYPE_DEFINED}
  15. {$define FPC_ANSISTRING_TYPE_DEFINED}
  16. {
  17. This file contains the implementation of the AnsiString type,
  18. and all things that are needed for it.
  19. AnsiString is defined as a 'silent' pansichar :
  20. a pansichar that points to (S= SizeOf(SizeInt), R= (if CPU64 then SizeOf(Longint) else SizeOf(SizeInt))):
  21. @-S-R-4 : Code page indicator.
  22. @-S-R-2 : Character size (2 bytes)
  23. @-S-R : Reference count (R bytes)
  24. @-S : SizeInt for size;
  25. @ : String + Terminating #0;
  26. PAnsiChar(Ansistring) is a valid typecast.
  27. So AS[i] is converted to the address @AS+i-1.
  28. Constants should be assigned a reference count of -1
  29. Meaning that they can't be disposed of.
  30. }
  31. Type
  32. PAnsiRec = ^TAnsiRec;
  33. TAnsiRec = Record
  34. CodePage : TSystemCodePage;
  35. ElementSize : Word;
  36. {$if not defined(VER3_2)}
  37. {$ifdef CPU64}
  38. Ref : Longint;
  39. {$else}
  40. Ref : SizeInt;
  41. {$endif}
  42. {$else}
  43. {$ifdef CPU64}
  44. { align fields }
  45. Dummy : DWord;
  46. {$endif CPU64}
  47. Ref : SizeInt;
  48. {$endif}
  49. Len : SizeInt;
  50. end;
  51. Const
  52. AnsiFirstOff = SizeOf(TAnsiRec);
  53. {$endif FPC_ANSISTRING_TYPE_DEFINED}
  54. {****************************************************************************
  55. Internal functions, not in interface.
  56. ****************************************************************************}
  57. {$ifndef FPC_HAS_TRANSLATEPLACEHOLDERCP}
  58. {$define FPC_HAS_TRANSLATEPLACEHOLDERCP}
  59. function TranslatePlaceholderCP(cp: TSystemCodePage): TSystemCodePage; {$ifdef SYSTEMINLINE}inline;{$endif}
  60. begin
  61. TranslatePlaceholderCP:=cp;
  62. case cp of
  63. CP_OEMCP,
  64. CP_ACP:
  65. TranslatePlaceholderCP:=DefaultSystemCodePage;
  66. end;
  67. end;
  68. {$endif FPC_HAS_TRANSLATEPLACEHOLDERCP}
  69. {$ifndef FPC_HAS_PCHAR_ANSISTR_INTERN_CHARMOVE}
  70. {$define FPC_HAS_PCHAR_ANSISTR_INTERN_CHARMOVE}
  71. procedure fpc_pchar_ansistr_intern_charmove(const src: pansichar; const srcindex: sizeint; var dst: rawbytestring; const dstindex, len: sizeint); rtlproc;{$ifdef SYSTEMINLINE}inline;{$endif}
  72. begin
  73. move(src[srcindex],pbyte(pointer(dst))[dstindex],len);
  74. end;
  75. {$endif FPC_HAS_PCHAR_ANSISTR_INTERN_CHARMOVE}
  76. {$ifndef FPC_HAS_PCHAR_PCHAR_INTERN_CHARMOVE}
  77. {$define FPC_HAS_PCHAR_PCHAR_INTERN_CHARMOVE}
  78. procedure fpc_pchar_pchar_intern_charmove(const src: pansichar; const srcindex: sizeint; const dst: pansichar; const dstindex, len: sizeint); rtlproc; {$ifdef SYSTEMINLINE}inline;{$endif}
  79. begin
  80. move(src[srcindex],dst[dstindex],len);
  81. end;
  82. {$endif FPC_HAS_PCHAR_PCHAR_INTERN_CHARMOVE}
  83. {$ifndef FPC_HAS_SHORTSTR_ANSISTR_INTERN_CHARMOVE}
  84. {$define FPC_HAS_SHORTSTR_ANSISTR_INTERN_CHARMOVE}
  85. procedure fpc_shortstr_ansistr_intern_charmove(const src: shortstring; const srcindex: sizeint; var dst: rawbytestring; const dstindex, len: sizeint); rtlproc; {$ifdef SYSTEMINLINE}inline;{$endif}
  86. begin
  87. move(src[srcindex],pbyte(pointer(dst))[dstindex],len);
  88. end;
  89. {$endif FPC_HAS_SHORTSTR_ANSISTR_INTERN_CHARMOVE}
  90. {$ifndef FPC_HAS_NEWANSISTR}
  91. {$define FPC_HAS_NEWANSISTR}
  92. Function NewAnsiString(Len : SizeInt) : Pointer;
  93. {
  94. Allocate a new AnsiString on the heap.
  95. initialize it to zero length and reference count 1.
  96. }
  97. begin
  98. { request a multiple of 16 because the heap manager alloctes anyways chunks of 16 bytes }
  99. Result:=GetMem(Len+(AnsiFirstOff+sizeof(AnsiChar)));
  100. If Result=Nil then
  101. Exit;
  102. PAnsiRec(Result)^.Ref:=1; { Set reference count }
  103. PAnsiRec(Result)^.Len:=0; { Initial length }
  104. PAnsiRec(Result)^.CodePage:=DefaultSystemCodePage;
  105. PAnsiRec(Result)^.ElementSize:=SizeOf(AnsiChar);
  106. inc(Result,AnsiFirstOff); { Points to string now }
  107. PAnsiChar(Result)^:=#0; { Terminating #0 }
  108. end;
  109. {$endif FPC_HAS_NEWANSISTR}
  110. {$ifndef FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  111. {$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  112. Procedure fpc_ansistr_decr_ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc;
  113. {
  114. Decreases the ReferenceCount of a non constant ansistring;
  115. If the reference count is zero, deallocate the string;
  116. }
  117. Var
  118. p: pointer;
  119. Begin
  120. p:=S;
  121. If p=Nil then
  122. exit;
  123. s:=nil;
  124. If (PAnsiRec(p-AnsiFirstOff)^.ref>0) and { ref = -1 is constant string. }
  125. ((PAnsiRec(p-AnsiFirstOff)^.ref=1) { Shortcut declocked on ref = 1. }
  126. or declocked(PAnsiRec(p-AnsiFirstOff)^.ref)) then
  127. FreeMem(p-AnsiFirstOff);
  128. end;
  129. {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  130. { also define alias for internal use in the system unit }
  131. Procedure fpc_ansistr_decr_ref (Var S : Pointer); [external name 'FPC_ANSISTR_DECR_REF'];
  132. {$ifndef FPC_SYSTEM_HAS_ANSISTR_INCR_REF}
  133. {$define FPC_SYSTEM_HAS_ANSISTR_INCR_REF}
  134. Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF']; compilerproc; inline;
  135. Begin
  136. If S=Nil then
  137. exit;
  138. { Let's be paranoid : Constant string ??}
  139. If PAnsiRec(S-AnsiFirstOff)^.Ref<0 then exit;
  140. inclocked(PAnsiRec(S-AnsiFirstOff)^.Ref);
  141. end;
  142. {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
  143. { also define alias which can be used inside the system unit }
  144. Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [external name 'FPC_ANSISTR_INCR_REF'];
  145. {$ifndef FPC_HAS_ANSISTR_ASSIGN}
  146. {$define FPC_HAS_ANSISTR_ASSIGN}
  147. Procedure fpc_AnsiStr_Assign (Var DestS : Pointer;S2 : Pointer);[Public,Alias:'FPC_ANSISTR_ASSIGN']; compilerproc;
  148. {
  149. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  150. }
  151. begin
  152. if DestS=S2 then
  153. exit;
  154. If S2<>nil then
  155. If PAnsiRec(S2-AnsiFirstOff)^.Ref>0 then
  156. inclocked(PAnsiRec(S2-AnsiFirstOff)^.Ref);
  157. { Decrease the reference count on the old S1 }
  158. fpc_ansistr_decr_ref (DestS);
  159. { And finally, have DestS pointing to S2 (or its copy) }
  160. DestS:=S2;
  161. end;
  162. {$endif FPC_HAS_ANSISTR_ASSIGN}
  163. { alias for internal use }
  164. Procedure fpc_AnsiStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_ANSISTR_ASSIGN'];
  165. {$ifndef FPC_HAS_ANSISTR_CONCAT_COMPLEX}
  166. {$define FPC_HAS_ANSISTR_CONCAT_COMPLEX}
  167. { keeps implicit try..finally block out from primary control flow }
  168. procedure ansistr_concat_complex(var DestS: RawByteString; const S1,S2: RawByteString; cp: TSystemCodePage);
  169. var
  170. U: UnicodeString;
  171. begin
  172. U:=UnicodeString(S1)+UnicodeString(S2);
  173. widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(U)),DestS,cp,Length(U));
  174. end;
  175. {$endif FPC_HAS_ANSISTR_CONCAT_COMPLEX}
  176. {$ifndef FPC_HAS_ANSISTR_CONCAT}
  177. {$define FPC_HAS_ANSISTR_CONCAT}
  178. procedure fpc_AnsiStr_Concat (var DestS:RawByteString;const S1,S2 : RawByteString;cp : TSystemCodePage); compilerproc;
  179. Var
  180. S1Len, S2Len: SizeInt;
  181. S1CP, S2CP, DestCP: TSystemCodePage;
  182. OldDestP, NewDestP, RealDestP, Src : Pointer;
  183. begin
  184. DestCP:=cp;
  185. if DestCp=CP_NONE then
  186. DestCP:=DefaultSystemCodePage;
  187. DestCP:=TranslatePlaceholderCP(DestCP);
  188. { if codepages are different then concat using unicodestring,
  189. but avoid conversions if either addend is empty (StringCodePage will return
  190. DefaultSystemCodePage in that case, which may differ from other addend/dest) }
  191. S1CP:=DestCP;
  192. if Length(S1)<>0 then
  193. S1CP:=TranslatePlaceholderCP(StringCodePage(S1));
  194. S2CP:=S1CP; { So if S2 is empty, S2CP = S1CP. }
  195. if Length(S2)<>0 then
  196. S2CP:=TranslatePlaceholderCP(StringCodePage(S2));
  197. { if the result is rawbytestring and both strings have the same code page,
  198. keep that code page or keep the code page if the other string is empty }
  199. if cp=CP_NONE then
  200. if S1CP=S2CP then { Includes the case of empty S2. }
  201. DestCP:=S1CP
  202. else if Length(S1)=0 then
  203. begin
  204. DestCP:=S2CP;
  205. S1CP:=S2CP;
  206. end;
  207. if (S1CP<>DestCP) or (S2CP<>DestCP) then
  208. begin
  209. ansistr_concat_complex(DestS,S1,S2,DestCP);
  210. exit;
  211. end;
  212. { only assign if s1 or s2 is empty }
  213. if (Length(S1)=0) then
  214. begin
  215. DestS:=s2;
  216. exit;
  217. end;
  218. if (Length(S2)=0) then
  219. begin
  220. DestS:=s1;
  221. exit;
  222. end;
  223. S1Len:=PAnsiRec(Pointer(S1)-AnsiFirstOff)^.Len;
  224. S2Len:=PAnsiRec(Pointer(S2)-AnsiFirstOff)^.Len;
  225. OldDestP:=Pointer(DestS);
  226. { Reallocate when possible; in the hope this will reuse the chunk more often than do a redundant copy. }
  227. if Assigned(OldDestP) and (PAnsiRec(OldDestP-AnsiFirstOff)^.Ref=1) then
  228. begin
  229. RealDestP:=OldDestP-AnsiFirstOff;
  230. NewDestP:=ReallocMem(RealDestP,AnsiFirstOff+1+S1Len+S2Len)+AnsiFirstOff;
  231. { Copy S2 first, as in the case of OldDestP = Pointer(S2) it must be copied first and in other cases the order does not matter. }
  232. Src:=Pointer(S2);
  233. if Src=OldDestP then
  234. Src:=NewDestP;
  235. Move(Src^,PAnsiChar(NewDestP)[S1Len],S2Len);
  236. if OldDestP<>Pointer(S1) then { Not an append, need to copy S1? }
  237. Move(Pointer(S1)^,NewDestP^,S1Len);
  238. end
  239. else
  240. begin
  241. NewDestP:=NewAnsiString(S1Len+S2Len);
  242. Move(Pointer(S1)^,NewDestP^,S1Len);
  243. Move(Pointer(S2)^,PAnsiChar(NewDestP)[S1Len],S2Len);
  244. fpc_ansistr_decr_ref(Pointer(DestS));
  245. end;
  246. PAnsiChar(NewDestP)[S1Len+S2Len]:=#0;
  247. PAnsiRec(NewDestP-AnsiFirstOff)^.CodePage:=DestCP;
  248. PAnsiRec(NewDestP-AnsiFirstOff)^.Len:=S1Len+S2Len;
  249. Pointer(DestS):=NewDestP;
  250. end;
  251. {$endif FPC_HAS_ANSISTR_CONCAT}
  252. {$ifndef FPC_HAS_ANSISTR_CONCAT_MULTI}
  253. {$define FPC_HAS_ANSISTR_CONCAT_MULTI}
  254. procedure AnsiStr_Concat_multi_complex(var DestS:RawByteString;const sarr:array of RawByteString;cp:TSystemCodePage);
  255. var
  256. i : ObjpasInt;
  257. U : UnicodeString;
  258. begin
  259. U:='';
  260. for i:=0 to high(sarr) do
  261. if (Length(sarr[i])<>0) then
  262. U:=U+UnicodeString(sarr[i]);
  263. DestS:='';
  264. widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(U)),DestS,cp,Length(U));
  265. end;
  266. procedure fpc_AnsiStr_Concat_multi (var DestS:RawByteString;const sarr:array of RawByteString;cp : TSystemCodePage); compilerproc;
  267. Var
  268. lowstart,i,Size,NewLen : SizeInt;
  269. p,pc,olddestp,newdestp,realdestp : pointer;
  270. DestCP,tmpCP : TSystemCodePage;
  271. begin
  272. DestCP:=cp;
  273. if DestCp=CP_NONE then
  274. DestCP:=DefaultSystemCodePage;
  275. lowstart:=low(sarr);
  276. { skip empty strings }
  277. while (lowstart<=high(sarr)) and
  278. (Length(sarr[lowstart])=0) do
  279. inc(lowstart);
  280. if lowstart>high(sarr) then
  281. begin
  282. DestS:=''; { All source strings empty }
  283. exit;
  284. end;
  285. DestCP:=TranslatePlaceholderCP(DestCP);
  286. tmpCP:=TranslatePlaceholderCP(StringCodePage(sarr[lowstart]));
  287. for i:=lowstart+1 to high(sarr) do
  288. begin
  289. { ignore the code page of empty strings, it will always be
  290. DefaultSystemCodePage but it doesn't matter for the outcome }
  291. if (length(sarr[i])<>0) and
  292. (tmpCP<>TranslatePlaceholderCP(StringCodePage(sarr[i]))) then
  293. begin
  294. AnsiStr_Concat_multi_complex(DestS,sarr,DestCP);
  295. exit;
  296. end;
  297. end;
  298. { if the result is rawbytestring and all strings have the same code page,
  299. keep that code page }
  300. if cp=CP_NONE then
  301. DestCP:=tmpCP;
  302. { Calculate size of the result so we can do
  303. a single call to SetLength() }
  304. NewLen:=0;
  305. for i:=lowstart to high(sarr) do
  306. inc(NewLen,length(sarr[i]));
  307. { In the case of the only nonempty string, either return it directly (if SetCodePage has nothing to do) or skip 1 allocation. }
  308. if NewLen=PAnsiRec(Pointer(sarr[lowstart])-AnsiFirstOff)^.Len then
  309. DestS:=sarr[lowstart]
  310. else
  311. begin
  312. olddestp:=pointer(dests);
  313. { Reallocate when possible; in the hope this will reuse the chunk more often than do a redundant copy. }
  314. if assigned(olddestp) and (PAnsiRec(olddestp-AnsiFirstOff)^.Ref=1) then
  315. begin
  316. realdestp:=olddestp-AnsiFirstOff;
  317. newdestp:=ReallocMem(realdestp,AnsiFirstOff+1+NewLen)+AnsiFirstOff;
  318. { First string can be skipped if appending. }
  319. if olddestp=pointer(sarr[lowstart]) then
  320. inc(lowstart);
  321. end
  322. else
  323. begin
  324. { Create new string. }
  325. olddestp:=nil; { This case is distinguished as "not assigned(olddestp)". Also prevents "if p=olddestp" in the loop below shared with the ReallocMem branch. }
  326. newdestp:=NewAnsiString(NewLen);
  327. end;
  328. { Copy strings from last to the first, so that possible occurences of DestS could read from the beginning of the reallocated DestS. }
  329. pc:=newdestp+NewLen;
  330. for i:=high(sarr) downto lowstart do
  331. begin
  332. p:=pointer(sarr[i]);
  333. if not assigned(p) then
  334. continue;
  335. if p=olddestp then
  336. { DestS occured among pieces in the ReallocMem case! Use the new pointer. Its header still conveniently contains old DestS length. }
  337. p:=newdestp;
  338. Size:=PAnsiRec(p-AnsiFirstOff)^.Len;
  339. dec(pc,size);
  340. Move(p^,pc^,Size);
  341. end;
  342. if not assigned(olddestp) then
  343. fpc_AnsiStr_Decr_Ref(pointer(DestS));
  344. PAnsiChar(newdestp)[NewLen]:=#0;
  345. PAnsiRec(newdestp-AnsiFirstOff)^.CodePage:=tmpCP;
  346. PAnsiRec(newdestp-AnsiFirstOff)^.Len:=NewLen; { Careful, loop above relies on the old Len in the newdestp header. }
  347. Pointer(DestS):=newdestp;
  348. end;
  349. { SetCodePage does the conversion (or at least uniquifying) if DestCP is not exactly the code page stored in the string header. Avoid if possible. }
  350. if DestCP<>tmpCP then
  351. SetCodePage(DestS,DestCP,True);
  352. end;
  353. {$endif FPC_HAS_ANSISTR_CONCAT_MULTI}
  354. {$ifdef EXTRAANSISHORT}
  355. Procedure fpc_AnsiStr_ShortStr_Concat (Var S1: AnsiString; Var S2 : ShortString);
  356. {
  357. Concatenates a Ansi with a short string; : S2 + S2
  358. }
  359. Var
  360. Size,Location : SizeInt;
  361. begin
  362. Size:=Length(S2);
  363. Location:=Length(S1);
  364. If Size=0 then
  365. exit;
  366. { Setlength takes case of uniqueness
  367. and alllocated memory. We need to use length,
  368. to take into account possibility of S1=Nil }
  369. SetLength (S1,Size+Length(S1));
  370. Move (S2[1],Pointer(Pointer(S1)+Location)^,Size);
  371. PByte( Pointer(S1)+length(S1) )^:=0; { Terminating Zero }
  372. end;
  373. {$endif EXTRAANSISHORT}
  374. {$ifndef FPC_HAS_ANSISTR_TO_ANSISTR}
  375. {$define FPC_HAS_ANSISTR_TO_ANSISTR}
  376. Function fpc_AnsiStr_To_AnsiStr (const S : RawByteString;cp : TSystemCodePage): RawByteString; [Public, alias: 'FPC_ANSISTR_TO_ANSISTR']; compilerproc;
  377. {
  378. Converts an AnsiString to an AnsiString taking code pages into care
  379. }
  380. Var
  381. Size : SizeInt;
  382. temp : UnicodeString;
  383. orgcp: TSystemCodePage;
  384. begin
  385. result:='';
  386. Size:=Length(S);
  387. if Size>0 then
  388. begin
  389. cp:=TranslatePlaceholderCP(cp);
  390. orgcp:=TranslatePlaceholderCP(StringCodePage(S));
  391. if (orgcp=cp) or (orgcp=CP_NONE) then
  392. begin
  393. SetLength(result,Size);
  394. Move(S[1],result[1],Size);
  395. PAnsiRec(Pointer(result)-AnsiFirstOff)^.CodePage:=cp;
  396. end
  397. else
  398. begin
  399. temp:=UnicodeString(S);
  400. Size:=Length(temp);
  401. widestringmanager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(temp)),result,cp,Size);
  402. end;
  403. end;
  404. end;
  405. Function fpc_AnsiStr_To_AnsiStr (const S : RawByteString;cp : TSystemCodePage): RawByteString; [external name 'FPC_ANSISTR_TO_ANSISTR'];
  406. {$endif FPC_HAS_ANSISTR_TO_ANSISTR}
  407. {$ifndef FPC_HAS_ANSISTR_TO_SHORTSTR}
  408. {$define FPC_HAS_ANSISTR_TO_SHORTSTR}
  409. procedure fpc_AnsiStr_To_ShortStr (out res: shortstring; const S2 : RawByteString);[Public, alias: 'FPC_ANSISTR_TO_SHORTSTR']; compilerproc;
  410. {
  411. Converts a AnsiString to a ShortString;
  412. }
  413. Var
  414. Size : SizeInt;
  415. begin
  416. if Length(S2)=0 then
  417. res:=''
  418. else
  419. begin
  420. Size:=Length(S2);
  421. If Size>high(res) then
  422. Size:=high(res);
  423. byte(res[0]):=byte(Size);
  424. Move (S2[1],res[1],Size);
  425. end;
  426. end;
  427. {$endif FPC_HAS_ANSISTR_TO_SHORTSTR}
  428. {$ifndef FPC_HAS_SHORTSTR_TO_ANSISTR}
  429. {$define FPC_HAS_SHORTSTR_TO_ANSISTR}
  430. Function fpc_ShortStr_To_AnsiStr (Const S2 : ShortString;cp : TSystemCodePage): RawByteString; compilerproc;
  431. {
  432. Converts a ShortString to a AnsiString;
  433. }
  434. Var
  435. Size : SizeInt;
  436. begin
  437. Size:=Length(S2);
  438. Setlength(fpc_ShortStr_To_AnsiStr,Size);
  439. if Size>0 then
  440. begin
  441. fpc_shortstr_ansistr_intern_charmove(S2,1,fpc_ShortStr_To_AnsiStr,0,Size);
  442. SetCodePage(fpc_ShortStr_To_AnsiStr,TranslatePlaceholderCP(cp),False);
  443. end
  444. end;
  445. {$endif FPC_HAS_SHORTSTR_TO_ANSISTR}
  446. {$ifndef FPC_HAS_CHAR_TO_ANSISTR}
  447. {$define FPC_HAS_CHAR_TO_ANSISTR}
  448. Function fpc_Char_To_AnsiStr(const c : AnsiChar;cp : TSystemCodePage): RawByteString; compilerproc;
  449. {
  450. Converts a AnsiChar to a AnsiString;
  451. }
  452. begin
  453. Setlength (fpc_Char_To_AnsiStr,1);
  454. PAnsiChar(fpc_Char_To_AnsiStr)^:=c;
  455. { Terminating Zero already set by SetLength above }
  456. SetCodePage(fpc_Char_To_AnsiStr,TranslatePlaceholderCP(cp),False);
  457. end;
  458. {$endif FPC_HAS_CHAR_TO_ANSISTR}
  459. {$ifndef FPC_HAS_PCHAR_TO_ANSISTR}
  460. {$define FPC_HAS_PCHAR_TO_ANSISTR}
  461. Function fpc_PChar_To_AnsiStr(const p : PAnsiChar;cp : TSystemCodePage): RawByteString; compilerproc;
  462. Var
  463. L : SizeInt;
  464. begin
  465. if (not assigned(p)) or (p[0]=#0) Then
  466. L := 0
  467. else
  468. L:=IndexChar(p^,-1,#0);
  469. SetLength(fpc_PChar_To_AnsiStr,L);
  470. if L > 0 then
  471. begin
  472. fpc_pchar_ansistr_intern_charmove(p,0,fpc_PChar_To_AnsiStr,0,L);
  473. SetCodePage(fpc_PChar_To_AnsiStr,TranslatePlaceholderCP(cp),False);
  474. end;
  475. end;
  476. {$endif FPC_HAS_PCHAR_TO_ANSISTR}
  477. {$ifndef FPC_HAS_CHARARRAY_TO_ANSISTR}
  478. {$define FPC_HAS_CHARARRAY_TO_ANSISTR}
  479. Function fpc_CharArray_To_AnsiStr(const arr: array of ansichar; cp : TSystemCodePage;zerobased: boolean = true): RawByteString; compilerproc;
  480. var
  481. i : SizeInt;
  482. begin
  483. if (zerobased) then
  484. begin
  485. if (arr[0]=#0) Then
  486. i := 0
  487. else
  488. begin
  489. i:=IndexChar(arr,high(arr)+1,#0);
  490. if i = -1 then
  491. i := high(arr)+1;
  492. end;
  493. end
  494. else
  495. i := high(arr)+1;
  496. SetLength(fpc_CharArray_To_AnsiStr,i);
  497. if i > 0 then
  498. begin
  499. fpc_pchar_ansistr_intern_charmove(pansichar(@arr),0,fpc_CharArray_To_AnsiStr,0,i);
  500. SetCodePage(fpc_CharArray_To_AnsiStr,TranslatePlaceholderCP(cp),False);
  501. end;
  502. end;
  503. {$endif FPC_HAS_ANSISTR_TO_CHARARRAY}
  504. {$ifndef FPC_HAS_ANSISTR_TO_CHARARRAY}
  505. {$define FPC_HAS_ANSISTR_TO_CHARARRAY}
  506. procedure fpc_ansistr_to_chararray(out res: array of AnsiChar; const src: RawByteString); compilerproc;
  507. var
  508. len: SizeInt;
  509. begin
  510. len := length(src);
  511. if len > length(res) then
  512. len := length(res);
  513. {$push}{$r-}
  514. { make sure we don't try to access element 1 of the ansistring if it's nil }
  515. if len > 0 then
  516. move(src[1],res[0],len);
  517. fillchar(res[len],length(res)-len,0);
  518. {$pop}
  519. end;
  520. {$endif FPC_HAS_ANSISTR_TO_CHARARRAY}
  521. {$ifndef FPC_HAS_ANSISTR_COMPARE}
  522. {$define FPC_HAS_ANSISTR_COMPARE}
  523. Function fpc_utf8_Compare(const S1,S2 : RawByteString): SizeInt;
  524. var
  525. r1,r2 : RawByteString;
  526. begin
  527. r1:=S1;
  528. r2:=S2;
  529. //convert them to utf8 then compare
  530. SetCodePage(r1,65001);
  531. SetCodePage(r2,65001);
  532. Result:=fpc_AnsiStr_Compare(r1,r2);
  533. end;
  534. Function fpc_AnsiStr_Compare(const S1,S2 : RawByteString): SizeInt;[Public,Alias : 'FPC_ANSISTR_COMPARE']; compilerproc;
  535. {
  536. Compares 2 AnsiStrings;
  537. The result is
  538. <0 if S1<S2
  539. 0 if S1=S2
  540. >0 if S1>S2
  541. }
  542. Var
  543. Len1,Len2,CmpLen : SizeInt;
  544. begin
  545. if (pointer(S1)=pointer(S2)) or (pointer(S1)=nil) or (pointer(S2)=nil) then
  546. exit(ord(pointer(S1)<>nil)-ord(pointer(S2)<>nil));
  547. if TranslatePlaceholderCP(PAnsiRec(Pointer(S1)-AnsiFirstOff)^.CodePage)<>TranslatePlaceholderCP(PAnsiRec(Pointer(S2)-AnsiFirstOff)^.CodePage) then
  548. exit(fpc_utf8_compare(s1,s2));
  549. Len1:=PAnsiRec(Pointer(S1)-AnsiFirstOff)^.Len;
  550. Len2:=PAnsiRec(Pointer(S2)-AnsiFirstOff)^.Len;
  551. CmpLen:=Len1;
  552. If Len1>Len2 then
  553. CmpLen:=Len2;
  554. result:=CompareByte(S1[1],S2[1],CmpLen);
  555. if result=0 then
  556. result:=Len1-Len2;
  557. end;
  558. {$endif FPC_HAS_ANSISTR_COMPARE}
  559. {$ifndef FPC_HAS_ANSISTR_COMPARE_EQUAL}
  560. {$define FPC_HAS_ANSISTR_COMPARE_EQUAL}
  561. Function fpc_utf8_Compare_equal(Const S1,S2 : RawByteString): SizeInt;
  562. Var
  563. r1,r2 : RawByteString;
  564. L1,L2 : SizeInt;
  565. begin
  566. r1:=S1;
  567. r2:=S2;
  568. //convert them to utf8 then compare
  569. SetCodePage(r1,65001);
  570. SetCodePage(r2,65001);
  571. L1:=Length(r1);
  572. L2:=Length(r2);
  573. Result:=L1-L2;
  574. if Result = 0 then
  575. if L1>0 then
  576. result:=CompareByte(r1[1],r2[1],L1);
  577. end;
  578. Function fpc_AnsiStr_Compare_equal(const S1,S2 : RawByteString): SizeInt;[Public,Alias : 'FPC_ANSISTR_COMPARE_EQUAL']; compilerproc;
  579. {
  580. Compares 2 AnsiStrings for equality/inequality only;
  581. The result is
  582. 0 if S1=S2
  583. <>0 if S1<>S2
  584. }
  585. Var
  586. MaxI : SizeInt;
  587. begin
  588. { don't compare strings if one of them is empty }
  589. if (pointer(S1)=pointer(S2)) or (pointer(S1)=nil) or (pointer(S2)=nil) then
  590. Exit(ord(pointer(S1)<>pointer(S2)));
  591. if TranslatePlaceholderCP(PAnsiRec(Pointer(S1)-AnsiFirstOff)^.CodePage)<>TranslatePlaceholderCP(PAnsiRec(Pointer(S2)-AnsiFirstOff)^.CodePage) then
  592. Exit(fpc_utf8_Compare_equal(S1,S2));
  593. Maxi:=PAnsiRec(Pointer(S1)-AnsiFirstOff)^.Len;
  594. Result:=Maxi-PAnsiRec(Pointer(S2)-AnsiFirstOff)^.Len;
  595. if Result=0 then
  596. result:=CompareByte(S1[1],S2[1],MaxI);
  597. end;
  598. {$endif FPC_HAS_ANSISTR_COMPARE_EQUAL}
  599. {$ifndef FPC_HAS_ANSISTR_RANGECHECK}
  600. {$define FPC_HAS_ANSISTR_RANGECHECK}
  601. Procedure fpc_AnsiStr_RangeCheck(p: Pointer; index: SizeInt);[Public,Alias : 'FPC_ANSISTR_RANGECHECK']; compilerproc;
  602. begin
  603. if (p=nil) or (index>PAnsiRec(p-AnsiFirstOff)^.Len) or (Index<1) then
  604. HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
  605. end;
  606. Procedure fpc_AnsiStr_ZeroBased_RangeCheck(p: Pointer; index: SizeInt);[Public,Alias : 'FPC_ANSISTR_ZEROBASED_RANGECHECK']; compilerproc;
  607. begin
  608. if (p=nil) or (index>=PAnsiRec(p-AnsiFirstOff)^.Len) or (Index<0) then
  609. HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
  610. end;
  611. {$endif FPC_HAS_ANSISTR_RANGECHECK}
  612. {$ifndef FPC_HAS_ANSISTR_SETLENGTH}
  613. {$define FPC_HAS_ANSISTR_SETLENGTH}
  614. Procedure fpc_AnsiStr_SetLength (Var S : RawByteString; l : SizeInt;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_SETLENGTH']; compilerproc;
  615. {
  616. Sets The length of string S to L.
  617. Makes sure S is unique, and contains enough room.
  618. }
  619. Var
  620. Temp : Pointer;
  621. lens, lena : SizeInt;
  622. begin
  623. if (l>0) then
  624. begin
  625. if Pointer(S)=nil then
  626. begin
  627. Pointer(S):=NewAnsiString(L);
  628. cp:=TranslatePlaceholderCP(cp);
  629. PAnsiRec(Pointer(S)-AnsiFirstOff)^.CodePage:=cp;
  630. end
  631. else if PAnsiRec(Pointer(S)-AnsiFirstOff)^.Ref=1 then
  632. begin
  633. Temp:=Pointer(s)-AnsiFirstOff;
  634. lens:=MemSize(Temp);
  635. lena:=AnsiFirstOff+L+sizeof(AnsiChar);
  636. { allow shrinking string if that saves at least half of current size }
  637. if (lena>lens) or ((lens>32) and (lena<=SizeInt(SizeUint(lens) div 2))) then
  638. Pointer(S):=reallocmem(Temp,lena)+AnsiFirstOff;
  639. end
  640. else
  641. begin
  642. { Reallocation is needed... }
  643. Temp:=NewAnsiString(L);
  644. PAnsiRec(Pointer(Temp)-AnsiFirstOff)^.CodePage:=PAnsiRec(Pointer(S)-AnsiFirstOff)^.CodePage;
  645. { Also copy a trailing implicit #0 of the original string
  646. to the new larger string }
  647. lens:=PAnsiRec(Pointer(S)-AnsiFirstOff)^.Len+1;
  648. if l<lens then
  649. lens:=l;
  650. Move(Pointer(S)^,Temp^,lens);
  651. fpc_ansistr_decr_ref(Pointer(s));
  652. Pointer(S):=Temp;
  653. end;
  654. { Force nil termination in case it gets shorter }
  655. PByte(Pointer(S)+l)^:=0;
  656. PAnsiRec(Pointer(S)-AnsiFirstOff)^.Len:=l;
  657. end
  658. else { length=0, deallocate the string }
  659. fpc_ansistr_decr_ref (Pointer(S));
  660. end;
  661. {$endif FPC_HAS_ANSISTR_SETLENGTH}
  662. {$ifdef EXTRAANSISHORT}
  663. Function fpc_AnsiStr_ShortStr_Compare (Var S1 : Pointer; Var S2 : ShortString): SizeInt; compilerproc;
  664. {
  665. Compares a AnsiString with a ShortString;
  666. The result is
  667. <0 if S1<S2
  668. 0 if S1=S2
  669. >0 if S1>S2
  670. }
  671. Var
  672. i,MaxI,Temp : SizeInt;
  673. begin
  674. Temp:=0;
  675. i:=0;
  676. MaxI:=Length(AnsiString(S1));
  677. if MaxI>byte(S2[0]) then
  678. MaxI:=Byte(S2[0]);
  679. While (i<MaxI) and (Temp=0) do
  680. begin
  681. Temp:= PByte(S1+I)^ - Byte(S2[i+1]);
  682. inc(i);
  683. end;
  684. AnsiStr_ShortStr_Compare:=Temp;
  685. end;
  686. {$endif EXTRAANSISHORT}
  687. {*****************************************************************************
  688. Public functions, In interface.
  689. *****************************************************************************}
  690. {$ifndef FPC_SYSTEM_HAS_TRUELY_ANSISTR_UNIQUE}
  691. {$define FPC_SYSTEM_HAS_TRUELY_ANSISTR_UNIQUE}
  692. function fpc_truely_ansistr_unique(Var S : Pointer): Pointer;
  693. Var
  694. SNew : Pointer;
  695. L : SizeInt;
  696. begin
  697. L:=PAnsiRec(Pointer(S)-AnsiFirstOff)^.len;
  698. SNew:=NewAnsiString (L);
  699. Move (Pointer(S)^,SNew^,L+1);
  700. PAnsiRec(SNew-AnsiFirstOff)^.len:=L;
  701. PAnsiRec(SNew-AnsiFirstOff)^.CodePage:=PAnsiRec(Pointer(S)-AnsiFirstOff)^.CodePage;
  702. fpc_ansistr_decr_ref (Pointer(S)); { Thread safe }
  703. pointer(S):=SNew;
  704. pointer(result):=SNew;
  705. end;
  706. {$endif FPC_SYSTEM_HAS_TRUELY_ANSISTR_UNIQUE}
  707. Function fpc_ansistr_Unique_func(Var S : RawByteString): Pointer; external name 'FPC_ANSISTR_UNIQUE';
  708. Procedure UniqueString(var S : RawByteString);rtlproc;{$ifdef SYSTEMINLINE}inline;{$endif}
  709. begin
  710. fpc_ansistr_Unique_func(S);
  711. end;
  712. {$ifndef FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  713. {$define FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  714. // MV: inline the basic checks for case that S is already unique.
  715. // Rest is too complex to inline, so factor that out as a call.
  716. Function fpc_ansistr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_ANSISTR_UNIQUE']; compilerproc; inline;
  717. {
  718. Make sure reference count of S is 1,
  719. using copy-on-write semantics.
  720. }
  721. begin
  722. pointer(result) := pointer(s);
  723. if (result<>Nil) and (PAnsiRec(result-AnsiFirstOff)^.Ref<>1) then
  724. result:=fpc_truely_ansistr_unique(s);
  725. end;
  726. {$endif FPC_SYSTEM_HAS_ANSISTR_UNIQUE}
  727. {$ifndef FPC_HAS_ANSISTR_COPY}
  728. {$define FPC_HAS_ANSISTR_COPY}
  729. Function Fpc_Ansistr_Copy(Const S : RawByteString; Index,Size : SizeInt): RawByteString;compilerproc;
  730. var
  731. Lim : SizeInt;
  732. ResultAddress : Pointer;
  733. begin
  734. ResultAddress:=Nil;
  735. dec(index);
  736. if Index < 0 then
  737. Index := 0;
  738. Lim:=Length(S)-Index; { Cannot overflow as both Length(S) and Index are non-negative. }
  739. if Size>Lim then
  740. Size:=Lim;
  741. If Size>0 then
  742. begin
  743. ResultAddress:=NewAnsiString(Size);
  744. if ResultAddress<>Nil then
  745. begin
  746. Move(Pointer(Pointer(S)+index)^,ResultAddress^,Size);
  747. PByte(ResultAddress+Size)^:=0;
  748. PAnsiRec(ResultAddress-AnsiFirstOff)^.Len:=Size;
  749. PAnsiRec(ResultAddress-AnsiFirstOff)^.CodePage:=PAnsiRec(Pointer(S)-AnsiFirstOff)^.CodePage;
  750. end;
  751. end;
  752. fpc_ansistr_decr_ref(Pointer(fpc_ansistr_copy));
  753. Pointer(fpc_ansistr_Copy):=ResultAddress;
  754. end;
  755. {$endif FPC_HAS_ANSISTR_COPY}
  756. {$ifndef FPC_HAS_POS_SHORTSTR_ANSISTR}
  757. {$define FPC_HAS_POS_SHORTSTR_ANSISTR}
  758. Function Pos(Const Substr : ShortString; Const Source : RawByteString; Offset : Sizeint = 1) : SizeInt;
  759. var
  760. nsource : SizeInt;
  761. begin
  762. nsource:=Length(Source);
  763. result:=0;
  764. dec(Offset);
  765. if SizeUint(Offset)<SizeUint(nsource) then { (Offset >= 0) and (Offset < nsource) }
  766. result:=MemPos(PByte(@Substr[1]),length(Substr),PByte(Source)+Offset,nsource-Offset)+1;
  767. if result>0 then
  768. inc(result,Offset);
  769. end;
  770. {$endif FPC_HAS_POS_SHORTSTR_ANSISTR}
  771. {$ifndef FPC_HAS_POS_ANSISTR_ANSISTR}
  772. {$define FPC_HAS_POS_ANSISTR_ANSISTR}
  773. Function Pos(Const Substr : RawByteString; Const Source : RawByteString; Offset : Sizeint = 1) : SizeInt;
  774. var
  775. nsource : SizeInt;
  776. begin
  777. nsource:=Length(Source);
  778. result:=0;
  779. dec(Offset);
  780. if SizeUint(Offset)<SizeUint(nsource) then { (Offset >= 0) and (Offset < nsource) }
  781. result:=MemPos(PByte(Substr),length(Substr),PByte(Source)+Offset,nsource-Offset)+1;
  782. if result>0 then
  783. inc(result,Offset);
  784. end;
  785. {$endif FPC_HAS_POS_ANSISTR_ANSISTR}
  786. {$ifndef FPC_HAS_POS_ANSICHAR_ANSISTR}
  787. {$define FPC_HAS_POS_ANSICHAR_ANSISTR}
  788. { Faster version for a AnsiChar alone. Must be implemented because }
  789. { pos(c: AnsiChar; const s: shortstring) also exists, so otherwise }
  790. { using pos(AnsiChar,pansichar) will always call the shortstring version }
  791. { (exact match for first argument), also with $h+ (JM) }
  792. Function Pos(c : AnsiChar; Const s : RawByteString; Offset : Sizeint = 1) : SizeInt;
  793. var
  794. ns,idx: SizeInt;
  795. begin
  796. pos:=0;
  797. ns:=length(s);
  798. if (Offset>0) and (Offset<=ns) then
  799. begin
  800. idx:=IndexByte(s[Offset],ns-Offset+1,byte(c));
  801. if idx>=0 then
  802. pos:=Offset+idx;
  803. end;
  804. end;
  805. {$endif FPC_HAS_POS_ANSICHAR_ANSISTR}
  806. {$ifndef FPUNONE}
  807. Function fpc_Val_Real_AnsiStr(Const S : RawByteString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_ANSISTR']; compilerproc;
  808. Var
  809. SS : ShortString;
  810. begin
  811. fpc_Val_Real_AnsiStr := 0;
  812. if length(S) > 255 then
  813. code := 256
  814. else
  815. begin
  816. SS := S;
  817. Val(SS,fpc_Val_Real_AnsiStr,code);
  818. end;
  819. end;
  820. {$endif}
  821. Function fpc_Val_Currency_AnsiStr(Const S : RawByteString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_ANSISTR']; compilerproc;
  822. Var
  823. SS : ShortString;
  824. begin
  825. if length(S) > 255 then
  826. begin
  827. fpc_Val_Currency_AnsiStr := 0;
  828. code := 256;
  829. end
  830. else
  831. begin
  832. SS := S;
  833. Val(SS,fpc_Val_Currency_AnsiStr,code);
  834. end;
  835. end;
  836. Function fpc_Val_UInt_AnsiStr ({$ifndef VER3_2}DestSize: SizeInt;{$endif VER3_2} Const S : RawByteString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_ANSISTR']; compilerproc;
  837. Var
  838. SS : ShortString;
  839. begin
  840. fpc_Val_UInt_AnsiStr := 0;
  841. if length(S) > 255 then
  842. code := 256
  843. else
  844. begin
  845. SS := S;
  846. Val(SS,fpc_Val_UInt_AnsiStr,code);
  847. end;
  848. end;
  849. Function fpc_Val_SInt_AnsiStr (DestSize: SizeInt; Const S : RawByteString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_ANSISTR']; compilerproc;
  850. Var
  851. SS : ShortString;
  852. begin
  853. fpc_Val_SInt_AnsiStr:=0;
  854. if length(S)>255 then
  855. code:=256
  856. else
  857. begin
  858. SS := S;
  859. fpc_Val_SInt_AnsiStr := int_Val_SInt_ShortStr(DestSize,SS,Code);
  860. end;
  861. end;
  862. {$ifndef CPU64}
  863. Function fpc_Val_qword_AnsiStr (Const S : RawByteString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_ANSISTR']; compilerproc;
  864. Var
  865. SS : ShortString;
  866. begin
  867. fpc_Val_qword_AnsiStr:=0;
  868. if length(S)>255 then
  869. code:=256
  870. else
  871. begin
  872. SS := S;
  873. Val(SS,fpc_Val_qword_AnsiStr,Code);
  874. end;
  875. end;
  876. Function fpc_Val_int64_AnsiStr (Const S : RawByteString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_ANSISTR']; compilerproc;
  877. Var
  878. SS : ShortString;
  879. begin
  880. fpc_Val_int64_AnsiStr:=0;
  881. if length(S)>255 then
  882. code:=256
  883. else
  884. begin
  885. SS := s;
  886. Val(SS,fpc_Val_int64_AnsiStr,Code);
  887. end;
  888. end;
  889. {$endif CPU64}
  890. {$if defined(CPU16) or defined(CPU8)}
  891. Function fpc_Val_longword_AnsiStr (Const S : RawByteString; out Code : ValSInt): longword; [public, alias:'FPC_VAL_LONGWORD_ANSISTR']; compilerproc;
  892. Var
  893. SS : ShortString;
  894. begin
  895. fpc_Val_longword_AnsiStr:=0;
  896. if length(S)>255 then
  897. code:=256
  898. else
  899. begin
  900. SS := S;
  901. Val(SS,fpc_Val_longword_AnsiStr,Code);
  902. end;
  903. end;
  904. Function fpc_Val_longint_AnsiStr (Const S : RawByteString; out Code : ValSInt): LongInt; [public, alias:'FPC_VAL_LONGINT_ANSISTR']; compilerproc;
  905. Var
  906. SS : ShortString;
  907. begin
  908. fpc_Val_longint_AnsiStr:=0;
  909. if length(S)>255 then
  910. code:=256
  911. else
  912. begin
  913. SS := s;
  914. Val(SS,fpc_Val_longint_AnsiStr,Code);
  915. end;
  916. end;
  917. Function fpc_Val_word_AnsiStr (Const S : RawByteString; out Code : ValSInt): word; [public, alias:'FPC_VAL_WORD_ANSISTR']; compilerproc;
  918. Var
  919. SS : ShortString;
  920. begin
  921. fpc_Val_word_AnsiStr:=0;
  922. if length(S)>255 then
  923. code:=256
  924. else
  925. begin
  926. SS := S;
  927. Val(SS,fpc_Val_word_AnsiStr,Code);
  928. end;
  929. end;
  930. Function fpc_Val_smallint_AnsiStr (Const S : RawByteString; out Code : ValSInt): smallint; [public, alias:'FPC_VAL_SMALLINT_ANSISTR']; compilerproc;
  931. Var
  932. SS : ShortString;
  933. begin
  934. fpc_Val_smallint_AnsiStr:=0;
  935. if length(S)>255 then
  936. code:=256
  937. else
  938. begin
  939. SS := s;
  940. Val(SS,fpc_Val_smallint_AnsiStr,Code);
  941. end;
  942. end;
  943. {$endif CPU16 or CPU8}
  944. {$if defined(CPU8)}
  945. Function fpc_Val_word_AnsiStr (Const S : RawByteString; out Code : ValSInt): longword; [public, alias:'FPC_VAL_WORD_ANSISTR']; compilerproc;
  946. Var
  947. SS : ShortString;
  948. begin
  949. fpc_Val_longword_AnsiStr:=0;
  950. if length(S)>255 then
  951. code:=256
  952. else
  953. begin
  954. SS := S;
  955. Val(SS,fpc_Val_longword_AnsiStr,Code);
  956. end;
  957. end;
  958. Function fpc_Val_smallint_AnsiStr (Const S : RawByteString; out Code : ValSInt): LongInt; [public, alias:'FPC_VAL_SMALLINT_ANSISTR']; compilerproc;
  959. Var
  960. SS : ShortString;
  961. begin
  962. fpc_Val_longint_AnsiStr:=0;
  963. if length(S)>255 then
  964. code:=256
  965. else
  966. begin
  967. SS := s;
  968. Val(SS,fpc_Val_longint_AnsiStr,Code);
  969. end;
  970. end;
  971. {$endif CPU8}
  972. {$ifndef FPUNONE}
  973. procedure fpc_AnsiStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : RawByteString;cp : TSystemCodePage);[public,alias:'FPC_ANSISTR_FLOAT']; compilerproc; inline;
  974. var
  975. ss: ShortString;
  976. begin
  977. str_real(len,fr,d,treal_type(rt),ss);
  978. s:=ss;
  979. SetCodePage(s,cp,false);
  980. end;
  981. {$endif}
  982. {$ifndef FPC_STR_ENUM_INTERN}
  983. procedure fpc_ansistr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:RawByteString;cp : TSystemCodePage);[public,alias:'FPC_ANSISTR_ENUM'];compilerproc; inline;
  984. var ss:shortstring;
  985. begin
  986. fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss);
  987. s:=ss;
  988. SetCodePage(s,cp,false);
  989. end;
  990. {$endif FPC_STR_ENUM_INTERN}
  991. procedure fpc_ansistr_bool(b : boolean;len:sizeint;out s:RawByteString;cp : TSystemCodePage);[public,alias:'FPC_ANSISTR_BOOL'];compilerproc; inline;
  992. var
  993. ss:shortstring;
  994. begin
  995. fpc_shortstr_bool(b,len,ss);
  996. s:=ss;
  997. SetCodePage(s,cp,false);
  998. end;
  999. {$ifndef FPC_STR_ENUM_INTERN}
  1000. function fpc_val_enum_ansistr(str2ordindex:pointer;const s:RawByteString;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_ANSISTR']; compilerproc;
  1001. begin
  1002. fpc_val_enum_ansistr:=fpc_val_enum_shortstr(str2ordindex,s,code);
  1003. end;
  1004. {$endif FPC_STR_ENUM_INTERN}
  1005. procedure fpc_AnsiStr_Currency(c : currency;len,fr : SizeInt;out s : RawByteString;cp : TSystemCodePage);[public,alias:'FPC_ANSISTR_CURRENCY']; compilerproc; inline;
  1006. var
  1007. ss: ShortString;
  1008. begin
  1009. str(c:len:fr,ss);
  1010. s:=ss;
  1011. SetCodePage(s,cp,false);
  1012. end;
  1013. Procedure fpc_AnsiStr_UInt(v : ValUInt;Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_VALUINT']; compilerproc; inline;
  1014. Var
  1015. SS : ShortString;
  1016. begin
  1017. str(v:Len,SS);
  1018. S:=SS;
  1019. SetCodePage(s,cp,false);
  1020. end;
  1021. Procedure fpc_AnsiStr_SInt(v : ValSInt;Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_VALSINT']; compilerproc; inline;
  1022. Var
  1023. SS : ShortString;
  1024. begin
  1025. str (v:Len,SS);
  1026. S:=SS;
  1027. SetCodePage(s,cp,false);
  1028. end;
  1029. {$ifndef CPU64}
  1030. Procedure fpc_AnsiStr_QWord(v : QWord;Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_QWORD']; compilerproc; inline;
  1031. Var
  1032. SS : ShortString;
  1033. begin
  1034. str(v:Len,SS);
  1035. S:=SS;
  1036. SetCodePage(s,cp,false);
  1037. end;
  1038. Procedure fpc_AnsiStr_Int64(v : Int64; Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_INT64']; compilerproc; inline;
  1039. Var
  1040. SS : ShortString;
  1041. begin
  1042. str (v:Len,SS);
  1043. S:=SS;
  1044. SetCodePage(s,cp,false);
  1045. end;
  1046. {$endif CPU64}
  1047. {$if defined(CPU16) or defined(CPU8)}
  1048. Procedure fpc_AnsiStr_LongWord(v : LongWord;Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_LONGWORD']; compilerproc; inline;
  1049. Var
  1050. SS : ShortString;
  1051. begin
  1052. str(v:Len,SS);
  1053. S:=SS;
  1054. SetCodePage(s,cp,false);
  1055. end;
  1056. Procedure fpc_AnsiStr_LongInt(v : LongInt; Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_LONGINT']; compilerproc; inline;
  1057. Var
  1058. SS : ShortString;
  1059. begin
  1060. str (v:Len,SS);
  1061. S:=SS;
  1062. SetCodePage(s,cp,false);
  1063. end;
  1064. Procedure fpc_AnsiStr_Word(v : Word;Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_WORD']; compilerproc; inline;
  1065. Var
  1066. SS : ShortString;
  1067. begin
  1068. str(v:Len,SS);
  1069. S:=SS;
  1070. SetCodePage(s,cp,false);
  1071. end;
  1072. Procedure fpc_AnsiStr_SmallInt(v : SmallInt; Len : SizeInt; out S : RawByteString;cp : TSystemCodePage);[Public,Alias : 'FPC_ANSISTR_SMALLINT']; compilerproc; inline;
  1073. Var
  1074. SS : ShortString;
  1075. begin
  1076. str (v:Len,SS);
  1077. S:=SS;
  1078. SetCodePage(s,cp,false);
  1079. end;
  1080. {$endif CPU16 or CPU8}
  1081. Procedure fpc_ansistr_delete(Var S : RawByteString; Index,Size: SizeInt);
  1082. Var
  1083. LS : SizeInt;
  1084. begin
  1085. ls:=Length(S);
  1086. If (Index>LS) or (Index<=0) or (Size<=0) then
  1087. exit;
  1088. UniqueString(S);
  1089. If (Size>LS-Index) then // Size+Index gives overflow ??
  1090. Size:=LS-Index+1;
  1091. If (Size<=LS-Index) then
  1092. begin
  1093. Dec(Index);
  1094. fpc_pchar_ansistr_intern_charmove(PAnsiChar(S),Index+Size,S,Index,LS-Index-Size+1);
  1095. end;
  1096. Setlength(S,LS-Size);
  1097. end;
  1098. Procedure fpc_ansistr_insert(Const Source : RawByteString; Var S : RawByteString; Index : SizeInt);
  1099. var
  1100. LS,LSource : SizeInt;
  1101. {$ifdef jvm}
  1102. Temp : RawByteString;
  1103. {$else}
  1104. selfinsert : boolean;
  1105. srcp : PAnsiChar;
  1106. {$endif}
  1107. begin
  1108. If Source='' then
  1109. exit;
  1110. if S='' then
  1111. begin
  1112. S:=Source;
  1113. exit;
  1114. end;
  1115. LSource:={$ifdef jvm}Length(Source){$else}PAnsiRec(Pointer(Source)-AnsiFirstOff)^.Len{$endif};
  1116. LS:={$ifdef jvm}Length(S){$else}PAnsiRec(Pointer(S)-AnsiFirstOff)^.Len{$endif};
  1117. Dec(Index);
  1118. if index < 0 then
  1119. index := 0;
  1120. if index > LS then
  1121. index := LS;
  1122. {$ifdef jvm}
  1123. SetLength(Temp,LSource+LS);
  1124. SetCodePage(Temp,StringCodePage(S),false);
  1125. If Index>0 then
  1126. fpc_pchar_ansistr_intern_charmove(PAnsiChar(S),0,Temp,0,Index);
  1127. fpc_pchar_ansistr_intern_charmove(PAnsiChar(Source),0,Temp,Index,LSource);
  1128. If (LS-Index)>0 then
  1129. fpc_pchar_ansistr_intern_charmove(PAnsiChar(S),Index,Temp,LSource+Index,LS-Index);
  1130. S:=Temp;
  1131. {$else}
  1132. selfinsert:=Pointer(Source)=Pointer(S);
  1133. SetLength(S,LS+LSource);
  1134. Move(PAnsiChar(Pointer(S))[Index],PAnsiChar(Pointer(S))[Index+LSource],(LS-Index)*SizeOf(AnsiChar));
  1135. srcp:=Pointer(Source);
  1136. if selfinsert then
  1137. srcp:=Pointer(S);
  1138. Move(srcp^,PAnsiChar(Pointer(S))[Index],LSource*SizeOf(AnsiChar));
  1139. {$endif}
  1140. end;
  1141. {$ifndef FPC_HAS_ANSISTR_OF_CHAR}
  1142. {$define FPC_HAS_ANSISTR_OF_CHAR}
  1143. Function StringOfChar(c : Ansichar;l : SizeInt) : AnsiString;
  1144. begin
  1145. SetLength(StringOfChar,l);
  1146. FillChar(Pointer(StringOfChar)^,Length(StringOfChar),c);
  1147. end;
  1148. {$endif FPC_HAS_ANSISTR_OF_CHAR}
  1149. Procedure fpc_setstring_ansistr_pansichar(out S : RawByteString; Buf : PAnsiChar; Len : SizeInt; cp: TSystemCodePage); rtlproc; compilerproc;
  1150. begin
  1151. SetLength(S,Len);
  1152. SetCodePage(S,cp,false);
  1153. If (Buf<>Nil) then
  1154. fpc_pchar_ansistr_intern_charmove(Buf,0,S,0,Len);
  1155. end;
  1156. Procedure fpc_setstring_ansistr_pwidechar(out S : RawByteString; Buf : PWideChar; Len : SizeInt; cp: TSystemCodePage); rtlproc; compilerproc;
  1157. begin
  1158. cp:=TranslatePlaceholderCP(cp);
  1159. if (Buf<>nil) and (Len>0) then
  1160. widestringmanager.Wide2AnsiMoveProc(Buf,S,cp,Len)
  1161. else
  1162. begin
  1163. SetLength(S, Len);
  1164. SetCodePage(S,cp,false);
  1165. end;
  1166. end;
  1167. {$ifndef FPC_HAS_UPCASE_ANSISTR}
  1168. {$define FPC_HAS_UPCASE_ANSISTR}
  1169. function upcase(const s : ansistring) : ansistring;
  1170. var
  1171. i : SizeInt;
  1172. begin
  1173. Setlength(result,length(s));
  1174. for i := 1 to length (s) do
  1175. result[i] := upcase(s[i]);
  1176. end;
  1177. {$endif FPC_HAS_UPCASE_ANSISTR}
  1178. {$ifndef FPC_HAS_LOWERCASE_ANSISTR}
  1179. {$define FPC_HAS_LOWERCASE_ANSISTR}
  1180. function lowercase(const s : ansistring) : ansistring;
  1181. var
  1182. i : SizeInt;
  1183. begin
  1184. Setlength(result,length(s));
  1185. for i := 1 to length (s) do
  1186. result[i] := lowercase(s[i]);
  1187. end;
  1188. {$endif FPC_HAS_LOWERCASE_ANSISTR}
  1189. {$ifndef FPC_HAS_ANSISTR_STRINGCODEPAGE}
  1190. {$define FPC_HAS_ANSISTR_STRINGCODEPAGE}
  1191. function StringCodePage(const S: RawByteString): TSystemCodePage; overload;
  1192. begin
  1193. if assigned(Pointer(S)) then
  1194. Result:=PAnsiRec(pointer(S)-AnsiFirstOff)^.CodePage
  1195. else
  1196. Result:=DefaultSystemCodePage;
  1197. end;
  1198. {$endif FPC_HAS_ANSISTR_STRINGCODEPAGE}
  1199. {$ifndef FPC_HAS_ANSISTR_STRINGELEMENTSIZE}
  1200. {$define FPC_HAS_ANSISTR_STRINGELEMENTSIZE}
  1201. function StringElementSize(const S: RawByteString): Word; overload;
  1202. begin
  1203. if assigned(Pointer(S)) then
  1204. Result:=PAnsiRec(pointer(S)-AnsiFirstOff)^.ElementSize
  1205. else
  1206. Result:=SizeOf(AnsiChar);
  1207. end;
  1208. {$endif FPC_HAS_ANSISTR_STRINGELEMENTSIZE}
  1209. {$ifndef FPC_HAS_ANSISTR_STRINGREFCOUNT}
  1210. {$define FPC_HAS_ANSISTR_STRINGREFCOUNT}
  1211. function StringRefCount(const S: RawByteString): SizeInt; overload;
  1212. begin
  1213. if assigned(Pointer(S)) then
  1214. Result:=PAnsiRec(pointer(S)-AnsiFirstOff)^.Ref
  1215. else
  1216. Result:=0;
  1217. end;
  1218. {$endif FPC_HAS_ANSISTR_STRINGREFCOUNT}
  1219. {$ifndef FPC_HAS_ANSISTR_SETCODEPAGE}
  1220. {$define FPC_HAS_ANSISTR_SETCODEPAGE}
  1221. procedure InternalSetCodePage(var s : RawByteString; CodePage : TSystemCodePage; Convert : Boolean = True);
  1222. begin
  1223. if Convert then
  1224. begin
  1225. s:=fpc_AnsiStr_To_AnsiStr(s,CodePage);
  1226. end
  1227. else
  1228. begin
  1229. UniqueString(s);
  1230. PAnsiRec(pointer(s)-AnsiFirstOff)^.CodePage:=CodePage;
  1231. end;
  1232. end;
  1233. { use this wrapper for the simple case to avoid the generation of a temp. ansistring which causes
  1234. extra exception frames }
  1235. procedure SetCodePage(var s : RawByteString; CodePage : TSystemCodePage; Convert : Boolean = True);
  1236. var
  1237. OrgCodePage,
  1238. TranslatedCodePage,
  1239. TranslatedCurrentCodePage: TSystemCodePage;
  1240. begin
  1241. if Length(S)=0 then
  1242. exit;
  1243. { if the codepage are identical, we don't have to do anything (even if the
  1244. string has multiple references) }
  1245. OrgCodePage:=PAnsiRec(pointer(S)-AnsiFirstOff)^.CodePage;
  1246. if OrgCodePage=CodePage then
  1247. exit;
  1248. { if we're just replacing a placeholder code page with its actual value or
  1249. vice versa, we don't have to perform any conversion }
  1250. TranslatedCurrentCodePage:=TranslatePlaceholderCP(OrgCodePage);
  1251. TranslatedCodePage:=TranslatePlaceholderCP(CodePage);
  1252. Convert:=Convert and
  1253. (TranslatedCurrentCodePage<>TranslatedCodePage);
  1254. if not Convert and (PAnsiRec(pointer(S)-AnsiFirstOff)^.Ref=1) then
  1255. PAnsiRec(pointer(S)-AnsiFirstOff)^.CodePage:=CodePage
  1256. else
  1257. InternalSetCodePage(S,CodePage,Convert);
  1258. end;
  1259. {$endif FPC_HAS_ANSISTR_SETCODEPAGE}
  1260. procedure SetMultiByteConversionCodePage(CodePage: TSystemCodePage);
  1261. begin
  1262. DefaultSystemCodePage:=CodePage;
  1263. end;
  1264. procedure SetMultiByteFileSystemCodePage(CodePage: TSystemCodePage);
  1265. begin
  1266. DefaultFileSystemCodePage:=CodePage;
  1267. end;
  1268. procedure SetMultiByteRTLFileSystemCodePage(CodePage: TSystemCodePage);
  1269. begin
  1270. DefaultRTLFileSystemCodePage:=CodePage;
  1271. end;