sstrings.inc 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************
  11. subroutines for string handling
  12. ****************************************************************************}
  13. {$ifndef FPC_HAS_SHORTSTR_SETLENGTH}
  14. {$define FPC_HAS_SHORTSTR_SETLENGTH}
  15. procedure fpc_Shortstr_SetLength(var s:shortstring;len:SizeInt);[Public,Alias : 'FPC_SHORTSTR_SETLENGTH']; compilerproc;
  16. begin
  17. if len<0 then
  18. len:=0;
  19. if len>high(s) then
  20. len:=high(s);
  21. s[0]:=chr(len);
  22. end;
  23. {$endif FPC_HAS_SHORTSTR_SETLENGTH}
  24. {$ifndef FPC_HAS_SHORTSTR_COPY}
  25. {$define FPC_HAS_SHORTSTR_COPY}
  26. function fpc_shortstr_copy(const s : shortstring;index : SizeInt;count : SizeInt): shortstring;compilerproc;
  27. begin
  28. if count<0 then
  29. count:=0;
  30. if index>1 then
  31. dec(index)
  32. else
  33. index:=0;
  34. if index>length(s) then
  35. count:=0
  36. else
  37. if count>length(s)-index then
  38. count:=length(s)-index;
  39. fpc_shortstr_Copy[0]:=chr(Count);
  40. fpc_shortstr_shortstr_intern_charmove(s,Index+1,fpc_shortstr_Copy,1,Count);
  41. end;
  42. {$endif FPC_HAS_SHORTSTR_COPY}
  43. {$ifndef FPC_HAS_SHORTSTR_DELETE}
  44. {$define FPC_HAS_SHORTSTR_DELETE}
  45. procedure fpc_shortstr_delete(var s : shortstring;index : SizeInt;count : SizeInt);
  46. begin
  47. if index<=0 then
  48. exit;
  49. if (Index<=Length(s)) and (Count>0) then
  50. begin
  51. if Count>length(s)-Index then
  52. Count:=length(s)-Index+1;
  53. s[0]:=Chr(length(s)-Count);
  54. if Index<=Length(s) then
  55. fpc_shortstr_shortstr_intern_charmove(s,Index+Count,s,Index,Length(s)-Index+1);
  56. end;
  57. end;
  58. {$endif FPC_HAS_SHORTSTR_DELETE}
  59. {$ifndef FPC_HAS_SHORTSTR_INSERT}
  60. {$define FPC_HAS_SHORTSTR_INSERT}
  61. procedure fpc_shortstr_insert(const source : shortstring;var s : shortstring;index : SizeInt);
  62. var
  63. cut,srclen,indexlen : SizeInt;
  64. begin
  65. if index<1 then
  66. index:=1;
  67. if index>length(s) then
  68. begin
  69. index:=length(s)+1;
  70. if index>high(s) then
  71. exit;
  72. end;
  73. indexlen:=Length(s)-Index+1;
  74. srclen:=length(Source);
  75. if sizeInt(length(source))+sizeint(length(s))>=sizeof(s) then
  76. begin
  77. cut:=sizeInt(length(source))+sizeint(length(s))-sizeof(s)+1;
  78. if cut>indexlen then
  79. begin
  80. dec(srclen,cut-indexlen);
  81. indexlen:=0;
  82. end
  83. else
  84. dec(indexlen,cut);
  85. end;
  86. fpc_shortstr_shortstr_intern_charmove(s,Index,s,Index+srclen,indexlen);
  87. fpc_shortstr_shortstr_intern_charmove(Source,1,s,Index,srclen);
  88. s[0]:=chr(index+srclen+indexlen-1);
  89. end;
  90. {$endif FPC_HAS_SHORTSTR_INSERT}
  91. {$ifndef FPC_HAS_SHORTSTR_INSERT_CHAR}
  92. {$define FPC_HAS_SHORTSTR_INSERT_CHAR}
  93. procedure fpc_shortstr_insert_char(source : AnsiChar;var s : shortstring;index : SizeInt);
  94. var
  95. indexlen : SizeInt;
  96. begin
  97. if index<1 then
  98. index:=1;
  99. if index>length(s) then
  100. begin
  101. index:=length(s)+1;
  102. if index>high(s) then
  103. exit;
  104. end;
  105. indexlen:=Length(s)-Index+1;
  106. if (sizeint(length(s))+1=sizeof(s)) and (indexlen>0) then
  107. dec(indexlen);
  108. fpc_shortstr_shortstr_intern_charmove(s,Index,s,Index+1,indexlen);
  109. s[Index]:=Source;
  110. s[0]:=chr(index+indexlen);
  111. end;
  112. {$endif FPC_HAS_SHORTSTR_INSERT_CHAR}
  113. {$ifndef FPC_HAS_SHORTSTR_POS_SHORTSTR}
  114. {$define FPC_HAS_SHORTSTR_POS_SHORTSTR}
  115. function pos(const substr : shortstring;const s : shortstring; Offset : Sizeint = 1):SizeInt;
  116. var
  117. i,MaxLen,d : SizeInt;
  118. begin
  119. Pos:=0;
  120. if (Length(SubStr)>0) and (Offset>0) and (Offset<=Length(S)) then
  121. begin
  122. MaxLen:=sizeint(Length(s))-Length(SubStr)+1;
  123. i:=Offset;
  124. while (i<=MaxLen) do
  125. begin
  126. d:=IndexByte(s[i],MaxLen-i+1,byte(substr[1]));
  127. if d<0 then
  128. exit;
  129. if (CompareByte(Substr[1],s[i+d],Length(SubStr))=0) then
  130. exit(i+d);
  131. i:=i+d+1;
  132. end;
  133. end;
  134. end;
  135. {$endif FPC_HAS_SHORTSTR_POS_SHORTSTR}
  136. {$ifndef FPC_HAS_SHORTSTR_POS_CHAR}
  137. {$define FPC_HAS_SHORTSTR_POS_CHAR}
  138. {Faster when looking for a single AnsiChar...}
  139. function pos(c:ansichar;const s:shortstring; Offset : Sizeint = 1 ):SizeInt;
  140. var
  141. idx : SizeInt;
  142. begin
  143. Pos:=0;
  144. if (Offset<1) or (Offset>Length(S)) then
  145. exit;
  146. idx:=IndexByte(s[Offset],length(s)-Offset+1,byte(c));
  147. if idx>=0 then
  148. Pos:=Offset+idx;
  149. end;
  150. {$endif FPC_HAS_SHORTSTR_POS_CHAR}
  151. function fpc_char_copy(c:ansichar;index : SizeInt;count : SizeInt): shortstring;compilerproc;
  152. begin
  153. if (index=1) and (Count>0) then
  154. fpc_char_Copy:=c
  155. else
  156. fpc_char_Copy:='';
  157. end;
  158. function pos(const substr : shortstring;c:Ansichar; Offset : Sizeint = 1): SizeInt;
  159. begin
  160. if (length(substr)=1) and (substr[1]=c) and (Offset=1) then
  161. Pos:=1
  162. else
  163. Pos:=0;
  164. end;
  165. {$if not defined(FPC_UPCASE_CHAR) or not defined(FPC_LOWERCASE_CHAR)}
  166. {$ifdef IBM_CHAR_SET}
  167. const
  168. UpCaseTbl : shortstring[7]=#154#142#153#144#128#143#165;
  169. LoCaseTbl : shortstring[7]=#129#132#148#130#135#134#164;
  170. {$endif}
  171. {$endif}
  172. {$ifndef FPC_UPCASE_CHAR}
  173. {$define FPC_UPCASE_CHAR}
  174. function upcase(c : Ansichar) : Ansichar;
  175. {$IFDEF IBM_CHAR_SET}
  176. var
  177. i : ObjpasInt;
  178. {$ENDIF}
  179. begin
  180. if (c in ['a'..'z']) then
  181. upcase:=AnsiChar(byte(c)-32)
  182. else
  183. {$IFDEF IBM_CHAR_SET}
  184. begin
  185. i:=Pos(c,LoCaseTbl);
  186. if i>0 then
  187. upcase:=UpCaseTbl[i]
  188. else
  189. upcase:=c;
  190. end;
  191. {$ELSE}
  192. upcase:=c;
  193. {$ENDIF}
  194. end;
  195. {$endif FPC_UPCASE_CHAR}
  196. {$ifndef FPC_UPCASE_SHORTSTR}
  197. {$define FPC_UPCASE_SHORTSTR}
  198. function upcase(const s : shortstring) : shortstring;
  199. var
  200. i : ObjpasInt;
  201. begin
  202. upcase[0]:=s[0];
  203. for i := 1 to length (s) do
  204. upcase[i] := upcase (s[i]);
  205. end;
  206. {$endif FPC_UPCASE_SHORTSTR}
  207. {$ifndef FPC_LOWERCASE_CHAR}
  208. {$define FPC_LOWERCASE_CHAR}
  209. function lowercase(c : AnsiChar) : AnsiChar;overload;
  210. {$IFDEF IBM_CHAR_SET}
  211. var
  212. i : ObjpasInt;
  213. {$ENDIF}
  214. begin
  215. if (c in ['A'..'Z']) then
  216. lowercase:=AnsiChar(byte(c)+32)
  217. else
  218. {$IFDEF IBM_CHAR_SET}
  219. begin
  220. i:=Pos(c,UpCaseTbl);
  221. if i>0 then
  222. lowercase:=LoCaseTbl[i]
  223. else
  224. lowercase:=c;
  225. end;
  226. {$ELSE}
  227. lowercase:=c;
  228. {$ENDIF}
  229. end;
  230. {$endif FPC_LOWERCASE_CHAR}
  231. {$ifndef FPC_LOWERCASE_SHORTSTR}
  232. {$define FPC_LOWERCASE_SHORTSTR}
  233. function lowercase(const s : shortstring) : shortstring; overload;
  234. var
  235. i : ObjpasInt;
  236. begin
  237. lowercase [0]:=s[0];
  238. for i:=1 to length(s) do
  239. lowercase[i]:=lowercase (s[i]);
  240. end;
  241. {$endif FPC_LOWERCASE_SHORTSTR}
  242. const
  243. HexTbl : array[0..15] of AnsiChar='0123456789ABCDEF';
  244. function hexstr(val : longint;cnt : byte) : shortstring;
  245. var
  246. i : ObjpasInt;
  247. begin
  248. hexstr[0]:=AnsiChar(cnt);
  249. for i:=cnt downto 1 do
  250. begin
  251. hexstr[i]:=hextbl[val and $f];
  252. val:=val shr 4;
  253. end;
  254. end;
  255. function octstr(val : longint;cnt : byte) : shortstring;
  256. var
  257. i : ObjpasInt;
  258. begin
  259. octstr[0]:=AnsiChar(cnt);
  260. for i:=cnt downto 1 do
  261. begin
  262. octstr[i]:=hextbl[val and 7];
  263. val:=val shr 3;
  264. end;
  265. end;
  266. function binstr(val : longint;cnt : byte) : shortstring;
  267. var
  268. i : ObjpasInt;
  269. begin
  270. binstr[0]:=AnsiChar(cnt);
  271. for i:=cnt downto 1 do
  272. begin
  273. binstr[i]:=AnsiChar(48+val and 1);
  274. val:=val shr 1;
  275. end;
  276. end;
  277. function hexstr(val : int64;cnt : byte) : shortstring;
  278. var
  279. i : ObjpasInt;
  280. begin
  281. hexstr[0]:=AnsiChar(cnt);
  282. for i:=cnt downto 1 do
  283. begin
  284. hexstr[i]:=hextbl[val and $f];
  285. val:=val shr 4;
  286. end;
  287. end;
  288. function octstr(val : int64;cnt : byte) : shortstring;
  289. var
  290. i : ObjpasInt;
  291. begin
  292. octstr[0]:=AnsiChar(cnt);
  293. for i:=cnt downto 1 do
  294. begin
  295. octstr[i]:=hextbl[val and 7];
  296. val:=val shr 3;
  297. end;
  298. end;
  299. function binstr(val : int64;cnt : byte) : shortstring;
  300. var
  301. i : ObjpasInt;
  302. begin
  303. binstr[0]:=AnsiChar(cnt);
  304. for i:=cnt downto 1 do
  305. begin
  306. binstr[i]:=AnsiChar(48+val and 1);
  307. val:=val shr 1;
  308. end;
  309. end;
  310. {$ifndef FPC_HAS_QWORD_HEX_SHORTSTR}
  311. {$define FPC_HAS_QWORD_HEX_SHORTSTR}
  312. Function hexStr(Val:qword;cnt:byte):shortstring;
  313. begin
  314. hexStr:=hexStr(int64(Val),cnt);
  315. end;
  316. {$endif FPC_HAS_QWORD_HEX_SHORTSTR}
  317. {$ifndef FPC_HAS_QWORD_OCT_SHORTSTR}
  318. {$define FPC_HAS_QWORD_OCT_SHORTSTR}
  319. Function OctStr(Val:qword;cnt:byte):shortstring;
  320. begin
  321. OctStr:=OctStr(int64(Val),cnt);
  322. end;
  323. {$endif FPC_HAS_QWORD_OCT_SHORTSTR}
  324. {$ifndef FPC_HAS_QWORD_BIN_SHORTSTR}
  325. {$define FPC_HAS_QWORD_BIN_SHORTSTR}
  326. Function binStr(Val:qword;cnt:byte):shortstring;
  327. begin
  328. binStr:=binStr(int64(Val),cnt);
  329. end;
  330. {$endif FPC_HAS_QWORD_BIN_SHORTSTR}
  331. {$ifndef FPC_HAS_HEXSTR_POINTER_SHORTSTR}
  332. {$define FPC_HAS_HEXSTR_POINTER_SHORTSTR}
  333. function hexstr(val : pointer) : shortstring;
  334. var
  335. i : ObjpasInt;
  336. v : ptruint;
  337. begin
  338. v:=ptruint(val);
  339. hexstr[0]:=chr(sizeof(pointer)*2);
  340. for i:=sizeof(pointer)*2 downto 1 do
  341. begin
  342. hexstr[i]:=hextbl[v and $f];
  343. v:=v shr 4;
  344. end;
  345. end;
  346. {$endif FPC_HAS_HEXSTR_POINTER_SHORTSTR}
  347. {$ifndef FPC_HAS_SPACE_SHORTSTR}
  348. {$define FPC_HAS_SPACE_SHORTSTR}
  349. function space (b : byte): shortstring;
  350. begin
  351. space[0] := chr(b);
  352. FillChar (Space[1],b,' ');
  353. end;
  354. {$endif FPC_HAS_SPACE_SHORTSTR}
  355. {*****************************************************************************
  356. Str() Helpers
  357. *****************************************************************************}
  358. procedure fpc_shortstr_SInt(v : valSInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SINT']; compilerproc;
  359. begin
  360. int_str(v,s);
  361. if length(s)<len then
  362. s:=space(len-length(s))+s;
  363. end;
  364. procedure fpc_shortstr_UInt(v : valUInt;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_UINT']; compilerproc;
  365. begin
  366. int_str_unsigned(v,s);
  367. if length(s)<len then
  368. s:=space(len-length(s))+s;
  369. end;
  370. {$ifndef CPU64}
  371. procedure fpc_shortstr_qword(v : qword;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_QWORD']; compilerproc;
  372. begin
  373. int_str_unsigned(v,s);
  374. if length(s)<len then
  375. s:=space(len-length(s))+s;
  376. end;
  377. procedure fpc_shortstr_int64(v : int64;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_INT64']; compilerproc;
  378. begin
  379. int_str(v,s);
  380. if length(s)<len then
  381. s:=space(len-length(s))+s;
  382. end;
  383. {$endif CPU64}
  384. {$if defined(CPU16) or defined(CPU8)}
  385. procedure fpc_shortstr_longword(v : longword;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_LONGWORD']; compilerproc;
  386. begin
  387. int_str_unsigned(v,s);
  388. if length(s)<len then
  389. s:=space(len-length(s))+s;
  390. end;
  391. procedure fpc_shortstr_longint(v : longint;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_LONGINT']; compilerproc;
  392. begin
  393. int_str(v,s);
  394. if length(s)<len then
  395. s:=space(len-length(s))+s;
  396. end;
  397. procedure fpc_shortstr_word(v : word;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_WORD']; compilerproc;
  398. begin
  399. int_str_unsigned(v,s);
  400. if length(s)<len then
  401. s:=space(len-length(s))+s;
  402. end;
  403. procedure fpc_shortstr_smallint(v : smallint;len : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_SMALLINT']; compilerproc;
  404. begin
  405. int_str(v,s);
  406. if length(s)<len then
  407. s:=space(len-length(s))+s;
  408. end;
  409. {$endif CPU16 or CPU8}
  410. { fpc_shortstr_sInt must appear before this file is included, because }
  411. { it's used inside real2str.inc and otherwise the searching via the }
  412. { compilerproc name will fail (JM) }
  413. {$ifndef FPUNONE}
  414. {$I flt_conv.inc}
  415. {$endif}
  416. {$ifndef FPUNONE}
  417. procedure fpc_shortstr_float(d : ValReal;len,fr,rt : SizeInt;out s : shortstring);[public,alias:'FPC_SHORTSTR_FLOAT']; compilerproc;
  418. begin
  419. str_real(len,fr,d,treal_type(rt),s);
  420. end;
  421. {$endif}
  422. {$ifndef FPC_STR_ENUM_INTERN}
  423. function fpc_shortstr_enum_intern(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring): longint;
  424. {$ifndef FPC_HAS_FEATURE_RTTI}
  425. begin
  426. int_str(ordinal,s);
  427. if length(s)<len then
  428. s:=space(len-length(s))+s;
  429. end;
  430. {$else with RTTI feature}
  431. { The following contains the TTypeInfo/TTypeData records from typinfo.pp
  432. specialized for the tkEnumeration case (and stripped of unused things). }
  433. type
  434. PPstring=^Pstring;
  435. Penum_typeinfo=^Tenum_typeinfo;
  436. Tenum_typeinfo={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  437. kind:TTypeKind; { always tkEnumeration }
  438. num_chars:byte;
  439. chars:array[0..0] of AnsiChar; { variable length with size of num_chars }
  440. end;
  441. {$push}
  442. {$packrecords c}
  443. Penum_typedata=^Tenum_typedata;
  444. Tenum_typedata={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  445. {$if declared(TRttiDataCommon)}
  446. Common: TRttiDataCommon;
  447. {$endif}
  448. case TTypeKind of
  449. tkInt64,tkQWord,tkInteger,tkChar,tkEnumeration,tkBool,tkWChar: (
  450. OrdType : Byte;
  451. case TTypeKind of
  452. tkInteger,tkChar,tkEnumeration,tkBool,tkWChar: (
  453. MinValue,MaxValue : Longint;
  454. case TTypeKind of
  455. tkEnumeration: (
  456. BaseTypeRef : pointer
  457. );
  458. {tkBool with OrdType=otSQWord }
  459. tkInt64:
  460. (MinInt64Value, MaxInt64Value: Int64);
  461. {tkBool with OrdType=otUQWord }
  462. tkQWord:
  463. (MinQWordValue, MaxQWordValue: QWord);
  464. );
  465. );
  466. { more data here, but not needed }
  467. end;
  468. { Pascal data types for the ordinal enum value to string table. It consists of a header
  469. that indicates what type of data the table stores, either a direct lookup table (when
  470. o = lookup) or a set of ordered (ordinal value, string) tuples (when o = search). }
  471. { A single entry in the set of ordered tuples }
  472. Psearch_data=^Tsearch_data;
  473. Tsearch_data={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  474. value:longint;
  475. name:Pstring;
  476. end;
  477. Penum_ord_to_string=^Tenum_ord_to_string;
  478. Tenum_ord_to_string={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  479. o:(lookup,search);
  480. case integer of
  481. 0: (lookup_data:array[0..0] of Pstring);
  482. 1: (num_entries:longint;
  483. search_data:array[0..0] of Tsearch_data);
  484. end;
  485. {$pop}
  486. var
  487. enum_o2s : Penum_ord_to_string;
  488. header:Penum_typeinfo;
  489. body:Penum_typedata;
  490. res:Pshortstring;
  491. sorted_data:Psearch_data;
  492. spaces,i,m,h,l:longint;
  493. begin
  494. { set default return value }
  495. fpc_shortstr_enum_intern:=107;
  496. enum_o2s:=Penum_ord_to_string(ord2strindex);
  497. { depending on the type of table in ord2strindex retrieve the data }
  498. if (enum_o2s^.o=lookup) then
  499. begin
  500. { direct lookup table }
  501. header:=Penum_typeinfo(typinfo);
  502. { calculate address of enum rtti body: add the actual size of the
  503. enum_rtti_header, and then align. Use an alignment of 1 (which
  504. does nothing) in case FPC_REQUIRES_PROPER_ALIGNMENT is not set
  505. to avoid the need for an if in this situation }
  506. body:=Penum_typedata(aligntoqword(pointer(header) + 2 * sizeof(byte) { kind, num_chars } + header^.num_chars));
  507. with body^ do
  508. begin
  509. { Bounds check for the ordinal value for this enum }
  510. if (ordinal<minvalue) or (ordinal>maxvalue) then
  511. exit;
  512. { make the ordinal index for lookup zero-based }
  513. dec(ordinal,minvalue);
  514. end;
  515. { temporarily disable range checking because of the access to the array[0..0]
  516. member of Tenum_ord_to_string_lookup }
  517. {$push}{$R-}
  518. res:=enum_o2s^.lookup_data[ordinal];
  519. {$pop}
  520. if (not assigned(res)) then
  521. exit;
  522. s:=res^;
  523. end
  524. else
  525. begin
  526. { The compiler did generate a sorted array of (ordvalue,Pstring) tuples }
  527. sorted_data:=@enum_o2s^.search_data;
  528. { Use a binary search to get the string }
  529. l:=0;
  530. { temporarily disable range checking because of the access to the array[0..0]
  531. member of Tenum_ord_to_string_search }
  532. {$push}{$R-}
  533. h:=enum_o2s^.num_entries-1;
  534. repeat
  535. m:=(l+h) div 2;
  536. if ordinal>sorted_data[m].value then
  537. l:=m+1
  538. else if ordinal<sorted_data[m].value then
  539. h:=m-1
  540. else
  541. break;
  542. if l>h then
  543. exit; { Ordinal value not found? Exit }
  544. until false;
  545. {$pop}
  546. s:=sorted_data[m].name^;
  547. end;
  548. { Pad the string with spaces if necessary }
  549. if (len>length(s)) then
  550. begin
  551. spaces:=len-length(s);
  552. for i:=1 to spaces do
  553. s[length(s)+i]:=' ';
  554. inc(byte(s[0]),spaces);
  555. end;
  556. fpc_shortstr_enum_intern:=0;
  557. end;
  558. {$endif with RTTI feature}
  559. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);[public,alias:'FPC_SHORTSTR_ENUM'];compilerproc;
  560. var
  561. res: longint;
  562. begin
  563. res:=fpc_shortstr_enum_intern(ordinal,len,typinfo,ord2strindex,s);
  564. if (res<>0) then
  565. runerror(107);
  566. end;
  567. { also define alias for internal use in the system unit }
  568. procedure fpc_shortstr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:shortstring);external name 'FPC_SHORTSTR_ENUM';
  569. {$endif FPC_SHORTSTR_ENUM_INTERN}
  570. procedure fpc_shortstr_bool(b : boolean;len:sizeint;out s:shortstring);[public,alias:'FPC_SHORTSTR_BOOL'];compilerproc;
  571. begin
  572. if b then
  573. s:='TRUE'
  574. else
  575. s:='FALSE';
  576. if length(s)<len then
  577. s:=space(len-length(s))+s;
  578. end;
  579. { also define alias for internal use in the system unit }
  580. procedure fpc_shortstr_bool(b : boolean;len:sizeint;out s:shortstring);external {$ifndef cpujvm}name 'FPC_SHORTSTR_BOOL'{$endif};
  581. procedure fpc_shortstr_currency({$ifdef cpujvm}constref{$endif} c : currency; len,f : SizeInt; out s : shortstring);[public,alias:'FPC_SHORTSTR_CURRENCY']; compilerproc;
  582. const
  583. MinLen = 8; { Minimal string length in scientific format }
  584. var
  585. buf : array[1..19] of AnsiChar;
  586. i,j,k,reslen,tlen,sign,r,point : ObjpasInt;
  587. ic : qword;
  588. begin
  589. fillchar(buf,length(buf),'0');
  590. { default value for length is -32767 }
  591. if len=-32767 then
  592. len:=25;
  593. if PInt64(@c)^ >= 0 then
  594. begin
  595. ic:=QWord(PInt64(@c)^);
  596. sign:=0;
  597. end
  598. else
  599. begin
  600. sign:=1;
  601. ic:=QWord(-PInt64(@c)^);
  602. end;
  603. { converting to integer string }
  604. tlen:=0;
  605. repeat
  606. Inc(tlen);
  607. buf[tlen]:=Chr(ic mod 10 + $30);
  608. ic:=ic div 10;
  609. until ic = 0;
  610. { calculating:
  611. reslen - length of result string,
  612. r - rounding or appending zeroes,
  613. point - place of decimal point }
  614. reslen:=tlen;
  615. if f <> 0 then
  616. Inc(reslen); { adding decimal point length }
  617. if f < 0 then
  618. begin
  619. { scientific format }
  620. Inc(reslen,5); { adding length of sign and exponent }
  621. if len < MinLen then
  622. len:=MinLen;
  623. r:=reslen-len;
  624. if reslen < len then
  625. reslen:=len;
  626. if r > 0 then
  627. begin
  628. reslen:=len;
  629. point:=tlen - r;
  630. end
  631. else
  632. point:=tlen;
  633. end
  634. else
  635. begin
  636. { fixed format }
  637. Inc(reslen, sign);
  638. { prepending fractional part with zeroes }
  639. while tlen < 5 do
  640. begin
  641. Inc(reslen);
  642. Inc(tlen);
  643. buf[tlen]:='0';
  644. end;
  645. { Currency have 4 digits in fractional part }
  646. r:=4 - f;
  647. point:=f;
  648. if point <> 0 then
  649. begin
  650. if point > 4 then
  651. point:=4;
  652. Inc(point);
  653. end;
  654. Dec(reslen,r);
  655. end;
  656. { rounding string if r > 0 }
  657. if r > 0 then
  658. begin
  659. k := 0;
  660. i := r+2;
  661. if i > tlen then
  662. i := tlen+1;
  663. if buf[i-2] >= '5' then
  664. begin
  665. if buf[i-1] < '9' then
  666. buf[i-1] := chr(ord(buf[i-1])+1)
  667. else
  668. begin
  669. buf[i-1] := '0';
  670. k := 1;
  671. end;
  672. end;
  673. If (k=1) and (buf[i-1]='0') then
  674. begin
  675. { 1.9996 rounded to two decimal digits after the decimal separator must result in
  676. 2.00, i.e. the rounding is propagated
  677. }
  678. while buf[i]='9' do
  679. begin
  680. buf[i]:='0';
  681. inc(i);
  682. end;
  683. buf[i]:=chr(Ord(buf[i])+1);
  684. { did we add another digit? This happens when rounding
  685. e.g. 99.9996 to two decimal digits after the decimal separator which should result in
  686. 100.00
  687. }
  688. if i>tlen then
  689. begin
  690. inc(reslen);
  691. inc(tlen);
  692. end;
  693. end;
  694. end;
  695. { preparing result string }
  696. if reslen<len then
  697. reslen:=len;
  698. if reslen>High(s) then
  699. begin
  700. if r < 0 then
  701. Inc(r, reslen - High(s));
  702. reslen:=High(s);
  703. end;
  704. SetLength(s,reslen);
  705. j:=reslen;
  706. if f<0 then
  707. begin
  708. { writing power of 10 part }
  709. if PInt64(@c)^ = 0 then
  710. k:=0
  711. else
  712. k:=tlen-5;
  713. if k >= 0 then
  714. s[j-2]:='+'
  715. else
  716. begin
  717. s[j-2]:='-';
  718. k:=-k;
  719. end;
  720. s[j]:=Chr(k mod 10 + $30);
  721. Dec(j);
  722. s[j]:=Chr(k div 10 + $30);
  723. Dec(j,2);
  724. s[j]:='E';
  725. Dec(j);
  726. end;
  727. { writing extra zeroes if r < 0 }
  728. while r < 0 do
  729. begin
  730. s[j]:='0';
  731. Dec(j);
  732. Inc(r);
  733. end;
  734. { writing digits and decimal point }
  735. for i:=r + 1 to tlen do
  736. begin
  737. Dec(point);
  738. if point = 0 then
  739. begin
  740. s[j]:='.';
  741. Dec(j);
  742. end;
  743. s[j]:=buf[i];
  744. Dec(j);
  745. end;
  746. { writing sign }
  747. if sign = 1 then
  748. begin
  749. s[j]:='-';
  750. Dec(j);
  751. end;
  752. { writing spaces }
  753. while j > 0 do
  754. begin
  755. s[j]:=' ';
  756. Dec(j);
  757. end;
  758. end;
  759. {
  760. Array Of AnsiChar Str() helpers
  761. }
  762. procedure fpc_chararray_sint(v : valsint;len : SizeInt;out a:array of AnsiChar);compilerproc;
  763. var
  764. ss : shortstring;
  765. maxlen : SizeInt;
  766. begin
  767. int_str(v,ss);
  768. if length(ss)<len then
  769. ss:=space(len-length(ss))+ss;
  770. if length(ss)<high(a)+1 then
  771. maxlen:=length(ss)
  772. else
  773. maxlen:=high(a)+1;
  774. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  775. end;
  776. procedure fpc_chararray_uint(v : valuint;len : SizeInt;out a : array of AnsiChar);compilerproc;
  777. var
  778. ss : shortstring;
  779. maxlen : SizeInt;
  780. begin
  781. int_str_unsigned(v,ss);
  782. if length(ss)<len then
  783. ss:=space(len-length(ss))+ss;
  784. if length(ss)<high(a)+1 then
  785. maxlen:=length(ss)
  786. else
  787. maxlen:=high(a)+1;
  788. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  789. end;
  790. {$ifndef CPU64}
  791. procedure fpc_chararray_qword(v : qword;len : SizeInt;out a : array of AnsiChar);compilerproc;
  792. {$ifdef EXCLUDE_COMPLEX_PROCS}
  793. begin
  794. runerror(219);
  795. end;
  796. {$else EXCLUDE_COMPLEX_PROCS}
  797. var
  798. ss : shortstring;
  799. maxlen : SizeInt;
  800. begin
  801. int_str_unsigned(v,ss);
  802. if length(ss)<len then
  803. ss:=space(len-length(ss))+ss;
  804. if length(ss)<high(a)+1 then
  805. maxlen:=length(ss)
  806. else
  807. maxlen:=high(a)+1;
  808. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  809. end;
  810. {$endif EXCLUDE_COMPLEX_PROCS}
  811. procedure fpc_chararray_int64(v : int64;len : SizeInt;out a : array of AnsiChar);compilerproc;
  812. {$ifdef EXCLUDE_COMPLEX_PROCS}
  813. begin
  814. runerror(219);
  815. end;
  816. {$else EXCLUDE_COMPLEX_PROCS}
  817. var
  818. ss : shortstring;
  819. maxlen : SizeInt;
  820. begin
  821. int_str(v,ss);
  822. if length(ss)<len then
  823. ss:=space(len-length(ss))+ss;
  824. if length(ss)<high(a)+1 then
  825. maxlen:=length(ss)
  826. else
  827. maxlen:=high(a)+1;
  828. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  829. end;
  830. {$endif EXCLUDE_COMPLEX_PROCS}
  831. {$endif CPU64}
  832. {$if defined(CPU16) or defined(CPU8)}
  833. procedure fpc_chararray_longword(v : longword;len : SizeInt;out a : array of AnsiChar);compilerproc;
  834. var
  835. ss : shortstring;
  836. maxlen : SizeInt;
  837. begin
  838. int_str_unsigned(v,ss);
  839. if length(ss)<len then
  840. ss:=space(len-length(ss))+ss;
  841. if length(ss)<high(a)+1 then
  842. maxlen:=length(ss)
  843. else
  844. maxlen:=high(a)+1;
  845. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  846. end;
  847. procedure fpc_chararray_longint(v : longint;len : SizeInt;out a : array of AnsiChar);compilerproc;
  848. var
  849. ss : shortstring;
  850. maxlen : SizeInt;
  851. begin
  852. int_str(v,ss);
  853. if length(ss)<len then
  854. ss:=space(len-length(ss))+ss;
  855. if length(ss)<high(a)+1 then
  856. maxlen:=length(ss)
  857. else
  858. maxlen:=high(a)+1;
  859. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  860. end;
  861. procedure fpc_chararray_word(v : word;len : SizeInt;out a : array of AnsiChar);compilerproc;
  862. var
  863. ss : shortstring;
  864. maxlen : SizeInt;
  865. begin
  866. int_str_unsigned(v,ss);
  867. if length(ss)<len then
  868. ss:=space(len-length(ss))+ss;
  869. if length(ss)<high(a)+1 then
  870. maxlen:=length(ss)
  871. else
  872. maxlen:=high(a)+1;
  873. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  874. end;
  875. procedure fpc_chararray_smallint(v : smallint;len : SizeInt;out a : array of AnsiChar);compilerproc;
  876. var
  877. ss : shortstring;
  878. maxlen : SizeInt;
  879. begin
  880. int_str(v,ss);
  881. if length(ss)<len then
  882. ss:=space(len-length(ss))+ss;
  883. if length(ss)<high(a)+1 then
  884. maxlen:=length(ss)
  885. else
  886. maxlen:=high(a)+1;
  887. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  888. end;
  889. {$endif CPU16 or CPU8}
  890. {$ifndef FPUNONE}
  891. procedure fpc_chararray_Float(d : ValReal;len,fr,rt : SizeInt;out a : array of AnsiChar);compilerproc;
  892. var
  893. ss : shortstring;
  894. maxlen : SizeInt;
  895. begin
  896. str_real(len,fr,d,treal_type(rt),ss);
  897. if length(ss)<high(a)+1 then
  898. maxlen:=length(ss)
  899. else
  900. maxlen:=high(a)+1;
  901. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  902. end;
  903. {$endif}
  904. {$ifndef FPC_STR_ENUM_INTERN}
  905. { currently, the avr code generator fails on this procedure, so we disable it,
  906. this is not a good solution but fixing compilation of this procedure for
  907. avr is hard, requires significant changes to the register allocator to take
  908. care of different register classes }
  909. procedure fpc_chararray_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out a : array of AnsiChar);compilerproc;
  910. var
  911. ss : shortstring;
  912. maxlen : SizeInt;
  913. begin
  914. {$ifdef EXCLUDE_COMPLEX_PROCS}
  915. runerror(219);
  916. {$else EXCLUDE_COMPLEX_PROCS}
  917. fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss);
  918. if length(ss)<high(a)+1 then
  919. maxlen:=length(ss)
  920. else
  921. maxlen:=high(a)+1;
  922. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  923. {$endif EXCLUDE_COMPLEX_PROCS}
  924. end;
  925. {$endif not FPC_STR_ENUM_INTERN}
  926. procedure fpc_chararray_bool(b : boolean;len:sizeint;out a : array of AnsiChar);compilerproc;
  927. var
  928. ss : shortstring;
  929. maxlen : SizeInt;
  930. begin
  931. fpc_shortstr_bool(b,len,ss);
  932. if length(ss)<high(a)+1 then
  933. maxlen:=length(ss)
  934. else
  935. maxlen:=high(a)+1;
  936. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  937. end;
  938. {$ifndef FPC_HAS_CHARARRAY_CURRENCY}
  939. {$define FPC_HAS_CHARARRAY_CURRENCY}
  940. procedure fpc_chararray_Currency(c : Currency;len,fr : SizeInt;out a : array of AnsiChar);compilerproc;
  941. {$ifdef EXCLUDE_COMPLEX_PROCS}
  942. begin
  943. runerror(217);
  944. end;
  945. {$else EXCLUDE_COMPLEX_PROCS}
  946. var
  947. ss : shortstring;
  948. maxlen : SizeInt;
  949. begin
  950. str(c:len:fr,ss);
  951. if length(ss)<high(a)+1 then
  952. maxlen:=length(ss)
  953. else
  954. maxlen:=high(a)+1;
  955. fpc_shortstr_chararray_intern_charmove(ss,a,maxlen);
  956. end;
  957. {$endif EXCLUDE_COMPLEX_PROCS}
  958. {$endif FPC_HAS_CHARARRAY_CURRENCY}
  959. {*****************************************************************************
  960. Val() Functions
  961. *****************************************************************************}
  962. Function InitVal(const s:shortstring;out negativ:boolean;out base:byte):ValSInt;
  963. var
  964. Code : SizeInt;
  965. begin
  966. code:=1;
  967. negativ:=false;
  968. base:=10;
  969. if length(s)=0 then
  970. begin
  971. InitVal:=code;
  972. Exit;
  973. end;
  974. {Skip Spaces and Tab}
  975. while (code<=length(s)) and (s[code] in [' ',#9]) do
  976. inc(code);
  977. {Sign}
  978. case s[code] of
  979. '-' : begin
  980. negativ:=true;
  981. inc(code);
  982. end;
  983. '+' : inc(code);
  984. end;
  985. {Base}
  986. if code<=length(s) then
  987. begin
  988. case s[code] of
  989. '$',
  990. 'X',
  991. 'x' : begin
  992. base:=16;
  993. inc(code);
  994. end;
  995. '%' : begin
  996. base:=2;
  997. inc(code);
  998. end;
  999. '&' : begin
  1000. Base:=8;
  1001. inc(code);
  1002. end;
  1003. '0' : begin
  1004. if (code < length(s)) and (s[code+1] in ['x', 'X']) then
  1005. begin
  1006. inc(code, 2);
  1007. base := 16;
  1008. end;
  1009. end;
  1010. end;
  1011. end;
  1012. { strip leading zeros }
  1013. while ((code < length(s)) and (s[code] = '0')) do begin
  1014. inc(code);
  1015. end;
  1016. InitVal:=code;
  1017. end;
  1018. const
  1019. ValValueArray : array['0'..'f'] of byte = (0,1,2,3,4,5,6,7,8,9,$FF,$FF,$FF,$FF,$FF,$FF,$FF,10,11,12,13,14,15,
  1020. $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
  1021. 10,11,12,13,14,15);
  1022. Function fpc_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_SHORTSTR']; compilerproc;
  1023. var
  1024. temp, prev, maxPrevValue: ValUInt;
  1025. base,u : byte;
  1026. negative: boolean;
  1027. UnsignedUpperLimit: ValUInt;
  1028. begin
  1029. fpc_Val_SInt_ShortStr := 0;
  1030. Temp:=0;
  1031. Code:=InitVal(s,negative,base);
  1032. { avoid error about being uninitialized }
  1033. UnsignedUpperLimit := 0;
  1034. if (base=10) or negative then
  1035. begin //always limit to either Low(DestType) or High(DestType)
  1036. case DestSize of
  1037. 1: UnsignedUpperLimit := ValUInt(High(ShortInt))+Ord(negative);
  1038. 2: UnsignedUpperLimit := ValUInt(High(SmallInt))+Ord(negative);
  1039. 4: UnsignedUpperLimit := ValUInt(High(LongInt))+Ord(negative);
  1040. {$ifdef CPU64}
  1041. 8: UnsignedUpperLimit := ValUInt(High(Int64))+Ord(negative);
  1042. {$endif CPU64}
  1043. end;
  1044. end
  1045. else
  1046. begin //not decimal and not negative
  1047. case DestSize of
  1048. 1: UnsignedUpperLimit := High(Byte);
  1049. 2: UnsignedUpperLimit := High(Word);
  1050. 4: UnsignedUpperLimit := High(DWord);
  1051. {$ifdef CPU64}
  1052. 8: UnsignedUpperLimit := High(UInt64);
  1053. {$endif CPU64}
  1054. end;
  1055. end;
  1056. if Code>length(s) then
  1057. exit;
  1058. if (s[Code]=#0) then
  1059. begin
  1060. if (Code>1) and (s[Code-1]='0') then
  1061. Code:=0;
  1062. exit;
  1063. end;
  1064. maxPrevValue := ValUInt(MaxUIntValue) div ValUInt(Base);
  1065. while Code<=Length(s) do
  1066. begin
  1067. u:=16;
  1068. case s[code] of
  1069. '0'..'f' : u:=ValValueArray[S[Code]];
  1070. #0 : break;
  1071. else
  1072. ;
  1073. end;
  1074. Prev := Temp;
  1075. Temp := Temp*ValUInt(base);
  1076. If (u >= base) or
  1077. (prev > maxPrevValue)
  1078. or ((Temp)>(UnsignedUpperLimit-u)) Then
  1079. Begin
  1080. fpc_Val_SInt_ShortStr := 0;
  1081. Exit
  1082. End;
  1083. Temp:=Temp+u;
  1084. inc(code);
  1085. end;
  1086. code := 0;
  1087. fpc_Val_SInt_ShortStr := ValSInt(Temp);
  1088. If Negative Then
  1089. fpc_Val_SInt_ShortStr := -fpc_Val_SInt_ShortStr;
  1090. If Not(Negative) and (base <> 10) Then
  1091. {sign extend the result to allow proper range checking}
  1092. Case DestSize of
  1093. 1: fpc_Val_SInt_ShortStr := shortint(fpc_Val_SInt_ShortStr);
  1094. 2: fpc_Val_SInt_ShortStr := smallint(fpc_Val_SInt_ShortStr);
  1095. {$ifdef cpu64}
  1096. 4: fpc_Val_SInt_ShortStr := longint(fpc_Val_SInt_ShortStr);
  1097. {$endif cpu64}
  1098. End;
  1099. end;
  1100. {$ifndef FPC_HAS_INT_VAL_SINT_SHORTSTR}
  1101. {$define FPC_HAS_INT_VAL_SINT_SHORTSTR}
  1102. { we need this for fpc_Val_SInt_Ansistr and fpc_Val_SInt_WideStr because }
  1103. { we have to pass the DestSize parameter on (JM) }
  1104. Function int_Val_SInt_ShortStr(DestSize: SizeInt; Const S: ShortString; out Code: ValSInt): ValSInt; [external name 'FPC_VAL_SINT_SHORTSTR'];
  1105. {$endif FPC_HAS_INT_VAL_SINT_SHORTSTR}
  1106. Function fpc_Val_UInt_Shortstr({$ifndef VER3_2}DestSize: SizeInt;{$endif VER3_2} Const S: ShortString; out Code: ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_SHORTSTR']; compilerproc;
  1107. var
  1108. base,u : byte;
  1109. negative : boolean;
  1110. UpperLimit: ValUInt;
  1111. begin
  1112. fpc_Val_UInt_Shortstr:=0;
  1113. Code:=InitVal(s,negative,base);
  1114. If Negative or (Code>length(s)) Then
  1115. begin
  1116. if Negative then Code:=Pos('-',S);
  1117. Exit;
  1118. end;
  1119. if (s[Code]=#0) then
  1120. begin
  1121. if (Code>1) and (s[Code-1]='0') then
  1122. Code:=0;
  1123. exit;
  1124. end;
  1125. {$ifndef VER3_2}
  1126. case DestSize of
  1127. 1: UpperLimit:=High(Byte);
  1128. 2: UpperLimit:=High(Word);
  1129. 4: UpperLimit:=High(DWord);
  1130. {$ifdef CPU64}
  1131. 8: UpperLimit:=High(QWord);
  1132. {$endif CPU64}
  1133. else
  1134. { avoid error about being uninitialized }
  1135. UpperLimit:=0;
  1136. end;
  1137. {$else VER3_2}
  1138. UpperLimit:=High(ValUInt); //this preserves 3.2 (and earlier) behaviour
  1139. {$ENDIF}
  1140. while Code<=Length(s) do
  1141. begin
  1142. u:=16;
  1143. case s[code] of
  1144. '0'..'f' : u:=ValValueArray[S[Code]];
  1145. #0 : break;
  1146. else
  1147. ;
  1148. end;
  1149. If (u>=base) or
  1150. (ValUInt(UpperLimit-u) div ValUInt(Base)<fpc_val_uint_shortstr) then
  1151. begin
  1152. fpc_Val_UInt_Shortstr:=0;
  1153. exit;
  1154. end;
  1155. fpc_Val_UInt_Shortstr:=fpc_Val_UInt_Shortstr*ValUInt(base) + u;
  1156. inc(code);
  1157. end;
  1158. code := 0;
  1159. {$ifndef VER3_2}
  1160. case DestSize of
  1161. 1: fpc_Val_UInt_Shortstr:=Byte(fpc_Val_UInt_Shortstr);
  1162. 2: fpc_Val_UInt_Shortstr:=Word(fpc_Val_UInt_Shortstr);
  1163. 4: fpc_Val_UInt_Shortstr:=DWord(fpc_Val_UInt_Shortstr);
  1164. //8: no typecast needed for QWord
  1165. end;
  1166. {$ENDIF}
  1167. end;
  1168. {$ifndef CPU64}
  1169. Function fpc_val_int64_shortstr(Const S: ShortString; out Code: ValSInt): Int64; [public, alias:'FPC_VAL_INT64_SHORTSTR']; compilerproc;
  1170. var u : sizeuint;
  1171. temp, prev, maxprevvalue, maxnewvalue : qword;
  1172. base : byte;
  1173. negative : boolean;
  1174. const maxint64=qword($7fffffffffffffff);
  1175. minint64_unsigned=qword($8000000000000000);
  1176. maxqword=qword($ffffffffffffffff);
  1177. begin
  1178. {$ifdef EXCLUDE_COMPLEX_PROCS}
  1179. runerror(219);
  1180. {$else EXCLUDE_COMPLEX_PROCS}
  1181. fpc_val_int64_shortstr := 0;
  1182. Temp:=0;
  1183. Code:=InitVal(s,negative,base);
  1184. if Code>length(s) then
  1185. exit;
  1186. if (s[Code]=#0) then
  1187. begin
  1188. if (Code>1) and (s[Code-1]='0') then
  1189. Code:=0;
  1190. exit;
  1191. end;
  1192. maxprevvalue := maxqword div base;
  1193. if (base = 10) then
  1194. maxnewvalue := maxint64 + ord(negative)
  1195. else
  1196. maxnewvalue := maxqword;
  1197. while Code<=Length(s) do
  1198. begin
  1199. u:=16;
  1200. case s[code] of
  1201. '0'..'f' : u:=ValValueArray[S[Code]];
  1202. #0 : break;
  1203. else
  1204. ;
  1205. end;
  1206. Prev:=Temp;
  1207. Temp:=Temp*qword(base);
  1208. If (u >= base) or
  1209. (qword(maxnewvalue-u) < temp) or
  1210. (prev > maxprevvalue) or
  1211. ((base<>10) and (negative) and ((Temp+u)>minint64_unsigned)) Then
  1212. Begin
  1213. fpc_val_int64_shortstr := 0;
  1214. Exit
  1215. End;
  1216. Temp:=Temp+u;
  1217. inc(code);
  1218. end;
  1219. code:=0;
  1220. fpc_val_int64_shortstr:=int64(Temp);
  1221. If Negative Then
  1222. fpc_val_int64_shortstr:=-fpc_val_int64_shortstr;
  1223. {$endif EXCLUDE_COMPLEX_PROCS}
  1224. end;
  1225. Function fpc_val_qword_shortstr(Const S: ShortString; out Code: ValSInt): QWord; [public, alias:'FPC_VAL_QWORD_SHORTSTR']; compilerproc;
  1226. var u : sizeuint;
  1227. base : byte;
  1228. negative : boolean;
  1229. const maxqword=qword($ffffffffffffffff);
  1230. begin
  1231. fpc_val_qword_shortstr:=0;
  1232. Code:=InitVal(s,negative,base);
  1233. If Negative or (Code>length(s)) Then
  1234. begin
  1235. if Negative then Code:=Pos('-',S);
  1236. Exit;
  1237. end;
  1238. if (s[Code]=#0) then
  1239. begin
  1240. if (Code>1) and (s[Code-1]='0') then
  1241. Code:=0;
  1242. exit;
  1243. end;
  1244. while Code<=Length(s) do
  1245. begin
  1246. u:=16;
  1247. case s[code] of
  1248. '0'..'f' : u:=ValValueArray[S[Code]];
  1249. #0 : break;
  1250. else
  1251. ;
  1252. end;
  1253. If (u>=base) or
  1254. ((QWord(maxqword-u) div QWord(base))<fpc_val_qword_shortstr) then
  1255. Begin
  1256. fpc_val_qword_shortstr := 0;
  1257. Exit
  1258. End;
  1259. fpc_val_qword_shortstr:=fpc_val_qword_shortstr*QWord(base) + u;
  1260. inc(code);
  1261. end;
  1262. code := 0;
  1263. end;
  1264. {$endif CPU64}
  1265. {$if defined(CPU16) or defined(CPU8)}
  1266. Function fpc_val_longint_shortstr(Const S: ShortString; out Code: ValSInt): LongInt; [public, alias:'FPC_VAL_LONGINT_SHORTSTR']; compilerproc;
  1267. var u, temp, prev, maxprevvalue, maxnewvalue : longword;
  1268. base : byte;
  1269. negative : boolean;
  1270. const maxlongint=longword($7fffffff);
  1271. maxlongword=longword($ffffffff);
  1272. begin
  1273. fpc_val_longint_shortstr := 0;
  1274. Temp:=0;
  1275. Code:=InitVal(s,negative,base);
  1276. if Code>length(s) then
  1277. exit;
  1278. if (s[Code]=#0) then
  1279. begin
  1280. if (Code>1) and (s[Code-1]='0') then
  1281. Code:=0;
  1282. exit;
  1283. end;
  1284. maxprevvalue := maxlongword div base;
  1285. if (base = 10) then
  1286. maxnewvalue := maxlongint + ord(negative)
  1287. else
  1288. maxnewvalue := maxlongword;
  1289. while Code<=Length(s) do
  1290. begin
  1291. u:=16;
  1292. case s[code] of
  1293. '0'..'f' : u:=ValValueArray[S[Code]];
  1294. #0 : break;
  1295. else
  1296. ;
  1297. end;
  1298. Prev:=Temp;
  1299. Temp:=Temp*longword(base);
  1300. If (u >= base) or
  1301. (longword(maxnewvalue-u) < temp) or
  1302. (prev > maxprevvalue) Then
  1303. Begin
  1304. fpc_val_longint_shortstr := 0;
  1305. Exit;
  1306. End;
  1307. Temp:=Temp+u;
  1308. inc(code);
  1309. end;
  1310. code:=0;
  1311. fpc_val_longint_shortstr:=longint(Temp);
  1312. If Negative Then
  1313. fpc_val_longint_shortstr:=-fpc_val_longint_shortstr;
  1314. end;
  1315. Function fpc_val_longword_shortstr(Const S: ShortString; out Code: ValSInt): LongWord; [public, alias:'FPC_VAL_LONGWORD_SHORTSTR']; compilerproc;
  1316. var u, prev: LongWord;
  1317. base : byte;
  1318. negative : boolean;
  1319. const UpperLimit=High(longword);
  1320. begin
  1321. fpc_val_longword_shortstr:=0;
  1322. Code:=InitVal(s,negative,base);
  1323. If Negative or (Code>length(s)) Then
  1324. Exit;
  1325. if (s[Code]=#0) then
  1326. begin
  1327. if (Code>1) and (s[Code-1]='0') then
  1328. Code:=0;
  1329. exit;
  1330. end;
  1331. while Code<=Length(s) do
  1332. begin
  1333. u:=16;
  1334. case s[code] of
  1335. '0'..'f' : u:=ValValueArray[S[Code]];
  1336. #0 : break;
  1337. else
  1338. ;
  1339. end;
  1340. If (u>=base) or
  1341. (LongWord(UpperLimit-u) div LongWord(Base)<fpc_val_longword_shortstr) then
  1342. begin
  1343. fpc_val_longword_shortstr:=0;
  1344. exit;
  1345. end;
  1346. fpc_val_longword_shortstr:=fpc_val_longword_shortstr*base + u;
  1347. inc(code);
  1348. end;
  1349. code := 0;
  1350. end;
  1351. Function fpc_val_smallint_shortstr(Const S: ShortString; out Code: ValSInt): SmallInt; [public, alias:'FPC_VAL_SMALLINT_SHORTSTR']; compilerproc;
  1352. var u, temp, prev, maxprevvalue : word;
  1353. base : byte;
  1354. negative : boolean;
  1355. UnsignedUpperLimit: ValUInt;
  1356. begin
  1357. fpc_val_smallint_shortstr := 0;
  1358. Temp:=0;
  1359. Code:=InitVal(s,negative,base);
  1360. if (base=10) or negative then
  1361. UnsignedUpperLimit := Word(High(SmallInt))+Ord(negative)
  1362. else
  1363. UnsignedUpperLimit := High(Word);
  1364. if Code>length(s) then
  1365. exit;
  1366. if (s[Code]=#0) then
  1367. begin
  1368. if (Code>1) and (s[Code-1]='0') then
  1369. Code:=0;
  1370. exit;
  1371. end;
  1372. maxprevvalue := High(Word) div base;
  1373. while Code<=Length(s) do
  1374. begin
  1375. u:=16;
  1376. case s[code] of
  1377. '0'..'f' : u:=ValValueArray[S[Code]];
  1378. #0 : break;
  1379. else
  1380. ;
  1381. end;
  1382. Prev:=Temp;
  1383. Temp:=Temp*longword(base);
  1384. If (u >= base) or
  1385. (prev > maxPrevValue) or
  1386. ((Temp)>(UnsignedUpperLimit-u)) Then
  1387. Begin
  1388. fpc_val_smallint_shortstr := 0;
  1389. Exit
  1390. End;
  1391. Temp:=Temp+u;
  1392. inc(code);
  1393. end;
  1394. code:=0;
  1395. fpc_val_smallint_shortstr:=SmallInt(Temp);
  1396. If Negative Then
  1397. fpc_val_smallint_shortstr:=-fpc_val_smallint_shortstr;
  1398. end;
  1399. Function fpc_val_word_shortstr(Const S: ShortString; out Code: ValSInt): Word; [public, alias:'FPC_VAL_WORD_SHORTSTR']; compilerproc;
  1400. var u, prev: word;
  1401. base : byte;
  1402. negative : boolean;
  1403. const UpperLimit=High(Word); //this preserves 3.2 (and earlier) behaviour
  1404. begin
  1405. fpc_val_word_shortstr:=0;
  1406. Code:=InitVal(s,negative,base);
  1407. If Negative or (Code>length(s)) Then
  1408. begin
  1409. if Negative then Code:=Pos('-',S);
  1410. Exit;
  1411. end;
  1412. if (s[Code]=#0) then
  1413. begin
  1414. if (Code>1) and (s[Code-1]='0') then
  1415. Code:=0;
  1416. exit;
  1417. end;
  1418. while Code<=Length(s) do
  1419. begin
  1420. u:=16;
  1421. case s[code] of
  1422. '0'..'f' : u:=ValValueArray[S[Code]];
  1423. #0 : break;
  1424. else
  1425. ;
  1426. end;
  1427. If (u>=base) or
  1428. (Word(UpperLimit-u) div Word(Base)<fpc_val_word_shortstr) then
  1429. begin
  1430. fpc_val_word_shortstr:=0;
  1431. exit;
  1432. end;
  1433. fpc_val_word_shortstr:=fpc_val_word_shortstr*base + u;
  1434. inc(code);
  1435. end;
  1436. code := 0;
  1437. end;
  1438. {$endif CPU16 or CPU8}
  1439. {$ifndef FPUNONE}
  1440. Function fpc_Val_Real_ShortStr(const s : shortstring; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_SHORTSTR']; compilerproc;
  1441. begin
  1442. fpc_Val_Real_ShortStr := val_real( s, code );
  1443. end;
  1444. {$endif FPUNONE}
  1445. {$ifndef FPC_STR_ENUM_INTERN}
  1446. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint; [public, alias:'FPC_VAL_ENUM_SHORTSTR']; compilerproc;
  1447. type Psorted_array=^Tsorted_array;
  1448. Tsorted_array={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1449. o:longint;
  1450. s:Pstring;
  1451. end;
  1452. Pstring_to_ord=^Tstring_to_ord;
  1453. Tstring_to_ord={$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  1454. count:longint;
  1455. data:array[0..0] of Tsorted_array;
  1456. end;
  1457. var l,r,l2,r2,m,sp,isp:SizeInt;
  1458. c:char;
  1459. begin
  1460. {Val for numbers accepts spaces at the start, so lets do the same
  1461. for enums. Skip spaces at the start of the string.}
  1462. sp:=1;
  1463. while (sp<=length(s)) and (s[sp]=' ') do
  1464. inc(sp);
  1465. { Let input be “abd” and sorted names be: _hm a aa ab aba abb abc abd ac ad b c
  1466. Start: L ┘R (R points PAST the last item in the range.)
  1467. After iteration 0 (“a” analyzed): L ┘R
  1468. After iteration 1 (“ab” analyzed): L ┘R
  1469. After iteration 2 (“abd” analyzed): L ┘R }
  1470. l:=0;
  1471. r:=Pstring_to_ord(str2ordindex)^.count;
  1472. dec(sp); { sp/isp are incremented at the beginning of the loop so that 'continue's advance sp/isp. }
  1473. isp:=0; { isp is the position without spaces. }
  1474. repeat
  1475. inc(sp);
  1476. if sp>length(s) then
  1477. break;
  1478. inc(isp);
  1479. c:=UpCase(s[sp]);
  1480. { Among all strings beginning with, say, ‘ab’, the ‘ab’ itself will be the first.
  1481. So after this check, “isp ≤ length(any string in the range)” is guaranteed. }
  1482. if isp>length(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[l].s^) then
  1483. begin
  1484. inc(l);
  1485. if l=r then
  1486. break;
  1487. end;
  1488. if UpCase(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[l].s^[isp])=c then { Shortcut: L may be already correct (enums often have common prefixes). }
  1489. begin
  1490. if l+1=r then { Shortcut: the only string left (enums often have different suffixes). }
  1491. continue;
  1492. end
  1493. else
  1494. begin
  1495. r2:=r; { Search for new L. }
  1496. repeat
  1497. m:=SizeUint(l+r2) div 2;
  1498. if UpCase(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[m].s^[isp])<c then
  1499. l:=m+1
  1500. else
  1501. r2:=m;
  1502. until l=r2;
  1503. if l=r then
  1504. break;
  1505. end;
  1506. if UpCase(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[r-1].s^[isp])=c then { Shortcut: R−1 may be already correct. }
  1507. continue;
  1508. l2:=l; { Search for new R. }
  1509. repeat
  1510. m:=SizeUint(l2+r) div 2;
  1511. if UpCase(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[m].s^[isp])<=c then
  1512. l2:=m+1
  1513. else
  1514. r:=m;
  1515. until l2=r;
  1516. if l=r then { Better not to make it the loop condition, or ‘continue’s may jump to it instead of the beginning. }
  1517. break;
  1518. until false;
  1519. if (l<r) and (isp=length(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[l].s^)) then
  1520. begin
  1521. code:=0;
  1522. exit(Psorted_array(Pstring_to_ord(str2ordindex)^.data)[l].o);
  1523. end;
  1524. code:=sp;
  1525. result:=-1; { Formally undefined, but −1 is very likely the invalid value prone to crashing, which is better than accidentally working. }
  1526. end;
  1527. {Redeclare fpc_val_enum_shortstr for internal use in the system unit.}
  1528. function fpc_val_enum_shortstr(str2ordindex:pointer;const s:shortstring;out code:valsint):longint;external name 'FPC_VAL_ENUM_SHORTSTR';
  1529. {$endif FPC_STR_ENUM_INTERN}
  1530. function fpc_Val_Currency_ShortStr(const s : shortstring; out Code : ValSInt): currency; [public, alias:'FPC_VAL_CURRENCY_SHORTSTR']; compilerproc;
  1531. {$ifdef EXCLUDE_COMPLEX_PROCS}
  1532. begin
  1533. runerror(217);
  1534. end;
  1535. {$else EXCLUDE_COMPLEX_PROCS}
  1536. const
  1537. MinInt64 : Int64 =-$8000000000000000;
  1538. MinInt64Edge : Int64 = (-$8000000000000000 + 10) div 10;
  1539. var
  1540. { to enable taking the address on the JVM target }
  1541. res : array[0..0] of Int64;
  1542. i,j,power,sign,len : longint;
  1543. FracOverflow : boolean;
  1544. begin
  1545. fpc_Val_Currency_ShortStr:=0;
  1546. res[0]:=0;
  1547. len:=Length(s);
  1548. Code:=1;
  1549. sign:=-1;
  1550. power:=0;
  1551. while True do
  1552. if Code > len then
  1553. exit
  1554. else
  1555. if s[Code] in [' ', #9] then
  1556. Inc(Code)
  1557. else
  1558. break;
  1559. { Read sign }
  1560. case s[Code] of
  1561. '+' : begin
  1562. Inc(Code);
  1563. end;
  1564. '-' : begin
  1565. sign:=+1;
  1566. Inc(Code);
  1567. end;
  1568. end;
  1569. { Read digits }
  1570. FracOverflow:=False;
  1571. i:=0;
  1572. while Code <= len do
  1573. begin
  1574. case s[Code] of
  1575. '0'..'9':
  1576. begin
  1577. j:=Ord(s[code])-Ord('0');
  1578. { check overflow }
  1579. if (res[0] >= MinInt64Edge) or (res[0] >= (MinInt64 + j) div 10) then
  1580. begin
  1581. res[0]:=res[0]*10 - j;
  1582. Inc(i);
  1583. end
  1584. else
  1585. if power = 0 then
  1586. { exit if integer part overflow }
  1587. exit
  1588. else
  1589. begin
  1590. if not FracOverflow and (j >= 5) and (res[0] > MinInt64) then
  1591. { round if first digit of fractional part overflow }
  1592. Dec(res[0]);
  1593. FracOverflow:=True;
  1594. end;
  1595. end;
  1596. '.':
  1597. begin
  1598. if power = 0 then
  1599. begin
  1600. power:=1;
  1601. i:=0;
  1602. end
  1603. else
  1604. exit;
  1605. end;
  1606. else
  1607. break;
  1608. end;
  1609. Inc(Code);
  1610. end;
  1611. if (i = 0) and (power = 0) then
  1612. exit;
  1613. if power <> 0 then
  1614. power:=i;
  1615. power:=4 - power;
  1616. { Exponent? }
  1617. if Code <= len then
  1618. if s[Code] in ['E', 'e'] then
  1619. begin
  1620. Inc(Code);
  1621. if Code > len then
  1622. exit;
  1623. i:=1;
  1624. case s[Code] of
  1625. '+':
  1626. Inc(Code);
  1627. '-':
  1628. begin
  1629. i:=-1;
  1630. Inc(Code);
  1631. end;
  1632. end;
  1633. { read exponent }
  1634. j:=0;
  1635. while Code <= len do
  1636. if s[Code] in ['0'..'9'] then
  1637. begin
  1638. if j > 4951 then
  1639. exit;
  1640. j:=j*10 + (Ord(s[code])-Ord('0'));
  1641. Inc(Code);
  1642. end
  1643. else
  1644. exit;
  1645. power:=power + j*i;
  1646. end
  1647. else
  1648. exit;
  1649. if power > 0 then
  1650. begin
  1651. for i:=1 to power do
  1652. if res[0] >= MinInt64 div 10 then
  1653. res[0]:=res[0]*10
  1654. else
  1655. exit;
  1656. end
  1657. else
  1658. for i:=1 to -power do
  1659. begin
  1660. if res[0] >= MinInt64 + 5 then
  1661. Dec(res[0], 5);
  1662. res[0]:=res[0] div 10;
  1663. end;
  1664. if sign <> 1 then
  1665. if res[0] > MinInt64 then
  1666. res[0]:=res[0]*sign
  1667. else
  1668. exit;
  1669. fpc_Val_Currency_ShortStr:=PCurrency(@res[0])^;
  1670. Code:=0;
  1671. end;
  1672. {$endif EXCLUDE_COMPLEX_PROCS}
  1673. {$ifndef FPC_HAS_SETSTRING_SHORTSTR}
  1674. {$define FPC_HAS_SETSTRING_SHORTSTR}
  1675. Procedure fpc_setstring_shortstr(Out S : Shortstring; Buf : PAnsiChar; Len : SizeInt); compilerproc;
  1676. begin
  1677. If Len > High(S) then
  1678. Len := High(S);
  1679. SetLength(S,Len);
  1680. If Buf<>Nil then
  1681. begin
  1682. Move (Buf[0],S[1],Len);
  1683. end;
  1684. end;
  1685. {$endif FPC_HAS_SETSTRING_SHORTSTR}
  1686. {$ifndef FPC_HAS_COMPARETEXT_SHORTSTR}
  1687. {$define FPC_HAS_COMPARETEXT_SHORTSTR}
  1688. function ShortCompareText(const S1, S2: shortstring): SizeInt;
  1689. var
  1690. c1, c2: Byte;
  1691. i: SizeInt;
  1692. L1, L2, Count: SizeInt;
  1693. P1, P2: PAnsiChar;
  1694. begin
  1695. L1 := Length(S1);
  1696. L2 := Length(S2);
  1697. if L1 > L2 then
  1698. Count := L2
  1699. else
  1700. Count := L1;
  1701. i := 0;
  1702. P1 := @S1[1];
  1703. P2 := @S2[1];
  1704. while i < count do
  1705. begin
  1706. c1 := byte(p1^);
  1707. c2 := byte(p2^);
  1708. if c1 <> c2 then
  1709. begin
  1710. if c1 in [97..122] then
  1711. Dec(c1, 32);
  1712. if c2 in [97..122] then
  1713. Dec(c2, 32);
  1714. if c1 <> c2 then
  1715. Break;
  1716. end;
  1717. Inc(P1); Inc(P2); Inc(I);
  1718. end;
  1719. if i < count then
  1720. ShortCompareText := c1 - c2
  1721. else
  1722. ShortCompareText := L1 - L2;
  1723. end;
  1724. {$endif FPC_HAS_COMPARETEXT_SHORTSTR}