1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1997-2005
5 *	Herbert Xu <herbert@gondor.apana.org.au>.  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 <unistd.h>
38#include <stdlib.h>
39#include <string.h>
40
41#ifdef USE_LINENOISE
42#include <linenoise/linenoise.h>
43#endif
44
45/*
46 * This file implements the input routines used by the parser.
47 */
48
49#include "eval.h"
50#include "shell.h"
51#include "redir.h"
52#include "syntax.h"
53#include "input.h"
54#include "output.h"
55#include "options.h"
56#include "memalloc.h"
57#include "error.h"
58#include "alias.h"
59#include "parser.h"
60#include "main.h"
61
62#define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
63#define IBUFSIZ (BUFSIZ + 1)
64
65
66MKINIT struct parsefile basepf;	/* top level input file */
67MKINIT char basebuf[IBUFSIZ];	/* buffer for top level input file */
68struct parsefile *parsefile = &basepf;	/* current input file */
69int whichprompt;		/* 1 == PS1, 2 == PS2 */
70
71#ifdef USE_LINENOISE
72static char *pending_line;
73static size_t pending_line_index;
74static size_t pending_line_length;
75#endif
76
77STATIC void pushfile(void);
78static int preadfd(void);
79static void setinputfd(int fd, int push);
80static int preadbuffer(void);
81
82#ifdef mkinit
83INCLUDE <stdio.h>
84INCLUDE "input.h"
85INCLUDE "error.h"
86
87INIT {
88	basepf.nextc = basepf.buf = basebuf;
89	basepf.linno = 1;
90}
91
92RESET {
93	/* clear input buffer */
94	basepf.lleft = basepf.nleft = 0;
95	popallfiles();
96}
97#endif
98
99
100/*
101 * Read a character from the script, returning PEOF on end of file.
102 * Nul characters in the input are silently discarded.
103 */
104
105int
106pgetc(void)
107{
108	int c;
109
110	if (parsefile->unget)
111		return parsefile->lastc[--parsefile->unget];
112
113	if (--parsefile->nleft >= 0)
114		c = (signed char)*parsefile->nextc++;
115	else
116		c = preadbuffer();
117
118	parsefile->lastc[1] = parsefile->lastc[0];
119	parsefile->lastc[0] = c;
120
121	return c;
122}
123
124
125/*
126 * Same as pgetc(), but ignores PEOA.
127 */
128
129int
130pgetc2()
131{
132	int c;
133	do {
134		c = pgetc();
135	} while (c == PEOA);
136	return c;
137}
138
139
140static int
141preadfd(void)
142{
143	int nr;
144	char *buf =  parsefile->buf;
145	parsefile->nextc = buf;
146	const char* prompt = NULL;
147
148retry:
149#ifdef USE_LINENOISE
150	if (parsefile->fd == 0 && iflag) {
151		if (pending_line == NULL) {
152			// linenoise stashs the prompt buffer away for
153			// the duration of its edit cycle. Because
154			// some edit functionality (in particular, tab
155			// completion allocates the parts of PATH from
156			// dash's stack-based allocator), we need to
157			// properly save the string and then free it,
158			// or it will be clobbered.
159			prompt = savestr(getprompt(NULL));
160			pending_line = linenoise(prompt);
161			if (pending_line) {
162				pending_line_index = 0u;
163				pending_line_length = strlen(pending_line);
164				pending_line[pending_line_length] = '\n';
165				pending_line_length += 1;
166			}
167		}
168		if (pending_line == NULL)
169			nr = 0;
170		else {
171			nr = pending_line_length - pending_line_index;
172			if (nr > IBUFSIZ - 1)
173				nr = IBUFSIZ - 1;
174			memcpy(buf, pending_line + pending_line_index, nr);
175			pending_line_index += nr;
176			if (pending_line_index == pending_line_length) {
177				linenoiseFree(pending_line);
178				free(prompt);
179				pending_line = NULL;
180				pending_line_index = 0u;
181				pending_line_length = 0u;
182			}
183		}
184	} else
185#endif
186		nr = read(parsefile->fd, buf, IBUFSIZ - 1);
187
188
189	if (nr < 0) {
190		if (errno == EINTR)
191			goto retry;
192		if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
193			int flags = fcntl(0, F_GETFL, 0);
194			if (flags >= 0 && flags & O_NONBLOCK) {
195				flags &=~ O_NONBLOCK;
196				if (fcntl(0, F_SETFL, flags) >= 0) {
197					out2str("sh: turning off NDELAY mode\n");
198					goto retry;
199				}
200			}
201		}
202	}
203	return nr;
204}
205
206static void addtohistory(const char* entry, size_t length) {
207	// TODO(abarth): If whichprompt != 1, we should append this value to an
208	// existing history entry. However, linenoise doesn't support editing the
209	// history entries, so we'll probably need to refactor the input system to
210	// get this behavior right.
211#ifdef USE_LINENOISE
212	linenoiseHistoryAdd(entry);
213#endif
214}
215
216/*
217 * Refill the input buffer and return the next input character:
218 *
219 * 1) If a string was pushed back on the input, pop it;
220 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
221 *    from a string so we can't refill the buffer, return EOF.
222 * 3) If the is more stuff in this buffer, use it else call read to fill it.
223 * 4) Process input up to the next newline, deleting nul characters.
224 */
225
226static int preadbuffer(void)
227{
228	char *q;
229	int more;
230#ifdef USE_LINENOISE
231	int something;
232#endif
233	char savec;
234
235	if (unlikely(parsefile->strpush)) {
236		if (
237			parsefile->nleft == -1 &&
238			parsefile->strpush->ap &&
239			parsefile->nextc[-1] != ' ' &&
240			parsefile->nextc[-1] != '\t'
241		) {
242			return PEOA;
243		}
244		popstring();
245		return pgetc();
246	}
247	if (unlikely(parsefile->nleft == EOF_NLEFT ||
248		     parsefile->buf == NULL))
249		return PEOF;
250	flushall();
251
252	more = parsefile->lleft;
253	if (more <= 0) {
254again:
255		if ((more = preadfd()) <= 0) {
256			parsefile->lleft = parsefile->nleft = EOF_NLEFT;
257			return PEOF;
258		}
259	}
260
261	q = parsefile->nextc;
262
263	/* delete nul characters */
264#ifdef USE_LINENOISE
265	something = 0;
266#endif
267	for (;;) {
268		int c;
269
270		more--;
271		c = *q;
272
273		if (!c)
274			memmove(q, q + 1, more);
275		else {
276			q++;
277
278			if (c == '\n') {
279				parsefile->nleft = q - parsefile->nextc - 1;
280				break;
281			}
282
283#ifdef USE_LINENOISE
284			switch (c) {
285			default:
286				something = 1;
287				/* fall through */
288			case '\t':
289			case ' ':
290				break;
291			}
292#endif
293		}
294
295		if (more <= 0) {
296			parsefile->nleft = q - parsefile->nextc - 1;
297			if (parsefile->nleft < 0)
298				goto again;
299			break;
300		}
301	}
302	parsefile->lleft = more;
303
304	savec = *q;
305	*q = '\0';
306
307#ifdef USE_LINENOISE
308	if (parsefile->fd == 0 && iflag && something) {
309		// linenoise doesn't expect the command terminator at the end of the history
310		// entry.
311		char command_terminator = q[-1];
312		q[-1] = '\0';
313
314		addtohistory(parsefile->nextc, strlen(parsefile->nextc));
315
316		// Restore the command terminator.
317		q[-1] = command_terminator;
318	}
319#endif
320
321	if (vflag) {
322		out2str(parsefile->nextc);
323#ifdef FLUSHERR
324		flushout(out2);
325#endif
326	}
327
328	*q = savec;
329
330	return (signed char)*parsefile->nextc++;
331}
332
333/*
334 * Undo a call to pgetc.  Only two characters may be pushed back.
335 * PEOF may be pushed back.
336 */
337
338void
339pungetc(void)
340{
341	parsefile->unget++;
342}
343
344/*
345 * Push a string back onto the input at this current parsefile level.
346 * We handle aliases this way.
347 */
348void
349pushstring(char *s, void *ap)
350{
351	struct strpush *sp;
352	size_t len;
353
354	len = strlen(s);
355	INTOFF;
356/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
357	if (parsefile->strpush) {
358		sp = ckmalloc(sizeof (struct strpush));
359		sp->prev = parsefile->strpush;
360		parsefile->strpush = sp;
361	} else
362		sp = parsefile->strpush = &(parsefile->basestrpush);
363	sp->prevstring = parsefile->nextc;
364	sp->prevnleft = parsefile->nleft;
365	sp->unget = parsefile->unget;
366	memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
367	sp->ap = (struct alias *)ap;
368	if (ap) {
369		((struct alias *)ap)->flag |= ALIASINUSE;
370		sp->string = s;
371	}
372	parsefile->nextc = s;
373	parsefile->nleft = len;
374	parsefile->unget = 0;
375	INTON;
376}
377
378void
379popstring(void)
380{
381	struct strpush *sp = parsefile->strpush;
382
383	INTOFF;
384	if (sp->ap) {
385		if (parsefile->nextc[-1] == ' ' ||
386		    parsefile->nextc[-1] == '\t') {
387			checkkwd |= CHKALIAS;
388		}
389		if (sp->string != sp->ap->val) {
390			ckfree(sp->string);
391		}
392		sp->ap->flag &= ~ALIASINUSE;
393		if (sp->ap->flag & ALIASDEAD) {
394			unalias(sp->ap->name);
395		}
396	}
397	parsefile->nextc = sp->prevstring;
398	parsefile->nleft = sp->prevnleft;
399	parsefile->unget = sp->unget;
400	memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
401/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
402	parsefile->strpush = sp->prev;
403	if (sp != &(parsefile->basestrpush))
404		ckfree(sp);
405	INTON;
406}
407
408/*
409 * Set the input to take input from a file.  If push is set, push the
410 * old input onto the stack first.
411 */
412
413int
414setinputfile(const char *fname, int flags)
415{
416	int fd;
417
418	INTOFF;
419	if ((fd = open(fname, O_RDONLY)) < 0) {
420		if (flags & INPUT_NOFILE_OK)
421			goto out;
422		exitstatus = 127;
423		exerror(EXERROR, "Can't open %s", fname);
424	}
425	if (fd < 10)
426		fd = savefd(fd, fd);
427	setinputfd(fd, flags & INPUT_PUSH_FILE);
428out:
429	INTON;
430	return fd;
431}
432
433
434/*
435 * Like setinputfile, but takes an open file descriptor.  Call this with
436 * interrupts off.
437 */
438
439static void
440setinputfd(int fd, int push)
441{
442	if (push) {
443		pushfile();
444		parsefile->buf = 0;
445	}
446	parsefile->fd = fd;
447	if (parsefile->buf == NULL)
448		parsefile->buf = ckmalloc(IBUFSIZ);
449	parsefile->lleft = parsefile->nleft = 0;
450	plinno = 1;
451}
452
453
454/*
455 * Like setinputfile, but takes input from a string.
456 */
457
458void
459setinputstring(char *string)
460{
461	INTOFF;
462	pushfile();
463	parsefile->nextc = string;
464	parsefile->nleft = strlen(string);
465	parsefile->buf = NULL;
466	plinno = 1;
467	INTON;
468}
469
470
471
472/*
473 * To handle the "." command, a stack of input files is used.  Pushfile
474 * adds a new entry to the stack and popfile restores the previous level.
475 */
476
477STATIC void
478pushfile(void)
479{
480	struct parsefile *pf;
481
482	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
483	pf->prev = parsefile;
484	pf->fd = -1;
485	pf->strpush = NULL;
486	pf->basestrpush.prev = NULL;
487	pf->unget = 0;
488	parsefile = pf;
489}
490
491
492void
493popfile(void)
494{
495	struct parsefile *pf = parsefile;
496
497	INTOFF;
498	if (pf->fd >= 0)
499		close(pf->fd);
500	if (pf->buf)
501		ckfree(pf->buf);
502	while (pf->strpush)
503		popstring();
504	parsefile = pf->prev;
505	ckfree(pf);
506	INTON;
507}
508
509
510/*
511 * Return to top level.
512 */
513
514void
515popallfiles(void)
516{
517	while (parsefile != &basepf)
518		popfile();
519}
520
521
522
523/*
524 * Close the file(s) that the shell is reading commands from.  Called
525 * after a fork is done.
526 */
527
528void
529closescript(void)
530{
531	popallfiles();
532	if (parsefile->fd > 0) {
533		close(parsefile->fd);
534		parsefile->fd = 0;
535	}
536}
537