1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2014 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgkorn@gmail.com> *
18 * *
19 ***********************************************************************/
20 #include "config_ast.h" // IWYU pragma: keep
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <setjmp.h>
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <termios.h>
31
32 #include "ast.h"
33 #include "ast_assert.h"
34 #include "builtins.h"
35 #include "cdt.h"
36 #include "defs.h"
37 #include "edit.h"
38 #include "error.h"
39 #include "fault.h"
40 #include "history.h"
41 #include "io.h"
42 #include "lexstates.h"
43 #include "name.h"
44 #include "optget_long.h"
45 #include "sfio.h"
46 #include "shcmd.h"
47 #include "stk.h"
48 #include "terminal.h"
49 #include "variables.h"
50
51 #define R_FLAG 1 // raw mode
52 #define S_FLAG 2 // save in history file
53 #define A_FLAG 4 // read into array
54 #define N_FLAG 8 // fixed size read at most
55 #define NN_FLAG 0x10 // fixed size read exact
56 #define V_FLAG 0x20 // use default value
57 #define C_FLAG 0x40 // read into compound variable
58 #define D_FLAG 8 // must be number of bits for all flags
59 #define SS_FLAG 0x80 // read .csv format file
60
61 struct read_save {
62 char **argv;
63 char *prompt;
64 short fd;
65 short plen;
66 int flags;
67 int mindex;
68 ssize_t len;
69 long timeout;
70 };
71
72 struct Method {
73 char *name;
74 void *fun;
75 };
76
77 // Support for json in `read` builtin seems very unstable, so this code is kept disabled.
78 // See https://github.com/att/ast/issues/820
79 #if SUPPORT_JSON
json2sh(Shell_t * shp,Sfio_t * in,Sfio_t * out)80 static_fn int json2sh(Shell_t *shp, Sfio_t *in, Sfio_t *out) {
81 int c, state = 0, lastc = 0, level = 0, line = 1;
82 size_t here, offset = stktell(shp->stk);
83 char *start;
84 bool isname, isnull = false;
85
86 while ((c = sfgetc(in)) > 0) {
87 if (c == '\n') line++;
88 if (state == 0) {
89 switch (c) {
90 case '\t':
91 case ' ': {
92 if (lastc == ' ' || lastc == '\t') continue;
93 break;
94 }
95 case ',': {
96 continue;
97 }
98 case '[':
99 case '{': {
100 c = '(';
101 level++;
102 break;
103 }
104 case ']':
105 case '}': {
106 c = ')';
107 level--;
108 break;
109 }
110 case '"': {
111 state = 1;
112 isname = true;
113 sfputc(shp->stk, c);
114 continue;
115 }
116 default: { break; }
117 }
118 sfputc(out, c);
119 if (level == 0) break;
120 } else if (state == 1) {
121 if (c == '"' && lastc != '\\') {
122 state = 2;
123 } else if (state == 1 && !isalnum(c) && c != '_') {
124 isname = false;
125 }
126 sfputc(shp->stk, c);
127 } else if (state == 2) {
128 if (c == ' ' || c == '\t') continue;
129 if (c == ':') {
130 int len;
131 while ((c = sfgetc(in)) && iswblank(c)) {
132 ; // empty loop
133 }
134 sfungetc(in, c);
135 if (!strchr("[{,\"", c)) {
136 if (isdigit(c) || c == '.' || c == '-') {
137 sfwrite(out, "float ", 6);
138 } else if (c == 't' || c == 'f') {
139 sfwrite(out, "bool ", 5);
140 } else if (c == 'n') {
141 char buff[4];
142 isnull = true;
143 sfread(in, buff, 4);
144 sfwrite(out, "typeset ", 8);
145 }
146 }
147 start = stkptr(shp->stk, offset);
148 here = stktell(shp->stk);
149 if (isname && !iswalpha(*(start + 1)) && c != '_') isname = false;
150 len = here - offset - 2;
151 if (!isname) {
152 char *sp;
153 sfwrite(out, ".[", 2);
154 for (sp = start + 1; len-- > 0; sp++) {
155 if (*sp == '$') {
156 if (sp > start + 1) sfwrite(out, start, sp - start);
157 sfputc(out, '\\');
158 sfputc(out, '$');
159 start = sp;
160 }
161 }
162 len = (sp - start) - 1;
163 }
164 sfwrite(out, start + 1, len);
165 if (!isname) sfputc(out, ']');
166 if (isnull) {
167 isnull = false;
168 } else {
169 sfputc(out, '=');
170 }
171 stkseek(shp->stk, offset);
172 if (c == '{') c = ' ';
173 }
174 if (c == ',' || c == '\n' || c == '}' || c == ']' || c == '{') {
175 start = stkptr(shp->stk, offset);
176 here = stktell(shp->stk);
177 if (here > 1) {
178 *stkptr(shp->stk, here - 1) = 0;
179 stresc(start + 1);
180 sfputr(out, sh_fmtq(start + 1), -1);
181 stkseek(shp->stk, offset);
182 }
183 if (c == '{') {
184 sfputc(out, '=');
185 } else {
186 sfputc(out, ' ');
187 }
188 if (c == '}' || c == ']' || c == '{') sfungetc(in, c);
189 }
190 c = ' ';
191 state = 0;
192 }
193 lastc = c;
194 }
195 return 0;
196 }
197 #endif
198
199 static struct Method methods[] = {
200 #if SUPPORT_JSON
201 {"json", json2sh},
202 #endif
203 {"ksh", NULL},
204 {NULL, NULL}};
205
206 static const char *short_options = "ad:n:p:rsu:t:vACN:S";
207 static const struct optget_option long_options[] = {
208 {"help", optget_no_arg, NULL, 1}, // all builtins support --help
209 {NULL, 0, NULL, 0}};
210
211 //
212 // Builtin `read` command.
213 //
b_read(int argc,char * argv[],Shbltin_t * context)214 int b_read(int argc, char *argv[], Shbltin_t *context) {
215 Sfdouble_t sec;
216 char *name = NULL;
217 int opt, r, flags = 0, fd = 0;
218 Shell_t *shp = context->shp;
219 char *cmd = argv[0];
220 ssize_t len = 0;
221 long timeout = 1000 * shp->st.tmout;
222 int save_prompt, fixargs = context->invariant;
223 struct read_save *rp;
224 int mindex = 0;
225 char *method = NULL;
226 void *readfn = NULL;
227 static char default_prompt[3] = {ESC, ESC};
228
229 rp = (struct read_save *)(context->data);
230 if (argc == 0) {
231 if (rp) free(rp);
232 return 0;
233 }
234 if (rp) {
235 flags = rp->flags;
236 timeout = rp->timeout;
237 fd = rp->fd;
238 argv = rp->argv;
239 name = rp->prompt;
240 mindex = rp->mindex;
241 r = rp->plen;
242 goto bypass;
243 }
244
245 optget_ind = 0;
246 while ((opt = optget_long(argc, argv, short_options, long_options)) != -1) {
247 switch (opt) {
248 case 1: {
249 builtin_print_help(shp, cmd);
250 return 0;
251 }
252 case 'a': {
253 // `read -a` is an alias for `read -A`
254 flags |= A_FLAG;
255 break;
256 }
257 case 'A': {
258 flags |= A_FLAG;
259 break;
260 }
261 case 'C': {
262 flags |= C_FLAG;
263 method = "ksh";
264 break;
265 }
266 case 't': {
267 sec = sh_strnum(shp, optget_arg, NULL, 1);
268 timeout = sec ? 1000 * sec : 1;
269 break;
270 }
271 case 'd': {
272 flags &= ((1 << (D_FLAG + 1)) - 1);
273 flags |= (mb1char(&optget_arg) << (D_FLAG + 1)) | (1 << D_FLAG);
274 break;
275 }
276 case 'p': {
277 if (shp->cpipe[0] <= 0 || (*optget_arg != '-' && (!strmatch(optget_arg, "+(\\w)") ||
278 isdigit(*optget_arg)))) {
279 name = optget_arg;
280 } else {
281 // For backward compatibility.
282 fd = shp->cpipe[0];
283 argv--;
284 argc--;
285 }
286 break;
287 }
288 #if SUPPORT_JSON
289 case 'm': {
290 method = optget_arg;
291 flags |= C_FLAG;
292 break;
293 }
294 #endif
295 case 'n':
296 case 'N': {
297 char *cp;
298 int64_t n = strton64(optget_arg, &cp, NULL, 0);
299 if (*cp || n < 0 || n > INT_MAX) {
300 builtin_usage_error(shp, cmd, "%s: invalid -%c value", optget_arg, optget_opt);
301 return 2;
302 }
303 len = n;
304 flags &= ((1 << D_FLAG) - 1);
305 flags |= (opt == 'n' ? N_FLAG : NN_FLAG);
306 break;
307 }
308 case 'r': {
309 flags |= R_FLAG;
310 break;
311 }
312 case 's': {
313 // Save in history file.
314 flags |= S_FLAG;
315 break;
316 }
317 case 'S': {
318 flags |= SS_FLAG;
319 break;
320 }
321 case 'u': {
322 if (optget_arg[0] == 'p' && optget_arg[1] == 0) {
323 fd = shp->cpipe[0];
324 if (fd <= 0) {
325 errormsg(SH_DICT, ERROR_exit(1), e_query);
326 __builtin_unreachable();
327 }
328 break;
329 }
330
331 char *cp;
332 int64_t n = strton64(optget_arg, &cp, NULL, 0);
333 if (*cp || n < 0 || n > INT_MAX || !sh_iovalidfd(shp, n)) {
334 builtin_usage_error(shp, cmd, "%s: invalid -u value", optget_arg);
335 return 2;
336 }
337 fd = n;
338 break;
339 }
340 case 'v': {
341 flags |= V_FLAG;
342 break;
343 }
344 case ':': {
345 if (optget_opt == 'p' && shp->cpipe[0] > 0) {
346 fd = shp->cpipe[0];
347 break;
348 }
349 builtin_missing_argument(shp, cmd, argv[optget_ind - 1]);
350 return 2;
351 }
352 case '?': {
353 builtin_unknown_option(shp, cmd, argv[optget_ind - 1]);
354 return 2;
355 }
356 default: { abort(); }
357 }
358 }
359 argv += optget_ind;
360
361 if (method) {
362 for (mindex = 0; methods[mindex].name; mindex++) {
363 if (strcmp(method, methods[mindex].name) == 0) break;
364 }
365 if (!methods[mindex].name) {
366 errormsg(SH_DICT, ERROR_system(1), "%s method not supported", method);
367 __builtin_unreachable();
368 }
369 }
370
371 if (!((r = shp->fdstatus[fd]) & IOREAD) || !(r & (IOSEEK | IONOSEEK))) {
372 assert(fd >= 0); // there is a theoretical path which could reach here with fd == -1
373 r = sh_iocheckfd(shp, fd, fd);
374 }
375 if (fd < 0 || !(r & IOREAD)) {
376 errormsg(SH_DICT, ERROR_system(1), e_file + 4);
377 __builtin_unreachable();
378 }
379 // Look for prompt.
380 if (!name && *argv && (name = strchr(*argv, '?'))) name++;
381 if (name && (r & IOTTY)) {
382 r = strlen(name) + 1;
383 } else {
384 r = 0;
385 }
386 if (argc == fixargs && (rp = calloc(1, sizeof(struct read_save)))) {
387 context->data = rp;
388 rp->fd = fd;
389 rp->flags = flags;
390 rp->timeout = timeout;
391 rp->argv = argv;
392 rp->prompt = name;
393 rp->plen = r;
394 rp->len = len;
395 rp->mindex = mindex;
396 }
397
398 bypass:
399 shp->prompt = default_prompt;
400 if (r && (shp->prompt = (char *)sfreserve(sfstderr, r, SF_LOCKR))) {
401 memcpy(shp->prompt, name, r);
402 sfwrite(sfstderr, shp->prompt, r - 1);
403 }
404 shp->timeout = 0;
405 save_prompt = shp->nextprompt;
406 shp->nextprompt = 0;
407 readfn = (flags & C_FLAG) ? methods[mindex].fun : 0;
408 r = sh_readline(shp, argv, readfn, fd, flags, len, timeout);
409 shp->nextprompt = save_prompt;
410 if (r == 0) {
411 r = (sfeof(shp->sftable[fd]) || sferror(shp->sftable[fd]));
412 if (r && fd == shp->cpipe[0] && errno != EINTR) sh_pclose(shp->cpipe);
413 }
414 return r;
415 }
416
417 struct timeout {
418 Shell_t *shp;
419 Sfio_t *iop;
420 };
421
422 //
423 // Here for read timeout.
424 //
timedout(void * handle)425 static_fn void timedout(void *handle) {
426 struct timeout *tp = (struct timeout *)handle;
427 sfclrlock(tp->iop);
428 sh_exit(tp->shp, 1);
429 }
430
431 //
432 // This is the code to read a line and to split it into tokens.
433 // <names> is an array of variable names.
434 // <fd> is the file descriptor.
435 // <flags> is union of -A, -r, -s, and contains delimiter if not '\n'.
436 // <timeout> is number of milli-seconds until timeout.
437 //
sh_readline(Shell_t * shp,char ** names,void * readfn,volatile int fd,int flags,ssize_t size,long timeout)438 int sh_readline(Shell_t *shp, char **names, void *readfn, volatile int fd, int flags, ssize_t size,
439 long timeout) {
440 ssize_t c;
441 unsigned char *cp;
442 char *name, *val;
443 Sfio_t *iop;
444 Namfun_t *nfp;
445 unsigned char *cpmax;
446 unsigned char *del;
447 char *ifs = NULL;
448 Namval_t *np = NULL;
449 Namval_t *nq = NULL;
450 char was_escape = 0;
451 char use_stak = 0;
452 volatile char was_write = 0;
453 volatile char was_share = 1;
454 volatile int keytrap;
455 int rel, wrd;
456 long array_index = 0;
457 Timer_t *timeslot = NULL;
458 int delim = '\n';
459 int jmpval = 0;
460 nvflag_t oflags = NV_ASSIGN | NV_VARNAME;
461 bool inquote = false;
462 checkpt_t buff;
463 Edit_t *ep = (struct edit *)shp->gd->ed_context;
464
465 if (!(iop = shp->sftable[fd]) && !(iop = sh_iostream(shp, fd, fd))) return 1;
466
467 memset(&buff, 0, sizeof(buff));
468 sh_stats(STAT_READS);
469 if (names && (name = *names)) {
470 Namval_t *mp = NULL;
471 val = strchr(name, '?');
472 if (val) *val = 0;
473 if (flags & C_FLAG) oflags |= NV_ARRAY;
474 np = nv_open(name, shp->var_tree, oflags);
475 if (np && nv_isarray(np) && (mp = nv_opensub(np))) np = mp;
476 if ((flags & V_FLAG) && shp->gd->ed_context) {
477 ((struct edit *)shp->gd->ed_context)->e_default = np;
478 }
479 if (flags & A_FLAG) {
480 Namarr_t *ap;
481 flags &= ~A_FLAG;
482 array_index = 1;
483 if ((ap = nv_arrayptr(np)) && !ap->fun) ap->nelem++;
484 nv_unset(np);
485 if ((ap = nv_arrayptr(np)) && !ap->fun) ap->nelem--;
486 nv_putsub(np, NULL, 0L, 0);
487 } else if (flags & C_FLAG) {
488 Namval_t *nvenv = np->nvenv;
489 if (strchr(name, '[')) nq = np;
490 delim = -1;
491 nv_unset(np);
492 if (!nv_isattr(np, NV_MINIMAL)) np->nvenv = nvenv;
493 nv_setvtree(np);
494 *(void **)(np->nvfun + 1) = readfn;
495 } else {
496 name = *++names;
497 }
498 if (val) *val = '?';
499 } else {
500 name = 0;
501 if (dtvnext(shp->var_tree) || shp->namespace) {
502 np = nv_open(nv_name(VAR_REPLY), shp->var_tree, 0);
503 } else {
504 np = VAR_REPLY;
505 }
506 }
507 keytrap = ep ? ep->e_keytrap : 0;
508 if (size || (flags >> D_FLAG)) { // delimiter not new-line or fixed size read
509 if ((shp->fdstatus[fd] & IOTTY) && !keytrap) tty_raw(sffileno(iop), 1);
510 if (!(flags & (N_FLAG | NN_FLAG))) {
511 delim = ((unsigned)flags) >> (D_FLAG + 1);
512 ep->e_nttyparm.c_cc[VEOL] = delim;
513 ep->e_nttyparm.c_lflag |= ISIG;
514 tty_set(sffileno(iop), TCSADRAIN, &ep->e_nttyparm);
515 }
516 }
517 bool binary = nv_isattr(np, NV_BINARY) == NV_BINARY;
518 if (!binary && !(flags & (N_FLAG | NN_FLAG))) {
519 Namval_t *mp;
520 // Set up state table based on IFS.
521 ifs = nv_getval(mp = sh_scoped(shp, VAR_IFS));
522 if ((flags & R_FLAG) && shp->ifstable['\\'] == S_ESC) {
523 shp->ifstable['\\'] = 0;
524 } else if (!(flags & R_FLAG) && shp->ifstable['\\'] == 0) {
525 shp->ifstable['\\'] = S_ESC;
526 }
527 if (delim > 0) shp->ifstable[delim] = S_NL;
528 if (delim != '\n') {
529 if (ifs && strchr(ifs, '\n')) {
530 shp->ifstable['\n'] = S_DELIM;
531 } else {
532 shp->ifstable['\n'] = 0;
533 }
534 nv_putval(mp, ifs, NV_RDONLY);
535 }
536 shp->ifstable[0] = S_EOF;
537 if ((flags & SS_FLAG)) {
538 shp->ifstable['"'] = S_QUOTE;
539 shp->ifstable['\r'] = S_ERR;
540 }
541 }
542 sfclrerr(iop);
543 for (nfp = np->nvfun; nfp; nfp = nfp->next) {
544 if (nfp->disc && nfp->disc->readf) {
545 Namval_t *mp;
546 if (nq) {
547 mp = nq;
548 } else {
549 mp = nv_open(name, shp->var_tree, oflags | NV_NOREF);
550 }
551 if ((c = (*nfp->disc->readf)(mp, iop, delim, nfp)) >= 0) return c;
552 }
553 }
554 if (binary && !(flags & (N_FLAG | NN_FLAG))) {
555 flags |= NN_FLAG;
556 size = nv_size(np);
557 }
558 was_write = (sfset(iop, SF_WRITE, 0) & SF_WRITE) != 0;
559 if (sffileno(iop) == 0) was_share = (sfset(iop, SF_SHARE, shp->redir0 != 2) & SF_SHARE) != 0;
560 if (timeout || (shp->fdstatus[fd] & (IOTTY | IONOSEEK))) {
561 sh_pushcontext(shp, &buff, 1);
562 jmpval = sigsetjmp(buff.buff, 0);
563 if (jmpval) goto done;
564 if (timeout) {
565 // WARNING: This assumes that ksh is single-threaded and this block will not be run
566 // concurrently by multiple threads. It can't be a stack var because the address of
567 // the var is passed to `timedout()` after this scope has exited.
568 static struct timeout tmout;
569 tmout.shp = shp;
570 tmout.iop = iop;
571 timeslot = sh_timeradd(timeout, 0, timedout, &tmout);
572 }
573 }
574 if (flags & (N_FLAG | NN_FLAG)) {
575 char buf[256], *cur, *end, *up, *v;
576 char *var = buf;
577
578 // Reserved buffer.
579 if ((c = size) >= sizeof(buf)) {
580 var = malloc(c + 1);
581 end = var + c;
582 } else {
583 end = var + sizeof(buf) - 1;
584 }
585 up = cur = var;
586 if ((sfset(iop, SF_SHARE, 1) & SF_SHARE) && sffileno(iop) != 0) was_share = 1;
587 if (size == 0) {
588 (void)sfreserve(iop, 0, 0);
589 c = 0;
590 } else {
591 ssize_t m;
592 int f;
593 for (;;) {
594 c = size;
595 if (keytrap) {
596 cp = NULL;
597 f = 0;
598 m = 0;
599 while (c-- > 0 && (buf[m] = ed_getchar(ep, 0))) m++;
600 if (m > 0) cp = (unsigned char *)buf;
601 } else {
602 f = 1;
603 cp = sfreserve(iop, c, SF_LOCKR);
604 if (cp) {
605 m = sfvalue(iop);
606 } else if (flags & NN_FLAG) {
607 c = size;
608 m = (cp = sfreserve(iop, c, 0)) ? sfvalue(iop) : 0;
609 f = 0;
610 } else {
611 c = sfvalue(iop);
612 m = (cp = sfreserve(iop, c, SF_LOCKR)) ? sfvalue(iop) : 0;
613 }
614 }
615 if (m > 0 && (flags & N_FLAG) && !binary && (v = memchr(cp, '\n', m))) {
616 *v++ = 0;
617 m = v - (char *)cp;
618 }
619 if ((c = m) > size) c = size;
620 if (c > 0) {
621 if (c > (end - cur)) {
622 ssize_t cx = cur - var, ux = up - var;
623 m = (end - var) + (c - (end - cur));
624 if (var == buf) {
625 v = malloc(m + 1);
626 var = memcpy(v, var, cur - var);
627 } else {
628 var = realloc(var, m + 1);
629 }
630 end = var + m;
631 cur = var + cx;
632 up = var + ux;
633 }
634 // There is a theoretical path to here where `cur` could be NULL. That should
635 // never happen so assert it can't happen. Coverity CID#340037.
636 assert(cur);
637 if (cur != (char *)cp) memcpy(cur, cp, c);
638 if (f) sfread(iop, cp, c);
639 cur += c;
640 if (!binary && mbwide()) {
641 int x;
642 int z;
643
644 *cur = 0;
645 x = z = 0;
646 while (up < cur && (z = mblen(up, MB_CUR_MAX)) > 0) {
647 up += z;
648 x++;
649 }
650 if ((size -= x) > 0 && (up >= cur || z < 0) &&
651 ((flags & NN_FLAG) || z < 0 || m > c)) {
652 continue;
653 }
654 }
655 }
656 if (!binary && mbwide() && (up == var || ((flags & NN_FLAG) && size))) cur = var;
657 *cur = 0;
658 if (c >= size || (flags & N_FLAG) || m == 0) {
659 if (m) sfclrerr(iop);
660 break;
661 }
662 size -= c;
663 }
664 }
665 if (timeslot) timerdel(timeslot);
666 if (binary && !((size = nv_size(np)) && nv_isarray(np) && c != size)) {
667 int optimize = !np->nvfun || !nv_hasdisc(np, &OPTIMIZE_disc);
668 char *cp = FETCH_VT(np->nvalue, cp);
669 if (optimize && (c == size) && cp && !nv_isarray(np)) {
670 memcpy(cp, var, c);
671 } else {
672 Namval_t *mp;
673 if (var == buf) var = memdup(var, c + 1);
674 nv_putval(np, var, NV_RAW);
675 nv_setsize(np, c);
676 if (!nv_isattr(np, NV_IMPORT | NV_EXPORT) && (mp = np->nvenv)) {
677 nv_setsize(mp, c);
678 }
679 }
680 } else {
681 nv_putval(np, var, 0);
682 if (var != buf) free(var);
683 }
684 goto done;
685 } else if ((cp = (unsigned char *)sfgetr(iop, delim, 0))) {
686 c = sfvalue(iop);
687 } else if ((cp = (unsigned char *)sfgetr(iop, delim, -1))) {
688 c = sfvalue(iop) + 1;
689 if (!sferror(iop) && sfgetc(iop) >= 0) {
690 errormsg(SH_DICT, ERROR_exit(1), e_overlimit, "line length");
691 __builtin_unreachable();
692 }
693 }
694 if (timeslot) timerdel(timeslot);
695 if ((flags & S_FLAG) && !shp->gd->hist_ptr) {
696 sh_histinit(shp);
697 if (!shp->gd->hist_ptr) flags &= ~S_FLAG;
698 }
699 if (cp) {
700 cpmax = cp + c;
701 if (*(cpmax - 1) != delim) *(cpmax - 1) = delim;
702 if (flags & S_FLAG) sfwrite(shp->gd->hist_ptr->histfp, (char *)cp, c);
703 c = shp->ifstable[*cp++];
704 } else {
705 c = S_NL;
706 }
707 shp->nextprompt = 2;
708 rel = stktell(shp->stk);
709 // val==0 at the start of a field.
710 val = 0;
711 del = 0;
712 while (1) {
713 switch (c) {
714 case S_MBYTE: {
715 if (val == 0) val = (char *)(cp - 1);
716 if (sh_strchr(ifs, (char *)cp - 1, cpmax - cp + 1) >= 0) {
717 c = mblen((char *)cp - 1, MB_CUR_MAX);
718 if (name) cp[-1] = 0;
719 if (c > 1) cp += (c - 1);
720 c = S_DELIM;
721 } else {
722 c = 0;
723 }
724 continue;
725 }
726 case S_QUOTE: {
727 c = shp->ifstable[*cp++];
728 if (inquote && c == S_QUOTE) {
729 c = -1;
730 } else {
731 inquote = !inquote;
732 }
733 if (val) {
734 sfputr(shp->stk, val, -1);
735 use_stak = 1;
736 *val = 0;
737 }
738 if (c == -1) {
739 sfputc(shp->stk, '"');
740 c = shp->ifstable[*cp++];
741 }
742 continue;
743 }
744 case S_ESC: {
745 // Process escape character.
746 if ((c = shp->ifstable[*cp++]) == S_NL) {
747 was_escape = 1;
748 } else {
749 c = 0;
750 }
751 if (val) {
752 sfputr(shp->stk, val, -1);
753 use_stak = 1;
754 was_escape = 1;
755 *val = 0;
756 }
757 continue;
758 }
759 case S_ERR: {
760 cp++;
761 }
762 // FALLTHRU
763 case S_EOF: {
764 // Check for end of buffer.
765 if (val && *val) {
766 sfputr(shp->stk, val, -1);
767 use_stak = 1;
768 }
769 val = 0;
770 if (cp >= cpmax) {
771 c = S_NL;
772 break;
773 }
774 // Eliminate null bytes.
775 c = shp->ifstable[*cp++];
776 if (!name && val && (c == S_SPACE || c == S_DELIM || c == S_MBYTE)) c = 0;
777 continue;
778 }
779 case S_NL: {
780 if (was_escape) {
781 was_escape = 0;
782 cp = (unsigned char *)sfgetr(iop, delim, 0);
783 if (cp) {
784 c = sfvalue(iop);
785 } else if ((cp = (unsigned char *)sfgetr(iop, delim, -1))) {
786 c = sfvalue(iop) + 1;
787 }
788 if (cp) {
789 if (flags & S_FLAG) sfwrite(shp->gd->hist_ptr->histfp, (char *)cp, c);
790 cpmax = cp + c;
791 c = shp->ifstable[*cp++];
792 val = 0;
793 if (!name && (c == S_SPACE || c == S_DELIM || c == S_MBYTE)) c = 0;
794 continue;
795 }
796 }
797 c = S_NL;
798 break;
799 }
800 case S_SPACE: {
801 // Skip over blanks.
802 while ((c = shp->ifstable[*cp++]) == S_SPACE) {
803 ; // empty loop
804 }
805 if (!val) continue;
806 if (c == S_MBYTE) {
807 if (sh_strchr(ifs, (char *)cp - 1, cpmax - cp + 1) >= 0) {
808 if ((c = mblen((char *)cp - 1, MB_CUR_MAX)) > 1) cp += (c - 1);
809 c = S_DELIM;
810 } else {
811 c = 0;
812 }
813 }
814 if (c != S_DELIM) break;
815 }
816 // FALLTHRU
817 case S_DELIM: {
818 if (!del) del = cp - 1;
819 if (name) {
820 // Skip over trailing blanks.
821 while ((c = shp->ifstable[*cp++]) == S_SPACE) {
822 ; // empty loop
823 }
824 break;
825 }
826 }
827 // FALLTHRU
828 case 0: {
829 if (val == 0 || was_escape) {
830 val = (char *)(cp - 1);
831 was_escape = 0;
832 }
833 // Skip over word characters.
834 wrd = -1;
835 while (1) {
836 while ((c = shp->ifstable[*cp++]) == 0) {
837 if (!wrd) wrd = 1;
838 }
839 if (inquote) {
840 if (c == S_QUOTE) {
841 if (shp->ifstable[*cp] == S_QUOTE) {
842 if (val) {
843 sfwrite(shp->stk, val, cp - (unsigned char *)val);
844 use_stak = 1;
845 }
846 val = (char *)++cp;
847 } else {
848 break;
849 }
850 }
851 if (c && c != S_EOF) {
852 if (c == S_NL) {
853 if (val) {
854 sfwrite(shp->stk, val, cp - (unsigned char *)val);
855 use_stak = 1;
856 }
857 cp = (unsigned char *)sfgetr(iop, delim, 0);
858 if (!cp) cp = (unsigned char *)sfgetr(iop, delim, -1);
859 val = (char *)cp;
860 }
861 continue;
862 }
863 }
864 if (!del && c == S_DELIM) del = cp - 1;
865 if (name || c == S_NL || c == S_ESC || c == S_EOF || c == S_MBYTE) break;
866 if (wrd < 0) wrd = 0;
867 }
868 if (wrd > 0) del = (unsigned char *)"";
869 if (c != S_MBYTE) cp[-1] = 0;
870 continue;
871 }
872 default: { break; }
873 }
874 // Assign value and advance to next variable.
875 if (!val) val = "";
876 if (use_stak) {
877 sfputr(shp->stk, val, 0);
878 val = stkptr(shp->stk, rel);
879 }
880 if (!name && *val) {
881 // Strip off trailing space delimiters.
882 unsigned char *vp = (unsigned char *)val + strlen(val);
883 while (shp->ifstable[*--vp] == S_SPACE) {
884 ; // empty loop
885 }
886 if (vp == del) {
887 if (vp == (unsigned char *)val) {
888 vp--;
889 } else {
890 while (shp->ifstable[*--vp] == S_SPACE) {
891 ; // empty loop
892 }
893 }
894 }
895 vp[1] = 0;
896 }
897 assert(np);
898 if (nv_isattr(np, NV_RDONLY)) {
899 errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
900 jmpval = 1;
901 } else {
902 nv_putval(np, val, 0);
903 }
904 val = 0;
905 del = 0;
906 if (use_stak) {
907 stkseek(shp->stk, rel);
908 use_stak = 0;
909 }
910 if (array_index) {
911 nv_putsub(np, NULL, array_index++, 0);
912 if (c != S_NL) continue;
913 name = *++names;
914 }
915 while (1) {
916 if (sh_isoption(shp, SH_ALLEXPORT) && !strchr(nv_name(np), '.') &&
917 !nv_isattr(np, NV_EXPORT)) {
918 nv_onattr(np, NV_EXPORT);
919 sh_envput(shp, np);
920 }
921 if (name) {
922 nv_close(np);
923 np = nv_open(name, shp->var_tree, NV_VARNAME);
924 name = *++names;
925 } else {
926 np = NULL;
927 }
928 if (c != S_NL) break;
929 if (!np) goto done;
930 if (nv_isattr(np, NV_RDONLY)) {
931 errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
932 jmpval = 1;
933 } else {
934 nv_putval(np, "", 0);
935 }
936 }
937 }
938
939 done:
940
941 if (timeout || (shp->fdstatus[fd] & (IOTTY | IONOSEEK))) sh_popcontext(shp, &buff);
942 if (was_write) sfset(iop, SF_WRITE, 1);
943 if (!was_share) sfset(iop, SF_SHARE, 0);
944 nv_close(np);
945 if ((shp->fdstatus[fd] & IOTTY) && !keytrap) tty_cooked(sffileno(iop));
946 if (flags & S_FLAG) hist_flush(shp->gd->hist_ptr);
947 if (jmpval > 1) siglongjmp(shp->jmplist->buff, jmpval);
948 return jmpval;
949 }
950