PrintfScanf.st
changeset 2875 17ad0f5c8f53
parent 2678 a2f6f1e865e6
child 2889 7491ae1f59ac
equal deleted inserted replaced
2874:039a4c07607a 2875:17ad0f5c8f53
    84 ! !
    84 ! !
    85 
    85 
    86 !PrintfScanf class methodsFor:'others'!
    86 !PrintfScanf class methodsFor:'others'!
    87 
    87 
    88 version_CVS
    88 version_CVS
    89     ^ '$Header: /cvs/stx/stx/libbasic2/PrintfScanf.st,v 1.5 2011-11-29 10:56:05 cg Exp $'
    89     ^ '$Header: /cvs/stx/stx/libbasic2/PrintfScanf.st,v 1.6 2013-01-23 10:01:22 cg Exp $'
       
    90 ! !
       
    91 
       
    92 !PrintfScanf class methodsFor:'printing'!
       
    93 
       
    94 printf:formatString arguments:args 
       
    95     "Format and print the receiver with <args> formatted in C style, 
       
    96      as described in the UTek manual page for printf(3)."
       
    97 
       
    98     ^  self new printf:formatString arguments:args
       
    99 !
       
   100 
       
   101 printf:formatString on:outStream arguments: args
       
   102     "Format and print formatString on <outStream> with <args>
       
   103      formatted in C style, as described in the UTek manual page for
       
   104      printf(3).  This method is designed for producing output
       
   105      suitable for a machine."     
       
   106 
       
   107     ^ self new printf:formatString on:outStream arguments: args
       
   108 ! !
       
   109 
       
   110 !PrintfScanf class methodsFor:'scanning'!
       
   111 
       
   112 scanf:formatString fromStream:dataStream 
       
   113     "Return a Collection of objects found in the Character Stream
       
   114      <dataStream> as interpreted according to the receiver.  The
       
   115      receiver is assumed to be a conversion control string as
       
   116      specified in the UTek manual page for scanf(3)."
       
   117 
       
   118    ^  self new scanf:formatString fromStream:dataStream
       
   119 !
       
   120 
       
   121 sscanf:formatString fromString:aString 
       
   122     "Return a Collection of objects found in <string> as
       
   123      interpreted according to the receiver.  The receiver is
       
   124      assumed to be a conversion control string as specified in the
       
   125      UTek manual page for scanf(3)."
       
   126 
       
   127    ^  self new sscanf:formatString fromString:aString
       
   128 ! !
       
   129 
       
   130 !PrintfScanf methodsFor:'helpers'!
       
   131 
       
   132 absDecimalPrintFloat:aFloat on:aStream digits:digits 
       
   133     "Place a string representation of the receiver on <aStream> using <digits> significant digits, using decimal notation."
       
   134     
       
   135     |exp x fuzz i|
       
   136 
       
   137     "x is myself normalized to (1.0, 10.0), exp is my exponent"
       
   138     exp := aFloat abs < 1.0 ifTrue:[
       
   139                 (10.0 / aFloat abs) log floor negated
       
   140             ] ifFalse:[
       
   141                 aFloat abs log floor
       
   142             ].
       
   143     x := aFloat abs / (10.0 raisedTo:exp).
       
   144     fuzz := 10.0 raisedTo:1 - digits.
       
   145     x := 0.5 * fuzz + x.
       
   146     x >= 10.0 ifTrue:[ 
       
   147         "check if rounding has unnormalized x" 
       
   148         x := x / 10.0.
       
   149         exp := exp + 1
       
   150     ].
       
   151     exp < 0 ifTrue:[
       
   152         1 to:1 - exp do:[:j | 
       
   153             aStream nextPut:('0.000000000000' at:j)
       
   154         ]
       
   155     ].
       
   156     [ x >= fuzz ] whileTrue:[ 
       
   157         "use fuzz to track significance" 
       
   158         i := x truncated.
       
   159         aStream nextPut:(48 + i) asCharacter.
       
   160         x := (x - i) * 10.0.
       
   161         fuzz := fuzz * 10.0.
       
   162         exp := exp - 1.
       
   163         exp = -1 ifTrue:[
       
   164             aStream nextPut:$.
       
   165         ]
       
   166     ].
       
   167     [ exp >= -1 ] whileTrue:[
       
   168         aStream nextPut:$0.
       
   169         exp := exp - 1.
       
   170         exp = -1 ifTrue:[
       
   171             aStream nextPut:$.
       
   172         ]
       
   173     ]
       
   174 !
       
   175 
       
   176 absPrintFloat:aFloat on:aStream digits:digits 
       
   177     "Place a string representation of the receiver on <aStream> using <digits> significant digits."
       
   178     
       
   179     (aFloat < 1.0e6 and:[ aFloat > 1.0e-4 ]) ifTrue:[
       
   180         self 
       
   181             absDecimalPrintFloat:aFloat
       
   182             on:aStream
       
   183             digits:digits
       
   184     ] ifFalse:[
       
   185         aFloat 
       
   186             absScientificPrintFloat:aFloat
       
   187             on:aStream
       
   188             digits:digits
       
   189     ]
       
   190 !
       
   191 
       
   192 absScientificPrintFloat:aFloat on:aStream digits:digits 
       
   193     "Place a string representation of the receiver on <aStream> using <digits> significant digits, using scientific notation."
       
   194     
       
   195     |exp fuzz x q i|
       
   196 
       
   197     "x is myself normalized to [1.0, 10.0), exp is my exponent"
       
   198     exp := aFloat abs < 1.0 ifTrue:[
       
   199                 (10.0 / aFloat abs) log floor negated
       
   200             ] ifFalse:[
       
   201                 aFloat abs log floor
       
   202             ].
       
   203     x := aFloat abs / (10.0 raisedTo:exp).
       
   204     fuzz := 10.0 raisedTo:1 - digits.
       
   205     x := 0.5 * fuzz + x.
       
   206     x >= 10.0 ifTrue:[ "check if rounding has unnormalized x" 
       
   207         x := x / 10.0.
       
   208         exp := exp + 1
       
   209     ].
       
   210     q := exp.
       
   211     exp := 0.
       
   212     [ x >= fuzz ] whileTrue:[
       
   213         "use fuzz to track significance" 
       
   214         i := x truncated.
       
   215         aStream nextPut:(48 + i) asCharacter.
       
   216         x := (x - i) * 10.0.
       
   217         fuzz := fuzz * 10.0.
       
   218         exp := exp - 1.
       
   219         exp = -1 ifTrue:[
       
   220             aStream nextPut:$.
       
   221         ]
       
   222     ].
       
   223     [ exp >= -1 ] whileTrue:[
       
   224         aStream nextPut:$0.
       
   225         exp := exp - 1.
       
   226         exp = -1 ifTrue:[
       
   227             aStream nextPut:$.
       
   228         ]
       
   229     ].
       
   230     aStream nextPut:$e.
       
   231     q printOn:aStream
       
   232 !
       
   233 
       
   234 formatArgCountFor:aFormatString
       
   235     "Return the number of arguments required/produced,
       
   236      if the argument is interpreted as a printf/scanf format control string."
       
   237 
       
   238     |nonConsecutive count|
       
   239 
       
   240     nonConsecutive := true.
       
   241     count := 0.
       
   242     aFormatString do:[:c |
       
   243         c == $% ifTrue:[
       
   244             nonConsecutive ifTrue:[
       
   245                 count := count + 1. 
       
   246                 nonConsecutive := false
       
   247             ] ifFalse:[
       
   248                 count := count - 1. 
       
   249                 nonConsecutive := true
       
   250             ]
       
   251         ] ifFalse:[
       
   252             nonConsecutive := true
       
   253         ]
       
   254     ].
       
   255     ^ count
    90 ! !
   256 ! !
    91 
   257 
    92 !PrintfScanf methodsFor:'printing'!
   258 !PrintfScanf methodsFor:'printing'!
    93 
   259 
    94 printArgFrom:inStream to:outStream arguments:argStream
   260 printArgFrom:inStream to:outStream arguments:argStream
   193                             ifTrue: ["self halt"]
   359                             ifTrue: ["self halt"]
   194                             ifFalse:
   360                             ifFalse:
   195                                     [precision - (argString size - (argString indexOf: $.)) timesRepeat:
   361                                     [precision - (argString size - (argString indexOf: $.)) timesRepeat:
   196                                             [argString _ argString, '0']]].
   362                                             [argString _ argString, '0']]].
   197             ljust ifTrue: [outStream nextPutAll: argString].
   363             ljust ifTrue: [outStream nextPutAll: argString].
   198             width - argString size timesRepeat: [outStream space].
   364             width - argString size timesRepeat: [outStream nextPut: pad].
   199             ljust ifFalse: [outStream nextPutAll: argString].
   365             ljust ifFalse: [outStream nextPutAll: argString].
   200             ^inStream next
   366             ^inStream next
   201     ].
   367     ].
   202 
   368 
   203     char == $c ifTrue:[
   369     char == $c ifTrue:[
   276             outStream nextPut: char
   442             outStream nextPut: char
   277         ] ifTrue: [
   443         ] ifTrue: [
   278             self printArgFrom:inStream to:outStream arguments:argStream
   444             self printArgFrom:inStream to:outStream arguments:argStream
   279         ]
   445         ]
   280     ]
   446     ]
   281 ! !
       
   282 
       
   283 !PrintfScanf methodsFor:'queries'!
       
   284 
       
   285 absDecimalPrintFloat:aFloat on:aStream digits:digits 
       
   286     "Place a string representation of the receiver on <aStream> using <digits> significant digits, using decimal notation."
       
   287     
       
   288     |exp x fuzz i|
       
   289 
       
   290     "x is myself normalized to (1.0, 10.0), exp is my exponent"
       
   291     exp := aFloat abs < 1.0 ifTrue:[
       
   292                 (10.0 / aFloat abs) log floor negated
       
   293             ] ifFalse:[
       
   294                 aFloat abs log floor
       
   295             ].
       
   296     x := aFloat abs / (10.0 raisedTo:exp).
       
   297     fuzz := 10.0 raisedTo:1 - digits.
       
   298     x := 0.5 * fuzz + x.
       
   299     x >= 10.0 ifTrue:[ 
       
   300         "check if rounding has unnormalized x" 
       
   301         x := x / 10.0.
       
   302         exp := exp + 1
       
   303     ].
       
   304     exp < 0 ifTrue:[
       
   305         1 to:1 - exp do:[:j | 
       
   306             aStream nextPut:('0.000000000000' at:j)
       
   307         ]
       
   308     ].
       
   309     [ x >= fuzz ] whileTrue:[ 
       
   310         "use fuzz to track significance" 
       
   311         i := x truncated.
       
   312         aStream nextPut:(48 + i) asCharacter.
       
   313         x := (x - i) * 10.0.
       
   314         fuzz := fuzz * 10.0.
       
   315         exp := exp - 1.
       
   316         exp = -1 ifTrue:[
       
   317             aStream nextPut:$.
       
   318         ]
       
   319     ].
       
   320     [ exp >= -1 ] whileTrue:[
       
   321         aStream nextPut:$0.
       
   322         exp := exp - 1.
       
   323         exp = -1 ifTrue:[
       
   324             aStream nextPut:$.
       
   325         ]
       
   326     ]
       
   327 !
       
   328 
       
   329 absPrintFloat:aFloat on:aStream digits:digits 
       
   330     "Place a string representation of the receiver on <aStream> using <digits> significant digits."
       
   331     
       
   332     (aFloat < 1.0e6 and:[ aFloat > 1.0e-4 ]) ifTrue:[
       
   333         self 
       
   334             absDecimalPrintFloat:aFloat
       
   335             on:aStream
       
   336             digits:digits
       
   337     ] ifFalse:[
       
   338         aFloat 
       
   339             absScientificPrintFloat:aFloat
       
   340             on:aStream
       
   341             digits:digits
       
   342     ]
       
   343 !
       
   344 
       
   345 absScientificPrintFloat:aFloat on:aStream digits:digits 
       
   346     "Place a string representation of the receiver on <aStream> using <digits> significant digits, using scientific notation."
       
   347     
       
   348     |exp fuzz x q i|
       
   349 
       
   350     "x is myself normalized to [1.0, 10.0), exp is my exponent"
       
   351     exp := aFloat abs < 1.0 ifTrue:[
       
   352                 (10.0 / aFloat abs) log floor negated
       
   353             ] ifFalse:[
       
   354                 aFloat abs log floor
       
   355             ].
       
   356     x := aFloat abs / (10.0 raisedTo:exp).
       
   357     fuzz := 10.0 raisedTo:1 - digits.
       
   358     x := 0.5 * fuzz + x.
       
   359     x >= 10.0 ifTrue:[ "check if rounding has unnormalized x" 
       
   360         x := x / 10.0.
       
   361         exp := exp + 1
       
   362     ].
       
   363     q := exp.
       
   364     exp := 0.
       
   365     [ x >= fuzz ] whileTrue:[
       
   366         "use fuzz to track significance" 
       
   367         i := x truncated.
       
   368         aStream nextPut:(48 + i) asCharacter.
       
   369         x := (x - i) * 10.0.
       
   370         fuzz := fuzz * 10.0.
       
   371         exp := exp - 1.
       
   372         exp = -1 ifTrue:[
       
   373             aStream nextPut:$.
       
   374         ]
       
   375     ].
       
   376     [ exp >= -1 ] whileTrue:[
       
   377         aStream nextPut:$0.
       
   378         exp := exp - 1.
       
   379         exp = -1 ifTrue:[
       
   380             aStream nextPut:$.
       
   381         ]
       
   382     ].
       
   383     aStream nextPut:$e.
       
   384     q printOn:aStream
       
   385 !
       
   386 
       
   387 formatArgCountFor:aFormatString
       
   388     "Return the number of arguments required/produced,
       
   389      if the argument is interpreted as a printf/scanf format control string."
       
   390 
       
   391     |nonConsecutive count|
       
   392 
       
   393     nonConsecutive := true.
       
   394     count := 0.
       
   395     aFormatString do:[:c |
       
   396         c == $% ifTrue:[
       
   397             nonConsecutive ifTrue:[
       
   398                 count := count + 1. 
       
   399                 nonConsecutive := false
       
   400             ] ifFalse:[
       
   401                 count := count - 1. 
       
   402                 nonConsecutive := true
       
   403             ]
       
   404         ] ifFalse:[
       
   405             nonConsecutive := true
       
   406         ]
       
   407     ].
       
   408     ^ count
       
   409 ! !
   447 ! !
   410 
   448 
   411 !PrintfScanf methodsFor:'scanning'!
   449 !PrintfScanf methodsFor:'scanning'!
   412 
   450 
   413 scanArgFrom:dataStream to:collection format:format 
   451 scanArgFrom:dataStream to:collection format:format 
   561 ! !
   599 ! !
   562 
   600 
   563 !PrintfScanf class methodsFor:'documentation'!
   601 !PrintfScanf class methodsFor:'documentation'!
   564 
   602 
   565 version
   603 version
   566     ^ '$Header: /cvs/stx/stx/libbasic2/PrintfScanf.st,v 1.5 2011-11-29 10:56:05 cg Exp $'
   604     ^ '$Header: /cvs/stx/stx/libbasic2/PrintfScanf.st,v 1.6 2013-01-23 10:01:22 cg Exp $'
   567 ! !
   605 ! !
       
   606