PipeStream.st
changeset 2969 1fcf6dfb6004
parent 2966 856dfc8a294a
child 2970 f846e7c1962c
equal deleted inserted replaced
2968:260a66f9f4e2 2969:1fcf6dfb6004
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 
    12 
    13 NonPositionableExternalStream subclass:#PipeStream
    13 NonPositionableExternalStream subclass:#PipeStream
    14 	instanceVariableNames:'commandString pid exitStatus exitSema'
    14 	instanceVariableNames:'commandString pid exitStatus exitSema exitAction'
    15 	classVariableNames:'BrokenPipeSignal'
    15 	classVariableNames:'BrokenPipeSignal'
    16 	poolDictionaries:''
    16 	poolDictionaries:''
    17 	category:'Streams-External'
    17 	category:'Streams-External'
    18 !
    18 !
    19 
    19 
   164 "
   164 "
   165     Pipestreams allow reading or writing from/to a unix command.
   165     Pipestreams allow reading or writing from/to a unix command.
   166     For example, to get a stream reading the output of an 'ls -l'
   166     For example, to get a stream reading the output of an 'ls -l'
   167     command, a PipeStream can be created with:
   167     command, a PipeStream can be created with:
   168 
   168 
   169         PipeStream readingFrom:'ls -l'
   169 	PipeStream readingFrom:'ls -l'
   170 
   170 
   171     the characters of the commands output can be read using the
   171     the characters of the commands output can be read using the
   172     standard stream messages as next, nextLine etc.
   172     standard stream messages as next, nextLine etc.
   173 
   173 
   174     If a writing pipeStream is written to, after the command has finished,
   174     If a writing pipeStream is written to, after the command has finished,
   175     UNIX will generate an error-signal (SIGPIPE), which will raise the BrokenPipeSignal. 
   175     UNIX will generate an error-signal (SIGPIPE), which will raise the BrokenPipeSignal. 
   176     Thus, to handle this condition correctly, the following code is suggested:
   176     Thus, to handle this condition correctly, the following code is suggested:
   177 
   177 
   178         |p|
   178 	|p|
   179         p := PipeStream writingTo:'echo hello'.
   179 	p := PipeStream writingTo:'echo hello'.
   180         PipeStream brokenPipeSignal handle:[:ex |
   180 	PipeStream brokenPipeSignal handle:[:ex |
   181             'broken pipe' printNewline.
   181 	    'broken pipe' printNewline.
   182             p shutDown.
   182 	    p shutDown.
   183             ex return
   183 	    ex return
   184         ] do:[
   184 	] do:[
   185             p nextPutLine:'oops'.
   185 	    p nextPutLine:'oops'.
   186            'after write' printNewline.
   186 	   'after write' printNewline.
   187             p close.
   187 	    p close.
   188            'after close' printNewline
   188 	   'after close' printNewline
   189         ]
   189 	]
   190 
   190 
   191     Notice, that iff the Stream is buffered, the Signal may occur some time after
   191     Notice, that iff the Stream is buffered, the Signal may occur some time after
   192     the write - or even at close time; to avoid a recursive signal in the exception
   192     the write - or even at close time; to avoid a recursive signal in the exception
   193     handler, a #shutDown is useful there; if you use close in the handler, this would
   193     handler, a #shutDown is useful there; if you use close in the handler, this would
   194     try to send any buffered output to the pipe, leading to another brokenPipe exception.
   194     try to send any buffered output to the pipe, leading to another brokenPipe exception.
   199     Currently, no filtering pipeStreams (i.e. both reading AND writing) are provided.
   199     Currently, no filtering pipeStreams (i.e. both reading AND writing) are provided.
   200     However, if you look at how things are setup, this can be implemented using the
   200     However, if you look at how things are setup, this can be implemented using the
   201     low level primitives #mapePipe and #executeCommand from the OS class protocol.
   201     low level primitives #mapePipe and #executeCommand from the OS class protocol.
   202 
   202 
   203     [author:]
   203     [author:]
   204         Claus Gittinger
   204 	Claus Gittinger
   205 
   205 
   206     [see also:]
   206     [see also:]
   207 	ExternalStream FileStream Socket
   207 	ExternalStream FileStream Socket
   208 	OperatingSystem
   208 	OperatingSystem
   209 "
   209 "
   219 	BrokenPipeSignal nameClass:self message:#brokenPipeSignal.
   219 	BrokenPipeSignal nameClass:self message:#brokenPipeSignal.
   220 	BrokenPipeSignal notifierString:'write on a pipe with no one to read'.
   220 	BrokenPipeSignal notifierString:'write on a pipe with no one to read'.
   221     ]
   221     ]
   222 ! !
   222 ! !
   223 
   223 
       
   224 !PipeStream class methodsFor:'helpers'!
       
   225 
       
   226 createCOMFileForVMSCommands:aCollectionOfCommandStrings
       
   227     "since DCL seems to not support multiple commands in one
       
   228      line, create a temporary COM file for them and let DCL
       
   229      execute that one. 
       
   230      A kludge around a poor CLI design."
       
   231 
       
   232     |tmpComFile s|
       
   233 
       
   234     tmpComFile := Filename newTemporary withSuffix:'COM'.
       
   235     s := tmpComFile writeStream.
       
   236     aCollectionOfCommandStrings do:[:aCommand |
       
   237 	s nextPutAll:'$'.
       
   238 	s nextPutAll:aCommand.
       
   239 	s nextPut:(Character nl).
       
   240     ].
       
   241     s close.
       
   242     ^ tmpComFile.
       
   243 !
       
   244 
       
   245 createCOMFileForVMSCommand:aCommandString in:aDirectory
       
   246     "since DCL seems to not support multiple commands in one
       
   247      line, create a temporary COM file for a set def, followed
       
   248      by the actual command string.
       
   249      A kludge around a poor CLI design."
       
   250 
       
   251     ^ self
       
   252 	createCOMFileForVMSCommands:(Array
       
   253 					with:('$set def ' , aDirectory asFilename pathName asFilename osNameForDirectory)
       
   254 					with:('$' , aCommandString)).
       
   255 ! !
       
   256 
   224 !PipeStream class methodsFor:'instance creation'!
   257 !PipeStream class methodsFor:'instance creation'!
   225 
   258 
   226 readingFrom:commandString
   259 readingFrom:commandString
   227     "create and return a new pipeStream which can read from the unix command
   260     "create and return a new pipeStream which can read from the unix command
   228      given by command."
   261      given by command."
   229 
   262 
   230     ^ (self basicNew) readingFrom:commandString
   263     ^ (self basicNew) readingFrom:commandString
   231 
   264 
   232     "unix:
   265     "unix:
   233         PipeStream readingFrom:'ls -l'.
   266 	PipeStream readingFrom:'ls -l'.
   234     "
   267     "
   235 
   268 
   236     "
   269     "
   237         p := PipeStream readingFrom:'ls -l'.
   270 	p := PipeStream readingFrom:'ls -l'.
   238 	Transcript showCR:p nextLine.
   271 	Transcript showCR:p nextLine.
   239 	p close
   272 	p close
   240     "
   273     "
   241 
   274 
   242     "
   275     "
   243         |s|
   276 	|s|
   244         s := PipeStream readingFrom:'sh -c sleep\ 600'.
   277 	s := PipeStream readingFrom:'sh -c sleep\ 600'.
   245         (Delay forSeconds:2) wait.
   278 	(Delay forSeconds:2) wait.
   246         s shutDown
   279 	s shutDown
   247     "
   280     "
   248 
   281 
   249     "vms:
   282     "vms:
   250 	PipeStream readingFrom:'dir'.
   283 	PipeStream readingFrom:'dir'.
   251     "
   284     "
   252 
   285 
   253     "
   286     "
   254         |p|
   287 	|p|
   255 	p := PipeStream readingFrom:'dir'.
   288 	p := PipeStream readingFrom:'dir'.
   256 	Transcript showCR:p nextLine.
   289 	Transcript showCR:p nextLine.
   257 	p close
   290 	p close
   258     "
   291     "
   259 
   292 
   260     "msdos:
   293     "msdos:
   261 	PipeStream readingFrom:'dir'.
   294 	PipeStream readingFrom:'dir'.
   262     "
   295     "
   263     "
   296     "
   264         |p|
   297 	|p|
   265 	p := PipeStream readingFrom:'dir'.
   298 	p := PipeStream readingFrom:'dir'.
   266 	Transcript showCR:p nextLine.
   299 	Transcript showCR:p nextLine.
   267 	p close
   300 	p close
   268     "
   301     "
   269 
   302 
   270     "Modified: 24.4.1996 / 09:09:25 / stefan"
   303     "Modified: 24.4.1996 / 09:09:25 / stefan"
   271 !
   304 !
   272 
   305 
       
   306 readingFrom:commandString inDirectory:aDirectory
       
   307     "similar to #readingFrom, but changes the directory while
       
   308      executing the command. Use this if a command is to be
       
   309      executed in another directory, to avoid any OS dependencies
       
   310      in your code."
       
   311 
       
   312     |cmd tmpComFile pipe|
       
   313 
       
   314     (OperatingSystem platformName == #vms) ifTrue:[
       
   315 	tmpComFile := self createCOMFileForVMSCommand:commandString in:aDirectory.
       
   316 	cmd := '@' , tmpComFile osName.
       
   317 	pipe := self readingFrom:cmd.
       
   318 	pipe notNil ifTrue:[
       
   319 	    pipe exitAction:[tmpComFile delete].
       
   320 	].
       
   321 	^ pipe
       
   322     ].
       
   323 
       
   324     "/ unix - prepend a 'cd' to the command
       
   325     cmd := 'cd ' , aDirectory asFilename pathName, '; ' , commandString.
       
   326     ^ self readingFrom:cmd
       
   327 !
       
   328 
   273 writingTo:commandString
   329 writingTo:commandString
   274     "create and return a new pipeStream which can write to the unix command
   330     "create and return a new pipeStream which can write to the unix command
   275      given by command."
   331      given by command."
   276 
   332 
   277     ^ (self basicNew) writingTo:commandString
   333     ^ (self basicNew) writingTo:commandString
   278 
   334 
   279     "unix:
   335     "unix:
   280          PipeStream writingTo:'sort'
   336 	 PipeStream writingTo:'sort'
   281     "
   337     "
       
   338 !
       
   339 
       
   340 writingTo:commandString inDirectory:aDirectory
       
   341     "similar to #writingTo, but changes the directory while
       
   342      executing the command. Use this if a command is to be
       
   343      executed in another directory, to avoid any OS dependencies
       
   344      in your code."
       
   345 
       
   346     |cmd tmpComFile pipe|
       
   347 
       
   348     (OperatingSystem platformName == #vms) ifTrue:[
       
   349 	tmpComFile := self createCOMFileForVMSCommand:commandString in:aDirectory.
       
   350 	cmd := '@' , tmpComFile osName.
       
   351 	pipe := self writingTo:cmd.
       
   352 	pipe notNil ifTrue:[
       
   353 	    pipe exitAction:[tmpComFile delete].
       
   354 	].
       
   355 	^ pipe
       
   356     ].
       
   357 
       
   358     "/ unix - prepend a 'cd' to the command
       
   359     cmd := 'cd ' , aDirectory asFilename pathName, '; ' , commandString.
       
   360     ^ self writingTo:cmd
   282 ! !
   361 ! !
   283 
   362 
   284 !PipeStream class methodsFor:'Signal constants'!
   363 !PipeStream class methodsFor:'Signal constants'!
   285 
   364 
   286 brokenPipeSignal
   365 brokenPipeSignal
   319     "low level close
   398     "low level close
   320      This waits for the command to finish. 
   399      This waits for the command to finish. 
   321      Use shutDown for a fast (nonBlocking) close."
   400      Use shutDown for a fast (nonBlocking) close."
   322 
   401 
   323     filePointer notNil ifTrue:[
   402     filePointer notNil ifTrue:[
   324         super closeFile.
   403 	super closeFile.
   325         filePointer := nil.
   404 	filePointer := nil.
   326         pid notNil ifTrue:[
   405 	pid notNil ifTrue:[
   327 	    [
   406 	    [
   328                 pid notNil ifTrue:[
   407 		pid notNil ifTrue:[
   329                     exitSema wait.
   408 		    exitSema wait.
   330 		]
   409 		]
   331 	    ] valueUninterruptably
   410 	    ] valueUninterruptably
   332         ].
   411 	].
   333     ].
   412     ].
   334 !
   413 !
   335 
   414 
   336 closeFileDescriptor
   415 closeFileDescriptor
   337     "alternative very low level close 
   416     "alternative very low level close 
   338      This closes the underlying OS-fileDescriptor 
   417      This closes the underlying OS-fileDescriptor 
   339      - and will NOT write any buffered data to the stream.
   418      - and will NOT write any buffered data to the stream.
   340      You have been warned."
   419      You have been warned."
   341 
   420 
   342 %{  /* NOCONTEXT */
   421     |action|
       
   422 
       
   423 %{  
   343 #if !defined(transputer) && !defined(MSDOS_LIKE)
   424 #if !defined(transputer) && !defined(MSDOS_LIKE)
   344     OBJ fp;
   425     OBJ fp;
   345     FILE *f;
   426     FILE *f;
   346 
   427 
   347     if ((fp = __INST(filePointer)) != nil) {
   428     if ((fp = __INST(filePointer)) != nil) {
   350 	__BEGIN_INTERRUPTABLE__
   431 	__BEGIN_INTERRUPTABLE__
   351 	close(fileno(f));
   432 	close(fileno(f));
   352 	__END_INTERRUPTABLE__
   433 	__END_INTERRUPTABLE__
   353     }
   434     }
   354 #endif /* not transputer && not MSDOS_LIKE */
   435 #endif /* not transputer && not MSDOS_LIKE */
   355 %}
   436 %}.
       
   437     exitAction notNil ifTrue:[
       
   438 	action := exitAction.
       
   439 	exitAction := nil.
       
   440 	action value.
       
   441     ]
   356 !
   442 !
   357 
   443 
   358 disposed
   444 disposed
   359     "redefined to avoid blocking in close."
   445     "redefined to avoid blocking in close."
   360 
   446 
   364 shutDown
   450 shutDown
   365     "close the Stream, ignoring any broken-pipe errors.
   451     "close the Stream, ignoring any broken-pipe errors.
   366      Terminate the command"
   452      Terminate the command"
   367 
   453 
   368     BrokenPipeSignal catch:[
   454     BrokenPipeSignal catch:[
   369         |tpid|
   455 	|tpid|
   370 
   456 
   371         Lobby unregister:self.
   457 	Lobby unregister:self.
   372         self closeFileDescriptor.
   458 	self closeFileDescriptor.
   373         tpid := pid.                    "copy pid to avoid race"
   459 	tpid := pid.                    "copy pid to avoid race"
   374         tpid notNil ifTrue:[
   460 	tpid notNil ifTrue:[
   375             "/
   461 	    "/
   376             "/ Terminate both the process and group, just in case the
   462 	    "/ Terminate both the process and group, just in case the
   377             "/ operating system does not support process groups.
   463 	    "/ operating system does not support process groups.
   378             "/
   464 	    "/
   379             OperatingSystem terminateProcess:tpid.
   465 	    OperatingSystem terminateProcess:tpid.
   380             OperatingSystem terminateProcessGroup:tpid.
   466 	    OperatingSystem terminateProcessGroup:tpid.
   381             pid := nil.
   467 	    pid := nil.
   382         ].
   468 	].
       
   469 
   383     ]
   470     ]
   384 
   471 
   385     "Modified: 23.5.1996 / 09:15:41 / stefan"
   472     "Modified: 23.5.1996 / 09:15:41 / stefan"
   386 ! !
   473 ! !
   387 
   474 
   388 !PipeStream methodsFor:'private'!
   475 !PipeStream methodsFor:'private'!
       
   476 
       
   477 exitAction:aBlock
       
   478     "define a block to be evaluated when the pipe is closed.
       
   479      This is only used with VMS, to remove any temporary COM file.
       
   480      (see readingFrom:inDirectory:)"
       
   481 
       
   482     exitAction := aBlock
       
   483 !
   389 
   484 
   390 openPipeFor:aCommandString withMode:mode
   485 openPipeFor:aCommandString withMode:mode
   391     "open a pipe to the unix command in commandString; 
   486     "open a pipe to the unix command in commandString; 
   392      mode may be 'r' or 'w'"
   487      mode may be 'r' or 'w'"
   393 
   488 
   394     |blocked pipeFdArray execFdArray execFd myFd 
   489     |blocked pipeFdArray execFdArray execFd myFd 
   395      osType shellPath shellArgs closeFdArray mbx mbxName|
   490      osType shellPath shellArgs closeFdArray mbx mbxName|
   396 
   491 
   397     filePointer notNil ifTrue:[
   492     filePointer notNil ifTrue:[
   398         "the pipe was already open ...
   493 	"the pipe was already open ...
   399          this should (can) not happen."
   494 	 this should (can) not happen."
   400         ^ self errorOpen
   495 	^ self errorOpen
   401     ].
   496     ].
   402     lastErrorNumber := nil.
   497     lastErrorNumber := nil.
   403     exitStatus := nil.
   498     exitStatus := nil.
   404     exitSema := Semaphore new name:'pipe exitSema'.
   499     exitSema := Semaphore new name:'pipe exitSema'.
   405 
   500 
   406     osType := OperatingSystem platformName.
   501     osType := OperatingSystem platformName.
   407     osType == #vms ifTrue:[
   502     osType == #vms ifTrue:[
   408         mbx := OperatingSystem createMailBox.
   503 	mbx := OperatingSystem createMailBox.
   409 	mbx isNil ifTrue:[
   504 	mbx isNil ifTrue:[
   410 	    lastErrorNumber := OperatingSystem currentErrorNumber.
   505 	    lastErrorNumber := OperatingSystem currentErrorNumber.
   411 	    ^ self openError
   506 	    ^ self openError
   412 	].
   507 	].
   413 'mailBox is ' print. mbx printCR.
   508 	mbxName := OperatingSystem mailBoxNameOf:mbx.
       
   509 'mailBox is ' print. mbx print. ' name is ' print. mbxName printCR.
   414 	shellPath := ''.
   510 	shellPath := ''.
   415 	shellArgs := aCommandString.
   511 	shellArgs := aCommandString.
   416 
   512 
   417 	mode = 'r' ifTrue:[
   513 	mode = 'r' ifTrue:[
   418 	    execFdArray := Array with:0 with:mbx with:2.
   514 	    execFdArray := Array with:0 with:mbx with:2.
   419 	] ifFalse:[
   515 	] ifFalse:[
   420 	    execFdArray := Array with:mbx with:1 with:2.
   516 	    execFdArray := Array with:mbx with:1 with:2.
   421 	].
   517 	].
   422 	closeFdArray := nil.
   518 	closeFdArray := nil.
   423     ] ifFalse:[
   519     ] ifFalse:[
   424         pipeFdArray := OperatingSystem makePipe.
   520 	pipeFdArray := OperatingSystem makePipe.
   425         pipeFdArray isNil ifTrue:[
   521 	pipeFdArray isNil ifTrue:[
   426             lastErrorNumber := OperatingSystem currentErrorNumber.
   522 	    lastErrorNumber := OperatingSystem currentErrorNumber.
   427             ^ self openError
   523 	    ^ self openError
   428 	].
   524 	].
   429 
   525 
   430         osType == #unix ifTrue:[
   526 	osType == #unix ifTrue:[
   431 	    shellPath := '/bin/sh'.
   527 	    shellPath := '/bin/sh'.
   432 	    shellArgs := Array with:'sh' with:'-c' with:aCommandString.
   528 	    shellArgs := Array with:'sh' with:'-c' with:aCommandString.
   433         ] ifFalse:[
   529 	] ifFalse:[
   434             osType == #win32 ifTrue:[
   530 	    osType == #win32 ifTrue:[
   435 	        shellPath := 'C:\WINNT\System32\cmd /c'.
   531 		shellPath := 'C:\WINNT\System32\cmd /c'.
   436 	        shellArgs := aCommandString.
   532 		shellArgs := aCommandString.
   437 	    ] ifFalse:[
   533 	    ] ifFalse:[
   438     		OperatingSystem closeFd:execFd; closeFd:myFd.
   534 		OperatingSystem closeFd:execFd; closeFd:myFd.
   439 		"/
   535 		"/
   440 		"/ dont know how to do it ...
   536 		"/ dont know how to do it ...
   441 		"/
   537 		"/
   442                 ^ self openError
   538 		^ self openError
   443 	    ]
   539 	    ]
   444 	].
   540 	].
   445         mode = 'r' ifTrue:[
   541 	mode = 'r' ifTrue:[
   446             execFd := pipeFdArray at:2.
   542 	    execFd := pipeFdArray at:2.
   447             execFdArray := Array with:0 with:execFd with:2.
   543 	    execFdArray := Array with:0 with:execFd with:2.
   448             myFd := pipeFdArray at:1.
   544 	    myFd := pipeFdArray at:1.
   449         ] ifFalse:[
   545 	] ifFalse:[
   450             execFd := pipeFdArray at:1.
   546 	    execFd := pipeFdArray at:1.
   451             execFdArray := Array with:execFd with:1 with:2.
   547 	    execFdArray := Array with:execFd with:1 with:2.
   452             myFd := pipeFdArray at:2.
   548 	    myFd := pipeFdArray at:2.
   453         ].
   549 	].
   454 	closeFdArray := Array with:myFd.
   550 	closeFdArray := Array with:myFd.
   455     ].
   551     ].
   456 
   552 
   457 
   553 
   458     "/ must block here, to avoid races due to early finishing
   554     "/ must block here, to avoid races due to early finishing
   460 
   556 
   461     blocked := OperatingSystem blockInterrupts.
   557     blocked := OperatingSystem blockInterrupts.
   462 
   558 
   463     pid := Processor 
   559     pid := Processor 
   464 	       monitor:[
   560 	       monitor:[
   465 	          OperatingSystem 
   561 		  OperatingSystem 
   466 		      exec:shellPath
   562 		      exec:shellPath
   467                       withArguments:shellArgs
   563 		      withArguments:shellArgs
   468                       fileDescriptors:execFdArray
   564 		      fileDescriptors:execFdArray
   469 		      closeDescriptors:closeFdArray
   565 		      closeDescriptors:closeFdArray
   470                       fork:true
   566 		      fork:true
   471 		      newPgrp:true.
   567 		      newPgrp:true.
   472 	       ]
   568 	       ]
   473 	       action:[:status |
   569 	       action:[:status |
   474                   status stillAlive ifFalse:[
   570 		  status stillAlive ifFalse:[
   475 		      exitStatus := status.
   571 		      exitStatus := status.
   476                       pid := nil.
   572 		      pid := nil.
   477                       exitSema signal.
   573 		      exitSema signal.
   478 	          ].
   574 		  ].
   479                ].
   575 	       ].
   480 
   576 
   481     (osType ~~ #vms) ifTrue:[
   577     (osType ~~ #vms) ifTrue:[
   482         OperatingSystem closeFd:execFd.
   578 	OperatingSystem closeFd:execFd.
   483     ].
   579     ].
   484 
   580 
   485     pid notNil ifTrue:[
   581     pid notNil ifTrue:[
   486         (osType == #win32) ifTrue:[
   582 	(osType == #win32) ifTrue:[
   487             self setFileHandle:myFd mode:mode
   583 	    self setFileHandle:myFd mode:mode
   488 	] ifFalse:[
   584 	] ifFalse:[
   489 	    (osType == #vms) ifTrue:[
   585 	    (osType == #vms) ifTrue:[
   490 		"/
   586 		"/
   491 		"/ reopen the mailbox as a file ...
   587 		"/ reopen the mailbox as a file ...
   492 		"/
   588 		"/
   493     	        mbxName := OperatingSystem mailBoxNameOf:mbx.
   589 		mbxName := OperatingSystem mailBoxNameOf:mbx.
   494 		mbxName notNil ifTrue:[
   590 		mbxName notNil ifTrue:[
   495 		    super open:mbxName withMode:mode
   591 		    super open:mbxName withMode:mode
   496 		].
   592 		].
   497 	    ] ifFalse:[
   593 	    ] ifFalse:[
   498                 self setFileDescriptor:myFd mode:mode.
   594 		self setFileDescriptor:myFd mode:mode.
   499 	    ]
   595 	    ]
   500 	]
   596 	]
   501     ] ifFalse:[
   597     ] ifFalse:[
   502         lastErrorNumber := OperatingSystem currentErrorNumber.
   598 	lastErrorNumber := OperatingSystem currentErrorNumber.
   503         osType ~~ #vms ifTrue:[
   599 	osType ~~ #vms ifTrue:[
   504             OperatingSystem closeFd:myFd.
   600 	    OperatingSystem closeFd:myFd.
   505 	] ifFalse:[
   601 	] ifFalse:[
   506 	    OperatingSystem destroyMailBox:mbx
   602 	    OperatingSystem destroyMailBox:mbx
   507 	].
   603 	].
   508     ].
   604     ].
   509 
   605 
   510     blocked ifFalse:[
   606     blocked ifFalse:[
   511         OperatingSystem unblockInterrupts
   607 	OperatingSystem unblockInterrupts
   512     ].
   608     ].
   513 
   609 
   514     lastErrorNumber notNil ifTrue:[
   610     lastErrorNumber notNil ifTrue:[
   515         "
   611 	"
   516          the pipe open failed for some reason ...
   612 	 the pipe open failed for some reason ...
   517          ... this may be either due to an invalid command string,
   613 	 ... this may be either due to an invalid command string,
   518          or due to the system running out of memory (when forking
   614 	 or due to the system running out of memory (when forking
   519          the unix process)
   615 	 the unix process)
   520         "
   616 	"
   521         ^ self openError
   617 	^ self openError
   522     ].
   618     ].
   523 
   619 
   524     commandString := aCommandString.
   620     commandString := aCommandString.
   525 %{
   621 %{
   526     /* LINUX stdio is corrupt here ... */
   622     /* LINUX stdio is corrupt here ... */
   553 ! !
   649 ! !
   554 
   650 
   555 !PipeStream class methodsFor:'documentation'!
   651 !PipeStream class methodsFor:'documentation'!
   556 
   652 
   557 version
   653 version
   558     ^ '$Header: /cvs/stx/stx/libbasic/PipeStream.st,v 1.58 1997-09-22 19:05:40 cg Exp $'
   654     ^ '$Header: /cvs/stx/stx/libbasic/PipeStream.st,v 1.59 1997-09-22 19:38:56 cg Exp $'
   559 ! !
   655 ! !
   560 PipeStream initialize!
   656 PipeStream initialize!