source: trunk/minix/commands/ash/input.c@ 11

Last change on this file since 11 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.0 KB
Line 
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * 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
38static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 7/1/91";
39#endif /* not lint */
40
41/*
42 * This file implements the input routines used by the parser.
43 */
44
45#include <sys/types.h>
46#include <stdio.h> /* defines BUFSIZ */
47#include "shell.h"
48#include <fcntl.h>
49#include <errno.h>
50#include "syntax.h"
51#include "input.h"
52#include "output.h"
53#include "memalloc.h"
54#include "error.h"
55
56#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
57
58
59/*
60 * The parsefile structure pointed to by the global variable parsefile
61 * contains information about the current file being read.
62 */
63
64MKINIT
65struct parsefile {
66 int linno; /* current line */
67 int fd; /* file descriptor (or -1 if string) */
68 int nleft; /* number of chars left in buffer */
69 char *nextc; /* next char in buffer */
70 struct parsefile *prev; /* preceding file on stack */
71 char *buf; /* input buffer */
72};
73
74
75int plinno = 1; /* input line number */
76MKINIT int parsenleft; /* copy of parsefile->nleft */
77char *parsenextc; /* copy of parsefile->nextc */
78MKINIT struct parsefile basepf; /* top level input file */
79char basebuf[BUFSIZ]; /* buffer for top level input file */
80struct parsefile *parsefile = &basepf; /* current input file */
81char *pushedstring; /* copy of parsenextc when text pushed back */
82int pushednleft; /* copy of parsenleft when text pushed back */
83
84#if READLINE
85char *readline __P((const char *prompt));
86char *r_use_prompt = NULL; /* the prompt to use with readline */
87#endif
88
89#ifdef __STDC__
90STATIC void pushfile(void);
91#else
92STATIC void pushfile();
93#endif
94
95
96
97#ifdef mkinit
98INCLUDE "input.h"
99INCLUDE "error.h"
100
101INIT {
102 extern char basebuf[];
103
104 basepf.nextc = basepf.buf = basebuf;
105}
106
107RESET {
108 if (exception != EXSHELLPROC)
109 parsenleft = 0; /* clear input buffer */
110 popallfiles();
111}
112
113SHELLPROC {
114 popallfiles();
115}
116#endif
117
118
119/*
120 * Read a line from the script.
121 */
122
123char *
124pfgets(line, len)
125 char *line;
126 {
127 register char *p = line;
128 int nleft = len;
129 int c;
130
131 while (--nleft > 0) {
132 c = pgetc_macro();
133 if (c == PEOF) {
134 if (p == line)
135 return NULL;
136 break;
137 }
138 *p++ = c;
139 if (c == '\n')
140 break;
141 }
142 *p = '\0';
143 return line;
144}
145
146
147
148/*
149 * Read a character from the script, returning PEOF on end of file.
150 * Nul characters in the input are silently discarded.
151 */
152
153int
154pgetc() {
155 return pgetc_macro();
156}
157
158
159/*
160 * Refill the input buffer and return the next input character:
161 *
162 * 1) If a string was pushed back on the input, switch back to the regular
163 * buffer.
164 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
165 * from a string so we can't refill the buffer, return EOF.
166 * 3) Call read to read in the characters.
167 * 4) Delete all nul characters from the buffer.
168 */
169
170int
171preadbuffer() {
172 register char *p, *q;
173 register int i;
174
175 if (pushedstring) {
176 parsenextc = pushedstring;
177 pushedstring = NULL;
178 parsenleft = pushednleft;
179 if (--parsenleft >= 0)
180 return *parsenextc++;
181 }
182 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
183 return PEOF;
184 flushout(&output);
185 flushout(&errout);
186#if READLINE
187 /* Use the readline() call if a prompt is to be printed (interactive). */
188 if (r_use_prompt != NULL) {
189 char *prompt;
190 char *line;
191
192 p = parsenextc = parsefile->buf;
193
194 prompt = r_use_prompt;
195 r_use_prompt = NULL;
196
197 if ((line = readline(prompt)) == NULL) {
198 parsenleft = EOF_NLEFT;
199 return PEOF;
200 }
201 strcpy(p, line);
202 free(line);
203 i = strlen(p);
204 p[i++] = '\n';
205 } else {
206#endif
207retry:
208 p = parsenextc = parsefile->buf;
209 i = read(parsefile->fd, p, BUFSIZ);
210 if (i <= 0) {
211 if (i < 0) {
212 if (errno == EINTR)
213 goto retry;
214#ifdef EWOULDBLOCK
215 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
216 int flags = fcntl(0, F_GETFL, 0);
217 if (flags >= 0 && flags & O_NONBLOCK) {
218 flags &=~ O_NONBLOCK;
219 if (fcntl(0, F_SETFL, flags) >= 0) {
220 out2str("sh: turning off NDELAY mode\n");
221 goto retry;
222 }
223 }
224 }
225#endif
226 }
227 parsenleft = EOF_NLEFT;
228 return PEOF;
229 }
230#if READLINE
231 }
232#endif
233 parsenleft = i - 1;
234
235 /* delete nul characters */
236 for (;;) {
237 if (*p++ == '\0')
238 break;
239 if (--i <= 0)
240 return *parsenextc++; /* no nul characters */
241 }
242 q = p - 1;
243 while (--i > 0) {
244 if (*p != '\0')
245 *q++ = *p;
246 p++;
247 }
248 if (q == parsefile->buf)
249 goto retry; /* buffer contained nothing but nuls */
250 parsenleft = q - parsefile->buf - 1;
251 return *parsenextc++;
252}
253
254
255/*
256 * Undo the last call to pgetc. Only one character may be pushed back.
257 * PEOF may be pushed back.
258 */
259
260void
261pungetc() {
262 parsenleft++;
263 parsenextc--;
264}
265
266
267/*
268 * Push a string back onto the input. This code doesn't work if the user
269 * tries to push back more than one string at once.
270 */
271
272void
273ppushback(string, length)
274 char *string;
275 {
276 pushedstring = parsenextc;
277 pushednleft = parsenleft;
278 parsenextc = string;
279 parsenleft = length;
280}
281
282
283
284/*
285 * Set the input to take input from a file. If push is set, push the
286 * old input onto the stack first.
287 */
288
289void
290setinputfile(fname, push)
291 char *fname;
292 {
293 int fd;
294 int fd2;
295
296 INTOFF;
297 if ((fd = open(fname, O_RDONLY)) < 0)
298 error("Can't open %s", fname);
299 if (fd < 10) {
300 fd2 = copyfd(fd, 10);
301 close(fd);
302 if (fd2 < 0)
303 error("Out of file descriptors");
304 fd = fd2;
305 }
306 setinputfd(fd, push);
307 INTON;
308}
309
310
311/*
312 * Like setinputfile, but takes an open file descriptor. Call this with
313 * interrupts off.
314 */
315
316void
317setinputfd(fd, push) {
318 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
319 if (push) {
320 pushfile();
321 parsefile->buf = ckmalloc(BUFSIZ);
322 }
323 if (parsefile->fd > 0)
324 close(parsefile->fd);
325 parsefile->fd = fd;
326 if (parsefile->buf == NULL)
327 parsefile->buf = ckmalloc(BUFSIZ);
328 parsenleft = 0;
329 plinno = 1;
330}
331
332
333/*
334 * Like setinputfile, but takes input from a string.
335 */
336
337void
338setinputstring(string, push)
339 char *string;
340 {
341 INTOFF;
342 if (push)
343 pushfile();
344 parsenextc = string;
345 parsenleft = strlen(string);
346 parsefile->buf = NULL;
347 plinno = 1;
348 INTON;
349}
350
351
352
353/*
354 * To handle the "." command, a stack of input files is used. Pushfile
355 * adds a new entry to the stack and popfile restores the previous level.
356 */
357
358STATIC void
359pushfile() {
360 struct parsefile *pf;
361
362 parsefile->nleft = parsenleft;
363 parsefile->nextc = parsenextc;
364 parsefile->linno = plinno;
365 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
366 pf->prev = parsefile;
367 pf->fd = -1;
368 parsefile = pf;
369}
370
371
372void
373popfile() {
374 struct parsefile *pf = parsefile;
375
376 INTOFF;
377 if (pf->fd >= 0)
378 close(pf->fd);
379 if (pf->buf)
380 ckfree(pf->buf);
381 parsefile = pf->prev;
382 ckfree(pf);
383 parsenleft = parsefile->nleft;
384 parsenextc = parsefile->nextc;
385 plinno = parsefile->linno;
386 INTON;
387}
388
389
390/*
391 * Return to top level.
392 */
393
394void
395popallfiles() {
396 while (parsefile != &basepf)
397 popfile();
398}
399
400
401
402/*
403 * Close the file(s) that the shell is reading commands from. Called
404 * after a fork is done.
405 */
406
407void
408closescript() {
409 popallfiles();
410 if (parsefile->fd > 0) {
411 close(parsefile->fd);
412 parsefile->fd = 0;
413 }
414}
Note: See TracBrowser for help on using the repository browser.