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