sstrings.inc 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  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)+length(s))>=sizeof(s) then
  59. begin
  60. cut:=SizeInt(length(source)+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 (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:=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 : pointer) : shortstring;
  276. var
  277. i : longint;
  278. v : ptrint;
  279. begin
  280. v:=ptrint(val);
  281. hexstr[0]:=chr(sizeof(pointer)*2);
  282. for i:=sizeof(pointer)*2 downto 1 do
  283. begin
  284. hexstr[i]:=hextbl[v and $f];
  285. v:=v shr 4;
  286. end;
  287. end;
  288. function space (b : byte): shortstring;
  289. begin
  290. space[0] := chr(b);
  291. FillChar (Space[1],b,' ');
  292. end;
  293. {*****************************************************************************
  294. Str() Helpers
  295. *****************************************************************************}
  296. procedure fpc_shortstr_SInt(v : valSInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SINT']; compilerproc;
  297. begin
  298. int_str(v,s);
  299. if length(s)<len then
  300. s:=space(len-length(s))+s;
  301. end;
  302. procedure fpc_shortstr_UInt(v : valUInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_UINT']; compilerproc;
  303. begin
  304. int_str(v,s);
  305. if length(s)<len then
  306. s:=space(len-length(s))+s;
  307. end;
  308. {$ifndef CPU64}
  309. procedure fpc_shortstr_qword(v : qword;len : longint;out s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; compilerproc;
  310. begin
  311. int_str(v,s);
  312. if length(s)<len then
  313. s:=space(len-length(s))+s;
  314. end;
  315. procedure fpc_shortstr_int64(v : int64;len : longint;out s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; compilerproc;
  316. begin
  317. int_str(v,s);
  318. if length(s)<len then
  319. s:=space(len-length(s))+s;
  320. end;
  321. {$endif CPU64}
  322. { fpc_shortstr_sInt must appear before this file is included, because }
  323. { it's used inside real2str.inc and otherwise the searching via the }
  324. { compilerproc name will fail (JM) }
  325. {$I real2str.inc}
  326. procedure fpc_shortstr_float(d : ValReal;len,fr,rt : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_FLOAT']; compilerproc;
  327. begin
  328. str_real(len,fr,d,treal_type(rt),s);
  329. end;
  330. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);[public,alias:'FPC_SHORTSTR_ENUM'];compilerproc;
  331. type Ptypeinfo=^Ttypeinfo;
  332. Ttypeinfo=record
  333. kind:byte;
  334. name:shortstring;
  335. end;
  336. Penuminfo=^Tenuminfo;
  337. Tenuminfo={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  338. ordtype:byte;
  339. minvalue,maxvalue:longint;
  340. basetype:pointer;
  341. namelist:shortstring;
  342. end;
  343. Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  344. o:longint;
  345. s:Pstring;
  346. end;
  347. var e:Penuminfo;
  348. p:Pstring;
  349. l,h,m:cardinal;
  350. sorted_array:^Tsorted_array;
  351. i,spaces:byte;
  352. label error;
  353. begin
  354. if Pcardinal(ord2strindex)^=0 then
  355. begin
  356. {The compiler did generate a lookup table.}
  357. with Penuminfo(Pbyte(typinfo)+2+length(Ptypeinfo(typinfo)^.name))^ do
  358. begin
  359. if (ordinal<minvalue) or (ordinal>maxvalue) then
  360. goto error; {Invalid ordinal value for this enum.}
  361. dec(ordinal,minvalue);
  362. end;
  363. {Get the address of the string.}
  364. p:=Pshortstring((PPpointer(ord2strindex)+1+ordinal)^);
  365. if p=nil then
  366. goto error; {Invalid ordinal value for this enum.}
  367. s:=p^;
  368. end
  369. else
  370. begin
  371. {The compiler did generate a sorted array of (ordvalue,Pstring) tuples.}
  372. sorted_array:=pointer(Pcardinal(ord2strindex)+2);
  373. {Use a binary search to get the string.}
  374. l:=0;
  375. h:=(Pcardinal(ord2strindex)+1)^-1;
  376. repeat
  377. m:=(l+h) div 2;
  378. if ordinal>sorted_array[m].o then
  379. l:=m+1
  380. else if ordinal<sorted_array[m].o then
  381. h:=m-1
  382. else
  383. break;
  384. if l>h then
  385. goto error; {Ordinal value not found? Kaboom.}
  386. until false;
  387. s:=sorted_array[m].s^;
  388. end;
  389. {Pad the string with spaces if necessary.}
  390. if len>length(s) then
  391. begin
  392. spaces:=len-length(s);
  393. for i:=1 to spaces do
  394. s[length(s)+i]:=' ';
  395. inc(byte(s[0]),spaces);
  396. end;
  397. exit;
  398. error:
  399. {Call runtime error in a central place, this saves space.}
  400. runerror(107);
  401. end;
  402. { also define alias for internal use in the system unit }
  403. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);external name 'FPC_SHORTSTR_ENUM';
  404. procedure fpc_shortstr_currency(c : currency; len,f : SizeInt; out s : shortstring);[public,alias:'FPC_SHORTSTR_CURRENCY']; compilerproc;
  405. const
  406. MinLen = 8; { Minimal string length in scientific format }
  407. var
  408. buf : array[1..19] of char;
  409. i,j,k,reslen,tlen,sign,r,point : longint;
  410. ic : qword;
  411. begin
  412. { default value for length is -32767 }
  413. if len=-32767 then
  414. len:=25;
  415. if PInt64(@c)^ >= 0 then
  416. begin
  417. ic:=QWord(PInt64(@c)^);
  418. sign:=0;
  419. end
  420. else
  421. begin
  422. sign:=1;
  423. ic:=QWord(-PInt64(@c)^);
  424. end;
  425. { converting to integer string }
  426. tlen:=0;
  427. repeat
  428. Inc(tlen);
  429. buf[tlen]:=Chr(ic mod 10 + $30);
  430. ic:=ic div 10;
  431. until ic = 0;
  432. { calculating:
  433. reslen - length of result string,
  434. r - rounding or appending zeroes,
  435. point - place of decimal point }
  436. reslen:=tlen;
  437. if f <> 0 then
  438. Inc(reslen); { adding decimal point length }
  439. if f < 0 then
  440. begin
  441. { scientific format }
  442. Inc(reslen,5); { adding length of sign and exponent }
  443. if len < MinLen then
  444. len:=MinLen;
  445. r:=reslen-len;
  446. if reslen < len then
  447. reslen:=len;
  448. if r > 0 then
  449. begin
  450. reslen:=len;
  451. point:=tlen - r;
  452. end
  453. else
  454. point:=tlen;
  455. end
  456. else
  457. begin
  458. { fixed format }
  459. Inc(reslen, sign);
  460. { prepending fractional part with zeroes }
  461. while tlen < 5 do
  462. begin
  463. Inc(reslen);
  464. Inc(tlen);
  465. buf[tlen]:='0';
  466. end;
  467. { Currency have 4 digits in fractional part }
  468. r:=4 - f;
  469. point:=f;
  470. if point <> 0 then
  471. begin
  472. if point > 4 then
  473. point:=4;
  474. Inc(point);
  475. end;
  476. Dec(reslen,r);
  477. end;
  478. { rounding string if r > 0 }
  479. if r > 0 then
  480. begin
  481. i:=1;
  482. k:=0;
  483. for j:=0 to r do
  484. begin
  485. buf[i]:=chr(ord(buf[i]) + k);
  486. if buf[i] >= '5' then
  487. k:=1
  488. else
  489. k:=0;
  490. Inc(i);
  491. if i>tlen then
  492. break;
  493. end;
  494. end;
  495. { preparing result string }
  496. if reslen<len then
  497. reslen:=len;
  498. if reslen>High(s) then
  499. begin
  500. if r < 0 then
  501. Inc(r, reslen - High(s));
  502. reslen:=High(s);
  503. end;
  504. SetLength(s,reslen);
  505. j:=reslen;
  506. if f<0 then
  507. begin
  508. { writing power of 10 part }
  509. if PInt64(@c)^ = 0 then
  510. k:=0
  511. else
  512. k:=tlen-5;
  513. if k >= 0 then
  514. s[j-2]:='+'
  515. else
  516. begin
  517. s[j-2]:='-';
  518. k:=-k;
  519. end;
  520. s[j]:=Chr(k mod 10 + $30);
  521. Dec(j);
  522. s[j]:=Chr(k div 10 + $30);
  523. Dec(j,2);
  524. s[j]:='E';
  525. Dec(j);
  526. end;
  527. { writing extra zeroes if r < 0 }
  528. while r < 0 do
  529. begin
  530. s[j]:='0';
  531. Dec(j);
  532. Inc(r);
  533. end;
  534. { writing digits and decimal point }
  535. for i:=r + 1 to tlen do
  536. begin
  537. Dec(point);
  538. if point = 0 then
  539. begin
  540. s[j]:='.';
  541. Dec(j);
  542. end;
  543. s[j]:=buf[i];
  544. Dec(j);
  545. end;
  546. { writing sign }
  547. if sign = 1 then
  548. begin
  549. s[j]:='-';
  550. Dec(j);
  551. end;
  552. { writing spaces }
  553. while j > 0 do
  554. begin
  555. s[j]:=' ';
  556. Dec(j);
  557. end;
  558. end;
  559. {
  560. Array Of Char Str() helpers
  561. }
  562. procedure fpc_chararray_sint(v : valsint;len : SizeInt;out a:array of char);compilerproc;
  563. var
  564. ss : shortstring;
  565. maxlen : SizeInt;
  566. begin
  567. int_str(v,ss);
  568. if length(ss)<len then
  569. ss:=space(len-length(ss))+ss;
  570. if length(ss)<high(a)+1 then
  571. maxlen:=length(ss)
  572. else
  573. maxlen:=high(a)+1;
  574. move(ss[1],pchar(@a)^,maxlen);
  575. end;
  576. procedure fpc_chararray_uint(v : valuint;len : SizeInt;out a : array of char);compilerproc;
  577. var
  578. ss : shortstring;
  579. maxlen : SizeInt;
  580. begin
  581. int_str(v,ss);
  582. if length(ss)<len then
  583. ss:=space(len-length(ss))+ss;
  584. if length(ss)<high(a)+1 then
  585. maxlen:=length(ss)
  586. else
  587. maxlen:=high(a)+1;
  588. move(ss[1],pchar(@a)^,maxlen);
  589. end;
  590. {$ifndef CPU64}
  591. procedure fpc_chararray_qword(v : qword;len : SizeInt;out a : array of char);compilerproc;
  592. var
  593. ss : shortstring;
  594. maxlen : SizeInt;
  595. begin
  596. int_str(v,ss);
  597. if length(ss)<len then
  598. ss:=space(len-length(ss))+ss;
  599. if length(ss)<high(a)+1 then
  600. maxlen:=length(ss)
  601. else
  602. maxlen:=high(a)+1;
  603. move(ss[1],pchar(@a)^,maxlen);
  604. end;
  605. procedure fpc_chararray_int64(v : int64;len : SizeInt;out a : array of char);compilerproc;
  606. var
  607. ss : shortstring;
  608. maxlen : SizeInt;
  609. begin
  610. int_str(v,ss);
  611. if length(ss)<len then
  612. ss:=space(len-length(ss))+ss;
  613. if length(ss)<high(a)+1 then
  614. maxlen:=length(ss)
  615. else
  616. maxlen:=high(a)+1;
  617. move(ss[1],pchar(@a)^,maxlen);
  618. end;
  619. {$endif CPU64}
  620. procedure fpc_chararray_Float(d : ValReal;len,fr,rt : SizeInt;out a : array of char);compilerproc;
  621. var
  622. ss : shortstring;
  623. maxlen : SizeInt;
  624. begin
  625. str_real(len,fr,d,treal_type(rt),ss);
  626. if length(ss)<high(a)+1 then
  627. maxlen:=length(ss)
  628. else
  629. maxlen:=high(a)+1;
  630. move(ss[1],pchar(@a)^,maxlen);
  631. end;
  632. {$ifdef FPC_HAS_STR_CURRENCY}
  633. procedure fpc_chararray_Currency(c : Currency;len,fr : SizeInt;out a : array of char);compilerproc;
  634. var
  635. ss : shortstring;
  636. maxlen : SizeInt;
  637. begin
  638. str(c:len:fr,ss);
  639. if length(ss)<high(a)+1 then
  640. maxlen:=length(ss)
  641. else
  642. maxlen:=high(a)+1;
  643. move(ss[1],pchar(@a)^,maxlen);
  644. end;
  645. {$endif FPC_HAS_STR_CURRENCY}
  646. {*****************************************************************************
  647. Val() Functions
  648. *****************************************************************************}
  649. Function InitVal(const s:shortstring;out negativ:boolean;out base:byte):ValSInt;
  650. var
  651. Code : SizeInt;
  652. begin
  653. {Skip Spaces and Tab}
  654. code:=1;
  655. while (code<=length(s)) and (s[code] in [' ',#9]) do
  656. inc(code);
  657. {Sign}
  658. negativ:=false;
  659. case s[code] of
  660. '-' : begin
  661. negativ:=true;
  662. inc(code);
  663. end;
  664. '+' : inc(code);
  665. end;
  666. {Base}
  667. base:=10;
  668. if code<=length(s) then
  669. begin
  670. case s[code] of
  671. '$',
  672. 'X',
  673. 'x' : begin
  674. base:=16;
  675. inc(code);
  676. end;
  677. '%' : begin
  678. base:=2;
  679. inc(code);
  680. end;
  681. '&' : begin
  682. Base:=8;
  683. inc(code);
  684. end;
  685. '0' : begin
  686. if (code < length(s)) and (s[code+1] in ['x', 'X']) then
  687. begin
  688. inc(code, 2);
  689. base := 16;
  690. end;
  691. end;
  692. end;
  693. end;
  694. { strip leading zeros }
  695. while ((code < length(s)) and (s[code] = '0')) do begin
  696. inc(code);
  697. end;
  698. InitVal:=code;
  699. end;
  700. Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
  701. var
  702. u, temp, prev, maxPrevValue, maxNewValue: ValUInt;
  703. base : byte;
  704. negative : boolean;
  705. begin
  706. fpc_Val_SInt_ShortStr := 0;
  707. Temp:=0;
  708. Code:=InitVal(s,negative,base);
  709. if Code>length(s) then
  710. exit;
  711. if (s[Code]=#0) then
  712. begin
  713. if (Code>1) and (s[Code-1]='0') then
  714. Code:=0;
  715. exit;
  716. end;
  717. maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
  718. if (base = 10) then
  719. maxNewValue := MaxSIntValue + ord(negative)
  720. else
  721. maxNewValue := MaxUIntValue;
  722. while Code<=Length(s) do
  723. begin
  724. case s[Code] of
  725. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  726. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  727. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  728. #0 : break;
  729. else
  730. u:=16;
  731. end;
  732. Prev := Temp;
  733. Temp := Temp*ValUInt(base);
  734. If (u >= base) or
  735. (ValUInt(maxNewValue-u) < Temp) or
  736. (prev > maxPrevValue) Then
  737. Begin
  738. fpc_Val_SInt_ShortStr := 0;
  739. Exit
  740. End;
  741. Temp:=Temp+u;
  742. inc(code);
  743. end;
  744. code := 0;
  745. fpc_Val_SInt_ShortStr := ValSInt(Temp);
  746. If Negative Then
  747. fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
  748. If Not(Negative) and (base <> 10) Then
  749. {sign extend the result to allow proper range checking}
  750. Case DestSize of
  751. 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr);
  752. 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr);
  753. {$ifdef cpu64}
  754. 4: fpc_Val_SInt_ShortStr := longint(fpc_Val_SInt_ShortStr);
  755. {$endif cpu64}
  756. End;
  757. end;
  758. { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because }
  759. { we have to pass the DestSize parameter on (JM) }
  760. Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR'];
  761. Function fpc_Val_UInt_Shortstr(Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc;
  762. var
  763. u, prev : ValUInt;
  764. base : byte;
  765. negative : boolean;
  766. begin
  767. fpc_Val_UInt_Shortstr:=0;
  768. Code:=InitVal(s,negative,base);
  769. If Negative or (Code>length(s)) Then
  770. Exit;
  771. if (s[Code]=#0) then
  772. begin
  773. if (Code>1) and (s[Code-1]='0') then
  774. Code:=0;
  775. exit;
  776. end;
  777. while Code<=Length(s) do
  778. begin
  779. case s[Code] of
  780. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  781. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  782. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  783. #0 : break;
  784. else
  785. u:=16;
  786. end;
  787. prev := fpc_Val_UInt_Shortstr;
  788. If (u>=base) or
  789. (ValUInt(MaxUIntValue-u) div ValUInt(Base)<prev) then
  790. begin
  791. fpc_Val_UInt_Shortstr:=0;
  792. exit;
  793. end;
  794. fpc_Val_UInt_Shortstr:=fpc_Val_UInt_Shortstr*ValUInt(base) + u;
  795. inc(code);
  796. end;
  797. code := 0;
  798. end;
  799. {$ifndef CPU64}
  800. Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; compilerproc;
  801. var u, temp, prev, maxprevvalue, maxnewvalue : qword;
  802. base : byte;
  803. negative : boolean;
  804. const maxint64=qword($7fffffffffffffff);
  805. maxqword=qword($ffffffffffffffff);
  806. begin
  807. fpc_val_int64_shortstr := 0;
  808. Temp:=0;
  809. Code:=InitVal(s,negative,base);
  810. if Code>length(s) then
  811. exit;
  812. if (s[Code]=#0) then
  813. begin
  814. if (Code>1) and (s[Code-1]='0') then
  815. Code:=0;
  816. exit;
  817. end;
  818. maxprevvalue := maxqword div base;
  819. if (base = 10) then
  820. maxnewvalue := maxint64 + ord(negative)
  821. else
  822. maxnewvalue := maxqword;
  823. while Code<=Length(s) do
  824. begin
  825. case s[Code] of
  826. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  827. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  828. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  829. #0 : break;
  830. else
  831. u:=16;
  832. end;
  833. Prev:=Temp;
  834. Temp:=Temp*qword(base);
  835. If (u >= base) or
  836. (qword(maxnewvalue-u) < temp) or
  837. (prev > maxprevvalue) Then
  838. Begin
  839. fpc_val_int64_shortstr := 0;
  840. Exit
  841. End;
  842. Temp:=Temp+u;
  843. inc(code);
  844. end;
  845. code:=0;
  846. fpc_val_int64_shortstr:=int64(Temp);
  847. If Negative Then
  848. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  849. end;
  850. Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc;
  851. var u, prev: QWord;
  852. base : byte;
  853. negative : boolean;
  854. const maxqword=qword($ffffffffffffffff);
  855. begin
  856. fpc_val_qword_shortstr:=0;
  857. Code:=InitVal(s,negative,base);
  858. If Negative or (Code>length(s)) Then
  859. Exit;
  860. if (s[Code]=#0) then
  861. begin
  862. if (Code>1) and (s[Code-1]='0') then
  863. Code:=0;
  864. exit;
  865. end;
  866. while Code<=Length(s) do
  867. begin
  868. case s[Code] of
  869. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  870. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  871. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  872. #0 : break;
  873. else
  874. u:=16;
  875. end;
  876. prev := fpc_val_qword_shortstr;
  877. If (u>=base) or
  878. ((QWord(maxqword-u) div QWord(base))<prev) then
  879. Begin
  880. fpc_val_qword_shortstr := 0;
  881. Exit
  882. End;
  883. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  884. inc(code);
  885. end;
  886. code := 0;
  887. end;
  888. {$endif CPU64}
  889. const
  890. {$ifdef FPC_HAS_TYPE_EXTENDED}
  891. valmaxexpnorm=4932;
  892. {$else}
  893. {$ifdef FPC_HAS_TYPE_DOUBLE}
  894. valmaxexpnorm=308;
  895. {$else}
  896. {$ifdef FPC_HAS_TYPE_SINGLE}
  897. valmaxexpnorm=38;
  898. {$else}
  899. {$error Unknown floating point precision }
  900. {$endif}
  901. {$endif}
  902. {$endif}
  903. Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
  904. var
  905. hd,
  906. esign,sign : valreal;
  907. exponent,i : SizeInt;
  908. flags : byte;
  909. begin
  910. fpc_Val_Real_ShortStr:=0.0;
  911. code:=1;
  912. exponent:=0;
  913. esign:=1;
  914. flags:=0;
  915. sign:=1;
  916. while (code<=length(s)) and (s[code] in [' ',#9]) do
  917. inc(code);
  918. if code<=length(s) then
  919. case s[code] of
  920. '+' : inc(code);
  921. '-' : begin
  922. sign:=-1;
  923. inc(code);
  924. end;
  925. end;
  926. while (Code<=Length(s)) and (s[code] in ['0'..'9']) do
  927. begin
  928. { Read integer part }
  929. flags:=flags or 1;
  930. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  931. inc(code);
  932. end;
  933. { Decimal ? }
  934. if (length(s)>=code) and (s[code]='.') then
  935. begin
  936. hd:=1.0;
  937. inc(code);
  938. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  939. begin
  940. { Read fractional part. }
  941. flags:=flags or 2;
  942. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  943. hd:=hd*10.0;
  944. inc(code);
  945. end;
  946. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  947. end;
  948. { Again, read integer and fractional part}
  949. if flags=0 then
  950. begin
  951. fpc_Val_Real_ShortStr:=0.0;
  952. exit;
  953. end;
  954. { Exponent ? }
  955. if (length(s)>=code) and (upcase(s[code])='E') then
  956. begin
  957. inc(code);
  958. if Length(s) >= code then
  959. if s[code]='+' then
  960. inc(code)
  961. else
  962. if s[code]='-' then
  963. begin
  964. esign:=-1;
  965. inc(code);
  966. end;
  967. if (length(s)<code) or not(s[code] in ['0'..'9']) then
  968. begin
  969. fpc_Val_Real_ShortStr:=0.0;
  970. exit;
  971. end;
  972. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  973. begin
  974. exponent:=exponent*10;
  975. exponent:=exponent+ord(s[code])-ord('0');
  976. inc(code);
  977. end;
  978. end;
  979. { evaluate sign }
  980. { (before exponent, because the exponent may turn it into a denormal) }
  981. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
  982. { Calculate Exponent }
  983. hd:=1.0;
  984. { the magnitude range maximum (normal) is lower in absolute value than the }
  985. { the magnitude range minimum (denormal). E.g. an extended value can go }
  986. { up to 1E4932, but "down" to 1E-4951. So make sure that we don't try to }
  987. { calculate 1E4951 as factor, since that would overflow and result in 0. }
  988. if (exponent>valmaxexpnorm-2) then
  989. begin
  990. for i:=1 to valmaxexpnorm-2 do
  991. hd:=hd*10.0;
  992. if esign>0 then
  993. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  994. else
  995. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  996. dec(exponent,valmaxexpnorm-2);
  997. hd:=1.0;
  998. end;
  999. for i:=1 to exponent do
  1000. hd:=hd*10.0;
  1001. if esign>0 then
  1002. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1003. else
  1004. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1005. { Not all characters are read ? }
  1006. if length(s)>=code then
  1007. begin
  1008. fpc_Val_Real_ShortStr:=0.0;
  1009. exit;
  1010. end;
  1011. { success ! }
  1012. code:=0;
  1013. end;
  1014. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_SHORTSTR']; compilerproc;
  1015. type Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1016. o:longint;
  1017. s:Pstring;
  1018. end;
  1019. var l,h,m:cardinal;
  1020. sorted_array:^Tsorted_array;
  1021. spaces:byte;
  1022. t:shortstring;
  1023. label error;
  1024. begin
  1025. {Val for numbers accepts spaces at the start, so lets do the same
  1026. for enums. Skip spaces at the start of the string.}
  1027. spaces:=1;
  1028. while (spaces<=length(s)) and (s[spaces]=' ') do
  1029. inc(spaces);
  1030. t:=upcase(copy(s,spaces,255));
  1031. sorted_array:=pointer(Pcardinal(str2ordindex)+1);
  1032. {Use a binary search to get the string.}
  1033. l:=1;
  1034. h:=Pcardinal(str2ordindex)^;
  1035. repeat
  1036. m:=(l+h) div 2;
  1037. if t>upcase(sorted_array[m-1].s^) then
  1038. l:=m+1
  1039. else if t<upcase(sorted_array[m-1].s^) then
  1040. h:=m-1
  1041. else
  1042. break;
  1043. if l>h then
  1044. goto error;
  1045. until false;
  1046. fpc_val_enum_shortstr:=sorted_array[m-1].o;
  1047. exit;
  1048. error:
  1049. {Not found. Find first error position. Take care of the string length.}
  1050. code:=1;
  1051. while (code<=length(s)) and (s[code]=sorted_array[m].s^[code]) do
  1052. inc(code);
  1053. if code>length(s) then
  1054. code:=length(s)+1;
  1055. inc(code,spaces-1); {Add skipped spaces again.}
  1056. {The result of val in case of error is undefined, don't assign a function
  1057. result.}
  1058. end;
  1059. {Redeclare fpc_val_enum_shortstr for internal use in the system unit.}
  1060. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint;external name 'FPC_VAL_ENUM_SHORTSTR';
  1061. function fpc_Val_Currency_ShortStr(const s : shortstring; out Code : ValSInt): currency; [public, alias:'FPC_VAL_CURRENCY_SHORTSTR']; compilerproc;
  1062. const
  1063. MaxInt64 : Int64 = $7FFFFFFFFFFFFFFF;
  1064. Int64Edge : Int64 = ($7FFFFFFFFFFFFFFF - 10) div 10;
  1065. Int64Edge2 : Int64 = $7FFFFFFFFFFFFFFF div 10;
  1066. var
  1067. res : Int64;
  1068. i,j,power,sign,len : longint;
  1069. FracOverflow : boolean;
  1070. begin
  1071. fpc_Val_Currency_ShortStr:=0;
  1072. res:=0;
  1073. len:=Length(s);
  1074. Code:=1;
  1075. sign:=1;
  1076. power:=0;
  1077. while True do
  1078. if Code > len then
  1079. exit
  1080. else
  1081. if s[Code] in [' ', #9] then
  1082. Inc(Code)
  1083. else
  1084. break;
  1085. { Read sign }
  1086. case s[Code] of
  1087. '+' : Inc(Code);
  1088. '-' : begin
  1089. sign:=-1;
  1090. inc(code);
  1091. end;
  1092. end;
  1093. { Read digits }
  1094. FracOverflow:=False;
  1095. i:=0;
  1096. while Code <= len do
  1097. begin
  1098. case s[Code] of
  1099. '0'..'9':
  1100. begin
  1101. j:=Ord(s[code])-Ord('0');
  1102. { check overflow }
  1103. if (res <= Int64Edge) or (res <= (MaxInt64 - j) div 10) then
  1104. begin
  1105. res:=res*10 + j;
  1106. Inc(i);
  1107. end
  1108. else
  1109. if power = 0 then
  1110. { exit if integer part overflow }
  1111. exit
  1112. else
  1113. begin
  1114. if not FracOverflow and (j >= 5) and (res < MaxInt64) then
  1115. { round if first digit of fractional part overflow }
  1116. Inc(res);
  1117. FracOverflow:=True;
  1118. end;
  1119. end;
  1120. '.':
  1121. begin
  1122. if power = 0 then
  1123. begin
  1124. power:=1;
  1125. i:=0;
  1126. end
  1127. else
  1128. exit;
  1129. end;
  1130. else
  1131. break;
  1132. end;
  1133. Inc(Code);
  1134. end;
  1135. if (i = 0) and (power = 0) then
  1136. exit;
  1137. if power <> 0 then
  1138. power:=i;
  1139. power:=4 - power;
  1140. { Exponent? }
  1141. if Code <= len then
  1142. if s[Code] in ['E', 'e'] then
  1143. begin
  1144. Inc(Code);
  1145. if Code > len then
  1146. exit;
  1147. i:=1;
  1148. case s[Code] of
  1149. '+':
  1150. Inc(Code);
  1151. '-':
  1152. begin
  1153. i:=-1;
  1154. Inc(Code);
  1155. end;
  1156. end;
  1157. { read exponent }
  1158. j:=0;
  1159. while Code <= len do
  1160. if s[Code] in ['0'..'9'] then
  1161. begin
  1162. if j > 4951 then
  1163. exit;
  1164. j:=j*10 + (Ord(s[code])-Ord('0'));
  1165. Inc(Code);
  1166. end
  1167. else
  1168. exit;
  1169. power:=power + j*i;
  1170. end
  1171. else
  1172. exit;
  1173. if power > 0 then
  1174. begin
  1175. for i:=1 to power do
  1176. if res <= Int64Edge2 then
  1177. res:=res*10
  1178. else
  1179. exit;
  1180. end
  1181. else
  1182. for i:=1 to -power do
  1183. begin
  1184. if res <= MaxInt64 - 5 then
  1185. Inc(res, 5);
  1186. res:=res div 10;
  1187. end;
  1188. res:=res*sign;
  1189. fpc_Val_Currency_ShortStr:=PCurrency(@res)^;
  1190. Code:=0;
  1191. end;
  1192. Procedure SetString (Out S : Shortstring; Buf : PChar; Len : SizeInt);
  1193. begin
  1194. If Len > High(S) then
  1195. Len := High(S);
  1196. SetLength(S,Len);
  1197. If Buf<>Nil then
  1198. begin
  1199. Move (Buf[0],S[1],Len);
  1200. end;
  1201. end;