1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
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. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE a_modes.inc}
18 interface
20 uses
24 // ////////////////////////////////////////////////////////////////////////// //
25 type
36 '.dfzip'
37 );
40 // ////////////////////////////////////////////////////////////////////////// //
41 type
43 public
48 private
51 public
54 public
63 // process one byte, return `true` if codepoint is ready
69 // ////////////////////////////////////////////////////////////////////////// //
74 // rewrites slashes to '/'
77 // replaces all the shitty characters with '_'
78 // (everything except alphanumerics, '_', '.')
84 // strips out name from `fn`, leaving trailing slash
87 // ends with '/' or '\'?
90 // strips extra trailing slashes in `path, and extra leading slashes in `fn`
91 // will add slash to `path`, even if `fn` is empty!
94 // does filename have one of ".wad", ".pk3", ".zip" extensions?
97 // does filepath have ".XXX:\" in it?
100 // adds ".wad" extension if filename doesn't have one of ".wad", ".pk3", ".zip"
103 // check wad signature
106 // convert number to strig with nice commas
116 // `true` if strings are equal; ignoring case for cp1251
123 // findFileCI takes case-insensitive path, traverses it, and rewrites it to
124 // a case-sensetive one (using real on-disk names). return value means 'success'.
125 // if some dir or file wasn't found, pathname is undefined (destroyed, but not
126 // necessarily cleared).
127 // last name assumed to be a file, not directory (unless `lastIsDir` flag is set).
130 // findDiskWad tries to find the wad file using common wad extensions
131 // (see `wadExtensions` array).
132 // returns real on-disk filename, or empty string.
133 // original wad extension is used as a hint for the first try.
134 // also, this automatically performs `findFileCI()`.
136 // slashes must be normalized!
139 // they throws
142 // create file if necessary, but don't truncate the existing one
145 // little endian
173 // big endian
203 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
205 {$ENDIF}
217 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
219 {$ENDIF}
230 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
232 {$ENDIF}
234 type
237 // returns formatted string if `writerCB` is `nil`, empty string otherwise
238 function formatstrf (const fmt: AnsiString; const args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
245 // returns string in single or double quotes
246 // single quotes supports only pascal-style '' for single quote char
247 // double quotes supports c-style escapes
248 // function will select quote mode automatically
250 // separate single-quote and double-quote escape functions
255 type
257 private
258 //type PItemT = ^ItemT;
261 public
262 type
264 private
268 public
275 private
279 private
286 public
290 //WARNING! don't change list contents in `for ... in`!
300 public
312 type
317 // not changed by info getter; used in other parts of the code
327 implementation
329 uses
330 xstreams;
332 // ////////////////////////////////////////////////////////////////////////// //
334 begin
339 begin
344 begin
349 // ////////////////////////////////////////////////////////////////////////// //
350 // rewrites slashes to '/'
352 {$IFDEF WINDOWS}
353 var
355 {$ENDIF}
356 begin
358 {$IFDEF WINDOWS}
360 {$ENDIF}
363 // replaces all the shitty characters with '_'
364 // (everything except alphanumerics, '_', '.')
366 var
368 const
371 begin
379 begin
382 {$IFDEF WINDOWS}
384 if (length(s) > 2) and (s[2] = ':') and ((s[3] = '/') or (s[3] = '\')) then begin result := true; exit; end;
385 {$ELSE}
387 {$ENDIF}
392 begin
395 {$IFDEF WINDOWS}
397 if (length(s) = 3) and (s[2] = ':') and ((s[3] = '/') or (s[3] = '\')) then begin result := true; exit; end;
398 {$ELSE}
400 {$ENDIF}
404 // ////////////////////////////////////////////////////////////////////////// //
406 begin
413 begin
419 begin
424 // ////////////////////////////////////////////////////////////////////////// //
426 begin
434 begin
441 begin
447 begin
454 begin
461 begin
467 begin
474 begin
480 begin
486 var
488 begin
490 begin
500 var
502 begin
504 begin
511 var
513 begin
515 begin
518 end
519 else
520 begin
526 // ////////////////////////////////////////////////////////////////////////// //
527 var
532 // ////////////////////////////////////////////////////////////////////////// //
533 const
535 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
536 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$FFFD,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
537 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
538 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
539 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
540 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
541 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
543 );
547 var
549 begin
557 // ////////////////////////////////////////////////////////////////////////// //
558 // fast state-machine based UTF-8 decoder; using 8 bytes of memory
559 // code points from invalid range will never be valid, this is the property of the state machine
560 const
561 // see http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
563 // maps bytes to character classes
580 // maps a combination of a state of the automaton and a character class to a state
590 // ////////////////////////////////////////////////////////////////////////// //
591 constructor TUtf8DecoderFast.Create (v: Boolean{fuck you, fpc}); begin state := Accept; codepoint := 0; end;
597 function TUtf8DecoderFast.completeOrInvalid (): Boolean; inline; begin result := (state = Accept) or (state = Reject); end;
599 function TUtf8DecoderFast.decode (c: AnsiChar): Boolean; inline; overload; begin result := decode(Byte(c)); end;
602 var
604 begin
607 if (state <> Accept) then codepoint := (b and $3f) or (codepoint shl 6) else codepoint := ($ff shr tp) and b;
614 // ////////////////////////////////////////////////////////////////////////// //
616 begin
622 // ////////////////////////////////////////////////////////////////////////// //
624 var
627 begin
629 begin
631 begin
635 begin
638 exit;
646 var
650 begin
653 begin
655 end
657 begin
660 end
662 begin
666 end
668 begin
673 end
674 else
675 begin
680 begin
682 begin
684 begin
687 begin
689 begin
691 end
692 else
693 begin
697 exit;
704 // ////////////////////////////////////////////////////////////////////////// //
706 begin
711 begin
714 end
715 else
716 begin
725 // ////////////////////////////////////////////////////////////////////////// //
727 var
729 begin
732 begin
740 var
743 begin
746 begin
754 begin
757 end
759 begin
762 end
763 else
764 begin
772 var
775 begin
777 begin
785 // ////////////////////////////////////////////////////////////////////////// //
787 var
790 begin
793 begin
796 begin
798 exit;
808 var
811 begin
816 begin
828 var
831 begin
835 begin
838 begin
840 begin
842 end
843 else
844 begin
847 exit;
854 begin
861 // strips out name from `fn`, leaving trailing slash
863 var
866 begin
871 begin
880 // ends with '/' or '\'?
882 begin
884 begin
886 end
887 else
888 begin
894 // strips extra trailing slashes in `path, and extra leading slashes in `fn`
895 // will add slash to `path`, even if `fn` is empty!
897 var
899 begin
903 if (Length(result) > 0) and ((result[Length(result)] <> '/') and (result[Length(result)] <> '\')) then result += '/';
905 begin
907 //FIXME: make this faster!
908 while (Length(result) > 0) and ((result[Length(result)] = '/') or (result[Length(result)] = '\')) do
909 begin
918 var
920 begin
925 //result := StrEquCI1251(ext, '.wad') or StrEquCI1251(ext, '.pk3') or StrEquCI1251(ext, '.zip') or StrEquCI1251(ext, '.dfz');
930 begin
938 begin
940 Result :=
941 (* ZIP *)
944 (* PACK *)
947 (* DFWAD *)
948 ((len > 5) and (p[0] = 'D') and (p[1] = 'F') and (p[2] = 'W') and (p[3] = 'A') and (p[4] = 'D') and (p[5] = #01))
953 var
956 begin
960 begin
962 begin
965 begin
968 begin
970 begin
972 exit;
983 var
985 begin
989 begin
996 begin
998 begin
1000 end
1001 else
1002 begin
1004 begin
1006 end
1007 else
1008 begin
1020 begin
1022 begin
1024 end
1025 else
1026 begin
1028 begin
1030 end
1031 else
1032 begin
1043 begin
1048 begin
1054 var
1056 begin
1065 var
1068 begin
1070 begin
1072 begin
1076 exit;
1079 // nothing to do
1084 // ////////////////////////////////////////////////////////////////////////// //
1085 // utils
1086 // `ch`: utf8 start
1087 // -1: invalid utf8
1089 begin
1101 var
1103 begin
1107 begin
1113 // check other sequence bytes
1115 begin
1125 // ////////////////////////////////////////////////////////////////////////// //
1126 const
1128 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
1129 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
1130 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
1131 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
1132 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
1133 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
1134 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
1135 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
1136 );
1140 var
1142 begin
1143 (* The following encodings are valid, except for the 5 and 6 byte
1144 * combinations:
1145 * 0xxxxxxx
1146 * 110xxxxx 10xxxxxx
1147 * 1110xxxx 10xxxxxx 10xxxxxx
1148 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1149 * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1150 * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1151 *)
1159 // mask out unused bits
1167 // now continue
1169 begin
1177 // done, try 1251
1179 // alas
1184 var
1186 begin
1190 begin
1201 // ////////////////////////////////////////////////////////////////////////// //
1202 // findFileCI eats case-insensitive path, traverses it and rewrites it to a
1203 // case-sensetive. result value means success.
1204 // if file/dir not founded than pathname is in undefined state!
1206 var
1214 begin
1219 begin
1220 // remove trailing slashes
1223 // extract name
1226 begin
1230 // remove trailing slashes again
1233 //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
1234 // try the easiest case first
1237 begin
1239 begin
1240 // i found her!
1243 continue;
1246 //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
1247 // alas, either not found, or invalid attributes
1249 try
1251 repeat
1253 begin
1254 // i found her!
1258 break;
1261 finally
1271 var
1274 begin
1277 // check first ext
1280 for newExt in wadExtensions do if (StrEquCI1251(ext, newExt)) then begin found := true; break; end;
1282 // check second ext
1285 for newExt in wadExtensions do if (StrEquCI1251(ext, newExt)) then begin found := true; break; end;
1293 var
1296 begin
1298 //writeln('findDiskWad00: fname=<', fname, '>');
1302 //writeln(' findDiskWad01: fname=<', fname, '>; origExt=<', origExt, '>');
1304 begin
1305 //writeln(' findDiskWad02: fname=<', fname, '>; origExt=<', origExt, '>; newExt=<', newExt, '>');
1307 begin
1308 //writeln(' SKIP');
1309 continue;
1319 begin
1320 if not findFileCI(pathname) then raise EFileNotFoundException.Create('can''t open file "'+pathname+'"');
1325 var
1327 begin
1330 begin
1331 if not findFileCI(path, true) then raise Exception.Create('can''t create file "'+pathname+'"');
1338 var
1341 begin
1342 //writeln('*** TRYING R/W FILE "', pathname, '"');
1345 begin
1346 if not findFileCI(path, true) then raise Exception.Create('can''t create file "'+pathname+'"');
1350 begin
1351 //writeln('*** found old file "', oldname, '"');
1353 end
1354 else
1355 begin
1362 {$IFDEF ENDIAN_LITTLE}
1363 begin
1366 {$ELSE}
1367 var
1369 begin
1372 begin
1378 {$ENDIF}
1381 {$IFDEF ENDIAN_LITTLE}
1382 var
1384 begin
1387 begin
1393 {$ELSE}
1394 begin
1397 {$ENDIF}
1400 begin
1405 var
1408 begin
1411 begin
1413 begin
1416 end
1417 else
1418 begin
1420 begin
1439 procedure writeIntBE (st: TStream; v: ShortInt); overload; begin writeIntegerBE(st, @v, 1); end;
1441 procedure writeIntBE (st: TStream; v: SmallInt); overload; begin writeIntegerBE(st, @v, 2); end;
1442 procedure writeIntBE (st: TStream; v: LongWord); overload; begin writeIntegerBE(st, @v, 4); end;
1443 procedure writeIntBE (st: TStream; v: LongInt); overload; begin writeIntegerBE(st, @v, 4); end;
1452 begin
1454 if (maxlen <= 65535) then writeInt(st, Word(Length(str))) else writeInt(st, LongWord(Length(str)));
1459 var
1461 begin
1466 begin
1474 {$IFDEF ENDIAN_LITTLE}
1475 begin
1478 {$ELSE}
1479 var
1481 begin
1484 begin
1490 {$ENDIF}
1493 {$IFDEF ENDIAN_LITTLE}
1494 var
1496 begin
1499 begin
1505 {$ELSE}
1506 begin
1509 {$ENDIF}
1530 // ////////////////////////////////////////////////////////////////////////// //
1531 function nmin (a, b: Byte): Byte; inline; overload; begin if (a < b) then result := a else result := b; end;
1532 function nmin (a, b: ShortInt): ShortInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1533 function nmin (a, b: Word): Word; inline; overload; begin if (a < b) then result := a else result := b; end;
1534 function nmin (a, b: SmallInt): SmallInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1535 function nmin (a, b: LongWord): LongWord; inline; overload; begin if (a < b) then result := a else result := b; end;
1536 function nmin (a, b: LongInt): LongInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1537 function nmin (a, b: Int64): Int64; inline; overload; begin if (a < b) then result := a else result := b; end;
1538 function nmin (a, b: UInt64): UInt64; inline; overload; begin if (a < b) then result := a else result := b; end;
1539 function nmin (a, b: Single): Single; inline; overload; begin if (a < b) then result := a else result := b; end;
1540 function nmin (a, b: Double): Double; inline; overload; begin if (a < b) then result := a else result := b; end;
1541 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1542 function nmin (a, b: Extended): Extended; inline; overload; begin if (a < b) then result := a else result := b; end;
1543 {$ENDIF}
1545 function nmax (a, b: Byte): Byte; inline; overload; begin if (a > b) then result := a else result := b; end;
1546 function nmax (a, b: ShortInt): ShortInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1547 function nmax (a, b: Word): Word; inline; overload; begin if (a > b) then result := a else result := b; end;
1548 function nmax (a, b: SmallInt): SmallInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1549 function nmax (a, b: LongWord): LongWord; inline; overload; begin if (a > b) then result := a else result := b; end;
1550 function nmax (a, b: LongInt): LongInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1551 function nmax (a, b: Int64): Int64; inline; overload; begin if (a > b) then result := a else result := b; end;
1552 function nmax (a, b: UInt64): UInt64; inline; overload; begin if (a > b) then result := a else result := b; end;
1553 function nmax (a, b: Single): Single; inline; overload; begin if (a > b) then result := a else result := b; end;
1554 function nmax (a, b: Double): Double; inline; overload; begin if (a > b) then result := a else result := b; end;
1555 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1556 function nmax (a, b: Extended): Extended; inline; overload; begin if (a > b) then result := a else result := b; end;
1557 {$ENDIF}
1559 function nclamp (v, a, b: Byte): Byte; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1560 function nclamp (v, a, b: ShortInt): ShortInt; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1561 function nclamp (v, a, b: Word): Word; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1562 function nclamp (v, a, b: SmallInt): SmallInt; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1563 function nclamp (v, a, b: LongWord): LongWord; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1564 function nclamp (v, a, b: LongInt): LongInt; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1565 function nclamp (v, a, b: Int64): Int64; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1566 function nclamp (v, a, b: UInt64): UInt64; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1567 function nclamp (v, a, b: Single): Single; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1568 function nclamp (v, a, b: Double): Double; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1569 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1570 function nclamp (v, a, b: Extended): Extended; inline; overload; begin if (v < a) then result := a else if (v > b) then result := b else result := v; end;
1571 {$ENDIF}
1573 // ////////////////////////////////////////////////////////////////////////// //
1574 {$IFDEF WINDOWS}
1575 function snprintf (buf: PAnsiChar; bufsize: SizeUInt; const fmt: PAnsiChar): SizeUInt; cdecl; varargs; external 'msvcrt.dll' name '_snprintf';
1576 {$ELSE}
1577 function snprintf (buf: PAnsiChar; bufsize: SizeUInt; const fmt: PAnsiChar): SizeUInt; cdecl; varargs; external 'libc' name 'snprintf';
1578 {$ENDIF}
1581 (*
1582 procedure conwriter (constref buf; len: SizeUInt);
1583 var
1584 ss: ShortString;
1585 slen: Integer;
1586 b: PByte;
1587 begin
1588 if (len < 1) then exit;
1589 b := PByte(@buf);
1590 while (len > 0) do
1591 begin
1592 if (len > 255) then slen := 255 else slen := Integer(len);
1593 Move(b^, ss[1], len);
1594 ss[0] := AnsiChar(slen);
1595 write(ss);
1596 b += slen;
1597 len -= slen;
1598 end;
1599 end;
1600 *)
1603 function formatstrf (const fmt: AnsiString; const args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
1604 const
1606 PadZeroes: AnsiString = '00000000000000000000000000000000000000000000000000000000000000000000000';
1607 var
1623 var
1627 begin
1631 begin
1633 end
1634 else
1635 begin
1637 begin
1649 begin
1654 begin
1660 var
1662 begin
1668 var
1670 begin
1676 begin
1680 begin
1690 begin
1695 var
1698 begin
1700 begin
1704 end
1705 else
1706 begin
1711 repeat
1713 begin
1717 end
1718 else
1719 begin
1721 begin
1724 end
1736 var
1738 begin
1741 repeat
1743 begin
1747 end
1748 else
1749 begin
1751 begin
1754 end
1764 var
1766 begin
1768 begin
1776 var
1778 begin
1780 begin
1787 begin
1791 begin
1792 // print literal part
1795 // output literal part
1797 begin
1799 begin
1801 break;
1805 begin
1809 end
1810 else
1811 begin
1815 continue;
1817 // check if we have argument for this format string
1819 begin
1822 break;
1824 // skip percent
1828 // parse format; check for sign
1832 // parse width
1835 begin
1836 if (fmt[spos] < '0') or (fmt[spos] > '9') then begin xwrite('<INVALID FORMAT>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1840 begin
1846 end
1847 else
1848 begin
1852 // parse precision
1855 begin
1858 if (fmt[spos] < '0') or (fmt[spos] > '9') then begin xwrite('<INVALID FORMAT>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1861 begin
1868 // get format char
1872 // done parsing format, check for valid format chars
1873 if not (fmtch in ['s','u','d','x','X','p','f','g','c']) then begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1874 // now write formatted string
1877 begin
1878 if not (fmtch in ['s','u','d','x','X']) then begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1887 begin
1889 if args[curarg].VBoolean then strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], 'true')
1894 begin
1896 if args[curarg].VBoolean then strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], AnsiChar('t'))
1901 begin
1906 else
1907 begin
1910 break;
1916 begin
1923 begin
1928 else
1929 begin
1932 break;
1935 //vtWideChar: begin end; // args[curarg].VWideChar (WideChar)
1939 begin
1946 begin
1952 begin
1954 strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], Integer(trunc(args[curarg].VExtended^)));
1958 begin
1960 strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], LongWord(trunc(args[curarg].VExtended^)));
1963 else
1964 begin
1967 break;
1971 begin
1979 begin
1988 begin
1996 else
1997 begin
2000 break;
2005 begin
2009 end
2010 else
2011 begin
2019 begin
2020 if (args[curarg].VObject <> nil) then ccname := args[curarg].VObject.Classname else ccname := '<nil>';
2026 begin
2027 if (args[curarg].VClass <> nil) then ccname := args[curarg].VClass.Classname else ccname := '<nil>';
2032 //vtPWideChar: begin end; // args[curarg].VPWideChar (PWideChar)
2034 begin
2039 //vtCurrency: begin end; // args[curarg].VCurrency (PCurrency)
2040 //vtVariant: begin end; // args[curarg].VVariant^ (PVariant)
2041 //vtInterface: begin end; // args[curarg].VInterface (Pointer);
2042 //vtWideString: begin end; // args[curarg].VWideString (Pointer);
2044 begin
2049 else begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
2054 begin
2056 begin
2058 begin
2063 end
2064 else
2065 begin
2068 end
2069 else
2070 begin
2078 begin
2083 else begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
2087 if (sign <> '-') then begin if zeropad then indent0(width-pclen) else indent(width-pclen); end;
2091 else
2092 begin
2095 break;
2104 var
2108 begin
2112 // get age
2115 // get size
2121 // fill info
2129 (*
2130 var
2131 ss: ShortString;
2132 ls: AnsiString;
2133 i64: Int64 = -$A000000000;
2134 ui64: UInt64 = $A000000000;
2135 begin
2136 writef(conwriter, 'test int:<%s> bool:<%s:%02d:%c> bool:<%s:%02d:%c>; char:<%2s;%c;%d>!'#10, [42, true, true, true, false, false, false, 'A', 'A', 'A']);
2137 writef(conwriter, 'test float:<%s;%u;%f;%g>'#10, [666.6942, 666.6942, 666.6942, 666.6942]);
2138 ss := 'fuckit';
2139 ls := 'FUCKIT';
2140 writef(conwriter, 'test ss:<%5s;%040s>'#10, [ss, ss]);
2141 writef(conwriter, 'test ls:<%5s;%040s>'#10, [ls, ls]);
2142 writef(conwriter, 'test pointer:<%s;%x;%p>'#10, [@ss, @ss, @ss]);
2143 writef(conwriter, 'test i64:<%s;%x;%015d;%u;%X>'#10, [i64, i64, i64, i64, i64]);
2144 writef(conwriter, 'test ui64:<%s;%x;%15d;%015u;%X>'#10, [ui64, ui64, ui64, ui64, ui64]);
2145 *)