PrintfScanf.st
changeset 4434 92084009a524
parent 4432 d4b8ac7168a6
child 4435 96ba42c85b3e
equal deleted inserted replaced
4433:37d85359188d 4434:92084009a524
   113     '%f\n' printf:{ 1234.0 } on:Transcript        
   113     '%f\n' printf:{ 1234.0 } on:Transcript        
   114     '%f\n' printf:{ 1234.0 asShortFloat } on:Transcript        
   114     '%f\n' printf:{ 1234.0 asShortFloat } on:Transcript        
   115     '%f\n' printf:{ 1234.0 asLongFloat } on:Transcript        
   115     '%f\n' printf:{ 1234.0 asLongFloat } on:Transcript        
   116     '%f\n' printf:{ 1234.0 asQDouble } on:Transcript        
   116     '%f\n' printf:{ 1234.0 asQDouble } on:Transcript        
   117 "
   117 "
       
   118 !
       
   119 
       
   120 format
       
   121 "
       
   122     Format specifier:
       
   123     
       
   124         required: leading '%'
       
   125         optional: '-' (POSIX refers to this as the <<flags>>)
       
   126         optional: positive number or '*' (POSIX <<width>>)
       
   127         optional: period followed by positive number or * (POSIX <<precision>>)
       
   128         optional: an h or l to indicate size of data (POSIX <<length>>)
       
   129         required: character describing output behavior (POSIX <<conversion specifier>>)
       
   130 
       
   131     Various implementations of printf have added different functionality.
       
   132 
       
   133     ANSI standards up through C99:
       
   134 
       
   135         more flags '+' ' ' '0' '#'
       
   136         more lengths 'L' 'hh' 'll' 'j' 'z' 't'
       
   137         more conversions 'F' 'a' 'A' 'n'
       
   138 
       
   139     The POSIX specification of printf added:
       
   140 
       
   141         positional parameters to identify argument indices
       
   142         more flags ''' (single quote)
       
   143         more conversions 'C' 'S'
       
   144         clarifications regarding corner cases and 'undefined behavior'
       
   145 
       
   146     BSD implementations added:
       
   147 
       
   148         more lengths 'q'
       
   149         more conversions 'D' 'U' 'O'
       
   150 
       
   151     glibc (GNU) added:
       
   152 
       
   153         more lengths 'Z'
       
   154         more conversions 'm'
       
   155 
       
   156     Windows C Runtime (CRT) added:
       
   157 
       
   158         more lengths 'I' 'I32' 'I64' 'w'
       
   159 
       
   160     glibc and CRT both added 'Z'. 
       
   161     glibc uses 'Z' for the length size_t. 
       
   162     CRT uses Z as a conversion for length-prefixed strings. 
       
   163     This implementation takes the former approach, handling 'Z' in the same way as 'z'.
       
   164 
       
   165     BSD and IBM C library both added 'D'. 
       
   166     BSD uses D as a conversion, namely as an alias of 'ld'. 
       
   167     IBM uses 'D' for the length for _Decimal64, a decimal floating point type, in accordance with ISO/IEC TR 24732. 
       
   168     This implementation takes the former approach.
       
   169 
       
   170     This implementation also adds new conversions:
       
   171 
       
   172         'b' and 'B' for binary (base-2) integer renderings
       
   173         'y' and 'Y' for true/false and yes/no Boolean conversions
       
   174         'J' for JSON
       
   175         'T' and 'V' for JS typeof and valueOf inspection
       
   176 
       
   177     Conversions (upper case same as lower case):
       
   178         'a'     (not implemented) base-2 floating point exp form
       
   179         'b'     binary (base 2)
       
   180         'c'     character or (first char of string)
       
   181         'd'     character or (first char of string)
       
   182         'e'     base-10 floating point exp form (scientific)
       
   183         'f'     base-10 floating point decimal form (non-scientific)
       
   184         'g'     'e' or 'f', whichever looks more appropriate (based on value)
       
   185         'i'     integer (alias for 'd')
       
   186         'j'     (not implemented) JSON format
       
   187         'n'     (not implemented) stores number of characters written into arg 
       
   188         'o'     base-8 octal
       
   189         'p'     (not implemented) pointer 
       
   190         's'     string
       
   191         't'     type (i.e. class name)
       
   192         'u'     (not implemented) unsigned (negative values are converted)
       
   193         'v'     (not implemented) store string
       
   194         'x'     base-16 hex
       
   195 
       
   196     Parameter selection (not implemented):
       
   197 
       
   198         <n>$    take n'th parameter
       
   199 
       
   200     Dynamic width/precision (consumed in order as presented):
       
   201 
       
   202         *       take width/parameter from next argument
       
   203 
       
   204         PrintfScanf printf:'|%s|'  arguments:{ 'abc' }        -> '|abc|'
       
   205         PrintfScanf printf:'|%5s|'  arguments:{ 'abc' }       -> '|  abc|'
       
   206         PrintfScanf printf:'|%*s|'  arguments:{ 5 . 'abc' }   -> '|  abc|'
       
   207 
       
   208         PrintfScanf printf:'|%8f|'  arguments:{ 1.234 }       -> '|   1.234|'
       
   209         PrintfScanf printf:'|%*f|'  arguments:{ 8 . 1.234 }   -> '|   1.234|'
       
   210 
       
   211 
       
   212     Negative width will fill at the right:
       
   213 
       
   214         PrintfScanf printf:'|%5s|'  arguments:{ 'abc' }      -> '|  abc|'
       
   215         PrintfScanf printf:'|%-5s|' arguments:{ 'abc' }      -> '|abc  |'
       
   216         PrintfScanf printf:'|%-*s|' arguments:{ 5 . 'abc' }  -> '|abc  |'
       
   217         PrintfScanf printf:'|%*s|'  arguments:{ -5 . 'abc' } -> '|abc  |'
       
   218 
       
   219         PrintfScanf printf:'|%*f|'  arguments:{ -8 . 1.234 }  -> '|1.234   |'
       
   220         PrintfScanf printf:'|%-8f|'  arguments:{ 1.234 }      -> '|1.234   |'
       
   221         PrintfScanf printf:'|%-*f|'  arguments:{ 8 . 1.234 }  -> '|1.234   |'
       
   222         PrintfScanf printf:'|%-*f|'  arguments:{ -8 . 1.234 } -> '|1.234   |'
       
   223 
       
   224 "
   118 ! !
   225 ! !
   119 
   226 
   120 !PrintfScanf class methodsFor:'instance creation'!
   227 !PrintfScanf class methodsFor:'instance creation'!
   121 
   228 
   122 new
   229 new
   163 
   270 
   164     char == $% ifTrue:[ 
   271     char == $% ifTrue:[ 
   165         ^ outStream nextPut: formatStream next
   272         ^ outStream nextPut: formatStream next
   166     ].
   273     ].
   167 
   274 
       
   275     "/ flags:
       
   276     
   168     char == $- ifTrue:[
   277     char == $- ifTrue:[
   169         ljust := true.  
   278         ljust := true.  
   170         formatStream next.  
   279         formatStream next.  
   171         char := formatStream peek
   280         char := formatStream peek
   172     ].
   281     ].
   187         pound := true.  
   296         pound := true.  
   188         formatStream next.  
   297         formatStream next.  
   189         char := formatStream peek
   298         char := formatStream peek
   190     ].
   299     ].
   191 
   300 
       
   301     "/ possibly a width
   192     char == $* ifTrue:[
   302     char == $* ifTrue:[
   193         width := nextArg value.  
   303         width := nextArg value. 
       
   304         width isInteger ifFalse:[
       
   305             self error:'non integer width argument in printf'
       
   306         ].
       
   307         width < 0 ifTrue:[
       
   308             ljust := true.
       
   309             width := width negated
       
   310         ].    
   194         formatStream next.  
   311         formatStream next.  
   195         char := formatStream peek
   312         char := formatStream peek
   196     ].
   313     ].
   197 
   314 
   198     char isDigit ifTrue:[
   315     char isDigit ifTrue:[
   199         char == $0 ifTrue: [pad := $0].
   316         char == $0 ifTrue: [pad := $0].
   200         width := Integer readFrom: formatStream.  
   317         width := Integer readFrom: formatStream onError:0.  
   201         char := formatStream peek
   318         char := formatStream peek
   202     ].
   319     ].
   203 
   320 
       
   321     "/ precision separator
       
   322     
   204     char == $. ifTrue:[
   323     char == $. ifTrue:[
   205         formatStream next.  char := formatStream peek.
   324         formatStream next.  char := formatStream peek.
   206         char == $*
   325         char == $* ifTrue: [
   207             ifTrue: [precision := nextArg value.  formatStream next.]
   326             precision := nextArg value.  
   208             ifFalse: [precision := Integer readFrom: formatStream.].
   327             precision isInteger ifFalse:[
       
   328                 self error:'non integer precision argument in printf'
       
   329             ].    
       
   330             formatStream next.
       
   331         ] ifFalse: [
       
   332             precision := Integer readFrom: formatStream.
       
   333         ].
   209         char := formatStream peek
   334         char := formatStream peek
   210     ].
   335     ].
   211 
   336 
   212     char == $l ifTrue:[
   337     char == $l ifTrue:[
   213         "Ignore long specifier."
   338         "Ignore long specifier."
   295     ljust ifTrue: [outStream nextPutAll: (arg copyFrom: 1 to: precision)].
   420     ljust ifTrue: [outStream nextPutAll: (arg copyFrom: 1 to: precision)].
   296     width - precision timesRepeat: [outStream nextPut: pad].
   421     width - precision timesRepeat: [outStream nextPut: pad].
   297     ljust ifFalse: [outStream nextPutAll: (arg copyFrom: 1 to: precision)].
   422     ljust ifFalse: [outStream nextPutAll: (arg copyFrom: 1 to: precision)].
   298     ^ formatStream next
   423     ^ formatStream next
   299 
   424 
   300     "Modified (comment): / 19-06-2017 / 15:46:33 / cg"
   425     "Modified: / 20-06-2017 / 15:26:02 / cg"
   301 !
   426 !
   302 
   427 
   303 printf:formatString argument:arg 
   428 printf:formatString argument:arg 
   304     "Format and print the receiver with <arg> formatted in C style, 
   429     "Format and print the receiver with <arg> formatted in C style, 
   305      as described in the UTek manual page for printf(3)."
   430      as described in the UTek manual page for printf(3)."
   476      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 log10  }
   601      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 log10  }
   477      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asShortFloat log10  }
   602      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asShortFloat log10  }
   478      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asLongFloat log10  }
   603      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asLongFloat log10  }
   479      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asQDouble log10  }
   604      self printf:'%20.10f\n' on:Transcript arguments: { 0.0 asQDouble log10  }
   480 
   605 
   481      self printf:'%20.10f\n' on:Transcript arguments: { -1.0 log10   }
   606      self printf:'%20.10f\n' on:Transcript arguments: { DomainError ignoreIn:[ -1.0 log10 ]   }
   482      self printf:'%20.10f\n' on:Transcript arguments: { -1.0 asShortFloat log10  }
   607      self printf:'%20.10f\n' on:Transcript arguments: { DomainError ignoreIn:[ -1.0 asShortFloat log10 ]  }
   483      self printf:'%20.10f\n' on:Transcript arguments: { -1.0 asLongFloat log10  }
   608      self printf:'%20.10f\n' on:Transcript arguments: { DomainError ignoreIn:[ -1.0 asLongFloat log10]   }
   484      self printf:'%20.10f\n' on:Transcript arguments: { -1.0 asQDouble log10  }
   609      self printf:'%20.10f\n' on:Transcript arguments: { DomainError ignoreIn:[ -1.0 asQDouble log10]   }
       
   610 
       
   611      self printf:'%10s\n' on:Transcript arguments:{ 'hello' }
       
   612      self printf:'%*s\n' on:Transcript arguments:{ 10 . 'hello' }
   485     "
   613     "
   486 
   614 
   487     |absVal exp x fuzz i|
   615     |absVal exp x fuzz i|
   488 
   616 
   489     aFloat isNaN ifTrue:[
   617     aFloat isNaN ifTrue:[
   544         exp == -1 ifTrue:[
   672         exp == -1 ifTrue:[
   545             aStream nextPut:$.
   673             aStream nextPut:$.
   546         ]
   674         ]
   547     ]
   675     ]
   548 
   676 
   549     "Modified (comment): / 20-06-2017 / 13:33:40 / cg"
   677     "Modified (comment): / 20-06-2017 / 15:00:22 / cg"
   550 !
   678 !
   551 
   679 
   552 absPrintFloat:aFloat on:aStream digits:digits 
   680 absPrintFloat:aFloat on:aStream digits:digits 
   553     "Place a string representation of the receiver on <aStream>,
   681     "Place a string representation of the receiver on <aStream>,
   554      using <digits> significant digits."
   682      using <digits> significant digits."