sstrings.inc 38 KB

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