tw.init.c revision 316958
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 35RCSID("$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 44typedef 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 54static struct varent *tw_vptr = NULL; /* Current shell variable */ 55static Char **tw_env = NULL; /* Current environment variable */ 56static const Char *tw_word; /* Current word pointer */ 57static struct KeyFuncs *tw_bind = NULL; /* List of the bindings */ 58#ifndef HAVENOLIMIT 59static struct limits *tw_limit = NULL; /* List of the resource limits */ 60#endif /* HAVENOLIMIT */ 61static int tw_index = 0; /* signal and job index */ 62static DIR *tw_dir_fd = NULL; /* Current directory descriptor */ 63static int tw_cmd_got = 0; /* What we need to do */ 64static stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 }; 65static 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 72static 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 94static Char *tw_str_add (stringlist_t *, size_t); 95static void tw_str_free (stringlist_t *); 96static int tw_dir_next (struct Strbuf *, DIR *); 97static void tw_cmd_add (const Char *name); 98static void tw_cmd_cmd (void); 99static void tw_cmd_builtin (void); 100static void tw_cmd_alias (void); 101static void tw_cmd_sort (void); 102static void tw_vptr_start (struct varent *); 103 104 105/* tw_str_add(): 106 * Add an item to the string list 107 */ 108static Char * 109tw_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 */ 142static void 143tw_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 160static int 161tw_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 */ 179static void 180tw_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 */ 192void 193tw_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 */ 203static void 204tw_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 */ 267static void 268tw_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 */ 286static void 287tw_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; 296x: 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 */ 317static void 318tw_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*/ 346void 347tw_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 */ 390int 391tw_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 */ 443static void 444tw_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; 451x: 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*/ 475int 476tw_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*/ 517int 518tw_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*/ 538void 539tw_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*/ 552void 553tw_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*/ 566void 567tw_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 */ 579int 580tw_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*/ 596void 597tw_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*/ 611int 612tw_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 */ 646void 647tw_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*/ 662void 663tw_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*/ 677int 678tw_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 */ 716void 717tw_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*/ 731void 732tw_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 */ 745int 746tw_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 */ 772void 773tw_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 */ 783void 784tw_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 */ 793Char ** 794tw_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 */ 803void 804tw_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 */ 817Char * 818tw_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 */ 835void 836tw_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 */ 851void 852tw_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*/ 863int 864tw_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*/ 890void 891tw_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*/ 903int 904tw_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*/ 924void 925tw_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*/ 939int 940tw_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*/ 962void 963tw_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*/ 975int 976tw_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*/ 999void 1000tw_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*/ 1012int 1013tw_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