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