1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2009 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 shp->prompt = default_prompt; 150 if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY)) 151 r = strlen(name++); 152 else 153 r = 0; 154 if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0))) 155 { 156 ((Shbltin_t*)extra)->data = (void*)rp; 157 rp->fd = fd; 158 rp->flags = flags; 159 rp->timeout = timeout; 160 rp->argv = argv; 161 rp->prompt = name; 162 rp->plen = r; 163 } 164 bypass: 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 = (flags&NN_FLAG) ? -size : -1; 346 cp = sfreserve(iop,c,SF_LOCKR); 347 f = 1; 348 if(cp) 349 m = sfvalue(iop); 350 else 351 { 352 m = (cp = sfreserve(iop,size,0)) ? sfvalue(iop) : 0; 353 f = 0; 354 } 355 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) 356 { 357 *v++ = 0; 358 m = v-(char*)cp; 359 } 360 if((c=m)>size) 361 c = size; 362 if(c>0) 363 { 364 if(c > (end-cur)) 365 { 366 ssize_t cx = cur - var, ux = up - var; 367 m = (end - var) + (c - (end - cur)); 368 if (var == buf) 369 { 370 v = (char*)malloc(m+1); 371 var = memcpy(v, var, cur - var); 372 } 373 else 374 var = newof(var, char, m, 1); 375 end = var + m; 376 cur = var + cx; 377 up = var + ux; 378 } 379 memcpy((void*)cur,cp,c); 380 if(f) 381 sfread(iop,cp,c); 382 cur += c; 383 #if SHOPT_MULTIBYTE 384 if(!binary && mbwide()) 385 { 386 int x; 387 int z; 388 389 mbinit(); 390 *cur = 0; 391 x = z = 0; 392 while (up < cur && (z = mbsize(up)) > 0) 393 { 394 up += z; 395 x++; 396 } 397 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c)) 398 continue; 399 } 400 #endif 401 } 402 #if SHOPT_MULTIBYTE 403 if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size)) 404 cur = var; 405 #endif 406 *cur = 0; 407 if(c>=size) 408 sfclrerr(iop); 409 break; 410 } 411 } 412 if(timeslot) 413 timerdel(timeslot); 414 if(binary && !((size=nv_size(np)) && nv_isarray(np) && c!=size)) 415 { 416 if((c==size) && np->nvalue.cp && !nv_isarray(np)) 417 memcpy((char*)np->nvalue.cp,var,c); 418 else 419 { 420 Namval_t *mp; 421 if(var==buf) 422 var = memdup(var,c); 423 nv_putval(np,var,NV_RAW); 424 nv_setsize(np,c); 425 if(!nv_isattr(np,NV_IMPORT|NV_EXPORT) && (mp=(Namval_t*)np->nvenv)) 426 nv_setsize(mp,c); 427 } 428 } 429 else 430 { 431 nv_putval(np,var,0); 432 if(var!=buf) 433 free((void*)var); 434 } 435 goto done; 436 } 437 else if(cp = (unsigned char*)sfgetr(iop,delim,0)) 438 c = sfvalue(iop); 439 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 440 c = sfvalue(iop)+1; 441 if(timeslot) 442 timerdel(timeslot); 443 if((flags&S_FLAG) && !shp->hist_ptr) 444 { 445 sh_histinit((void*)shp); 446 if(!shp->hist_ptr) 447 flags &= ~S_FLAG; 448 } 449 if(cp) 450 { 451 cpmax = cp + c; 452 #if SHOPT_CRNL 453 if(delim=='\n' && c>=2 && cpmax[-2]=='\r') 454 cpmax--; 455 #endif /* SHOPT_CRNL */ 456 if(*(cpmax-1) != delim) 457 *(cpmax-1) = delim; 458 if(flags&S_FLAG) 459 sfwrite(shp->hist_ptr->histfp,(char*)cp,c); 460 c = shp->ifstable[*cp++]; 461 #if !SHOPT_MULTIBYTE 462 if(!name && (flags&R_FLAG)) /* special case single argument */ 463 { 464 /* skip over leading blanks */ 465 while(c==S_SPACE) 466 c = shp->ifstable[*cp++]; 467 /* strip trailing delimiters */ 468 if(cpmax[-1] == '\n') 469 cpmax--; 470 if(cpmax>cp) 471 { 472 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); 473 cpmax[1] = 0; 474 } 475 else 476 *cpmax =0; 477 if(nv_isattr(np, NV_RDONLY)) 478 { 479 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 480 jmpval = 1; 481 } 482 else 483 nv_putval(np,(char*)cp-1,0); 484 goto done; 485 } 486 #endif /* !SHOPT_MULTIBYTE */ 487 } 488 else 489 c = S_NL; 490 shp->nextprompt = 2; 491 rel= staktell(); 492 /* val==0 at the start of a field */ 493 val = 0; 494 del = 0; 495 while(1) 496 { 497 switch(c) 498 { 499 #if SHOPT_MULTIBYTE 500 case S_MBYTE: 501 if(val==0) 502 val = (char*)(cp-1); 503 if(sh_strchr(ifs,(char*)cp-1)>=0) 504 { 505 c = mbsize((char*)cp-1); 506 if(name) 507 cp[-1] = 0; 508 if(c>1) 509 cp += (c-1); 510 c = S_DELIM; 511 } 512 else 513 c = 0; 514 continue; 515 #endif /*SHOPT_MULTIBYTE */ 516 case S_ESC: 517 /* process escape character */ 518 if((c = shp->ifstable[*cp++]) == S_NL) 519 was_escape = 1; 520 else 521 c = 0; 522 if(val) 523 { 524 stakputs(val); 525 use_stak = 1; 526 was_escape = 1; 527 *val = 0; 528 } 529 continue; 530 531 case S_EOF: 532 /* check for end of buffer */ 533 if(val && *val) 534 { 535 stakputs(val); 536 use_stak = 1; 537 } 538 val = 0; 539 if(cp>=cpmax) 540 { 541 c = S_NL; 542 break; 543 } 544 /* eliminate null bytes */ 545 c = shp->ifstable[*cp++]; 546 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) 547 c = 0; 548 continue; 549 case S_NL: 550 if(was_escape) 551 { 552 was_escape = 0; 553 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 554 c = sfvalue(iop); 555 else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) 556 c = sfvalue(iop)+1; 557 if(cp) 558 { 559 if(flags&S_FLAG) 560 sfwrite(shp->hist_ptr->histfp,(char*)cp,c); 561 cpmax = cp + c; 562 c = shp->ifstable[*cp++]; 563 val=0; 564 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) 565 c = 0; 566 continue; 567 } 568 } 569 c = S_NL; 570 break; 571 572 case S_SPACE: 573 /* skip over blanks */ 574 while((c=shp->ifstable[*cp++])==S_SPACE); 575 if(!val) 576 continue; 577 #if SHOPT_MULTIBYTE 578 if(c==S_MBYTE) 579 { 580 if(sh_strchr(ifs,(char*)cp-1)>=0) 581 { 582 if((c = mbsize((char*)cp-1))>1) 583 cp += (c-1); 584 c = S_DELIM; 585 } 586 else 587 c = 0; 588 } 589 #endif /* SHOPT_MULTIBYTE */ 590 if(c!=S_DELIM) 591 break; 592 /* FALL THRU */ 593 594 case S_DELIM: 595 if(!del) 596 del = cp - 1; 597 if(name) 598 { 599 /* skip over trailing blanks */ 600 while((c=shp->ifstable[*cp++])==S_SPACE); 601 break; 602 } 603 /* FALL THRU */ 604 605 case 0: 606 if(val==0 || was_escape) 607 { 608 val = (char*)(cp-1); 609 was_escape = 0; 610 } 611 /* skip over word characters */ 612 wrd = -1; 613 while(1) 614 { 615 while((c=shp->ifstable[*cp++])==0) 616 if(!wrd) 617 wrd = 1; 618 if(!del&&c==S_DELIM) 619 del = cp - 1; 620 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) 621 break; 622 if(wrd<0) 623 wrd = 0; 624 } 625 if(wrd>0) 626 del = (unsigned char*)""; 627 if(c!=S_MBYTE) 628 cp[-1] = 0; 629 continue; 630 } 631 /* assign value and advance to next variable */ 632 if(!val) 633 val = ""; 634 if(use_stak) 635 { 636 stakputs(val); 637 stakputc(0); 638 val = stakptr(rel); 639 } 640 if(!name && *val) 641 { 642 /* strip off trailing space delimiters */ 643 register unsigned char *vp = (unsigned char*)val + strlen(val); 644 while(shp->ifstable[*--vp]==S_SPACE); 645 if(vp==del) 646 { 647 if(vp==(unsigned char*)val) 648 vp--; 649 else 650 while(shp->ifstable[*--vp]==S_SPACE); 651 } 652 vp[1] = 0; 653 } 654 if(nv_isattr(np, NV_RDONLY)) 655 { 656 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 657 jmpval = 1; 658 } 659 else 660 nv_putval(np,val,0); 661 val = 0; 662 del = 0; 663 if(use_stak) 664 { 665 stakseek(rel); 666 use_stak = 0; 667 } 668 if(array_index) 669 { 670 nv_putsub(np, NIL(char*), array_index++); 671 if(c!=S_NL) 672 continue; 673 name = *++names; 674 } 675 while(1) 676 { 677 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 678 { 679 nv_onattr(np,NV_EXPORT); 680 sh_envput(sh.env,np); 681 } 682 if(name) 683 { 684 nv_close(np); 685 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 686 name = *++names; 687 } 688 else 689 np = 0; 690 if(c!=S_NL) 691 break; 692 if(!np) 693 goto done; 694 if(nv_isattr(np, NV_RDONLY)) 695 { 696 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 697 jmpval = 1; 698 } 699 else 700 nv_putval(np, "", 0); 701 } 702 } 703 done: 704 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 705 sh_popcontext(&buff); 706 if(was_write) 707 sfset(iop,SF_WRITE,1); 708 if(!was_share) 709 sfset(iop,SF_SHARE,0); 710 nv_close(np); 711 if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY)) 712 tty_cooked(fd); 713 if(flags&S_FLAG) 714 hist_flush(shp->hist_ptr); 715 if(jmpval > 1) 716 siglongjmp(*shp->jmplist,jmpval); 717 return(jmpval); 718 } 719 720