]> git.saurik.com Git - apple/shell_cmds.git/blob - sh/input.c
shell_cmds-198.tar.gz
[apple/shell_cmds.git] / sh / input.c
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <stdio.h> /* defines BUFSIZ */
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 /*
49 * This file implements the input routines used by the parser.
50 */
51
52 #include "shell.h"
53 #include "redir.h"
54 #include "syntax.h"
55 #include "input.h"
56 #include "output.h"
57 #include "options.h"
58 #include "memalloc.h"
59 #include "error.h"
60 #include "alias.h"
61 #include "parser.h"
62 #include "myhistedit.h"
63 #include "trap.h"
64
65 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
66
67 struct strpush {
68 struct strpush *prev; /* preceding string on stack */
69 const char *prevstring;
70 int prevnleft;
71 int prevlleft;
72 struct alias *ap; /* if push was associated with an alias */
73 };
74
75 /*
76 * The parsefile structure pointed to by the global variable parsefile
77 * contains information about the current file being read.
78 */
79
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 this line */
85 int lleft; /* number of lines left in this buffer */
86 const char *nextc; /* next char in buffer */
87 char *buf; /* input buffer */
88 struct strpush *strpush; /* for pushing strings at this level */
89 struct strpush basestrpush; /* so pushing one is fast */
90 };
91
92
93 int plinno = 1; /* input line number */
94 int parsenleft; /* copy of parsefile->nleft */
95 static int parselleft; /* copy of parsefile->lleft */
96 const char *parsenextc; /* copy of parsefile->nextc */
97 static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
98 static struct parsefile basepf = { /* top level input file */
99 .nextc = basebuf,
100 .buf = basebuf
101 };
102 static struct parsefile *parsefile = &basepf; /* current input file */
103 int whichprompt; /* 1 == PS1, 2 == PS2 */
104
105 #ifndef __APPLE__
106 EditLine *el; /* cookie for editline package */
107 #endif /* !__APPLE__ */
108
109 static void pushfile(void);
110 static int preadfd(void);
111 static void popstring(void);
112
113 void
114 resetinput(void)
115 {
116 popallfiles();
117 parselleft = parsenleft = 0; /* clear input buffer */
118 }
119
120
121
122 /*
123 * Read a character from the script, returning PEOF on end of file.
124 * Nul characters in the input are silently discarded.
125 */
126
127 int
128 pgetc(void)
129 {
130 return pgetc_macro();
131 }
132
133
134 static int
135 preadfd(void)
136 {
137 int nr;
138 parsenextc = parsefile->buf;
139
140 retry:
141 #ifndef NO_HISTORY
142 if (parsefile->fd == 0 && el) {
143 static const char *rl_cp;
144 static int el_len;
145
146 if (rl_cp == NULL) {
147 el_resize(el);
148 rl_cp = el_gets(el, &el_len);
149 }
150 if (rl_cp == NULL)
151 nr = el_len == 0 ? 0 : -1;
152 else {
153 nr = el_len;
154 if (nr > BUFSIZ)
155 nr = BUFSIZ;
156 memcpy(parsefile->buf, rl_cp, nr);
157 if (nr != el_len) {
158 el_len -= nr;
159 rl_cp += nr;
160 } else
161 rl_cp = NULL;
162 }
163 } else
164 #endif
165 nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
166
167 if (nr <= 0) {
168 if (nr < 0) {
169 if (errno == EINTR)
170 goto retry;
171 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
172 int flags = fcntl(0, F_GETFL, 0);
173 if (flags >= 0 && flags & O_NONBLOCK) {
174 flags &=~ O_NONBLOCK;
175 if (fcntl(0, F_SETFL, flags) >= 0) {
176 out2fmt_flush("sh: turning off NDELAY mode\n");
177 goto retry;
178 }
179 }
180 }
181 }
182 nr = -1;
183 }
184 return nr;
185 }
186
187 /*
188 * Refill the input buffer and return the next input character:
189 *
190 * 1) If a string was pushed back on the input, pop it;
191 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
192 * from a string so we can't refill the buffer, return EOF.
193 * 3) If there is more in this buffer, use it else call read to fill it.
194 * 4) Process input up to the next newline, deleting nul characters.
195 */
196
197 int
198 preadbuffer(void)
199 {
200 char *p, *q;
201 int more;
202 char savec;
203
204 while (parsefile->strpush) {
205 /*
206 * Add a space to the end of an alias to ensure that the
207 * alias remains in use while parsing its last word.
208 * This avoids alias recursions.
209 */
210 if (parsenleft == -1 && parsefile->strpush->ap != NULL)
211 return ' ';
212 popstring();
213 if (--parsenleft >= 0)
214 return (*parsenextc++);
215 }
216 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
217 return PEOF;
218 flushout(&output);
219 flushout(&errout);
220
221 again:
222 if (parselleft <= 0) {
223 if ((parselleft = preadfd()) == -1) {
224 parselleft = parsenleft = EOF_NLEFT;
225 return PEOF;
226 }
227 }
228
229 q = p = parsefile->buf + (parsenextc - parsefile->buf);
230
231 /* delete nul characters */
232 for (more = 1; more;) {
233 switch (*p) {
234 case '\0':
235 p++; /* Skip nul */
236 goto check;
237
238 case '\n':
239 parsenleft = q - parsenextc;
240 more = 0; /* Stop processing here */
241 break;
242
243 default:
244 break;
245 }
246
247 *q++ = *p++;
248 check:
249 if (--parselleft <= 0) {
250 parsenleft = q - parsenextc - 1;
251 if (parsenleft < 0)
252 goto again;
253 *q = '\0';
254 more = 0;
255 }
256 }
257
258 savec = *q;
259 *q = '\0';
260
261 #ifndef NO_HISTORY
262 if (parsefile->fd == 0 && hist &&
263 parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
264 HistEvent he;
265 INTOFF;
266 history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
267 parsenextc);
268 INTON;
269 }
270 #endif
271
272 if (vflag) {
273 out2str(parsenextc);
274 flushout(out2);
275 }
276
277 *q = savec;
278
279 return *parsenextc++;
280 }
281
282 /*
283 * Returns if we are certain we are at EOF. Does not cause any more input
284 * to be read from the outside world.
285 */
286
287 int
288 preadateof(void)
289 {
290 if (parsenleft > 0)
291 return 0;
292 if (parsefile->strpush)
293 return 0;
294 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
295 return 1;
296 return 0;
297 }
298
299 /*
300 * Undo the last call to pgetc. Only one character may be pushed back.
301 * PEOF may be pushed back.
302 */
303
304 void
305 pungetc(void)
306 {
307 parsenleft++;
308 parsenextc--;
309 }
310
311 /*
312 * Push a string back onto the input at this current parsefile level.
313 * We handle aliases this way.
314 */
315 void
316 pushstring(const char *s, int len, struct alias *ap)
317 {
318 struct strpush *sp;
319
320 INTOFF;
321 /*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
322 if (parsefile->strpush) {
323 sp = ckmalloc(sizeof (struct strpush));
324 sp->prev = parsefile->strpush;
325 parsefile->strpush = sp;
326 } else
327 sp = parsefile->strpush = &(parsefile->basestrpush);
328 sp->prevstring = parsenextc;
329 sp->prevnleft = parsenleft;
330 sp->prevlleft = parselleft;
331 sp->ap = ap;
332 if (ap)
333 ap->flag |= ALIASINUSE;
334 parsenextc = s;
335 parsenleft = len;
336 INTON;
337 }
338
339 static void
340 popstring(void)
341 {
342 struct strpush *sp = parsefile->strpush;
343
344 INTOFF;
345 if (sp->ap) {
346 if (parsenextc != sp->ap->val &&
347 (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
348 forcealias();
349 sp->ap->flag &= ~ALIASINUSE;
350 }
351 parsenextc = sp->prevstring;
352 parsenleft = sp->prevnleft;
353 parselleft = sp->prevlleft;
354 /*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
355 parsefile->strpush = sp->prev;
356 if (sp != &(parsefile->basestrpush))
357 ckfree(sp);
358 INTON;
359 }
360
361 /*
362 * Set the input to take input from a file. If push is set, push the
363 * old input onto the stack first.
364 */
365
366 void
367 setinputfile(const char *fname, int push)
368 {
369 int fd;
370 int fd2;
371
372 INTOFF;
373 if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
374 error("cannot open %s: %s", fname, strerror(errno));
375 if (fd < 10) {
376 fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
377 close(fd);
378 if (fd2 < 0)
379 error("Out of file descriptors");
380 fd = fd2;
381 }
382 setinputfd(fd, push);
383 INTON;
384 }
385
386
387 /*
388 * Like setinputfile, but takes an open file descriptor (which should have
389 * its FD_CLOEXEC flag already set). Call this with interrupts off.
390 */
391
392 void
393 setinputfd(int fd, int push)
394 {
395 if (push) {
396 pushfile();
397 parsefile->buf = ckmalloc(BUFSIZ + 1);
398 }
399 if (parsefile->fd > 0)
400 close(parsefile->fd);
401 parsefile->fd = fd;
402 if (parsefile->buf == NULL)
403 parsefile->buf = ckmalloc(BUFSIZ + 1);
404 parselleft = parsenleft = 0;
405 plinno = 1;
406 }
407
408
409 /*
410 * Like setinputfile, but takes input from a string.
411 */
412
413 void
414 setinputstring(const char *string, int push)
415 {
416 INTOFF;
417 if (push)
418 pushfile();
419 parsenextc = string;
420 parselleft = parsenleft = strlen(string);
421 parsefile->buf = NULL;
422 plinno = 1;
423 INTON;
424 }
425
426
427
428 /*
429 * To handle the "." command, a stack of input files is used. Pushfile
430 * adds a new entry to the stack and popfile restores the previous level.
431 */
432
433 static void
434 pushfile(void)
435 {
436 struct parsefile *pf;
437
438 parsefile->nleft = parsenleft;
439 parsefile->lleft = parselleft;
440 parsefile->nextc = parsenextc;
441 parsefile->linno = plinno;
442 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
443 pf->prev = parsefile;
444 pf->fd = -1;
445 pf->strpush = NULL;
446 pf->basestrpush.prev = NULL;
447 parsefile = pf;
448 }
449
450
451 void
452 popfile(void)
453 {
454 struct parsefile *pf = parsefile;
455
456 INTOFF;
457 if (pf->fd >= 0)
458 close(pf->fd);
459 if (pf->buf)
460 ckfree(pf->buf);
461 while (pf->strpush)
462 popstring();
463 parsefile = pf->prev;
464 ckfree(pf);
465 parsenleft = parsefile->nleft;
466 parselleft = parsefile->lleft;
467 parsenextc = parsefile->nextc;
468 plinno = parsefile->linno;
469 INTON;
470 }
471
472
473 /*
474 * Return current file (to go back to it later using popfilesupto()).
475 */
476
477 struct parsefile *
478 getcurrentfile(void)
479 {
480 return parsefile;
481 }
482
483
484 /*
485 * Pop files until the given file is on top again. Useful for regular
486 * builtins that read shell commands from files or strings.
487 * If the given file is not an active file, an error is raised.
488 */
489
490 void
491 popfilesupto(struct parsefile *file)
492 {
493 while (parsefile != file && parsefile != &basepf)
494 popfile();
495 if (parsefile != file)
496 error("popfilesupto() misused");
497 }
498
499 /*
500 * Return to top level.
501 */
502
503 void
504 popallfiles(void)
505 {
506 while (parsefile != &basepf)
507 popfile();
508 }
509
510
511
512 /*
513 * Close the file(s) that the shell is reading commands from. Called
514 * after a fork is done.
515 */
516
517 void
518 closescript(void)
519 {
520 popallfiles();
521 if (parsefile->fd > 0) {
522 close(parsefile->fd);
523 parsefile->fd = 0;
524 }
525 }