sstrings.inc 36 KB

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