sysformt.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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 : TFormatChar;
  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 : TFormatChar;
  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 : TFormatChar);
  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. 'B' : begin
  230. if Checkarg(vtInteger,False) then
  231. ToAdd:=BoolToStr((Args[Doarg].VInteger<>0),True)
  232. else if Checkarg(vtInt64,False) then
  233. ToAdd:=BoolToStr((Args[Doarg].VInt64^<>0),True)
  234. else if Checkarg(vtBoolean,True) then
  235. ToAdd:=BoolToStr(Args[Doarg].VBoolean,True);
  236. Index:=Length(ToAdd);
  237. // Top off
  238. If (Prec<>-1) and (Index>Prec) then
  239. begin
  240. Index:=Prec;
  241. ToAdd:=Copy(ToAdd,1,Index);
  242. end;
  243. end;
  244. 'D' : begin
  245. if Checkarg(vtinteger,false) then
  246. Str(Args[Doarg].VInteger,ToAdd)
  247. else if CheckArg(vtInt64,false) then
  248. Str(Args[DoArg].VInt64^,toadd)
  249. else if CheckArg(vtQWord,true) then
  250. Str(int64(Args[DoArg].VQWord^),toadd);
  251. Width:=Abs(width);
  252. Index:=Prec-Length(ToAdd);
  253. If ToAdd[1]<>'-' then
  254. ToAdd:=TFormatString(StringOfChar('0',Index))+ToAdd
  255. else
  256. // + 1 to accomodate for - sign in length !!
  257. Insert(TFormatString(StringOfChar('0',Index+1)),toadd,2);
  258. end;
  259. 'U' : begin
  260. if Checkarg(vtinteger,false) then
  261. Str(cardinal(Args[Doarg].VInteger),ToAdd)
  262. else if CheckArg(vtInt64,false) then
  263. Str(qword(Args[DoArg].VInt64^),toadd)
  264. else if CheckArg(vtQWord,true) then
  265. Str(Args[DoArg].VQWord^,toadd);
  266. Width:=Abs(width);
  267. Index:=Prec-Length(ToAdd);
  268. ToAdd:=TFormatString(StringOfChar('0',Index))+ToAdd
  269. end;
  270. {$ifndef FPUNONE}
  271. 'E' : begin
  272. if CheckArg(vtCurrency,false) then
  273. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffexponent,Prec,3,FormatSettings))
  274. else if CheckArg(vtExtended,true) then
  275. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffexponent,Prec,3,FormatSettings));
  276. end;
  277. 'F' : begin
  278. if CheckArg(vtCurrency,false) then
  279. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffFixed,9999,Prec,FormatSettings))
  280. else if CheckArg(vtExtended,true) then
  281. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffFixed,9999,Prec,FormatSettings));
  282. end;
  283. 'G' : begin
  284. if CheckArg(vtCurrency,false) then
  285. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffGeneral,Prec,3,FormatSettings))
  286. else if CheckArg(vtExtended,true) then
  287. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffGeneral,Prec,3,FormatSettings));
  288. end;
  289. 'N' : begin
  290. if CheckArg(vtCurrency,false) then
  291. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffNumber,9999,Prec,FormatSettings))
  292. else if CheckArg(vtExtended,true) then
  293. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffNumber,9999,Prec,FormatSettings));
  294. end;
  295. 'M' : begin
  296. if CheckArg(vtExtended,false) then
  297. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VExtended^,ffCurrency,9999,Prec,FormatSettings))
  298. else if CheckArg(vtCurrency,true) then
  299. ToAdd:=TFormatString(FloatToStrF(Args[doarg].VCurrency^,ffCurrency,9999,Prec,FormatSettings));
  300. end;
  301. {$else}
  302. 'E','F','G','N','M':
  303. RunError(207);
  304. {$endif}
  305. 'S' : begin
  306. if CheckArg(vtString,false) then
  307. hs:=TFormatString(Args[doarg].VString^)
  308. else
  309. if CheckArg(vtChar,false) then
  310. hs:=TFormatString(Args[doarg].VChar)
  311. else
  312. if CheckArg(vtPChar,false) then
  313. hs:=TFormatString(Args[doarg].VPChar)
  314. else
  315. if CheckArg(vtPWideChar,false) then
  316. hs:=TFormatString(WideString(Args[doarg].VPWideChar))
  317. else
  318. if CheckArg(vtWideChar,false) then
  319. hs:=TFormatString(WideString(Args[doarg].VWideChar))
  320. else
  321. if CheckArg(vtWidestring,false) then
  322. hs:=TFormatString(WideString(Args[doarg].VWideString))
  323. else
  324. if CheckArg(vtAnsiString,false) then
  325. hs:=TFormatString(ansistring(Args[doarg].VAnsiString))
  326. else
  327. if CheckArg(vtUnicodeString,false) then
  328. hs:=TFormatString(UnicodeString(Args[doarg].VUnicodeString))
  329. else
  330. if CheckArg(vtVariant,true) then
  331. hs:=Args[doarg].VVariant^;
  332. Index:=Length(hs);
  333. If (Prec<>-1) and (Index>Prec) then
  334. Index:=Prec;
  335. ToAdd:=Copy(hs,1,Index);
  336. end;
  337. 'P' : Begin
  338. CheckArg(vtpointer,true);
  339. ToAdd:=TFormatString(HexStr(ptruint(Args[DoArg].VPointer),sizeof(Ptruint)*2));
  340. // Insert ':'. Is this needed in 32 bit ? No it isn't.
  341. // Insert(':',ToAdd,5);
  342. end;
  343. 'X' : begin
  344. if Checkarg(vtinteger,false) then
  345. begin
  346. vq:=Cardinal(Args[Doarg].VInteger);
  347. index:=16;
  348. end
  349. else
  350. if CheckArg(vtQWord, false) then
  351. begin
  352. vq:=Qword(Args[DoArg].VQWord^);
  353. index:=31;
  354. end
  355. else
  356. begin
  357. CheckArg(vtInt64,true);
  358. vq:=Qword(Args[DoArg].VInt64^);
  359. index:=31;
  360. end;
  361. If Prec>index then
  362. ToAdd:=TFormatString(HexStr(int64(vq),index))
  363. else
  364. begin
  365. // determine minimum needed number of hex digits.
  366. Index:=1;
  367. While (qWord(1) shl (Index*4)<=vq) and (index<16) do
  368. inc(Index);
  369. If Index>Prec then
  370. Prec:=Index;
  371. ToAdd:=TFormatString(HexStr(int64(vq),Prec));
  372. end;
  373. end;
  374. '%': ToAdd:='%';
  375. end;
  376. If Width<>-1 then
  377. If Length(ToAdd)<Width then
  378. If not Left then
  379. ToAdd:=TFormatString(Space(Width-Length(ToAdd)))+ToAdd
  380. else
  381. ToAdd:=ToAdd+TFormatString(space(Width-Length(ToAdd)));
  382. Result:=Result+ToAdd;
  383. end;
  384. inc(ChPos);
  385. Oldpos:=ChPos;
  386. end;
  387. end;