PipeStream.st
author claus
Fri, 05 Aug 1994 02:55:07 +0200
changeset 92 0c73b48551ac
parent 88 81dacba7a63a
child 93 e31220cb391f
permissions -rw-r--r--
*** empty log message ***
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
     1
"
5
67342904af11 *** empty log message ***
claus
parents: 3
diff changeset
     2
 COPYRIGHT (c) 1989 by Claus Gittinger
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
     3
              All Rights Reserved
a27a279701f8 Initial revision
claus
parents:
diff changeset
     4
a27a279701f8 Initial revision
claus
parents:
diff changeset
     5
 This software is furnished under a license and may be used
a27a279701f8 Initial revision
claus
parents:
diff changeset
     6
 only in accordance with the terms of that license and with the
a27a279701f8 Initial revision
claus
parents:
diff changeset
     7
 inclusion of the above copyright notice.   This software may not
a27a279701f8 Initial revision
claus
parents:
diff changeset
     8
 be provided or otherwise made available to, or used by, any
a27a279701f8 Initial revision
claus
parents:
diff changeset
     9
 other person.  No title to or ownership of the software is
a27a279701f8 Initial revision
claus
parents:
diff changeset
    10
 hereby transferred.
a27a279701f8 Initial revision
claus
parents:
diff changeset
    11
"
a27a279701f8 Initial revision
claus
parents:
diff changeset
    12
a27a279701f8 Initial revision
claus
parents:
diff changeset
    13
NonPositionableExternalStream subclass:#PipeStream
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
    14
       instanceVariableNames:'commandString'
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    15
       classVariableNames:'BrokenPipeSignal'
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    16
       poolDictionaries:''
a27a279701f8 Initial revision
claus
parents:
diff changeset
    17
       category:'Streams-External'
a27a279701f8 Initial revision
claus
parents:
diff changeset
    18
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
    19
a27a279701f8 Initial revision
claus
parents:
diff changeset
    20
PipeStream comment:'
5
67342904af11 *** empty log message ***
claus
parents: 3
diff changeset
    21
COPYRIGHT (c) 1989 by Claus Gittinger
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    22
              All Rights Reserved
a27a279701f8 Initial revision
claus
parents:
diff changeset
    23
'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
    24
88
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    25
!PipeStream class methodsFor:'documentation'!
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    26
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    27
copyright
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    28
"
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    29
 COPYRIGHT (c) 1989 by Claus Gittinger
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    30
              All Rights Reserved
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
    31
88
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    32
 This software is furnished under a license and may be used
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    33
 only in accordance with the terms of that license and with the
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    34
 inclusion of the above copyright notice.   This software may not
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    35
 be provided or otherwise made available to, or used by, any
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    36
 other person.  No title to or ownership of the software is
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    37
 hereby transferred.
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    38
"
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    39
!
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    40
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    41
version
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    42
"
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    43
$Header: /cvs/stx/stx/libbasic/PipeStream.st,v 1.11 1994-06-02 16:21:16 claus Exp $
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    44
"
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    45
!
2
claus
parents: 1
diff changeset
    46
claus
parents: 1
diff changeset
    47
documentation
claus
parents: 1
diff changeset
    48
"
claus
parents: 1
diff changeset
    49
Pipestreams allow reading or writing from/to a unix command.
claus
parents: 1
diff changeset
    50
For example, to get a stream reading the output of an 'ls -l'
claus
parents: 1
diff changeset
    51
command, a PipeStream can be created with:
claus
parents: 1
diff changeset
    52
claus
parents: 1
diff changeset
    53
        PipeStream readingFrom:'ls -l'
claus
parents: 1
diff changeset
    54
claus
parents: 1
diff changeset
    55
the characters of the commands output can be read using the
claus
parents: 1
diff changeset
    56
standard stream messages as next, nextLine etc.
claus
parents: 1
diff changeset
    57
claus
parents: 1
diff changeset
    58
If a writing pipeStream is written to, after the command has finished,
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    59
UNIX will generate an error-signal (SIGPIPE), which will raise the
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    60
BrokenPipeSignal. 
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    61
Thus, to handle this condition correctly, the following code is suggested:
2
claus
parents: 1
diff changeset
    62
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    63
        |p|
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    64
        p := PipeStream writingTo:'echo hello'.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    65
        PipeStream brokenPipeSignal handle:[:ex |
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    66
            'broken pipe' printNewline.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    67
            p shutDown.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    68
            ex return
2
claus
parents: 1
diff changeset
    69
        ] do:[
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    70
            p nextPutLine:'oops'.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    71
           'after write' printNewline.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    72
            p close.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    73
           'after close' printNewline
2
claus
parents: 1
diff changeset
    74
        ]
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    75
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    76
Notice, that if the Stream is buffered, the Signal may occur some time after
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    77
the write - or even at close time; to avoid a recursive signal in the exception
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    78
handler, a shutDown is useful there.
2
claus
parents: 1
diff changeset
    79
