tw.init.c revision 231990
1231990Smp/* $Header: /p/tcsh/cvsroot/tcsh/tw.init.c,v 3.42 2011/04/17 14:49:30 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tw.init.c: Handle lists of things to complete 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35231990SmpRCSID("$tcsh: tw.init.c,v 3.42 2011/04/17 14:49:30 christos Exp $") 3659243Sobrien 3759243Sobrien#include "tw.h" 3859243Sobrien#include "ed.h" 3959243Sobrien#include "tc.h" 4059243Sobrien#include "sh.proc.h" 4159243Sobrien 4259243Sobrien#define TW_INCR 128 4359243Sobrien 4459243Sobrientypedef struct { 4559243Sobrien Char **list, /* List of command names */ 4659243Sobrien *buff; /* Space holding command names */ 47167465Smp size_t nlist, /* Number of items */ 4859243Sobrien nbuff, /* Current space in name buf */ 4959243Sobrien tlist, /* Total space in list */ 5059243Sobrien tbuff; /* Total space in name buf */ 5159243Sobrien} stringlist_t; 5259243Sobrien 5359243Sobrien 5459243Sobrienstatic struct varent *tw_vptr = NULL; /* Current shell variable */ 5559243Sobrienstatic Char **tw_env = NULL; /* Current environment variable */ 56167465Smpstatic const Char *tw_word; /* Current word pointer */ 5759243Sobrienstatic struct KeyFuncs *tw_bind = NULL; /* List of the bindings */ 5859243Sobrien#ifndef HAVENOLIMIT 5959243Sobrienstatic struct limits *tw_limit = NULL; /* List of the resource limits */ 6059243Sobrien#endif /* HAVENOLIMIT */ 6159243Sobrienstatic int tw_index = 0; /* signal and job index */ 6259243Sobrienstatic DIR *tw_dir_fd = NULL; /* Current directory descriptor */ 6359243Sobrienstatic int tw_cmd_got = 0; /* What we need to do */ 6459243Sobrienstatic stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 }; 6559243Sobrienstatic stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 }; 6659243Sobrien#define TW_FL_CMD 0x01 6759243Sobrien#define TW_FL_ALIAS 0x02 6859243Sobrien#define TW_FL_BUILTIN 0x04 6959243Sobrien#define TW_FL_SORT 0x08 7059243Sobrien#define TW_FL_REL 0x10 7159243Sobrien 7259243Sobrienstatic struct { /* Current element pointer */ 73167465Smp size_t cur; /* Current element number */ 7459243Sobrien Char **pathv; /* Current element in path */ 7559243Sobrien DIR *dfd; /* Current directory descriptor */ 7659243Sobrien} tw_cmd_state; 7759243Sobrien 7859243Sobrien 7959243Sobrien#define SETDIR(dfd) \ 8059243Sobrien { \ 8159243Sobrien tw_dir_fd = dfd; \ 8259243Sobrien if (tw_dir_fd != NULL) \ 8359243Sobrien rewinddir(tw_dir_fd); \ 8459243Sobrien } 8559243Sobrien 8659243Sobrien#define CLRDIR(dfd) \ 8759243Sobrien if (dfd != NULL) { \ 88167465Smp pintr_disabled++; \ 89167465Smp xclosedir(dfd); \ 9059243Sobrien dfd = NULL; \ 91167465Smp disabled_cleanup(&pintr_disabled); \ 9259243Sobrien } 9359243Sobrien 94167465Smpstatic Char *tw_str_add (stringlist_t *, size_t); 95167465Smpstatic void tw_str_free (stringlist_t *); 96167465Smpstatic int tw_dir_next (struct Strbuf *, DIR *); 97167465Smpstatic void tw_cmd_add (const Char *name); 98167465Smpstatic void tw_cmd_cmd (void); 99167465Smpstatic void tw_cmd_builtin (void); 100167465Smpstatic void tw_cmd_alias (void); 101167465Smpstatic void tw_cmd_sort (void); 102167465Smpstatic void tw_vptr_start (struct varent *); 10359243Sobrien 10459243Sobrien 10559243Sobrien/* tw_str_add(): 10659243Sobrien * Add an item to the string list 10759243Sobrien */ 10859243Sobrienstatic Char * 109167465Smptw_str_add(stringlist_t *sl, size_t len) 11059243Sobrien{ 11159243Sobrien Char *ptr; 11259243Sobrien 11359243Sobrien if (sl->tlist <= sl->nlist) { 114167465Smp pintr_disabled++; 11559243Sobrien sl->tlist += TW_INCR; 116167465Smp sl->list = xrealloc(sl->list, sl->tlist * sizeof(Char *)); 117167465Smp disabled_cleanup(&pintr_disabled); 11859243Sobrien } 11959243Sobrien if (sl->tbuff <= sl->nbuff + len) { 120167465Smp size_t i; 121167465Smp 12259243Sobrien ptr = sl->buff; 123167465Smp pintr_disabled++; 12459243Sobrien sl->tbuff += TW_INCR + len; 125167465Smp sl->buff = xrealloc(sl->buff, sl->tbuff * sizeof(Char)); 12659243Sobrien /* Re-thread the new pointer list, if changed */ 12759243Sobrien if (ptr != NULL && ptr != sl->buff) { 128145479Smp intptr_t offs = sl->buff - ptr; 12959243Sobrien for (i = 0; i < sl->nlist; i++) 13059243Sobrien sl->list[i] += offs; 13159243Sobrien } 132167465Smp disabled_cleanup(&pintr_disabled); 13359243Sobrien } 13459243Sobrien ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff]; 13559243Sobrien sl->nbuff += len; 13659243Sobrien return ptr; 13759243Sobrien} /* tw_str_add */ 13859243Sobrien 13959243Sobrien 14059243Sobrien/* tw_str_free(): 14159243Sobrien * Free a stringlist 14259243Sobrien */ 14359243Sobrienstatic void 144167465Smptw_str_free(stringlist_t *sl) 14559243Sobrien{ 146167465Smp pintr_disabled++; 14759243Sobrien if (sl->list) { 148167465Smp xfree(sl->list); 14959243Sobrien sl->list = NULL; 15059243Sobrien sl->tlist = sl->nlist = 0; 15159243Sobrien } 15259243Sobrien if (sl->buff) { 153167465Smp xfree(sl->buff); 15459243Sobrien sl->buff = NULL; 15559243Sobrien sl->tbuff = sl->nbuff = 0; 15659243Sobrien } 157167465Smp disabled_cleanup(&pintr_disabled); 15859243Sobrien} /* end tw_str_free */ 15959243Sobrien 16059243Sobrien 161167465Smpstatic int 162167465Smptw_dir_next(struct Strbuf *res, DIR *dfd) 16359243Sobrien{ 164145479Smp struct dirent *dirp; 16559243Sobrien 16659243Sobrien if (dfd == NULL) 167167465Smp return 0; 16859243Sobrien 16959243Sobrien if ((dirp = readdir(dfd)) != NULL) { 170167465Smp Strbuf_append(res, str2short(dirp->d_name)); 171167465Smp return 1; 17259243Sobrien } 173167465Smp return 0; 17459243Sobrien} /* end tw_dir_next */ 17559243Sobrien 17659243Sobrien 17759243Sobrien/* tw_cmd_add(): 17859243Sobrien * Add the name to the command list 17959243Sobrien */ 18059243Sobrienstatic void 181167465Smptw_cmd_add(const Char *name) 18259243Sobrien{ 183167465Smp size_t len; 18459243Sobrien 185167465Smp len = Strlen(name) + 2; 18659243Sobrien (void) Strcpy(tw_str_add(&tw_cmd, len), name); 18759243Sobrien} /* end tw_cmd_add */ 18859243Sobrien 18959243Sobrien 19059243Sobrien/* tw_cmd_free(): 19159243Sobrien * Free the command list 19259243Sobrien */ 19359243Sobrienvoid 194167465Smptw_cmd_free(void) 19559243Sobrien{ 19659243Sobrien CLRDIR(tw_dir_fd) 19759243Sobrien tw_str_free(&tw_cmd); 19859243Sobrien tw_cmd_got = 0; 19959243Sobrien} /* end tw_cmd_free */ 20059243Sobrien 20159243Sobrien/* tw_cmd_cmd(): 20259243Sobrien * Add system commands to the command list 20359243Sobrien */ 20459243Sobrienstatic void 205167465Smptw_cmd_cmd(void) 20659243Sobrien{ 207145479Smp DIR *dirp; 208145479Smp struct dirent *dp; 209145479Smp Char *dir = NULL, *name; 210145479Smp Char **pv; 21159243Sobrien struct varent *v = adrof(STRpath); 21259243Sobrien struct varent *recexec = adrof(STRrecognize_only_executables); 213167465Smp size_t len; 21459243Sobrien 21559243Sobrien 216100616Smp if (v == NULL || v->vec == NULL) /* if no path */ 21759243Sobrien return; 21859243Sobrien 21959243Sobrien for (pv = v->vec; *pv; pv++) { 22059243Sobrien if (pv[0][0] != '/') { 22159243Sobrien tw_cmd_got |= TW_FL_REL; 22259243Sobrien continue; 22359243Sobrien } 22459243Sobrien 22559243Sobrien if ((dirp = opendir(short2str(*pv))) == NULL) 22659243Sobrien continue; 22759243Sobrien 228167465Smp cleanup_push(dirp, opendir_cleanup); 229167465Smp if (recexec) { 23059243Sobrien dir = Strspl(*pv, STRslash); 231167465Smp cleanup_push(dir, xfree); 232167465Smp } 23359243Sobrien while ((dp = readdir(dirp)) != NULL) { 23469408Sache#if defined(_UWIN) || defined(__CYGWIN__) 23569408Sache /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 23669408Sache * the file with the .exe, .com, .bat extension 237231990Smp * 238231990Smp * Same for Cygwin, but only for .exe and .com extension. 23969408Sache */ 240167465Smp len = strlen(dp->d_name); 241167465Smp if (len > 4 && (strcmp(&dp->d_name[len - 4], ".exe") == 0 || 242231990Smp#ifndef __CYGWIN__ 243167465Smp strcmp(&dp->d_name[len - 4], ".bat") == 0 || 244231990Smp#endif /* !__CYGWIN__ */ 245167465Smp strcmp(&dp->d_name[len - 4], ".com") == 0)) 246167465Smp dp->d_name[len - 4] = '\0'; 24769408Sache#endif /* _UWIN || __CYGWIN__ */ 24859243Sobrien /* the call to executable() may make this a bit slow */ 24959243Sobrien name = str2short(dp->d_name); 25059243Sobrien if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0))) 25159243Sobrien continue; 252167465Smp len = Strlen(name); 25359243Sobrien if (name[0] == '#' || /* emacs temp files */ 25459243Sobrien name[0] == '.' || /* .files */ 255167465Smp name[len - 1] == '~' || /* emacs backups */ 256167465Smp name[len - 1] == '%') /* textedit backups */ 25759243Sobrien continue; /* Ignore! */ 25859243Sobrien tw_cmd_add(name); 25959243Sobrien } 260167465Smp cleanup_until(dirp); 26159243Sobrien } 26259243Sobrien} /* end tw_cmd_cmd */ 26359243Sobrien 26459243Sobrien 26559243Sobrien/* tw_cmd_builtin(): 26659243Sobrien * Add builtins to the command list 26759243Sobrien */ 26859243Sobrienstatic void 269167465Smptw_cmd_builtin(void) 27059243Sobrien{ 271167465Smp const struct biltins *bptr; 27259243Sobrien 27359243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) 27459243Sobrien if (bptr->bname) 27559243Sobrien tw_cmd_add(str2short(bptr->bname)); 27669408Sache#ifdef WINNT_NATIVE 27759243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) 27859243Sobrien if (bptr->bname) 27959243Sobrien tw_cmd_add(str2short(bptr->bname)); 28069408Sache#endif /* WINNT_NATIVE*/ 28159243Sobrien} /* end tw_cmd_builtin */ 28259243Sobrien 28359243Sobrien 28459243Sobrien/* tw_cmd_alias(): 28559243Sobrien * Add aliases to the command list 28659243Sobrien */ 28759243Sobrienstatic void 288167465Smptw_cmd_alias(void) 28959243Sobrien{ 290145479Smp struct varent *p; 291145479Smp struct varent *c; 29259243Sobrien 29359243Sobrien p = &aliases; 29459243Sobrien for (;;) { 29559243Sobrien while (p->v_left) 29659243Sobrien p = p->v_left; 29759243Sobrienx: 29859243Sobrien if (p->v_parent == 0) /* is it the header? */ 29959243Sobrien return; 30059243Sobrien if (p->v_name) 30159243Sobrien tw_cmd_add(p->v_name); 30259243Sobrien if (p->v_right) { 30359243Sobrien p = p->v_right; 30459243Sobrien continue; 30559243Sobrien } 30659243Sobrien do { 30759243Sobrien c = p; 30859243Sobrien p = p->v_parent; 30959243Sobrien } while (p->v_right == c); 31059243Sobrien goto x; 31159243Sobrien } 31259243Sobrien} /* end tw_cmd_alias */ 31359243Sobrien 31459243Sobrien 31559243Sobrien/* tw_cmd_sort(): 31659243Sobrien * Sort the command list removing duplicate elements 31759243Sobrien */ 31859243Sobrienstatic void 319167465Smptw_cmd_sort(void) 32059243Sobrien{ 321167465Smp size_t fwd, i; 32259243Sobrien 323167465Smp pintr_disabled++; 32459243Sobrien /* sort the list. */ 325167465Smp qsort(tw_cmd.list, tw_cmd.nlist, sizeof(Char *), fcompare); 32659243Sobrien 32759243Sobrien /* get rid of multiple entries */ 328167465Smp for (i = 0, fwd = 0; i + 1 < tw_cmd.nlist; i++) { 32959243Sobrien if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */ 33059243Sobrien fwd++; /* increase the forward ref. count */ 33159243Sobrien else if (fwd) 33259243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 33359243Sobrien } 33459243Sobrien /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */ 33559243Sobrien if (fwd) 33659243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 33759243Sobrien tw_cmd.nlist -= fwd; 338167465Smp disabled_cleanup(&pintr_disabled); 33959243Sobrien} /* end tw_cmd_sort */ 34059243Sobrien 34159243Sobrien 34259243Sobrien/* tw_cmd_start(): 34359243Sobrien * Get the command list and sort it, if not done yet. 34459243Sobrien * Reset the current pointer to the beginning of the command list 34559243Sobrien */ 34659243Sobrien/*ARGSUSED*/ 34759243Sobrienvoid 348167465Smptw_cmd_start(DIR *dfd, const Char *pat) 34959243Sobrien{ 35059243Sobrien static Char *defpath[] = { STRNULL, 0 }; 35159243Sobrien USE(pat); 35259243Sobrien SETDIR(dfd) 35359243Sobrien if ((tw_cmd_got & TW_FL_CMD) == 0) { 35459243Sobrien tw_cmd_free(); 35559243Sobrien tw_cmd_cmd(); 35659243Sobrien tw_cmd_got |= TW_FL_CMD; 35759243Sobrien } 35859243Sobrien if ((tw_cmd_got & TW_FL_ALIAS) == 0) { 35959243Sobrien tw_cmd_alias(); 36059243Sobrien tw_cmd_got &= ~TW_FL_SORT; 36159243Sobrien tw_cmd_got |= TW_FL_ALIAS; 36259243Sobrien } 36359243Sobrien if ((tw_cmd_got & TW_FL_BUILTIN) == 0) { 36459243Sobrien tw_cmd_builtin(); 36559243Sobrien tw_cmd_got &= ~TW_FL_SORT; 36659243Sobrien tw_cmd_got |= TW_FL_BUILTIN; 36759243Sobrien } 36859243Sobrien if ((tw_cmd_got & TW_FL_SORT) == 0) { 36959243Sobrien tw_cmd_sort(); 37059243Sobrien tw_cmd_got |= TW_FL_SORT; 37159243Sobrien } 37259243Sobrien 37359243Sobrien tw_cmd_state.cur = 0; 37459243Sobrien CLRDIR(tw_cmd_state.dfd) 37559243Sobrien if (tw_cmd_got & TW_FL_REL) { 37659243Sobrien struct varent *vp = adrof(STRpath); 37759243Sobrien if (vp && vp->vec) 37859243Sobrien tw_cmd_state.pathv = vp->vec; 37959243Sobrien else 38059243Sobrien tw_cmd_state.pathv = defpath; 38159243Sobrien } 38259243Sobrien else 38359243Sobrien tw_cmd_state.pathv = defpath; 38459243Sobrien} /* tw_cmd_start */ 38559243Sobrien 38659243Sobrien 38759243Sobrien/* tw_cmd_next(): 38859243Sobrien * Return the next element in the command list or 38959243Sobrien * Look for commands in the relative path components 39059243Sobrien */ 391167465Smpint 392167465Smptw_cmd_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 39359243Sobrien{ 394167465Smp int ret = 0; 395167465Smp Char *ptr; 39659243Sobrien 39759243Sobrien if (tw_cmd_state.cur < tw_cmd.nlist) { 39859243Sobrien *flags = TW_DIR_OK; 399167465Smp Strbuf_append(res, tw_cmd.list[tw_cmd_state.cur++]); 400167465Smp return 1; 40159243Sobrien } 40259243Sobrien 40359243Sobrien /* 40459243Sobrien * We need to process relatives in the path. 40559243Sobrien */ 406167465Smp while ((tw_cmd_state.dfd == NULL || 407231990Smp (res->len = 0, ret = tw_dir_next(res, tw_cmd_state.dfd)) == 0) && 408167465Smp *tw_cmd_state.pathv != NULL) { 40959243Sobrien 41059243Sobrien CLRDIR(tw_cmd_state.dfd) 41159243Sobrien 41259243Sobrien while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/') 41359243Sobrien tw_cmd_state.pathv++; 41459243Sobrien if ((ptr = *tw_cmd_state.pathv) != 0) { 415231990Smp res->len = 0; 416167465Smp Strbuf_append(res, ptr); 417167465Smp ret = 1; 41859243Sobrien /* 41959243Sobrien * We complete directories only on '.' should that 42059243Sobrien * be changed? 42159243Sobrien */ 422167465Smp dir->len = 0; 42359243Sobrien if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) { 42459243Sobrien tw_cmd_state.dfd = opendir("."); 425167465Smp *flags = TW_DIR_OK | TW_EXEC_CHK; 42659243Sobrien } 42759243Sobrien else { 428167465Smp Strbuf_append(dir, *tw_cmd_state.pathv); 429167465Smp Strbuf_append1(dir, '/'); 43059243Sobrien tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv)); 43159243Sobrien *flags = TW_EXEC_CHK; 43259243Sobrien } 433167465Smp Strbuf_terminate(dir); 43459243Sobrien tw_cmd_state.pathv++; 43559243Sobrien } 43659243Sobrien } 437167465Smp return ret; 43859243Sobrien} /* end tw_cmd_next */ 43959243Sobrien 44059243Sobrien 44159243Sobrien/* tw_vptr_start(): 44259243Sobrien * Find the first variable in the variable list 44359243Sobrien */ 44459243Sobrienstatic void 445167465Smptw_vptr_start(struct varent *c) 44659243Sobrien{ 44759243Sobrien tw_vptr = c; /* start at beginning of variable list */ 44859243Sobrien 44959243Sobrien for (;;) { 45059243Sobrien while (tw_vptr->v_left) 45159243Sobrien tw_vptr = tw_vptr->v_left; 45259243Sobrienx: 45359243Sobrien if (tw_vptr->v_parent == 0) { /* is it the header? */ 45459243Sobrien tw_vptr = NULL; 45559243Sobrien return; 45659243Sobrien } 45759243Sobrien if (tw_vptr->v_name) 45859243Sobrien return; /* found first one */ 45959243Sobrien if (tw_vptr->v_right) { 46059243Sobrien tw_vptr = tw_vptr->v_right; 46159243Sobrien continue; 46259243Sobrien } 46359243Sobrien do { 46459243Sobrien c = tw_vptr; 46559243Sobrien tw_vptr = tw_vptr->v_parent; 46659243Sobrien } while (tw_vptr->v_right == c); 46759243Sobrien goto x; 46859243Sobrien } 46959243Sobrien} /* end tw_shvar_start */ 47059243Sobrien 47159243Sobrien 47259243Sobrien/* tw_shvar_next(): 47359243Sobrien * Return the next shell variable 47459243Sobrien */ 47559243Sobrien/*ARGSUSED*/ 476167465Smpint 477167465Smptw_shvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 47859243Sobrien{ 479145479Smp struct varent *p; 480145479Smp struct varent *c; 48159243Sobrien 48259243Sobrien USE(flags); 48359243Sobrien USE(dir); 48459243Sobrien if ((p = tw_vptr) == NULL) 485167465Smp return 0; /* just in case */ 48659243Sobrien 487167465Smp Strbuf_append(res, p->v_name); /* we know that this name is here now */ 48859243Sobrien 48959243Sobrien /* now find the next one */ 49059243Sobrien for (;;) { 49159243Sobrien if (p->v_right) { /* if we can go right */ 49259243Sobrien p = p->v_right; 49359243Sobrien while (p->v_left) 49459243Sobrien p = p->v_left; 49559243Sobrien } 49659243Sobrien else { /* else go up */ 49759243Sobrien do { 49859243Sobrien c = p; 49959243Sobrien p = p->v_parent; 50059243Sobrien } while (p->v_right == c); 50159243Sobrien } 50259243Sobrien if (p->v_parent == 0) { /* is it the header? */ 50359243Sobrien tw_vptr = NULL; 504167465Smp return 1; 50559243Sobrien } 50659243Sobrien if (p->v_name) { 50759243Sobrien tw_vptr = p; /* save state for the next call */ 508167465Smp return 1; 50959243Sobrien } 51059243Sobrien } 51159243Sobrien} /* end tw_shvar_next */ 51259243Sobrien 51359243Sobrien 51459243Sobrien/* tw_envvar_next(): 51559243Sobrien * Return the next environment variable 51659243Sobrien */ 51759243Sobrien/*ARGSUSED*/ 518167465Smpint 519167465Smptw_envvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 52059243Sobrien{ 521167465Smp const Char *ps; 52259243Sobrien 52359243Sobrien USE(flags); 52459243Sobrien USE(dir); 52559243Sobrien if (tw_env == NULL || *tw_env == NULL) 526167465Smp return 0; 527167465Smp for (ps = *tw_env; *ps && *ps != '='; ps++) 52859243Sobrien continue; 529167465Smp Strbuf_appendn(res, *tw_env, ps - *tw_env); 53059243Sobrien tw_env++; 531167465Smp return 1; 53259243Sobrien} /* end tw_envvar_next */ 53359243Sobrien 53459243Sobrien 53559243Sobrien/* tw_var_start(): 53659243Sobrien * Begin the list of the shell and environment variables 53759243Sobrien */ 53859243Sobrien/*ARGSUSED*/ 53959243Sobrienvoid 540167465Smptw_var_start(DIR *dfd, const Char *pat) 54159243Sobrien{ 54259243Sobrien USE(pat); 54359243Sobrien SETDIR(dfd) 54459243Sobrien tw_vptr_start(&shvhed); 54559243Sobrien tw_env = STR_environ; 54659243Sobrien} /* end tw_var_start */ 54759243Sobrien 54859243Sobrien 54959243Sobrien/* tw_alias_start(): 55059243Sobrien * Begin the list of the shell aliases 55159243Sobrien */ 55259243Sobrien/*ARGSUSED*/ 55359243Sobrienvoid 554167465Smptw_alias_start(DIR *dfd, const Char *pat) 55559243Sobrien{ 55659243Sobrien USE(pat); 55759243Sobrien SETDIR(dfd) 55859243Sobrien tw_vptr_start(&aliases); 55959243Sobrien tw_env = NULL; 56059243Sobrien} /* tw_alias_start */ 56159243Sobrien 56259243Sobrien 56359243Sobrien/* tw_complete_start(): 56459243Sobrien * Begin the list of completions 56559243Sobrien */ 56659243Sobrien/*ARGSUSED*/ 56759243Sobrienvoid 568167465Smptw_complete_start(DIR *dfd, const Char *pat) 56959243Sobrien{ 57059243Sobrien USE(pat); 57159243Sobrien SETDIR(dfd) 57259243Sobrien tw_vptr_start(&completions); 57359243Sobrien tw_env = NULL; 57459243Sobrien} /* end tw_complete_start */ 57559243Sobrien 57659243Sobrien 57759243Sobrien/* tw_var_next(): 57859243Sobrien * Return the next shell or environment variable 57959243Sobrien */ 580167465Smpint 581167465Smptw_var_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 58259243Sobrien{ 583167465Smp int ret = 0; 58459243Sobrien 58559243Sobrien if (tw_vptr) 586167465Smp ret = tw_shvar_next(res, dir, flags); 587167465Smp if (ret == 0 && tw_env) 588167465Smp ret = tw_envvar_next(res, dir, flags); 589167465Smp return ret; 59059243Sobrien} /* end tw_var_next */ 59159243Sobrien 59259243Sobrien 59359243Sobrien/* tw_logname_start(): 59459243Sobrien * Initialize lognames to the beginning of the list 59559243Sobrien */ 59659243Sobrien/*ARGSUSED*/ 59759243Sobrienvoid 598167465Smptw_logname_start(DIR *dfd, const Char *pat) 59959243Sobrien{ 60059243Sobrien USE(pat); 60159243Sobrien SETDIR(dfd) 602145479Smp#ifdef HAVE_GETPWENT 60359243Sobrien (void) setpwent(); /* Open passwd file */ 604145479Smp#endif 60559243Sobrien} /* end tw_logname_start */ 60659243Sobrien 60759243Sobrien 60859243Sobrien/* tw_logname_next(): 60959243Sobrien * Return the next entry from the passwd file 61059243Sobrien */ 61159243Sobrien/*ARGSUSED*/ 612167465Smpint 613167465Smptw_logname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 61459243Sobrien{ 61559243Sobrien struct passwd *pw; 616167465Smp 61759243Sobrien /* 61859243Sobrien * We don't want to get interrupted inside getpwent() 61959243Sobrien * because the yellow pages code is not interruptible, 62059243Sobrien * and if we call endpwent() immediatetely after 62159243Sobrien * (in pintr()) we may be freeing an invalid pointer 62259243Sobrien */ 62359243Sobrien USE(flags); 62459243Sobrien USE(dir); 625167465Smp pintr_disabled++; 626145479Smp#ifdef HAVE_GETPWENT 627145479Smp pw = getpwent(); 628145479Smp#else 62959243Sobrien pw = NULL; 630145479Smp#endif 631167465Smp disabled_cleanup(&pintr_disabled); 63259243Sobrien 63359243Sobrien if (pw == NULL) { 63459243Sobrien#ifdef YPBUGS 63559243Sobrien fix_yp_bugs(); 63659243Sobrien#endif 637167465Smp return 0; 63859243Sobrien } 639167465Smp Strbuf_append(res, str2short(pw->pw_name)); 640167465Smp return 1; 64159243Sobrien} /* end tw_logname_next */ 64259243Sobrien 64359243Sobrien 64459243Sobrien/* tw_logname_end(): 64559243Sobrien * Close the passwd file to finish the logname list 64659243Sobrien */ 64759243Sobrienvoid 648167465Smptw_logname_end(void) 64959243Sobrien{ 65059243Sobrien#ifdef YPBUGS 65159243Sobrien fix_yp_bugs(); 65259243Sobrien#endif 653145479Smp#ifdef HAVE_GETPWENT 65459243Sobrien (void) endpwent(); 655145479Smp#endif 65659243Sobrien} /* end tw_logname_end */ 65759243Sobrien 65859243Sobrien 65959243Sobrien/* tw_grpname_start(): 66059243Sobrien * Initialize grpnames to the beginning of the list 66159243Sobrien */ 66259243Sobrien/*ARGSUSED*/ 66359243Sobrienvoid 664167465Smptw_grpname_start(DIR *dfd, const Char *pat) 66559243Sobrien{ 66659243Sobrien USE(pat); 66759243Sobrien SETDIR(dfd) 668231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 66959243Sobrien (void) setgrent(); /* Open group file */ 67069408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 67159243Sobrien} /* end tw_grpname_start */ 67259243Sobrien 67359243Sobrien 67459243Sobrien/* tw_grpname_next(): 67559243Sobrien * Return the next entry from the group file 67659243Sobrien */ 67759243Sobrien/*ARGSUSED*/ 678167465Smpint 679167465Smptw_grpname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 68059243Sobrien{ 68159243Sobrien struct group *gr; 682167465Smp 68359243Sobrien /* 68459243Sobrien * We don't want to get interrupted inside getgrent() 68559243Sobrien * because the yellow pages code is not interruptible, 68659243Sobrien * and if we call endgrent() immediatetely after 68759243Sobrien * (in pintr()) we may be freeing an invalid pointer 68859243Sobrien */ 68959243Sobrien USE(flags); 69059243Sobrien USE(dir); 691167465Smp pintr_disabled++; 692231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined(__ANDROID__) 693167465Smp errno = 0; 694167465Smp while ((gr = getgrent()) == NULL && errno == EINTR) { 695167465Smp handle_pending_signals(); 696167465Smp errno = 0; 697167465Smp } 69869408Sache#else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */ 69959243Sobrien gr = NULL; 70069408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 701167465Smp disabled_cleanup(&pintr_disabled); 70259243Sobrien 70359243Sobrien if (gr == NULL) { 70459243Sobrien#ifdef YPBUGS 70559243Sobrien fix_yp_bugs(); 70659243Sobrien#endif 707167465Smp return 0; 70859243Sobrien } 709167465Smp Strbuf_append(res, str2short(gr->gr_name)); 710167465Smp return 1; 71159243Sobrien} /* end tw_grpname_next */ 71259243Sobrien 71359243Sobrien 71459243Sobrien/* tw_grpname_end(): 71559243Sobrien * Close the group file to finish the groupname list 71659243Sobrien */ 71759243Sobrienvoid 718167465Smptw_grpname_end(void) 71959243Sobrien{ 72059243Sobrien#ifdef YPBUGS 72159243Sobrien fix_yp_bugs(); 72259243Sobrien#endif 723231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 72459243Sobrien (void) endgrent(); 72569408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 72659243Sobrien} /* end tw_grpname_end */ 72759243Sobrien 72859243Sobrien/* tw_file_start(): 72959243Sobrien * Initialize the directory for the file list 73059243Sobrien */ 73159243Sobrien/*ARGSUSED*/ 73259243Sobrienvoid 733167465Smptw_file_start(DIR *dfd, const Char *pat) 73459243Sobrien{ 73559243Sobrien struct varent *vp; 73659243Sobrien USE(pat); 73759243Sobrien SETDIR(dfd) 73859243Sobrien if ((vp = adrof(STRcdpath)) != NULL) 73959243Sobrien tw_env = vp->vec; 74059243Sobrien} /* end tw_file_start */ 74159243Sobrien 74259243Sobrien 74359243Sobrien/* tw_file_next(): 74459243Sobrien * Return the next file in the directory 74559243Sobrien */ 746167465Smpint 747167465Smptw_file_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 74859243Sobrien{ 749167465Smp int ret = tw_dir_next(res, tw_dir_fd); 750167465Smp if (ret == 0 && (*flags & TW_DIR_OK) != 0) { 75159243Sobrien CLRDIR(tw_dir_fd) 75259243Sobrien while (tw_env && *tw_env) 75359243Sobrien if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL) 75459243Sobrien break; 75559243Sobrien else 75659243Sobrien tw_env++; 757167465Smp 75859243Sobrien if (tw_dir_fd) { 759167465Smp dir->len = 0; 760167465Smp Strbuf_append(dir, *tw_env++); 761167465Smp Strbuf_append1(dir, '/'); 762167465Smp Strbuf_terminate(dir); 763167465Smp ret = tw_dir_next(res, tw_dir_fd); 76459243Sobrien } 76559243Sobrien } 766167465Smp return ret; 76759243Sobrien} /* end tw_file_next */ 76859243Sobrien 76959243Sobrien 77059243Sobrien/* tw_dir_end(): 77159243Sobrien * Clear directory related lists 77259243Sobrien */ 77359243Sobrienvoid 774167465Smptw_dir_end(void) 77559243Sobrien{ 77659243Sobrien CLRDIR(tw_dir_fd) 77759243Sobrien CLRDIR(tw_cmd_state.dfd) 77859243Sobrien} /* end tw_dir_end */ 77959243Sobrien 78059243Sobrien 78159243Sobrien/* tw_item_free(): 78259243Sobrien * Free the item list 78359243Sobrien */ 78459243Sobrienvoid 785167465Smptw_item_free(void) 78659243Sobrien{ 78759243Sobrien tw_str_free(&tw_item); 78859243Sobrien} /* end tw_item_free */ 78959243Sobrien 79059243Sobrien 79159243Sobrien/* tw_item_get(): 79259243Sobrien * Return the list of items 79359243Sobrien */ 79459243SobrienChar ** 795167465Smptw_item_get(void) 79659243Sobrien{ 79759243Sobrien return tw_item.list; 79859243Sobrien} /* end tw_item_get */ 79959243Sobrien 80059243Sobrien 80159243Sobrien/* tw_item_add(): 802167465Smp * Return a new item for a Strbuf_terminate()'d s 80359243Sobrien */ 804167465Smpvoid 805167465Smptw_item_add(const struct Strbuf *s) 80659243Sobrien{ 807167465Smp Char *p; 808167465Smp 809167465Smp p = tw_str_add(&tw_item, s->len + 1); 810167465Smp Strcpy(p, s->s); 81159243Sobrien} /* tw_item_add */ 81259243Sobrien 81359243Sobrien 81459243Sobrien/* tw_item_find(): 81559243Sobrien * Find the string if it exists in the item list 81659243Sobrien * end return it. 81759243Sobrien */ 81859243SobrienChar * 819167465Smptw_item_find(Char *str) 82059243Sobrien{ 821167465Smp size_t i; 82259243Sobrien 82359243Sobrien if (tw_item.list == NULL || str == NULL) 82459243Sobrien return NULL; 82559243Sobrien 82659243Sobrien for (i = 0; i < tw_item.nlist; i++) 82759243Sobrien if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0) 82859243Sobrien return tw_item.list[i]; 82959243Sobrien return NULL; 83059243Sobrien} /* end tw_item_find */ 83159243Sobrien 83259243Sobrien 83359243Sobrien/* tw_vl_start(): 83459243Sobrien * Initialize a variable list 83559243Sobrien */ 83659243Sobrienvoid 837167465Smptw_vl_start(DIR *dfd, const Char *pat) 83859243Sobrien{ 83959243Sobrien SETDIR(dfd) 84059243Sobrien if ((tw_vptr = adrof(pat)) != NULL) { 84159243Sobrien tw_env = tw_vptr->vec; 84259243Sobrien tw_vptr = NULL; 84359243Sobrien } 84459243Sobrien else 84559243Sobrien tw_env = NULL; 84659243Sobrien} /* end tw_vl_start */ 84759243Sobrien 84859243Sobrien 84959243Sobrien/* 85059243Sobrien * Initialize a word list 85159243Sobrien */ 85259243Sobrienvoid 853167465Smptw_wl_start(DIR *dfd, const Char *pat) 85459243Sobrien{ 85559243Sobrien SETDIR(dfd); 85659243Sobrien tw_word = pat; 85759243Sobrien} /* end tw_wl_start */ 85859243Sobrien 85959243Sobrien 86059243Sobrien/* 86159243Sobrien * Return the next word from the word list 86259243Sobrien */ 86359243Sobrien/*ARGSUSED*/ 864167465Smpint 865167465Smptw_wl_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 86659243Sobrien{ 867167465Smp const Char *p; 868167465Smp 869167465Smp USE(dir); 87059243Sobrien USE(flags); 87159243Sobrien if (tw_word == NULL || tw_word[0] == '\0') 872167465Smp return 0; 873167465Smp 87459243Sobrien while (*tw_word && Isspace(*tw_word)) tw_word++; 87559243Sobrien 876167465Smp for (p = tw_word; *tw_word && !Isspace(*tw_word); tw_word++) 87759243Sobrien continue; 878167465Smp if (tw_word == p) 879167465Smp return 0; 880167465Smp Strbuf_appendn(res, p, tw_word - p); 88159243Sobrien if (*tw_word) 882167465Smp tw_word++; 883167465Smp return 1; 88459243Sobrien} /* end tw_wl_next */ 88559243Sobrien 88659243Sobrien 88759243Sobrien/* tw_bind_start(): 88859243Sobrien * Begin the list of the shell bindings 88959243Sobrien */ 89059243Sobrien/*ARGSUSED*/ 89159243Sobrienvoid 892167465Smptw_bind_start(DIR *dfd, const Char *pat) 89359243Sobrien{ 89459243Sobrien USE(pat); 89559243Sobrien SETDIR(dfd) 89659243Sobrien tw_bind = FuncNames; 89759243Sobrien} /* end tw_bind_start */ 89859243Sobrien 89959243Sobrien 90059243Sobrien/* tw_bind_next(): 90159243Sobrien * Begin the list of the shell bindings 90259243Sobrien */ 90359243Sobrien/*ARGSUSED*/ 904167465Smpint 905167465Smptw_bind_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 90659243Sobrien{ 907167465Smp USE(dir); 90859243Sobrien USE(flags); 90959243Sobrien if (tw_bind && tw_bind->name) { 910167465Smp const char *ptr; 911167465Smp 912167465Smp for (ptr = tw_bind->name; *ptr != '\0'; ptr++) 913167465Smp Strbuf_append1(res, *ptr); 91459243Sobrien tw_bind++; 915167465Smp return 1; 91659243Sobrien } 917167465Smp return 0; 91859243Sobrien} /* end tw_bind_next */ 91959243Sobrien 92059243Sobrien 92159243Sobrien/* tw_limit_start(): 92259243Sobrien * Begin the list of the shell limitings 92359243Sobrien */ 92459243Sobrien/*ARGSUSED*/ 92559243Sobrienvoid 926167465Smptw_limit_start(DIR *dfd, const Char *pat) 92759243Sobrien{ 92859243Sobrien USE(pat); 92959243Sobrien SETDIR(dfd) 93059243Sobrien#ifndef HAVENOLIMIT 93159243Sobrien tw_limit = limits; 93259243Sobrien#endif /* ! HAVENOLIMIT */ 93359243Sobrien} /* end tw_limit_start */ 93459243Sobrien 93559243Sobrien 93659243Sobrien/* tw_limit_next(): 93759243Sobrien * Begin the list of the shell limitings 93859243Sobrien */ 93959243Sobrien/*ARGSUSED*/ 940167465Smpint 941167465Smptw_limit_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 94259243Sobrien{ 943167465Smp USE(dir); 944167465Smp USE(flags); 94559243Sobrien#ifndef HAVENOLIMIT 94659243Sobrien if (tw_limit && tw_limit->limname) { 947167465Smp const char *ptr; 948167465Smp 949167465Smp for (ptr = tw_limit->limname; *ptr != '\0'; ptr++) 950167465Smp Strbuf_append1(res, *ptr); 95159243Sobrien tw_limit++; 952167465Smp return 1; 95359243Sobrien } 95459243Sobrien#endif /* ! HAVENOLIMIT */ 955167465Smp return 0; 95659243Sobrien} /* end tw_limit_next */ 95759243Sobrien 95859243Sobrien 95959243Sobrien/* tw_sig_start(): 96059243Sobrien * Begin the list of the shell sigings 96159243Sobrien */ 96259243Sobrien/*ARGSUSED*/ 96359243Sobrienvoid 964167465Smptw_sig_start(DIR *dfd, const Char *pat) 96559243Sobrien{ 96659243Sobrien USE(pat); 96759243Sobrien SETDIR(dfd) 96859243Sobrien tw_index = 0; 96959243Sobrien} /* end tw_sig_start */ 97059243Sobrien 97159243Sobrien 97259243Sobrien/* tw_sig_next(): 97359243Sobrien * Begin the list of the shell sigings 97459243Sobrien */ 97559243Sobrien/*ARGSUSED*/ 976167465Smpint 977167465Smptw_sig_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 97859243Sobrien{ 979167465Smp USE(dir); 98059243Sobrien USE(flags); 98159243Sobrien for (;tw_index < nsig; tw_index++) { 982167465Smp const char *ptr; 98359243Sobrien 98459243Sobrien if (mesg[tw_index].iname == NULL) 98559243Sobrien continue; 98659243Sobrien 987167465Smp for (ptr = mesg[tw_index].iname; *ptr != '\0'; ptr++) 988167465Smp Strbuf_append1(res, *ptr); 98959243Sobrien tw_index++; 990167465Smp return 1; 99159243Sobrien } 992167465Smp return 0; 99359243Sobrien} /* end tw_sig_next */ 99459243Sobrien 99559243Sobrien 99659243Sobrien/* tw_job_start(): 99759243Sobrien * Begin the list of the shell jobings 99859243Sobrien */ 99959243Sobrien/*ARGSUSED*/ 100059243Sobrienvoid 1001167465Smptw_job_start(DIR *dfd, const Char *pat) 100259243Sobrien{ 100359243Sobrien USE(pat); 100459243Sobrien SETDIR(dfd) 100559243Sobrien tw_index = 1; 100659243Sobrien} /* end tw_job_start */ 100759243Sobrien 100859243Sobrien 100959243Sobrien/* tw_job_next(): 101059243Sobrien * Begin the list of the shell jobings 101159243Sobrien */ 101259243Sobrien/*ARGSUSED*/ 1013167465Smpint 1014167465Smptw_job_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 101559243Sobrien{ 101659243Sobrien struct process *j; 101759243Sobrien 1018167465Smp USE(dir); 101959243Sobrien USE(flags); 102059243Sobrien for (;tw_index <= pmaxindex; tw_index++) { 102159243Sobrien for (j = proclist.p_next; j != NULL; j = j->p_next) 102259243Sobrien if (j->p_index == tw_index && j->p_procid == j->p_jobid) 102359243Sobrien break; 102459243Sobrien if (j == NULL) 102559243Sobrien continue; 1026167465Smp Strbuf_append(res, j->p_command); 102759243Sobrien tw_index++; 1028167465Smp return 1; 102959243Sobrien } 1030167465Smp return 0; 103159243Sobrien} /* end tw_job_next */ 1032