input.c revision 1.38 1 /* $NetBSD: input.c,v 1.38 2003/05/15 13:26:45 dsl Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
43 #else
44 __RCSID("$NetBSD: input.c,v 1.38 2003/05/15 13:26:45 dsl Exp $");
45 #endif
46 #endif /* not lint */
47
48 #include <stdio.h> /* defines BUFSIZ */
49 #include <fcntl.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 /*
56 * This file implements the input routines used by the parser.
57 */
58
59 #include "shell.h"
60 #include "redir.h"
61 #include "syntax.h"
62 #include "input.h"
63 #include "output.h"
64 #include "options.h"
65 #include "memalloc.h"
66 #include "error.h"
67 #include "alias.h"
68 #include "parser.h"
69 #include "myhistedit.h"
70
71 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
72
73 MKINIT
74 struct strpush {
75 struct strpush *prev; /* preceding string on stack */
76 char *prevstring;
77 int prevnleft;
78 int prevlleft;
79 struct alias *ap; /* if push was associated with an alias */
80 };
81
82 /*
83 * The parsefile structure pointed to by the global variable parsefile
84 * contains information about the current file being read.
85 */
86
87 MKINIT
88 struct parsefile {
89 struct parsefile *prev; /* preceding file on stack */
90 int linno; /* current line */
91 int fd; /* file descriptor (or -1 if string) */
92 int nleft; /* number of chars left in this line */
93 int lleft; /* number of chars left in this buffer */
94 char *nextc; /* next char in buffer */
95 char *buf; /* input buffer */
96 struct strpush *strpush; /* for pushing strings at this level */
97 struct strpush basestrpush; /* so pushing one is fast */
98 };
99
100
101 int plinno = 1; /* input line number */
102 int parsenleft; /* copy of parsefile->nleft */
103 MKINIT int parselleft; /* copy of parsefile->lleft */
104 char *parsenextc; /* copy of parsefile->nextc */
105 MKINIT struct parsefile basepf; /* top level input file */
106 MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */
107 struct parsefile *parsefile = &basepf; /* current input file */
108 int init_editline = 0; /* editline library initialized? */
109 int whichprompt; /* 1 == PS1, 2 == PS2 */
110
111 EditLine *el; /* cookie for editline package */
112
113 STATIC void pushfile(void);
114 static int preadfd(void);
115
116 #ifdef mkinit
117 INCLUDE <stdio.h>
118 INCLUDE "input.h"
119 INCLUDE "error.h"
120
121 INIT {
122 basepf.nextc = basepf.buf = basebuf;
123 }
124
125 RESET {
126 if (exception != EXSHELLPROC)
127 parselleft = parsenleft = 0; /* clear input buffer */
128 popallfiles();
129 }
130
131 SHELLPROC {
132 popallfiles();
133 }
134 #endif
135
136
137 /*
138 * Read a line from the script.
139 */
140
141 char *
142 pfgets(char *line, int len)
143 {
144 char *p = line;
145 int nleft = len;
146 int c;
147
148 while (--nleft > 0) {
149 c = pgetc_macro();
150 if (c == PEOF) {
151 if (p == line)
152 return NULL;
153 break;
154 }
155 *p++ = c;
156 if (c == '\n')
157 break;
158 }
159 *p = '\0';
160 return line;
161 }
162
163
164
165 /*
166 * Read a character from the script, returning PEOF on end of file.
167 * Nul characters in the input are silently discarded.
168 */
169
170 int
171 pgetc(void)
172 {
173 return pgetc_macro();
174 }
175
176
177 static int
178 preadfd(void)
179 {
180 int nr;
181 char *buf = parsefile->buf;
182 parsenextc = buf;
183
184 retry:
185 #ifndef SMALL
186 if (parsefile->fd == 0 && el) {
187 static const char *rl_cp;
188 static int el_len;
189
190 if (rl_cp == NULL)
191 rl_cp = el_gets(el, &el_len);
192 if (rl_cp == NULL)
193 nr = 0;
194 else {
195 nr = el_len;
196 if (nr > BUFSIZ - 8)
197 nr = BUFSIZ - 8;
198 memcpy(buf, rl_cp, nr);
199 if (nr != el_len) {
200 el_len -= nr;
201 rl_cp += nr;
202 } else
203 rl_cp = 0;
204 }
205
206 } else
207 #endif
208 nr = read(parsefile->fd, buf, BUFSIZ - 8);
209
210
211 if (nr <= 0) {
212 if (nr < 0) {
213 if (errno == EINTR)
214 goto retry;
215 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
216 int flags = fcntl(0, F_GETFL, 0);
217 if (flags >= 0 && flags & O_NONBLOCK) {
218 flags &=~ O_NONBLOCK;
219 if (fcntl(0, F_SETFL, flags) >= 0) {
220 out2str("sh: turning off NDELAY mode\n");
221 goto retry;
222 }
223 }
224 }
225 }
226 nr = -1;
227 }
228 return nr;
229 }
230
231 /*
232 * Refill the input buffer and return the next input character:
233 *
234 * 1) If a string was pushed back on the input, pop it;
235 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
236 * from a string so we can't refill the buffer, return EOF.
237 * 3) If the is more stuff in this buffer, use it else call read to fill it.
238 * 4) Process input up to the next newline, deleting nul characters.
239 */
240
241 int
242 preadbuffer(void)
243 {
244 char *p, *q;
245 int more;
246 int something;
247 char savec;
248
249 if (parsefile->strpush) {
250 popstring();
251 if (--parsenleft >= 0)
252 return (*parsenextc++);
253 }
254 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
255 return PEOF;
256 flushout(&output);
257 flushout(&errout);
258
259 again:
260 if (parselleft <= 0) {
261 if ((parselleft = preadfd()) == -1) {
262 parselleft = parsenleft = EOF_NLEFT;
263 return PEOF;
264 }
265 }
266
267 q = p = parsenextc;
268
269 /* delete nul characters */
270 something = 0;
271 for (more = 1; more;) {
272 switch (*p) {
273 case '\0':
274 p++; /* Skip nul */
275 goto check;
276
277 case '\t':
278 case ' ':
279 break;
280
281 case '\n':
282 parsenleft = q - parsenextc;
283 more = 0; /* Stop processing here */
284 break;
285
286 default:
287 something = 1;
288 break;
289 }
290
291 *q++ = *p++;
292 check:
293 if (--parselleft <= 0) {
294 parsenleft = q - parsenextc - 1;
295 if (parsenleft < 0)
296 goto again;
297 *q = '\0';
298 more = 0;
299 }
300 }
301
302 savec = *q;
303 *q = '\0';
304
305 #ifndef SMALL
306 if (parsefile->fd == 0 && hist && something) {
307 HistEvent he;
308 INTOFF;
309 history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
310 parsenextc);
311 INTON;
312 }
313 #endif
314
315 if (vflag) {
316 out2str(parsenextc);
317 flushout(out2);
318 }
319
320 *q = savec;
321
322 return *parsenextc++;
323 }
324
325 /*
326 * Undo the last call to pgetc. Only one character may be pushed back.
327 * PEOF may be pushed back.
328 */
329
330 void
331 pungetc(void)
332 {
333 parsenleft++;
334 parsenextc--;
335 }
336
337 /*
338 * Push a string back onto the input at this current parsefile level.
339 * We handle aliases this way.
340 */
341 void
342 pushstring(char *s, int len, void *ap)
343 {
344 struct strpush *sp;
345
346 INTOFF;
347 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
348 if (parsefile->strpush) {
349 sp = ckmalloc(sizeof (struct strpush));
350 sp->prev = parsefile->strpush;
351 parsefile->strpush = sp;
352 } else
353 sp = parsefile->strpush = &(parsefile->basestrpush);
354 sp->prevstring = parsenextc;
355 sp->prevnleft = parsenleft;
356 sp->prevlleft = parselleft;
357 sp->ap = (struct alias *)ap;
358 if (ap)
359 ((struct alias *)ap)->flag |= ALIASINUSE;
360 parsenextc = s;
361 parsenleft = len;
362 INTON;
363 }
364
365 void
366 popstring(void)
367 {
368 struct strpush *sp = parsefile->strpush;
369
370 INTOFF;
371 parsenextc = sp->prevstring;
372 parsenleft = sp->prevnleft;
373 parselleft = sp->prevlleft;
374 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
375 if (sp->ap)
376 sp->ap->flag &= ~ALIASINUSE;
377 parsefile->strpush = sp->prev;
378 if (sp != &(parsefile->basestrpush))
379 ckfree(sp);
380 INTON;
381 }
382
383 /*
384 * Set the input to take input from a file. If push is set, push the
385 * old input onto the stack first.
386 */
387
388 void
389 setinputfile(const char *fname, int push)
390 {
391 int fd;
392 int fd2;
393
394 INTOFF;
395 if ((fd = open(fname, O_RDONLY)) < 0)
396 error("Can't open %s", fname);
397 if (fd < 10) {
398 fd2 = copyfd(fd, 10);
399 close(fd);
400 if (fd2 < 0)
401 error("Out of file descriptors");
402 fd = fd2;
403 }
404 setinputfd(fd, push);
405 INTON;
406 }
407
408
409 /*
410 * Like setinputfile, but takes an open file descriptor. Call this with
411 * interrupts off.
412 */
413
414 void
415 setinputfd(int fd, int push)
416 {
417 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
418 if (push) {
419 pushfile();
420 parsefile->buf = ckmalloc(BUFSIZ);
421 }
422 if (parsefile->fd > 0)
423 close(parsefile->fd);
424 parsefile->fd = fd;
425 if (parsefile->buf == NULL)
426 parsefile->buf = ckmalloc(BUFSIZ);
427 parselleft = parsenleft = 0;
428 plinno = 1;
429 }
430
431
432 /*
433 * Like setinputfile, but takes input from a string.
434 */
435
436 void
437 setinputstring(char *string, int push)
438 {
439 INTOFF;
440 if (push)
441 pushfile();
442 parsenextc = string;
443 parselleft = parsenleft = strlen(string);
444 parsefile->buf = NULL;
445 plinno = 1;
446 INTON;
447 }
448
449
450
451 /*
452 * To handle the "." command, a stack of input files is used. Pushfile
453 * adds a new entry to the stack and popfile restores the previous level.
454 */
455
456 STATIC void
457 pushfile(void)
458 {
459 struct parsefile *pf;
460
461 parsefile->nleft = parsenleft;
462 parsefile->lleft = parselleft;
463 parsefile->nextc = parsenextc;
464 parsefile->linno = plinno;
465 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
466 pf->prev = parsefile;
467 pf->fd = -1;
468 pf->strpush = NULL;
469 pf->basestrpush.prev = NULL;
470 parsefile = pf;
471 }
472
473
474 void
475 popfile(void)
476 {
477 struct parsefile *pf = parsefile;
478
479 INTOFF;
480 if (pf->fd >= 0)
481 close(pf->fd);
482 if (pf->buf)
483 ckfree(pf->buf);
484 while (pf->strpush)
485 popstring();
486 parsefile = pf->prev;
487 ckfree(pf);
488 parsenleft = parsefile->nleft;
489 parselleft = parsefile->lleft;
490 parsenextc = parsefile->nextc;
491 plinno = parsefile->linno;
492 INTON;
493 }
494
495
496 /*
497 * Return to top level.
498 */
499
500 void
501 popallfiles(void)
502 {
503 while (parsefile != &basepf)
504 popfile();
505 }
506
507
508
509 /*
510 * Close the file(s) that the shell is reading commands from. Called
511 * after a fork is done.
512 *
513 * Takes one arg, vfork, which tells it to not modify its global vars
514 * as it is still running in the parent.
515 *
516 * This code is (probably) unnecessary as the 'close on exec' flag is
517 * set and should be enough. In the vfork case it is definitely wrong
518 * to close the fds as another fork() may be done later to feed data
519 * from a 'here' document into a pipe and we don't want to close the
520 * pipe!
521 */
522
523 void
524 closescript(int vforked)
525 {
526 if (vforked)
527 return;
528 popallfiles();
529 if (parsefile->fd > 0) {
530 close(parsefile->fd);
531 parsefile->fd = 0;
532 }
533 }
534