• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $	*/
2 
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 <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
39 #else
40 __RCSID("$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $");
41 #endif
42 #endif /* not lint */
43 
44 #include <stdio.h>	/* defines BUFSIZ */
45 #include <fcntl.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <string.h>
50 
51 /*
52  * This file implements the input routines used by the parser.
53  */
54 
55 #include "shell.h"
56 #include "redir.h"
57 #include "syntax.h"
58 #include "input.h"
59 #include "output.h"
60 #include "options.h"
61 #include "memalloc.h"
62 #include "error.h"
63 #include "alias.h"
64 #include "parser.h"
65 #include "myhistedit.h"
66 
67 #ifdef WITH_LINENOISE
68 #include "linenoise.h"
69 #endif
70 
71 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
72 
73 MKINIT
74 struct strpush {
75 	struct strpush *prev;	/* preceding string on stack */
76 	char *prevstring;
77 	int prevnleft;
78 	int prevlleft;
79 	struct alias *ap;	/* if push was associated with an alias */
80 };
81 
82 /*
83  * The parsefile structure pointed to by the global variable parsefile
84  * contains information about the current file being read.
85  */
86 
87 MKINIT
88 struct parsefile {
89 	struct parsefile *prev;	/* preceding file on stack */
90 	int linno;		/* current line */
91 	int fd;			/* file descriptor (or -1 if string) */
92 	int nleft;		/* number of chars left in this line */
93 	int lleft;		/* number of chars left in this buffer */
94 	char *nextc;		/* next char in buffer */
95 	char *buf;		/* input buffer */
96 	struct strpush *strpush; /* for pushing strings at this level */
97 	struct strpush basestrpush; /* so pushing one is fast */
98 };
99 
100 
101 int plinno = 1;			/* input line number */
102 int parsenleft;			/* copy of parsefile->nleft */
103 MKINIT int parselleft;		/* copy of parsefile->lleft */
104 char *parsenextc;		/* copy of parsefile->nextc */
105 MKINIT struct parsefile basepf;	/* top level input file */
106 MKINIT char basebuf[BUFSIZ];	/* buffer for top level input file */
107 struct parsefile *parsefile = &basepf;	/* current input file */
108 int init_editline = 0;		/* editline library initialized? */
109 int whichprompt;		/* 1 == PS1, 2 == PS2 */
110 
111 #if WITH_HISTORY
112 EditLine *el;			/* cookie for editline package */
113 #endif
114 
115 STATIC void pushfile(void);
116 static int preadfd(void);
117 
118 #ifdef mkinit
119 INCLUDE <stdio.h>
120 INCLUDE "input.h"
121 INCLUDE "error.h"
122 
123 INIT {
124 	basepf.nextc = basepf.buf = basebuf;
125 }
126 
127 RESET {
128 	if (exception != EXSHELLPROC)
129 		parselleft = parsenleft = 0;	/* clear input buffer */
130 	popallfiles();
131 }
132 
133 SHELLPROC {
134 	popallfiles();
135 }
136 #endif
137 
138 
139 /*
140  * Read a line from the script.
141  */
142 
143 char *
pfgets(char * line,int len)144 pfgets(char *line, int len)
145 {
146 	char *p = line;
147 	int nleft = len;
148 	int c;
149 
150 	while (--nleft > 0) {
151 		c = pgetc_macro();
152 		if (c == PEOF) {
153 			if (p == line)
154 				return NULL;
155 			break;
156 		}
157 		*p++ = c;
158 		if (c == '\n')
159 			break;
160 	}
161 	*p = '\0';
162 	return line;
163 }
164 
165 
166 
167 /*
168  * Read a character from the script, returning PEOF on end of file.
169  * Nul characters in the input are silently discarded.
170  */
171 
172 int
pgetc(void)173 pgetc(void)
174 {
175 	return pgetc_macro();
176 }
177 
in_interactive_mode()178 int in_interactive_mode() {
179     return parsefile != NULL && parsefile->fd == 0;
180 }
181 
182 static int
preadfd(void)183 preadfd(void)
184 {
185 	int nr;
186 	char *buf =  parsefile->buf;
187 	parsenextc = buf;
188 
189 retry:
190 #ifdef WITH_HISTORY
191 	if (parsefile->fd == 0 && el) {
192 		static const char *rl_cp;
193 		static int el_len;
194 
195 		if (rl_cp == NULL)
196 			rl_cp = el_gets(el, &el_len);
197 		if (rl_cp == NULL)
198 			nr = 0;
199 		else {
200 			nr = el_len;
201 			if (nr > BUFSIZ - 8)
202 				nr = BUFSIZ - 8;
203 			memcpy(buf, rl_cp, nr);
204 			if (nr != el_len) {
205 				el_len -= nr;
206 				rl_cp += nr;
207 			} else
208 				rl_cp = 0;
209 		}
210 
211 	} else
212 #endif
213 #ifdef WITH_LINENOISE
214     if (parsefile->fd == 0) {
215         static char *rl_start;
216         static const char *rl_cp;
217         static int el_len;
218 
219         if (rl_cp == NULL) {
220             rl_cp = rl_start = linenoise(getprompt(""));
221             if (rl_cp != NULL) {
222                 el_len = strlen(rl_start);
223                 if (el_len != 0) {
224                     /* Add non-blank lines to history. */
225                     linenoiseHistoryAdd(rl_start);
226                 }
227                 out2str("\n");
228                 /* Client expects a newline at end of input, doesn't expect null */
229                 rl_start[el_len++] = '\n';
230             }
231         }
232         if (rl_cp == NULL)
233             nr = 0;
234         else {
235             nr = el_len;
236             if (nr > BUFSIZ - 8)
237                 nr = BUFSIZ - 8;
238             memcpy(buf, rl_cp, nr);
239             if (nr != el_len) {
240                 el_len -= nr;
241                 rl_cp += nr;
242             } else {
243                 rl_cp = 0;
244                 if (rl_start != NULL) {
245                     free(rl_start);
246                     rl_start = NULL;
247                 }
248             }
249         }
250     } else
251 #endif
252 		nr = read(parsefile->fd, buf, BUFSIZ - 8);
253 
254 
255 	if (nr <= 0) {
256                 if (nr < 0) {
257                         if (errno == EINTR)
258                                 goto retry;
259                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
260                                 int flags = fcntl(0, F_GETFL, 0);
261                                 if (flags >= 0 && flags & O_NONBLOCK) {
262                                         flags &=~ O_NONBLOCK;
263                                         if (fcntl(0, F_SETFL, flags) >= 0) {
264 						out2str("sh: turning off NDELAY mode\n");
265                                                 goto retry;
266                                         }
267                                 }
268                         }
269                 }
270                 nr = -1;
271 	}
272 	return nr;
273 }
274 
275 /*
276  * Refill the input buffer and return the next input character:
277  *
278  * 1) If a string was pushed back on the input, pop it;
279  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
280  *    from a string so we can't refill the buffer, return EOF.
281  * 3) If the is more stuff in this buffer, use it else call read to fill it.
282  * 4) Process input up to the next newline, deleting nul characters.
283  */
284 
285 int
preadbuffer(void)286 preadbuffer(void)
287 {
288 	char *p, *q;
289 	int more;
290 	int something;
291 	char savec;
292 
293 	if (parsefile->strpush) {
294 		popstring();
295 		if (--parsenleft >= 0)
296 			return (*parsenextc++);
297 	}
298 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
299 		return PEOF;
300 	flushout(&output);
301 	flushout(&errout);
302 
303 again:
304 	if (parselleft <= 0) {
305 		if ((parselleft = preadfd()) == -1) {
306 			parselleft = parsenleft = EOF_NLEFT;
307 			return PEOF;
308 		}
309 	}
310 
311 	q = p = parsenextc;
312 
313 	/* delete nul characters */
314 	something = 0;
315 	for (more = 1; more;) {
316 		switch (*p) {
317 		case '\0':
318 			p++;	/* Skip nul */
319 			goto check;
320 
321 		case '\t':
322 		case ' ':
323 			break;
324 
325 		case '\n':
326 			parsenleft = q - parsenextc;
327 			more = 0; /* Stop processing here */
328 			break;
329 
330 		default:
331 			something = 1;
332 			break;
333 		}
334 
335 		*q++ = *p++;
336 check:
337 		if (--parselleft <= 0) {
338 			parsenleft = q - parsenextc - 1;
339 			if (parsenleft < 0)
340 				goto again;
341 			*q = '\0';
342 			more = 0;
343 		}
344 	}
345 
346 	savec = *q;
347 	*q = '\0';
348 
349 #ifdef WITH_HISTORY
350 	if (parsefile->fd == 0 && hist && something) {
351 		HistEvent he;
352 		INTOFF;
353 		history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
354 		    parsenextc);
355 		INTON;
356 	}
357 #endif
358 
359 	if (vflag) {
360 		out2str(parsenextc);
361 		flushout(out2);
362 	}
363 
364 	*q = savec;
365 
366 	return *parsenextc++;
367 }
368 
369 /*
370  * Undo the last call to pgetc.  Only one character may be pushed back.
371  * PEOF may be pushed back.
372  */
373 
374 void
pungetc(void)375 pungetc(void)
376 {
377 	parsenleft++;
378 	parsenextc--;
379 }
380 
381 /*
382  * Push a string back onto the input at this current parsefile level.
383  * We handle aliases this way.
384  */
385 void
pushstring(char * s,int len,void * ap)386 pushstring(char *s, int len, void *ap)
387 {
388 	struct strpush *sp;
389 
390 	INTOFF;
391 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
392 	if (parsefile->strpush) {
393 		sp = ckmalloc(sizeof (struct strpush));
394 		sp->prev = parsefile->strpush;
395 		parsefile->strpush = sp;
396 	} else
397 		sp = parsefile->strpush = &(parsefile->basestrpush);
398 	sp->prevstring = parsenextc;
399 	sp->prevnleft = parsenleft;
400 	sp->prevlleft = parselleft;
401 	sp->ap = (struct alias *)ap;
402 	if (ap)
403 		((struct alias *)ap)->flag |= ALIASINUSE;
404 	parsenextc = s;
405 	parsenleft = len;
406 	INTON;
407 }
408 
409 void
popstring(void)410 popstring(void)
411 {
412 	struct strpush *sp = parsefile->strpush;
413 
414 	INTOFF;
415 	parsenextc = sp->prevstring;
416 	parsenleft = sp->prevnleft;
417 	parselleft = sp->prevlleft;
418 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
419 	if (sp->ap)
420 		sp->ap->flag &= ~ALIASINUSE;
421 	parsefile->strpush = sp->prev;
422 	if (sp != &(parsefile->basestrpush))
423 		ckfree(sp);
424 	INTON;
425 }
426 
427 /*
428  * Set the input to take input from a file.  If push is set, push the
429  * old input onto the stack first.
430  */
431 
432 void
setinputfile(const char * fname,int push)433 setinputfile(const char *fname, int push)
434 {
435 	int fd;
436 	int fd2;
437 
438 	INTOFF;
439 	if ((fd = open(fname, O_RDONLY)) < 0)
440 		error("Can't open %s", fname);
441 	if (fd < 10) {
442 		fd2 = copyfd(fd, 10);
443 		close(fd);
444 		if (fd2 < 0)
445 			error("Out of file descriptors");
446 		fd = fd2;
447 	}
448 	setinputfd(fd, push);
449 	INTON;
450 }
451 
452 
453 /*
454  * Like setinputfile, but takes an open file descriptor.  Call this with
455  * interrupts off.
456  */
457 
458 void
setinputfd(int fd,int push)459 setinputfd(int fd, int push)
460 {
461 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
462 	if (push) {
463 		pushfile();
464 		parsefile->buf = ckmalloc(BUFSIZ);
465 	}
466 	if (parsefile->fd > 0)
467 		close(parsefile->fd);
468 	parsefile->fd = fd;
469 	if (parsefile->buf == NULL)
470 		parsefile->buf = ckmalloc(BUFSIZ);
471 	parselleft = parsenleft = 0;
472 	plinno = 1;
473 }
474 
475 
476 /*
477  * Like setinputfile, but takes input from a string.
478  */
479 
480 void
setinputstring(char * string,int push)481 setinputstring(char *string, int push)
482 {
483 	INTOFF;
484 	if (push)
485 		pushfile();
486 	parsenextc = string;
487 	parselleft = parsenleft = strlen(string);
488 	parsefile->buf = NULL;
489 	plinno = 1;
490 	INTON;
491 }
492 
493 
494 
495 /*
496  * To handle the "." command, a stack of input files is used.  Pushfile
497  * adds a new entry to the stack and popfile restores the previous level.
498  */
499 
500 STATIC void
pushfile(void)501 pushfile(void)
502 {
503 	struct parsefile *pf;
504 
505 	parsefile->nleft = parsenleft;
506 	parsefile->lleft = parselleft;
507 	parsefile->nextc = parsenextc;
508 	parsefile->linno = plinno;
509 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
510 	pf->prev = parsefile;
511 	pf->fd = -1;
512 	pf->strpush = NULL;
513 	pf->basestrpush.prev = NULL;
514 	parsefile = pf;
515 }
516 
517 
518 void
popfile(void)519 popfile(void)
520 {
521 	struct parsefile *pf = parsefile;
522 
523 	INTOFF;
524 	if (pf->fd >= 0)
525 		close(pf->fd);
526 	if (pf->buf)
527 		ckfree(pf->buf);
528 	while (pf->strpush)
529 		popstring();
530 	parsefile = pf->prev;
531 	ckfree(pf);
532 	parsenleft = parsefile->nleft;
533 	parselleft = parsefile->lleft;
534 	parsenextc = parsefile->nextc;
535 	plinno = parsefile->linno;
536 	INTON;
537 }
538 
539 
540 /*
541  * Return to top level.
542  */
543 
544 void
popallfiles(void)545 popallfiles(void)
546 {
547 	while (parsefile != &basepf)
548 		popfile();
549 }
550 
551 
552 
553 /*
554  * Close the file(s) that the shell is reading commands from.  Called
555  * after a fork is done.
556  *
557  * Takes one arg, vfork, which tells it to not modify its global vars
558  * as it is still running in the parent.
559  *
560  * This code is (probably) unnecessary as the 'close on exec' flag is
561  * set and should be enough.  In the vfork case it is definitely wrong
562  * to close the fds as another fork() may be done later to feed data
563  * from a 'here' document into a pipe and we don't want to close the
564  * pipe!
565  */
566 
567 void
closescript(int vforked)568 closescript(int vforked)
569 {
570 	if (vforked)
571 		return;
572 	popallfiles();
573 	if (parsefile->fd > 0) {
574 		close(parsefile->fd);
575 		parsefile->fd = 0;
576 	}
577 }
578