1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1982-2011 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 21/* 22 * read [-ACprs] [-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 50struct read_save 51{ 52 char **argv; 53 char *prompt; 54 short fd; 55 short plen; 56 int flags; 57 long timeout; 58}; 59 60int b_read(int argc,char *argv[], void *extra) 61{ 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) 72 { 73 if(rp) 74 free((void*)rp); 75 return(0); 76 } 77 if(rp) 78 { 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; 86 } 87 while((r = optget(argv,sh_optread))) switch(r) 88 { 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') 101 { 102 char *cp = opt_info.arg; 103 flags &= ~((1<<D_FLAG)-1); 104 flags |= (mbchar(cp)<< D_FLAG); 105 } 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(shp,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; 140 } 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))) 154 { 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; 162 } 163bypass: 164 shp->prompt = default_prompt; 165 if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR))) 166 { 167 memcpy(shp->prompt,name,r); 168 sfwrite(sfstderr,shp->prompt,r-1); 169 } 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])))) 176 { 177 if(fd == shp->cpipe[0]) 178 { 179 sh_pclose(shp->cpipe); 180 return(1); 181 } 182 } 183 sfclrerr(shp->sftable[fd]); 184 return(r); 185} 186 187/* 188 * here for read timeout 189 */ 190static void timedout(void *handle) 191{ 192 sfclrlock((Sfio_t*)handle); 193 sh_exit(1); 194} 195 196/* 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 202 */ 203 204int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout) 205{ 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 int oflags=NV_NOASSIGN|NV_VARNAME; 227 struct checkpt buff; 228 if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd))) 229 return(1); 230 sh_stats(STAT_READS); 231 if(names && (name = *names)) 232 { 233 Namval_t *mp; 234 if(val= strchr(name,'?')) 235 *val = 0; 236 if(flags&C_FLAG) 237 oflags |= NV_ARRAY; 238 np = nv_open(name,shp->var_tree,oflags); 239 if(np && nv_isarray(np) && (mp=nv_opensub(np))) 240 np = mp; 241 if((flags&V_FLAG) && shp->gd->ed_context) 242 ((struct edit*)shp->gd->ed_context)->e_default = np; 243 if(flags&A_FLAG) 244 { 245 flags &= ~A_FLAG; 246 array_index = 1; 247 nv_unset(np); 248 nv_putsub(np,NIL(char*),0L); 249 } 250 else if(flags&C_FLAG) 251 { 252 char *sp = np->nvenv; 253 delim = -1; 254 nv_unset(np); 255 if(!nv_isattr(np,NV_MINIMAL)) 256 np->nvenv = sp; 257 nv_setvtree(np); 258 } 259 else 260 name = *++names; 261 if(val) 262 *val = '?'; 263 } 264 else 265 { 266 name = 0; 267 if(dtvnext(shp->var_tree) || shp->namespace) 268 np = nv_open(nv_name(REPLYNOD),shp->var_tree,0); 269 else 270 np = REPLYNOD; 271 } 272 if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */ 273 { 274 if(flags&(N_FLAG|NN_FLAG)) 275 size = ((unsigned)flags)>>D_FLAG; 276 else 277 delim = ((unsigned)flags)>>D_FLAG; 278 if(shp->fdstatus[fd]&IOTTY) 279 tty_raw(fd,1); 280 } 281 binary = nv_isattr(np,NV_BINARY); 282 if(!binary && !(flags&(N_FLAG|NN_FLAG))) 283 { 284 Namval_t *mp; 285 /* set up state table based on IFS */ 286 ifs = nv_getval(mp=sh_scoped(shp,IFSNOD)); 287 if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC) 288 shp->ifstable['\\'] = 0; 289 else if(!(flags&R_FLAG) && shp->ifstable['\\']==0) 290 shp->ifstable['\\'] = S_ESC; 291 if(delim>0) 292 shp->ifstable[delim] = S_NL; 293 if(delim!='\n') 294 { 295 shp->ifstable['\n'] = 0; 296 nv_putval(mp, ifs, NV_RDONLY); 297 } 298 shp->ifstable[0] = S_EOF; 299 } 300 sfclrerr(iop); 301 for(nfp=np->nvfun; nfp; nfp = nfp->next) 302 { 303 if(nfp->disc && nfp->disc->readf) 304 { 305 if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0) 306 return(c); 307 } 308 } 309 if(binary && !(flags&(N_FLAG|NN_FLAG))) 310 { 311 flags |= NN_FLAG; 312 size = nv_size(np); 313 } 314 was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; 315 if(fd==0) 316 was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0; 317 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 318 { 319 sh_pushcontext(shp,&buff,1); 320 jmpval = sigsetjmp(buff.buff,0); 321 if(jmpval) 322 goto done; 323 if(timeout) 324 timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop); 325 } 326 if(flags&(N_FLAG|NN_FLAG)) 327 { 328 char buf[256],*var=buf,*cur,*end,*up,*v; 329 /* reserved buffer */ 330 if((c=size)>=sizeof(buf)) 331 { 332 if(!(var = (char*)malloc(c+1))) 333 sh_exit(1); 334 end = var + c; 335 } 336 else 337 end = var + sizeof(buf) - 1; 338 up = cur = var; 339 if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0) 340 was_share = 1; 341 if(size==0) 342 { 343 cp = sfreserve(iop,0,0); 344 c = 0; 345 } 346 else 347 { 348 ssize_t m; 349 int f; 350 for (;;) 351 { 352 c = size; 353 cp = sfreserve(iop,c,SF_LOCKR); 354 f = 1; 355 if(cp) 356 m = sfvalue(iop); 357 else if(flags&NN_FLAG) 358 { 359 c = size; 360 m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0; 361 f = 0; 362 } 363 else 364 { 365 c = sfvalue(iop); 366 m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0; 367 } 368 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) 369 { 370 *v++ = 0; 371 m = v-(char*)cp; 372 } 373 if((c=m)>size) 374 c = size; 375 if(c>0) 376 { 377 if(c > (end-cur)) 378 { 379 ssize_t cx = cur - var, ux = up - var; 380 m = (end - var) + (c - (end - cur)); 381 if (var == buf) 382 { 383 v = (char*)malloc(m+1); 384 var = memcpy(v, var, cur - var); 385 } 386 else 387 var = newof(var, char, m, 1); 388 end = var + m; 389 cur = var + cx; 390 up = var + ux; 391 } 392 memcpy((void*)cur,cp,c); 393 if(f) 394 sfread(iop,cp,c); 395 cur += c; 396#if SHOPT_MULTIBYTE 397 if(!binary && mbwide()) 398 { 399 int x; 400 int z; 401 402 mbinit(); 403 *cur = 0; 404 x = z = 0; 405 while (up < cur && (z = mbsize(up)) > 0) 406 { 407 up += z; 408 x++; 409 } 410 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c)) 411 continue; 412 } 413#endif 414 } 415#if SHOPT_MULTIBYTE 416 if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size)) 417 cur = var; 418#endif 419 *cur = 0; 420 if(c>=size || (flags&N_FLAG) || m==0) 421 { 422 if(m) 423 sfclrerr(iop); 424 break; 425 } 426 size -= c; 427 } 428 } 429 if(timeslot) 430 timerdel(timeslot); 431 if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) 432 { 433 if((c==size) && np->nvalue.cp && !nv_isarray(np)) 434 memcpy((char*)np->nvalue.cp,var,c); 435 else 436 { 437 Namval_t *mp; 438 if(var==buf) 439 var = memdup(var,c+1); 440 nv_putval(np,var,NV_RAW); 441 nv_setsize(np,c); 442 if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv)) 443 nv_setsize(mp,c); 444 } 445 } 446 else 447 { 448 nv_putval(np,var,0); 449 if(var!=buf) 450 free((void*)var); 451 } 452 goto done; 453 } 454 else if(cp = (unsigned char*)sfgetr(iop,delim,0)) 455 c = sfvalue(iop); 456 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 457 c = sfvalue(iop)+1; 458 if(timeslot) 459 timerdel(timeslot); 460 if((flags&S_FLAG) && !shp->gd->hist_ptr) 461 { 462 sh_histinit((void*)shp); 463 if(!shp->gd->hist_ptr) 464 flags &= ~S_FLAG; 465 } 466 if(cp) 467 { 468 cpmax = cp + c; 469#if SHOPT_CRNL 470 if(delim=='\n' && c>=2 && cpmax[-2]=='\r') 471 cpmax--; 472#endif /* SHOPT_CRNL */ 473 if(*(cpmax-1) != delim) 474 *(cpmax-1) = delim; 475 if(flags&S_FLAG) 476 sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c); 477 c = shp->ifstable[*cp++]; 478#if !SHOPT_MULTIBYTE 479 if(!name && (flags&R_FLAG)) /* special case single argument */ 480 { 481 /* skip over leading blanks */ 482 while(c==S_SPACE) 483 c = shp->ifstable[*cp++]; 484 /* strip trailing delimiters */ 485 if(cpmax[-1] == '\n') 486 cpmax--; 487 if(cpmax>cp) 488 { 489 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); 490 cpmax[1] = 0; 491 } 492 else 493 *cpmax =0; 494 if(nv_isattr(np, NV_RDONLY)) 495 { 496 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 497 jmpval = 1; 498 } 499 else 500 nv_putval(np,(char*)cp-1,0); 501 goto done; 502 } 503#endif /* !SHOPT_MULTIBYTE */ 504 } 505 else 506 c = S_NL; 507 shp->nextprompt = 2; 508 rel= staktell(); 509 /* val==0 at the start of a field */ 510 val = 0; 511 del = 0; 512 while(1) 513 { 514 switch(c) 515 { 516#if SHOPT_MULTIBYTE 517 case S_MBYTE: 518 if(val==0) 519 val = (char*)(cp-1); 520 if(sh_strchr(ifs,(char*)cp-1)>=0) 521 { 522 c = mbsize((char*)cp-1); 523 if(name) 524 cp[-1] = 0; 525 if(c>1) 526 cp += (c-1); 527 c = S_DELIM; 528 } 529 else 530 c = 0; 531 continue; 532#endif /*SHOPT_MULTIBYTE */ 533 case S_ESC: 534 /* process escape character */ 535 if((c = shp->ifstable[*cp++]) == S_NL) 536 was_escape = 1; 537 else 538 c = 0; 539 if(val) 540 { 541 stakputs(val); 542 use_stak = 1; 543 was_escape = 1; 544 *val = 0; 545 } 546 continue; 547 548 case S_EOF: 549 /* check for end of buffer */ 550 if(val && *val) 551 { 552 stakputs(val); 553 use_stak = 1; 554 } 555 val = 0; 556 if(cp>=cpmax) 557 { 558 c = S_NL; 559 break; 560 } 561 /* eliminate null bytes */ 562 c = shp->ifstable[*cp++]; 563 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) 564 c = 0; 565 continue; 566 case S_NL: 567 if(was_escape) 568 { 569 was_escape = 0; 570 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 571 c = sfvalue(iop); 572 else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) 573 c = sfvalue(iop)+1; 574 if(cp) 575 { 576 if(flags&S_FLAG) 577 sfwrite(shp->gd->hist_ptr->histfp,(char*)cp,c); 578 cpmax = cp + c; 579 c = shp->ifstable[*cp++]; 580 val=0; 581 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) 582 c = 0; 583 continue; 584 } 585 } 586 c = S_NL; 587 break; 588 589 case S_SPACE: 590 /* skip over blanks */ 591 while((c=shp->ifstable[*cp++])==S_SPACE); 592 if(!val) 593 continue; 594#if SHOPT_MULTIBYTE 595 if(c==S_MBYTE) 596 { 597 if(sh_strchr(ifs,(char*)cp-1)>=0) 598 { 599 if((c = mbsize((char*)cp-1))>1) 600 cp += (c-1); 601 c = S_DELIM; 602 } 603 else 604 c = 0; 605 } 606#endif /* SHOPT_MULTIBYTE */ 607 if(c!=S_DELIM) 608 break; 609 /* FALL THRU */ 610 611 case S_DELIM: 612 if(!del) 613 del = cp - 1; 614 if(name) 615 { 616 /* skip over trailing blanks */ 617 while((c=shp->ifstable[*cp++])==S_SPACE); 618 break; 619 } 620 /* FALL THRU */ 621 622 case 0: 623 if(val==0 || was_escape) 624 { 625 val = (char*)(cp-1); 626 was_escape = 0; 627 } 628 /* skip over word characters */ 629 wrd = -1; 630 while(1) 631 { 632 while((c=shp->ifstable[*cp++])==0) 633 if(!wrd) 634 wrd = 1; 635 if(!del&&c==S_DELIM) 636 del = cp - 1; 637 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) 638 break; 639 if(wrd<0) 640 wrd = 0; 641 } 642 if(wrd>0) 643 del = (unsigned char*)""; 644 if(c!=S_MBYTE) 645 cp[-1] = 0; 646 continue; 647 } 648 /* assign value and advance to next variable */ 649 if(!val) 650 val = ""; 651 if(use_stak) 652 { 653 stakputs(val); 654 stakputc(0); 655 val = stakptr(rel); 656 } 657 if(!name && *val) 658 { 659 /* strip off trailing space delimiters */ 660 register unsigned char *vp = (unsigned char*)val + strlen(val); 661 while(shp->ifstable[*--vp]==S_SPACE); 662 if(vp==del) 663 { 664 if(vp==(unsigned char*)val) 665 vp--; 666 else 667 while(shp->ifstable[*--vp]==S_SPACE); 668 } 669 vp[1] = 0; 670 } 671 if(nv_isattr(np, NV_RDONLY)) 672 { 673 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 674 jmpval = 1; 675 } 676 else 677 nv_putval(np,val,0); 678 val = 0; 679 del = 0; 680 if(use_stak) 681 { 682 stakseek(rel); 683 use_stak = 0; 684 } 685 if(array_index) 686 { 687 nv_putsub(np, NIL(char*), array_index++); 688 if(c!=S_NL) 689 continue; 690 name = *++names; 691 } 692 while(1) 693 { 694 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 695 { 696 nv_onattr(np,NV_EXPORT); 697 sh_envput(shp->env,np); 698 } 699 if(name) 700 { 701 nv_close(np); 702 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 703 name = *++names; 704 } 705 else 706 np = 0; 707 if(c!=S_NL) 708 break; 709 if(!np) 710 goto done; 711 if(nv_isattr(np, NV_RDONLY)) 712 { 713 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 714 jmpval = 1; 715 } 716 else 717 nv_putval(np, "", 0); 718 } 719 } 720done: 721 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 722 sh_popcontext(shp,&buff); 723 if(was_write) 724 sfset(iop,SF_WRITE,1); 725 if(!was_share) 726 sfset(iop,SF_SHARE,0); 727 nv_close(np); 728 if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY)) 729 tty_cooked(fd); 730 if(flags&S_FLAG) 731 hist_flush(shp->gd->hist_ptr); 732 if(jmpval > 1) 733 siglongjmp(*shp->jmplist,jmpval); 734 return(jmpval); 735} 736 737