source: mainline/uspace/app/ash/input.c@ 8ccd2ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8ccd2ea was c28a023, checked in by Josef Cejka <malyzelenyhnus@…>, 17 years ago

Initial commit of ash shell.
It cannot be compiled yet.

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