sstrings.inc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  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. type
  348. Ptypeinfo=^Ttypeinfo;
  349. Ttypeinfo=record
  350. kind:byte;
  351. name:shortstring;
  352. end;
  353. Penuminfo=^Tenuminfo;
  354. Tenuminfo={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  355. ordtype:byte;
  356. minvalue,maxvalue:longint;
  357. basetype:pointer;
  358. namelist:shortstring;
  359. end;
  360. Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  361. o:longint;
  362. s:Pstring;
  363. end;
  364. var
  365. p:Pstring;
  366. l,h,m:cardinal;
  367. sorted_array:^Tsorted_array;
  368. i,spaces:byte;
  369. begin
  370. fpc_shortstr_enum_intern:=107;
  371. if Pcardinal(ord2strindex)^=0 then
  372. begin
  373. {The compiler did generate a lookup table.}
  374. with Penuminfo(Pbyte(typinfo)+2+length(Ptypeinfo(typinfo)^.name))^ do
  375. begin
  376. if (ordinal<minvalue) or (ordinal>maxvalue) then
  377. exit; {Invalid ordinal value for this enum.}
  378. dec(ordinal,minvalue);
  379. end;
  380. {Get the address of the string.}
  381. p:=Pshortstring((PPpointer(ord2strindex)+1+ordinal)^);
  382. if p=nil then
  383. exit; {Invalid ordinal value for this enum.}
  384. s:=p^;
  385. end
  386. else
  387. begin
  388. {The compiler did generate a sorted array of (ordvalue,Pstring) tuples.}
  389. sorted_array:=pointer(Pcardinal(ord2strindex)+2);
  390. {Use a binary search to get the string.}
  391. l:=0;
  392. h:=(Pcardinal(ord2strindex)+1)^-1;
  393. repeat
  394. m:=(l+h) div 2;
  395. if ordinal>sorted_array[m].o then
  396. l:=m+1
  397. else if ordinal<sorted_array[m].o then
  398. h:=m-1
  399. else
  400. break;
  401. if l>h then
  402. exit; {Ordinal value not found? Kaboom.}
  403. until false;
  404. s:=sorted_array[m].s^;
  405. end;
  406. {Pad the string with spaces if necessary.}
  407. if len>length(s) then
  408. begin
  409. spaces:=len-length(s);
  410. for i:=1 to spaces do
  411. s[length(s)+i]:=' ';
  412. inc(byte(s[0]),spaces);
  413. end;
  414. fpc_shortstr_enum_intern:=0;
  415. end;
  416. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);[public,alias:'FPC_SHORTSTR_ENUM'];compilerproc;
  417. var
  418. res: longint;
  419. begin
  420. res:=fpc_shortstr_enum_intern(ordinal,len,typinfo,ord2strindex,s);
  421. if (res<>0) then
  422. runerror(107);
  423. end;
  424. { also define alias for internal use in the system unit }
  425. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);external name 'FPC_SHORTSTR_ENUM';
  426. procedure fpc_shortstr_currency(c : currency; len,f : SizeInt; out s : shortstring);[public,alias:'FPC_SHORTSTR_CURRENCY']; compilerproc;
  427. const
  428. MinLen = 8; { Minimal string length in scientific format }
  429. var
  430. buf : array[1..19] of char;
  431. i,j,k,reslen,tlen,sign,r,point : longint;
  432. ic : qword;
  433. begin
  434. fillchar(buf,length(buf),'0');
  435. { default value for length is -32767 }
  436. if len=-32767 then
  437. len:=25;
  438. if PInt64(@c)^ >= 0 then
  439. begin
  440. ic:=QWord(PInt64(@c)^);
  441. sign:=0;
  442. end
  443. else
  444. begin
  445. sign:=1;
  446. ic:=QWord(-PInt64(@c)^);
  447. end;
  448. { converting to integer string }
  449. tlen:=0;
  450. repeat
  451. Inc(tlen);
  452. buf[tlen]:=Chr(ic mod 10 + $30);
  453. ic:=ic div 10;
  454. until ic = 0;
  455. { calculating:
  456. reslen - length of result string,
  457. r - rounding or appending zeroes,
  458. point - place of decimal point }
  459. reslen:=tlen;
  460. if f <> 0 then
  461. Inc(reslen); { adding decimal point length }
  462. if f < 0 then
  463. begin
  464. { scientific format }
  465. Inc(reslen,5); { adding length of sign and exponent }
  466. if len < MinLen then
  467. len:=MinLen;
  468. r:=reslen-len;
  469. if reslen < len then
  470. reslen:=len;
  471. if r > 0 then
  472. begin
  473. reslen:=len;
  474. point:=tlen - r;
  475. end
  476. else
  477. point:=tlen;
  478. end
  479. else
  480. begin
  481. { fixed format }
  482. Inc(reslen, sign);
  483. { prepending fractional part with zeroes }
  484. while tlen < 5 do
  485. begin
  486. Inc(reslen);
  487. Inc(tlen);
  488. buf[tlen]:='0';
  489. end;
  490. { Currency have 4 digits in fractional part }
  491. r:=4 - f;
  492. point:=f;
  493. if point <> 0 then
  494. begin
  495. if point > 4 then
  496. point:=4;
  497. Inc(point);
  498. end;
  499. Dec(reslen,r);
  500. end;
  501. { rounding string if r > 0 }
  502. if r > 0 then
  503. begin
  504. i:=1;
  505. k:=0;
  506. for j:=0 to r do
  507. begin
  508. if (k=1) and (buf[i]='9') then
  509. buf[i]:='0'
  510. else
  511. begin
  512. buf[i]:=chr(ord(buf[i]) + k);
  513. if buf[i] >= '5' then
  514. k:=1
  515. else
  516. k:=0;
  517. end;
  518. Inc(i);
  519. if i>tlen then
  520. break;
  521. end;
  522. If (k=1) and (buf[i-1]='0') then
  523. begin
  524. { 1.9996 rounded to two decimal digits after the decimal separator must result in
  525. 2.00, i.e. the rounding is propagated
  526. }
  527. while buf[i]='9' do
  528. begin
  529. buf[i]:='0';
  530. inc(i);
  531. end;
  532. buf[i]:=chr(Ord(buf[i])+1);
  533. { did we add another digit? This happens when rounding
  534. e.g. 99.9996 to two decimal digits after the decimal separator which should result in
  535. 100.00
  536. }
  537. if i>reslen then
  538. begin
  539. inc(reslen);
  540. inc(tlen);
  541. end;
  542. end;
  543. end;
  544. { preparing result string }
  545. if reslen<len then
  546. reslen:=len;
  547. if reslen>High(s) then
  548. begin
  549. if r < 0 then
  550. Inc(r, reslen - High(s));
  551. reslen:=High(s);
  552. end;
  553. SetLength(s,reslen);
  554. j:=reslen;
  555. if f<0 then
  556. begin
  557. { writing power of 10 part }
  558. if PInt64(@c)^ = 0 then
  559. k:=0
  560. else
  561. k:=tlen-5;
  562. if k >= 0 then
  563. s[j-2]:='+'
  564. else
  565. begin
  566. s[j-2]:='-';
  567. k:=-k;
  568. end;
  569. s[j]:=Chr(k mod 10 + $30);
  570. Dec(j);
  571. s[j]:=Chr(k div 10 + $30);
  572. Dec(j,2);
  573. s[j]:='E';
  574. Dec(j);
  575. end;
  576. { writing extra zeroes if r < 0 }
  577. while r < 0 do
  578. begin
  579. s[j]:='0';
  580. Dec(j);
  581. Inc(r);
  582. end;
  583. { writing digits and decimal point }
  584. for i:=r + 1 to tlen do
  585. begin
  586. Dec(point);
  587. if point = 0 then
  588. begin
  589. s[j]:='.';
  590. Dec(j);
  591. end;
  592. s[j]:=buf[i];
  593. Dec(j);
  594. end;
  595. { writing sign }
  596. if sign = 1 then
  597. begin
  598. s[j]:='-';
  599. Dec(j);
  600. end;
  601. { writing spaces }
  602. while j > 0 do
  603. begin
  604. s[j]:=' ';
  605. Dec(j);
  606. end;
  607. end;
  608. {
  609. Array Of Char Str() helpers
  610. }
  611. procedure fpc_chararray_sint(v : valsint;len : SizeInt;out a:array of char);compilerproc;
  612. var
  613. ss : shortstring;
  614. maxlen : SizeInt;
  615. begin
  616. int_str(v,ss);
  617. if length(ss)<len then
  618. ss:=space(len-length(ss))+ss;
  619. if length(ss)<high(a)+1 then
  620. maxlen:=length(ss)
  621. else
  622. maxlen:=high(a)+1;
  623. move(ss[1],pchar(@a)^,maxlen);
  624. end;
  625. procedure fpc_chararray_uint(v : valuint;len : SizeInt;out a : array of char);compilerproc;
  626. var
  627. ss : shortstring;
  628. maxlen : SizeInt;
  629. begin
  630. int_str(v,ss);
  631. if length(ss)<len then
  632. ss:=space(len-length(ss))+ss;
  633. if length(ss)<high(a)+1 then
  634. maxlen:=length(ss)
  635. else
  636. maxlen:=high(a)+1;
  637. move(ss[1],pchar(@a)^,maxlen);
  638. end;
  639. {$ifndef CPU64}
  640. procedure fpc_chararray_qword(v : qword;len : SizeInt;out a : array of char);compilerproc;
  641. var
  642. ss : shortstring;
  643. maxlen : SizeInt;
  644. begin
  645. int_str(v,ss);
  646. if length(ss)<len then
  647. ss:=space(len-length(ss))+ss;
  648. if length(ss)<high(a)+1 then
  649. maxlen:=length(ss)
  650. else
  651. maxlen:=high(a)+1;
  652. move(ss[1],pchar(@a)^,maxlen);
  653. end;
  654. procedure fpc_chararray_int64(v : int64;len : SizeInt;out a : array of char);compilerproc;
  655. var
  656. ss : shortstring;
  657. maxlen : SizeInt;
  658. begin
  659. int_str(v,ss);
  660. if length(ss)<len then
  661. ss:=space(len-length(ss))+ss;
  662. if length(ss)<high(a)+1 then
  663. maxlen:=length(ss)
  664. else
  665. maxlen:=high(a)+1;
  666. move(ss[1],pchar(@a)^,maxlen);
  667. end;
  668. {$endif CPU64}
  669. {$ifndef FPUNONE}
  670. procedure fpc_chararray_Float(d : ValReal;len,fr,rt : SizeInt;out a : array of char);compilerproc;
  671. var
  672. ss : shortstring;
  673. maxlen : SizeInt;
  674. begin
  675. str_real(len,fr,d,treal_type(rt),ss);
  676. if length(ss)<high(a)+1 then
  677. maxlen:=length(ss)
  678. else
  679. maxlen:=high(a)+1;
  680. move(ss[1],pchar(@a)^,maxlen);
  681. end;
  682. {$endif}
  683. procedure fpc_chararray_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out a : array of char);compilerproc;
  684. var
  685. ss : shortstring;
  686. maxlen : SizeInt;
  687. begin
  688. fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss);
  689. if length(ss)<high(a)+1 then
  690. maxlen:=length(ss)
  691. else
  692. maxlen:=high(a)+1;
  693. move(ss[1],pchar(@a)^,maxlen);
  694. end;
  695. {$ifdef FPC_HAS_STR_CURRENCY}
  696. procedure fpc_chararray_Currency(c : Currency;len,fr : SizeInt;out a : array of char);compilerproc;
  697. var
  698. ss : shortstring;
  699. maxlen : SizeInt;
  700. begin
  701. str(c:len:fr,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. {$endif FPC_HAS_STR_CURRENCY}
  709. {*****************************************************************************
  710. Val() Functions
  711. *****************************************************************************}
  712. Function InitVal(const s:shortstring;out negativ:boolean;out base:byte):ValSInt;
  713. var
  714. Code : SizeInt;
  715. begin
  716. code:=1;
  717. negativ:=false;
  718. base:=10;
  719. if length(s)=0 then
  720. begin
  721. InitVal:=code;
  722. Exit;
  723. end;
  724. {Skip Spaces and Tab}
  725. while (code<=length(s)) and (s[code] in [' ',#9]) do
  726. inc(code);
  727. {Sign}
  728. case s[code] of
  729. '-' : begin
  730. negativ:=true;
  731. inc(code);
  732. end;
  733. '+' : inc(code);
  734. end;
  735. {Base}
  736. if code<=length(s) then
  737. begin
  738. case s[code] of
  739. '$',
  740. 'X',
  741. 'x' : begin
  742. base:=16;
  743. inc(code);
  744. end;
  745. '%' : begin
  746. base:=2;
  747. inc(code);
  748. end;
  749. '&' : begin
  750. Base:=8;
  751. inc(code);
  752. end;
  753. '0' : begin
  754. if (code < length(s)) and (s[code+1] in ['x', 'X']) then
  755. begin
  756. inc(code, 2);
  757. base := 16;
  758. end;
  759. end;
  760. end;
  761. end;
  762. { strip leading zeros }
  763. while ((code < length(s)) and (s[code] = '0')) do begin
  764. inc(code);
  765. end;
  766. InitVal:=code;
  767. end;
  768. Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
  769. var
  770. temp, prev, maxPrevValue, maxNewValue: ValUInt;
  771. base,u : byte;
  772. negative : boolean;
  773. begin
  774. fpc_Val_SInt_ShortStr := 0;
  775. Temp:=0;
  776. Code:=InitVal(s,negative,base);
  777. if Code>length(s) then
  778. exit;
  779. if (s[Code]=#0) then
  780. begin
  781. if (Code>1) and (s[Code-1]='0') then
  782. Code:=0;
  783. exit;
  784. end;
  785. maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
  786. if (base = 10) then
  787. maxNewValue := MaxSIntValue + ord(negative)
  788. else
  789. maxNewValue := MaxUIntValue;
  790. while Code<=Length(s) do
  791. begin
  792. case s[Code] of
  793. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  794. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  795. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  796. #0 : break;
  797. else
  798. u:=16;
  799. end;
  800. Prev := Temp;
  801. Temp := Temp*ValUInt(base);
  802. If (u >= base) or
  803. (ValUInt(maxNewValue-u) < Temp) or
  804. (prev > maxPrevValue) Then
  805. Begin
  806. fpc_Val_SInt_ShortStr := 0;
  807. Exit
  808. End;
  809. Temp:=Temp+u;
  810. inc(code);
  811. end;
  812. code := 0;
  813. fpc_Val_SInt_ShortStr := ValSInt(Temp);
  814. If Negative Then
  815. fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
  816. If Not(Negative) and (base <> 10) Then
  817. {sign extend the result to allow proper range checking}
  818. Case DestSize of
  819. 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr);
  820. 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr);
  821. {$ifdef cpu64}
  822. 4: fpc_Val_SInt_ShortStr := longint(fpc_Val_SInt_ShortStr);
  823. {$endif cpu64}
  824. End;
  825. end;
  826. { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because }
  827. { we have to pass the DestSize parameter on (JM) }
  828. Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR'];
  829. Function fpc_Val_UInt_Shortstr(Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc;
  830. var
  831. prev : ValUInt;
  832. base,u : byte;
  833. negative : boolean;
  834. begin
  835. fpc_Val_UInt_Shortstr:=0;
  836. Code:=InitVal(s,negative,base);
  837. If Negative or (Code>length(s)) Then
  838. Exit;
  839. if (s[Code]=#0) then
  840. begin
  841. if (Code>1) and (s[Code-1]='0') then
  842. Code:=0;
  843. exit;
  844. end;
  845. while Code<=Length(s) do
  846. begin
  847. case s[Code] of
  848. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  849. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  850. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  851. #0 : break;
  852. else
  853. u:=16;
  854. end;
  855. prev := fpc_Val_UInt_Shortstr;
  856. If (u>=base) or
  857. (ValUInt(MaxUIntValue-u) div ValUInt(Base)<prev) then
  858. begin
  859. fpc_Val_UInt_Shortstr:=0;
  860. exit;
  861. end;
  862. fpc_Val_UInt_Shortstr:=fpc_Val_UInt_Shortstr*ValUInt(base) + u;
  863. inc(code);
  864. end;
  865. code := 0;
  866. end;
  867. {$ifndef CPU64}
  868. Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; compilerproc;
  869. var u, temp, prev, maxprevvalue, maxnewvalue : qword;
  870. base : byte;
  871. negative : boolean;
  872. const maxint64=qword($7fffffffffffffff);
  873. maxqword=qword($ffffffffffffffff);
  874. begin
  875. fpc_val_int64_shortstr := 0;
  876. Temp:=0;
  877. Code:=InitVal(s,negative,base);
  878. if Code>length(s) then
  879. exit;
  880. if (s[Code]=#0) then
  881. begin
  882. if (Code>1) and (s[Code-1]='0') then
  883. Code:=0;
  884. exit;
  885. end;
  886. maxprevvalue := maxqword div base;
  887. if (base = 10) then
  888. maxnewvalue := maxint64 + ord(negative)
  889. else
  890. maxnewvalue := maxqword;
  891. while Code<=Length(s) do
  892. begin
  893. case s[Code] of
  894. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  895. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  896. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  897. #0 : break;
  898. else
  899. u:=16;
  900. end;
  901. Prev:=Temp;
  902. Temp:=Temp*qword(base);
  903. If (u >= base) or
  904. (qword(maxnewvalue-u) < temp) or
  905. (prev > maxprevvalue) Then
  906. Begin
  907. fpc_val_int64_shortstr := 0;
  908. Exit
  909. End;
  910. Temp:=Temp+u;
  911. inc(code);
  912. end;
  913. code:=0;
  914. fpc_val_int64_shortstr:=int64(Temp);
  915. If Negative Then
  916. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  917. end;
  918. Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc;
  919. var u, prev: QWord;
  920. base : byte;
  921. negative : boolean;
  922. const maxqword=qword($ffffffffffffffff);
  923. begin
  924. fpc_val_qword_shortstr:=0;
  925. Code:=InitVal(s,negative,base);
  926. If Negative or (Code>length(s)) Then
  927. Exit;
  928. if (s[Code]=#0) then
  929. begin
  930. if (Code>1) and (s[Code-1]='0') then
  931. Code:=0;
  932. exit;
  933. end;
  934. while Code<=Length(s) do
  935. begin
  936. case s[Code] of
  937. '0'..'9' : u:=Ord(S[Code])-Ord('0');
  938. 'A'..'F' : u:=Ord(S[Code])-(Ord('A')-10);
  939. 'a'..'f' : u:=Ord(S[Code])-(Ord('a')-10);
  940. #0 : break;
  941. else
  942. u:=16;
  943. end;
  944. prev := fpc_val_qword_shortstr;
  945. If (u>=base) or
  946. ((QWord(maxqword-u) div QWord(base))<prev) then
  947. Begin
  948. fpc_val_qword_shortstr := 0;
  949. Exit
  950. End;
  951. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  952. inc(code);
  953. end;
  954. code := 0;
  955. end;
  956. {$endif CPU64}
  957. {$ifndef FPUNONE}
  958. const
  959. {$ifdef FPC_HAS_TYPE_EXTENDED}
  960. valmaxexpnorm=4932;
  961. {$else}
  962. {$ifdef FPC_HAS_TYPE_DOUBLE}
  963. valmaxexpnorm=308;
  964. {$else}
  965. {$ifdef FPC_HAS_TYPE_SINGLE}
  966. valmaxexpnorm=38;
  967. {$else}
  968. {$error Unknown floating point precision }
  969. {$endif}
  970. {$endif}
  971. {$endif}
  972. {$endif}
  973. {$ifndef FPUNONE}
  974. Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
  975. var
  976. hd,
  977. esign,sign : valreal;
  978. exponent,
  979. decpoint,i : SizeInt;
  980. flags : byte;
  981. begin
  982. fpc_Val_Real_ShortStr:=0.0;
  983. code:=1;
  984. exponent:=0;
  985. decpoint:=0;
  986. esign:=1;
  987. flags:=0;
  988. sign:=1;
  989. while (code<=length(s)) and (s[code] in [' ',#9]) do
  990. inc(code);
  991. if code<=length(s) then
  992. case s[code] of
  993. '+' : inc(code);
  994. '-' : begin
  995. sign:=-1;
  996. inc(code);
  997. end;
  998. end;
  999. while (Code<=Length(s)) and (s[code] in ['0'..'9']) do
  1000. begin
  1001. { Read integer part }
  1002. flags:=flags or 1;
  1003. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  1004. inc(code);
  1005. end;
  1006. { Decimal ? }
  1007. if (length(s)>=code) and (s[code]='.') then
  1008. begin
  1009. inc(code);
  1010. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  1011. begin
  1012. { Read fractional part. }
  1013. flags:=flags or 2;
  1014. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*10+(ord(s[code])-ord('0'));
  1015. inc(decpoint);
  1016. inc(code);
  1017. end;
  1018. end;
  1019. { Again, read integer and fractional part}
  1020. if flags=0 then
  1021. begin
  1022. fpc_Val_Real_ShortStr:=0.0;
  1023. exit;
  1024. end;
  1025. { Exponent ? }
  1026. if (length(s)>=code) and (s[code] in ['e','E']) then
  1027. begin
  1028. inc(code);
  1029. if Length(s) >= code then
  1030. if s[code]='+' then
  1031. inc(code)
  1032. else
  1033. if s[code]='-' then
  1034. begin
  1035. esign:=-1;
  1036. inc(code);
  1037. end;
  1038. if (length(s)<code) or not(s[code] in ['0'..'9']) then
  1039. begin
  1040. fpc_Val_Real_ShortStr:=0.0;
  1041. exit;
  1042. end;
  1043. while (length(s)>=code) and (s[code] in ['0'..'9']) do
  1044. begin
  1045. exponent:=exponent*10;
  1046. exponent:=exponent+ord(s[code])-ord('0');
  1047. inc(code);
  1048. end;
  1049. end;
  1050. { adjust exponent based on decimal point }
  1051. if esign>0 then
  1052. begin
  1053. dec(exponent,decpoint);
  1054. if (exponent<0) then
  1055. begin
  1056. esign:=-1;
  1057. exponent:=-exponent;
  1058. end
  1059. end
  1060. else
  1061. inc(exponent,decpoint);
  1062. { evaluate sign }
  1063. { (before exponent, because the exponent may turn it into a denormal) }
  1064. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*sign;
  1065. { Calculate Exponent }
  1066. hd:=1.0;
  1067. { the magnitude range maximum (normal) is lower in absolute value than the }
  1068. { the magnitude range minimum (denormal). E.g. an extended value can go }
  1069. { up to 1E4932, but "down" to 1E-4951. So make sure that we don't try to }
  1070. { calculate 1E4951 as factor, since that would overflow and result in 0. }
  1071. if (exponent>valmaxexpnorm-2) then
  1072. begin
  1073. for i:=1 to valmaxexpnorm-2 do
  1074. hd:=hd*10.0;
  1075. if esign>0 then
  1076. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1077. else
  1078. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1079. dec(exponent,valmaxexpnorm-2);
  1080. hd:=1.0;
  1081. end;
  1082. for i:=1 to exponent do
  1083. hd:=hd*10.0;
  1084. if esign>0 then
  1085. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr*hd
  1086. else
  1087. fpc_Val_Real_ShortStr:=fpc_Val_Real_ShortStr/hd;
  1088. { Not all characters are read ? }
  1089. if length(s)>=code then
  1090. begin
  1091. fpc_Val_Real_ShortStr:=0.0;
  1092. exit;
  1093. end;
  1094. { success ! }
  1095. code:=0;
  1096. end;
  1097. {$endif}
  1098. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_SHORTSTR']; compilerproc;
  1099. type Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1100. o:longint;
  1101. s:Pstring;
  1102. end;
  1103. var l,h,m:cardinal;
  1104. sorted_array:^Tsorted_array;
  1105. spaces:byte;
  1106. t:shortstring;
  1107. label error;
  1108. begin
  1109. {Val for numbers accepts spaces at the start, so lets do the same
  1110. for enums. Skip spaces at the start of the string.}
  1111. spaces:=1;
  1112. while (spaces<=length(s)) and (s[spaces]=' ') do
  1113. inc(spaces);
  1114. t:=upcase(copy(s,spaces,255));
  1115. sorted_array:=pointer(Pcardinal(str2ordindex)+1);
  1116. {Use a binary search to get the string.}
  1117. l:=1;
  1118. h:=Pcardinal(str2ordindex)^;
  1119. repeat
  1120. m:=(l+h) div 2;
  1121. if t>upcase(sorted_array[m-1].s^) then
  1122. l:=m+1
  1123. else if t<upcase(sorted_array[m-1].s^) then
  1124. h:=m-1
  1125. else
  1126. break;
  1127. if l>h then
  1128. goto error;
  1129. until false;
  1130. code:=0;
  1131. fpc_val_enum_shortstr:=sorted_array[m-1].o;
  1132. exit;
  1133. error:
  1134. {Not found. Find first error position. Take care of the string length.}
  1135. code:=1;
  1136. while (code<=length(s)) and (s[code]=sorted_array[m].s^[code]) do
  1137. inc(code);
  1138. if code>length(s) then
  1139. code:=length(s)+1;
  1140. inc(code,spaces-1); {Add skipped spaces again.}
  1141. {The result of val in case of error is undefined, don't assign a function
  1142. result.}
  1143. end;
  1144. {Redeclare fpc_val_enum_shortstr for internal use in the system unit.}
  1145. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint;external name 'FPC_VAL_ENUM_SHORTSTR';
  1146. function fpc_Val_Currency_ShortStr(const s : shortstring; out Code : ValSInt): currency; [public, alias:'FPC_VAL_CURRENCY_SHORTSTR']; compilerproc;
  1147. const
  1148. MaxInt64 : Int64 = $7FFFFFFFFFFFFFFF;
  1149. Int64Edge : Int64 = ($7FFFFFFFFFFFFFFF - 10) div 10;
  1150. Int64Edge2 : Int64 = $7FFFFFFFFFFFFFFF div 10;
  1151. var
  1152. res : Int64;
  1153. i,j,power,sign,len : longint;
  1154. FracOverflow : boolean;
  1155. begin
  1156. fpc_Val_Currency_ShortStr:=0;
  1157. res:=0;
  1158. len:=Length(s);
  1159. Code:=1;
  1160. sign:=1;
  1161. power:=0;
  1162. while True do
  1163. if Code > len then
  1164. exit
  1165. else
  1166. if s[Code] in [' ', #9] then
  1167. Inc(Code)
  1168. else
  1169. break;
  1170. { Read sign }
  1171. case s[Code] of
  1172. '+' : Inc(Code);
  1173. '-' : begin
  1174. sign:=-1;
  1175. inc(code);
  1176. end;
  1177. end;
  1178. { Read digits }
  1179. FracOverflow:=False;
  1180. i:=0;
  1181. while Code <= len do
  1182. begin
  1183. case s[Code] of
  1184. '0'..'9':
  1185. begin
  1186. j:=Ord(s[code])-Ord('0');
  1187. { check overflow }
  1188. if (res <= Int64Edge) or (res <= (MaxInt64 - j) div 10) then
  1189. begin
  1190. res:=res*10 + j;
  1191. Inc(i);
  1192. end
  1193. else
  1194. if power = 0 then
  1195. { exit if integer part overflow }
  1196. exit
  1197. else
  1198. begin
  1199. if not FracOverflow and (j >= 5) and (res < MaxInt64) then
  1200. { round if first digit of fractional part overflow }
  1201. Inc(res);
  1202. FracOverflow:=True;
  1203. end;
  1204. end;
  1205. '.':
  1206. begin
  1207. if power = 0 then
  1208. begin
  1209. power:=1;
  1210. i:=0;
  1211. end
  1212. else
  1213. exit;
  1214. end;
  1215. else
  1216. break;
  1217. end;
  1218. Inc(Code);
  1219. end;
  1220. if (i = 0) and (power = 0) then
  1221. exit;
  1222. if power <> 0 then
  1223. power:=i;
  1224. power:=4 - power;
  1225. { Exponent? }
  1226. if Code <= len then
  1227. if s[Code] in ['E', 'e'] then
  1228. begin
  1229. Inc(Code);
  1230. if Code > len then
  1231. exit;
  1232. i:=1;
  1233. case s[Code] of
  1234. '+':
  1235. Inc(Code);
  1236. '-':
  1237. begin
  1238. i:=-1;
  1239. Inc(Code);
  1240. end;
  1241. end;
  1242. { read exponent }
  1243. j:=0;
  1244. while Code <= len do
  1245. if s[Code] in ['0'..'9'] then
  1246. begin
  1247. if j > 4951 then
  1248. exit;
  1249. j:=j*10 + (Ord(s[code])-Ord('0'));
  1250. Inc(Code);
  1251. end
  1252. else
  1253. exit;
  1254. power:=power + j*i;
  1255. end
  1256. else
  1257. exit;
  1258. if power > 0 then
  1259. begin
  1260. for i:=1 to power do
  1261. if res <= Int64Edge2 then
  1262. res:=res*10
  1263. else
  1264. exit;
  1265. end
  1266. else
  1267. for i:=1 to -power do
  1268. begin
  1269. if res <= MaxInt64 - 5 then
  1270. Inc(res, 5);
  1271. res:=res div 10;
  1272. end;
  1273. res:=res*sign;
  1274. fpc_Val_Currency_ShortStr:=PCurrency(@res)^;
  1275. Code:=0;
  1276. end;
  1277. Procedure SetString (Out S : Shortstring; Buf : PChar; Len : SizeInt);
  1278. begin
  1279. If Len > High(S) then
  1280. Len := High(S);
  1281. SetLength(S,Len);
  1282. If Buf<>Nil then
  1283. begin
  1284. Move (Buf[0],S[1],Len);
  1285. end;
  1286. end;
  1287. function ShortCompareText(const S1, S2: shortstring): SizeInt;
  1288. var
  1289. c1, c2: Byte;
  1290. i: Integer;
  1291. L1, L2, Count: SizeInt;
  1292. P1, P2: PChar;
  1293. begin
  1294. L1 := Length(S1);
  1295. L2 := Length(S2);
  1296. if L1 > L2 then
  1297. Count := L2
  1298. else
  1299. Count := L1;
  1300. i := 0;
  1301. P1 := @S1[1];
  1302. P2 := @S2[1];
  1303. while i < count do
  1304. begin
  1305. c1 := byte(p1^);
  1306. c2 := byte(p2^);
  1307. if c1 <> c2 then
  1308. begin
  1309. if c1 in [97..122] then
  1310. Dec(c1, 32);
  1311. if c2 in [97..122] then
  1312. Dec(c2, 32);
  1313. if c1 <> c2 then
  1314. Break;
  1315. end;
  1316. Inc(P1); Inc(P2); Inc(I);
  1317. end;
  1318. if i < count then
  1319. ShortCompareText := c1 - c2
  1320. else
  1321. ShortCompareText := L1 - L2;
  1322. end;