sysformt.inc 12 KB

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