Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
2 | /* |
||
3 | This is popen() and pclose() for MSDOS. They were developed using |
||
4 | Microsoft C, but should port easily to DOS C any compiler. |
||
5 | |||
6 | Original author: pacetti@fl-ngnet.army.mil |
||
7 | |||
8 | These routines are hacks, that is they SIMULATE thier UNIX |
||
9 | counterparts. Since MSDOS and won't allow concurrent process spawning, |
||
10 | you can't really pipe. I came up with this nearly stupid way around |
||
11 | piping because I wanted to have some portability between UNIX and MSDOS. |
||
12 | I'm probably not the first person to have this idea or implement it, but |
||
13 | I think I'm the first to give it away for free (no points?!). |
||
14 | |||
15 | The functions simulate popen() and pclose() by redirecting stdin or |
||
16 | stdout, then spawning a child processes via system(). |
||
17 | |||
18 | If you popen() for read, the stdout is redirected to a temporary |
||
19 | file, and the child is spawned. The stdout is reopened via dup2(), the |
||
20 | temporary file is opened for read and a file pointer to it is returned. |
||
21 | |||
22 | If you popen() for write, a temporary file is opened for write, and |
||
23 | a file pointer to it is returned. When you pclose(), the stdin is |
||
24 | redirected to the temporary file and the child is spawned. |
||
25 | |||
26 | In both cases, pclose() closes and unlinks the temporary file. |
||
27 | |||
28 | A static linked list of C structures is built to store necessary |
||
29 | info for all popen()ed files so you can popen() more than one file at |
||
30 | a time. |
||
31 | |||
32 | The popen() function will return NULL on an error, or a valid FILE |
||
33 | *pointer on a successful open. The pclose() function will return |
||
34 | negative one (-1) on an error or zero (0) on a successful close. |
||
35 | |||
36 | The function prototypes are: |
||
37 | |||
38 | FILE *popen(command, mode) |
||
39 | char *command, char *mode; |
||
40 | |||
41 | int pclose(pp) |
||
42 | FILE *pp; |
||
43 | |||
44 | Where command is a character string equivilant to a MSDOS command |
||
45 | line, mode is "r" for read or "w" for write, and pp is a pointer to a |
||
46 | file opened through popen(). |
||
47 | |||
48 | A main() function has been included for testing purposes, to compile |
||
49 | it define the preprocessor token TEST at compile time. |
||
50 | */ |
||
51 | |||
52 | #include |
||
53 | #include |
||
54 | #include |
||
55 | #include |
||
56 | #include |
||
57 | #include |
||
58 | #include |
||
59 | #include |
||
60 | |||
61 | /* hold file pointer, descriptor, command, mode, temporary file name */ |
||
62 | struct pipe_list { |
||
63 | FILE *fp; |
||
64 | int fd; |
||
65 | char *command, mode[10], temp_name[FILENAME_MAX]; |
||
66 | struct pipe_list *next; |
||
67 | }; |
||
68 | |||
69 | /* static, global list pointer */ |
||
70 | static struct pipe_list *pl = NULL; |
||
71 | |||
72 | FILE * |
||
73 | popen (const char *cm, const char *md) /* program name, pipe mode */ |
||
74 | { |
||
75 | struct pipe_list *l1, *l2; |
||
76 | static char *tn = NULL; /* temporary file basename */ |
||
77 | |||
78 | if (!tn) |
||
79 | if ((tn = tmpnam(0)) == NULL) |
||
80 | return NULL; |
||
81 | |||
82 | /* make new node */ |
||
83 | if ((l1 = (struct pipe_list *) malloc (sizeof (struct pipe_list))) == NULL) |
||
84 | return NULL; |
||
85 | |||
86 | /* zero out elements to we'll get here */ |
||
87 | l1->fd = 0; |
||
88 | l1->fp = NULL; |
||
89 | l1->next = NULL; |
||
90 | |||
91 | /* if empty list - just grab new node */ |
||
92 | if (!pl) |
||
93 | pl = l1; |
||
94 | else |
||
95 | { |
||
96 | /* otherwise, find last node in list */ |
||
97 | ++(l1->fd); |
||
98 | l2 = pl; |
||
99 | while (l2->next) |
||
100 | { |
||
101 | ++(l1->fd); |
||
102 | l2 = l2->next; |
||
103 | }; |
||
104 | /* add new node to list */ |
||
105 | l2->next = l1; |
||
106 | } |
||
107 | |||
108 | /* stick in elements we know already */ |
||
109 | strcpy (l1->mode, md); |
||
110 | sprintf (l1->temp_name, "%s.%d", tn, l1->fd); |
||
111 | |||
112 | /* if can save the program name, build temp file */ |
||
113 | if ((l1->command = malloc(strlen(cm)+1))) |
||
114 | { |
||
115 | strcpy(l1->command, cm); |
||
116 | /* if caller wants to read */ |
||
117 | if (l1->mode[0] == 'r') |
||
118 | { |
||
119 | /* dup stdout */ |
||
120 | if ((l1->fd = dup (fileno (stdout))) == EOF) |
||
121 | l1->fp = NULL; |
||
122 | else if (!(l1->fp = freopen (l1->temp_name, "wb", stdout))) |
||
123 | l1->fp = NULL; |
||
124 | else |
||
125 | /* exec cmd */ |
||
126 | if (system (cm) == EOF) |
||
127 | l1->fp = NULL; |
||
128 | /* reopen real stdout */ |
||
129 | if (dup2 (l1->fd, fileno (stdout)) == EOF) |
||
130 | { |
||
131 | l1->fp = NULL; |
||
132 | close(l1->fd); |
||
133 | } |
||
134 | else |
||
135 | /* open file for reader */ |
||
136 | l1->fp = fopen (l1->temp_name, l1->mode); |
||
137 | } |
||
138 | else |
||
139 | /* if caller wants to write */ |
||
140 | if (l1->mode[0] == 'w') |
||
141 | /* open temp file */ |
||
142 | l1->fp = fopen (l1->temp_name, l1->mode); |
||
143 | else |
||
144 | /* unknown mode */ |
||
145 | l1->fp = NULL; |
||
146 | } |
||
147 | return l1->fp; /* return == NULL ? ERROR : OK */ |
||
148 | } |
||
149 | |||
150 | int |
||
151 | pclose (FILE *pp) |
||
152 | { |
||
153 | struct pipe_list *l1, *l2; /* list pointers */ |
||
154 | int retval=0; /* function return value */ |
||
155 | |||
156 | /* if pointer is first node */ |
||
157 | if (pl->fp == pp) |
||
158 | { |
||
159 | /* save node and take it out the list */ |
||
160 | l1 = pl; |
||
161 | pl = l1->next; |
||
162 | } |
||
163 | else |
||
164 | /* if more than one node in list */ |
||
165 | if (pl->next) |
||
166 | { |
||
167 | /* find right node */ |
||
168 | for (l2 = pl, l1 = pl->next; l1; l2 = l1, l1 = l2->next) |
||
169 | if (l1->fp == pp) |
||
170 | break; |
||
171 | |||
172 | /* take node out of list */ |
||
173 | l2->next = l1->next; |
||
174 | } |
||
175 | else |
||
176 | return -1; |
||
177 | |||
178 | /* if FILE not in list - return error */ |
||
179 | if (l1->fp == pp) |
||
180 | { |
||
181 | /* close the (hopefully) popen()ed file */ |
||
182 | fclose (l1->fp); |
||
183 | |||
184 | /* if pipe was opened to write */ |
||
185 | if (l1->mode[0] == 'w') |
||
186 | { |
||
187 | /* dup stdin */ |
||
188 | if ((l1->fd = dup (fileno (stdin))) == EOF) |
||
189 | retval = -1; |
||
190 | else |
||
191 | /* open temp stdin */ |
||
192 | if (!(l1->fp = freopen (l1->temp_name, "rb", stdin))) |
||
193 | retval = -1; |
||
194 | else |
||
195 | /* exec cmd */ |
||
196 | if (system (l1->command) == EOF) |
||
197 | retval = -1; |
||
198 | else |
||
199 | { |
||
200 | /* reopen stdin */ |
||
201 | if (dup2 (l1->fd, fileno (stdin)) == EOF) |
||
202 | retval = -1; |
||
203 | close(l1->fd); |
||
204 | } |
||
205 | } |
||
206 | else |
||
207 | /* if pipe was opened to read */ |
||
208 | if (l1->mode[0] == 'r') |
||
209 | retval = 0; |
||
210 | else |
||
211 | /* invalid mode */ |
||
212 | retval = -1; |
||
213 | } |
||
214 | remove (l1->temp_name); /* remove temporary file */ |
||
215 | free (l1->command); /* dealloc memory */ |
||
216 | free (l1); /* dealloc memory */ |
||
217 | l1 = NULL; /* make pointer bogus */ |
||
218 | |||
219 | return retval; /* retval==0 ? OK : ERROR */ |
||
220 | } |