sysformt.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. Var ChPos,OldPos,ArgPos,DoArg,Len : SizeInt;
  2. Hs,ToAdd : TFormatString;
  3. Index : SizeInt;
  4. Width,Prec : Longint;
  5. Left : Boolean;
  6. Fchar : char;
  7. vq : qword;
  8. {
  9. ReadFormat reads the format string. It returns the type character in
  10. uppercase, and sets index, Width, Prec to their correct values,
  11. or -1 if not set. It sets Left to true if left alignment was requested.
  12. In case of an error, DoFormatError is called.
  13. }
  14. Function ReadFormat : Char;
  15. Var Value : longint;
  16. Procedure ReadInteger;
  17. var
  18. Code: Word;
  19. ArgN: SizeInt;
  20. begin
  21. If Value<>-1 then exit; // Was already read.
  22. OldPos:=ChPos;
  23. While (ChPos<=Len) and
  24. (Fmt[ChPos]<='9') and (Fmt[ChPos]>='0') do inc(ChPos);
  25. If ChPos>len then
  26. DoFormatError(feInvalidFormat,Fmt);
  27. If Fmt[ChPos]='*' then
  28. begin
  29. if Index=-1 then
  30. ArgN:=Argpos
  31. else
  32. begin
  33. ArgN:=Index;
  34. Inc(Index);
  35. end;
  36. If (ChPos>OldPos) or (ArgN>High(Args)) then
  37. DoFormatError(feInvalidFormat,Fmt);
  38. ArgPos:=ArgN+1;
  39. case Args[ArgN].Vtype of
  40. vtInteger: Value := Args[ArgN].VInteger;
  41. vtInt64: Value := Args[ArgN].VInt64^;
  42. vtQWord: Value := Args[ArgN].VQWord^;
  43. else
  44. DoFormatError(feInvalidFormat,Fmt);
  45. end;
  46. Inc(ChPos);
  47. end
  48. else
  49. begin
  50. If (OldPos<ChPos) Then
  51. begin
  52. Val (Copy(Fmt,OldPos,ChPos-OldPos),value,code);
  53. // This should never happen !!
  54. If Code>0 then DoFormatError (feInvalidFormat,Fmt);
  55. end
  56. else
  57. Value:=-1;
  58. end;
  59. end;
  60. Procedure ReadIndex;
  61. begin
  62. If Fmt[ChPos]<>':' then
  63. ReadInteger
  64. else
  65. value:=0; // Delphi undocumented behaviour, assume 0, #11099
  66. If Fmt[ChPos]=':' then
  67. begin
  68. If Value=-1 then DoFormatError(feMissingArgument,fmt);
  69. Index:=Value;
  70. Value:=-1;
  71. Inc(ChPos);
  72. end;
  73. {$ifdef fmtdebug}
  74. Log ('Read index');
  75. {$endif}
  76. end;
  77. Procedure ReadLeft;
  78. begin
  79. If Fmt[ChPos]='-' then
  80. begin
  81. left:=True;
  82. Inc(ChPos);
  83. end
  84. else
  85. Left:=False;
  86. {$ifdef fmtdebug}
  87. Log ('Read Left');
  88. {$endif}
  89. end;
  90. Procedure ReadWidth;
  91. begin
  92. ReadInteger;
  93. If Value<>-1 then
  94. begin
  95. Width:=Value;
  96. Value:=-1;
  97. end;
  98. {$ifdef fmtdebug}
  99. Log ('Read width');
  100. {$endif}
  101. end;
  102. Procedure ReadPrec;
  103. begin
  104. If Fmt[ChPos]='.' then
  105. begin
  106. inc(ChPos);
  107. ReadInteger;
  108. If Value=-1 then
  109. Value:=0;
  110. prec:=Value;
  111. end;
  112. {$ifdef fmtdebug}
  113. Log ('Read precision');
  114. {$endif}
  115. end;
  116. {$ifdef INWIDEFORMAT}
  117. var
  118. FormatChar : TFormatChar;
  119. {$endif INWIDEFORMAT}
  120. begin
  121. {$ifdef fmtdebug}
  122. Log ('Start format');
  123. {$endif}
  124. Index:=-1;
  125. Width:=-1;
  126. Prec:=-1;
  127. Value:=-1;
  128. inc(ChPos);
  129. If Fmt[ChPos]='%' then
  130. begin
  131. Result:='%';
  132. exit; // VP fix
  133. end;
  134. ReadIndex;
  135. ReadLeft;
  136. ReadWidth;
  137. ReadPrec;
  138. {$ifdef INWIDEFORMAT}
  139. {$ifdef VER2_2}
  140. FormatChar:=UpCase(Fmt[ChPos])[1];
  141. {$else VER2_2}
  142. FormatChar:=UpCase(UnicodeChar(Fmt[ChPos]));
  143. {$endif VER2_2}
  144. if word(FormatChar)>255 then
  145. ReadFormat:=#255
  146. else
  147. ReadFormat:=FormatChar;
  148. {$else INWIDEFORMAT}
  149. ReadFormat:=Upcase(Fmt[ChPos]);
  150. {$endif INWIDEFORMAT}
  151. {$ifdef fmtdebug}
  152. Log ('End format');
  153. {$endif}
  154. end;
  155. {$ifdef fmtdebug}
  156. Procedure DumpFormat (C : char);
  157. begin
  158. Write ('Fmt : ',fmt:10);
  159. Write (' Index : ',Index:3);
  160. Write (' Left : ',left:5);
  161. Write (' Width : ',Width:3);
  162. Write (' Prec : ',prec:3);
  163. Writeln (' Type : ',C);
  164. end;
  165. {$endif}
  166. function Checkarg (AT : SizeInt;err:boolean):boolean;
  167. {
  168. Check if argument INDEX is of correct type (AT)
  169. If Index=-1, ArgPos is used, and argpos is augmented with 1
  170. DoArg is set to the argument that must be used.
  171. }
  172. begin
  173. result:=false;
  174. if Index=-1 then
  175. DoArg:=Argpos
  176. else
  177. DoArg:=Index;
  178. ArgPos:=DoArg+1;
  179. If (Doarg>High(Args)) or (Args[Doarg].Vtype<>AT) then
  180. begin
  181. if err then
  182. DoFormatError(feInvalidArgindex,Fmt);
  183. dec(ArgPos);
  184. exit;
  185. end;
  186. result:=true;
  187. end;
  188. begin
  189. Result:='';
  190. Len:=Length(Fmt);
  191. ChPos:=1;
  192. OldPos:=1;
  193. ArgPos:=0;
  194. While ChPos<=len do
  195. begin
  196. While (ChPos<=Len) and (Fmt[ChPos]<>'%') do
  197. inc(ChPos);
  198. If ChPos>OldPos Then
  199. Result:=Result+Copy(Fmt,OldPos,ChPos-Oldpos);
  200. If ChPos<Len then
  201. begin
  202. FChar:=ReadFormat;
  203. {$ifdef fmtdebug}
  204. DumpFormat(FCHar);
  205. {$endif}
  206. Case FChar of
  207. 'D' : begin
  208. if Checkarg(vtinteger,false) then
  209. Str(Args[Doarg].VInteger,ToAdd)
  210. else if CheckArg(vtInt64,false) then
  211. Str(Args[DoArg].VInt64^,toadd)
  212. else if CheckArg(vtQWord,true) then
  213. Str(int64(Args[DoArg].VQWord^),toadd);
  214. Width:=Abs(width);
  215. Index:=Prec-Length(ToAdd);
  216. If ToAdd[1]<>'-' then
  217. ToAdd:=StringOfChar('0',Index)+ToAdd
  218. else
  219. // + 1 to accomodate for - sign in length !!
  220. Insert(StringOfChar('0',Index+1),toadd,2);
  221. end;
  222. 'U' : begin
  223. if Checkarg(vtinteger,false) then
  224. Str(cardinal(Args[Doarg].VInteger),ToAdd)
  225. else if CheckArg(vtInt64,false) then
  226. Str(qword(Args[DoArg].VInt64^),toadd)
  227. else if CheckArg(vtQWord,true) then
  228. Str(Args[DoArg].VQWord^,toadd);
  229. Width:=Abs(width);
  230. Index:=Prec-Length(ToAdd);
  231. ToAdd:=StringOfChar('0',Index)+ToAdd
  232. end;
  233. {$ifndef FPUNONE}
  234. 'E' : begin
  235. if CheckArg(vtCurrency,false) then
  236. ToAdd:=FloatToStrF(Args[doarg].VCurrency^,ffexponent,Prec,3,FormatSettings)
  237. else if CheckArg(vtExtended,true) then
  238. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffexponent,Prec,3,FormatSettings);
  239. end;
  240. 'F' : begin
  241. if CheckArg(vtCurrency,false) then
  242. ToAdd:=FloatToStrF(Args[doarg].VCurrency^,ffFixed,9999,Prec,FormatSettings)
  243. else if CheckArg(vtExtended,true) then
  244. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffFixed,9999,Prec,FormatSettings);
  245. end;
  246. 'G' : begin
  247. if CheckArg(vtCurrency,false) then
  248. ToAdd:=FloatToStrF(Args[doarg].VCurrency^,ffGeneral,Prec,3,FormatSettings)
  249. else if CheckArg(vtExtended,true) then
  250. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffGeneral,Prec,3,FormatSettings);
  251. end;
  252. 'N' : begin
  253. if CheckArg(vtCurrency,false) then
  254. ToAdd:=FloatToStrF(Args[doarg].VCurrency^,ffNumber,9999,Prec,FormatSettings)
  255. else if CheckArg(vtExtended,true) then
  256. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffNumber,9999,Prec,FormatSettings);
  257. end;
  258. 'M' : begin
  259. if CheckArg(vtExtended,false) then
  260. ToAdd:=FloatToStrF(Args[doarg].VExtended^,ffCurrency,9999,Prec,FormatSettings)
  261. else if CheckArg(vtCurrency,true) then
  262. ToAdd:=FloatToStrF(Args[doarg].VCurrency^,ffCurrency,9999,Prec,FormatSettings);
  263. end;
  264. {$else}
  265. 'E','F','G','N','M':
  266. RunError(207);
  267. {$endif}
  268. 'S' : begin
  269. if CheckArg(vtString,false) then
  270. hs:=Args[doarg].VString^
  271. else
  272. if CheckArg(vtChar,false) then
  273. hs:=Args[doarg].VChar
  274. else
  275. if CheckArg(vtPChar,false) then
  276. hs:=Args[doarg].VPChar
  277. else
  278. if CheckArg(vtPWideChar,false) then
  279. hs:=WideString(Args[doarg].VPWideChar)
  280. else
  281. if CheckArg(vtWideChar,false) then
  282. hs:=WideString(Args[doarg].VWideChar)
  283. else
  284. if CheckArg(vtWidestring,false) then
  285. hs:=WideString(Args[doarg].VWideString)
  286. else
  287. if CheckArg(vtAnsiString,false) then
  288. hs:=ansistring(Args[doarg].VAnsiString)
  289. else
  290. if CheckArg(vtUnicodeString,false) then
  291. hs:=UnicodeString(Args[doarg].VUnicodeString)
  292. else
  293. if CheckArg(vtVariant,true) then
  294. hs:=Args[doarg].VVariant^;
  295. Index:=Length(hs);
  296. If (Prec<>-1) and (Index>Prec) then
  297. Index:=Prec;
  298. ToAdd:=Copy(hs,1,Index);
  299. end;
  300. 'P' : Begin
  301. CheckArg(vtpointer,true);
  302. ToAdd:=HexStr(ptruint(Args[DoArg].VPointer),sizeof(Ptruint)*2);
  303. // Insert ':'. Is this needed in 32 bit ? No it isn't.
  304. // Insert(':',ToAdd,5);
  305. end;
  306. 'X' : begin
  307. if Checkarg(vtinteger,false) then
  308. begin
  309. vq:=Cardinal(Args[Doarg].VInteger);
  310. index:=16;
  311. end
  312. else
  313. if CheckArg(vtQWord, false) then
  314. begin
  315. vq:=Qword(Args[DoArg].VQWord^);
  316. index:=31;
  317. end
  318. else
  319. begin
  320. CheckArg(vtInt64,true);
  321. vq:=Qword(Args[DoArg].VInt64^);
  322. index:=31;
  323. end;
  324. If Prec>index then
  325. ToAdd:=HexStr(int64(vq),index)
  326. else
  327. begin
  328. // determine minimum needed number of hex digits.
  329. Index:=1;
  330. While (qWord(1) shl (Index*4)<=vq) and (index<16) do
  331. inc(Index);
  332. If Index>Prec then
  333. Prec:=Index;
  334. ToAdd:=HexStr(int64(vq),Prec);
  335. end;
  336. end;
  337. '%': ToAdd:='%';
  338. end;
  339. If Width<>-1 then
  340. If Length(ToAdd)<Width then
  341. If not Left then
  342. ToAdd:=Space(Width-Length(ToAdd))+ToAdd
  343. else
  344. ToAdd:=ToAdd+space(Width-Length(ToAdd));
  345. Result:=Result+ToAdd;
  346. end;
  347. inc(ChPos);
  348. Oldpos:=ChPos;
  349. end;
  350. end;