sstrings.inc 40 KB

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