Make /dev/c1* device nodes on disk and on the boot ramdisk.
[minix3.git] / commands / ash / input.c
blob109cbfa30cd97c5f7f7bb05a43ecc615faa1aa92
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
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.
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.
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
36 #endif
37 #endif /* not lint */
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
43 #include <sys/types.h>
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>
52 * This file implements the input routines used by the parser.
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 #ifdef EDITLINE
66 #ifdef __minix_vmd
67 #include <readline/readline.h>
68 #else
69 /* What about other systems? */
70 char *readline(char *prompt);
71 #endif
72 #else
73 #include "myhistedit.h"
74 #endif
75 #include "redir.h"
76 #include "trap.h"
78 static void popstring(void);
80 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
82 MKINIT
83 struct strpush {
84 struct strpush *prev; /* preceding string on stack */
85 char *prevstring;
86 int prevnleft;
87 int prevlleft;
88 struct alias *ap; /* if push was associated with an alias */
92 * The parsefile structure pointed to by the global variable parsefile
93 * contains information about the current file being read.
96 MKINIT
97 struct parsefile {
98 struct parsefile *prev; /* preceding file on stack */
99 int linno; /* current line */
100 int fd; /* file descriptor (or -1 if string) */
101 int nleft; /* number of chars left in this line */
102 int lleft; /* number of lines left in this buffer */
103 char *nextc; /* next char in buffer */
104 char *buf; /* input buffer */
105 struct strpush *strpush; /* for pushing strings at this level */
106 struct strpush basestrpush; /* so pushing one is fast */
110 int plinno = 1; /* input line number */
111 MKINIT int parsenleft; /* copy of parsefile->nleft */
112 MKINIT int parselleft; /* copy of parsefile->lleft */
113 char *parsenextc; /* copy of parsefile->nextc */
114 MKINIT struct parsefile basepf; /* top level input file */
115 char basebuf[BUFSIZ]; /* buffer for top level input file */
116 STATIC struct parsefile *parsefile = &basepf; /* current input file */
117 int init_editline = 0; /* editline library initialized? */
118 int whichprompt; /* -1 == PSE, 1 == PS1, 2 == PS2 */
120 #ifndef EDITLINE
121 EditLine *el; /* cookie for editline package */
122 #endif
124 STATIC void pushfile(void);
125 static int preadfd(void);
127 #ifdef mkinit
128 INCLUDE "input.h"
129 INCLUDE "error.h"
131 INIT {
132 extern char basebuf[];
134 basepf.nextc = basepf.buf = basebuf;
137 RESET {
138 if (exception != EXSHELLPROC)
139 parselleft = parsenleft = 0; /* clear input buffer */
140 popallfiles();
143 SHELLPROC {
144 popallfiles();
146 #endif
150 * Read a line from the script.
153 char *
154 pfgets(char *line, int len)
156 char *p = line;
157 int nleft = len;
158 int c;
160 while (--nleft > 0) {
161 c = pgetc_macro();
162 if (c == PEOF) {
163 if (p == line)
164 return NULL;
165 break;
167 *p++ = c;
168 if (c == '\n')
169 break;
171 *p = '\0';
172 return line;
178 * Read a character from the script, returning PEOF on end of file.
179 * Nul characters in the input are silently discarded.
183 pgetc(void)
185 return pgetc_macro();
189 static int
190 preadfd(void)
192 int nr;
193 parsenextc = parsefile->buf;
195 #if !defined(NO_HISTORY) && !defined(EDITLINE)
196 if (el != NULL && gotwinch) {
197 gotwinch = 0;
198 el_resize(el);
200 #endif
201 retry:
202 #ifndef NO_HISTORY
203 #ifdef EDITLINE
204 if (parsefile->fd == 0 && editable) {
205 static const char *rl_cp= NULL;
206 static size_t rl_off= 0;
208 if (!rl_cp)
210 rl_cp = readline(getprompt(NULL));
211 if (rl_cp == NULL)
212 nr = 0;
214 if (rl_cp)
216 nr= strlen(rl_cp+rl_off);
217 if (nr >= BUFSIZ-1)
219 nr= BUFSIZ-1;
220 (void) memcpy(parsenextc, rl_cp+rl_off, nr);
221 rl_off += nr;
223 else
225 (void) memcpy(parsenextc, rl_cp+rl_off, nr);
226 parsenextc[nr++]= '\n';
227 free(rl_cp);
228 rl_cp= NULL;
229 rl_off= 0;
232 } else
233 #else /* !EDITLINE */
234 if (parsefile->fd == 0 && el) {
235 const char *rl_cp;
237 rl_cp = el_gets(el, &nr);
238 if (rl_cp == NULL)
239 nr = 0;
240 else {
241 /* XXX - BUFSIZE should redesign so not necessary */
242 (void) strcpy(parsenextc, rl_cp);
244 } else
245 #endif /* !EDITLINE */
246 #endif
247 nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
249 if (nr <= 0) {
250 if (nr < 0) {
251 if (errno == EINTR)
252 goto retry;
253 #ifdef EWOULDBLOCK
254 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
255 int flags = fcntl(0, F_GETFL, 0);
256 if (flags >= 0 && flags & O_NONBLOCK) {
257 flags &=~ O_NONBLOCK;
258 if (fcntl(0, F_SETFL, flags) >= 0) {
259 out2str("sh: turning off NDELAY mode\n");
260 goto retry;
264 #endif /* EWOULDBLOCK */
266 nr = -1;
268 return nr;
272 * Refill the input buffer and return the next input character:
274 * 1) If a string was pushed back on the input, pop it;
275 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
276 * from a string so we can't refill the buffer, return EOF.
277 * 3) If there is more in this buffer, use it else call read to fill it.
278 * 4) Process input up to the next newline, deleting nul characters.
282 preadbuffer(void)
284 char *p, *q;
285 int more;
286 int something;
287 char savec;
289 if (parsefile->strpush) {
290 popstring();
291 if (--parsenleft >= 0)
292 return (*parsenextc++);
294 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
295 return PEOF;
296 flushout(&output);
297 flushout(&errout);
299 again:
300 if (parselleft <= 0) {
301 if ((parselleft = preadfd()) == -1) {
302 parselleft = parsenleft = EOF_NLEFT;
303 return PEOF;
307 q = p = parsenextc;
309 /* delete nul characters */
310 something = 0;
311 for (more = 1; more;) {
312 switch (*p) {
313 case '\0':
314 p++; /* Skip nul */
315 goto check;
317 case '\t':
318 case ' ':
319 break;
321 case '\n':
322 parsenleft = q - parsenextc;
323 more = 0; /* Stop processing here */
324 break;
326 default:
327 something = 1;
328 break;
331 *q++ = *p++;
332 check:
333 if (--parselleft <= 0) {
334 parsenleft = q - parsenextc - 1;
335 if (parsenleft < 0)
336 goto again;
337 *q = '\0';
338 more = 0;
342 savec = *q;
343 *q = '\0';
345 #if !defined(NO_HISTORY) && !defined(EDITLINE)
346 if (parsefile->fd == 0 && hist && something) {
347 HistEvent he;
348 INTOFF;
349 history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
350 parsenextc);
351 INTON;
353 #endif
355 if (vflag) {
356 out2str(parsenextc);
357 flushout(out2);
360 *q = savec;
362 return *parsenextc++;
366 * Undo the last call to pgetc. Only one character may be pushed back.
367 * PEOF may be pushed back.
370 void
371 pungetc(void)
373 parsenleft++;
374 parsenextc--;
378 * Push a string back onto the input at this current parsefile level.
379 * We handle aliases this way.
381 void
382 pushstring(char *s, int len, void *ap)
384 struct strpush *sp;
386 INTOFF;
387 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
388 if (parsefile->strpush) {
389 sp = ckmalloc(sizeof (struct strpush));
390 sp->prev = parsefile->strpush;
391 parsefile->strpush = sp;
392 } else
393 sp = parsefile->strpush = &(parsefile->basestrpush);
394 sp->prevstring = parsenextc;
395 sp->prevnleft = parsenleft;
396 sp->prevlleft = parselleft;
397 sp->ap = (struct alias *)ap;
398 if (ap)
399 ((struct alias *)ap)->flag |= ALIASINUSE;
400 parsenextc = s;
401 parsenleft = len;
402 INTON;
405 static void
406 popstring(void)
408 struct strpush *sp = parsefile->strpush;
410 INTOFF;
411 parsenextc = sp->prevstring;
412 parsenleft = sp->prevnleft;
413 parselleft = sp->prevlleft;
414 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
415 if (sp->ap)
416 sp->ap->flag &= ~ALIASINUSE;
417 parsefile->strpush = sp->prev;
418 if (sp != &(parsefile->basestrpush))
419 ckfree(sp);
420 INTON;
424 * Set the input to take input from a file. If push is set, push the
425 * old input onto the stack first.
428 void
429 setinputfile(char *fname, int push)
431 int fd;
432 int fd2;
434 INTOFF;
435 if ((fd = open(fname, O_RDONLY)) < 0)
436 error("Can't open %s: %s", fname, strerror(errno));
437 if (fd < 10) {
438 fd2 = fcntl(fd, F_DUPFD, 10);
439 close(fd);
440 if (fd2 < 0)
441 error("Out of file descriptors");
442 fd = fd2;
444 setinputfd(fd, push);
445 INTON;
450 * Like setinputfile, but takes an open file descriptor. Call this with
451 * interrupts off.
454 void
455 setinputfd(int fd, int push)
457 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
458 if (push) {
459 pushfile();
460 parsefile->buf = ckmalloc(BUFSIZ);
462 if (parsefile->fd > 0)
463 close(parsefile->fd);
464 parsefile->fd = fd;
465 if (parsefile->buf == NULL)
466 parsefile->buf = ckmalloc(BUFSIZ);
467 parselleft = parsenleft = 0;
468 plinno = 1;
473 * Like setinputfile, but takes input from a string.
476 void
477 setinputstring(char *string, int push)
479 INTOFF;
480 if (push)
481 pushfile();
482 parsenextc = string;
483 parselleft = parsenleft = strlen(string);
484 parsefile->buf = NULL;
485 plinno = 1;
486 INTON;
492 * To handle the "." command, a stack of input files is used. Pushfile
493 * adds a new entry to the stack and popfile restores the previous level.
496 STATIC void
497 pushfile(void)
499 struct parsefile *pf;
501 parsefile->nleft = parsenleft;
502 parsefile->lleft = parselleft;
503 parsefile->nextc = parsenextc;
504 parsefile->linno = plinno;
505 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
506 pf->prev = parsefile;
507 pf->fd = -1;
508 pf->strpush = NULL;
509 pf->basestrpush.prev = NULL;
510 parsefile = pf;
514 void
515 popfile(void)
517 struct parsefile *pf = parsefile;
519 INTOFF;
520 if (pf->fd >= 0)
521 close(pf->fd);
522 if (pf->buf)
523 ckfree(pf->buf);
524 while (pf->strpush)
525 popstring();
526 parsefile = pf->prev;
527 ckfree(pf);
528 parsenleft = parsefile->nleft;
529 parselleft = parsefile->lleft;
530 parsenextc = parsefile->nextc;
531 plinno = parsefile->linno;
532 INTON;
537 * Return to top level.
540 void
541 popallfiles(void)
543 while (parsefile != &basepf)
544 popfile();
550 * Close the file(s) that the shell is reading commands from. Called
551 * after a fork is done.
554 void
555 closescript(void)
557 popallfiles();
558 if (parsefile->fd > 0) {
559 close(parsefile->fd);
560 parsefile->fd = 0;
565 * $PchId: input.c,v 1.7 2006/05/29 13:09:38 philip Exp $