perl 3.0 patch #37 (combined patch)
[p5sagit/p5-mst-13.2.git] / os2 / popen.c
1 /* added real/protect mode branch at runtime and real mode version
2  * names changed for perl
3  * Kai Uwe Rommel
4  */
5
6 /*
7 Several people in the past have asked about having Unix-like pipe
8 calls in OS/2.  The following source file, adapted from 4.3 BSD Unix,
9 uses a #define to give you a pipe(2) call, and contains function
10 definitions for popen(3) and pclose(3).  Anyone with problems should
11 send mail to me; they seem to work fine.
12
13 Mark Towfigh
14 Racal Interlan, Inc.
15 ----------------------------------cut-here------------------------------------
16 */
17
18 /*
19  * The following code segment is derived from BSD 4.3 Unix.  See
20  * copyright below.  Any bugs, questions, improvements, or problems
21  * should be sent to Mark Towfigh (towfiq@interlan.interlan.com).
22  *
23  * Racal InterLan Inc.
24  */
25
26 /*
27  * Copyright (c) 1980 Regents of the University of California.
28  * All rights reserved.  The Berkeley software License Agreement
29  * specifies the terms and conditions for redistribution.
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <io.h>
35 #include <string.h>
36 #include <process.h>
37 #include <errno.h>
38
39 #define INCL_NOPM
40 #define INCL_DOS
41 #include <os2.h>
42
43 static FILE *dos_popen(const char *cmd, const char *flags);
44 static int dos_pclose(FILE *pipe);
45
46 /*
47  * emulate Unix pipe(2) call
48  */
49
50 #define tst(a,b)        (*mode == 'r'? (b) : (a))
51 #define READH           0
52 #define WRITEH          1
53
54 static  int       popen_pid[20];
55
56 FILE *mypopen(char *cmd, char *mode)
57 {
58         int p[2];
59         register myside, hisside, save_stream;
60         char *shell = getenv("COMPSPEC");
61
62         if ( shell == NULL )
63           shell = "C:\\OS2\\CMD.EXE";
64
65         if ( _osmode == DOS_MODE )
66           return dos_popen(cmd, mode);
67
68         if (DosMakePipe((PHFILE) &p[0], (PHFILE) &p[1], 4096) < 0)
69                 return NULL;
70
71         myside = tst(p[WRITEH], p[READH]);
72         hisside = tst(p[READH], p[WRITEH]);
73
74         /* set up file descriptors for remote function */
75         save_stream = dup(tst(0, 1));           /* don't lose stdin/out! */
76         if (dup2(hisside, tst(0, 1)) < 0)
77         {
78                 perror("dup2");
79                 return NULL;
80         }
81         close(hisside);
82
83         /*
84          * make sure that we can close our side of the pipe, by
85          * preventing it from being inherited!
86          */
87
88         /* set no-inheritance flag */
89         DosSetFHandState(myside, OPEN_FLAGS_NOINHERIT);
90
91         /* execute the command:  it will inherit our other file descriptors */
92         popen_pid[myside] = spawnlp(P_NOWAIT, shell, shell, "/C", cmd, NULL);
93
94         /* now restore our previous file descriptors */
95         if (dup2(save_stream, tst(0, 1)) < 0)   /* retrieve stdin/out */
96         {
97                 perror("dup2");
98                 return NULL;
99         }
100         close(save_stream);
101
102         return fdopen(myside, mode);            /* return a FILE pointer */
103 }
104
105 int mypclose(FILE *ptr)
106 {
107         register f;
108         int status;
109
110         if ( _osmode == DOS_MODE )
111           return dos_pclose(ptr);
112
113         f = fileno(ptr);
114         fclose(ptr);
115
116         /* wait for process to terminate */
117         cwait(&status, popen_pid[f], WAIT_GRANDCHILD);
118
119         return status;
120 }
121
122
123 int pipe(int *filedes)
124 {
125   int res;
126
127   if ( res = DosMakePipe((PHFILE) &filedes[0], (PHFILE) &filedes[1], 4096) )
128     return res;
129
130   DosSetFHandState(filedes[0], OPEN_FLAGS_NOINHERIT);
131   DosSetFHandState(filedes[1], OPEN_FLAGS_NOINHERIT);
132   return 0;
133 }
134
135
136 /* this is the MS-DOS version */
137
138 typedef enum { unopened = 0, reading, writing } pipemode;
139
140 static struct
141 {
142     char *name;
143     char *command;
144     pipemode pmode;
145 }
146 pipes[_NFILE];
147
148 static FILE *dos_popen(const char *command, const char *mode)
149 {
150     FILE *current;
151     char name[128];
152     int cur;
153     pipemode curmode;
154
155     /*
156     ** decide on mode.
157     */
158     if(strchr(mode, 'r') != NULL)
159         curmode = reading;
160     else if(strchr(mode, 'w') != NULL)
161         curmode = writing;
162     else
163         return NULL;
164
165     /*
166     ** get a name to use.
167     */
168     strcpy(name, "piXXXXXX");
169     Mktemp(name);
170
171     /*
172     ** If we're reading, just call system to get a file filled with
173     ** output.
174     */
175     if(curmode == reading)
176     {
177         char cmd[256];
178         sprintf(cmd,"%s > %s", command, name);
179         system(cmd);
180
181         if((current = fopen(name, mode)) == NULL)
182             return NULL;
183     }
184     else
185     {
186         if((current = fopen(name, mode)) == NULL)
187             return NULL;
188     }
189
190     cur = fileno(current);
191     pipes[cur].name = strdup(name);
192     pipes[cur].command = strdup(command);
193     pipes[cur].pmode = curmode;
194
195     return current;
196 }
197
198 static int dos_pclose(FILE * current)
199 {
200     int cur = fileno(current), rval;
201     char command[256];
202
203     /*
204     ** check for an open file.
205     */
206     if(pipes[cur].pmode == unopened)
207         return -1;
208
209     if(pipes[cur].pmode == reading)
210     {
211         /*
212         ** input pipes are just files we're done with.
213         */
214         rval = fclose(current);
215         unlink(pipes[cur].name);
216     }
217     else
218     {
219         /*
220         ** output pipes are temporary files we have
221         ** to cram down the throats of programs.
222         */
223         fclose(current);
224         sprintf(command,"%s < %s", pipes[cur].command, pipes[cur].name);
225         rval = system(command);
226         unlink(pipes[cur].name);
227     }
228
229     /*
230     ** clean up current pipe.
231     */
232     free(pipes[cur].name);
233     free(pipes[cur].command);
234     pipes[cur].pmode = unopened;
235
236     return rval;
237 }