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