#FEATURE by exept
class: PrintfScanf class
comment/format in: #format_printf
changed: #printArgFrom:to:arguments:
handle + and space flag for infinity.
--- a/PrintfScanf.st Fri Aug 30 02:23:07 2019 +0200
+++ b/PrintfScanf.st Sat Aug 31 10:30:08 2019 +0200
@@ -131,50 +131,46 @@
"
Printf Format specifier:
- required: leading '%'
+ required: leading '%'
optional: '-' (POSIX refers to this as the <<flags>>)
- optional: positive number or '*' (POSIX <<width>>)
- optional: period followed by positive number or * (POSIX <<precision>>)
- optional: an h or l to indicate size of data (POSIX <<length>>)
- required: character describing output behavior (POSIX <<conversion specifier>>)
+ optional: positive number or '*' (POSIX: <<width>>)
+ optional: period followed by positive number or * (POSIX: <<precision>>)
+ optional: an h or l to indicate size of data (POSIX: <<length>>)
+ required: character describing output behavior (POSIX: <<conversion specifier>>)
Various implementations of printf have added different functionality.
ANSI standards up through C99:
-
more flags '+' ' ' '0' '#'
more lengths 'L' 'hh' 'll' 'j' 'z' 't'
more conversions 'F' 'a' 'A' 'n'
The POSIX specification of printf added:
-
positional parameters to identify argument indices
more flags ''' (single quote)
more conversions 'C' 'S'
clarifications regarding corner cases and 'undefined behavior'
BSD implementations added:
-
more lengths 'q'
more conversions 'D' 'U' 'O'
glibc (GNU) added:
-
more lengths 'Z'
more conversions 'm'
Windows C Runtime (CRT) added:
-
more lengths 'I' 'I32' 'I64' 'w'
- glibc and CRT both added 'Z'.
- glibc uses 'Z' for the length size_t.
- CRT uses Z as a conversion for length-prefixed strings.
+ glibc and CRT both added length 'Z'.
+ glibc uses 'Z' for the length size_t.
+ CRT uses Z as a conversion for length-prefixed strings.
This implementation takes the former approach, handling 'Z' in the same way as 'z'.
BSD and IBM C library both added 'D'.
- BSD uses D as a conversion, namely as an alias of 'ld'.
- IBM uses 'D' for the length for _Decimal64, a decimal floating point type, in accordance with ISO/IEC TR 24732.
+ BSD uses D as a conversion, namely as an alias of 'ld'.
+ IBM uses 'D' for the length for _Decimal64, a decimal floating point type,
+ in accordance with ISO/IEC TR 24732.
This implementation takes the former approach.
================================================================
@@ -198,7 +194,7 @@
'g' 'e' or 'f', whichever looks more appropriate (based on value)
'i' integer (alias for 'd')
'j' (not implemented) JSON format
- 'n' (not implemented) stores number of characters written into arg
+ 'n' (not implemented) stores number of characters written so far into arg
'o' base-8 octal
'p' (not implemented) pointer
's' string
@@ -209,13 +205,12 @@
'X' base-16 hex upper case
Parameter selection (not implemented):
-
<n>$ take n'th parameter
Dynamic width/precision (consumed in order as presented):
-
* take width/parameter from next argument
+ Examples:
PrintfScanf printf:'|%d|' arguments:{ 123 } -> '|123|'
PrintfScanf printf:'|%5d|' arguments:{ 123 } -> '| 123|'
PrintfScanf printf:'|%-5d|' arguments:{ 123 } -> '|123 |'
@@ -229,7 +224,6 @@
Negative width will fill at the right:
-
PrintfScanf printf:'|%5s|' arguments:{ 'abc' } -> '| abc|'
PrintfScanf printf:'|%-5s|' arguments:{ 'abc' } -> '|abc |'
PrintfScanf printf:'|%-*s|' arguments:{ 5 . 'abc' } -> '|abc |'
@@ -241,7 +235,6 @@
PrintfScanf printf:'|%-*f|' arguments:{ -8 . 1.234 } -> '|1.234 |'
A Zero as fill character:
-
PrintfScanf printf:'|%05s|' arguments:{ 'abc' } -> '|00abc|'
PrintfScanf printf:'|%-05s|' arguments:{ 'abc' } -> '|abc00|'
@@ -251,7 +244,6 @@
PrintfScanf printf:'|%-*f|' arguments:{ -8 . 1.234 } -> '|1.234 |'
Case of float-format character only affects printing of Nan and infinity:
-
PrintfScanf printf:'%f' argument:1.234
PrintfScanf printf:'%F' argument:1.234
PrintfScanf printf:'%f' argument:(Float NaN)
@@ -458,6 +450,10 @@
"Ignore ptrdiff-length specifier."
more := true.
].
+ char == $z ifTrue:[
+ "Ignore size_t-length specifier."
+ more := true.
+ ].
more ifTrue:[
formatStream next.
char := formatStream peek.
@@ -477,6 +473,15 @@
(char isUppercase)
ifTrue:[ argString := argString asUppercase ]
ifFalse:[ argString := argString asLowercase ].
+ arg positive ifTrue:[
+ plus ifTrue: [
+ argString := '+', argString
+ ] ifFalse:[
+ spaceIfPositive ifTrue: [
+ argString := ' ', argString
+ ].
+ ].
+ ].
] ifFalse:[
argString := WriteStream on:''.
(char == $g or:[char == $G]) ifTrue: [
@@ -525,7 +530,7 @@
char == $c ifTrue:[
arg := nextArg value.
arg isString ifTrue:[
- arg := arg first
+ arg := arg first asString
] ifFalse:[
arg := arg asCharacter asString
].