This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
b9522b5671b252002e0bc5c6290661acb8743648
[perl5.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 ( _pipe(p, 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 = _pipe(filedes, 4096, 0) )
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     char *tmp = getenv("TMP");
153     int cur;
154     pipemode curmode;
155
156     /*
157     ** decide on mode.
158     */
159     if(strchr(mode, 'r') != NULL)
160         curmode = reading;
161     else if(strchr(mode, 'w') != NULL)
162         curmode = writing;
163     else
164         return NULL;
165
166     /*
167     ** get a name to use.
168     */
169     strcpy(name, tmp ? tmp : "\\");
170     if ( name[strlen(name) - 1] != '\\' )
171       strcat(name, "\\");
172     strcat(name, "piXXXXXX");
173     mktemp(name);
174
175     /*
176     ** If we're reading, just call system to get a file filled with
177     ** output.
178     */
179     if(curmode == reading)
180     {
181         char cmd[256];
182         sprintf(cmd,"%s > %s", command, name);
183         system(cmd);
184
185         if((current = fopen(name, mode)) == NULL)
186             return NULL;
187     }
188     else
189     {
190         if((current = fopen(name, mode)) == NULL)
191             return NULL;
192     }
193
194     cur = fileno(current);
195     pipes[cur].name = strdup(name);
196     pipes[cur].command = strdup(command);
197     pipes[cur].pmode = curmode;
198
199     return current;
200 }
201
202 static int dos_pclose(FILE * current)
203 {
204     int cur = fileno(current), rval;
205     char command[256];
206
207     /*
208     ** check for an open file.
209     */
210     if(pipes[cur].pmode == unopened)
211         return -1;
212
213     if(pipes[cur].pmode == reading)
214     {
215         /*
216         ** input pipes are just files we're done with.
217         */
218         rval = fclose(current);
219         unlink(pipes[cur].name);
220     }
221     else
222     {
223         /*
224         ** output pipes are temporary files we have
225         ** to cram down the throats of programs.
226         */
227         fclose(current);
228         sprintf(command,"%s < %s", pipes[cur].command, pipes[cur].name);
229         rval = system(command);
230         unlink(pipes[cur].name);
231     }
232
233     /*
234     ** clean up current pipe.
235     */
236     free(pipes[cur].name);
237     free(pipes[cur].command);
238     pipes[cur].pmode = unopened;
239
240     return rval;
241 }