sstrings.inc 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************
  11. subroutines for string handling
  12. ****************************************************************************}
  13. procedure fpc_Shortstr_SetLength(var s:shortstring;len:SizeInt);[Public,Alias : 'FPC_SHORTSTR_SETLENGTH']; compilerproc;
  14. begin
  15. if Len>255 then
  16. Len:=255;
  17. s[0]:=chr(len);
  18. end;
  19. function fpc_shortstr_copy(const s : shortstring;index : SizeInt;count : SizeInt): shortstring;compilerproc;
  20. begin
  21. if count<0 then
  22. count:=0;
  23. if index>1 then
  24. dec(index)
  25. else
  26. index:=0;
  27. if index>length(s) then
  28. count:=0
  29. else
  30. if count>length(s)-index then
  31. count:=length(s)-index;
  32. fpc_shortstr_Copy[0]:=chr(Count);
  33. Move(s[Index+1],fpc_shortstr_Copy[1],Count);
  34. end;
  35. procedure delete(var s : shortstring;index : SizeInt;count : SizeInt);
  36. begin
  37. if index<=0 then
  38. exit;
  39. if (Index<=Length(s)) and (Count>0) then
  40. begin
  41. if Count>length(s)-Index then
  42. Count:=length(s)-Index+1;
  43. s[0]:=Chr(length(s)-Count);
  44. if Index<=Length(s) then
  45. Move(s[Index+Count],s[Index],Length(s)-Index+1);
  46. end;
  47. end;
  48. procedure insert(const source : shortstring;var s : shortstring;index : SizeInt);
  49. var
  50. cut,srclen,indexlen : SizeInt;
  51. begin
  52. if index<1 then
  53. index:=1;
  54. if index>length(s) then
  55. index:=length(s)+1;
  56. indexlen:=Length(s)-Index+1;
  57. srclen:=length(Source);
  58. if sizeInt(length(source))+sizeint(length(s))>=sizeof(s) then
  59. begin
  60. cut:=sizeInt(length(source))+sizeint(length(s))-sizeof(s)+1;
  61. if cut>indexlen then
  62. begin
  63. dec(srclen,cut-indexlen);
  64. indexlen:=0;
  65. end
  66. else
  67. dec(indexlen,cut);
  68. end;
  69. move(s[Index],s[Index+srclen],indexlen);
  70. move(Source[1],s[Index],srclen);
  71. s[0]:=chr(index+srclen+indexlen-1);
  72. end;
  73. procedure insert(source : Char;var s : shortstring;index : SizeInt);
  74. var
  75. indexlen : SizeInt;
  76. begin
  77. if index<1 then
  78. index:=1;
  79. if index>length(s) then
  80. index:=length(s)+1;
  81. indexlen:=Length(s)-Index+1;
  82. if (sizeint(length(s))+1=sizeof(s)) and (indexlen>0) then
  83. dec(indexlen);
  84. move(s[Index],s[Index+1],indexlen);
  85. s[Index]:=Source;
  86. s[0]:=chr(index+indexlen);
  87. end;
  88. function pos(const substr : shortstring;const s : shortstring):SizeInt;
  89. var
  90. i,MaxLen : SizeInt;
  91. pc : pchar;
  92. begin
  93. Pos:=0;
  94. if Length(SubStr)>0 then
  95. begin
  96. MaxLen:=sizeint(Length(s))-Length(SubStr);
  97. i:=0;
  98. pc:=@s[1];
  99. while (i<=MaxLen) do
  100. begin
  101. inc(i);
  102. if (SubStr[1]=pc^) and
  103. (CompareChar(Substr[1],pc^,Length(SubStr))=0) then
  104. begin
  105. Pos:=i;
  106. exit;
  107. end;
  108. inc(pc);
  109. end;
  110. end;
  111. end;
  112. {Faster when looking for a single char...}
  113. function pos(c:char;const s:shortstring):SizeInt;
  114. var
  115. i : SizeInt;
  116. pc : pchar;
  117. begin
  118. pc:=@s[1];
  119. for i:=1 to length(s) do
  120. begin
  121. if pc^=c then
  122. begin
  123. pos:=i;
  124. exit;
  125. end;
  126. inc(pc);
  127. end;
  128. pos:=0;
  129. end;
  130. function fpc_char_copy(c:char;index : SizeInt;count : SizeInt): shortstring;compilerproc;
  131. begin
  132. if (index=1) and (Count>0) then
  133. fpc_char_Copy:=c
  134. else
  135. fpc_char_Copy:='';
  136. end;
  137. function pos(const substr : shortstring;c:char): SizeInt;
  138. begin
  139. if (length(substr)=1) and (substr[1]=c) then
  140. Pos:=1
  141. else
  142. Pos:=0;
  143. end;
  144. {$ifdef IBM_CHAR_SET}
  145. const
  146. UpCaseTbl : shortstring[7]=#154#142#153#144#128#143#165;
  147. LoCaseTbl : shortstring[7]=#129#132#148#130#135#134#164;
  148. {$endif}
  149. function upcase(c : char) : char;
  150. {$IFDEF IBM_CHAR_SET}
  151. var
  152. i : longint;
  153. {$ENDIF}
  154. begin
  155. if (c in ['a'..'z']) then
  156. upcase:=char(byte(c)-32)
  157. else
  158. {$IFDEF IBM_CHAR_SET}
  159. begin
  160. i:=Pos(c,LoCaseTbl);
  161. if i>0 then
  162. upcase:=UpCaseTbl[i]
  163. else
  164. upcase:=c;
  165. end;
  166. {$ELSE}
  167. upcase:=c;
  168. {$ENDIF}
  169. end;
  170. function upcase(const s : shortstring) : shortstring;
  171. var
  172. i : longint;
  173. begin
  174. upcase[0]:=s[0];
  175. for i := 1 to length (s) do
  176. upcase[i] := upcase (s[i]);
  177. end;
  178. function lowercase(c : char) : char;overload;
  179. {$IFDEF IBM_CHAR_SET}
  180. var
  181. i : longint;
  182. {$ENDIF}
  183. begin
  184. if (c in ['A'..'Z']) then
  185. lowercase:=char(byte(c)+32)
  186. else
  187. {$IFDEF IBM_CHAR_SET}
  188. begin
  189. i:=Pos(c,UpCaseTbl);
  190. if i>0 then
  191. lowercase:=LoCaseTbl[i]
  192. else
  193. lowercase:=c;
  194. end;
  195. {$ELSE}
  196. lowercase:=c;
  197. {$ENDIF}
  198. end;
  199. function lowercase(const s : shortstring) : shortstring; overload;
  200. var
  201. i : longint;
  202. begin
  203. lowercase [0]:=s[0];
  204. for i:=1 to length(s) do
  205. lowercase[i]:=lowercase (s[i]);
  206. end;
  207. const
  208. HexTbl : array[0..15] of char='0123456789ABCDEF';
  209. function hexstr(val : longint;cnt : byte) : shortstring;
  210. var
  211. i : longint;
  212. begin
  213. hexstr[0]:=char(cnt);
  214. for i:=cnt downto 1 do
  215. begin
  216. hexstr[i]:=hextbl[val and $f];
  217. val:=val shr 4;
  218. end;
  219. end;
  220. function octstr(val : longint;cnt : byte) : shortstring;
  221. var
  222. i : longint;
  223. begin
  224. octstr[0]:=char(cnt);
  225. for i:=cnt downto 1 do
  226. begin
  227. octstr[i]:=hextbl[val and 7];
  228. val:=val shr 3;
  229. end;
  230. end;
  231. function binstr(val : longint;cnt : byte) : shortstring;
  232. var
  233. i : longint;
  234. begin
  235. binstr[0]:=char(cnt);
  236. for i:=cnt downto 1 do
  237. begin
  238. binstr[i]:=char(48+val and 1);
  239. val:=val shr 1;
  240. end;
  241. end;
  242. function hexstr(val : int64;cnt : byte) : shortstring;
  243. var
  244. i : longint;
  245. begin
  246. hexstr[0]:=char(cnt);
  247. for i:=cnt downto 1 do
  248. begin
  249. hexstr[i]:=hextbl[val and $f];
  250. val:=val shr 4;
  251. end;
  252. end;
  253. function octstr(val : int64;cnt : byte) : shortstring;
  254. var
  255. i : longint;
  256. begin
  257. octstr[0]:=char(cnt);
  258. for i:=cnt downto 1 do
  259. begin
  260. octstr[i]:=hextbl[val and 7];
  261. val:=val shr 3;
  262. end;
  263. end;
  264. function binstr(val : int64;cnt : byte) : shortstring;
  265. var
  266. i : longint;
  267. begin
  268. binstr[0]:=char(cnt);
  269. for i:=cnt downto 1 do
  270. begin
  271. binstr[i]:=char(48+val and 1);
  272. val:=val shr 1;
  273. end;
  274. end;
  275. Function hexStr(Val:qword;cnt:byte):shortstring;
  276. begin
  277. hexStr:=hexStr(int64(Val),cnt);
  278. end;
  279. Function OctStr(Val:qword;cnt:byte):shortstring;
  280. begin
  281. OctStr:=OctStr(int64(Val),cnt);
  282. end;
  283. Function binStr(Val:qword;cnt:byte):shortstring;
  284. begin
  285. binStr:=binStr(int64(Val),cnt);
  286. end;
  287. function hexstr(val : pointer) : shortstring;
  288. var
  289. i : longint;
  290. v : ptruint;
  291. begin
  292. v:=ptruint(val);
  293. hexstr[0]:=chr(sizeof(pointer)*2);
  294. for i:=sizeof(pointer)*2 downto 1 do
  295. begin
  296. hexstr[i]:=hextbl[v and $f];
  297. v:=v shr 4;
  298. end;
  299. end;
  300. function space (b : byte): shortstring;
  301. begin
  302. space[0] := chr(b);
  303. FillChar (Space[1],b,' ');
  304. end;
  305. {*****************************************************************************
  306. Str() Helpers
  307. *****************************************************************************}
  308. procedure fpc_shortstr_SInt(v : valSInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SINT']; compilerproc;
  309. begin
  310. int_str(v,s);
  311. if length(s)<len then
  312. s:=space(len-length(s))+s;
  313. end;
  314. procedure fpc_shortstr_UInt(v : valUInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_UINT']; compilerproc;
  315. begin
  316. int_str(v,s);
  317. if length(s)<len then
  318. s:=space(len-length(s))+s;
  319. end;
  320. {$ifndef CPU64}
  321. procedure fpc_shortstr_qword(v : qword;len : longint;out s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; compilerproc;
  322. begin
  323. int_str(v,s);
  324. if length(s)<len then
  325. s:=space(len-length(s))+s;
  326. end;
  327. procedure fpc_shortstr_int64(v : int64;len : longint;out s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; compilerproc;
  328. begin
  329. int_str(v,s);
  330. if length(s)<len then
  331. s:=space(len-length(s))+s;
  332. end;
  333. {$endif CPU64}
  334. { fpc_shortstr_sInt must appear before this file is included, because }
  335. { it's used inside real2str.inc and otherwise the searching via the }
  336. { compilerproc name will fail (JM) }
  337. {$I real2str.inc}
  338. procedure fpc_shortstr_float(d : ValReal;len,fr,rt : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_FLOAT']; compilerproc;
  339. begin
  340. str_real(len,fr,d,treal_type(rt),s);
  341. end;
  342. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);[public,alias:'FPC_SHORTSTR_ENUM'];compilerproc;
  343. type
  344. Ptypeinfo=^Ttypeinfo;
  345. Ttypeinfo=record
  346. kind:byte;
  347. name:shortstring;
  348. end;
  349. Penuminfo=^Tenuminfo;
  350. Tenuminfo={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  351. ordtype:byte;
  352. minvalue,maxvalue:longint;
  353. basetype:pointer;
  354. namelist:shortstring;
  355. end;
  356. Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  357. o:longint;
  358. s:Pstring;
  359. end;
  360. var
  361. p:Pstring;
  362. l,h,m:cardinal;
  363. sorted_array:^Tsorted_array;
  364. i,spaces:byte;
  365. label
  366. error;
  367. begin
  368. if Pcardinal(ord2strindex)^=0 then
  369. begin
  370. {The compiler did generate a lookup table.}
  371. with Penuminfo(Pbyte(typinfo)+2+length(Ptypeinfo(typinfo)^.name))^ do
  372. begin
  373. if (ordinal<minvalue) or (ordinal>maxvalue) then
  374. goto error; {Invalid ordinal value for this enum.}
  375. dec(ordinal,minvalue);
  376. end;
  377. {Get the address of the string.}
  378. p:=Pshortstring((PPpointer(ord2strindex)+1+ordinal)^);
  379. if p=nil then
  380. goto error; {Invalid ordinal value for this enum.}
  381. s:=p^;
  382. end
  383. else
  384. begin
  385. {The compiler did generate a sorted array of (ordvalue,Pstring) tuples.}
  386. sorted_array:=pointer(Pcardinal(ord2strindex)+2);
  387. {Use a binary search to get the string.}
  388. l:=0;
  389. h:=(Pcardinal(ord2strindex)+1)^-1;
  390. repeat
  391. m:=(l+h) div 2;
  392. if ordinal>sorted_array[m].o then
  393. l:=m+1
  394. else if ordinal<sorted_array[m].o then
  395. h:=m-1
  396. else
  397. break;
  398. if l>h then
  399. goto error; {Ordinal value not found? Kaboom.}
  400. until false;
  401. s:=sorted_array[m].s^;
  402. end;
  403. {Pad the string with spaces if necessary.}
  404. if len>length(s) then
  405. begin
  406. spaces:=len-length(s);
  407. for i:=1 to spaces do
  408. s[length(s)+i]:=' ';
  409. inc(byte(s[0]),spaces);
  410. end;
  411. exit;
  412. error:
  413. {Call runtime error in a central place, this saves space.}
  414. runerror(107);
  415. end;
  416. { also define alias for internal use in the system unit }
  417. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);external name 'FPC_SHORTSTR_ENUM';
  418. procedure fpc_shortstr_currency(c : currency; len,f : SizeInt; out s : shortstring);[public,alias:'FPC_SHORTSTR_CURRENCY']; compilerproc;
  419. const
  420. MinLen = 8; { Minimal string length in scientific format }
  421. var
  422. buf : array[1..19] of char;
  423. i,j,k,reslen,tlen,sign,r,point : longint;
  424. ic : qword;
  425. begin
  426. { default value for length is -32767 }
  427. if len=-32767 then
  428. len:=25;
  429. if PInt64(@c)^ >= 0 then
  430. begin
  431. ic:=QWord(PInt64(@c)^);
  432. sign:=0;
  433. end
  434. else
  435. begin
  436. sign:=1;
  437. ic:=QWord(-PInt64(@c)^);
  438. end;
  439. { converting to integer string }
  440. tlen:=0;
  441. repeat
  442. Inc(tlen);
  443. buf[tlen]:=Chr(ic mod 10 + $30);
  444. ic:=ic div 10;
  445. until ic = 0;
  446. { calculating:
  447. reslen - length of result string,
  448. r - rounding or appending zeroes,
  449. point - place of decimal point }
  450. reslen:=tlen;
  451. if f <> 0 then
  452. Inc(reslen); { adding decimal point length }
  453. if f < 0 then
  454. begin
  455. { scientific format }
  456. Inc(reslen,5); { adding length of sign and exponent }
  457. if len < MinLen then
  458. len:=MinLen;
  459. r:=reslen-len;
  460. if reslen < len then
  461. reslen:=len;
  462. if r > 0 then
  463. begin
  464. reslen:=len;
  465. point:=tlen - r;
  466. end
  467. else
  468. point:=tlen;
  469. end
  470. else
  471. begin
  472. { fixed format }
  473. Inc(reslen, sign);
  474. { prepending fractional part with zeroes }
  475. while tlen < 5 do
  476. begin
  477. Inc(reslen);
  478. Inc(tlen);
  479. buf[tlen]:='0';
  480. end;
  481. { Currency have 4 digits in fractional part }
  482. r:=4 - f;
  483. point:=f;
  484. if point <> 0 then
  485. begin
  486. if point > 4 then
  487. point:=4;
  488. Inc(point);
  489. end;
  490. Dec(reslen,r);
  491. end;
  492. { rounding string if r > 0 }
  493. if r > 0 then
  494. begin
  495. i:=1;
  496. k:=0;
  497. for j:=0 to r do
  498. begin
  499. if (k=1) and (buf[i]='9') then
  500. buf[i]:='0'
  501. else
  502. begin
  503. buf[i]:=chr(ord(buf[i]) + k);
  504. if buf[i] >= '5' then
  505. k:=1
  506. else
  507. k:=0;
  508. end;
  509. Inc(i);
  510. if i>tlen then
  511. break;
  512. end;
  513. If (k=1) and (buf[i-1]='0') then
  514. buf[i]:=chr(Ord(buf[i])+1);
  515. end;
  516. { preparing result string }
  517. if reslen<len then
  518. reslen:=len;
  519. if reslen>High(s) then
  520. begin
  521. if r < 0 then
  522. Inc(r, reslen - High(s));
  523. reslen:=High(s);
  524. end;
  525. SetLength(s,reslen);
  526. j:=reslen;
  527. if f<0 then
  528. begin
  529. { writing power of 10 part }
  530. if PInt64(@c)^ = 0 then
  531. k:=0
  532. else
  533. k:=tlen-5;
  534. if k >= 0 then
  535. s[j-2]:='+'
  536. else
  537. begin
  538. s[j-2]:='-';
  539. k:=-k;
  540. end;
  541. s[j]:=Chr(k mod 10 + $30);
  542. Dec(j);
  543. s[j]:=Chr(k div 10 + $30);
  544. Dec(j,2);
  545. s[j]:='E';
  546. Dec(j);
  547. end;
  548. { writing extra zeroes if r < 0 }
  549. while r < 0 do
  550. begin
  551. s[j]:='0';
  552. Dec(j);
  553. Inc(r);
  554. end;
  555. { writing digits and decimal point }
  556. for i:=r + 1 to tlen do
  557. begin
  558. Dec(point);
  559. if point = 0 then
  560. begin
  561. s[j]:='.';
  562. Dec(j);
  563. end;
  564. s[j]:=buf[i];
  565. Dec(j);
  566. end;
  567. { writing sign }
  568. if sign = 1 then
  569. begin
  570. s[j]:='-';
  571. Dec(j);
  572. end;
  573. { writing spaces }
  574. while j > 0 do
  575. begin
  576. s[j]:=' ';
  577. Dec(j);
  578. end;
  579. end;
  580. {
  581. Array Of Char Str() helpers
  582. }
  583. procedure fpc_chararray_sint(v : valsint;len : SizeInt;out a:array of char);compilerproc;
  584. var
  585. ss : shortstring;
  586. maxlen : SizeInt;
  587. begin
  588. int_str(v,ss);
  589. if length(ss)<len then
  590. ss:=space(len-length(ss))+ss;
  591. if length(ss)<high(a)+1 then
  592. maxlen:=length(ss)
  593. else
  594. maxlen:=high(a)+1;
  595. move(ss[1],pchar(@a)^,maxlen);
  596. end;
  597. procedure fpc_chararray_uint(v : valuint;len : SizeInt;out a : array of char);compilerproc;
  598. var
  599. ss : shortstring;
  600. maxlen : SizeInt;
  601. begin
  602. int_str(v,ss);
  603. if length(ss)<len then
  604. ss:=space(len-length(ss))+ss;
  605. if length(ss)<high(a)+1 then
  606. maxlen:=length(ss)
  607. else
  608. maxlen:=high(a)+1;
  609. move(ss[1],pchar(@a)^,maxlen);
  610. end;
  611. {$ifndef CPU64}
  612. procedure fpc_chararray_qword(v : qword;len : SizeInt;out a : array of char);compilerproc;
  613. var
  614. ss : shortstring;
  615. maxlen : SizeInt;
  616. begin
  617. int_str(v,ss);
  618. if length(ss)<len then
  619. ss:=space(len-length(ss))+ss;
  620. if length(ss)<high(a)+1 then
  621. maxlen:=length(ss)
  622. else
  623. maxlen:=high(a)+1;
  624. move(ss[1],pchar(@a)^,maxlen);
  625. end;
  626. procedure fpc_chararray_int64(v : int64;len : SizeInt;out a : array of char);compilerproc;
  627. var
  628. ss : shortstring;
  629. maxlen : SizeInt;
  630. begin
  631. int_str(v,ss);
  632. if length(ss)<len then
  633. ss:=space(len-length(ss))+ss;
  634. if length(ss)<high(a)+1 then
  635. maxlen:=length(ss)
  636. else
  637. maxlen:=high(a)+1;
  638. move(ss[1],pchar(@a)^,maxlen);
  639. end;
  640. {$endif CPU64}
  641. procedure fpc_chararray_Float(d : ValReal;len,fr,rt : SizeInt;out a : array of char);compilerproc;
  642. var
  643. ss : shortstring;
  644. maxlen : SizeInt;
  645. begin
  646. str_real(len,fr,d,treal_type(rt),ss);
  647. if length(ss)<high(a)+1 then
  648. maxlen:=length(ss)
  649. else
  650. maxlen:=high(a)+1;
  651. move(ss[1],pchar(@a)^,maxlen);
  652. end;
  653. {$ifdef FPC_HAS_STR_CURRENCY}
  654. procedure fpc_chararray_Currency(c : Currency;len,fr : SizeInt;out a : array of char);compilerproc;
  655. var
  656. ss : shortstring;
  657. maxlen : SizeInt;
  658. begin
  659. str(c:len:fr,ss);
  660. if length(ss)<high(a)+1 then
  661. maxlen:=length(ss)
  662. else
  663. maxlen:=high(a)+1;
  664. move(ss[1],pchar(@a)^,maxlen);
  665. end;
  666. {$endif FPC_HAS_STR_CURRENCY}
  667. {*****************************************************************************
  668. Val() Functions
  669. *****************************************************************************}
  670. Function InitVal(const s:shortstring;out negativ:boolean;out base:byte):ValSInt;
  671. var
  672. Code : SizeInt;
  673. begin
  674. {Skip Spaces and Tab}
  675. code:=1;
  676. while (code<=length(s)) and (s[code] in [' ',#9]) do
  677. inc(code);
  678. {Sign}
  679. negativ:=false;
  680. case s[code] of
  681. '-' : begin
  682. negativ:=true;
  683. inc(code);
  684. end;
  685. '+' : inc(code);
  686. end;
  687. {Base}
  688. base:=10;
  689. if code<=length(s) then
  690. begin
  691. case s[code] of
  692. '$',
  693. 'X',
  694. 'x' : begin
  695. base:=16;
  696. inc(code);
  697. end;
  698. '%' : begin
  699. base:=2;
  700. inc(code);
  701. end;
  702. '&' : begin
  703. Base:=8;
  704. inc(code);
  705. end;
  706. '0' : begin
  707. if (code < length(s)) and (s[code+1] in ['x', 'X']) then
  708. begin
  709. inc(code, 2);
  710. base := 16;
  711. end;
  712. end;
  713. end;
  714. end;
  715. { strip leading zeros }
  716. while ((code < length(s)) and (s[code] = '0')) do begin
  717. inc(code);
  718. end;
  719. InitVal:=code;
  720. end;
  721. Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
  722. var
  723. temp, prev, maxPrevValue, maxNewValue: ValUInt;
  724. base,u : byte;
  725. negative : boolean;
  726. begin
  727. fpc_Val_SInt_ShortStr := 0;
  728. Temp:=0;
  729. Code:=InitVal(s,negative,base);
  730. if Code>length(s) then
  731. exit;
  732. if (s[Code]=#0) then
  733. begin
  734. if (Code>1) and (s[Code-1]='0') then
  735. Code:=0;
  736. exit;
  737. end;
  738. maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
  739. if (base = 10) then
  740. maxNewValue := MaxSIntValue + ord(negative)
  741. else
  742. maxNewValue := MaxUIntValue;
  743. while Code<=Length(s) do
  744. begin
  745. case s[Code] of
  746. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  747. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  748. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  749. #0 : break;
  750. else
  751. u:=16;
  752. end;
  753. Prev := Temp;
  754. Temp := Temp*ValUInt(base);
  755. If (u >= base) or
  756. (ValUInt(maxNewValue-u) < Temp) or
  757. (prev > maxPrevValue) Then
  758. Begin
  759. fpc_Val_SInt_ShortStr := 0;
  760. Exit
  761. End;
  762. Temp:=Temp+u;
  763. inc(code);
  764. end;
  765. code := 0;
  766. fpc_Val_SInt_ShortStr := ValSInt(Temp);
  767. If Negative Then
  768. fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
  769. If Not(Negative) and (base <> 10) Then
  770. {sign extend the result to allow proper range checking}
  771. Case DestSize of
  772. 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr);
  773. 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr);
  774. {$ifdef cpu64}
  775. 4: fpc_Val_SInt_ShortStr := longint(fpc_Val_SInt_ShortStr);
  776. {$endif cpu64}
  777. End;
  778. end;
  779. { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because }
  780. { we have to pass the DestSize parameter on (JM) }
  781. Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR'];
  782. Function fpc_Val_UInt_Shortstr(Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc;
  783. var
  784. prev : ValUInt;
  785. base,u : byte;
  786. negative : boolean;
  787. begin
  788. fpc_Val_UInt_Shortstr:=0;
  789. Code:=InitVal(s,negative,base);
  790. If Negative or (Code>length(s)) Then
  791. Exit;
  792. if (s[Code]=#0) then
  793. begin
  794. if (Code>1) and (s[Code-1]='0') then
  795. Code:=0;
  796. exit;
  797. end;
  798. while Code<=Length(s) do
  799. begin
  800. case s[Code] of
  801. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  802. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  803. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  804. #0 : break;
  805. else
  806. u:=16;
  807. end;
  808. prev := fpc_Val_UInt_Shortstr;
  809. If (u>=base) or
  810. (ValUInt(MaxUIntValue-u) div ValUInt(Base)<prev) then
  811. begin
  812. fpc_Val_UInt_Shortstr:=0;
  813. exit;
  814. end;
  815. fpc_Val_UInt_Shortstr:=fpc_Val_UInt_Shortstr*ValUInt(base) + u;
  816. inc(code);
  817. end;
  818. code := 0;
  819. end;
  820. {$ifndef CPU64}
  821. Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; compilerproc;
  822. var u, temp, prev, maxprevvalue, maxnewvalue : qword;
  823. base : byte;
  824. negative : boolean;
  825. const maxint64=qword($7fffffffffffffff);
  826. maxqword=qword($ffffffffffffffff);
  827. begin
  828. fpc_val_int64_shortstr := 0;
  829. Temp:=0;
  830. Code:=InitVal(s,negative,base);
  831. if Code>length(s) then
  832. exit;
  833. if (s[Code]=#0) then
  834. begin
  835. if (Code>1) and (s[Code-1]='0') then
  836. Code:=0;
  837. exit;
  838. end;
  839. maxprevvalue := maxqword div base;
  840. if (base = 10) then
  841. maxnewvalue := maxint64 + ord(negative)
  842. else
  843. maxnewvalue := maxqword;
  844. while Code<=Length(s) do
  845. begin
  846. case s[Code] of
  847. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  848. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  849. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  850. #0 : break;
  851. else
  852. u:=16;
  853. end;
  854. Prev:=Temp;
  855. Temp:=Temp*qword(base);
  856. If (u >= base) or
  857. (qword(maxnewvalue-u) < temp) or
  858. (prev > maxprevvalue) Then
  859. Begin
  860. fpc_val_int64_shortstr := 0;
  861. Exit
  862. End;
  863. Temp:=Temp+u;
  864. inc(code);
  865. end;
  866. code:=0;
  867. fpc_val_int64_shortstr:=int64(Temp);
  868. If Negative Then
  869. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  870. end;
  871. Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc;
  872. var u, prev: QWord;
  873. base : byte;
  874. negative : boolean;
  875. const maxqword=qword($ffffffffffffffff);
  876. begin
  877. fpc_val_qword_shortstr:=0;
  878. Code:=InitVal(s,negative,base);
  879. If Negative or (Code>length(s)) Then
  880. Exit;
  881. if (s[Code]=#0) then
  882. begin
  883. if (Code>1) and (s[Code-1]='0') then
  884. Code:=0;
  885. exit;
  886. end;
  887. while Code<=Length(s) do
  888. begin
  889. case s[Code] of
  890. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  891. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  892. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  893. #0 : break;
  894. else
  895. u:=16;
  896. end;
  897. prev := fpc_val_qword_shortstr;
  898. If (u>=base) or
  899. ((QWord(maxqword-u) div QWord(base))<prev) then
  900. Begin
  901. fpc_val_qword_shortstr := 0;
  902. Exit
  903. End;
  904. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  905. inc(code);
  906. end;
  907. code := 0;
  908. end;
  909. {$endif CPU64}
  910. const
  911. {$ifdef FPC_HAS_TYPE_EXTENDED}
  912. valmaxexpnorm=4932;
  913. {$else}
  914. {$ifdef FPC_HAS_TYPE_DOUBLE}
  915. valmaxexpnorm=308;
  916. {$else}
  917. {$ifdef FPC_HAS_TYPE_SINGLE}
  918. valmaxexpnorm=38;
  919. {$else}
  920. {$error Unknown floating point precision }
  921. {$endif}
  922. {$endif}
  923. {$endif}
  924. Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
  925. var
  926. hd,
  927. esign,sign : valreal;
  928. exponent,i : SizeInt;
  929. flags : byte;
  930. begin
  931. fpc_Val_Real_ShortStr:=0.0;
  932. code:=1;
  933. exponent:=0;
  934. esign:=1;
  935. flags:=0;
  936. sign:=1;
  937. while (code<=length(s)) and (s[code] in [' ',#9]) do
  938. inc(code);
  939. if code<=length(s) then
  940. case s[code] of
  941. '+' : inc(code);
  942. '-' : begin
  943. sign:=-1;
  944. inc(code);
  945. end;
  946. end;
  947. while (Code<=Length(s)) and (s[code] in ['0'..'9']) do
  948. begin
  949. { Read integer part }
  950. flags:=flags or 1;
  951. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  952. inc(code);
  953. end;
  954. { Decimal ? }
  955. if (length(s)>=code) and (s[code]='.') then
  956. begin
  957. hd:=1.0;
  958. inc(code);
  959. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  960. begin
  961. { Read fractional part. }
  962. flags:=flags or 2;
  963. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  964. hd:=hd*10.0;
  965. inc(code);
  966. end;
  967. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  968. end;
  969. { Again, read integer and fractional part}
  970. if flags=0 then
  971. begin
  972. fpc_Val_Real_ShortStr:=0.0;
  973. exit;
  974. end;
  975. { Exponent ? }
  976. if (length(s)>=code) and (upcase(s[code])='E') then
  977. begin
  978. inc(code);
  979. if Length(s) >= code then
  980. if s[code]='+' then
  981. inc(code)
  982. else
  983. if s[code]='-' then
  984. begin
  985. esign:=-1;
  986. inc(code);
  987. end;
  988. if (length(s)<code) or not(s[code] in ['0'..'9']) then
  989. begin
  990. fpc_Val_Real_ShortStr:=0.0;
  991. exit;
  992. end;
  993. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  994. begin
  995. exponent:=exponent*10;
  996. exponent:=exponent+ord(s[code])-ord('0');
  997. inc(code);
  998. end;
  999. end;
  1000. { evaluate sign }
  1001. { (before exponent, because the exponent may turn it into a denormal) }
  1002. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
  1003. { Calculate Exponent }
  1004. hd:=1.0;
  1005. { the magnitude range maximum (normal) is lower in absolute value than the }
  1006. { the magnitude range minimum (denormal). E.g. an extended value can go }
  1007. { up to 1E4932, but "down" to 1E-4951. So make sure that we don't try to }
  1008. { calculate 1E4951 as factor, since that would overflow and result in 0. }
  1009. if (exponent>valmaxexpnorm-2) then
  1010. begin
  1011. for i:=1 to valmaxexpnorm-2 do
  1012. hd:=hd*10.0;
  1013. if esign>0 then
  1014. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1015. else
  1016. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1017. dec(exponent,valmaxexpnorm-2);
  1018. hd:=1.0;
  1019. end;
  1020. for i:=1 to exponent do
  1021. hd:=hd*10.0;
  1022. if esign>0 then
  1023. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1024. else
  1025. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1026. { Not all characters are read ? }
  1027. if length(s)>=code then
  1028. begin
  1029. fpc_Val_Real_ShortStr:=0.0;
  1030. exit;
  1031. end;
  1032. { success ! }
  1033. code:=0;
  1034. end;
  1035. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_SHORTSTR']; compilerproc;
  1036. type Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1037. o:longint;
  1038. s:Pstring;
  1039. end;
  1040. var l,h,m:cardinal;
  1041. sorted_array:^Tsorted_array;
  1042. spaces:byte;
  1043. t:shortstring;
  1044. label error;
  1045. begin
  1046. {Val for numbers accepts spaces at the start, so lets do the same
  1047. for enums. Skip spaces at the start of the string.}
  1048. spaces:=1;
  1049. while (spaces<=length(s)) and (s[spaces]=' ') do
  1050. inc(spaces);
  1051. t:=upcase(copy(s,spaces,255));
  1052. sorted_array:=pointer(Pcardinal(str2ordindex)+1);
  1053. {Use a binary search to get the string.}
  1054. l:=1;
  1055. h:=Pcardinal(str2ordindex)^;
  1056. repeat
  1057. m:=(l+h) div 2;
  1058. if t>upcase(sorted_array[m-1].s^) then
  1059. l:=m+1
  1060. else if t<upcase(sorted_array[m-1].s^) then
  1061. h:=m-1
  1062. else
  1063. break;
  1064. if l>h then
  1065. goto error;
  1066. until false;
  1067. fpc_val_enum_shortstr:=sorted_array[m-1].o;
  1068. exit;
  1069. error:
  1070. {Not found. Find first error position. Take care of the string length.}
  1071. code:=1;
  1072. while (code<=length(s)) and (s[code]=sorted_array[m].s^[code]) do
  1073. inc(code);
  1074. if code>length(s) then
  1075. code:=length(s)+1;
  1076. inc(code,spaces-1); {Add skipped spaces again.}
  1077. {The result of val in case of error is undefined, don't assign a function
  1078. result.}
  1079. end;
  1080. {Redeclare fpc_val_enum_shortstr for internal use in the system unit.}
  1081. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint;external name 'FPC_VAL_ENUM_SHORTSTR';
  1082. function fpc_Val_Currency_ShortStr(const s : shortstring; out Code : ValSInt): currency; [public, alias:'FPC_VAL_CURRENCY_SHORTSTR']; compilerproc;
  1083. const
  1084. MaxInt64 : Int64 = $7FFFFFFFFFFFFFFF;
  1085. Int64Edge : Int64 = ($7FFFFFFFFFFFFFFF - 10) div 10;
  1086. Int64Edge2 : Int64 = $7FFFFFFFFFFFFFFF div 10;
  1087. var
  1088. res : Int64;
  1089. i,j,power,sign,len : longint;
  1090. FracOverflow : boolean;
  1091. begin
  1092. fpc_Val_Currency_ShortStr:=0;
  1093. res:=0;
  1094. len:=Length(s);
  1095. Code:=1;
  1096. sign:=1;
  1097. power:=0;
  1098. while True do
  1099. if Code > len then
  1100. exit
  1101. else
  1102. if s[Code] in [' ', #9] then
  1103. Inc(Code)
  1104. else
  1105. break;
  1106. { Read sign }
  1107. case s[Code] of
  1108. '+' : Inc(Code);
  1109. '-' : begin
  1110. sign:=-1;
  1111. inc(code);
  1112. end;
  1113. end;
  1114. { Read digits }
  1115. FracOverflow:=False;
  1116. i:=0;
  1117. while Code <= len do
  1118. begin
  1119. case s[Code] of
  1120. '0'..'9':
  1121. begin
  1122. j:=Ord(s[code])-Ord('0');
  1123. { check overflow }
  1124. if (res <= Int64Edge) or (res <= (MaxInt64 - j) div 10) then
  1125. begin
  1126. res:=res*10 + j;
  1127. Inc(i);
  1128. end
  1129. else
  1130. if power = 0 then
  1131. { exit if integer part overflow }
  1132. exit
  1133. else
  1134. begin
  1135. if not FracOverflow and (j >= 5) and (res < MaxInt64) then
  1136. { round if first digit of fractional part overflow }
  1137. Inc(res);
  1138. FracOverflow:=True;
  1139. end;
  1140. end;
  1141. '.':
  1142. begin
  1143. if power = 0 then
  1144. begin
  1145. power:=1;
  1146. i:=0;
  1147. end
  1148. else
  1149. exit;
  1150. end;
  1151. else
  1152. break;
  1153. end;
  1154. Inc(Code);
  1155. end;
  1156. if (i = 0) and (power = 0) then
  1157. exit;
  1158. if power <> 0 then
  1159. power:=i;
  1160. power:=4 - power;
  1161. { Exponent? }
  1162. if Code <= len then
  1163. if s[Code] in ['E', 'e'] then
  1164. begin
  1165. Inc(Code);
  1166. if Code > len then
  1167. exit;
  1168. i:=1;
  1169. case s[Code] of
  1170. '+':
  1171. Inc(Code);
  1172. '-':
  1173. begin
  1174. i:=-1;
  1175. Inc(Code);
  1176. end;
  1177. end;
  1178. { read exponent }
  1179. j:=0;
  1180. while Code <= len do
  1181. if s[Code] in ['0'..'9'] then
  1182. begin
  1183. if j > 4951 then
  1184. exit;
  1185. j:=j*10 + (Ord(s[code])-Ord('0'));
  1186. Inc(Code);
  1187. end
  1188. else
  1189. exit;
  1190. power:=power + j*i;
  1191. end
  1192. else
  1193. exit;
  1194. if power > 0 then
  1195. begin
  1196. for i:=1 to power do
  1197. if res <= Int64Edge2 then
  1198. res:=res*10
  1199. else
  1200. exit;
  1201. end
  1202. else
  1203. for i:=1 to -power do
  1204. begin
  1205. if res <= MaxInt64 - 5 then
  1206. Inc(res, 5);
  1207. res:=res div 10;
  1208. end;
  1209. res:=res*sign;
  1210. fpc_Val_Currency_ShortStr:=PCurrency(@res)^;
  1211. Code:=0;
  1212. end;
  1213. Procedure SetString (Out S : Shortstring; Buf : PChar; Len : SizeInt);
  1214. begin
  1215. If Len > High(S) then
  1216. Len := High(S);
  1217. SetLength(S,Len);
  1218. If Buf<>Nil then
  1219. begin
  1220. Move (Buf[0],S[1],Len);
  1221. end;
  1222. end;