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