0 0 1
default
Jean-Francois Pieronne - 5 years ago 2014-10-21 09:15:32
jf.pieronne@laposte.net
Add vms/popen2.py initial version
1 file changed with 300 insertions and 0 deletions:
↑ Collapse Diff ↑
 
new file 100644
1
 
"""OpenVMS popen2, popen3 and popen4 routines"""
2
 

	
3
 
import vms.crtl
4
 
import vms.descrip
5
 
import os
6
 
import time
7
 
import ctypes
8
 

	
9
 
VMSSYS = "/SYS$COMMON/SYSLIB/SYS$PUBLIC_VECTORS.EXE"
10
 
SYS = ctypes.CDLL(VMSSYS)
11
 
vmscrembx = getattr(SYS, "SYS$CREMBX")
12
 
vmsclref  = getattr(SYS, "SYS$CLREF")
13
 
vmsdassgn = getattr(SYS, "SYS$DASSGN")
14
 
vmswaitfr = getattr(SYS, "SYS$WAITFR")
15
 

	
16
 
VMSLIBRTL = "/SYS$COMMON/SYSLIB/LIBRTL.EXE"
17
 
LIBRTL = ctypes.CDLL(VMSLIBRTL)
18
 
vmsget_ef = getattr(LIBRTL,"LIB$GET_EF")
19
 
vmsfree_ef= getattr(LIBRTL,"LIB$FREE_EF")
20
 
vmsgetdvi = getattr(LIBRTL,"LIB$GETDVI")
21
 
vmsspawn  = getattr(LIBRTL,"LIB$SPAWN")
22
 

	
23
 
def vmscall(f, *args, **kargs):
24
 
    s = f(*args, **kargs)
25
 
    if s & 1:
26
 
        return s
27
 
    else:
28
 
        raise VMSError(s)
29
 

	
30
 
def crembx():
31
 
    chan = ctypes.c_ushort()
32
 
    s = vmscall(vmscrembx, ctypes.c_byte(0), ctypes.byref(chan), None, None,
33
 
                None, None, None, None, None)
34
 
    return chan.value
35
 

	
36
 
def clref(efn):
37
 
    return vmscall(vmsclref, ctypes.c_uint(efn))
38
 

	
39
 
def dassgn(chan):
40
 
    return vmscall(vmsdassgn, ctypes.c_ushort(chan))
41
 

	
42
 
def waitfr(efn):
43
 
    return vmscall(vmswaitfr, ctypes.c_uint(efn))
44
 

	
45
 
def get_ef():
46
 
    efn = ctypes.c_uint()
47
 
    s = vmscall(vmsget_ef, ctypes.byref(efn))
48
 
    return efn.value
49
 

	
50
 
def free_ef(efn):
51
 
    return vmscall(vmsfree_ef, ctypes.byref(ctypes.c_uint(efn)))
52
 

	
53
 
def getdvi(itm, chan):
54
 
    retlen = ctypes.c_ushort()
55
 
    nambuf = ctypes.create_string_buffer(31 + 1)
56
 
    s = vmscall(vmsgetdvi, ctypes.byref(ctypes.c_uint(itm)),
57
 
                ctypes.byref(ctypes.c_ushort(chan)), None, None,
58
 
                vms.descrip.bydesc(nambuf), ctypes.byref(retlen))
59
 
    return nambuf.raw[:retlen.value]
60
 

	
61
 
def spawn(cmd, dev_i, dev_o, flags, efn):
62
 
    pid = ctypes.c_uint()
63
 
    completion_status = ctypes.c_uint()
64
 
    s = vmscall(vmsspawn, vms.descrip.bydesc(cmd),
65
 
                vms.descrip.bydesc(dev_i), vms.descrip.bydesc(dev_o),
66
 
                ctypes.byref(ctypes.c_uint(flags)),
67
 
                None, ctypes.byref(pid),
68
 
                ctypes.byref(completion_status),
69
 
                ctypes.byref(ctypes.c_ubyte(efn)),
70
 
                None, None, None, None, None)
71
 
    return pid.value, completion_status
72
 

	
73
 
__all__ = ["popen2", "popen3", "popen4"]
74
 

	
75
 
class filevms(file):
76
 
    def __init__(self, name, *args, **kwargs):
77
 
        super(filevms, self).__init__(name, *args, **kwargs)
78
 
        self.handle = None
79
 
    def close(self):
80
 
        if self.closed:
81
 
            return
82
 
        if 'w' in self.mode:
83
 
            self.flush()
84
 
            os.fsync(self)
85
 
        super(filevms, self).close()
86
 
        if (self.handle.p2cwrite.closed and self.handle.c2pread.closed and
87
 
            (self.handle.c2rerror is None or 
88
 
             self.handle.c2rerror and self.handle.c2rerror.closed)):
89
 
            self.handle.close()
90
 

	
91
 
class vms_popenx_handle(object):
92
 
    def __init__(self, cmd, mode, bufsize, popentype=2):
93
 
        if mode not in ('t', 'b'):
94
 
            raise ValueError("mode must be 't' or 'b'")
