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