EncodedStream.st
changeset 21472 f48f79c4ce5c
parent 20477 e293ff040ddc
child 21521 3766ddd131dc
equal deleted inserted replaced
21471:bbf99c77f552 21472:f48f79c4ce5c
       
     1 "{ Encoding: utf8 }"
       
     2 
     1 "
     3 "
     2  COPYRIGHT (c) 2004 by eXept Software AG
     4  COPYRIGHT (c) 2004 by eXept Software AG
     3               All Rights Reserved
     5               All Rights Reserved
     4 
     6 
     5  This software is furnished under a license and may be used
     7  This software is furnished under a license and may be used
    51     ^ (self basicNew) stream:streamArg; encoder:encoder
    53     ^ (self basicNew) stream:streamArg; encoder:encoder
    52 
    54 
    53     "
    55     "
    54      |s|
    56      |s|
    55      s := EncodedStream stream:Transcript encoder:(CharacterEncoder encoderToEncodeFrom:#utf8 into:#unicode).
    57      s := EncodedStream stream:Transcript encoder:(CharacterEncoder encoderToEncodeFrom:#utf8 into:#unicode).
    56      s nextPutAll:('öäü' utf8Encoded)
    58      s nextPutAll:('öäü' utf8Encoded)
    57     "
    59     "
    58 !
    60 !
    59 
    61 
    60 stream:streamArg encoding:encodingSymbol
    62 stream:streamArg encoding:encodingSymbol
    61     ^ self stream:streamArg encoder:(CharacterEncoder encoderFor:encodingSymbol)
    63     ^ self stream:streamArg encoder:(CharacterEncoder encoderFor:encodingSymbol)
    62 
    64 
    63     "
    65     "
    64      |baseStream s|
    66      |baseStream s|
    65      baseStream := '' readWriteStream.
    67      baseStream := '' readWriteStream.
    66      s := EncodedStream stream:baseStream encoding:#utf8.
    68      s := EncodedStream stream:baseStream encoding:#utf8.
    67      s nextPutAll:'öäü'.
    69      s nextPutAll:'öäü'.
    68      baseStream reset; contents.
    70      baseStream reset; contents.
    69     "
    71     "
    70 ! !
    72 ! !
    71 
    73 
    72 !EncodedStream class methodsFor:'Compatibility-VW5.4'!
    74 !EncodedStream class methodsFor:'Compatibility-VW5.4'!
   166     ].
   168     ].
   167     ^ stream pathName.
   169     ^ stream pathName.
   168 !
   170 !
   169 
   171 
   170 readStream
   172 readStream
       
   173     "read from self"
       
   174 
   171     ^ self
   175     ^ self
       
   176 
       
   177     "Modified (comment): / 16-02-2017 / 15:59:52 / stefan"
   172 !
   178 !
   173 
   179 
   174 stream
   180 stream
   175     ^ stream
   181     ^ stream
   176 !
   182 !
   177 
   183 
   178 stream:something
   184 stream:something
   179     stream := something.
   185     stream := something.
   180 ! !
   186 ! !
   181 
   187 
   182 !EncodedStream methodsFor:'private fileIn'!
   188 !EncodedStream methodsFor:'chunk input/output'!
   183 
   189 
   184 basicFileInNotifying:someone passChunk:passChunk
   190 nextChunk
   185     "central method to file in from the receiver, i.e. read chunks and evaluate them -
   191     "as a side effect, check for an encoding chunk"
   186      return the value of the last chunk.
   192     
   187      Someone (which is usually some codeView) is notified of errors."
   193     |prevEncoder chunk|
   188 
   194 
   189     |lastValue pkg nameSpace usedNameSpaces
   195     chunk := stream nextChunk.
   190      packageQuerySignal nameSpaceQuerySignal usedNameSpaceQuerySignal
   196     chunk isEmptyOrNil ifTrue:[
   191      changeDefaultApplicationNotificationSignal
   197         ^ chunk.
   192      defaultApplicationQuerySignal defaultApplication
   198     ].
   193      confirmationQuerySignal handledSignals passedSignals askSomeoneForPackage outerContext askForVariableTypeOfUndeclaredQuery|
   199 
   194 
   200     prevEncoder := encoder.
   195     self skipSeparators.
   201     (prevEncoder isNullEncoder and:[stream isPositionable not]) ifTrue:[
   196     lastValue := self peek.
   202         "/ not already checked
   197     lastValue == $< ifTrue:[
   203         "/ check if we need lazy setup of the encoder
   198         "/ assume, it's an xml file
   204         "/ (used with non-positionable streams)
   199         ^ self fileInXMLNotifying:someone passChunk:passChunk.
   205         (chunk includesString:'{ Encoding:') ifTrue:[
   200     ].
   206             |enc|
   201     lastValue == $# ifTrue:[
   207 
   202         "assume unix interpreter name:
   208             enc := self class encoderFor:(CharacterEncoder guessEncodingOfBuffer:chunk).
   203          '#!!stx -e' or something like this"
   209             enc notNil ifTrue:[
   204         self nextPeek == $!! ifTrue:[
   210                 prevEncoder := encoder := enc.
   205             "skip the unix command line"
   211             ].
   206             self nextLine
       
   207         ] ifFalse:[
       
   208              self error:'Invalid chunk start'
       
   209         ]
   212         ]
   210     ].
   213     ].
   211 
   214     ^ prevEncoder decodeString:chunk
   212     (Smalltalk at:#Compiler) isNil ifTrue:[
   215 
   213         self isFileStream ifTrue:[
   216     "Modified: / 16-02-2017 / 14:54:57 / stefan"
   214             Transcript show:('[' , self pathName , '] ').
       
   215         ].
       
   216         Transcript showCR:'cannot fileIn (no compiler).'.
       
   217         ^ nil.
       
   218     ].
       
   219 
       
   220     "/ support for V'Age applications
       
   221     defaultApplicationQuerySignal := Class defaultApplicationQuerySignal.
       
   222     changeDefaultApplicationNotificationSignal := Class changeDefaultApplicationNotificationSignal.
       
   223 
       
   224     "/ support for ST/X's nameSpaces & packages
       
   225     packageQuerySignal := Class packageQuerySignal.
       
   226     nameSpaceQuerySignal := Class nameSpaceQuerySignal.
       
   227     usedNameSpaceQuerySignal := Class usedNameSpaceQuerySignal.
       
   228 
       
   229     (someone respondsTo:#packageToInstall) ifTrue:[
       
   230         pkg := someone packageToInstall.
       
   231         askSomeoneForPackage := true.
       
   232     ] ifFalse:[
       
   233         pkg := packageQuerySignal query.
       
   234         askSomeoneForPackage := false.
       
   235     ].
       
   236     (someone respondsTo:#currentNameSpace) ifTrue:[
       
   237         nameSpace := someone currentNameSpace
       
   238     ] ifFalse:[
       
   239         nameSpace := nameSpaceQuerySignal query.
       
   240     ].
       
   241     (someone respondsTo:#usedNameSpaces) ifTrue:[
       
   242         usedNameSpaces := someone usedNameSpaces
       
   243     ] ifFalse:[
       
   244         usedNameSpaces := usedNameSpaceQuerySignal query.
       
   245     ].
       
   246     (someone respondsTo:#defaultApplication) ifTrue:[
       
   247         defaultApplication := someone defaultApplication
       
   248     ] ifFalse:[
       
   249         defaultApplication := defaultApplicationQuerySignal query.
       
   250     ].
       
   251 
       
   252     confirmationQuerySignal := Metaclass confirmationQuerySignal.
       
   253 
       
   254     handledSignals := SignalSet new.
       
   255     passedSignals := IdentitySet new.
       
   256 
       
   257     handledSignals add:changeDefaultApplicationNotificationSignal.
       
   258     passedSignals add:changeDefaultApplicationNotificationSignal.
       
   259     handledSignals add:defaultApplicationQuerySignal.
       
   260     passedSignals add:defaultApplicationQuerySignal.
       
   261 
       
   262     handledSignals add:packageQuerySignal.
       
   263     handledSignals add:usedNameSpaceQuerySignal.
       
   264     handledSignals add:nameSpaceQuerySignal.
       
   265     handledSignals add:confirmationQuerySignal.
       
   266     passedSignals add:confirmationQuerySignal.
       
   267     Parser notNil ifTrue:[
       
   268         "only if libcomp is present"
       
   269         "Also catch a 'Parser askForVariableTypeOfUndeclaredQuery' and proceed with nil. 
       
   270          Imagine somebody has autodefine workspace variables on and then 
       
   271          evaluate Smalltalk loadPackage:'xyz' that loads code from source (using file-in), 
       
   272          certainly we don't want to compile workspace variable access for every
       
   273          not-yet-loaded class in some namespace. 
       
   274          This is demonstrated by Regression::CompilerTests2>>test_01 
       
   275          and this change actually fixes this test."
       
   276         askForVariableTypeOfUndeclaredQuery := Parser askForVariableTypeOfUndeclaredQuery.
       
   277         handledSignals add:askForVariableTypeOfUndeclaredQuery.
       
   278     ].
       
   279 
       
   280 
       
   281     outerContext := thisContext.
       
   282 
       
   283     handledSignals handle:[:ex |
       
   284         |sig|
       
   285 
       
   286         sig := ex creator.
       
   287         ((passedSignals includes:sig) and:[sig isHandledIn:outerContext]) ifTrue:[
       
   288             ex reject
       
   289         ].
       
   290         
       
   291         sig == changeDefaultApplicationNotificationSignal ifTrue:[
       
   292             "/ invoked via #becomeDefault to set the defaultApp and the package.
       
   293             "/ (only when filing in V'Age code)
       
   294             defaultApplication := ex parameter.
       
   295             pkg := defaultApplication name asSymbol.
       
   296             ex proceedWith:nil
       
   297         ].
       
   298         sig == defaultApplicationQuerySignal ifTrue:[
       
   299             "/ query for the application to add classes & methods into
       
   300             "/ (only when filing in V'Age code)
       
   301             ex proceedWith:defaultApplication
       
   302         ].
       
   303         sig == packageQuerySignal ifTrue:[
       
   304             "answer the package to use for classes & methods"
       
   305             askSomeoneForPackage ifTrue:[
       
   306                 ex proceedWith:someone packageToInstall
       
   307             ] ifFalse:[
       
   308                 ex proceedWith:pkg
       
   309             ]
       
   310         ].
       
   311         sig == usedNameSpaceQuerySignal ifTrue:[
       
   312             "answer the nameSpaces to be searched when encountering globals"
       
   313             ex proceedWith:usedNameSpaces
       
   314         ].
       
   315         sig == nameSpaceQuerySignal ifTrue:[
       
   316             "answer the nameSpace to install new classes in"
       
   317             ex proceedWith:nameSpace
       
   318         ].
       
   319         sig == confirmationQuerySignal ifTrue:[
       
   320             "don't pop up dialogs"
       
   321             ex proceedWith:false
       
   322         ].
       
   323         sig == askForVariableTypeOfUndeclaredQuery ifTrue:[
       
   324            "no autodefined variables or so"
       
   325             ex proceedWith:nil.
       
   326         ].
       
   327     ] do:[
       
   328         [self atEnd] whileFalse:[
       
   329             lastValue := self fileInNextChunkNotifying:someone passChunk:passChunk
       
   330         ]
       
   331     ].
       
   332     ^ lastValue
       
   333 
       
   334     "Modified: / 10.9.1999 / 16:54:01 / stefan"
       
   335     "Modified: / 16.11.2001 / 16:21:28 / cg"
       
   336     "Modified: / 18-03-2013 / 17:45:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
       
   337 ! !
   217 ! !
   338 
   218 
   339 !EncodedStream methodsFor:'stream protocol'!
   219 !EncodedStream methodsFor:'stream protocol'!
   340 
   220 
   341 atEnd
   221 atEnd
   398     ^encoder readNext:charactersToRead charactersFrom:stream
   278     ^encoder readNext:charactersToRead charactersFrom:stream
   399 
   279 
   400     "Created: / 16-06-2005 / 11:43:43 / masca"
   280     "Created: / 16-06-2005 / 11:43:43 / masca"
   401 !
   281 !
   402 
   282 
   403 nextChunk
       
   404     "as a side effect, check for an encoding chunk"
       
   405     
       
   406     |prevEncoder chunk|
       
   407 
       
   408     chunk := stream nextChunk.
       
   409     chunk isNil ifTrue:[
       
   410         ^ nil
       
   411     ].
       
   412     prevEncoder := encoder.
       
   413     (prevEncoder isNullEncoder and:[stream isPositionable not]) ifTrue:[
       
   414         "/ not already checked
       
   415         "/ check if we need lazy setup of the encoder
       
   416         "/ (used with non-positionable streams)
       
   417         (chunk includesString:'{ Encoding:') ifTrue:[
       
   418             |enc|
       
   419 
       
   420             enc := self class encoderFor:(CharacterEncoder guessEncodingOfBuffer:chunk).
       
   421             enc notNil ifTrue:[
       
   422                 prevEncoder := encoder := enc.
       
   423             ].
       
   424         ]
       
   425     ].
       
   426     ^ prevEncoder decodeString:chunk
       
   427 !
       
   428 
       
   429 nextChunkPut:chunk
       
   430     stream nextChunkPut:(encoder encodeString:chunk)
       
   431 !
       
   432 
       
   433 nextPut:aCharacter
   283 nextPut:aCharacter
   434     self nextPutAll:(aCharacter asString).
   284     encoder encodeCharacter:aCharacter on:stream.
       
   285 
       
   286     "Modified: / 16-02-2017 / 16:22:23 / stefan"
   435 !
   287 !
   436 
   288 
   437 nextPutAll:aCollection
   289 nextPutAll:aCollection
   438     encoder encodeString:aCollection on:stream 
   290     encoder encodeString:aCollection on:stream 
   439 !
   291 !
   582         token ~= #EOF ifTrue:[
   434         token ~= #EOF ifTrue:[
   583             self position:pos
   435             self position:pos
   584         ].
   436         ].
   585     ] on:Parser parseWarningSignal do:[:ex|
   437     ] on:Parser parseWarningSignal do:[:ex|
   586         "really ignore any error.
   438         "really ignore any error.
   587          Even setting ignorError will output diagnostics here
   439          Even setting ignoreError will output diagnostics here
   588          during standalone startup when debugging"
   440          during standalone startup when debugging"
   589         ex proceedWith:#ignore.
   441         ex proceedWith:#ignore.
   590     ].
   442     ].
   591 
   443 
   592     "Modified: / 29-07-2011 / 17:42:11 / cg"
   444     "Modified: / 29-07-2011 / 17:42:11 / cg"
       
   445     "Modified (format): / 16-02-2017 / 16:01:09 / stefan"
   593 ! !
   446 ! !
   594 
   447 
   595 !EncodedStream class methodsFor:'documentation'!
   448 !EncodedStream class methodsFor:'documentation'!
   596 
   449 
   597 version
   450 version