95
 
        if popentype not in (2, 3, 4):
96
 
            raise ValueError("popentype must be 2 or 3 or 4")
97
 
        self.popentype = popentype
98
 
        self.completion_status = None
99
 
        self.closed = False
100
 
        chan_i = crembx()
101
 
        chan_o = crembx()
102
 
        dev_i = getdvi(32, chan_i) # DVI__DEVNAM = 32
103
 
        dev_o = getdvi(32, chan_o)
104
 
        if popentype == 2:
105
 
            chan_e = None
106
 
            dev_e = None
107
 
        elif popentype == 3:
108
 
            chan_e = crembx()
109
 
            dev_e = getdvi(32, chan_e)
110
 
        elif popentype == 4:
111
 
            chan_e = chan_o
112
 
            dev_e = None
113
 
        if mode == "t":
114
 
            self.p2cwrite = filevms(dev_i, 'w', buffering=0,
115
 
                                    rmsattr=['ctx=stm', 'rfm=stmlf'])
116
 
            self.c2pread = filevms(dev_o, 'r', buffering=0,
117
 
                                   rmsattr=['ctx=popen', 'rat=none'])
118
 
            if popentype == 2:
119
 
                self.c2rerror = None
120
 
            elif popentype == 3:
121
 
                self.c2rerror = filevms(dev_e, 'r', buffering=0,
122
 
                                        rmsattr=['ctx=popen', 'rat=none'])
123
 
            elif popentype == 4:
124
 
                self.c2rerror = self.p2cwrite
125
 
        else:
126
 
            self.p2cwrite = filevms(dev_i, 'wb', buffering=0,
127
 
                                    rmsattr=['ctx=popen', 'rfm=stmlf'])
128
 
            self.c2pread = filevms(dev_o, 'rb', buffering=0,
129
 
                                   rmsattr=['ctx=popen', 'rat=none'])
130
 
            if popentype == 2:
131
 
                self.c2rerror = None
132
 
            elif popentype == 3:
133
 
                self.c2rerror = filevms(dev_e, 'rb', buffering=0,
134
 
                                        rmsattr=['ctx=popen', 'rat=none'])
135
 
            elif popentype == 4:
136
 
                self.c2rerror = self.p2cwrite
137
 
        self.p2cwrite.handle = self
138
 
        s = dassgn(chan_i)
139
 
        self.c2pread.handle = self
140
 
        s = dassgn(chan_o)
141
 
        if popentype == 3:
142
 
            self.c2rerror.handle = self
143
 
            s = dassgn(chan_e)
144
 
        if popentype == 2:
145
 
            cmd2 = cmd
146
 
            cmd = "define/nolog sys$error nla0:"
147
 
        elif popentype == 3:
148
 
            cmd2 = cmd
149
 
            cmd = "define/nolog sys$error %s" % (dev_e,)
150
 
        flags = 0x1L # CLI_M_NOWAIT
151
 
        self.efn = get_ef()
152
 
        clref(self.efn)
153
 
        self.pid, self.handle = spawn(cmd, dev_i, dev_o, flags,
154
 
                                      self.efn)
155
 
        if popentype == 3:
156
 
            self.p2cwrite.write('OPEN PYPOPEN2SYSERROR /WRITE %s' % (dev_e,))
157
 
        if popentype in (2, 3):
158
 
            self.p2cwrite.write(cmd2)
159
 
    def wait(self):
160
 
        waitfr(self.efn)
161
 
    def close(self):
162
 
        if self.closed:
163
 
           return
164
 
        self.closed = True
165
 
        if not self.p2cwrite.closed:
166
 
            self.p2cwrite.close()
167
 
        if not self.c2pread.closed:
168
 
            self.c2pread.close()
169
 
        if self.c2rerror and not self.c2rerror.closed:
170
 
            self.c2rerror.close() 
171
 
        self.wait()
172
 
        self.p2cwrite = self.c2pread = self.c2rerror = None
173
 
        free_ef(self.efn)
174
 
        self.completion_status = self.handle.value
175
 
        self.handle = None
176
 

	
177
 

	
178
 
def popen2(cmd, mode="t", bufsize=-1):
179
 
    """Execute the shell command 'cmd' in a sub-process.  On UNIX, 'cmd'
180
 
    may be a sequence, in which case arguments will be passed directly to
181
 
    the program without shell intervention (as with os.spawnv()).  If 'cmd'
182
 
    is a string it will be passed to the shell (as with os.system()). If
183
 
    'bufsize' is specified, it sets the buffer size for the I/O pipes.  The
184
 
    file objects (child_stdin, child_stdout) are returned."""
185
 
    import warnings
186
 
    msg = "os.popen2 is deprecated.  Use the subprocess module."
187
 
    warnings.warn(msg, DeprecationWarning, stacklevel=2)
188
 
    vph = vms_popenx_handle(cmd, mode, bufsize, popentype=2)
189
 
    return vph.p2cwrite, vph.c2pread
190
 

	
191
 
