8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libshell / common / bltins / read.c
blob6abf7a82f6c43754e2425fe606f01c93ea5c5ba4
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
22 * read [-ACprs] [-d delim] [-u filenum] [-t timeout] [-n n] [-N n] [name...]
24 * David Korn
25 * AT&T Labs
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"
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 */
50 struct read_save
52 char **argv;
53 char *prompt;
54 short fd;
55 short plen;
56 int flags;
57 long timeout;
60 int b_read(int argc,char *argv[], void *extra)
62 Sfdouble_t sec;
63 register char *name;
64 register int r, flags=0, fd=0;
65 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
66 long timeout = 1000*shp->st.tmout;
67 int save_prompt, fixargs=((Shbltin_t*)extra)->invariant;
68 struct read_save *rp;
69 static char default_prompt[3] = {ESC,ESC};
70 rp = (struct read_save*)(((Shbltin_t*)extra)->data);
71 if(argc==0)
73 if(rp)
74 free((void*)rp);
75 return(0);
77 if(rp)
79 flags = rp->flags;
80 timeout = rp->timeout;
81 fd = rp->fd;
82 argv = rp->argv;
83 name = rp->prompt;
84 r = rp->plen;
85 goto bypass;
87 while((r = optget(argv,sh_optread))) switch(r)
89 case 'A':
90 flags |= A_FLAG;
91 break;
92 case 'C':
93 flags |= C_FLAG;
94 break;
95 case 't':
96 sec = sh_strnum(opt_info.arg, (char**)0,1);
97 timeout = sec ? 1000*sec : 1;
98 break;
99 case 'd':
100 if(opt_info.arg && *opt_info.arg!='\n')
102 char *cp = opt_info.arg;
103 flags &= ~((1<<D_FLAG)-1);
104 flags |= (mbchar(cp)<< D_FLAG);
106 break;
107 case 'p':
108 if((fd = shp->cpipe[0])<=0)
109 errormsg(SH_DICT,ERROR_exit(1),e_query);
110 break;
111 case 'n': case 'N':
112 flags &= ((1<<D_FLAG)-1);
113 flags |= (r=='n'?N_FLAG:NN_FLAG);
114 r = (int)opt_info.num;
115 if((unsigned)r > (1<<((8*sizeof(int))-D_FLAG))-1)
116 errormsg(SH_DICT,ERROR_exit(1),e_overlimit,opt_info.name);
117 flags |= (r<< D_FLAG);
118 break;
119 case 'r':
120 flags |= R_FLAG;
121 break;
122 case 's':
123 /* save in history file */
124 flags |= S_FLAG;
125 break;
126 case 'u':
127 fd = (int)opt_info.num;
128 if(sh_inuse(fd))
129 fd = -1;
130 break;
131 case 'v':
132 flags |= V_FLAG;
133 break;
134 case ':':
135 errormsg(SH_DICT,2, "%s", opt_info.arg);
136 break;
137 case '?':
138 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
139 break;
141 argv += opt_info.index;
142 if(error_info.errors)
143 errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
144 if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK)))
145 r = sh_iocheckfd(shp,fd);
146 if(fd<0 || !(r&IOREAD))
147 errormsg(SH_DICT,ERROR_system(1),e_file+4);
148 /* look for prompt */
149 if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
150 r = strlen(name++);
151 else
152 r = 0;
153 if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0)))
155 ((Shbltin_t*)extra)->data = (void*)rp;
156 rp->fd = fd;
157 rp->flags = flags;
158 rp->timeout = timeout;
159 rp->argv = argv;
160 rp->prompt = name;
161 rp->plen = r;
163 bypass:
164 shp->prompt = default_prompt;
165 if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR)))
167 memcpy(shp->prompt,name,r);
168 sfwrite(sfstderr,shp->prompt,r-1);
170 shp->timeout = 0;
171 save_prompt = shp->nextprompt;
172 shp->nextprompt = 0;
173 r=sh_readline(shp,argv,fd,flags,timeout);
174 shp->nextprompt = save_prompt;
175 if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd]))))
177 if(fd == shp->cpipe[0])
179 sh_pclose(shp->cpipe);
180 return(1);
183 sfclrerr(shp->sftable[fd]);
184 return(r);
188 * here for read timeout
190 static void timedout(void *handle)
192 sfclrlock((Sfio_t*)handle);
193 sh_exit(1);
197 * This is the code to read a line and to split it into tokens
198 * <names> is an array of variable names
199 * <fd> is the file descriptor
200 * <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
201 * <timeout> is number of milli-seconds until timeout
204 int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout)
206 register ssize_t c;
207 register unsigned char *cp;
208 register Namval_t *np;
209 register char *name, *val;
210 register Sfio_t *iop;
211 Namfun_t *nfp;
212 char *ifs;
213 unsigned char *cpmax;
214 unsigned char *del;
215 char was_escape = 0;
216 char use_stak = 0;
217 volatile char was_write = 0;
218 volatile char was_share = 1;
219 int rel, wrd;
220 long array_index = 0;
221 void *timeslot=0;
222 int delim = '\n';
223 int jmpval=0;
224 ssize_t size = 0;
225 int binary;
226 struct checkpt buff;
227 if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd)))
228 return(1);
229 sh_stats(STAT_READS);
230 if(names && (name = *names))
232 Namval_t *mp;
233 if(val= strchr(name,'?'))
234 *val = 0;
235 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
236 if(np && nv_isarray(np) && (mp=nv_opensub(np)))
237 np = mp;
238 if((flags&V_FLAG) && shp->ed_context)
239 ((struct edit*)shp->ed_context)->e_default = np;
240 if(flags&A_FLAG)
242 flags &= ~A_FLAG;
243 array_index = 1;
244 nv_unset(np);
245 nv_putsub(np,NIL(char*),0L);
247 else if(flags&C_FLAG)
249 delim = -1;
250 nv_unset(np);
251 nv_setvtree(np);
253 else
254 name = *++names;
255 if(val)
256 *val = '?';
258 else
260 name = 0;
261 if(dtvnext(shp->var_tree) || shp->namespace)
262 np = nv_open(nv_name(REPLYNOD),shp->var_tree,0);
263 else
264 np = REPLYNOD;
266 if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */
268 if(flags&(N_FLAG|NN_FLAG))
269 size = ((unsigned)flags)>>D_FLAG;
270 else
271 delim = ((unsigned)flags)>>D_FLAG;
272 if(shp->fdstatus[fd]&IOTTY)
273 tty_raw(fd,1);
275 binary = nv_isattr(np,NV_BINARY);
276 if(!binary && !(flags&(N_FLAG|NN_FLAG)))
278 Namval_t *mp;
279 /* set up state table based on IFS */
280 ifs = nv_getval(mp=sh_scoped(shp,IFSNOD));
281 if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC)
282 shp->ifstable['\\'] = 0;
283 else if(!(flags&R_FLAG) && shp->ifstable['\\']==0)
284 shp->ifstable['\\'] = S_ESC;
285 shp->ifstable[delim] = S_NL;
286 if(delim!='\n')
288 shp->ifstable['\n'] = 0;
289 nv_putval(mp, ifs, NV_RDONLY);
291 shp->ifstable[0] = S_EOF;
293 sfclrerr(iop);
294 for(nfp=np->nvfun; nfp; nfp = nfp->next)
296 if(nfp->disc && nfp->disc->readf)
298 if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0)
299 return(c);
302 if(binary && !(flags&(N_FLAG|NN_FLAG)))
304 flags |= NN_FLAG;
305 size = nv_size(np);
307 was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0;
308 if(fd==0)
309 was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0;
310 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
312 sh_pushcontext(&buff,1);
313 jmpval = sigsetjmp(buff.buff,0);
314 if(jmpval)
315 goto done;
316 if(timeout)
317 timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop);
319 if(flags&(N_FLAG|NN_FLAG))
321 char buf[256],*var=buf,*cur,*end,*up,*v;
322 /* reserved buffer */
323 if((c=size)>=sizeof(buf))
325 if(!(var = (char*)malloc(c+1)))
326 sh_exit(1);
327 end = var + c;
329 else
330 end = var + sizeof(buf) - 1;
331 up = cur = var;
332 if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0)
333 was_share = 1;
334 if(size==0)
336 cp = sfreserve(iop,0,0);
337 c = 0;
339 else
341 ssize_t m;
342 int f;
343 for (;;)
345 c = size;
346 cp = sfreserve(iop,c,SF_LOCKR);
347 f = 1;
348 if(cp)
349 m = sfvalue(iop);
350 else if(flags&NN_FLAG)
352 c = size;
353 m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0;
354 f = 0;
356 else
358 c = sfvalue(iop);
359 m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0;
361 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m)))
363 *v++ = 0;
364 m = v-(char*)cp;
366 if((c=m)>size)
367 c = size;
368 if(c>0)
370 if(c > (end-cur))
372 ssize_t cx = cur - var, ux = up - var;
373 m = (end - var) + (c - (end - cur));
374 if (var == buf)
376 v = (char*)malloc(m+1);
377 var = memcpy(v, var, cur - var);
379 else
380 var = newof(var, char, m, 1);
381 end = var + m;
382 cur = var + cx;
383 up = var + ux;
385 memcpy((void*)cur,cp,c);
386 if(f)
387 sfread(iop,cp,c);
388 cur += c;
389 #if SHOPT_MULTIBYTE
390 if(!binary && mbwide())
392 int x;
393 int z;
395 mbinit();
396 *cur = 0;
397 x = z = 0;
398 while (up < cur && (z = mbsize(up)) > 0)
400 up += z;
401 x++;
403 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c))
404 continue;
406 #endif
408 #if SHOPT_MULTIBYTE
409 if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size))
410 cur = var;
411 #endif
412 *cur = 0;
413 if(c>=size || (flags&N_FLAG) || m==0)
415 if(m)
416 sfclrerr(iop);
417 break;
419 size -= c;
422 if(timeslot)
423 timerdel(timeslot);
424 if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size))
426 if((c==size) && np->nvalue.cp && !nv_isarray(np))
427 memcpy((char*)np->nvalue.cp,var,c);
428 else
430 Namval_t *mp;
431 if(var==buf)
432 var = memdup(var,c+1);
433 nv_putval(np,var,NV_RAW);
434 nv_setsize(np,c);
435 if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv))
436 nv_setsize(mp,c);
439 else
441 nv_putval(np,var,0);
442 if(var!=buf)
443 free((void*)var);
445 goto done;
447 else if(cp = (unsigned char*)sfgetr(iop,delim,0))
448 c = sfvalue(iop);
449 else if(cp = (unsigned char*)sfgetr(iop,delim,-1))
450 c = sfvalue(iop)+1;
451 if(timeslot)
452 timerdel(timeslot);
453 if((flags&S_FLAG) && !shp->hist_ptr)
455 sh_histinit((void*)shp);
456 if(!shp->hist_ptr)
457 flags &= ~S_FLAG;
459 if(cp)
461 cpmax = cp + c;
462 #if SHOPT_CRNL
463 if(delim=='\n' && c>=2 && cpmax[-2]=='\r')
464 cpmax--;
465 #endif /* SHOPT_CRNL */
466 if(*(cpmax-1) != delim)
467 *(cpmax-1) = delim;
468 if(flags&S_FLAG)
469 sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
470 c = shp->ifstable[*cp++];
471 #if !SHOPT_MULTIBYTE
472 if(!name && (flags&R_FLAG)) /* special case single argument */
474 /* skip over leading blanks */
475 while(c==S_SPACE)
476 c = shp->ifstable[*cp++];
477 /* strip trailing delimiters */
478 if(cpmax[-1] == '\n')
479 cpmax--;
480 if(cpmax>cp)
482 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
483 cpmax[1] = 0;
485 else
486 *cpmax =0;
487 if(nv_isattr(np, NV_RDONLY))
489 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
490 jmpval = 1;
492 else
493 nv_putval(np,(char*)cp-1,0);
494 goto done;
496 #endif /* !SHOPT_MULTIBYTE */
498 else
499 c = S_NL;
500 shp->nextprompt = 2;
501 rel= staktell();
502 /* val==0 at the start of a field */
503 val = 0;
504 del = 0;
505 while(1)
507 switch(c)
509 #if SHOPT_MULTIBYTE
510 case S_MBYTE:
511 if(val==0)
512 val = (char*)(cp-1);
513 if(sh_strchr(ifs,(char*)cp-1)>=0)
515 c = mbsize((char*)cp-1);
516 if(name)
517 cp[-1] = 0;
518 if(c>1)
519 cp += (c-1);
520 c = S_DELIM;
522 else
523 c = 0;
524 continue;
525 #endif /*SHOPT_MULTIBYTE */
526 case S_ESC:
527 /* process escape character */
528 if((c = shp->ifstable[*cp++]) == S_NL)
529 was_escape = 1;
530 else
531 c = 0;
532 if(val)
534 stakputs(val);
535 use_stak = 1;
536 was_escape = 1;
537 *val = 0;
539 continue;
541 case S_EOF:
542 /* check for end of buffer */
543 if(val && *val)
545 stakputs(val);
546 use_stak = 1;
548 val = 0;
549 if(cp>=cpmax)
551 c = S_NL;
552 break;
554 /* eliminate null bytes */
555 c = shp->ifstable[*cp++];
556 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
557 c = 0;
558 continue;
559 case S_NL:
560 if(was_escape)
562 was_escape = 0;
563 if(cp = (unsigned char*)sfgetr(iop,delim,0))
564 c = sfvalue(iop);
565 else if(cp=(unsigned char*)sfgetr(iop,delim,-1))
566 c = sfvalue(iop)+1;
567 if(cp)
569 if(flags&S_FLAG)
570 sfwrite(shp->hist_ptr->histfp,(char*)cp,c);
571 cpmax = cp + c;
572 c = shp->ifstable[*cp++];
573 val=0;
574 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
575 c = 0;
576 continue;
579 c = S_NL;
580 break;
582 case S_SPACE:
583 /* skip over blanks */
584 while((c=shp->ifstable[*cp++])==S_SPACE);
585 if(!val)
586 continue;
587 #if SHOPT_MULTIBYTE
588 if(c==S_MBYTE)
590 if(sh_strchr(ifs,(char*)cp-1)>=0)
592 if((c = mbsize((char*)cp-1))>1)
593 cp += (c-1);
594 c = S_DELIM;
596 else
597 c = 0;
599 #endif /* SHOPT_MULTIBYTE */
600 if(c!=S_DELIM)
601 break;
602 /* FALL THRU */
604 case S_DELIM:
605 if(!del)
606 del = cp - 1;
607 if(name)
609 /* skip over trailing blanks */
610 while((c=shp->ifstable[*cp++])==S_SPACE);
611 break;
613 /* FALL THRU */
615 case 0:
616 if(val==0 || was_escape)
618 val = (char*)(cp-1);
619 was_escape = 0;
621 /* skip over word characters */
622 wrd = -1;
623 while(1)
625 while((c=shp->ifstable[*cp++])==0)
626 if(!wrd)
627 wrd = 1;
628 if(!del&&c==S_DELIM)
629 del = cp - 1;
630 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
631 break;
632 if(wrd<0)
633 wrd = 0;
635 if(wrd>0)
636 del = (unsigned char*)"";
637 if(c!=S_MBYTE)
638 cp[-1] = 0;
639 continue;
641 /* assign value and advance to next variable */
642 if(!val)
643 val = "";
644 if(use_stak)
646 stakputs(val);
647 stakputc(0);
648 val = stakptr(rel);
650 if(!name && *val)
652 /* strip off trailing space delimiters */
653 register unsigned char *vp = (unsigned char*)val + strlen(val);
654 while(shp->ifstable[*--vp]==S_SPACE);
655 if(vp==del)
657 if(vp==(unsigned char*)val)
658 vp--;
659 else
660 while(shp->ifstable[*--vp]==S_SPACE);
662 vp[1] = 0;
664 if(nv_isattr(np, NV_RDONLY))
666 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
667 jmpval = 1;
669 else
670 nv_putval(np,val,0);
671 val = 0;
672 del = 0;
673 if(use_stak)
675 stakseek(rel);
676 use_stak = 0;
678 if(array_index)
680 nv_putsub(np, NIL(char*), array_index++);
681 if(c!=S_NL)
682 continue;
683 name = *++names;
685 while(1)
687 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT))
689 nv_onattr(np,NV_EXPORT);
690 sh_envput(sh.env,np);
692 if(name)
694 nv_close(np);
695 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
696 name = *++names;
698 else
699 np = 0;
700 if(c!=S_NL)
701 break;
702 if(!np)
703 goto done;
704 if(nv_isattr(np, NV_RDONLY))
706 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np));
707 jmpval = 1;
709 else
710 nv_putval(np, "", 0);
713 done:
714 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK)))
715 sh_popcontext(&buff);
716 if(was_write)
717 sfset(iop,SF_WRITE,1);
718 if(!was_share)
719 sfset(iop,SF_SHARE,0);
720 nv_close(np);
721 if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY))
722 tty_cooked(fd);
723 if(flags&S_FLAG)
724 hist_flush(shp->hist_ptr);
725 if(jmpval > 1)
726 siglongjmp(*shp->jmplist,jmpval);
727 return(jmpval);