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