sysformt.inc 12 KB

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