sstrings.inc 42 KB

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