sstrings.inc 36 KB

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