339b3ba9dfaa2833256b6fe9b9dd4f8a2e923a96
[perl.git] / do / open
1 bool
2 do_open(stab,name,len)
3 STAB *stab;
4 register char *name;
5 int len;
6 {
7     FILE *fp;
8     register STIO *stio = stab_io(stab);
9     char *myname = savestr(name);
10     int result;
11     int fd;
12     int writing = 0;
13     char mode[3];               /* stdio file mode ("r\0" or "r+\0") */
14     FILE *saveifp = Nullfp;
15     FILE *saveofp = Nullfp;
16     char savetype = ' ';
17
18     mode[0] = mode[1] = mode[2] = '\0';
19     name = myname;
20     forkprocess = 1;            /* assume true if no fork */
21     while (len && isSPACE(name[len-1]))
22         name[--len] = '\0';
23     if (!stio)
24         stio = stab_io(stab) = stio_new();
25     else if (stio->ifp) {
26         fd = fileno(stio->ifp);
27         if (stio->type == '-')
28             result = 0;
29         else if (fd <= maxsysfd) {
30             saveifp = stio->ifp;
31             saveofp = stio->ofp;
32             savetype = stio->type;
33             result = 0;
34         }
35         else if (stio->type == '|')
36             result = mypclose(stio->ifp);
37         else if (stio->ifp != stio->ofp) {
38             if (stio->ofp) {
39                 result = fclose(stio->ofp);
40                 fclose(stio->ifp);      /* clear stdio, fd already closed */
41             }
42             else
43                 result = fclose(stio->ifp);
44         }
45         else
46             result = fclose(stio->ifp);
47         if (result == EOF && fd > maxsysfd)
48             fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
49               stab_ename(stab));
50         stio->ofp = stio->ifp = Nullfp;
51     }
52     if (*name == '+' && len > 1 && name[len-1] != '|') {        /* scary */
53         mode[1] = *name++;
54         mode[2] = '\0';
55         --len;
56         writing = 1;
57     }
58     else  {
59         mode[1] = '\0';
60     }
61     stio->type = *name;
62     if (*name == '|') {
63         /*SUPPRESS 530*/
64         for (name++; isSPACE(*name); name++) ;
65         TAINT_ENV();
66         TAINT_PROPER("piped open");
67         fp = mypopen(name,"w");
68         writing = 1;
69     }
70     else if (*name == '>') {
71         TAINT_PROPER("open");
72         name++;
73         if (*name == '>') {
74             mode[0] = stio->type = 'a';
75             name++;
76         }
77         else
78             mode[0] = 'w';
79         writing = 1;
80         if (*name == '&') {
81           duplicity:
82             name++;
83             while (isSPACE(*name))
84                 name++;
85             if (isDIGIT(*name))
86                 fd = atoi(name);
87             else {
88                 stab = stabent(name,FALSE);
89                 if (!stab || !stab_io(stab)) {
90 #ifdef EINVAL
91                     errno = EINVAL;
92 #endif
93                     goto say_false;
94                 }
95                 if (stab_io(stab) && stab_io(stab)->ifp) {
96                     fd = fileno(stab_io(stab)->ifp);
97                     if (stab_io(stab)->type == 's')
98                         stio->type = 's';
99                 }
100                 else
101                     fd = -1;
102             }
103             if (!(fp = fdopen(fd = dup(fd),mode))) {
104                 close(fd);
105             }
106         }
107         else {
108             while (isSPACE(*name))
109                 name++;
110             if (strEQ(name,"-")) {
111                 fp = stdout;
112                 stio->type = '-';
113             }
114             else  {
115                 fp = fopen(name,mode);
116             }
117         }
118     }
119     else {
120         if (*name == '<') {
121             mode[0] = 'r';
122             name++;
123             while (isSPACE(*name))
124                 name++;
125             if (*name == '&')
126                 goto duplicity;
127             if (strEQ(name,"-")) {
128                 fp = stdin;
129                 stio->type = '-';
130             }
131             else
132                 fp = fopen(name,mode);
133         }
134         else if (name[len-1] == '|') {
135             TAINT_ENV();
136             TAINT_PROPER("piped open");
137             name[--len] = '\0';
138             while (len && isSPACE(name[len-1]))
139                 name[--len] = '\0';
140             /*SUPPRESS 530*/
141             for (; isSPACE(*name); name++) ;
142             fp = mypopen(name,"r");
143             stio->type = '|';
144         }
145         else {
146             stio->type = '<';
147             /*SUPPRESS 530*/
148             for (; isSPACE(*name); name++) ;
149             if (strEQ(name,"-")) {
150                 fp = stdin;
151                 stio->type = '-';
152             }
153             else
154                 fp = fopen(name,"r");
155         }
156     }
157     if (!fp) {
158         if (dowarn && stio->type == '<' && index(name, '\n'))
159             warn(warn_nl, "open");
160         Safefree(myname);
161         goto say_false;
162     }
163     Safefree(myname);
164     if (stio->type &&
165       stio->type != '|' && stio->type != '-') {
166         if (fstat(fileno(fp),&statbuf) < 0) {
167             (void)fclose(fp);
168             goto say_false;
169         }
170         if (S_ISSOCK(statbuf.st_mode))
171             stio->type = 's';   /* in case a socket was passed in to us */
172 #ifdef HAS_SOCKET
173         else if (
174 #ifdef S_IFMT
175             !(statbuf.st_mode & S_IFMT)
176 #else
177             !statbuf.st_mode
178 #endif
179         ) {
180             int buflen = sizeof tokenbuf;
181             if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
182                 || errno != ENOTSOCK)
183                 stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
184                                 /* but some return 0 for streams too, sigh */
185         }
186 #endif
187     }
188     if (saveifp) {              /* must use old fp? */
189         fd = fileno(saveifp);
190         if (saveofp) {
191             fflush(saveofp);            /* emulate fclose() */
192             if (saveofp != saveifp) {   /* was a socket? */
193                 fclose(saveofp);
194                 if (fd > 2)
195                     Safefree(saveofp);
196             }
197         }
198         if (fd != fileno(fp)) {
199             int pid;
200             STR *TARG;
201
202             dup2(fileno(fp), fd);
203             TARG = afetch(fdpid,fileno(fp),TRUE);
204             pid = TARG->str_u.str_useful;
205             TARG->str_u.str_useful = 0;
206             TARG = afetch(fdpid,fd,TRUE);
207             TARG->str_u.str_useful = pid;
208             fclose(fp);
209
210         }
211         fp = saveifp;
212         clearerr(fp);
213     }
214 #if defined(HAS_FCNTL) && defined(F_SETFD)
215     fd = fileno(fp);
216     fcntl(fd,F_SETFD,fd > maxsysfd);
217 #endif
218     stio->ifp = fp;
219     if (writing) {
220         if (stio->type == 's'
221           || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
222             if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
223                 fclose(fp);
224                 stio->ifp = Nullfp;
225                 goto say_false;
226             }
227         }
228         else
229             stio->ofp = fp;
230     }
231     return TRUE;
232
233 say_false:
234     stio->ifp = saveifp;
235     stio->ofp = saveofp;
236     stio->type = savetype;
237     return FALSE;
238 }
239