1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2008 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 <ctype.h> 32 #include "defs.h" 33 #include "variables.h" 34 #include "lexstates.h" 35 #include "io.h" 36 #include "name.h" 37 #include "builtins.h" 38 #include "history.h" 39 #include "terminal.h" 40 #include "edit.h" 41 42 #define R_FLAG 1 /* raw mode */ 43 #define S_FLAG 2 /* save in history file */ 44 #define A_FLAG 4 /* read into array */ 45 #define N_FLAG 8 /* fixed size read at most */ 46 #define NN_FLAG 0x10 /* fixed size read exact */ 47 #define V_FLAG 0x20 /* use default value */ 48 #define C_FLAG 0x40 /* read into compound variable */ 49 #define D_FLAG 8 /* must be number of bits for all flags */ 50 51 struct read_save 52 { 53 char **argv; 54 char *prompt; 55 short fd; 56 short plen; 57 int flags; 58 long timeout; 59 }; 60 61 int b_read(int argc,char *argv[], void *extra) 62 { 63 Sfdouble_t sec; 64 register char *name; 65 register int r, flags=0, fd=0; 66 register Shell_t *shp = ((Shbltin_t*)extra)->shp; 67 long timeout = 1000*shp->st.tmout; 68 int save_prompt, fixargs=((Shbltin_t*)extra)->invariant; 69 struct read_save *rp; 70 static char default_prompt[3] = {ESC,ESC}; 71 if(argc==0) 72 return(0); 73 if(rp = (struct read_save*)(((Shbltin_t*)extra)->data)) 74 { 75 flags = rp->flags; 76 timeout = rp->timeout; 77 fd = rp->fd; 78 argv = rp->argv; 79 name = rp->prompt; 80 r = rp->plen; 81 goto bypass; 82 } 83 while((r = optget(argv,sh_optread))) switch(r) 84 { 85 case 'A': 86 flags |= A_FLAG; 87 break; 88 case 'C': 89 flags |= C_FLAG; 90 break; 91 case 't': 92 sec = sh_strnum(opt_info.arg, (char**)0,1); 93 timeout = sec ? 1000*sec : 1; 94 break; 95 case 'd': 96 if(opt_info.arg && *opt_info.arg!='\n') 97 { 98 char *cp = opt_info.arg; 99 flags &= ~((1<<D_FLAG)-1); 100 flags |= (mbchar(cp)<< D_FLAG); 101 } 102 break; 103 case 'p': 104 if((fd = shp->cpipe[0])<=0) 105 errormsg(SH_DICT,ERROR_exit(1),e_query); 106 break; 107 case 'n': case 'N': 108 flags &= ((1<<D_FLAG)-1); 109 flags |= (r=='n'?N_FLAG:NN_FLAG); 110 r = (int)opt_info.num; 111 if((unsigned)r > (1<<((8*sizeof(int))-D_FLAG))-1) 112 errormsg(SH_DICT,ERROR_exit(1),e_overlimit,opt_info.name); 113 flags |= (r<< D_FLAG); 114 break; 115 case 'r': 116 flags |= R_FLAG; 117 break; 118 case 's': 119 /* save in history file */ 120 flags |= S_FLAG; 121 break; 122 case 'u': 123 fd = (int)opt_info.num; 124 if(sh_inuse(fd)) 125 fd = -1; 126 break; 127 case 'v': 128 flags |= V_FLAG; 129 break; 130 case ':': 131 errormsg(SH_DICT,2, "%s", opt_info.arg); 132 break; 133 case '?': 134 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 135 break; 136 } 137 argv += opt_info.index; 138 if(error_info.errors) 139 errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0)); 140 if(!((r=shp->fdstatus[fd])&IOREAD) || !(r&(IOSEEK|IONOSEEK))) 141 r = sh_iocheckfd(shp,fd); 142 if(fd<0 || !(r&IOREAD)) 143 errormsg(SH_DICT,ERROR_system(1),e_file+4); 144 /* look for prompt */ 145 shp->prompt = default_prompt; 146 if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY)) 147 r = strlen(name++); 148 else 149 r = 0; 150 if(argc==fixargs && (rp=newof(NIL(struct read_save*),struct read_save,1,0))) 151 { 152 ((Shbltin_t*)extra)->data = (void*)rp; 153 rp->fd = fd; 154 rp->flags = flags; 155 rp->timeout = timeout; 156 rp->argv = argv; 157 rp->prompt = name; 158 rp->plen = r; 159 } 160 bypass: 161 if(r && (shp->prompt=(char*)sfreserve(sfstderr,r,SF_LOCKR))) 162 { 163 memcpy(shp->prompt,name,r); 164 sfwrite(sfstderr,shp->prompt,r-1); 165 } 166 shp->timeout = 0; 167 save_prompt = shp->nextprompt; 168 shp->nextprompt = 0; 169 r=sh_readline(shp,argv,fd,flags,timeout); 170 shp->nextprompt = save_prompt; 171 if(r==0 && (r=(sfeof(shp->sftable[fd])||sferror(shp->sftable[fd])))) 172 { 173 if(fd == shp->cpipe[0]) 174 { 175 sh_pclose(shp->cpipe); 176 return(1); 177 } 178 } 179 sfclrerr(shp->sftable[fd]); 180 return(r); 181 } 182 183 /* 184 * here for read timeout 185 */ 186 static void timedout(void *handle) 187 { 188 sfclrlock((Sfio_t*)handle); 189 sh_exit(1); 190 } 191 192 /* 193 * This is the code to read a line and to split it into tokens 194 * <names> is an array of variable names 195 * <fd> is the file descriptor 196 * <flags> is union of -A, -r, -s, and contains delimiter if not '\n' 197 * <timeout> is number of milli-seconds until timeout 198 */ 199 200 int sh_readline(register Shell_t *shp,char **names, int fd, int flags,long timeout) 201 { 202 register int c; 203 register unsigned char *cp; 204 register Namval_t *np; 205 register char *name, *val; 206 register Sfio_t *iop; 207 Namfun_t *nfp; 208 char *ifs; 209 unsigned char *cpmax; 210 unsigned char *del; 211 char was_escape = 0; 212 char use_stak = 0; 213 volatile char was_write = 0; 214 volatile char was_share = 1; 215 int rel, wrd; 216 long array_index = 0; 217 void *timeslot=0; 218 int delim = '\n'; 219 int jmpval=0; 220 int size = 0; 221 int binary; 222 struct checkpt buff; 223 if(!(iop=shp->sftable[fd]) && !(iop=sh_iostream(shp,fd))) 224 return(1); 225 sh_stats(STAT_READS); 226 if(names && (name = *names)) 227 { 228 if(val= strchr(name,'?')) 229 *val = 0; 230 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 231 if((flags&V_FLAG) && shp->ed_context) 232 ((struct edit*)shp->ed_context)->e_default = np; 233 if(flags&A_FLAG) 234 { 235 flags &= ~A_FLAG; 236 array_index = 1; 237 nv_unset(np); 238 nv_putsub(np,NIL(char*),0L); 239 } 240 else if(flags&C_FLAG) 241 { 242 delim = -1; 243 nv_unset(np); 244 nv_setvtree(np); 245 } 246 else 247 name = *++names; 248 if(val) 249 *val = '?'; 250 } 251 else 252 { 253 name = 0; 254 if(dtvnext(shp->var_tree) || shp->namespace) 255 np = nv_open(nv_name(REPLYNOD),shp->var_tree,0); 256 else 257 np = REPLYNOD; 258 } 259 if(flags>>D_FLAG) /* delimiter not new-line or fixed size read */ 260 { 261 if(flags&(N_FLAG|NN_FLAG)) 262 size = ((unsigned)flags)>>D_FLAG; 263 else 264 delim = ((unsigned)flags)>>D_FLAG; 265 if(shp->fdstatus[fd]&IOTTY) 266 tty_raw(fd,1); 267 } 268 binary = nv_isattr(np,NV_BINARY); 269 if(!binary && !(flags&(N_FLAG|NN_FLAG))) 270 { 271 Namval_t *mp; 272 /* set up state table based on IFS */ 273 ifs = nv_getval(mp=sh_scoped(shp,IFSNOD)); 274 if((flags&R_FLAG) && shp->ifstable['\\']==S_ESC) 275 shp->ifstable['\\'] = 0; 276 else if(!(flags&R_FLAG) && shp->ifstable['\\']==0) 277 shp->ifstable['\\'] = S_ESC; 278 shp->ifstable[delim] = S_NL; 279 if(delim!='\n') 280 { 281 shp->ifstable['\n'] = 0; 282 nv_putval(mp, ifs, NV_RDONLY); 283 } 284 shp->ifstable[0] = S_EOF; 285 } 286 sfclrerr(iop); 287 for(nfp=np->nvfun; nfp; nfp = nfp->next) 288 { 289 if(nfp->disc && nfp->disc->readf) 290 { 291 if((c=(*nfp->disc->readf)(np,iop,delim,nfp))>=0) 292 return(c); 293 } 294 } 295 if(binary && !(flags&(N_FLAG|NN_FLAG))) 296 { 297 flags |= NN_FLAG; 298 size = nv_size(np); 299 } 300 was_write = (sfset(iop,SF_WRITE,0)&SF_WRITE)!=0; 301 if(fd==0) 302 was_share = (sfset(iop,SF_SHARE,1)&SF_SHARE)!=0; 303 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 304 { 305 sh_pushcontext(&buff,1); 306 jmpval = sigsetjmp(buff.buff,0); 307 if(jmpval) 308 goto done; 309 if(timeout) 310 timeslot = (void*)sh_timeradd(timeout,0,timedout,(void*)iop); 311 } 312 if(flags&(N_FLAG|NN_FLAG)) 313 { 314 char buf[64],*var=buf,*cur,*end,*up,*v; 315 /* reserved buffer */ 316 if((c=size)>=sizeof(buf)) 317 { 318 if(!(var = (char*)malloc(c+1))) 319 sh_exit(1); 320 end = var + c; 321 } 322 else 323 end = var + sizeof(buf) - 1; 324 up = cur = var; 325 if((sfset(iop,SF_SHARE,1)&SF_SHARE) && fd!=0) 326 was_share = 1; 327 if(size==0) 328 { 329 cp = sfreserve(iop,0,0); 330 c = 0; 331 } 332 else 333 { 334 int f,m; 335 for (;;) 336 { 337 c = (flags&NN_FLAG) ? -size : -1; 338 cp = sfreserve(iop,c,SF_LOCKR); 339 f = 1; 340 if((m = sfvalue(iop)) > 0) 341 { 342 if(!cp) 343 { 344 m = (cp = sfreserve(iop,size,0)) ? sfvalue(iop) : 0; 345 f = 0; 346 } 347 if(m>0 && (flags&N_FLAG) && !binary && (v=memchr(cp,'\n',m))) 348 m = v-(char*)cp; 349 } 350 if((c=m)>size) 351 c = size; 352 if(c>0) 353 { 354 if(c > (end-cur)) 355 { 356 int cx = cur - var, ux = up - var; 357 if (var == buf) 358 { 359 m = (end - var) + (c - (end - cur)); 360 v = (char*)malloc(m+1); 361 memcpy(v, var, cur - var); 362 } 363 else 364 v = newof(var, char, m, 1); 365 end = v + m; 366 cur = v + cx; 367 up = v + ux; 368 } 369 memcpy((void*)cur,cp,c); 370 if(f) 371 sfread(iop,cp,c); 372 cur += c; 373 #if SHOPT_MULTIBYTE 374 if(!binary && mbwide()) 375 { 376 int x; 377 int z; 378 int y = cur - up; 379 380 mbinit(); 381 *cur = 0; 382 x = z = 0; 383 while (up < cur && (z = mbsize(up)) > 0) 384 { 385 up += z; 386 x++; 387 } 388 if((size -= x) > 0 && (up >= cur || z < 0) && ((flags & NN_FLAG) || z < 0 || m > c)) 389 continue; 390 } 391 #endif 392 } 393 #if SHOPT_MULTIBYTE 394 if(!binary && mbwide() && (up == var || (flags & NN_FLAG) && size)) 395 cur = var; 396 #endif 397 *cur = 0; 398 if(c>=size) 399 sfclrerr(iop); 400 break; 401 } 402 } 403 if(timeslot) 404 timerdel(timeslot); 405 if(binary) 406 { 407 if(c==nv_size(np)) 408 memcpy((char*)np->nvalue.cp,var,c); 409 else 410 { 411 if(var==buf) 412 var = memdup(var,c); 413 nv_putval(np,var,NV_RAW); 414 nv_setsize(np,c); 415 } 416 } 417 else 418 { 419 nv_putval(np,var,0); 420 if(var!=buf) 421 free((void*)var); 422 } 423 goto done; 424 } 425 else if(cp = (unsigned char*)sfgetr(iop,delim,0)) 426 c = sfvalue(iop); 427 else if(cp = (unsigned char*)sfgetr(iop,delim,-1)) 428 c = sfvalue(iop)+1; 429 if(timeslot) 430 timerdel(timeslot); 431 if((flags&S_FLAG) && !shp->hist_ptr) 432 { 433 sh_histinit((void*)shp); 434 if(!shp->hist_ptr) 435 flags &= ~S_FLAG; 436 } 437 if(cp) 438 { 439 cpmax = cp + c; 440 #if SHOPT_CRNL 441 if(delim=='\n' && c>=2 && cpmax[-2]=='\r') 442 cpmax--; 443 #endif /* SHOPT_CRNL */ 444 if(*(cpmax-1) != delim) 445 *(cpmax-1) = delim; 446 if(flags&S_FLAG) 447 sfwrite(shp->hist_ptr->histfp,(char*)cp,c); 448 c = shp->ifstable[*cp++]; 449 #if !SHOPT_MULTIBYTE 450 if(!name && (flags&R_FLAG)) /* special case single argument */ 451 { 452 /* skip over leading blanks */ 453 while(c==S_SPACE) 454 c = shp->ifstable[*cp++]; 455 /* strip trailing delimiters */ 456 if(cpmax[-1] == '\n') 457 cpmax--; 458 if(cpmax>cp) 459 { 460 while((c=shp->ifstable[*--cpmax])==S_DELIM || c==S_SPACE); 461 cpmax[1] = 0; 462 } 463 else 464 *cpmax =0; 465 if(nv_isattr(np, NV_RDONLY)) 466 { 467 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 468 jmpval = 1; 469 } 470 else 471 nv_putval(np,(char*)cp-1,0); 472 goto done; 473 } 474 #endif /* !SHOPT_MULTIBYTE */ 475 } 476 else 477 c = S_NL; 478 shp->nextprompt = 2; 479 rel= staktell(); 480 /* val==0 at the start of a field */ 481 val = 0; 482 del = 0; 483 while(1) 484 { 485 switch(c) 486 { 487 #if SHOPT_MULTIBYTE 488 case S_MBYTE: 489 if(val==0) 490 val = (char*)(cp-1); 491 if(sh_strchr(ifs,(char*)cp-1)>=0) 492 { 493 c = mbsize((char*)cp-1); 494 if(name) 495 cp[-1] = 0; 496 if(c>1) 497 cp += (c-1); 498 c = S_DELIM; 499 } 500 else 501 c = 0; 502 continue; 503 #endif /*SHOPT_MULTIBYTE */ 504 case S_ESC: 505 /* process escape character */ 506 if((c = shp->ifstable[*cp++]) == S_NL) 507 was_escape = 1; 508 else 509 c = 0; 510 if(val) 511 { 512 stakputs(val); 513 use_stak = 1; 514 was_escape = 1; 515 *val = 0; 516 } 517 continue; 518 519 case S_EOF: 520 /* check for end of buffer */ 521 if(val && *val) 522 { 523 stakputs(val); 524 use_stak = 1; 525 } 526 val = 0; 527 if(cp>=cpmax) 528 { 529 c = S_NL; 530 break; 531 } 532 /* eliminate null bytes */ 533 c = shp->ifstable[*cp++]; 534 if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE)) 535 c = 0; 536 continue; 537 case S_NL: 538 if(was_escape) 539 { 540 was_escape = 0; 541 if(cp = (unsigned char*)sfgetr(iop,delim,0)) 542 c = sfvalue(iop); 543 else if(cp=(unsigned char*)sfgetr(iop,delim,-1)) 544 c = sfvalue(iop)+1; 545 if(cp) 546 { 547 if(flags&S_FLAG) 548 sfwrite(shp->hist_ptr->histfp,(char*)cp,c); 549 cpmax = cp + c; 550 c = shp->ifstable[*cp++]; 551 val=0; 552 if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE)) 553 c = 0; 554 continue; 555 } 556 } 557 c = S_NL; 558 break; 559 560 case S_SPACE: 561 /* skip over blanks */ 562 while((c=shp->ifstable[*cp++])==S_SPACE); 563 if(!val) 564 continue; 565 #if SHOPT_MULTIBYTE 566 if(c==S_MBYTE) 567 { 568 if(sh_strchr(ifs,(char*)cp-1)>=0) 569 { 570 if((c = mbsize((char*)cp-1))>1) 571 cp += (c-1); 572 c = S_DELIM; 573 } 574 else 575 c = 0; 576 } 577 #endif /* SHOPT_MULTIBYTE */ 578 if(c!=S_DELIM) 579 break; 580 /* FALL THRU */ 581 582 case S_DELIM: 583 if(!del) 584 del = cp - 1; 585 if(name) 586 { 587 /* skip over trailing blanks */ 588 while((c=shp->ifstable[*cp++])==S_SPACE); 589 break; 590 } 591 /* FALL THRU */ 592 593 case 0: 594 if(val==0 || was_escape) 595 { 596 val = (char*)(cp-1); 597 was_escape = 0; 598 } 599 /* skip over word characters */ 600 wrd = -1; 601 while(1) 602 { 603 while((c=shp->ifstable[*cp++])==0) 604 if(!wrd) 605 wrd = 1; 606 if(!del&&c==S_DELIM) 607 del = cp - 1; 608 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE) 609 break; 610 if(wrd<0) 611 wrd = 0; 612 } 613 if(wrd>0) 614 del = (unsigned char*)""; 615 if(c!=S_MBYTE) 616 cp[-1] = 0; 617 continue; 618 } 619 /* assign value and advance to next variable */ 620 if(!val) 621 val = ""; 622 if(use_stak) 623 { 624 stakputs(val); 625 stakputc(0); 626 val = stakptr(rel); 627 } 628 if(!name && *val) 629 { 630 /* strip off trailing space delimiters */ 631 register unsigned char *vp = (unsigned char*)val + strlen(val); 632 while(shp->ifstable[*--vp]==S_SPACE); 633 if(vp==del) 634 { 635 if(vp==(unsigned char*)val) 636 vp--; 637 else 638 while(shp->ifstable[*--vp]==S_SPACE); 639 } 640 vp[1] = 0; 641 } 642 if(nv_isattr(np, NV_RDONLY)) 643 { 644 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 645 jmpval = 1; 646 } 647 else 648 nv_putval(np,val,0); 649 val = 0; 650 del = 0; 651 if(use_stak) 652 { 653 stakseek(rel); 654 use_stak = 0; 655 } 656 if(array_index) 657 { 658 nv_putsub(np, NIL(char*), array_index++); 659 if(c!=S_NL) 660 continue; 661 name = *++names; 662 } 663 while(1) 664 { 665 if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.') && !nv_isattr(np,NV_EXPORT)) 666 { 667 nv_onattr(np,NV_EXPORT); 668 sh_envput(sh.env,np); 669 } 670 if(name) 671 { 672 nv_close(np); 673 np = nv_open(name,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 674 name = *++names; 675 } 676 else 677 np = 0; 678 if(c!=S_NL) 679 break; 680 if(!np) 681 goto done; 682 if(nv_isattr(np, NV_RDONLY)) 683 { 684 errormsg(SH_DICT,ERROR_warn(0),e_readonly, nv_name(np)); 685 jmpval = 1; 686 } 687 else 688 nv_putval(np, "", 0); 689 } 690 } 691 done: 692 if(timeout || (shp->fdstatus[fd]&(IOTTY|IONOSEEK))) 693 sh_popcontext(&buff); 694 if(was_write) 695 sfset(iop,SF_WRITE,1); 696 if(!was_share) 697 sfset(iop,SF_SHARE,0); 698 nv_close(np); 699 if((flags>>D_FLAG) && (shp->fdstatus[fd]&IOTTY)) 700 tty_cooked(fd); 701 if(flags&S_FLAG) 702 hist_flush(shp->hist_ptr); 703 if(jmpval > 1) 704 siglongjmp(*shp->jmplist,jmpval); 705 return(jmpval); 706 } 707 708