sstrings.inc 43 KB

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