sstrings.inc 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  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. begin
  56. index:=length(s)+1;
  57. if index>high(s) then
  58. exit;
  59. end;
  60. indexlen:=Length(s)-Index+1;
  61. srclen:=length(Source);
  62. if sizeInt(length(source))+sizeint(length(s))>=sizeof(s) then
  63. begin
  64. cut:=sizeInt(length(source))+sizeint(length(s))-sizeof(s)+1;
  65. if cut>indexlen then
  66. begin
  67. dec(srclen,cut-indexlen);
  68. indexlen:=0;
  69. end
  70. else
  71. dec(indexlen,cut);
  72. end;
  73. move(s[Index],s[Index+srclen],indexlen);
  74. move(Source[1],s[Index],srclen);
  75. s[0]:=chr(index+srclen+indexlen-1);
  76. end;
  77. procedure insert(source : Char;var s : shortstring;index : SizeInt);
  78. var
  79. indexlen : SizeInt;
  80. begin
  81. if index<1 then
  82. index:=1;
  83. if index>length(s) then
  84. begin
  85. index:=length(s)+1;
  86. if index>high(s) then
  87. exit;
  88. end;
  89. indexlen:=Length(s)-Index+1;
  90. if (sizeint(length(s))+1=sizeof(s)) and (indexlen>0) then
  91. dec(indexlen);
  92. move(s[Index],s[Index+1],indexlen);
  93. s[Index]:=Source;
  94. s[0]:=chr(index+indexlen);
  95. end;
  96. function pos(const substr : shortstring;const s : shortstring):SizeInt;
  97. var
  98. i,MaxLen : SizeInt;
  99. pc : pchar;
  100. begin
  101. Pos:=0;
  102. if Length(SubStr)>0 then
  103. begin
  104. MaxLen:=sizeint(Length(s))-Length(SubStr);
  105. i:=0;
  106. pc:=@s[1];
  107. while (i<=MaxLen) do
  108. begin
  109. inc(i);
  110. if (SubStr[1]=pc^) and
  111. (CompareChar(Substr[1],pc^,Length(SubStr))=0) then
  112. begin
  113. Pos:=i;
  114. exit;
  115. end;
  116. inc(pc);
  117. end;
  118. end;
  119. end;
  120. {Faster when looking for a single char...}
  121. function pos(c:char;const s:shortstring):SizeInt;
  122. var
  123. i : SizeInt;
  124. pc : pchar;
  125. begin
  126. pc:=@s[1];
  127. for i:=1 to length(s) do
  128. begin
  129. if pc^=c then
  130. begin
  131. pos:=i;
  132. exit;
  133. end;
  134. inc(pc);
  135. end;
  136. pos:=0;
  137. end;
  138. function fpc_char_copy(c:char;index : SizeInt;count : SizeInt): shortstring;compilerproc;
  139. begin
  140. if (index=1) and (Count>0) then
  141. fpc_char_Copy:=c
  142. else
  143. fpc_char_Copy:='';
  144. end;
  145. function pos(const substr : shortstring;c:char): SizeInt;
  146. begin
  147. if (length(substr)=1) and (substr[1]=c) then
  148. Pos:=1
  149. else
  150. Pos:=0;
  151. end;
  152. {$ifdef IBM_CHAR_SET}
  153. const
  154. UpCaseTbl : shortstring[7]=#154#142#153#144#128#143#165;
  155. LoCaseTbl : shortstring[7]=#129#132#148#130#135#134#164;
  156. {$endif}
  157. function upcase(c : char) : char;
  158. {$IFDEF IBM_CHAR_SET}
  159. var
  160. i : longint;
  161. {$ENDIF}
  162. begin
  163. if (c in ['a'..'z']) then
  164. upcase:=char(byte(c)-32)
  165. else
  166. {$IFDEF IBM_CHAR_SET}
  167. begin
  168. i:=Pos(c,LoCaseTbl);
  169. if i>0 then
  170. upcase:=UpCaseTbl[i]
  171. else
  172. upcase:=c;
  173. end;
  174. {$ELSE}
  175. upcase:=c;
  176. {$ENDIF}
  177. end;
  178. function upcase(const s : shortstring) : shortstring;
  179. var
  180. i : longint;
  181. begin
  182. upcase[0]:=s[0];
  183. for i := 1 to length (s) do
  184. upcase[i] := upcase (s[i]);
  185. end;
  186. function lowercase(c : char) : char;overload;
  187. {$IFDEF IBM_CHAR_SET}
  188. var
  189. i : longint;
  190. {$ENDIF}
  191. begin
  192. if (c in ['A'..'Z']) then
  193. lowercase:=char(byte(c)+32)
  194. else
  195. {$IFDEF IBM_CHAR_SET}
  196. begin
  197. i:=Pos(c,UpCaseTbl);
  198. if i>0 then
  199. lowercase:=LoCaseTbl[i]
  200. else
  201. lowercase:=c;
  202. end;
  203. {$ELSE}
  204. lowercase:=c;
  205. {$ENDIF}
  206. end;
  207. function lowercase(const s : shortstring) : shortstring; overload;
  208. var
  209. i : longint;
  210. begin
  211. lowercase [0]:=s[0];
  212. for i:=1 to length(s) do
  213. lowercase[i]:=lowercase (s[i]);
  214. end;
  215. const
  216. HexTbl : array[0..15] of char='0123456789ABCDEF';
  217. function hexstr(val : longint;cnt : byte) : shortstring;
  218. var
  219. i : longint;
  220. begin
  221. hexstr[0]:=char(cnt);
  222. for i:=cnt downto 1 do
  223. begin
  224. hexstr[i]:=hextbl[val and $f];
  225. val:=val shr 4;
  226. end;
  227. end;
  228. function octstr(val : longint;cnt : byte) : shortstring;
  229. var
  230. i : longint;
  231. begin
  232. octstr[0]:=char(cnt);
  233. for i:=cnt downto 1 do
  234. begin
  235. octstr[i]:=hextbl[val and 7];
  236. val:=val shr 3;
  237. end;
  238. end;
  239. function binstr(val : longint;cnt : byte) : shortstring;
  240. var
  241. i : longint;
  242. begin
  243. binstr[0]:=char(cnt);
  244. for i:=cnt downto 1 do
  245. begin
  246. binstr[i]:=char(48+val and 1);
  247. val:=val shr 1;
  248. end;
  249. end;
  250. function hexstr(val : int64;cnt : byte) : shortstring;
  251. var
  252. i : longint;
  253. begin
  254. hexstr[0]:=char(cnt);
  255. for i:=cnt downto 1 do
  256. begin
  257. hexstr[i]:=hextbl[val and $f];
  258. val:=val shr 4;
  259. end;
  260. end;
  261. function octstr(val : int64;cnt : byte) : shortstring;
  262. var
  263. i : longint;
  264. begin
  265. octstr[0]:=char(cnt);
  266. for i:=cnt downto 1 do
  267. begin
  268. octstr[i]:=hextbl[val and 7];
  269. val:=val shr 3;
  270. end;
  271. end;
  272. function binstr(val : int64;cnt : byte) : shortstring;
  273. var
  274. i : longint;
  275. begin
  276. binstr[0]:=char(cnt);
  277. for i:=cnt downto 1 do
  278. begin
  279. binstr[i]:=char(48+val and 1);
  280. val:=val shr 1;
  281. end;
  282. end;
  283. Function hexStr(Val:qword;cnt:byte):shortstring;
  284. begin
  285. hexStr:=hexStr(int64(Val),cnt);
  286. end;
  287. Function OctStr(Val:qword;cnt:byte):shortstring;
  288. begin
  289. OctStr:=OctStr(int64(Val),cnt);
  290. end;
  291. Function binStr(Val:qword;cnt:byte):shortstring;
  292. begin
  293. binStr:=binStr(int64(Val),cnt);
  294. end;
  295. function hexstr(val : pointer) : shortstring;
  296. var
  297. i : longint;
  298. v : ptruint;
  299. begin
  300. v:=ptruint(val);
  301. hexstr[0]:=chr(sizeof(pointer)*2);
  302. for i:=sizeof(pointer)*2 downto 1 do
  303. begin
  304. hexstr[i]:=hextbl[v and $f];
  305. v:=v shr 4;
  306. end;
  307. end;
  308. function space (b : byte): shortstring;
  309. begin
  310. space[0] := chr(b);
  311. FillChar (Space[1],b,' ');
  312. end;
  313. {*****************************************************************************
  314. Str() Helpers
  315. *****************************************************************************}
  316. procedure fpc_shortstr_SInt(v : valSInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SINT']; compilerproc;
  317. begin
  318. int_str(v,s);
  319. if length(s)<len then
  320. s:=space(len-length(s))+s;
  321. end;
  322. procedure fpc_shortstr_UInt(v : valUInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_UINT']; compilerproc;
  323. begin
  324. int_str(v,s);
  325. if length(s)<len then
  326. s:=space(len-length(s))+s;
  327. end;
  328. {$ifndef CPU64}
  329. procedure fpc_shortstr_qword(v : qword;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; compilerproc;
  330. begin
  331. int_str(v,s);
  332. if length(s)<len then
  333. s:=space(len-length(s))+s;
  334. end;
  335. procedure fpc_shortstr_int64(v : int64;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; compilerproc;
  336. begin
  337. int_str(v,s);
  338. if length(s)<len then
  339. s:=space(len-length(s))+s;
  340. end;
  341. {$endif CPU64}
  342. { fpc_shortstr_sInt must appear before this file is included, because }
  343. { it's used inside real2str.inc and otherwise the searching via the }
  344. { compilerproc name will fail (JM) }
  345. {$ifndef FPUNONE}
  346. {$I real2str.inc}
  347. {$endif}
  348. {$ifndef FPUNONE}
  349. procedure fpc_shortstr_float(d : ValReal;len,fr,rt : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_FLOAT']; compilerproc;
  350. begin
  351. str_real(len,fr,d,treal_type(rt),s);
  352. end;
  353. {$endif}
  354. function fpc_shortstr_enum_intern(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring): longint;
  355. { The following contains the TTypeInfo/TTypeData records from typinfo.pp
  356. specialized for the tkEnumeration case (and stripped of unused things). }
  357. type
  358. PPstring=^Pstring;
  359. Penum_typeinfo=^Tenum_typeinfo;
  360. Tenum_typeinfo={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  361. kind:byte; { always tkEnumeration }
  362. num_chars:byte;
  363. chars:array[0..0] of char; { variable length with size of num_chars }
  364. end;
  365. Penum_typedata=^Tenum_typedata;
  366. Tenum_typedata={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  367. ordtype:byte;
  368. { this seemingly extraneous inner record is here for alignment purposes, so
  369. that its data gets aligned properly (if FPC_REQUIRES_PROPER_ALIGNMENT is
  370. set }
  371. inner: {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  372. minvalue,maxvalue:longint;
  373. basetype:pointer; { required for alignment }
  374. end;
  375. { more data here, but not needed }
  376. end;
  377. { Pascal data types for the ordinal enum value to string table. It consists of a header
  378. that indicates what type of data the table stores, either a direct lookup table (when
  379. o = lookup) or a set of ordered (ordinal value, string) tuples (when o = search). }
  380. { A single entry in the set of ordered tuples }
  381. Psearch_data=^Tsearch_data;
  382. Tsearch_data={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  383. value:longint;
  384. name:Pstring;
  385. end;
  386. Penum_ord_to_string=^Tenum_ord_to_string;
  387. Tenum_ord_to_string={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  388. o:(lookup,search);
  389. case integer of
  390. 0: (lookup_data:array[0..0] of Pstring);
  391. 1: (num_entries:longint;
  392. search_data:array[0..0] of Tsearch_data);
  393. end;
  394. var
  395. enum_o2s : Penum_ord_to_string;
  396. header:Penum_typeinfo;
  397. body:Penum_typedata;
  398. res:Pshortstring;
  399. sorted_data:Psearch_data;
  400. spaces,i,m,h,l:longint;
  401. begin
  402. { set default return value }
  403. fpc_shortstr_enum_intern:=107;
  404. enum_o2s:=Penum_ord_to_string(ord2strindex);
  405. { depending on the type of table in ord2strindex retrieve the data }
  406. if (enum_o2s^.o=lookup) then
  407. begin
  408. { direct lookup table }
  409. header:=Penum_typeinfo(typinfo);
  410. { calculate address of enum rtti body: add the actual size of the
  411. enum_rtti_header, and then align. Use an alignment of 1 (which
  412. does nothing) in case FPC_REQUIRES_PROPER_ALIGNMENT is not set
  413. to avoid the need for an if in this situation }
  414. body:=Penum_typedata(align(ptruint(header) + 2 * sizeof(byte) { kind, num_chars } + header^.num_chars,
  415. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT} 1 {$else} sizeof(pointer) {$endif}));
  416. with (body^.inner) do
  417. begin
  418. { Bounds check for the ordinal value for this enum }
  419. if (ordinal<minvalue) or (ordinal>maxvalue) then
  420. exit;
  421. { make the ordinal index for lookup zero-based }
  422. dec(ordinal,minvalue);
  423. end;
  424. { temporarily disable range checking because of the access to the array[0..0]
  425. member of Tenum_ord_to_string_lookup }
  426. {$PUSH}{$R-}
  427. res:=enum_o2s^.lookup_data[ordinal];
  428. {$POP}
  429. if (not assigned(res)) then
  430. exit;
  431. s:=res^;
  432. end
  433. else
  434. begin
  435. { The compiler did generate a sorted array of (ordvalue,Pstring) tuples }
  436. sorted_data:=@enum_o2s^.search_data;
  437. { Use a binary search to get the string }
  438. l:=0;
  439. { temporarily disable range checking because of the access to the array[0..0]
  440. member of Tenum_ord_to_string_search }
  441. {$PUSH}{$R-}
  442. h:=enum_o2s^.num_entries-1;
  443. repeat
  444. m:=(l+h) div 2;
  445. if ordinal>sorted_data[m].value then
  446. l:=m+1
  447. else if ordinal<sorted_data[m].value then
  448. h:=m-1
  449. else
  450. break;
  451. if l>h then
  452. exit; { Ordinal value not found? Exit }
  453. until false;
  454. {$POP}
  455. s:=sorted_data[m].name^;
  456. end;
  457. { Pad the string with spaces if necessary }
  458. if (len>length(s)) then
  459. begin
  460. spaces:=len-length(s);
  461. for i:=1 to spaces do
  462. s[length(s)+i]:=' ';
  463. inc(byte(s[0]),spaces);
  464. end;
  465. fpc_shortstr_enum_intern:=0;
  466. end;
  467. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);[public,alias:'FPC_SHORTSTR_ENUM'];compilerproc;
  468. var
  469. res: longint;
  470. begin
  471. res:=fpc_shortstr_enum_intern(ordinal,len,typinfo,ord2strindex,s);
  472. if (res<>0) then
  473. runerror(107);
  474. end;
  475. { also define alias for internal use in the system unit }
  476. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);external name 'FPC_SHORTSTR_ENUM';
  477. procedure fpc_shortstr_bool(b : boolean;len:sizeint;out s:shortstring);[public,alias:'FPC_SHORTSTR_BOOL'];compilerproc;
  478. begin
  479. if b then
  480. s:='TRUE'
  481. else
  482. s:='FALSE';
  483. if length(s)<len then
  484. s:=space(len-length(s))+s;
  485. end;
  486. { also define alias for internal use in the system unit }
  487. procedure fpc_shortstr_bool(b : boolean;len:sizeint;out s:shortstring);external name 'FPC_SHORTSTR_BOOL';
  488. procedure fpc_shortstr_currency(c : currency; len,f : SizeInt; out s : shortstring);[public,alias:'FPC_SHORTSTR_CURRENCY']; compilerproc;
  489. const
  490. MinLen = 8; { Minimal string length in scientific format }
  491. var
  492. buf : array[1..19] of char;
  493. i,j,k,reslen,tlen,sign,r,point : longint;
  494. ic : qword;
  495. begin
  496. fillchar(buf,length(buf),'0');
  497. { default value for length is -32767 }
  498. if len=-32767 then
  499. len:=25;
  500. if PInt64(@c)^ >= 0 then
  501. begin
  502. ic:=QWord(PInt64(@c)^);
  503. sign:=0;
  504. end
  505. else
  506. begin
  507. sign:=1;
  508. ic:=QWord(-PInt64(@c)^);
  509. end;
  510. { converting to integer string }
  511. tlen:=0;
  512. repeat
  513. Inc(tlen);
  514. buf[tlen]:=Chr(ic mod 10 + $30);
  515. ic:=ic div 10;
  516. until ic = 0;
  517. { calculating:
  518. reslen - length of result string,
  519. r - rounding or appending zeroes,
  520. point - place of decimal point }
  521. reslen:=tlen;
  522. if f <> 0 then
  523. Inc(reslen); { adding decimal point length }
  524. if f < 0 then
  525. begin
  526. { scientific format }
  527. Inc(reslen,5); { adding length of sign and exponent }
  528. if len < MinLen then
  529. len:=MinLen;
  530. r:=reslen-len;
  531. if reslen < len then
  532. reslen:=len;
  533. if r > 0 then
  534. begin
  535. reslen:=len;
  536. point:=tlen - r;
  537. end
  538. else
  539. point:=tlen;
  540. end
  541. else
  542. begin
  543. { fixed format }
  544. Inc(reslen, sign);
  545. { prepending fractional part with zeroes }
  546. while tlen < 5 do
  547. begin
  548. Inc(reslen);
  549. Inc(tlen);
  550. buf[tlen]:='0';
  551. end;
  552. { Currency have 4 digits in fractional part }
  553. r:=4 - f;
  554. point:=f;
  555. if point <> 0 then
  556. begin
  557. if point > 4 then
  558. point:=4;
  559. Inc(point);
  560. end;
  561. Dec(reslen,r);
  562. end;
  563. { rounding string if r > 0 }
  564. if r > 0 then
  565. begin
  566. i:=1;
  567. k:=0;
  568. for j:=0 to r do
  569. begin
  570. if (k=1) and (buf[i]='9') then
  571. buf[i]:='0'
  572. else
  573. begin
  574. buf[i]:=chr(ord(buf[i]) + k);
  575. if buf[i] >= '5' then
  576. k:=1
  577. else
  578. k:=0;
  579. end;
  580. Inc(i);
  581. if i>tlen then
  582. break;
  583. end;
  584. If (k=1) and (buf[i-1]='0') then
  585. begin
  586. { 1.9996 rounded to two decimal digits after the decimal separator must result in
  587. 2.00, i.e. the rounding is propagated
  588. }
  589. while buf[i]='9' do
  590. begin
  591. buf[i]:='0';
  592. inc(i);
  593. end;
  594. buf[i]:=chr(Ord(buf[i])+1);
  595. { did we add another digit? This happens when rounding
  596. e.g. 99.9996 to two decimal digits after the decimal separator which should result in
  597. 100.00
  598. }
  599. if i>reslen then
  600. begin
  601. inc(reslen);
  602. inc(tlen);
  603. end;
  604. end;
  605. end;
  606. { preparing result string }
  607. if reslen<len then
  608. reslen:=len;
  609. if reslen>High(s) then
  610. begin
  611. if r < 0 then
  612. Inc(r, reslen - High(s));
  613. reslen:=High(s);
  614. end;
  615. SetLength(s,reslen);
  616. j:=reslen;
  617. if f<0 then
  618. begin
  619. { writing power of 10 part }
  620. if PInt64(@c)^ = 0 then
  621. k:=0
  622. else
  623. k:=tlen-5;
  624. if k >= 0 then
  625. s[j-2]:='+'
  626. else
  627. begin
  628. s[j-2]:='-';
  629. k:=-k;
  630. end;
  631. s[j]:=Chr(k mod 10 + $30);
  632. Dec(j);
  633. s[j]:=Chr(k div 10 + $30);
  634. Dec(j,2);
  635. s[j]:='E';
  636. Dec(j);
  637. end;
  638. { writing extra zeroes if r < 0 }
  639. while r < 0 do
  640. begin
  641. s[j]:='0';
  642. Dec(j);
  643. Inc(r);
  644. end;
  645. { writing digits and decimal point }
  646. for i:=r + 1 to tlen do
  647. begin
  648. Dec(point);
  649. if point = 0 then
  650. begin
  651. s[j]:='.';
  652. Dec(j);
  653. end;
  654. s[j]:=buf[i];
  655. Dec(j);
  656. end;
  657. { writing sign }
  658. if sign = 1 then
  659. begin
  660. s[j]:='-';
  661. Dec(j);
  662. end;
  663. { writing spaces }
  664. while j > 0 do
  665. begin
  666. s[j]:=' ';
  667. Dec(j);
  668. end;
  669. end;
  670. {
  671. Array Of Char Str() helpers
  672. }
  673. procedure fpc_chararray_sint(v : valsint;len : SizeInt;out a:array of char);compilerproc;
  674. var
  675. ss : shortstring;
  676. maxlen : SizeInt;
  677. begin
  678. int_str(v,ss);
  679. if length(ss)<len then
  680. ss:=space(len-length(ss))+ss;
  681. if length(ss)<high(a)+1 then
  682. maxlen:=length(ss)
  683. else
  684. maxlen:=high(a)+1;
  685. move(ss[1],pchar(@a)^,maxlen);
  686. end;
  687. procedure fpc_chararray_uint(v : valuint;len : SizeInt;out a : array of char);compilerproc;
  688. var
  689. ss : shortstring;
  690. maxlen : SizeInt;
  691. begin
  692. int_str(v,ss);
  693. if length(ss)<len then
  694. ss:=space(len-length(ss))+ss;
  695. if length(ss)<high(a)+1 then
  696. maxlen:=length(ss)
  697. else
  698. maxlen:=high(a)+1;
  699. move(ss[1],pchar(@a)^,maxlen);
  700. end;
  701. {$ifndef CPU64}
  702. procedure fpc_chararray_qword(v : qword;len : SizeInt;out a : array of char);compilerproc;
  703. var
  704. ss : shortstring;
  705. maxlen : SizeInt;
  706. begin
  707. int_str(v,ss);
  708. if length(ss)<len then
  709. ss:=space(len-length(ss))+ss;
  710. if length(ss)<high(a)+1 then
  711. maxlen:=length(ss)
  712. else
  713. maxlen:=high(a)+1;
  714. move(ss[1],pchar(@a)^,maxlen);
  715. end;
  716. procedure fpc_chararray_int64(v : int64;len : SizeInt;out a : array of char);compilerproc;
  717. var
  718. ss : shortstring;
  719. maxlen : SizeInt;
  720. begin
  721. int_str(v,ss);
  722. if length(ss)<len then
  723. ss:=space(len-length(ss))+ss;
  724. if length(ss)<high(a)+1 then
  725. maxlen:=length(ss)
  726. else
  727. maxlen:=high(a)+1;
  728. move(ss[1],pchar(@a)^,maxlen);
  729. end;
  730. {$endif CPU64}
  731. {$ifndef FPUNONE}
  732. procedure fpc_chararray_Float(d : ValReal;len,fr,rt : SizeInt;out a : array of char);compilerproc;
  733. var
  734. ss : shortstring;
  735. maxlen : SizeInt;
  736. begin
  737. str_real(len,fr,d,treal_type(rt),ss);
  738. if length(ss)<high(a)+1 then
  739. maxlen:=length(ss)
  740. else
  741. maxlen:=high(a)+1;
  742. move(ss[1],pchar(@a)^,maxlen);
  743. end;
  744. {$endif}
  745. procedure fpc_chararray_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out a : array of char);compilerproc;
  746. var
  747. ss : shortstring;
  748. maxlen : SizeInt;
  749. begin
  750. fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss);
  751. if length(ss)<high(a)+1 then
  752. maxlen:=length(ss)
  753. else
  754. maxlen:=high(a)+1;
  755. move(ss[1],pchar(@a)^,maxlen);
  756. end;
  757. procedure fpc_chararray_bool(b : boolean;len:sizeint;out a : array of char);compilerproc;
  758. var
  759. ss : shortstring;
  760. maxlen : SizeInt;
  761. begin
  762. fpc_shortstr_bool(b,len,ss);
  763. if length(ss)<high(a)+1 then
  764. maxlen:=length(ss)
  765. else
  766. maxlen:=high(a)+1;
  767. move(ss[1],pchar(@a)^,maxlen);
  768. end;
  769. {$ifdef FPC_HAS_STR_CURRENCY}
  770. procedure fpc_chararray_Currency(c : Currency;len,fr : SizeInt;out a : array of char);compilerproc;
  771. var
  772. ss : shortstring;
  773. maxlen : SizeInt;
  774. begin
  775. str(c:len:fr,ss);
  776. if length(ss)<high(a)+1 then
  777. maxlen:=length(ss)
  778. else
  779. maxlen:=high(a)+1;
  780. move(ss[1],pchar(@a)^,maxlen);
  781. end;
  782. {$endif FPC_HAS_STR_CURRENCY}
  783. {*****************************************************************************
  784. Val() Functions
  785. *****************************************************************************}
  786. Function InitVal(const s:shortstring;out negativ:boolean;out base:byte):ValSInt;
  787. var
  788. Code : SizeInt;
  789. begin
  790. code:=1;
  791. negativ:=false;
  792. base:=10;
  793. if length(s)=0 then
  794. begin
  795. InitVal:=code;
  796. Exit;
  797. end;
  798. {Skip Spaces and Tab}
  799. while (code<=length(s)) and (s[code] in [' ',#9]) do
  800. inc(code);
  801. {Sign}
  802. case s[code] of
  803. '-' : begin
  804. negativ:=true;
  805. inc(code);
  806. end;
  807. '+' : inc(code);
  808. end;
  809. {Base}
  810. if code<=length(s) then
  811. begin
  812. case s[code] of
  813. '$',
  814. 'X',
  815. 'x' : begin
  816. base:=16;
  817. inc(code);
  818. end;
  819. '%' : begin
  820. base:=2;
  821. inc(code);
  822. end;
  823. '&' : begin
  824. Base:=8;
  825. inc(code);
  826. end;
  827. '0' : begin
  828. if (code < length(s)) and (s[code+1] in ['x', 'X']) then
  829. begin
  830. inc(code, 2);
  831. base := 16;
  832. end;
  833. end;
  834. end;
  835. end;
  836. { strip leading zeros }
  837. while ((code < length(s)) and (s[code] = '0')) do begin
  838. inc(code);
  839. end;
  840. InitVal:=code;
  841. end;
  842. Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
  843. var
  844. temp, prev, maxPrevValue, maxNewValue: ValUInt;
  845. base,u : byte;
  846. negative : boolean;
  847. begin
  848. fpc_Val_SInt_ShortStr := 0;
  849. Temp:=0;
  850. Code:=InitVal(s,negative,base);
  851. if Code>length(s) then
  852. exit;
  853. if (s[Code]=#0) then
  854. begin
  855. if (Code>1) and (s[Code-1]='0') then
  856. Code:=0;
  857. exit;
  858. end;
  859. maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
  860. if (base = 10) then
  861. maxNewValue := MaxSIntValue + ord(negative)
  862. else
  863. maxNewValue := MaxUIntValue;
  864. while Code<=Length(s) do
  865. begin
  866. case s[Code] of
  867. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  868. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  869. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  870. #0 : break;
  871. else
  872. u:=16;
  873. end;
  874. Prev := Temp;
  875. Temp := Temp*ValUInt(base);
  876. If (u >= base) or
  877. (ValUInt(maxNewValue-u) < Temp) or
  878. (prev > maxPrevValue) Then
  879. Begin
  880. fpc_Val_SInt_ShortStr := 0;
  881. Exit
  882. End;
  883. Temp:=Temp+u;
  884. inc(code);
  885. end;
  886. code := 0;
  887. fpc_Val_SInt_ShortStr := ValSInt(Temp);
  888. If Negative Then
  889. fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
  890. If Not(Negative) and (base <> 10) Then
  891. {sign extend the result to allow proper range checking}
  892. Case DestSize of
  893. 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr);
  894. 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr);
  895. {$ifdef cpu64}
  896. 4: fpc_Val_SInt_ShortStr := longint(fpc_Val_SInt_ShortStr);
  897. {$endif cpu64}
  898. End;
  899. end;
  900. { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because }
  901. { we have to pass the DestSize parameter on (JM) }
  902. Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR'];
  903. Function fpc_Val_UInt_Shortstr(Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc;
  904. var
  905. prev : ValUInt;
  906. base,u : byte;
  907. negative : boolean;
  908. begin
  909. fpc_Val_UInt_Shortstr:=0;
  910. Code:=InitVal(s,negative,base);
  911. If Negative or (Code>length(s)) Then
  912. Exit;
  913. if (s[Code]=#0) then
  914. begin
  915. if (Code>1) and (s[Code-1]='0') then
  916. Code:=0;
  917. exit;
  918. end;
  919. while Code<=Length(s) do
  920. begin
  921. case s[Code] of
  922. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  923. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  924. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  925. #0 : break;
  926. else
  927. u:=16;
  928. end;
  929. prev := fpc_Val_UInt_Shortstr;
  930. If (u>=base) or
  931. (ValUInt(MaxUIntValue-u) div ValUInt(Base)<prev) then
  932. begin
  933. fpc_Val_UInt_Shortstr:=0;
  934. exit;
  935. end;
  936. fpc_Val_UInt_Shortstr:=fpc_Val_UInt_Shortstr*ValUInt(base) + u;
  937. inc(code);
  938. end;
  939. code := 0;
  940. end;
  941. {$ifndef CPU64}
  942. Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; compilerproc;
  943. var u, temp, prev, maxprevvalue, maxnewvalue : qword;
  944. base : byte;
  945. negative : boolean;
  946. const maxint64=qword($7fffffffffffffff);
  947. maxqword=qword($ffffffffffffffff);
  948. begin
  949. fpc_val_int64_shortstr := 0;
  950. Temp:=0;
  951. Code:=InitVal(s,negative,base);
  952. if Code>length(s) then
  953. exit;
  954. if (s[Code]=#0) then
  955. begin
  956. if (Code>1) and (s[Code-1]='0') then
  957. Code:=0;
  958. exit;
  959. end;
  960. maxprevvalue := maxqword div base;
  961. if (base = 10) then
  962. maxnewvalue := maxint64 + ord(negative)
  963. else
  964. maxnewvalue := maxqword;
  965. while Code<=Length(s) do
  966. begin
  967. case s[Code] of
  968. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  969. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  970. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  971. #0 : break;
  972. else
  973. u:=16;
  974. end;
  975. Prev:=Temp;
  976. Temp:=Temp*qword(base);
  977. If (u >= base) or
  978. (qword(maxnewvalue-u) < temp) or
  979. (prev > maxprevvalue) Then
  980. Begin
  981. fpc_val_int64_shortstr := 0;
  982. Exit
  983. End;
  984. Temp:=Temp+u;
  985. inc(code);
  986. end;
  987. code:=0;
  988. fpc_val_int64_shortstr:=int64(Temp);
  989. If Negative Then
  990. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  991. end;
  992. Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc;
  993. var u, prev: QWord;
  994. base : byte;
  995. negative : boolean;
  996. const maxqword=qword($ffffffffffffffff);
  997. begin
  998. fpc_val_qword_shortstr:=0;
  999. Code:=InitVal(s,negative,base);
  1000. If Negative or (Code>length(s)) Then
  1001. Exit;
  1002. if (s[Code]=#0) then
  1003. begin
  1004. if (Code>1) and (s[Code-1]='0') then
  1005. Code:=0;
  1006. exit;
  1007. end;
  1008. while Code<=Length(s) do
  1009. begin
  1010. case s[Code] of
  1011. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  1012. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  1013. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  1014. #0 : break;
  1015. else
  1016. u:=16;
  1017. end;
  1018. prev := fpc_val_qword_shortstr;
  1019. If (u>=base) or
  1020. ((QWord(maxqword-u) div QWord(base))<prev) then
  1021. Begin
  1022. fpc_val_qword_shortstr := 0;
  1023. Exit
  1024. End;
  1025. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  1026. inc(code);
  1027. end;
  1028. code := 0;
  1029. end;
  1030. {$endif CPU64}
  1031. {$ifndef FPUNONE}
  1032. const
  1033. {$ifdef FPC_HAS_TYPE_EXTENDED}
  1034. valmaxexpnorm=4932;
  1035. {$else}
  1036. {$ifdef FPC_HAS_TYPE_DOUBLE}
  1037. valmaxexpnorm=308;
  1038. {$else}
  1039. {$ifdef FPC_HAS_TYPE_SINGLE}
  1040. valmaxexpnorm=38;
  1041. {$else}
  1042. {$error Unknown floating point precision }
  1043. {$endif}
  1044. {$endif}
  1045. {$endif}
  1046. {$endif}
  1047. {$ifndef FPUNONE}
  1048. Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
  1049. var
  1050. hd,
  1051. esign,sign : valreal;
  1052. exponent,
  1053. decpoint,i : SizeInt;
  1054. flags : byte;
  1055. begin
  1056. fpc_Val_Real_ShortStr:=0.0;
  1057. code:=1;
  1058. exponent:=0;
  1059. decpoint:=0;
  1060. esign:=1;
  1061. flags:=0;
  1062. sign:=1;
  1063. while (code<=length(s)) and (s[code] in [' ',#9]) do
  1064. inc(code);
  1065. if code<=length(s) then
  1066. case s[code] of
  1067. '+' : inc(code);
  1068. '-' : begin
  1069. sign:=-1;
  1070. inc(code);
  1071. end;
  1072. end;
  1073. while (Code<=Length(s)) and (s[code] in ['0'..'9']) do
  1074. begin
  1075. { Read integer part }
  1076. flags:=flags or 1;
  1077. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  1078. inc(code);
  1079. end;
  1080. { Decimal ? }
  1081. if (length(s)>=code) and (s[code]='.') then
  1082. begin
  1083. inc(code);
  1084. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  1085. begin
  1086. { Read fractional part. }
  1087. flags:=flags or 2;
  1088. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  1089. inc(decpoint);
  1090. inc(code);
  1091. end;
  1092. end;
  1093. { Again, read integer and fractional part}
  1094. if flags=0 then
  1095. begin
  1096. fpc_Val_Real_ShortStr:=0.0;
  1097. exit;
  1098. end;
  1099. { Exponent ? }
  1100. if (length(s)>=code) and (s[code] in ['e','E']) then
  1101. begin
  1102. inc(code);
  1103. if Length(s) >= code then
  1104. if s[code]='+' then
  1105. inc(code)
  1106. else
  1107. if s[code]='-' then
  1108. begin
  1109. esign:=-1;
  1110. inc(code);
  1111. end;
  1112. if (length(s)<code) or not(s[code] in ['0'..'9']) then
  1113. begin
  1114. fpc_Val_Real_ShortStr:=0.0;
  1115. exit;
  1116. end;
  1117. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  1118. begin
  1119. exponent:=exponent*10;
  1120. exponent:=exponent+ord(s[code])-ord('0');
  1121. inc(code);
  1122. end;
  1123. end;
  1124. { adjust exponent based on decimal point }
  1125. if esign>0 then
  1126. begin
  1127. dec(exponent,decpoint);
  1128. if (exponent<0) then
  1129. begin
  1130. esign:=-1;
  1131. exponent:=-exponent;
  1132. end
  1133. end
  1134. else
  1135. inc(exponent,decpoint);
  1136. { evaluate sign }
  1137. { (before exponent, because the exponent may turn it into a denormal) }
  1138. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
  1139. { Calculate Exponent }
  1140. hd:=1.0;
  1141. { the magnitude range maximum (normal) is lower in absolute value than the }
  1142. { the magnitude range minimum (denormal). E.g. an extended value can go }
  1143. { up to 1E4932, but "down" to 1E-4951. So make sure that we don't try to }
  1144. { calculate 1E4951 as factor, since that would overflow and result in 0. }
  1145. if (exponent>valmaxexpnorm-2) then
  1146. begin
  1147. for i:=1 to valmaxexpnorm-2 do
  1148. hd:=hd*10.0;
  1149. if esign>0 then
  1150. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1151. else
  1152. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1153. dec(exponent,valmaxexpnorm-2);
  1154. hd:=1.0;
  1155. end;
  1156. for i:=1 to exponent do
  1157. hd:=hd*10.0;
  1158. if esign>0 then
  1159. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1160. else
  1161. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1162. { Not all characters are read ? }
  1163. if length(s)>=code then
  1164. begin
  1165. fpc_Val_Real_ShortStr:=0.0;
  1166. exit;
  1167. end;
  1168. { success ! }
  1169. code:=0;
  1170. end;
  1171. {$endif}
  1172. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_SHORTSTR']; compilerproc;
  1173. function string_compare(const s1,s2:shortstring):sizeint;
  1174. {We cannot use the > and < operators to compare a string here, because we if the string is
  1175. not found in the enum, we need to return the position of error in "code". Code equals the
  1176. highest matching character of all string compares, which is only known inside the string
  1177. comparison.}
  1178. var i,l:byte;
  1179. c1,c2:char;
  1180. begin
  1181. l:=length(s1);
  1182. if length(s1)>length(s2) then
  1183. l:=length(s2);
  1184. i:=1;
  1185. while i<=l do
  1186. begin
  1187. c1:=s1[i];
  1188. c2:=s2[i];
  1189. if c1<>c2 then
  1190. break;
  1191. inc(i);
  1192. end;
  1193. if i>code then
  1194. code:=i;
  1195. if i<=l then
  1196. string_compare:=byte(c1)-byte(c2)
  1197. else
  1198. string_compare:=length(s1)-length(s2);
  1199. end;
  1200. type Psorted_array=^Tsorted_array;
  1201. Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1202. o:longint;
  1203. s:Pstring;
  1204. end;
  1205. Pstring_to_ord=^Tstring_to_ord;
  1206. Tstring_to_ord={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1207. count:longint;
  1208. data:array[0..0] of Tsorted_array;
  1209. end;
  1210. var l,h,m:cardinal;
  1211. c:sizeint;
  1212. sorted_array:^Tsorted_array;
  1213. spaces:byte;
  1214. t:shortstring;
  1215. begin
  1216. {Val for numbers accepts spaces at the start, so lets do the same
  1217. for enums. Skip spaces at the start of the string.}
  1218. spaces:=1;
  1219. code:=1;
  1220. while (spaces<=length(s)) and (s[spaces]=' ') do
  1221. inc(spaces);
  1222. t:=upcase(copy(s,spaces,255));
  1223. sorted_array:=pointer(@Pstring_to_ord(str2ordindex)^.data);
  1224. {Use a binary search to get the string.}
  1225. l:=1;
  1226. h:=Pstring_to_ord(str2ordindex)^.count;
  1227. repeat
  1228. m:=(l+h) div 2;
  1229. c:=string_compare(t,upcase(sorted_array[m-1].s^));
  1230. if c>0 then
  1231. l:=m+1
  1232. else if c<0 then
  1233. h:=m-1
  1234. else
  1235. break;
  1236. if l>h then
  1237. begin
  1238. {Not found...}
  1239. inc(code,spaces-1); {Add skipped spaces again.}
  1240. {The result of val in case of error is undefined, don't assign a function result.}
  1241. exit;
  1242. end;
  1243. until false;
  1244. code:=0;
  1245. fpc_val_enum_shortstr:=sorted_array[m-1].o;
  1246. end;
  1247. {Redeclare fpc_val_enum_shortstr for internal use in the system unit.}
  1248. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint;external name 'FPC_VAL_ENUM_SHORTSTR';
  1249. function fpc_Val_Currency_ShortStr(const s : shortstring; out Code : ValSInt): currency; [public, alias:'FPC_VAL_CURRENCY_SHORTSTR']; compilerproc;
  1250. const
  1251. MaxInt64 : Int64 = $7FFFFFFFFFFFFFFF;
  1252. Int64Edge : Int64 = ($7FFFFFFFFFFFFFFF - 10) div 10;
  1253. Int64Edge2 : Int64 = $7FFFFFFFFFFFFFFF div 10;
  1254. var
  1255. res : Int64;
  1256. i,j,power,sign,len : longint;
  1257. FracOverflow : boolean;
  1258. begin
  1259. fpc_Val_Currency_ShortStr:=0;
  1260. res:=0;
  1261. len:=Length(s);
  1262. Code:=1;
  1263. sign:=1;
  1264. power:=0;
  1265. while True do
  1266. if Code > len then
  1267. exit
  1268. else
  1269. if s[Code] in [' ', #9] then
  1270. Inc(Code)
  1271. else
  1272. break;
  1273. { Read sign }
  1274. case s[Code] of
  1275. '+' : Inc(Code);
  1276. '-' : begin
  1277. sign:=-1;
  1278. inc(code);
  1279. end;
  1280. end;
  1281. { Read digits }
  1282. FracOverflow:=False;
  1283. i:=0;
  1284. while Code <= len do
  1285. begin
  1286. case s[Code] of
  1287. '0'..'9':
  1288. begin
  1289. j:=Ord(s[code])-Ord('0');
  1290. { check overflow }
  1291. if (res <= Int64Edge) or (res <= (MaxInt64 - j) div 10) then
  1292. begin
  1293. res:=res*10 + j;
  1294. Inc(i);
  1295. end
  1296. else
  1297. if power = 0 then
  1298. { exit if integer part overflow }
  1299. exit
  1300. else
  1301. begin
  1302. if not FracOverflow and (j >= 5) and (res < MaxInt64) then
  1303. { round if first digit of fractional part overflow }
  1304. Inc(res);
  1305. FracOverflow:=True;
  1306. end;
  1307. end;
  1308. '.':
  1309. begin
  1310. if power = 0 then
  1311. begin
  1312. power:=1;
  1313. i:=0;
  1314. end
  1315. else
  1316. exit;
  1317. end;
  1318. else
  1319. break;
  1320. end;
  1321. Inc(Code);
  1322. end;
  1323. if (i = 0) and (power = 0) then
  1324. exit;
  1325. if power <> 0 then
  1326. power:=i;
  1327. power:=4 - power;
  1328. { Exponent? }
  1329. if Code <= len then
  1330. if s[Code] in ['E', 'e'] then
  1331. begin
  1332. Inc(Code);
  1333. if Code > len then
  1334. exit;
  1335. i:=1;
  1336. case s[Code] of
  1337. '+':
  1338. Inc(Code);
  1339. '-':
  1340. begin
  1341. i:=-1;
  1342. Inc(Code);
  1343. end;
  1344. end;
  1345. { read exponent }
  1346. j:=0;
  1347. while Code <= len do
  1348. if s[Code] in ['0'..'9'] then
  1349. begin
  1350. if j > 4951 then
  1351. exit;
  1352. j:=j*10 + (Ord(s[code])-Ord('0'));
  1353. Inc(Code);
  1354. end
  1355. else
  1356. exit;
  1357. power:=power + j*i;
  1358. end
  1359. else
  1360. exit;
  1361. if power > 0 then
  1362. begin
  1363. for i:=1 to power do
  1364. if res <= Int64Edge2 then
  1365. res:=res*10
  1366. else
  1367. exit;
  1368. end
  1369. else
  1370. for i:=1 to -power do
  1371. begin
  1372. if res <= MaxInt64 - 5 then
  1373. Inc(res, 5);
  1374. res:=res div 10;
  1375. end;
  1376. res:=res*sign;
  1377. fpc_Val_Currency_ShortStr:=PCurrency(@res)^;
  1378. Code:=0;
  1379. end;
  1380. Procedure SetString (Out S : Shortstring; Buf : PChar; Len : SizeInt);
  1381. begin
  1382. If Len > High(S) then
  1383. Len := High(S);
  1384. SetLength(S,Len);
  1385. If Buf<>Nil then
  1386. begin
  1387. Move (Buf[0],S[1],Len);
  1388. end;
  1389. end;
  1390. function ShortCompareText(const S1, S2: shortstring): SizeInt;
  1391. var
  1392. c1, c2: Byte;
  1393. i: Integer;
  1394. L1, L2, Count: SizeInt;
  1395. P1, P2: PChar;
  1396. begin
  1397. L1 := Length(S1);
  1398. L2 := Length(S2);
  1399. if L1 > L2 then
  1400. Count := L2
  1401. else
  1402. Count := L1;
  1403. i := 0;
  1404. P1 := @S1[1];
  1405. P2 := @S2[1];
  1406. while i < count do
  1407. begin
  1408. c1 := byte(p1^);
  1409. c2 := byte(p2^);
  1410. if c1 <> c2 then
  1411. begin
  1412. if c1 in [97..122] then
  1413. Dec(c1, 32);
  1414. if c2 in [97..122] then
  1415. Dec(c2, 32);
  1416. if c1 <> c2 then
  1417. Break;
  1418. end;
  1419. Inc(P1); Inc(P2); Inc(I);
  1420. end;
  1421. if i < count then
  1422. ShortCompareText := c1 - c2
  1423. else
  1424. ShortCompareText := L1 - L2;
  1425. end;