sstrings.inc 31 KB

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