def popen3(cmd, mode="t", bufsize=-1):
192
 
    """Execute the shell command 'cmd' in a sub-process.  On UNIX, 'cmd'
193
 
    may be a sequence, in which case arguments will be passed directly to
194
 
    the program without shell intervention (as with os.spawnv()).  If 'cmd'
195
 
    is a string it will be passed to the shell (as with os.system()). If
196
 
    'bufsize' is specified, it sets the buffer size for the I/O pipes.  The
197
 
    file objects (child_stdin, child_stdout, child_stderr) are returned."""
198
 
    import warnings
199
 
    msg = "os.popen3 is deprecated.  Use the subprocess module."
200
 
    warnings.warn(msg, DeprecationWarning, stacklevel=2)
201
 
    vph = vms_popenx_handle(cmd, mode, bufsize, popentype=3)
202
 
    return vph.p2cwrite, vph.c2pread, vph.c2rerror
203
 

	
204
 
def popen4(cmd, mode="t", bufsize=-1):
205
 
    """Execute the shell command 'cmd' in a sub-process.  On UNIX, 'cmd'
206
 
    may be a sequence, in which case arguments will be passed directly to
207
 
    the program without shell intervention (as with os.spawnv()).  If 'cmd'
208
 
    is a string it will be passed to the shell (as with os.system()). If
209
 
    'bufsize' is specified, it sets the buffer size for the I/O pipes.  The
210
 
    file objects (child_stdin, child_stdout_stderr) are returned."""
211
 
    import warnings
212
 
    msg = "os.popen4 is deprecated.  Use the subprocess module."
213
 
    warnings.warn(msg, DeprecationWarning, stacklevel=2)
214
 
    vph = vms_popenx_handle(cmd, mode, bufsize, popentype=4)
215
 
    return vph.p2cwrite, vph.c2pread
216
 

	
217
 
def test_popen2():
218
 
    cmd = "type sys$input"
219
 
    teststr = "ab cd\n"
220
 
    expected = teststr.strip()
221
 
    print "testing popen2..."
222
 
    w, r = popen2(cmd)
223
 
    w.write(teststr)
224
 
    vms.crtl.write_eof_to_mbx(w.fileno())
225
 
    w.close()
226
 
    got = r.read()
227
 
    if got.strip() != expected:
228
 
        raise ValueError("wrote %r read %r" % (teststr, got))
229
 
    r.close()
230
 
    assert r.handle.completion_status & 1, "Subprocess final status should be 1"
231
 
    print "All OK"
232
 

	
233
 
def test_popen3():
234
 
    """ test.EXE runs the following test.C program:
235
 
    #include <stdio.h>
236
 

	
237
 
    void main()
238
 
    {
239
 
        char buf[80];
240
 
        fgets(buf,sizeof(buf),stdin);
241
 
        fprintf(stderr,buf);
242
 
    }
243
 
    """
244
 
    cmd = "run python_root:[local.vms]test.EXE"
245
 
    print "testing popen3..."
246
 
    w, r, e = popen3(cmd)
247
 
    teststr = "ab dc\n"
248
 
    expected = teststr.strip()
249
 
    w.write(teststr)
250
 
    w.close()
251
 
    # stdout must be read before stderr
252
 
    try:
253
 
      got = r.read()
254
 
    except EOFError:
255
 
      pass
256
 
    try:
257
 
      got = e.read()
258
 
    except EOFError:   
259
 
      pass
260
 
    if got.strip() != expected:
261
 
       raise ValueError("expecting %r read %r" % (expected, got))
262
 
    r.close()
263
 
    e.close()
264
 
    assert r.handle.completion_status & 1, "Subprocess final status should be 1"
265
 
    print "All OK"   
266
 

	
267
 
def test_popen4():
268
 
    cmd = "type sys$input"
269
 
    teststr = "ab cd\n"
270
 
    expected = teststr.strip()
271
 
    print "testing popen4..."
272
 
    w, r = popen4(cmd)
273
 
    w.write(teststr)
274
 
    vms.crtl.write_eof_to_mbx(w.fileno())
275
 
    w.close()
276
 
    got = r.read()
277
 
    if got.strip() != expected:
278
 
        raise ValueError("wrote %r read %r" % (teststr, got))
279
 
    r.close()
280
 
    assert r.handle.completion_status & 1, "Subprocess final status should be 1"
281
 

	
282
 
    teststr = "ab cd"
283
 
    expected = teststr.strip() + "\n" + teststr.strip()
284
 
    cmd = 'write sys$output "%s"' % (teststr,)
285
 
    w, r = popen4(cmd)
286
 
    cmd = 'write sys$error "%s"' % (teststr,)
287
 
    w.write(cmd)
288
 
    w.close()
289
 
    got = r.read()
290
 
    if got.strip() != expected:
291
 
        raise ValueError("wrote %r read %r" % (teststr, got))
292
 
    r.close()
293
 
    assert r.handle.completion_status & 1, "Subprocess final status should be 1"
294
 
    print "All OK"
295
 
    
296
 

	
297
 
if __name__=='__main__':
298
 
    test_popen2()
299
 
    test_popen3()
300
 
    test_popen4()
0 comments (0 inline, 0 general)