"
claus
parents: 1
diff changeset
    80
! !
claus
parents: 1
diff changeset
    81
88
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    82
%{
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    83
#include <stdio.h>
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    84
#include <errno.h>
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    85
#ifndef transputer
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    86
# include <sys/types.h>
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    87
# include <sys/stat.h>
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    88
#endif
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    89
%}
81dacba7a63a *** empty log message ***
claus
parents: 85
diff changeset
    90
2
claus
parents: 1
diff changeset
    91
!PipeStream class methodsFor:'initialization'!
claus
parents: 1
diff changeset
    92
claus
parents: 1
diff changeset
    93
initialize
claus
parents: 1
diff changeset
    94
    "setup the signal"
claus
parents: 1
diff changeset
    95
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    96
    BrokenPipeSignal isNil ifTrue:[
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    97
        BrokenPipeSignal := (Signal new) mayProceed:true.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    98
        BrokenPipeSignal notifierString:'write on a pipe with no one to read'.
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
    99
    ]
2
claus
parents: 1
diff changeset
   100
! !
claus
parents: 1
diff changeset
   101
claus
parents: 1
diff changeset
   102
!PipeStream class methodsFor:'signal access'!
claus
parents: 1
diff changeset
   103
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   104
brokenPipeSignal
2
claus
parents: 1
diff changeset
   105
    "return the signal used to handle SIGPIPE unix-signals"
claus
parents: 1
diff changeset
   106
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   107
    ^ BrokenPipeSignal
2
claus
parents: 1
diff changeset
   108
! !
claus
parents: 1
diff changeset
   109
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   110
!PipeStream class methodsFor:'instance creation'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   111
2
claus
parents: 1
diff changeset
   112
writingTo:commandString
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   113
    "create and return a new pipeStream which can write to the unix command
a27a279701f8 Initial revision
claus
parents:
diff changeset
   114
     given by command."
a27a279701f8 Initial revision
claus
parents:
diff changeset
   115
2
claus
parents: 1
diff changeset
   116
    ^ (self basicNew) writingTo:commandString
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   117
a27a279701f8 Initial revision
claus
parents:
diff changeset
   118
    "PipeStream writingTo:'sort'"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   119
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   120
2
claus
parents: 1
diff changeset
   121
readingFrom:commandString
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   122
    "create and return a new pipeStream which can read from the unix command
a27a279701f8 Initial revision
claus
parents:
diff changeset
   123
     given by command."
a27a279701f8 Initial revision
claus
parents:
diff changeset
   124
2
claus
parents: 1
diff changeset
   125
    ^ (self basicNew) readingFrom:commandString
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   126
2
claus
parents: 1
diff changeset
   127
    "PipeStream readingFrom:'ls -l'"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   128
! !
a27a279701f8 Initial revision
claus
parents:
diff changeset
   129
a27a279701f8 Initial revision
claus
parents:
diff changeset
   130
!PipeStream methodsFor:'instance release'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   131
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   132
shutDown
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   133
    "close the Stream, ignoring any broken-pipe errors"
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   134
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   135
    BrokenPipeSignal catch:[self closeFile]
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   136
!
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   137
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   138
closeFile
a27a279701f8 Initial revision
claus
parents:
diff changeset
   139
    "low level close - redefined since we close a pipe here"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   140
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   141
%{  /* UNLIMITEDSTACK */
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   142
#ifndef transputer
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   143
    extern int _immediateInterrupt;
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   144
    int savInt;
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   145
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   146
    if (_INST(filePointer) != nil) {
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   147
        savInt = _immediateInterrupt;
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   148
        /*
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   149
         * allow interrupt even when blocking here ...
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   150
         */
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   151
        _immediateInterrupt = 1;
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   152
        pclose(MKFD(_INST(filePointer)));
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   153
        _immediateInterrupt = savInt;
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   154
    }
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   155
#endif
a27a279701f8 Initial revision
claus
parents:
diff changeset
   156
%}
a27a279701f8 Initial revision
claus
parents:
diff changeset
   157
! !
a27a279701f8 Initial revision
claus
parents:
diff changeset
   158
