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