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