1 /* $Header: /src/pub/tcsh/tw.init.c,v 3.29 2002/06/25 19:02:12 christos Exp $ */ 2 /* 3 * tw.init.c: Handle lists of things to complete 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$Id: tw.init.c,v 3.29 2002/06/25 19:02:12 christos Exp $") 36 37 #include "tw.h" 38 #include "ed.h" 39 #include "tc.h" 40 #include "sh.proc.h" 41 42 #if !defined(NSIG) && defined(SIGMAX) 43 # define NSIG (SIGMAX+1) 44 #endif /* !NSIG && SIGMAX */ 45 #if !defined(NSIG) && defined(_NSIG) 46 # define NSIG _NSIG 47 #endif /* !NSIG && _NSIG */ 48 49 #define TW_INCR 128 50 51 typedef struct { 52 Char **list, /* List of command names */ 53 *buff; /* Space holding command names */ 54 int nlist, /* Number of items */ 55 nbuff, /* Current space in name buf */ 56 tlist, /* Total space in list */ 57 tbuff; /* Total space in name buf */ 58 } stringlist_t; 59 60 61 static struct varent *tw_vptr = NULL; /* Current shell variable */ 62 static Char **tw_env = NULL; /* Current environment variable */ 63 static Char *tw_word; /* Current word pointer */ 64 static struct KeyFuncs *tw_bind = NULL; /* List of the bindings */ 65 #ifndef HAVENOLIMIT 66 static struct limits *tw_limit = NULL; /* List of the resource limits */ 67 #endif /* HAVENOLIMIT */ 68 static int tw_index = 0; /* signal and job index */ 69 static DIR *tw_dir_fd = NULL; /* Current directory descriptor */ 70 static Char tw_retname[MAXPATHLEN+1]; /* Return buffer */ 71 static int tw_cmd_got = 0; /* What we need to do */ 72 static stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 }; 73 static stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 }; 74 #define TW_FL_CMD 0x01 75 #define TW_FL_ALIAS 0x02 76 #define TW_FL_BUILTIN 0x04 77 #define TW_FL_SORT 0x08 78 #define TW_FL_REL 0x10 79 80 static struct { /* Current element pointer */ 81 int cur; /* Current element number */ 82 Char **pathv; /* Current element in path */ 83 DIR *dfd; /* Current directory descriptor */ 84 } tw_cmd_state; 85 86 87 #ifdef BSDSIGS 88 static sigmask_t tw_omask; 89 # define TW_HOLD() tw_omask = sigblock(sigmask(SIGINT)) 90 # define TW_RELS() (void) sigsetmask(tw_omask) 91 #else /* !BSDSIGS */ 92 # define TW_HOLD() (void) sighold(SIGINT) 93 # define TW_RELS() (void) sigrelse(SIGINT) 94 #endif /* BSDSIGS */ 95 96 #define SETDIR(dfd) \ 97 { \ 98 tw_dir_fd = dfd; \ 99 if (tw_dir_fd != NULL) \ 100 rewinddir(tw_dir_fd); \ 101 } 102 103 #define CLRDIR(dfd) \ 104 if (dfd != NULL) { \ 105 TW_HOLD(); \ 106 (void) closedir(dfd); \ 107 dfd = NULL; \ 108 TW_RELS(); \ 109 } 110 111 static Char *tw_str_add __P((stringlist_t *, int)); 112 static void tw_str_free __P((stringlist_t *)); 113 static Char *tw_dir_next __P((DIR *)); 114 static void tw_cmd_add __P((Char *name)); 115 static void tw_cmd_cmd __P((void)); 116 static void tw_cmd_builtin __P((void)); 117 static void tw_cmd_alias __P((void)); 118 static void tw_cmd_sort __P((void)); 119 static void tw_vptr_start __P((struct varent *)); 120 121 122 /* tw_str_add(): 123 * Add an item to the string list 124 */ 125 static Char * 126 tw_str_add(sl, len) 127 stringlist_t *sl; 128 int len; 129 { 130 Char *ptr; 131 132 if (sl->tlist <= sl->nlist) { 133 TW_HOLD(); 134 sl->tlist += TW_INCR; 135 sl->list = sl->list ? 136 (Char **) xrealloc((ptr_t) sl->list, 137 (size_t) (sl->tlist * sizeof(Char *))) : 138 (Char **) xmalloc((size_t) (sl->tlist * sizeof(Char *))); 139 TW_RELS(); 140 } 141 if (sl->tbuff <= sl->nbuff + len) { 142 int i; 143 ptr = sl->buff; 144 145 TW_HOLD(); 146 sl->tbuff += TW_INCR + len; 147 sl->buff = sl->buff ? 148 (Char *) xrealloc((ptr_t) sl->buff, 149 (size_t) (sl->tbuff * sizeof(Char))) : 150 (Char *) xmalloc((size_t) (sl->tbuff * sizeof(Char))); 151 /* Re-thread the new pointer list, if changed */ 152 if (ptr != NULL && ptr != sl->buff) { 153 int offs = (int) (sl->buff - ptr); 154 for (i = 0; i < sl->nlist; i++) 155 sl->list[i] += offs; 156 } 157 TW_RELS(); 158 } 159 ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff]; 160 sl->nbuff += len; 161 return ptr; 162 } /* tw_str_add */ 163 164 165 /* tw_str_free(): 166 * Free a stringlist 167 */ 168 static void 169 tw_str_free(sl) 170 stringlist_t *sl; 171 { 172 TW_HOLD(); 173 if (sl->list) { 174 xfree((ptr_t) sl->list); 175 sl->list = NULL; 176 sl->tlist = sl->nlist = 0; 177 } 178 if (sl->buff) { 179 xfree((ptr_t) sl->buff); 180 sl->buff = NULL; 181 sl->tbuff = sl->nbuff = 0; 182 } 183 TW_RELS(); 184 } /* end tw_str_free */ 185 186 187 static Char * 188 tw_dir_next(dfd) 189 DIR *dfd; 190 { 191 register struct dirent *dirp; 192 193 if (dfd == NULL) 194 return NULL; 195 196 if ((dirp = readdir(dfd)) != NULL) { 197 (void) Strcpy(tw_retname, str2short(dirp->d_name)); 198 return (tw_retname); 199 } 200 return NULL; 201 } /* end tw_dir_next */ 202 203 204 /* tw_cmd_add(): 205 * Add the name to the command list 206 */ 207 static void 208 tw_cmd_add(name) 209 Char *name; 210 { 211 int len; 212 213 len = (int) Strlen(name) + 2; 214 (void) Strcpy(tw_str_add(&tw_cmd, len), name); 215 } /* end tw_cmd_add */ 216 217 218 /* tw_cmd_free(): 219 * Free the command list 220 */ 221 void 222 tw_cmd_free() 223 { 224 CLRDIR(tw_dir_fd) 225 tw_str_free(&tw_cmd); 226 tw_cmd_got = 0; 227 } /* end tw_cmd_free */ 228 229 /* tw_cmd_cmd(): 230 * Add system commands to the command list 231 */ 232 static void 233 tw_cmd_cmd() 234 { 235 register DIR *dirp; 236 register struct dirent *dp; 237 register Char *dir = NULL, *name; 238 register Char **pv; 239 struct varent *v = adrof(STRpath); 240 struct varent *recexec = adrof(STRrecognize_only_executables); 241 int len; 242 243 244 if (v == NULL || v->vec == NULL) /* if no path */ 245 return; 246 247 for (pv = v->vec; *pv; pv++) { 248 if (pv[0][0] != '/') { 249 tw_cmd_got |= TW_FL_REL; 250 continue; 251 } 252 253 if ((dirp = opendir(short2str(*pv))) == NULL) 254 continue; 255 256 if (recexec) 257 dir = Strspl(*pv, STRslash); 258 while ((dp = readdir(dirp)) != NULL) { 259 #if defined(_UWIN) || defined(__CYGWIN__) 260 /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 261 * the file with the .exe, .com, .bat extension 262 */ 263 size_t ext = strlen(dp->d_name) - 4; 264 if ((ext > 0) && (strcmp(&dp->d_name[ext], ".exe") == 0 || 265 strcmp(&dp->d_name[ext], ".bat") == 0 || 266 strcmp(&dp->d_name[ext], ".com") == 0)) 267 dp->d_name[ext] = '\0'; 268 #endif /* _UWIN || __CYGWIN__ */ 269 /* the call to executable() may make this a bit slow */ 270 name = str2short(dp->d_name); 271 if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0))) 272 continue; 273 len = (int) Strlen(name) + 2; 274 if (name[0] == '#' || /* emacs temp files */ 275 name[0] == '.' || /* .files */ 276 name[len - 3] == '~' || /* emacs backups */ 277 name[len - 3] == '%') /* textedit backups */ 278 continue; /* Ignore! */ 279 tw_cmd_add(name); 280 } 281 (void) closedir(dirp); 282 if (recexec) 283 xfree((ptr_t) dir); 284 } 285 } /* end tw_cmd_cmd */ 286 287 288 /* tw_cmd_builtin(): 289 * Add builtins to the command list 290 */ 291 static void 292 tw_cmd_builtin() 293 { 294 register struct biltins *bptr; 295 296 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) 297 if (bptr->bname) 298 tw_cmd_add(str2short(bptr->bname)); 299 #ifdef WINNT_NATIVE 300 for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) 301 if (bptr->bname) 302 tw_cmd_add(str2short(bptr->bname)); 303 #endif /* WINNT_NATIVE*/ 304 } /* end tw_cmd_builtin */ 305 306 307 /* tw_cmd_alias(): 308 * Add aliases to the command list 309 */ 310 static void 311 tw_cmd_alias() 312 { 313 register struct varent *p; 314 register struct varent *c; 315 316 p = &aliases; 317 for (;;) { 318 while (p->v_left) 319 p = p->v_left; 320 x: 321 if (p->v_parent == 0) /* is it the header? */ 322 return; 323 if (p->v_name) 324 tw_cmd_add(p->v_name); 325 if (p->v_right) { 326 p = p->v_right; 327 continue; 328 } 329 do { 330 c = p; 331 p = p->v_parent; 332 } while (p->v_right == c); 333 goto x; 334 } 335 } /* end tw_cmd_alias */ 336 337 338 /* tw_cmd_sort(): 339 * Sort the command list removing duplicate elements 340 */ 341 static void 342 tw_cmd_sort() 343 { 344 int fwd, i; 345 346 TW_HOLD(); 347 /* sort the list. */ 348 qsort((ptr_t) tw_cmd.list, (size_t) tw_cmd.nlist, sizeof(Char *), 349 (int (*) __P((const void *, const void *))) fcompare); 350 351 /* get rid of multiple entries */ 352 for (i = 0, fwd = 0; i < tw_cmd.nlist - 1; i++) { 353 if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */ 354 fwd++; /* increase the forward ref. count */ 355 else if (fwd) 356 tw_cmd.list[i - fwd] = tw_cmd.list[i]; 357 } 358 /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */ 359 if (fwd) 360 tw_cmd.list[i - fwd] = tw_cmd.list[i]; 361 tw_cmd.nlist -= fwd; 362 TW_RELS(); 363 } /* end tw_cmd_sort */ 364 365 366 /* tw_cmd_start(): 367 * Get the command list and sort it, if not done yet. 368 * Reset the current pointer to the beginning of the command list 369 */ 370 /*ARGSUSED*/ 371 void 372 tw_cmd_start(dfd, pat) 373 DIR *dfd; 374 Char *pat; 375 { 376 static Char *defpath[] = { STRNULL, 0 }; 377 USE(pat); 378 SETDIR(dfd) 379 if ((tw_cmd_got & TW_FL_CMD) == 0) { 380 tw_cmd_free(); 381 tw_cmd_cmd(); 382 tw_cmd_got |= TW_FL_CMD; 383 } 384 if ((tw_cmd_got & TW_FL_ALIAS) == 0) { 385 tw_cmd_alias(); 386 tw_cmd_got &= ~TW_FL_SORT; 387 tw_cmd_got |= TW_FL_ALIAS; 388 } 389 if ((tw_cmd_got & TW_FL_BUILTIN) == 0) { 390 tw_cmd_builtin(); 391 tw_cmd_got &= ~TW_FL_SORT; 392 tw_cmd_got |= TW_FL_BUILTIN; 393 } 394 if ((tw_cmd_got & TW_FL_SORT) == 0) { 395 tw_cmd_sort(); 396 tw_cmd_got |= TW_FL_SORT; 397 } 398 399 tw_cmd_state.cur = 0; 400 CLRDIR(tw_cmd_state.dfd) 401 if (tw_cmd_got & TW_FL_REL) { 402 struct varent *vp = adrof(STRpath); 403 if (vp && vp->vec) 404 tw_cmd_state.pathv = vp->vec; 405 else 406 tw_cmd_state.pathv = defpath; 407 } 408 else 409 tw_cmd_state.pathv = defpath; 410 } /* tw_cmd_start */ 411 412 413 /* tw_cmd_next(): 414 * Return the next element in the command list or 415 * Look for commands in the relative path components 416 */ 417 Char * 418 tw_cmd_next(dir, flags) 419 Char *dir; 420 int *flags; 421 { 422 Char *ptr = NULL; 423 424 if (tw_cmd_state.cur < tw_cmd.nlist) { 425 *flags = TW_DIR_OK; 426 return tw_cmd.list[tw_cmd_state.cur++]; 427 } 428 429 /* 430 * We need to process relatives in the path. 431 */ 432 while (((tw_cmd_state.dfd == NULL) || 433 ((ptr = tw_dir_next(tw_cmd_state.dfd)) == NULL)) && 434 (*tw_cmd_state.pathv != NULL)) { 435 436 CLRDIR(tw_cmd_state.dfd) 437 438 while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/') 439 tw_cmd_state.pathv++; 440 if ((ptr = *tw_cmd_state.pathv) != 0) { 441 /* 442 * We complete directories only on '.' should that 443 * be changed? 444 */ 445 if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) { 446 *dir = '\0'; 447 tw_cmd_state.dfd = opendir("."); 448 *flags = TW_DIR_OK | TW_EXEC_CHK; 449 } 450 else { 451 copyn(dir, *tw_cmd_state.pathv, FILSIZ); 452 catn(dir, STRslash, FILSIZ); 453 tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv)); 454 *flags = TW_EXEC_CHK; 455 } 456 tw_cmd_state.pathv++; 457 } 458 } 459 return ptr; 460 } /* end tw_cmd_next */ 461 462 463 /* tw_vptr_start(): 464 * Find the first variable in the variable list 465 */ 466 static void 467 tw_vptr_start(c) 468 struct varent *c; 469 { 470 tw_vptr = c; /* start at beginning of variable list */ 471 472 for (;;) { 473 while (tw_vptr->v_left) 474 tw_vptr = tw_vptr->v_left; 475 x: 476 if (tw_vptr->v_parent == 0) { /* is it the header? */ 477 tw_vptr = NULL; 478 return; 479 } 480 if (tw_vptr->v_name) 481 return; /* found first one */ 482 if (tw_vptr->v_right) { 483 tw_vptr = tw_vptr->v_right; 484 continue; 485 } 486 do { 487 c = tw_vptr; 488 tw_vptr = tw_vptr->v_parent; 489 } while (tw_vptr->v_right == c); 490 goto x; 491 } 492 } /* end tw_shvar_start */ 493 494 495 /* tw_shvar_next(): 496 * Return the next shell variable 497 */ 498 /*ARGSUSED*/ 499 Char * 500 tw_shvar_next(dir, flags) 501 Char *dir; 502 int *flags; 503 { 504 register struct varent *p; 505 register struct varent *c; 506 register Char *cp; 507 508 USE(flags); 509 USE(dir); 510 if ((p = tw_vptr) == NULL) 511 return (NULL); /* just in case */ 512 513 cp = p->v_name; /* we know that this name is here now */ 514 515 /* now find the next one */ 516 for (;;) { 517 if (p->v_right) { /* if we can go right */ 518 p = p->v_right; 519 while (p->v_left) 520 p = p->v_left; 521 } 522 else { /* else go up */ 523 do { 524 c = p; 525 p = p->v_parent; 526 } while (p->v_right == c); 527 } 528 if (p->v_parent == 0) { /* is it the header? */ 529 tw_vptr = NULL; 530 return (cp); 531 } 532 if (p->v_name) { 533 tw_vptr = p; /* save state for the next call */ 534 return (cp); 535 } 536 } 537 } /* end tw_shvar_next */ 538 539 540 /* tw_envvar_next(): 541 * Return the next environment variable 542 */ 543 /*ARGSUSED*/ 544 Char * 545 tw_envvar_next(dir, flags) 546 Char *dir; 547 int *flags; 548 { 549 Char *ps, *pd; 550 551 USE(flags); 552 USE(dir); 553 if (tw_env == NULL || *tw_env == NULL) 554 return (NULL); 555 for (ps = *tw_env, pd = tw_retname; 556 *ps && *ps != '=' && pd <= &tw_retname[MAXPATHLEN]; *pd++ = *ps++) 557 continue; 558 *pd = '\0'; 559 tw_env++; 560 return (tw_retname); 561 } /* end tw_envvar_next */ 562 563 564 /* tw_var_start(): 565 * Begin the list of the shell and environment variables 566 */ 567 /*ARGSUSED*/ 568 void 569 tw_var_start(dfd, pat) 570 DIR *dfd; 571 Char *pat; 572 { 573 USE(pat); 574 SETDIR(dfd) 575 tw_vptr_start(&shvhed); 576 tw_env = STR_environ; 577 } /* end tw_var_start */ 578 579 580 /* tw_alias_start(): 581 * Begin the list of the shell aliases 582 */ 583 /*ARGSUSED*/ 584 void 585 tw_alias_start(dfd, pat) 586 DIR *dfd; 587 Char *pat; 588 { 589 USE(pat); 590 SETDIR(dfd) 591 tw_vptr_start(&aliases); 592 tw_env = NULL; 593 } /* tw_alias_start */ 594 595 596 /* tw_complete_start(): 597 * Begin the list of completions 598 */ 599 /*ARGSUSED*/ 600 void 601 tw_complete_start(dfd, pat) 602 DIR *dfd; 603 Char *pat; 604 { 605 extern struct varent completions; 606 607 USE(pat); 608 SETDIR(dfd) 609 tw_vptr_start(&completions); 610 tw_env = NULL; 611 } /* end tw_complete_start */ 612 613 614 /* tw_var_next(): 615 * Return the next shell or environment variable 616 */ 617 Char * 618 tw_var_next(dir, flags) 619 Char *dir; 620 int *flags; 621 { 622 Char *ptr = NULL; 623 624 if (tw_vptr) 625 ptr = tw_shvar_next(dir, flags); 626 if (!ptr && tw_env) 627 ptr = tw_envvar_next(dir, flags); 628 return ptr; 629 } /* end tw_var_next */ 630 631 632 /* tw_logname_start(): 633 * Initialize lognames to the beginning of the list 634 */ 635 /*ARGSUSED*/ 636 void 637 tw_logname_start(dfd, pat) 638 DIR *dfd; 639 Char *pat; 640 { 641 USE(pat); 642 SETDIR(dfd) 643 #if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE) 644 (void) setpwent(); /* Open passwd file */ 645 #endif /* !_VMS_POSIX && !WINNT_NATIVE */ 646 } /* end tw_logname_start */ 647 648 649 /* tw_logname_next(): 650 * Return the next entry from the passwd file 651 */ 652 /*ARGSUSED*/ 653 Char * 654 tw_logname_next(dir, flags) 655 Char *dir; 656 int *flags; 657 { 658 static Char retname[MAXPATHLEN]; 659 struct passwd *pw; 660 /* 661 * We don't want to get interrupted inside getpwent() 662 * because the yellow pages code is not interruptible, 663 * and if we call endpwent() immediatetely after 664 * (in pintr()) we may be freeing an invalid pointer 665 */ 666 USE(flags); 667 USE(dir); 668 TW_HOLD(); 669 #if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE) 670 /* ISC does not declare getpwent()? */ 671 pw = (struct passwd *) getpwent(); 672 #else /* _VMS_POSIX || WINNT_NATIVE */ 673 pw = NULL; 674 #endif /* !_VMS_POSIX && !WINNT_NATIVE */ 675 TW_RELS(); 676 677 if (pw == NULL) { 678 #ifdef YPBUGS 679 fix_yp_bugs(); 680 #endif 681 return (NULL); 682 } 683 (void) Strcpy(retname, str2short(pw->pw_name)); 684 return (retname); 685 } /* end tw_logname_next */ 686 687 688 /* tw_logname_end(): 689 * Close the passwd file to finish the logname list 690 */ 691 void 692 tw_logname_end() 693 { 694 #ifdef YPBUGS 695 fix_yp_bugs(); 696 #endif 697 #if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE) 698 (void) endpwent(); 699 #endif /* !_VMS_POSIX && !WINNT_NATIVE */ 700 } /* end tw_logname_end */ 701 702 703 /* tw_grpname_start(): 704 * Initialize grpnames to the beginning of the list 705 */ 706 /*ARGSUSED*/ 707 void 708 tw_grpname_start(dfd, pat) 709 DIR *dfd; 710 Char *pat; 711 { 712 USE(pat); 713 SETDIR(dfd) 714 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) 715 (void) setgrent(); /* Open group file */ 716 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 717 } /* end tw_grpname_start */ 718 719 720 /* tw_grpname_next(): 721 * Return the next entry from the group file 722 */ 723 /*ARGSUSED*/ 724 Char * 725 tw_grpname_next(dir, flags) 726 Char *dir; 727 int *flags; 728 { 729 static Char retname[MAXPATHLEN]; 730 struct group *gr; 731 /* 732 * We don't want to get interrupted inside getgrent() 733 * because the yellow pages code is not interruptible, 734 * and if we call endgrent() immediatetely after 735 * (in pintr()) we may be freeing an invalid pointer 736 */ 737 USE(flags); 738 USE(dir); 739 TW_HOLD(); 740 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) 741 gr = (struct group *) getgrent(); 742 #else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */ 743 gr = NULL; 744 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 745 TW_RELS(); 746 747 if (gr == NULL) { 748 #ifdef YPBUGS 749 fix_yp_bugs(); 750 #endif 751 return (NULL); 752 } 753 (void) Strcpy(retname, str2short(gr->gr_name)); 754 return (retname); 755 } /* end tw_grpname_next */ 756 757 758 /* tw_grpname_end(): 759 * Close the group file to finish the groupname list 760 */ 761 void 762 tw_grpname_end() 763 { 764 #ifdef YPBUGS 765 fix_yp_bugs(); 766 #endif 767 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) 768 (void) endgrent(); 769 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 770 } /* end tw_grpname_end */ 771 772 /* tw_file_start(): 773 * Initialize the directory for the file list 774 */ 775 /*ARGSUSED*/ 776 void 777 tw_file_start(dfd, pat) 778 DIR *dfd; 779 Char *pat; 780 { 781 struct varent *vp; 782 USE(pat); 783 SETDIR(dfd) 784 if ((vp = adrof(STRcdpath)) != NULL) 785 tw_env = vp->vec; 786 } /* end tw_file_start */ 787 788 789 /* tw_file_next(): 790 * Return the next file in the directory 791 */ 792 Char * 793 tw_file_next(dir, flags) 794 Char *dir; 795 int *flags; 796 { 797 Char *ptr = tw_dir_next(tw_dir_fd); 798 if (ptr == NULL && (*flags & TW_DIR_OK) != 0) { 799 CLRDIR(tw_dir_fd) 800 while (tw_env && *tw_env) 801 if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL) 802 break; 803 else 804 tw_env++; 805 806 if (tw_dir_fd) { 807 copyn(dir, *tw_env++, MAXPATHLEN); 808 catn(dir, STRslash, MAXPATHLEN); 809 ptr = tw_dir_next(tw_dir_fd); 810 } 811 } 812 return ptr; 813 } /* end tw_file_next */ 814 815 816 /* tw_dir_end(): 817 * Clear directory related lists 818 */ 819 void 820 tw_dir_end() 821 { 822 CLRDIR(tw_dir_fd) 823 CLRDIR(tw_cmd_state.dfd) 824 } /* end tw_dir_end */ 825 826 827 /* tw_item_free(): 828 * Free the item list 829 */ 830 void 831 tw_item_free() 832 { 833 tw_str_free(&tw_item); 834 } /* end tw_item_free */ 835 836 837 /* tw_item_get(): 838 * Return the list of items 839 */ 840 Char ** 841 tw_item_get() 842 { 843 return tw_item.list; 844 } /* end tw_item_get */ 845 846 847 /* tw_item_add(): 848 * Return a new item 849 */ 850 Char * 851 tw_item_add(len) 852 int len; 853 { 854 return tw_str_add(&tw_item, len); 855 } /* tw_item_add */ 856 857 858 /* tw_item_find(): 859 * Find the string if it exists in the item list 860 * end return it. 861 */ 862 Char * 863 tw_item_find(str) 864 Char *str; 865 { 866 int i; 867 868 if (tw_item.list == NULL || str == NULL) 869 return NULL; 870 871 for (i = 0; i < tw_item.nlist; i++) 872 if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0) 873 return tw_item.list[i]; 874 return NULL; 875 } /* end tw_item_find */ 876 877 878 /* tw_vl_start(): 879 * Initialize a variable list 880 */ 881 void 882 tw_vl_start(dfd, pat) 883 DIR *dfd; 884 Char *pat; 885 { 886 SETDIR(dfd) 887 if ((tw_vptr = adrof(pat)) != NULL) { 888 tw_env = tw_vptr->vec; 889 tw_vptr = NULL; 890 } 891 else 892 tw_env = NULL; 893 } /* end tw_vl_start */ 894 895 896 /* 897 * Initialize a word list 898 */ 899 void 900 tw_wl_start(dfd, pat) 901 DIR *dfd; 902 Char *pat; 903 { 904 SETDIR(dfd); 905 tw_word = pat; 906 } /* end tw_wl_start */ 907 908 909 /* 910 * Return the next word from the word list 911 */ 912 /*ARGSUSED*/ 913 Char * 914 tw_wl_next(dir, flags) 915 Char *dir; 916 int *flags; 917 { 918 USE(flags); 919 if (tw_word == NULL || tw_word[0] == '\0') 920 return NULL; 921 922 while (*tw_word && Isspace(*tw_word)) tw_word++; 923 924 for (dir = tw_word; *tw_word && !Isspace(*tw_word); tw_word++) 925 continue; 926 if (*tw_word) 927 *tw_word++ = '\0'; 928 return *dir ? dir : NULL; 929 } /* end tw_wl_next */ 930 931 932 /* tw_bind_start(): 933 * Begin the list of the shell bindings 934 */ 935 /*ARGSUSED*/ 936 void 937 tw_bind_start(dfd, pat) 938 DIR *dfd; 939 Char *pat; 940 { 941 USE(pat); 942 SETDIR(dfd) 943 tw_bind = FuncNames; 944 } /* end tw_bind_start */ 945 946 947 /* tw_bind_next(): 948 * Begin the list of the shell bindings 949 */ 950 /*ARGSUSED*/ 951 Char * 952 tw_bind_next(dir, flags) 953 Char *dir; 954 int *flags; 955 { 956 char *ptr; 957 USE(flags); 958 if (tw_bind && tw_bind->name) { 959 for (ptr = tw_bind->name, dir = tw_retname; 960 (*dir++ = (Char) *ptr++) != '\0';) 961 continue; 962 tw_bind++; 963 return(tw_retname); 964 } 965 return NULL; 966 } /* end tw_bind_next */ 967 968 969 /* tw_limit_start(): 970 * Begin the list of the shell limitings 971 */ 972 /*ARGSUSED*/ 973 void 974 tw_limit_start(dfd, pat) 975 DIR *dfd; 976 Char *pat; 977 { 978 USE(pat); 979 SETDIR(dfd) 980 #ifndef HAVENOLIMIT 981 tw_limit = limits; 982 #endif /* ! HAVENOLIMIT */ 983 } /* end tw_limit_start */ 984 985 986 /* tw_limit_next(): 987 * Begin the list of the shell limitings 988 */ 989 /*ARGSUSED*/ 990 Char * 991 tw_limit_next(dir, flags) 992 Char *dir; 993 int *flags; 994 { 995 #ifndef HAVENOLIMIT 996 char *ptr; 997 if (tw_limit && tw_limit->limname) { 998 for (ptr = tw_limit->limname, dir = tw_retname; 999 (*dir++ = (Char) *ptr++) != '\0';) 1000 continue; 1001 tw_limit++; 1002 return(tw_retname); 1003 } 1004 #endif /* ! HAVENOLIMIT */ 1005 USE(flags); 1006 return NULL; 1007 } /* end tw_limit_next */ 1008 1009 1010 /* tw_sig_start(): 1011 * Begin the list of the shell sigings 1012 */ 1013 /*ARGSUSED*/ 1014 void 1015 tw_sig_start(dfd, pat) 1016 DIR *dfd; 1017 Char *pat; 1018 { 1019 USE(pat); 1020 SETDIR(dfd) 1021 tw_index = 0; 1022 } /* end tw_sig_start */ 1023 1024 1025 /* tw_sig_next(): 1026 * Begin the list of the shell sigings 1027 */ 1028 /*ARGSUSED*/ 1029 Char * 1030 tw_sig_next(dir, flags) 1031 Char *dir; 1032 int *flags; 1033 { 1034 char *ptr; 1035 extern int nsig; 1036 USE(flags); 1037 for (;tw_index < nsig; tw_index++) { 1038 1039 if (mesg[tw_index].iname == NULL) 1040 continue; 1041 1042 for (ptr = mesg[tw_index].iname, dir = tw_retname; 1043 (*dir++ = (Char) *ptr++) != '\0';) 1044 continue; 1045 tw_index++; 1046 return(tw_retname); 1047 } 1048 return NULL; 1049 } /* end tw_sig_next */ 1050 1051 1052 /* tw_job_start(): 1053 * Begin the list of the shell jobings 1054 */ 1055 /*ARGSUSED*/ 1056 void 1057 tw_job_start(dfd, pat) 1058 DIR *dfd; 1059 Char *pat; 1060 { 1061 USE(pat); 1062 SETDIR(dfd) 1063 tw_index = 1; 1064 } /* end tw_job_start */ 1065 1066 1067 /* tw_job_next(): 1068 * Begin the list of the shell jobings 1069 */ 1070 /*ARGSUSED*/ 1071 Char * 1072 tw_job_next(dir, flags) 1073 Char *dir; 1074 int *flags; 1075 { 1076 Char *ptr; 1077 struct process *j; 1078 1079 USE(flags); 1080 for (;tw_index <= pmaxindex; tw_index++) { 1081 for (j = proclist.p_next; j != NULL; j = j->p_next) 1082 if (j->p_index == tw_index && j->p_procid == j->p_jobid) 1083 break; 1084 if (j == NULL) 1085 continue; 1086 for (ptr = j->p_command, dir = tw_retname; (*dir++ = *ptr++) != '\0';) 1087 continue; 1088 *dir = '\0'; 1089 tw_index++; 1090 return(tw_retname); 1091 } 1092 return NULL; 1093 } /* end tw_job_next */ 1094