sysformt.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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,ansistring(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,ansistring(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,ansistring(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,ansistring(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,ansistring(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. FormatChar:=UpCase(UnicodeChar(Fmt[ChPos]));
  151. if word(FormatChar)>255 then
  152. ReadFormat:=#255
  153. else
  154. ReadFormat:=FormatChar;
  155. {$else INWIDEFORMAT}
  156. ReadFormat:=Upcase(Fmt[ChPos]);
  157. {$endif INWIDEFORMAT}
  158. {$ifdef fmtdebug}
  159. Log ('End format');
  160. {$endif}
  161. end;
  162. {$ifdef fmtdebug}
  163. Procedure DumpFormat (C : char);
  164. begin
  165. Write ('Fmt : ',fmt:10);
  166. Write (' Index : ',Index:3);
  167. Write (' Left : ',left:5);
  168. Write (' Width : ',Width:3);
  169. Write (' Prec : ',prec:3);
  170. Writeln (' Type : ',C);
  171. end;
  172. {$endif}
  173. function Checkarg (AT : SizeInt;err:boolean):boolean;
  174. {
  175. Check if argument INDEX is of correct type (AT)
  176. If Index=-1, ArgPos is used, and argpos is augmented with 1
  177. DoArg is set to the argument that must be used.
  178. }
  179. begin
  180. result:=false;
  181. if Index=-1 then
  182. DoArg:=Argpos
  183. else
  184. DoArg:=Index;
  185. ArgPos:=DoArg+1;
  186. If (Doarg>High(Args)) or (Args[Doarg].Vtype<>AT) then
  187. begin
  188. if err then
  189. DoFormatError(feInvalidArgindex,ansistring(Fmt));
  190. dec(ArgPos);
  191. exit;
  192. end;
  193. result:=true;
  194. end;
  195. begin
  196. Result:='';
  197. Len:=Length(Fmt);
  198. ChPos:=1;
  199. OldPos:=1;
  200. ArgPos:=0;
  201. While ChPos<=len do
  202. begin
  203. While (ChPos<=Len) and (Fmt[ChPos]<>'%') do
  204. inc(ChPos);
  205. If ChPos>OldPos Then
  206. Result:=Result+Copy(Fmt,OldPos,ChPos-Oldpos);
  207. If ChPos<Len then
  208. begin
  209. FChar:=ReadFormat;
  210. {$ifdef fmtdebug}
  211. DumpFormat(FCHar);
  212. {$endif}
  213. Case FChar of
  214. 'D' : begin
  215. if Checkarg(vtinteger,false) then
  216. Str(Args[Doarg].VInteger,ToAdd)
  217. else if CheckArg(vtInt64,false) then
  218. Str(Args[DoArg].VInt64^,toadd)
  219. else if CheckArg(vtQWord,true) then
  220. Str(int64(Args[DoArg].VQWord^),toadd);
  221. Width:=Abs(width);
  222. Index:=Prec-Length(ToAdd);
  223. If ToAdd[1]<>'-' then
  224. ToAdd:=TFormatString(StringOfChar('0',Index))+ToAdd
  225. else
  226. // + 1 to accomodate for - sign in length !!
  227. Insert(TFormatString(StringOfChar('0',Index+1)),toadd,2);
  228. end;
  229. 'U' : begin
  230. if Checkarg(vtinteger,false) then
  231. Str(cardinal(Args[Doarg].VInteger),ToAdd)
  232. else if CheckArg(vtInt64,false) then
  233. Str(qword(Args[DoArg].VInt64^),toadd)
  234. else if CheckArg(vtQWord,true) then
  235. Str(Args[DoArg].VQWord^,toadd);
  236. Width:=Abs(width);
  237. Index:=Prec-Length(ToAdd);
  238. ToAdd:=TFormatString(StringOfChar('0',Index))+ToAdd
  239. end;
  240. {$ifndef FPUNONE}
  241. 'E' : begin
  242. if CheckArg(vtCurrency,false) then
  243. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffexponent,Prec,3,FormatSettings))
  244. else if CheckArg(vtExtended,true) then
  245. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffexponent,Prec,3,FormatSettings));
  246. end;
  247. 'F' : begin
  248. if CheckArg(vtCurrency,false) then
  249. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffFixed,9999,Prec,FormatSettings))
  250. else if CheckArg(vtExtended,true) then
  251. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffFixed,9999,Prec,FormatSettings));
  252. end;
  253. 'G' : begin
  254. if CheckArg(vtCurrency,false) then
  255. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffGeneral,Prec,3,FormatSettings))
  256. else if CheckArg(vtExtended,true) then
  257. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffGeneral,Prec,3,FormatSettings));
  258. end;
  259. 'N' : begin
  260. if CheckArg(vtCurrency,false) then
  261. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffNumber,9999,Prec,FormatSettings))
  262. else if CheckArg(vtExtended,true) then
  263. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffNumber,9999,Prec,FormatSettings));
  264. end;
  265. 'M' : begin
  266. if CheckArg(vtExtended,false) then
  267. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffCurrency,9999,Prec,FormatSettings))
  268. else if CheckArg(vtCurrency,true) then
  269. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffCurrency,9999,Prec,FormatSettings));
  270. end;
  271. {$else}
  272. 'E','F','G','N','M':
  273. RunError(207);
  274. {$endif}
  275. 'S' : begin
  276. if CheckArg(vtString,false) then
  277. hs:=TFormatString(Args[doarg].VString^)
  278. else
  279. if CheckArg(vtChar,false) then
  280. hs:=TFormatString(Args[doarg].VChar)
  281. else
  282. if CheckArg(vtPChar,false) then
  283. hs:=TFormatString(Args[doarg].VPChar)
  284. else
  285. if CheckArg(vtPWideChar,false) then
  286. hs:=TFormatString(WideString(Args[doarg].VPWideChar))
  287. else
  288. if CheckArg(vtWideChar,false) then
  289. hs:=TFormatString(WideString(Args[doarg].VWideChar))
  290. else
  291. if CheckArg(vtWidestring,false) then
  292. hs:=TFormatString(WideString(Args[doarg].VWideString))
  293. else
  294. if CheckArg(vtAnsiString,false) then
  295. hs:=TFormatString(ansistring(Args[doarg].VAnsiString))
  296. else
  297. if CheckArg(vtUnicodeString,false) then
  298. hs:=TFormatString(UnicodeString(Args[doarg].VUnicodeString))
  299. else
  300. if CheckArg(vtVariant,true) then
  301. hs:=Args[doarg].VVariant^;
  302. Index:=Length(hs);
  303. If (Prec<>-1) and (Index>Prec) then
  304. Index:=Prec;
  305. ToAdd:=Copy(hs,1,Index);
  306. end;
  307. 'P' : Begin
  308. CheckArg(vtpointer,true);
  309. ToAdd:=TFormatString(HexStr(ptruint(Args[DoArg].VPointer),sizeof(Ptruint)*2));
  310. // Insert ':'. Is this needed in 32 bit ? No it isn't.
  311. // Insert(':',ToAdd,5);
  312. end;
  313. 'X' : begin
  314. if Checkarg(vtinteger,false) then
  315. begin
  316. vq:=Cardinal(Args[Doarg].VInteger);
  317. index:=16;
  318. end
  319. else
  320. if CheckArg(vtQWord, false) then
  321. begin
  322. vq:=Qword(Args[DoArg].VQWord^);
  323. index:=31;
  324. end
  325. else
  326. begin
  327. CheckArg(vtInt64,true);
  328. vq:=Qword(Args[DoArg].VInt64^);
  329. index:=31;
  330. end;
  331. If Prec>index then
  332. ToAdd:=TFormatString(HexStr(int64(vq),index))
  333. else
  334. begin
  335. // determine minimum needed number of hex digits.
  336. Index:=1;
  337. While (qWord(1) shl (Index*4)<=vq) and (index<16) do
  338. inc(Index);
  339. If Index>Prec then
  340. Prec:=Index;
  341. ToAdd:=TFormatString(HexStr(int64(vq),Prec));
  342. end;
  343. end;
  344. '%': ToAdd:='%';
  345. end;
  346. If Width<>-1 then
  347. If Length(ToAdd)<Width then
  348. If not Left then
  349. ToAdd:=TFormatString(Space(Width-Length(ToAdd)))+ToAdd
  350. else
  351. ToAdd:=ToAdd+TFormatString(space(Width-Length(ToAdd)));
  352. Result:=Result+ToAdd;
  353. end;
  354. inc(ChPos);
  355. Oldpos:=ChPos;
  356. end;
  357. end;