a27a279701f8 Initial revision
claus
parents:
diff changeset
   159
!PipeStream methodsFor:'private'!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   160
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   161
openPipeFor:aCommandString withMode:mode
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   162
    "open a pipe to the unix command in aCcommandString; mode may be 'r' or 'w'"
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   163
a27a279701f8 Initial revision
claus
parents:
diff changeset
   164
    |retVal|
a27a279701f8 Initial revision
claus
parents:
diff changeset
   165
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   166
%{  /* STACK: 32000 */
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   167
#ifndef transputer
a27a279701f8 Initial revision
claus
parents:
diff changeset
   168
    {
a27a279701f8 Initial revision
claus
parents:
diff changeset
   169
        FILE *f;
a27a279701f8 Initial revision
claus
parents:
diff changeset
   170
        extern errno;
2
claus
parents: 1
diff changeset
   171
        extern int _immediateInterrupt;
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   172
        int savInt;
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   173
57
db9677479d35 *** empty log message ***
claus
parents: 49
diff changeset
   174
        if (__isString(aCommandString) && __isString(mode)) {
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   175
            savInt = _immediateInterrupt;
2
claus
parents: 1
diff changeset
   176
            _immediateInterrupt = 1;
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   177
            do {
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   178
#ifdef LINUX
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   179
                /* LINUX returns a non-NULL f even when interrupted */
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   180
                errno = 0;
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   181
                f = (FILE *)popen((char *) _stringVal(aCommandString),
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   182
                                  (char *) _stringVal(mode));
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   183
                if (errno == EINTR)
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   184
                    f = NULL;
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   185
#else
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   186
                f = (FILE *)popen((char *) _stringVal(aCommandString),
10
claus
parents: 5
diff changeset
   187
                                  (char *) _stringVal(mode));
13
62303f84ff5f *** empty log message ***
claus
parents: 10
diff changeset
   188
#endif
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   189
            } while ((f == NULL) && (errno == EINTR));
10
claus
parents: 5
diff changeset
   190
            _immediateInterrupt = savInt;
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   191
            if (f == NULL) {
85
claus
parents: 57
diff changeset
   192
                ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   193
            } else {
a27a279701f8 Initial revision
claus
parents:
diff changeset
   194
                _INST(filePointer) = MKOBJ(f);
a27a279701f8 Initial revision
claus
parents:
diff changeset
   195
                retVal = self;
a27a279701f8 Initial revision
claus
parents:
diff changeset
   196
            }
a27a279701f8 Initial revision
claus
parents:
diff changeset
   197
        }
a27a279701f8 Initial revision
claus
parents:
diff changeset
   198
    }
a27a279701f8 Initial revision
claus
parents:
diff changeset
   199
#endif
a27a279701f8 Initial revision
claus
parents:
diff changeset
   200
%}
a27a279701f8 Initial revision
claus
parents:
diff changeset
   201
.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   202
    retVal notNil ifTrue:[
49
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   203
        commandString := aCommandString.
f1c2d75f2eb6 *** empty log message ***
claus
parents: 32
diff changeset
   204
        buffered := true.
32
ee1a621c696c *** empty log message ***
claus
parents: 13
diff changeset
   205
        Lobby register:self
1
a27a279701f8 Initial revision
claus
parents:
diff changeset
   206
    ].
a27a279701f8 Initial revision
claus
parents:
diff changeset
   207
    ^ retVal
a27a279701f8 Initial revision
claus
parents:
diff changeset
   208
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   209
a27a279701f8 Initial revision
claus
parents:
diff changeset
   210
readingFrom:command
a27a279701f8 Initial revision
claus
parents:
diff changeset
   211
    "setup the receiver to read from command"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   212
a27a279701f8 Initial revision
claus
parents:
diff changeset
   213
    self readonly.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   214
    ^ self openPipeFor:command withMode:'r'
a27a279701f8 Initial revision
claus
parents:
diff changeset
   215
!
a27a279701f8 Initial revision
claus
parents:
diff changeset
   216
a27a279701f8 Initial revision
claus
parents:
diff changeset
   217
writingTo:command
a27a279701f8 Initial revision
claus
parents:
diff changeset
   218
    "setup the receiver to write to command"
a27a279701f8 Initial revision
claus
parents:
diff changeset
   219
a27a279701f8 Initial revision
claus
parents:
diff changeset
   220
    self writeonly.
a27a279701f8 Initial revision
claus
parents:
diff changeset
   221
    ^ self openPipeFor:command withMode:'w'
a27a279701f8 Initial revision
claus
parents:
diff changeset
   222
! !