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