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