VirtualBox

source: kBuild/trunk/src/ash/input.c@ 1158

Last change on this file since 1158 was 809, checked in by bird, 18 years ago

Solaris + cleanup.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette