194 BrokenPipeSignal nameClass:self message:#brokenPipeSignal. |
194 BrokenPipeSignal nameClass:self message:#brokenPipeSignal. |
195 BrokenPipeSignal notifierString:'write on a pipe with no one to read'. |
195 BrokenPipeSignal notifierString:'write on a pipe with no one to read'. |
196 ] |
196 ] |
197 ! ! |
197 ! ! |
198 |
198 |
199 !PipeStream class methodsFor:'instance creation'! |
199 !PipeStream class methodsFor:'instance creation'! |
200 |
200 |
201 readingFrom:commandString |
201 readingFrom:commandString |
202 "create and return a new pipeStream which can read from the unix command |
202 "create and return a new pipeStream which can read from the unix command |
203 given by command." |
203 given by command." |
204 |
204 |
205 ^ (self basicNew) readingFrom:commandString |
205 ^ (self basicNew) readingFrom:commandString |
206 |
206 |
207 "PipeStream readingFrom:'ls -l'" |
207 " |
|
208 PipeStream readingFrom:'ls -l' |
|
209 |
|
210 |s| |
|
211 s := PipeStream readingFrom:'sh -c sleep\ 600'. |
|
212 (Delay forSeconds:2) wait. |
|
213 s shutDown |
|
214 " |
|
215 |
|
216 "Modified: 24.4.1996 / 09:09:25 / stefan" |
208 ! |
217 ! |
209 |
218 |
210 writingTo:commandString |
219 writingTo:commandString |
211 "create and return a new pipeStream which can write to the unix command |
220 "create and return a new pipeStream which can write to the unix command |
212 given by command." |
221 given by command." |
228 |
237 |
229 commandString |
238 commandString |
230 "return the command string" |
239 "return the command string" |
231 |
240 |
232 ^ commandString |
241 ^ commandString |
|
242 ! |
|
243 |
|
244 exitStatus |
|
245 "return exitStatus" |
|
246 |
|
247 ^ exitStatus |
|
248 |
|
249 "Created: 28.12.1995 / 14:54:41 / stefan" |
|
250 ! |
|
251 |
|
252 pid |
|
253 "return pid" |
|
254 |
|
255 ^ pid |
|
256 |
|
257 "Created: 28.12.1995 / 14:54:30 / stefan" |
233 ! ! |
258 ! ! |
234 |
259 |
235 !PipeStream methodsFor:'instance release'! |
260 !PipeStream methodsFor:'instance release'! |
236 |
261 |
237 closeFile |
262 closeFile |
238 "low level close - redefined since we close a pipe here. |
263 "low level close |
239 This waits for the command to finish. |
264 This waits for the command to finish. |
240 Use shutDown for a fast (nonBlocking) close." |
265 Use shutDown for a fast (nonBlocking) close." |
241 |
266 |
242 %{ /* UNLIMITEDSTACK */ |
267 filePointer notNil ifTrue:[ |
243 #if !defined(transputer) && !defined(MSDOS_LIKE) |
268 super closeFile. |
244 OBJ fp; |
269 filePointer := nil. |
245 |
270 pid notNil ifTrue:[ |
246 if ((fp = __INST(filePointer)) != nil) { |
271 exitSema wait. |
247 __INST(filePointer) = nil; |
272 ]. |
248 /* |
273 ]. |
249 * allow interrupt even when blocking here ... |
|
250 */ |
|
251 __BEGIN_INTERRUPTABLE__ |
|
252 pclose(__FILEVal(fp)); |
|
253 __END_INTERRUPTABLE__ |
|
254 } |
|
255 #endif /* not transputer && not MSDOS_LIKE */ |
|
256 %} |
|
257 ! |
274 ! |
258 |
275 |
259 closeFileDescriptor |
276 closeFileDescriptor |
260 "alternative very low level close |
277 "alternative very low level close |
261 This closes the underlying OS-fileDescriptor |
278 This closes the underlying OS-fileDescriptor |
284 |
301 |
285 self shutDown |
302 self shutDown |
286 ! |
303 ! |
287 |
304 |
288 shutDown |
305 shutDown |
289 "close the Stream, ignoring any broken-pipe errors" |
306 "close the Stream, ignoring any broken-pipe errors. |
|
307 Terminate the command" |
290 |
308 |
291 BrokenPipeSignal catch:[ |
309 BrokenPipeSignal catch:[ |
292 Lobby unregister:self. |
310 |tpid| |
293 self closeFileDescriptor |
311 |
|
312 Lobby unregister:self. |
|
313 self closeFileDescriptor. |
|
314 tpid := pid. "copy pid to avoid race" |
|
315 tpid notNil ifTrue:[ |
|
316 "/ |
|
317 "/ Terminate both the process and group, just in case the |
|
318 "/ operating system does not support process groups. |
|
319 "/ |
|
320 OperatingSystem terminateProcess:tpid. |
|
321 OperatingSystem terminateProcessGroup:tpid. |
|
322 pid := nil. |
|
323 ]. |
294 ] |
324 ] |
|
325 |
|
326 "Modified: 23.5.1996 / 09:15:41 / stefan" |
295 ! ! |
327 ! ! |
296 |
328 |
297 !PipeStream methodsFor:'private'! |
329 !PipeStream methodsFor:'private'! |
298 |
330 |
299 atEnd |
331 atEnd |
321 . |
353 . |
322 ^ super atEnd |
354 ^ super atEnd |
323 ! |
355 ! |
324 |
356 |
325 openPipeFor:aCommandString withMode:mode |
357 openPipeFor:aCommandString withMode:mode |
326 "open a pipe to the unix command in aCcommandString; |
358 "open a pipe to the unix command in commandString; |
327 mode may be 'r' or 'w'" |
359 mode may be 'r' or 'w'" |
328 |
360 |
329 |retVal| |
361 |blocked pipeFdArray execFdArray execFd myFd| |
330 |
362 |
331 filePointer notNil ifTrue:[ |
363 filePointer notNil ifTrue:[ |
332 "the pipe was already open ... |
364 "the pipe was already open ... |
333 this should (can) not happen." |
365 this should (can) not happen." |
334 ^ self errorOpen |
366 ^ self errorOpen |
335 ]. |
367 ]. |
336 |
368 lastErrorNumber := nil. |
337 %{ /* STACK: 32000 */ |
369 exitStatus := nil. |
338 #if !defined(transputer) && !defined(MSDOS_LIKE) |
370 exitSema := Semaphore new. |
339 FILE *f; |
371 |
340 OBJ fp; |
372 pipeFdArray := OperatingSystem makePipe. |
341 |
373 pipeFdArray isNil ifTrue:[ |
342 __INST(lastErrorNumber) = nil; |
374 lastErrorNumber := OperatingSystem currentErrorNumber. |
343 |
375 ^ self openError |
344 if (__isString(aCommandString) && __isString(mode)) { |
376 ]. |
345 __BEGIN_INTERRUPTABLE__ |
377 |
346 do { |
378 mode = 'r' ifTrue:[ |
347 # ifdef LINUX |
379 execFd := pipeFdArray at:2. |
348 /* LINUX returns a non-NULL f even when interrupted */ |
380 execFdArray := Array with:0 with:execFd with:2. |
349 errno = 0; |
381 myFd := pipeFdArray at:1. |
350 f = (FILE *)popen((char *) __stringVal(aCommandString), |
382 ] ifFalse:[ |
351 (char *) __stringVal(mode)); |
383 execFd := pipeFdArray at:1. |
352 if (errno == EINTR) |
384 execFdArray := Array with:execFd with:1 with:2. |
353 f = NULL; |
385 myFd := pipeFdArray at:2. |
354 # else |
386 ]. |
355 f = (FILE *)popen((char *) __stringVal(aCommandString), |
387 |
356 (char *) __stringVal(mode)); |
388 blocked := OperatingSystem blockInterrupts. |
357 # endif /* LINUX */ |
389 pid := OperatingSystem exec:'/bin/sh' |
358 } while ((f == NULL) && (errno == EINTR)); |
390 withArguments:(Array with:'sh' with:'-c' with:aCommandString) |
359 __END_INTERRUPTABLE__ |
391 fileDescriptors:execFdArray |
360 |
392 closeDescriptors:(Array with:myFd) |
361 if (f == NULL) { |
393 fork:true |
362 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
394 newPgrp:true. |
363 } else { |
395 |
364 clearerr(f); |
396 OperatingSystem closeFd:execFd. |
365 __INST(filePointer) = fp = __MKOBJ(f); __STORE(self, fp); |
397 pid > 0 ifTrue:[ |
366 retVal = self; |
398 self fileDescriptor:myFd withMode:mode. |
367 } |
399 Processor monitorPid:pid action:[ :stat | |
368 } |
400 exitStatus := stat. |
369 #endif /* not transputer && not MSDOS_LIKE */ |
401 pid := nil. |
370 %}. |
402 exitSema signal. |
371 retVal notNil ifTrue:[ |
403 ]. |
372 commandString := aCommandString. |
404 ] ifFalse:[ |
373 buffered := true. |
405 pid := nil. |
374 hitEOF := false. |
406 lastErrorNumber := OperatingSystem currentErrorNumber. |
375 binary := false. |
407 OperatingSystem closeFd:myFd. |
376 Lobby register:self |
408 ]. |
377 ]. |
409 blocked ifFalse:[ |
378 lastErrorNumber notNil ifTrue:[ |
410 OperatingSystem unblockInterrupts |
379 " |
411 ]. |
380 the pipe open failed for some reason ... |
412 |
381 ... this may be either due to an invalid command string, |
413 lastErrorNumber isNil ifTrue:[ |
382 or due to the system running out of memory (when forking |
414 commandString := aCommandString. |
383 the unix process) |
415 buffered := true. |
384 " |
416 hitEOF := false. |
385 ^ self openError |
417 binary := false. |
386 ]. |
418 Lobby register:self |
387 ^ retVal |
419 ] ifFalse:[ |
|
420 " |
|
421 the pipe open failed for some reason ... |
|
422 ... this may be either due to an invalid command string, |
|
423 or due to the system running out of memory (when forking |
|
424 the unix process) |
|
425 " |
|
426 ^ self openError |
|
427 ]. |
|
428 ^ self |
|
429 |
|
430 "Modified: 23.4.1996 / 17:05:59 / stefan" |
388 ! |
431 ! |
389 |
432 |
390 readingFrom:command |
433 readingFrom:command |
391 "setup the receiver to read from command" |
434 "setup the receiver to read from command" |
392 |
435 |