sysformt.inc 11 KB

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