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