5ef58845df0057b088866ef616bbf1e1f6b3ebcf
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
29 // ////////////////////////////////////////////////////////////////////////// //
30 type
32 public
37 private
40 public
43 public
52 // process one byte, return `true` if codepoint is ready
58 // ////////////////////////////////////////////////////////////////////////// //
63 // strips out name from `fn`, leaving trailing slash
66 // ends with '/' or '\'?
69 // strips extra trailing slashes in `path, and extra leading slashes in `fn`
70 // will add slash to `path`, even if `fn` is empty!
73 // does filename have one of ".wad", ".pk3", ".zip" extensions?
76 // does filepath have ".XXX:\" in it?
79 // adds ".wad" extension if filename doesn't have one of ".wad", ".pk3", ".zip"
82 // check wad signature
85 // convert number to strig with nice commas
93 // `true` if strings are equal; ignoring case for cp1251
100 // `pathname` will be modified if path is valid
101 // `lastIsDir` should be `true` if we are searching for directory
102 // nobody cares about shitdoze, so i'll use the same code path for it
105 // return fixed AnsiString or empty AnsiString
107 // slashes must be normalized!
110 // they throws
113 // creates file if necessary
116 // little endian
144 // big endian
174 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
176 {$ENDIF}
188 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
190 {$ENDIF}
201 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
203 {$ENDIF}
205 type
208 // returns formatted string if `writerCB` is `nil`, empty string otherwise
209 function formatstrf (const fmt: AnsiString; const args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
216 // returns string in single or double quotes
217 // single quotes supports only pascal-style '' for single quote char
218 // double quotes supports c-style escapes
219 // function will select quote mode automatically
223 type
225 private
226 //type PItemT = ^ItemT;
229 public
230 type
232 private
236 public
243 private
247 private
254 public
258 //WARNING! don't change list contents in `for ... in`!
268 public
280 implementation
282 uses
283 xstreams;
292 '.dfzip'
293 );
296 // ////////////////////////////////////////////////////////////////////////// //
298 begin
303 begin
308 begin
313 // ////////////////////////////////////////////////////////////////////////// //
315 begin
322 begin
328 begin
333 // ////////////////////////////////////////////////////////////////////////// //
335 begin
343 begin
350 begin
356 begin
363 begin
370 begin
376 begin
383 begin
389 begin
395 var
397 begin
399 begin
409 var
411 begin
413 begin
420 var
422 begin
424 begin
427 end
428 else
429 begin
435 // ////////////////////////////////////////////////////////////////////////// //
436 var
441 // ////////////////////////////////////////////////////////////////////////// //
442 const
444 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
445 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
446 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
447 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
448 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
449 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
450 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
452 );
456 var
458 begin
466 // ////////////////////////////////////////////////////////////////////////// //
467 // fast state-machine based UTF-8 decoder; using 8 bytes of memory
468 // code points from invalid range will never be valid, this is the property of the state machine
469 const
470 // see http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
472 // maps bytes to character classes
489 // maps a combination of a state of the automaton and a character class to a state
499 // ////////////////////////////////////////////////////////////////////////// //
500 constructor TUtf8DecoderFast.Create (v: Boolean{fuck you, fpc}); begin state := Accept; codepoint := 0; end;
506 function TUtf8DecoderFast.completeOrInvalid (): Boolean; inline; begin result := (state = Accept) or (state = Reject); end;
508 function TUtf8DecoderFast.decode (c: AnsiChar): Boolean; inline; overload; begin result := decode(Byte(c)); end;
511 var
513 begin
516 if (state <> Accept) then codepoint := (b and $3f) or (codepoint shl 6) else codepoint := ($ff shr tp) and b;
523 // ////////////////////////////////////////////////////////////////////////// //
525 begin
531 // ////////////////////////////////////////////////////////////////////////// //
533 var
536 begin
538 begin
540 begin
544 begin
547 exit;
555 var
559 begin
562 begin
564 end
566 begin
569 end
571 begin
575 end
577 begin
582 end
583 else
584 begin
589 begin
591 begin
593 begin
596 begin
598 begin
600 end
601 else
602 begin
606 exit;
613 // ////////////////////////////////////////////////////////////////////////// //
615 begin
620 begin
623 end
624 else
625 begin
634 // ////////////////////////////////////////////////////////////////////////// //
638 var
640 begin
643 begin
651 var
654 begin
657 begin
665 begin
668 end
670 begin
673 end
674 else
675 begin
682 var
685 begin
687 begin
695 // ////////////////////////////////////////////////////////////////////////// //
697 var
700 begin
703 begin
706 begin
708 exit;
718 var
721 begin
726 begin
738 var
741 begin
745 begin
748 begin
750 begin
752 end
753 else
754 begin
757 exit;
764 begin
771 // strips out name from `fn`, leaving trailing slash
773 var
776 begin
781 begin
790 // ends with '/' or '\'?
792 begin
794 begin
796 end
797 else
798 begin
804 // strips extra trailing slashes in `path, and extra leading slashes in `fn`
805 // will add slash to `path`, even if `fn` is empty!
807 var
809 begin
813 if (Length(result) > 0) and ((result[Length(result)] <> '/') and (result[Length(result)] <> '\')) then result += '/';
815 begin
817 //FIXME: make this faster!
818 while (Length(result) > 0) and ((result[Length(result)] = '/') or (result[Length(result)] = '\')) do
819 begin
828 var
830 begin
835 //result := StrEquCI1251(ext, '.wad') or StrEquCI1251(ext, '.pk3') or StrEquCI1251(ext, '.zip') or StrEquCI1251(ext, '.dfz');
840 begin
848 begin
850 Result :=
851 (* ZIP *)
854 (* PACK *)
857 (* DFWAD *)
858 ((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))
863 var
866 begin
870 begin
872 begin
875 begin
877 if StrEquCI1251(s, '.wad') or StrEquCI1251(s, '.pk3') or StrEquCI1251(s, '.zip') or StrEquCI1251(s, '.dfz') then
878 begin
880 exit;
890 var
892 begin
896 begin
903 begin
905 begin
907 end
908 else
909 begin
911 begin
913 end
914 else
915 begin
927 begin
929 begin
931 end
932 else
933 begin
935 begin
937 end
938 else
939 begin
951 var
953 begin
962 var
965 begin
967 begin
969 begin
973 exit;
976 // nothing to do
981 // ////////////////////////////////////////////////////////////////////////// //
982 // utils
983 // `ch`: utf8 start
984 // -1: invalid utf8
986 begin
998 var
1000 begin
1004 begin
1010 // check other sequence bytes
1012 begin
1022 // ////////////////////////////////////////////////////////////////////////// //
1023 const
1025 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
1026 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
1027 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
1028 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
1029 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
1030 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
1031 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
1032 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
1033 );
1037 var
1039 begin
1040 (* The following encodings are valid, except for the 5 and 6 byte
1041 * combinations:
1042 * 0xxxxxxx
1043 * 110xxxxx 10xxxxxx
1044 * 1110xxxx 10xxxxxx 10xxxxxx
1045 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1046 * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1047 * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1048 *)
1056 // mask out unused bits
1064 // now continue
1066 begin
1074 // done, try 1251
1076 // alas
1081 var
1083 begin
1087 begin
1098 // ////////////////////////////////////////////////////////////////////////// //
1099 // `pathname` will be modified if path is valid
1100 // `lastIsDir` should be `true` if we are searching for directory
1101 // nobody cares about shitdoze, so i'll use the same code path for it
1103 var
1111 begin
1116 begin
1117 // remove trailing slashes
1120 // extract name
1123 begin
1127 // remove trailing slashes again
1130 //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
1131 // try the easiest case first
1134 begin
1136 begin
1137 // i found her!
1140 continue;
1143 //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
1144 // alas, either not found, or invalid attributes
1146 try
1148 repeat
1150 begin
1151 // i found her!
1155 break;
1158 finally
1168 var
1171 begin
1174 // check first ext
1177 for newExt in wadExtensions do if (StrEquCI1251(ext, newExt)) then begin found := true; break; end;
1179 // check second ext
1182 for newExt in wadExtensions do if (StrEquCI1251(ext, newExt)) then begin found := true; break; end;
1190 var
1193 begin
1195 //writeln('findDiskWad00: fname=<', fname, '>');
1199 //writeln(' findDiskWad01: fname=<', fname, '>; origExt=<', origExt, '>');
1201 begin
1202 //writeln(' findDiskWad02: fname=<', fname, '>; origExt=<', origExt, '>; newExt=<', newExt, '>');
1204 begin
1205 //writeln(' SKIP');
1206 continue;
1216 begin
1217 if not findFileCI(pathname) then raise EFileNotFoundException.Create('can''t open file "'+pathname+'"');
1222 var
1224 begin
1227 begin
1228 if not findFileCI(path, true) then raise Exception.Create('can''t create file "'+pathname+'"');
1235 var
1238 begin
1239 //writeln('*** TRYING R/W FILE "', pathname, '"');
1242 begin
1243 if not findFileCI(path, true) then raise Exception.Create('can''t create file "'+pathname+'"');
1247 begin
1248 //writeln('*** found old file "', oldname, '"');
1250 end
1251 else
1252 begin
1259 {$IFDEF ENDIAN_LITTLE}
1260 begin
1263 {$ELSE}
1264 var
1266 begin
1269 begin
1275 {$ENDIF}
1278 {$IFDEF ENDIAN_LITTLE}
1279 var
1281 begin
1284 begin
1290 {$ELSE}
1291 begin
1294 {$ENDIF}
1297 begin
1302 var
1305 begin
1308 begin
1310 begin
1313 end
1314 else
1315 begin
1317 begin
1336 procedure writeIntBE (st: TStream; v: ShortInt); overload; begin writeIntegerBE(st, @v, 1); end;
1338 procedure writeIntBE (st: TStream; v: SmallInt); overload; begin writeIntegerBE(st, @v, 2); end;
1339 procedure writeIntBE (st: TStream; v: LongWord); overload; begin writeIntegerBE(st, @v, 4); end;
1340 procedure writeIntBE (st: TStream; v: LongInt); overload; begin writeIntegerBE(st, @v, 4); end;
1349 begin
1351 if (maxlen <= 65535) then writeInt(st, Word(Length(str))) else writeInt(st, LongWord(Length(str)));
1356 var
1358 begin
1363 begin
1371 {$IFDEF ENDIAN_LITTLE}
1372 begin
1375 {$ELSE}
1376 var
1378 begin
1381 begin
1387 {$ENDIF}
1390 {$IFDEF ENDIAN_LITTLE}
1391 var
1393 begin
1396 begin
1402 {$ELSE}
1403 begin
1406 {$ENDIF}
1427 // ////////////////////////////////////////////////////////////////////////// //
1428 function nmin (a, b: Byte): Byte; inline; overload; begin if (a < b) then result := a else result := b; end;
1429 function nmin (a, b: ShortInt): ShortInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1430 function nmin (a, b: Word): Word; inline; overload; begin if (a < b) then result := a else result := b; end;
1431 function nmin (a, b: SmallInt): SmallInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1432 function nmin (a, b: LongWord): LongWord; inline; overload; begin if (a < b) then result := a else result := b; end;
1433 function nmin (a, b: LongInt): LongInt; inline; overload; begin if (a < b) then result := a else result := b; end;
1434 function nmin (a, b: Int64): Int64; inline; overload; begin if (a < b) then result := a else result := b; end;
1435 function nmin (a, b: UInt64): UInt64; inline; overload; begin if (a < b) then result := a else result := b; end;
1436 function nmin (a, b: Single): Single; inline; overload; begin if (a < b) then result := a else result := b; end;
1437 function nmin (a, b: Double): Double; inline; overload; begin if (a < b) then result := a else result := b; end;
1438 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1439 function nmin (a, b: Extended): Extended; inline; overload; begin if (a < b) then result := a else result := b; end;
1440 {$ENDIF}
1442 function nmax (a, b: Byte): Byte; inline; overload; begin if (a > b) then result := a else result := b; end;
1443 function nmax (a, b: ShortInt): ShortInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1444 function nmax (a, b: Word): Word; inline; overload; begin if (a > b) then result := a else result := b; end;
1445 function nmax (a, b: SmallInt): SmallInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1446 function nmax (a, b: LongWord): LongWord; inline; overload; begin if (a > b) then result := a else result := b; end;
1447 function nmax (a, b: LongInt): LongInt; inline; overload; begin if (a > b) then result := a else result := b; end;
1448 function nmax (a, b: Int64): Int64; inline; overload; begin if (a > b) then result := a else result := b; end;
1449 function nmax (a, b: UInt64): UInt64; inline; overload; begin if (a > b) then result := a else result := b; end;
1450 function nmax (a, b: Single): Single; inline; overload; begin if (a > b) then result := a else result := b; end;
1451 function nmax (a, b: Double): Double; inline; overload; begin if (a > b) then result := a else result := b; end;
1452 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1453 function nmax (a, b: Extended): Extended; inline; overload; begin if (a > b) then result := a else result := b; end;
1454 {$ENDIF}
1456 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;
1457 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;
1458 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;
1459 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;
1460 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;
1461 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;
1462 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;
1463 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;
1464 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;
1465 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;
1466 {$IF DEFINED(CPU386) OR DEFINED(CPUAMD64)}
1467 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;
1468 {$ENDIF}
1470 // ////////////////////////////////////////////////////////////////////////// //
1471 {$IFDEF WINDOWS}
1472 function snprintf (buf: PAnsiChar; bufsize: SizeUInt; const fmt: PAnsiChar): SizeUInt; cdecl; varargs; external 'msvcrt.dll' name '_snprintf';
1473 {$ELSE}
1474 function snprintf (buf: PAnsiChar; bufsize: SizeUInt; const fmt: PAnsiChar): SizeUInt; cdecl; varargs; external 'libc' name 'snprintf';
1475 {$ENDIF}
1478 (*
1479 procedure conwriter (constref buf; len: SizeUInt);
1480 var
1481 ss: ShortString;
1482 slen: Integer;
1483 b: PByte;
1484 begin
1485 if (len < 1) then exit;
1486 b := PByte(@buf);
1487 while (len > 0) do
1488 begin
1489 if (len > 255) then slen := 255 else slen := Integer(len);
1490 Move(b^, ss[1], len);
1491 ss[0] := AnsiChar(slen);
1492 write(ss);
1493 b += slen;
1494 len -= slen;
1495 end;
1496 end;
1497 *)
1500 function formatstrf (const fmt: AnsiString; const args: array of const; writerCB: TFormatStrFCallback=nil): AnsiString;
1501 const
1503 PadZeroes: AnsiString = '00000000000000000000000000000000000000000000000000000000000000000000000';
1504 var
1520 var
1524 begin
1528 begin
1530 end
1531 else
1532 begin
1534 begin
1546 begin
1551 begin
1557 var
1559 begin
1565 var
1567 begin
1573 begin
1577 begin
1587 begin
1592 var
1595 begin
1597 begin
1601 end
1602 else
1603 begin
1608 repeat
1610 begin
1614 end
1615 else
1616 begin
1618 begin
1621 end
1633 var
1635 begin
1638 repeat
1640 begin
1644 end
1645 else
1646 begin
1648 begin
1651 end
1661 var
1663 begin
1665 begin
1673 var
1675 begin
1677 begin
1684 begin
1688 begin
1689 // print literal part
1692 // output literal part
1694 begin
1696 begin
1698 break;
1702 begin
1706 end
1707 else
1708 begin
1712 continue;
1714 // check if we have argument for this format string
1716 begin
1719 break;
1721 // skip percent
1725 // parse format; check for sign
1729 // parse width
1732 begin
1733 if (fmt[spos] < '0') or (fmt[spos] > '9') then begin xwrite('<INVALID FORMAT>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1737 begin
1743 end
1744 else
1745 begin
1749 // parse precision
1752 begin
1755 if (fmt[spos] < '0') or (fmt[spos] > '9') then begin xwrite('<INVALID FORMAT>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1758 begin
1765 // get format char
1769 // done parsing format, check for valid format chars
1770 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;
1771 // now write formatted string
1774 begin
1775 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;
1784 begin
1786 if args[curarg].VBoolean then strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], 'true')
1791 begin
1793 if args[curarg].VBoolean then strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], AnsiChar('t'))
1798 begin
1803 else
1804 begin
1807 break;
1813 begin
1820 begin
1825 else
1826 begin
1829 break;
1832 //vtWideChar: begin end; // args[curarg].VWideChar (WideChar)
1836 begin
1843 begin
1849 begin
1851 strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], Integer(trunc(args[curarg].VExtended^)));
1855 begin
1857 strblen := snprintf(@strbuf[0], Length(strbuf), @fmtbuf[0], LongWord(trunc(args[curarg].VExtended^)));
1860 else
1861 begin
1864 break;
1868 begin
1876 begin
1885 begin
1893 else
1894 begin
1897 break;
1902 begin
1906 end
1907 else
1908 begin
1916 begin
1917 if (args[curarg].VObject <> nil) then ccname := args[curarg].VObject.Classname else ccname := '<nil>';
1923 begin
1924 if (args[curarg].VClass <> nil) then ccname := args[curarg].VClass.Classname else ccname := '<nil>';
1929 //vtPWideChar: begin end; // args[curarg].VPWideChar (PWideChar)
1931 begin
1936 //vtCurrency: begin end; // args[curarg].VCurrency (PCurrency)
1937 //vtVariant: begin end; // args[curarg].VVariant^ (PVariant)
1938 //vtInterface: begin end; // args[curarg].VInterface (Pointer);
1939 //vtWideString: begin end; // args[curarg].VWideString (Pointer);
1941 begin
1946 else begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1951 begin
1953 begin
1955 begin
1960 end
1961 else
1962 begin
1965 end
1966 else
1967 begin
1975 begin
1980 else begin xwrite('<INVALID FORMAT CHAR>'); writer((PAnsiChar(fmt)+spos-1)^, Length(fmt)-spos+1); break; end;
1984 if (sign <> '-') then begin if zeropad then indent0(width-pclen) else indent(width-pclen); end;
1988 else
1989 begin
1992 break;
2000 (*
2001 var
2002 ss: ShortString;
2003 ls: AnsiString;
2004 i64: Int64 = -$A000000000;
2005 ui64: UInt64 = $A000000000;
2006 begin
2007 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']);
2008 writef(conwriter, 'test float:<%s;%u;%f;%g>'#10, [666.6942, 666.6942, 666.6942, 666.6942]);
2009 ss := 'fuckit';
2010 ls := 'FUCKIT';
2011 writef(conwriter, 'test ss:<%5s;%040s>'#10, [ss, ss]);
2012 writef(conwriter, 'test ls:<%5s;%040s>'#10, [ls, ls]);
2013 writef(conwriter, 'test pointer:<%s;%x;%p>'#10, [@ss, @ss, @ss]);
2014 writef(conwriter, 'test i64:<%s;%x;%015d;%u;%X>'#10, [i64, i64, i64, i64, i64]);
2015 writef(conwriter, 'test ui64:<%s;%x;%15d;%015u;%X>'#10, [ui64, ui64, ui64, ui64, ui64]);
2016 *)