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