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