# HG changeset patch # User Claus Gittinger # Date 1252965574 -7200 # Node ID 81f10d4ad4bfc2f97ac11f4a90f8fe645b2a9847 # Parent ee1b89564617a8c3b79814ef8819e68fa3a683a4 *** empty log message *** diff -r ee1b89564617 -r 81f10d4ad4bf extensions.st --- a/extensions.st Mon Sep 14 19:49:05 2009 +0200 +++ b/extensions.st Mon Sep 14 23:59:34 2009 +0200 @@ -92,6 +92,436 @@ " ! ! +!CharacterArray methodsFor:'printing & storing'! + +printf:args + "Format and print the receiver with formatted in C style, as + specified in the Unix C-language manual page for printf(3). + + For copyright information, see goodies/String-printf_scanf.chg" + + |aStream| + + aStream := WriteStream on:String new. + self printf_printOn:aStream withData:args. + ^ aStream contents + + " + Transcript showCR: 'Some examples:'!! + + Transcript show:'''%#x %#X %03o%*.*s'' printf: #(16rABCD 16rEF 5 9 5 ''ghijklmn'') = .'. + Transcript show: ('%#x %#X %03o%*.*s' printf: #(16rABCD 16rEF 5 9 5 'ghijklmn')). + Transcript showCR: '.' + + Transcript show: '''%- 10.4s%.2e'' printf: (Array with: ''abcdefghijkl'' with: Float pi) = .'. + Transcript show: ('%- 10.4s%.2e' printf: (Array with: 'abcdefghijkl' with: Float pi)). + Transcript showCR: '.' + + Transcript show: '''%8.3f'' printf: (Array with: 200 sqrt negated) = .'. + Transcript show: ('%8.3f' printf: (Array with: 200 sqrt negated)). + Transcript showCR: '.' + + Transcript show: '''%c'' printf: #(16r41) = .'. + Transcript show: ('%c' printf: #(16r41)). + Transcript showCR: '.' + + Transcript show: '''%f%2s%s%s%s'' sscanf: ''237.0 this is a test'' = '. + Transcript showCR: ('%f%2s%s%s%s' sscanf: '237.0 this is a test') printString. + + Transcript show: '''%d%f%s'' sscanf: ''25 54.32e-01 monday'' = '. + Transcript showCR: ('%d%f%s' sscanf: '25 54.32e-01 monday') printString. + + Transcript show: '''%f%*f %8[A-F0-9]%c%d 0x%x%f'' sscanf: ''12.45 1048.73 AE40Z527 0x75BCD15 34'' = '. + Transcript showCR: ('%f%*f %8[A-F0-9]%c%d 0x%x%f' sscanf: '12.45 1048.73 AE40Z527 0x75BCD15 34') printString. + " +! ! + +!CharacterArray methodsFor:'printing & storing'! + +printf_formatArgCount + "Return the number of arguments required/produced if the receiver is interpreted + as a printf/scanf format control string. + For copyright information, see goodies/String-printf_scanf.chg" + + |nonConsecutive count| + + nonConsecutive := true. + count := 0. + self do:[:c | + c == $% ifTrue:[ + nonConsecutive ifTrue:[ + count := count + 1. + nonConsecutive := false + ] ifFalse:[ + count := count - 1. + nonConsecutive := true + ] + ] ifFalse:[ + nonConsecutive := true + ] + ]. + ^ count +! ! + +!CharacterArray methodsFor:'private'! + +printf_printArgFrom:inStream to:outStream withData:argStream + "Interpret the required number of arguments from + according to the formatting information in . + Place the interpretation on . + The interpretation is C printf(3) style, as + specified in the Unix C-language manual page for printf(3). + is assumed to be positioned just past + $%, and a complete control string is assumed available. + + Return when the conversion control string is consumed. + Leave pointing past the last character in the conversion control string. + + This code assumes that is formatted according to + specification, and error checking is minimal. Unexpected + results will be obtained by illegal control strings, or when + argument types do not match conversion codes, but it probably + won't dump core, like C does in such cases!! + + For copyright information, see goodies/String-printf_scanf.chg" + + |ljust plus pound width precision pad char arg argString| + + ljust := plus := pound := false. + width := 0. + precision := SmallInteger maxVal. + pad := $ . + char := inStream peek. + char == $% ifTrue:[ + ^ outStream nextPut:inStream next + ]. + char == $- ifTrue:[ + ljust := true. + inStream next. + char := inStream peek + ]. + char == $ ifTrue:[ + outStream space. + inStream next. + char := inStream peek + ]. + char == $+ ifTrue:[ + plus := true. + inStream next. + char := inStream peek + ]. + char == $# ifTrue:[ + pound := true. + inStream next. + char := inStream peek + ]. + char == $* ifTrue:[ + width := argStream next. + inStream next. + char := inStream peek + ]. + char isDigit ifTrue:[ + char == $0 ifTrue:[ + pad := $0 + ]. + width := Integer readFrom:inStream. + char := inStream peek + ]. + char == $. ifTrue:[ + inStream next. + char := inStream peek. + char == $* ifTrue:[ + precision := argStream next. + inStream next. + char := inStream peek + ] ifFalse:[ + precision := Integer readFrom:inStream. + char := inStream peek + ] + ]. + char == $l "Ignore long specifier." ifTrue:[ + inStream next. + char := inStream peek + ]. + ('feg' includes:char) ifTrue:[ + arg := argStream next asFloat. + precision := precision min:6. + argString := WriteStream on:VariableString "String" new. + char == $g ifTrue:[ + arg absPrintOn:argString digits:precision + 1 + ]. + char == $f ifTrue:[ + arg absDecimalPrintOn:argString digits:precision + arg abs log + 1 + ]. + char == $e ifTrue:[ + arg absScientificPrintOn:argString digits:precision + 1 + ]. + argString := argString contents. + arg < 0 ifTrue:[ + argString := '-' , argString + ] ifFalse:[ + plus ifTrue:[ + argString := '+' , argString + ] + ]. + (precision = 0 and:[ pound not ]) ifTrue:[ + (argString includes:$e) ifTrue:[ + "self halt" + ] ifFalse:[ + argString := arg truncated printString + ] + ]. + pound ifTrue:[ + (argString includes:$e) ifTrue:[ + "self halt" + ] ifFalse:[ + precision - (argString size - (argString indexOf:$.)) timesRepeat:[ + argString := argString , '0' + ] + ] + ]. + ljust ifTrue:[ + outStream nextPutAll:argString + ]. + width - argString size timesRepeat:[ + outStream space + ]. + ljust ifFalse:[ + outStream nextPutAll:argString + ]. + ^ inStream next + ]. + char == $c ifTrue:[ + arg := String with:argStream next asCharacter + ]. + char == $s "Assume the arg is a String or Symbol." ifTrue:[ + arg := argStream next asString + ]. + char == $d ifTrue:[ + arg := argStream next asInteger printString. + plus ifTrue:[ + arg := '+' , arg + ] + ]. + char == $u ifTrue:[ + arg := argStream next asInteger abs printString + ]. + char == $o ifTrue:[ + arg := argStream next asInteger abs printStringRadix:8. + pound ifTrue:[ + arg := '0' , arg + ] + ]. + ('xX' includes:char) ifTrue:[ + arg := argStream next asInteger abs printStringRadix:16. + pound ifTrue:[ + arg := '0x' , arg + ] + ]. + char == $x ifTrue:[ + 1 to:arg size do:[:i | + ('ABCDEF' includes:(arg at:i)) ifTrue:[ + arg at:i put:((arg at:i) asciiValue + 16r20) asCharacter + ] + ] + ]. + precision := precision min:arg size. + ljust ifTrue:[ + outStream nextPutAll:(arg copyFrom:1 to:precision) + ]. + width - precision timesRepeat:[ + outStream nextPut:pad + ]. + ljust ifFalse:[ + outStream nextPutAll:(arg copyFrom:1 to:precision) + ]. + ^ inStream next +! ! + +!CharacterArray methodsFor:'printing & storing'! + +printf_printOn:outStream withData:args + "Format and print the receiver on with + formatted in C style, as specified in the Unix C-language manual page for printf(3). + + For copyright information, see goodies/String-printf_scanf.chg" + + |argStream inStream char| + + argStream := ReadStream on:args. + inStream := ReadStream on:self. + [ inStream atEnd ] whileFalse:[ + (char := inStream next) == $% ifFalse:[ + outStream nextPut:char + ] ifTrue:[ + self + printf_printArgFrom:inStream + to:outStream + withData:argStream + ] + ] +! ! + +!CharacterArray methodsFor:'converting'! + +scanf:dataStream + "Return a Collection of objects found in the Character Stream + as interpreted according to the receiver. + The receiver is assumed to be a conversion control string as + specified in the Unix C-language manual page for scanf(3). + For copyright information, see goodies/String-printf_scanf.chg" + + |results format char| + + results := OrderedCollection new. + format := ReadStream on:self. + [ format atEnd ] whileFalse:[ + char := format next. + (char == Character space or:[ char == Character tab ]) ifTrue:[ + dataStream skipSeparators. + format skipSeparators + ]. + char == $% ifTrue:[ + self + scanf_scanArgFrom:dataStream + to:results + format:format + ] ifFalse:[ + dataStream peekFor:char + ] + ]. + ^ results + + " + '%d %x' scanf:(ReadStream on:'1234 ff00') + " +! ! + +!CharacterArray methodsFor:'private'! + +scanf_scanArgFrom:dataStream to:collection format:format + "Add to an object who's representation is found + in interpreted according to the conversion + control string in the Stream . + is assumed to be positioned just past a $%, and a complete control + string is assumed available. + + Return when the conversion control string is consumed. Leave + pointing past the last character in the conversion + control string, leave pointing past any width + specified in , or at the first character that doesn't + make sense for the . + + For copyright information, see goodies/String-printf_scanf.chg" + + |final width char pos data scanset exclusive return last| + + final := [:retval | + collection add:retval. + data == dataStream ifFalse:[ + dataStream position:dataStream position + data position + ]. + ^ self + ]. + width := 0. + char := format peek. + char == $% ifTrue:[ + ^ dataStream peekFor:char + ]. + char == $* ifTrue:[ + format next. + char := format peek. + final := [:retval | + data == dataStream ifFalse:[ + dataStream position:dataStream position + data position + ]. + ^ self + ] + ]. + char isDigit ifTrue:[ + width := Integer readFrom:format. + char := format peek + ]. + ('slhduoxfeg' includes:char) ifTrue:[ + dataStream skipSeparators + ]. + width = 0 ifTrue:[ + data := dataStream + ] ifFalse:[ + pos := dataStream position. + data := ReadStream on:(dataStream next:width). + dataStream position:pos + ]. + char == $s ifTrue:[ + final value:(data upToSeparator) + ]. + char == $c ifTrue:[ + width = 0 ifTrue:[ + final value:(String with:data next) + ] ifFalse:[ + final value:data contents + ] + ]. + char == $[ "What a mess!!" ifTrue:[ + return := WriteStream on:(VariableString "String" new:8). + scanset := IdentitySet new. + format next. + width = 0 ifTrue:[ + width := SmallInteger maxVal + ]. + exclusive := format peekFor:$^. + [ + last := char. + char := format next. + char == $] + ] whileFalse:[ + char == $- ifFalse:[ + scanset add:char + ] ifTrue:[ + (last to:format next) do:[:c | + scanset add:c + ] + ] + ]. + [ + data atEnd not and:[ (scanset includes:data peek) xor:exclusive ] + ] whileTrue:[ return nextPut:data next ]. + final value:return contents + ]. + ('lh' includes:char) ifTrue:[ + format next. + char := format peek + ]. + ('DUdu' includes:char) ifTrue:[ + final value:(Integer readFrom:data) + ]. + ('FEGfeg' includes:char) ifTrue:[ + final value:(Float readFrom:data) + ]. + ('Oo' includes:char) ifTrue:[ + final value:(Integer readFrom:data radix:8) + ]. + ('Xx' includes:char) ifTrue:[ + final value:(Integer readFrom:data radix:16) + ] +! ! + +!CharacterArray methodsFor:'converting'! + +sscanf:string + "Return a Collection of objects found in as + interpreted according to the receiver. + The receiver is assumed to be a conversion control string as + specified in the Unix C-language manual page for scanf(3). + For copyright information, see goodies/String-printf_scanf.chg" + + ^ self scanf:(ReadStream on:string) + + " + '%d %x' sscanf:'1234 ff00' + " +! ! + !Float methodsFor:'private'! absDecimalPrintOn:aStream digits:digits @@ -609,433 +1039,3 @@ " ! ! -!String methodsFor:'printing'! - -printf:args - "Format and print the receiver with formatted in C style, as - specified in the Unix C-language manual page for printf(3). - - For copyright information, see goodies/String-printf_scanf.chg" - - |aStream| - - aStream := WriteStream on:String new. - self printf_printOn:aStream withData:args. - ^ aStream contents - - " - Transcript showCR: 'Some examples:'!! - - Transcript show:'''%#x %#X %03o%*.*s'' printf: #(16rABCD 16rEF 5 9 5 ''ghijklmn'') = .'. - Transcript show: ('%#x %#X %03o%*.*s' printf: #(16rABCD 16rEF 5 9 5 'ghijklmn')). - Transcript showCR: '.' - - Transcript show: '''%- 10.4s%.2e'' printf: (Array with: ''abcdefghijkl'' with: Float pi) = .'. - Transcript show: ('%- 10.4s%.2e' printf: (Array with: 'abcdefghijkl' with: Float pi)). - Transcript showCR: '.' - - Transcript show: '''%8.3f'' printf: (Array with: 200 sqrt negated) = .'. - Transcript show: ('%8.3f' printf: (Array with: 200 sqrt negated)). - Transcript showCR: '.' - - Transcript show: '''%c'' printf: #(16r41) = .'. - Transcript show: ('%c' printf: #(16r41)). - Transcript showCR: '.' - - Transcript show: '''%f%2s%s%s%s'' sscanf: ''237.0 this is a test'' = '. - Transcript showCR: ('%f%2s%s%s%s' sscanf: '237.0 this is a test') printString. - - Transcript show: '''%d%f%s'' sscanf: ''25 54.32e-01 monday'' = '. - Transcript showCR: ('%d%f%s' sscanf: '25 54.32e-01 monday') printString. - - Transcript show: '''%f%*f %8[A-F0-9]%c%d 0x%x%f'' sscanf: ''12.45 1048.73 AE40Z527 0x75BCD15 34'' = '. - Transcript showCR: ('%f%*f %8[A-F0-9]%c%d 0x%x%f' sscanf: '12.45 1048.73 AE40Z527 0x75BCD15 34') printString. - " -! ! - -!String methodsFor:'printing'! - -printf_formatArgCount - "Return the number of arguments required/produced if the receiver is interpreted - as a printf/scanf format control string. - For copyright information, see goodies/String-printf_scanf.chg" - - |nonConsecutive count| - - nonConsecutive := true. - count := 0. - self do:[:c | - c == $% ifTrue:[ - nonConsecutive ifTrue:[ - count := count + 1. - nonConsecutive := false - ] ifFalse:[ - count := count - 1. - nonConsecutive := true - ] - ] ifFalse:[ - nonConsecutive := true - ] - ]. - ^ count -! ! - -!String methodsFor:'private'! - -printf_printArgFrom:inStream to:outStream withData:argStream - "Interpret the required number of arguments from - according to the formatting information in . - Place the interpretation on . - The interpretation is C printf(3) style, as - specified in the Unix C-language manual page for printf(3). - is assumed to be positioned just past - $%, and a complete control string is assumed available. - - Return when the conversion control string is consumed. - Leave pointing past the last character in the conversion control string. - - This code assumes that is formatted according to - specification, and error checking is minimal. Unexpected - results will be obtained by illegal control strings, or when - argument types do not match conversion codes, but it probably - won't dump core, like C does in such cases!! - - For copyright information, see goodies/String-printf_scanf.chg" - - |ljust plus pound width precision pad char arg argString| - - ljust := plus := pound := false. - width := 0. - precision := SmallInteger maxVal. - pad := $ . - char := inStream peek. - char == $% ifTrue:[ - ^ outStream nextPut:inStream next - ]. - char == $- ifTrue:[ - ljust := true. - inStream next. - char := inStream peek - ]. - char == $ ifTrue:[ - outStream space. - inStream next. - char := inStream peek - ]. - char == $+ ifTrue:[ - plus := true. - inStream next. - char := inStream peek - ]. - char == $# ifTrue:[ - pound := true. - inStream next. - char := inStream peek - ]. - char == $* ifTrue:[ - width := argStream next. - inStream next. - char := inStream peek - ]. - char isDigit ifTrue:[ - char == $0 ifTrue:[ - pad := $0 - ]. - width := Integer readFrom:inStream. - char := inStream peek - ]. - char == $. ifTrue:[ - inStream next. - char := inStream peek. - char == $* ifTrue:[ - precision := argStream next. - inStream next. - char := inStream peek - ] ifFalse:[ - precision := Integer readFrom:inStream. - char := inStream peek - ] - ]. - char == $l "Ignore long specifier." ifTrue:[ - inStream next. - char := inStream peek - ]. - ('feg' includes:char) ifTrue:[ - arg := argStream next asFloat. - precision := precision min:6. - argString := WriteStream on:VariableString "String" new. - char == $g ifTrue:[ - arg absPrintOn:argString digits:precision + 1 - ]. - char == $f ifTrue:[ - arg absDecimalPrintOn:argString digits:precision + arg abs log + 1 - ]. - char == $e ifTrue:[ - arg absScientificPrintOn:argString digits:precision + 1 - ]. - argString := argString contents. - arg < 0 ifTrue:[ - argString := '-' , argString - ] ifFalse:[ - plus ifTrue:[ - argString := '+' , argString - ] - ]. - (precision = 0 and:[ pound not ]) ifTrue:[ - (argString includes:$e) ifTrue:[ - "self halt" - ] ifFalse:[ - argString := arg truncated printString - ] - ]. - pound ifTrue:[ - (argString includes:$e) ifTrue:[ - "self halt" - ] ifFalse:[ - precision - (argString size - (argString indexOf:$.)) timesRepeat:[ - argString := argString , '0' - ] - ] - ]. - ljust ifTrue:[ - outStream nextPutAll:argString - ]. - width - argString size timesRepeat:[ - outStream space - ]. - ljust ifFalse:[ - outStream nextPutAll:argString - ]. - ^ inStream next - ]. - char == $c ifTrue:[ - arg := String with:argStream next asCharacter - ]. - char == $s "Assume the arg is a String or Symbol." ifTrue:[ - arg := argStream next asString - ]. - char == $d ifTrue:[ - arg := argStream next asInteger printString. - plus ifTrue:[ - arg := '+' , arg - ] - ]. - char == $u ifTrue:[ - arg := argStream next asInteger abs printString - ]. - char == $o ifTrue:[ - arg := argStream next asInteger abs printStringRadix:8. - pound ifTrue:[ - arg := '0' , arg - ] - ]. - ('xX' includes:char) ifTrue:[ - arg := argStream next asInteger abs printStringRadix:16. - pound ifTrue:[ - arg := '0x' , arg - ] - ]. - char == $x ifTrue:[ - 1 to:arg size do:[:i | - ('ABCDEF' includes:(arg at:i)) ifTrue:[ - arg at:i put:((arg at:i) asciiValue + 16r20) asCharacter - ] - ] - ]. - precision := precision min:arg size. - ljust ifTrue:[ - outStream nextPutAll:(arg copyFrom:1 to:precision) - ]. - width - precision timesRepeat:[ - outStream nextPut:pad - ]. - ljust ifFalse:[ - outStream nextPutAll:(arg copyFrom:1 to:precision) - ]. - ^ inStream next -! ! - -!String methodsFor:'printing'! - -printf_printOn:outStream withData:args - "Format and print the receiver on with - formatted in C style, as specified in the Unix C-language manual page for printf(3). - - For copyright information, see goodies/String-printf_scanf.chg" - - |argStream inStream char| - - argStream := ReadStream on:args. - inStream := ReadStream on:self. - [ inStream atEnd ] whileFalse:[ - (char := inStream next) == $% ifFalse:[ - outStream nextPut:char - ] ifTrue:[ - self - printf_printArgFrom:inStream - to:outStream - withData:argStream - ] - ] -! ! - -!String methodsFor:'converting'! - -scanf:dataStream - "Return a Collection of objects found in the Character Stream - as interpreted according to the receiver. - The receiver is assumed to be a conversion control string as - specified in the Unix C-language manual page for scanf(3). - For copyright information, see goodies/String-printf_scanf.chg" - - |results format char| - - results := OrderedCollection new. - format := ReadStream on:self. - [ format atEnd ] whileFalse:[ - char := format next. - (char == Character space or:[ char == Character tab ]) ifTrue:[ - dataStream skipSeparators. - format skipSeparators - ]. - char == $% ifTrue:[ - self - scanf_scanArgFrom:dataStream - to:results - format:format - ] ifFalse:[ - dataStream peekFor:char - ] - ]. - ^ results - - " - '%d %x' scanf:(ReadStream on:'1234 ff00') - " -! ! - -!String methodsFor:'private'! - -scanf_scanArgFrom:dataStream to:collection format:format - "Add to an object who's representation is found - in interpreted according to the conversion - control string in the Stream . - is assumed to be positioned just past a $%, and a complete control - string is assumed available. - - Return when the conversion control string is consumed. Leave - pointing past the last character in the conversion - control string, leave pointing past any width - specified in , or at the first character that doesn't - make sense for the . - - For copyright information, see goodies/String-printf_scanf.chg" - - |final width char pos data scanset exclusive return last| - - final := [:retval | - collection add:retval. - data == dataStream ifFalse:[ - dataStream position:dataStream position + data position - ]. - ^ self - ]. - width := 0. - char := format peek. - char == $% ifTrue:[ - ^ dataStream peekFor:char - ]. - char == $* ifTrue:[ - format next. - char := format peek. - final := [:retval | - data == dataStream ifFalse:[ - dataStream position:dataStream position + data position - ]. - ^ self - ] - ]. - char isDigit ifTrue:[ - width := Integer readFrom:format. - char := format peek - ]. - ('slhduoxfeg' includes:char) ifTrue:[ - dataStream skipSeparators - ]. - width = 0 ifTrue:[ - data := dataStream - ] ifFalse:[ - pos := dataStream position. - data := ReadStream on:(dataStream next:width). - dataStream position:pos - ]. - char == $s ifTrue:[ - final value:(data upToSeparator) - ]. - char == $c ifTrue:[ - width = 0 ifTrue:[ - final value:(String with:data next) - ] ifFalse:[ - final value:data contents - ] - ]. - char == $[ "What a mess!!" ifTrue:[ - return := WriteStream on:(VariableString "String" new:8). - scanset := IdentitySet new. - format next. - width = 0 ifTrue:[ - width := SmallInteger maxVal - ]. - exclusive := format peekFor:$^. - [ - last := char. - char := format next. - char == $] - ] whileFalse:[ - char == $- ifFalse:[ - scanset add:char - ] ifTrue:[ - (last to:format next) do:[:c | - scanset add:c - ] - ] - ]. - [ - data atEnd not and:[ (scanset includes:data peek) xor:exclusive ] - ] whileTrue:[ return nextPut:data next ]. - final value:return contents - ]. - ('lh' includes:char) ifTrue:[ - format next. - char := format peek - ]. - ('DUdu' includes:char) ifTrue:[ - final value:(Integer readFrom:data) - ]. - ('FEGfeg' includes:char) ifTrue:[ - final value:(Float readFrom:data) - ]. - ('Oo' includes:char) ifTrue:[ - final value:(Integer readFrom:data radix:8) - ]. - ('Xx' includes:char) ifTrue:[ - final value:(Integer readFrom:data radix:16) - ] -! ! - -!String methodsFor:'converting'! - -sscanf:string - "Return a Collection of objects found in as - interpreted according to the receiver. - The receiver is assumed to be a conversion control string as - specified in the Unix C-language manual page for scanf(3). - For copyright information, see goodies/String-printf_scanf.chg" - - ^ self scanf:(ReadStream on:string) - - " - '%d %x' sscanf:'1234 ff00' - " -! ! -