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