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