96e68558ccbf5ce6bf0da68eb21ce47d8f87e0e9
[p5sagit/p5-mst-13.2.git] / msdos / popen.c
1 /* $Header: popen.c,v 4.0 91/03/20 01:34:50 lwall Locked $
2  *
3  *    (C) Copyright 1988, 1990 Diomidis Spinellis.
4  *
5  *    You may distribute under the terms of the GNU General Public License
6  *    as specified in the README file that comes with the perl 3.0 kit.
7  *
8  * $Log:        popen.c,v $
9  * Revision 4.0  91/03/20  01:34:50  lwall
10  * 4.0 baseline.
11  * 
12  * Revision 3.0.1.2  90/08/09  04:04:42  lwall
13  * patch19: various MSDOS and OS/2 patches folded in
14  * 
15  * Revision 3.0.1.1  90/03/27  16:11:57  lwall
16  * patch16: MSDOS support
17  * 
18  * Revision 1.1  90/03/18  20:32:20  dds
19  * Initial revision
20  *
21  */
22
23 /*
24  * Popen and pclose for MS-DOS
25  */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <process.h>
30
31 /*
32  * Possible actions on an popened file
33  */
34 enum action {
35         delete,                         /* Used for "r". Delete the tmp file */
36         execute                         /* Used for "w". Execute the command. */
37 };
38
39 /*
40  * Linked list of things to do at the end of the program execution.
41  */
42 static struct todo {
43         FILE *f;                        /* File we are working on (to fclose) */
44         const char *name;               /* Name of the file (to unlink) */
45         const char *command;            /* Command to execute */
46         enum action what;               /* What to do (execute or delete) */
47         struct todo *next;              /* Next structure */
48 } *todolist;
49
50
51 /* Clean up function */
52 static int close_pipes(void);
53
54 /*
55  * Add a file f running the command command on file name to the list
56  * of actions to be done at the end.  The action is specified in what.
57  * Return -1 on failure, 0 if ok.
58  */
59 static int
60 add(FILE *f, const char *command, const char *name, enum action what)
61 {
62         struct todo    *p;
63
64         if ((p = (struct todo *) malloc(sizeof(struct todo))) == NULL)
65                 return -1;
66         p->f = f;
67         p->command = command;
68         p->name = name;
69         p->what = what;
70         p->next = todolist;
71         todolist = p;
72         return 0;
73 }
74
75 FILE *
76 mypopen(const char *command, const char *t)
77 {
78         char buff[256];
79         char *name;
80         FILE *f;
81         static init = 0;
82
83         if (!init)
84                 if (onexit(close_pipes) == NULL)
85                         return NULL;
86                 else
87                         init++;
88
89         if ((name = tempnam((char*)NULL, "pp")) == NULL)
90                 return NULL;
91
92         switch (*t) {
93         case 'r':
94                 sprintf(buff, "%s >%s", command, name);
95                 if (system(buff) || (f = fopen(name, "r")) == NULL) {
96                         free(name);
97                         return NULL;
98                 }
99                 if (add(f, command, name, delete)) {
100                         (void)fclose(f);
101                         (void)unlink(name);
102                         free(name);
103                         return NULL;
104                 }
105                 return f;
106         case 'w':
107                 if ((f = fopen(name, "w")) == NULL) {
108                         free(name);
109                         return NULL;
110                 }
111                 if (add(f, command, name, execute)) {
112                         (void)fclose(f);
113                         (void)unlink(name);
114                         free(name);
115                         return NULL;
116                 }
117                 return f;
118         default:
119                 free(name);
120                 return NULL;
121         }
122 }
123
124 int
125 mypclose(FILE *f)
126 {
127         struct todo *p, **prev;
128         char buff[256];
129         const char *name;
130         int status;
131
132         for (p = todolist, prev = &todolist; p; prev = &(p->next), p = p->next)
133                 if (p->f == f) {
134                         *prev = p->next;
135                         name = p->name;
136                         switch (p->what) {
137                         case delete:
138                                 free(p);
139                                 if (fclose(f) == EOF) {
140                                         (void)unlink(name);
141                                         status = EOF;
142                                 } else if (unlink(name) < 0)
143                                         status = EOF;
144                                 else
145                                         status = 0;
146                                 free((void*)name);
147                                 return status;
148                         case execute:
149                                 (void)sprintf(buff, "%s <%s", p->command, p->name);
150                                 free(p);
151                                 if (fclose(f) == EOF) {
152                                         (void)unlink(name);
153                                         status = EOF;
154                                 } else if (system(buff)) {
155                                         (void)unlink(name);
156                                         status = EOF;
157                                 } else if (unlink(name) < 0)
158                                         status = EOF;
159                                 else
160                                         status = 0;
161                                 free((void*)name);
162                                 return status;
163                         default:
164                                 return EOF;
165                         }
166                 }
167         return EOF;
168 }
169
170 /*
171  * Clean up at the end.  Called by the onexit handler.
172  */
173 static int
174 close_pipes(void)
175 {
176         struct todo    *p;
177
178         for (p = todolist; p; p = p->next)
179                 (void)mypclose(p->f);
180         return 0;
181 }