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 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 50 struct read_save 51 { 52 char **argv; 53 char *prompt; 54 short fd; 55 short plen; 56 int flags; 57 long timeout; 58 }; 59 60 int 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(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 } 163 bypass: 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 */ 190 static 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 204 int 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 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)) 231 { 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) 241 { 242 flags &= ~A_FLAG; 243 array_index = 1; 244 nv_unset(np); 245 nv_putsub(np,NIL(char*),0L); 246 } 247 else if(flags&C_FLAG) 248 { 249 delim = -1; 250 nv_unset(np); 251 nv_setvtree(np); 252 } 253 else 254 name = *++names; 255 if(val) 256 *val = '?'; 257 } 258 else 259 { 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; 265 } 266 if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */ 267 { 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); 274 } 275 binary = nv_isattr(np,NV_BINARY); 276 if(!binary && !(flags&(N_FLAG|NN_FLAG))) 277 { 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') 287 { 288 shp->ifstable['\n'] = 0; 289 nv_putval(mp, ifs, NV_RDONLY); 290 } 291 shp->ifstable[0] = S_EOF; 292 } 293 sfclrerr(iop); 294 for(nfp=np->nvfun; nfp; nfp = nfp->next) 295 { 296 if(nfp->disc && nfp->disc->readf) 297 { 298 if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0) 299 return(c); 300 } 301 } 302 if(binary && !(flags&(N_FLAG|NN_FLAG))) 303 { 304 flags |= NN_FLAG; 305 size = nv_size(np); 306 } 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))) 311 { 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); 318 } 319 if(flags&(N_FLAG|NN_FLAG)) 320 { 321 char buf[256],*var=buf,*cur,*end,*up,*v; 322 /* reserved buffer */ 323 if((c=size)>=sizeof(buf)) 324 { 325 if(!(var = (char*)malloc(c+1))) 326 sh_exit(1); 327 end = var + c; 328 } 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) 335 { 336 cp = sfreserve(iop,0,0); 337 c = 0; 338 } 339 else 340 { 341 ssize_t m; 342 int f; 343 for (;;) 344 { 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) 351 { 352 c = size; 353 m = (cp = sfreserve(iop,c,0)) ? sfvalue(iop) : 0; 354 f = 0; 355 } 356 else 357 { 358 c = sfvalue(iop); 359 m = (cp = sfreserve(iop,c,SF_LOCKR)) ? sfvalue(iop) : 0; 360 } 361 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) 362 { 363 *v++ = 0; 364 m = v-(char*)cp; 365 } 366 if((c=m)>size) 367 c = size; 368 if(c>0) 369 { 370 if(c > (end-cur)) 371 { 372 ssize_t cx = cur - var, ux = up - var; 373 m = (end - var) + (c - (end - cur)); 374 if (var == buf) 375 { 376 v = (char*)malloc(m+1); 377 var = memcpy(v, var, cur - var); 378 } 379 else 380 var = newof(var, char, m, 1); 381 end = var + m; 382 cur = var + cx; 383 up = var + ux; 384 } 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()) 391 { 392 int x; 393 int z; 394 395 mbinit(); 396 *cur = 0; 397 x = z = 0; 398 while (up < cur && (z = mbsize(up)) > 0) 399 { 400 up += z; 401 x++; 402 } 403 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c)) 404 continue; 405 } 406 #endif 407 } 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) 414 { 415 if(m) 416 sfclrerr(iop); 417 break; 418 } 419 size -= c; 420 } 421 } 422 if(timeslot) 423 timerdel(timeslot); 424 if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) 425 { 426 if((c==size) && np->nvalue.cp && !nv_isarray(np)) 427 memcpy((char*)np->nvalue.cp,var,c); 428 else 429 { 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); 437 } 438 } 439 else 440 { 441 nv_putval(np,var,0); 442 if(var!=buf) 443 free((void*)var); 444 } 445 goto done; 446 } 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) 454 { 455 sh_histinit((void*)shp); 456 if(!shp->hist_ptr) 457 flags &= ~S_FLAG; 458 } 459 if(cp) 460 { 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 */ 473 { 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) 481 { 482 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); 483 cpmax[1] = 0; 484 } 485 else 486 *cpmax =0; 487 if(nv_isattr(np, NV_RDONLY)) 488 { 489 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 490 jmpval = 1; 491 } 492 else 493 nv_putval(np,(char*)cp-1,0); 494 goto done; 495 } 496 #endif /* !SHOPT_MULTIBYTE */ 497 } 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) 506 { 507 switch(c) 508 { 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) 514 { 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; 521 } 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) 533 { 534 stakputs(val); 535 use_stak = 1; 536 was_escape = 1; 537 *val = 0; 538 } 539 continue; 540 541 case S_EOF: 542 /* check for end of buffer */ 543 if(val && *val) 544 { 545 stakputs(val); 546 use_stak = 1; 547 } 548 val = 0; 549 if(cp>=cpmax) 550 { 551 c = S_NL; 552 break; 553 } 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) 561 { 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) 568 { 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; 577 } 578 } 579 c = S_NL; 580 break; 581 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) 589 { 590 if(sh_strchr(ifs,(char*)cp-1)>=0) 591 { 592 if((c = mbsize((char*)cp-1))>1) 593 cp += (c-1); 594 c = S_DELIM; 595 } 596 else 597 c = 0; 598 } 599 #endif /* SHOPT_MULTIBYTE */ 600 if(c!=S_DELIM) 601 break; 602 /* FALL THRU */ 603 604 case S_DELIM: 605 if(!del) 606 del = cp - 1; 607 if(name) 608 { 609 /* skip over trailing blanks */ 610 while((c=shp->ifstable[*cp++])==S_SPACE); 611 break; 612 } 613 /* FALL THRU */ 614 615 case 0: 616 if(val==0 || was_escape) 617 { 618 val = (char*)(cp-1); 619 was_escape = 0; 620 } 621 /* skip over word characters */ 622 wrd = -1; 623 while(1) 624 { 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; 634 } 635 if(wrd>0) 636 del = (unsigned char*)""; 637 if(c!=S_MBYTE) 638 cp[-1] = 0; 639 continue; 640 } 641 /* assign value and advance to next variable */ 642 if(!val) 643 val = ""; 644 if(use_stak) 645 { 646 stakputs(val); 647 stakputc(0); 648 val = stakptr(rel); 649 } 650 if(!name && *val) 651 { 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) 656 { 657 if(vp==(unsigned char*)val) 658 vp--; 659 else 660 while(shp->ifstable[*--vp]==S_SPACE); 661 } 662 vp[1] = 0; 663 } 664 if(nv_isattr(np, NV_RDONLY)) 665 { 666 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 667 jmpval = 1; 668 } 669 else 670 nv_putval(np,val,0); 671 val = 0; 672 del = 0; 673 if(use_stak) 674 { 675 stakseek(rel); 676 use_stak = 0; 677 } 678 if(array_index) 679 { 680 nv_putsub(np, NIL(char*), array_index++); 681 if(c!=S_NL) 682 continue; 683 name = *++names; 684 } 685 while(1) 686 { 687 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 688 { 689 nv_onattr(np,NV_EXPORT); 690 sh_envput(sh.env,np); 691 } 692 if(name) 693 { 694 nv_close(np); 695 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 696 name = *++names; 697 } 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)) 705 { 706 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 707 jmpval = 1; 708 } 709 else 710 nv_putval(np, "", 0); 711 } 712 } 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); 728 } 729 730