159243Sobrien/* 259243Sobrien * tw.init.c: Handle lists of things to complete 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "tw.h" 3459243Sobrien#include "ed.h" 3559243Sobrien#include "tc.h" 3659243Sobrien#include "sh.proc.h" 3759243Sobrien 3859243Sobrien#define TW_INCR 128 3959243Sobrien 4059243Sobrientypedef struct { 4159243Sobrien Char **list, /* List of command names */ 4259243Sobrien *buff; /* Space holding command names */ 43167465Smp size_t nlist, /* Number of items */ 4459243Sobrien nbuff, /* Current space in name buf */ 4559243Sobrien tlist, /* Total space in list */ 4659243Sobrien tbuff; /* Total space in name buf */ 4759243Sobrien} stringlist_t; 4859243Sobrien 4959243Sobrien 5059243Sobrienstatic struct varent *tw_vptr = NULL; /* Current shell variable */ 5159243Sobrienstatic Char **tw_env = NULL; /* Current environment variable */ 52167465Smpstatic const Char *tw_word; /* Current word pointer */ 5359243Sobrienstatic struct KeyFuncs *tw_bind = NULL; /* List of the bindings */ 5459243Sobrien#ifndef HAVENOLIMIT 5559243Sobrienstatic struct limits *tw_limit = NULL; /* List of the resource limits */ 5659243Sobrien#endif /* HAVENOLIMIT */ 5759243Sobrienstatic int tw_index = 0; /* signal and job index */ 5859243Sobrienstatic DIR *tw_dir_fd = NULL; /* Current directory descriptor */ 5959243Sobrienstatic int tw_cmd_got = 0; /* What we need to do */ 6059243Sobrienstatic stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 }; 6159243Sobrienstatic stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 }; 6259243Sobrien#define TW_FL_CMD 0x01 6359243Sobrien#define TW_FL_ALIAS 0x02 6459243Sobrien#define TW_FL_BUILTIN 0x04 6559243Sobrien#define TW_FL_SORT 0x08 6659243Sobrien#define TW_FL_REL 0x10 6759243Sobrien 6859243Sobrienstatic struct { /* Current element pointer */ 69167465Smp size_t cur; /* Current element number */ 7059243Sobrien Char **pathv; /* Current element in path */ 7159243Sobrien DIR *dfd; /* Current directory descriptor */ 7259243Sobrien} tw_cmd_state; 7359243Sobrien 7459243Sobrien 7559243Sobrien#define SETDIR(dfd) \ 7659243Sobrien { \ 7759243Sobrien tw_dir_fd = dfd; \ 7859243Sobrien if (tw_dir_fd != NULL) \ 7959243Sobrien rewinddir(tw_dir_fd); \ 8059243Sobrien } 8159243Sobrien 8259243Sobrien#define CLRDIR(dfd) \ 8359243Sobrien if (dfd != NULL) { \ 84167465Smp pintr_disabled++; \ 85167465Smp xclosedir(dfd); \ 8659243Sobrien dfd = NULL; \ 87167465Smp disabled_cleanup(&pintr_disabled); \ 8859243Sobrien } 8959243Sobrien 90167465Smpstatic Char *tw_str_add (stringlist_t *, size_t); 91167465Smpstatic void tw_str_free (stringlist_t *); 92167465Smpstatic int tw_dir_next (struct Strbuf *, DIR *); 93167465Smpstatic void tw_cmd_add (const Char *name); 94167465Smpstatic void tw_cmd_cmd (void); 95167465Smpstatic void tw_cmd_builtin (void); 96167465Smpstatic void tw_cmd_alias (void); 97167465Smpstatic void tw_cmd_sort (void); 98167465Smpstatic void tw_vptr_start (struct varent *); 9959243Sobrien 10059243Sobrien 10159243Sobrien/* tw_str_add(): 10259243Sobrien * Add an item to the string list 10359243Sobrien */ 10459243Sobrienstatic Char * 105167465Smptw_str_add(stringlist_t *sl, size_t len) 10659243Sobrien{ 10759243Sobrien Char *ptr; 10859243Sobrien 10959243Sobrien if (sl->tlist <= sl->nlist) { 110167465Smp pintr_disabled++; 11159243Sobrien sl->tlist += TW_INCR; 112167465Smp sl->list = xrealloc(sl->list, sl->tlist * sizeof(Char *)); 113167465Smp disabled_cleanup(&pintr_disabled); 11459243Sobrien } 11559243Sobrien if (sl->tbuff <= sl->nbuff + len) { 116167465Smp size_t i; 117167465Smp 11859243Sobrien ptr = sl->buff; 119167465Smp pintr_disabled++; 12059243Sobrien sl->tbuff += TW_INCR + len; 121167465Smp sl->buff = xrealloc(sl->buff, sl->tbuff * sizeof(Char)); 12259243Sobrien /* Re-thread the new pointer list, if changed */ 12359243Sobrien if (ptr != NULL && ptr != sl->buff) { 12459243Sobrien for (i = 0; i < sl->nlist; i++) 125316957Sdchagin sl->list[i] = sl->buff + (sl->list[i] - ptr); 12659243Sobrien } 127167465Smp disabled_cleanup(&pintr_disabled); 12859243Sobrien } 12959243Sobrien ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff]; 13059243Sobrien sl->nbuff += len; 13159243Sobrien return ptr; 13259243Sobrien} /* tw_str_add */ 13359243Sobrien 13459243Sobrien 13559243Sobrien/* tw_str_free(): 13659243Sobrien * Free a stringlist 13759243Sobrien */ 13859243Sobrienstatic void 139167465Smptw_str_free(stringlist_t *sl) 14059243Sobrien{ 141167465Smp pintr_disabled++; 14259243Sobrien if (sl->list) { 143167465Smp xfree(sl->list); 14459243Sobrien sl->list = NULL; 14559243Sobrien sl->tlist = sl->nlist = 0; 14659243Sobrien } 14759243Sobrien if (sl->buff) { 148167465Smp xfree(sl->buff); 14959243Sobrien sl->buff = NULL; 15059243Sobrien sl->tbuff = sl->nbuff = 0; 15159243Sobrien } 152167465Smp disabled_cleanup(&pintr_disabled); 15359243Sobrien} /* end tw_str_free */ 15459243Sobrien 15559243Sobrien 156167465Smpstatic int 157167465Smptw_dir_next(struct Strbuf *res, DIR *dfd) 15859243Sobrien{ 159145479Smp struct dirent *dirp; 16059243Sobrien 16159243Sobrien if (dfd == NULL) 162167465Smp return 0; 16359243Sobrien 16459243Sobrien if ((dirp = readdir(dfd)) != NULL) { 165167465Smp Strbuf_append(res, str2short(dirp->d_name)); 166167465Smp return 1; 16759243Sobrien } 168167465Smp return 0; 16959243Sobrien} /* end tw_dir_next */ 17059243Sobrien 17159243Sobrien 17259243Sobrien/* tw_cmd_add(): 17359243Sobrien * Add the name to the command list 17459243Sobrien */ 17559243Sobrienstatic void 176167465Smptw_cmd_add(const Char *name) 17759243Sobrien{ 178167465Smp size_t len; 17959243Sobrien 180167465Smp len = Strlen(name) + 2; 18159243Sobrien (void) Strcpy(tw_str_add(&tw_cmd, len), name); 18259243Sobrien} /* end tw_cmd_add */ 18359243Sobrien 18459243Sobrien 18559243Sobrien/* tw_cmd_free(): 18659243Sobrien * Free the command list 18759243Sobrien */ 18859243Sobrienvoid 189167465Smptw_cmd_free(void) 19059243Sobrien{ 19159243Sobrien CLRDIR(tw_dir_fd) 19259243Sobrien tw_str_free(&tw_cmd); 19359243Sobrien tw_cmd_got = 0; 19459243Sobrien} /* end tw_cmd_free */ 19559243Sobrien 19659243Sobrien/* tw_cmd_cmd(): 19759243Sobrien * Add system commands to the command list 19859243Sobrien */ 19959243Sobrienstatic void 200167465Smptw_cmd_cmd(void) 20159243Sobrien{ 202145479Smp DIR *dirp; 203145479Smp struct dirent *dp; 204145479Smp Char *dir = NULL, *name; 205145479Smp Char **pv; 20659243Sobrien struct varent *v = adrof(STRpath); 20759243Sobrien struct varent *recexec = adrof(STRrecognize_only_executables); 208167465Smp size_t len; 20959243Sobrien 21059243Sobrien 211100616Smp if (v == NULL || v->vec == NULL) /* if no path */ 21259243Sobrien return; 21359243Sobrien 21459243Sobrien for (pv = v->vec; *pv; pv++) { 21559243Sobrien if (pv[0][0] != '/') { 21659243Sobrien tw_cmd_got |= TW_FL_REL; 21759243Sobrien continue; 21859243Sobrien } 21959243Sobrien 22059243Sobrien if ((dirp = opendir(short2str(*pv))) == NULL) 22159243Sobrien continue; 22259243Sobrien 223167465Smp cleanup_push(dirp, opendir_cleanup); 224167465Smp if (recexec) { 22559243Sobrien dir = Strspl(*pv, STRslash); 226167465Smp cleanup_push(dir, xfree); 227167465Smp } 22859243Sobrien while ((dp = readdir(dirp)) != NULL) { 22969408Sache#if defined(_UWIN) || defined(__CYGWIN__) 23069408Sache /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 23169408Sache * the file with the .exe, .com, .bat extension 232231990Smp * 233231990Smp * Same for Cygwin, but only for .exe and .com extension. 23469408Sache */ 235167465Smp len = strlen(dp->d_name); 236167465Smp if (len > 4 && (strcmp(&dp->d_name[len - 4], ".exe") == 0 || 237231990Smp#ifndef __CYGWIN__ 238167465Smp strcmp(&dp->d_name[len - 4], ".bat") == 0 || 239231990Smp#endif /* !__CYGWIN__ */ 240167465Smp strcmp(&dp->d_name[len - 4], ".com") == 0)) 241167465Smp dp->d_name[len - 4] = '\0'; 24269408Sache#endif /* _UWIN || __CYGWIN__ */ 24359243Sobrien /* the call to executable() may make this a bit slow */ 24459243Sobrien name = str2short(dp->d_name); 24559243Sobrien if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0))) 24659243Sobrien continue; 247167465Smp len = Strlen(name); 24859243Sobrien if (name[0] == '#' || /* emacs temp files */ 24959243Sobrien name[0] == '.' || /* .files */ 250167465Smp name[len - 1] == '~' || /* emacs backups */ 251167465Smp name[len - 1] == '%') /* textedit backups */ 25259243Sobrien continue; /* Ignore! */ 25359243Sobrien tw_cmd_add(name); 25459243Sobrien } 255167465Smp cleanup_until(dirp); 25659243Sobrien } 25759243Sobrien} /* end tw_cmd_cmd */ 25859243Sobrien 25959243Sobrien 26059243Sobrien/* tw_cmd_builtin(): 26159243Sobrien * Add builtins to the command list 26259243Sobrien */ 26359243Sobrienstatic void 264167465Smptw_cmd_builtin(void) 26559243Sobrien{ 266167465Smp const struct biltins *bptr; 26759243Sobrien 26859243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) 26959243Sobrien if (bptr->bname) 27059243Sobrien tw_cmd_add(str2short(bptr->bname)); 27169408Sache#ifdef WINNT_NATIVE 27259243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) 27359243Sobrien if (bptr->bname) 27459243Sobrien tw_cmd_add(str2short(bptr->bname)); 27569408Sache#endif /* WINNT_NATIVE*/ 27659243Sobrien} /* end tw_cmd_builtin */ 27759243Sobrien 27859243Sobrien 27959243Sobrien/* tw_cmd_alias(): 28059243Sobrien * Add aliases to the command list 28159243Sobrien */ 28259243Sobrienstatic void 283167465Smptw_cmd_alias(void) 28459243Sobrien{ 285145479Smp struct varent *p; 286145479Smp struct varent *c; 28759243Sobrien 28859243Sobrien p = &aliases; 28959243Sobrien for (;;) { 29059243Sobrien while (p->v_left) 29159243Sobrien p = p->v_left; 29259243Sobrienx: 29359243Sobrien if (p->v_parent == 0) /* is it the header? */ 29459243Sobrien return; 29559243Sobrien if (p->v_name) 29659243Sobrien tw_cmd_add(p->v_name); 29759243Sobrien if (p->v_right) { 29859243Sobrien p = p->v_right; 29959243Sobrien continue; 30059243Sobrien } 30159243Sobrien do { 30259243Sobrien c = p; 30359243Sobrien p = p->v_parent; 30459243Sobrien } while (p->v_right == c); 30559243Sobrien goto x; 30659243Sobrien } 30759243Sobrien} /* end tw_cmd_alias */ 30859243Sobrien 30959243Sobrien 31059243Sobrien/* tw_cmd_sort(): 31159243Sobrien * Sort the command list removing duplicate elements 31259243Sobrien */ 31359243Sobrienstatic void 314167465Smptw_cmd_sort(void) 31559243Sobrien{ 316167465Smp size_t fwd, i; 31759243Sobrien 318167465Smp pintr_disabled++; 31959243Sobrien /* sort the list. */ 320167465Smp qsort(tw_cmd.list, tw_cmd.nlist, sizeof(Char *), fcompare); 32159243Sobrien 32259243Sobrien /* get rid of multiple entries */ 323167465Smp for (i = 0, fwd = 0; i + 1 < tw_cmd.nlist; i++) { 32459243Sobrien if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */ 32559243Sobrien fwd++; /* increase the forward ref. count */ 32659243Sobrien else if (fwd) 32759243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 32859243Sobrien } 32959243Sobrien /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */ 33059243Sobrien if (fwd) 33159243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 33259243Sobrien tw_cmd.nlist -= fwd; 333167465Smp disabled_cleanup(&pintr_disabled); 33459243Sobrien} /* end tw_cmd_sort */ 33559243Sobrien 33659243Sobrien 33759243Sobrien/* tw_cmd_start(): 33859243Sobrien * Get the command list and sort it, if not done yet. 33959243Sobrien * Reset the current pointer to the beginning of the command list 34059243Sobrien */ 34159243Sobrien/*ARGSUSED*/ 34259243Sobrienvoid 343167465Smptw_cmd_start(DIR *dfd, const Char *pat) 34459243Sobrien{ 34559243Sobrien static Char *defpath[] = { STRNULL, 0 }; 34659243Sobrien USE(pat); 34759243Sobrien SETDIR(dfd) 34859243Sobrien if ((tw_cmd_got & TW_FL_CMD) == 0) { 34959243Sobrien tw_cmd_free(); 35059243Sobrien tw_cmd_cmd(); 35159243Sobrien tw_cmd_got |= TW_FL_CMD; 35259243Sobrien } 35359243Sobrien if ((tw_cmd_got & TW_FL_ALIAS) == 0) { 35459243Sobrien tw_cmd_alias(); 35559243Sobrien tw_cmd_got &= ~TW_FL_SORT; 35659243Sobrien tw_cmd_got |= TW_FL_ALIAS; 35759243Sobrien } 35859243Sobrien if ((tw_cmd_got & TW_FL_BUILTIN) == 0) { 35959243Sobrien tw_cmd_builtin(); 36059243Sobrien tw_cmd_got &= ~TW_FL_SORT; 36159243Sobrien tw_cmd_got |= TW_FL_BUILTIN; 36259243Sobrien } 36359243Sobrien if ((tw_cmd_got & TW_FL_SORT) == 0) { 36459243Sobrien tw_cmd_sort(); 36559243Sobrien tw_cmd_got |= TW_FL_SORT; 36659243Sobrien } 36759243Sobrien 36859243Sobrien tw_cmd_state.cur = 0; 36959243Sobrien CLRDIR(tw_cmd_state.dfd) 37059243Sobrien if (tw_cmd_got & TW_FL_REL) { 37159243Sobrien struct varent *vp = adrof(STRpath); 37259243Sobrien if (vp && vp->vec) 37359243Sobrien tw_cmd_state.pathv = vp->vec; 37459243Sobrien else 37559243Sobrien tw_cmd_state.pathv = defpath; 37659243Sobrien } 37759243Sobrien else 37859243Sobrien tw_cmd_state.pathv = defpath; 37959243Sobrien} /* tw_cmd_start */ 38059243Sobrien 38159243Sobrien 38259243Sobrien/* tw_cmd_next(): 38359243Sobrien * Return the next element in the command list or 38459243Sobrien * Look for commands in the relative path components 38559243Sobrien */ 386167465Smpint 387167465Smptw_cmd_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 38859243Sobrien{ 389167465Smp int ret = 0; 390167465Smp Char *ptr; 39159243Sobrien 39259243Sobrien if (tw_cmd_state.cur < tw_cmd.nlist) { 39359243Sobrien *flags = TW_DIR_OK; 394167465Smp Strbuf_append(res, tw_cmd.list[tw_cmd_state.cur++]); 395167465Smp return 1; 39659243Sobrien } 39759243Sobrien 39859243Sobrien /* 39959243Sobrien * We need to process relatives in the path. 40059243Sobrien */ 401167465Smp while ((tw_cmd_state.dfd == NULL || 402231990Smp (res->len = 0, ret = tw_dir_next(res, tw_cmd_state.dfd)) == 0) && 403167465Smp *tw_cmd_state.pathv != NULL) { 40459243Sobrien 40559243Sobrien CLRDIR(tw_cmd_state.dfd) 40659243Sobrien 40759243Sobrien while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/') 40859243Sobrien tw_cmd_state.pathv++; 40959243Sobrien if ((ptr = *tw_cmd_state.pathv) != 0) { 410231990Smp res->len = 0; 411167465Smp Strbuf_append(res, ptr); 412167465Smp ret = 1; 41359243Sobrien /* 41459243Sobrien * We complete directories only on '.' should that 41559243Sobrien * be changed? 41659243Sobrien */ 417167465Smp dir->len = 0; 41859243Sobrien if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) { 41959243Sobrien tw_cmd_state.dfd = opendir("."); 420167465Smp *flags = TW_DIR_OK | TW_EXEC_CHK; 42159243Sobrien } 42259243Sobrien else { 423167465Smp Strbuf_append(dir, *tw_cmd_state.pathv); 424167465Smp Strbuf_append1(dir, '/'); 42559243Sobrien tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv)); 42659243Sobrien *flags = TW_EXEC_CHK; 42759243Sobrien } 428167465Smp Strbuf_terminate(dir); 42959243Sobrien tw_cmd_state.pathv++; 43059243Sobrien } 43159243Sobrien } 432167465Smp return ret; 43359243Sobrien} /* end tw_cmd_next */ 43459243Sobrien 43559243Sobrien 43659243Sobrien/* tw_vptr_start(): 43759243Sobrien * Find the first variable in the variable list 43859243Sobrien */ 43959243Sobrienstatic void 440167465Smptw_vptr_start(struct varent *c) 44159243Sobrien{ 44259243Sobrien tw_vptr = c; /* start at beginning of variable list */ 44359243Sobrien 44459243Sobrien for (;;) { 44559243Sobrien while (tw_vptr->v_left) 44659243Sobrien tw_vptr = tw_vptr->v_left; 44759243Sobrienx: 44859243Sobrien if (tw_vptr->v_parent == 0) { /* is it the header? */ 44959243Sobrien tw_vptr = NULL; 45059243Sobrien return; 45159243Sobrien } 45259243Sobrien if (tw_vptr->v_name) 45359243Sobrien return; /* found first one */ 45459243Sobrien if (tw_vptr->v_right) { 45559243Sobrien tw_vptr = tw_vptr->v_right; 45659243Sobrien continue; 45759243Sobrien } 45859243Sobrien do { 45959243Sobrien c = tw_vptr; 46059243Sobrien tw_vptr = tw_vptr->v_parent; 46159243Sobrien } while (tw_vptr->v_right == c); 46259243Sobrien goto x; 46359243Sobrien } 46459243Sobrien} /* end tw_shvar_start */ 46559243Sobrien 46659243Sobrien 46759243Sobrien/* tw_shvar_next(): 46859243Sobrien * Return the next shell variable 46959243Sobrien */ 47059243Sobrien/*ARGSUSED*/ 471167465Smpint 472167465Smptw_shvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 47359243Sobrien{ 474145479Smp struct varent *p; 475145479Smp struct varent *c; 47659243Sobrien 47759243Sobrien USE(flags); 47859243Sobrien USE(dir); 47959243Sobrien if ((p = tw_vptr) == NULL) 480167465Smp return 0; /* just in case */ 48159243Sobrien 482167465Smp Strbuf_append(res, p->v_name); /* we know that this name is here now */ 48359243Sobrien 48459243Sobrien /* now find the next one */ 48559243Sobrien for (;;) { 48659243Sobrien if (p->v_right) { /* if we can go right */ 48759243Sobrien p = p->v_right; 48859243Sobrien while (p->v_left) 48959243Sobrien p = p->v_left; 49059243Sobrien } 49159243Sobrien else { /* else go up */ 49259243Sobrien do { 49359243Sobrien c = p; 49459243Sobrien p = p->v_parent; 49559243Sobrien } while (p->v_right == c); 49659243Sobrien } 49759243Sobrien if (p->v_parent == 0) { /* is it the header? */ 49859243Sobrien tw_vptr = NULL; 499167465Smp return 1; 50059243Sobrien } 50159243Sobrien if (p->v_name) { 50259243Sobrien tw_vptr = p; /* save state for the next call */ 503167465Smp return 1; 50459243Sobrien } 50559243Sobrien } 50659243Sobrien} /* end tw_shvar_next */ 50759243Sobrien 50859243Sobrien 50959243Sobrien/* tw_envvar_next(): 51059243Sobrien * Return the next environment variable 51159243Sobrien */ 51259243Sobrien/*ARGSUSED*/ 513167465Smpint 514167465Smptw_envvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 51559243Sobrien{ 516167465Smp const Char *ps; 51759243Sobrien 51859243Sobrien USE(flags); 51959243Sobrien USE(dir); 52059243Sobrien if (tw_env == NULL || *tw_env == NULL) 521167465Smp return 0; 522167465Smp for (ps = *tw_env; *ps && *ps != '='; ps++) 52359243Sobrien continue; 524167465Smp Strbuf_appendn(res, *tw_env, ps - *tw_env); 52559243Sobrien tw_env++; 526167465Smp return 1; 52759243Sobrien} /* end tw_envvar_next */ 52859243Sobrien 52959243Sobrien 53059243Sobrien/* tw_var_start(): 53159243Sobrien * Begin the list of the shell and environment variables 53259243Sobrien */ 53359243Sobrien/*ARGSUSED*/ 53459243Sobrienvoid 535167465Smptw_var_start(DIR *dfd, const Char *pat) 53659243Sobrien{ 53759243Sobrien USE(pat); 53859243Sobrien SETDIR(dfd) 53959243Sobrien tw_vptr_start(&shvhed); 54059243Sobrien tw_env = STR_environ; 54159243Sobrien} /* end tw_var_start */ 54259243Sobrien 54359243Sobrien 54459243Sobrien/* tw_alias_start(): 54559243Sobrien * Begin the list of the shell aliases 54659243Sobrien */ 54759243Sobrien/*ARGSUSED*/ 54859243Sobrienvoid 549167465Smptw_alias_start(DIR *dfd, const Char *pat) 55059243Sobrien{ 55159243Sobrien USE(pat); 55259243Sobrien SETDIR(dfd) 55359243Sobrien tw_vptr_start(&aliases); 55459243Sobrien tw_env = NULL; 55559243Sobrien} /* tw_alias_start */ 55659243Sobrien 55759243Sobrien 55859243Sobrien/* tw_complete_start(): 55959243Sobrien * Begin the list of completions 56059243Sobrien */ 56159243Sobrien/*ARGSUSED*/ 56259243Sobrienvoid 563167465Smptw_complete_start(DIR *dfd, const Char *pat) 56459243Sobrien{ 56559243Sobrien USE(pat); 56659243Sobrien SETDIR(dfd) 56759243Sobrien tw_vptr_start(&completions); 56859243Sobrien tw_env = NULL; 56959243Sobrien} /* end tw_complete_start */ 57059243Sobrien 57159243Sobrien 57259243Sobrien/* tw_var_next(): 57359243Sobrien * Return the next shell or environment variable 57459243Sobrien */ 575167465Smpint 576167465Smptw_var_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 57759243Sobrien{ 578167465Smp int ret = 0; 57959243Sobrien 58059243Sobrien if (tw_vptr) 581167465Smp ret = tw_shvar_next(res, dir, flags); 582167465Smp if (ret == 0 && tw_env) 583167465Smp ret = tw_envvar_next(res, dir, flags); 584167465Smp return ret; 58559243Sobrien} /* end tw_var_next */ 58659243Sobrien 58759243Sobrien 58859243Sobrien/* tw_logname_start(): 58959243Sobrien * Initialize lognames to the beginning of the list 59059243Sobrien */ 59159243Sobrien/*ARGSUSED*/ 59259243Sobrienvoid 593167465Smptw_logname_start(DIR *dfd, const Char *pat) 59459243Sobrien{ 59559243Sobrien USE(pat); 59659243Sobrien SETDIR(dfd) 597145479Smp#ifdef HAVE_GETPWENT 59859243Sobrien (void) setpwent(); /* Open passwd file */ 599145479Smp#endif 60059243Sobrien} /* end tw_logname_start */ 60159243Sobrien 60259243Sobrien 60359243Sobrien/* tw_logname_next(): 60459243Sobrien * Return the next entry from the passwd file 60559243Sobrien */ 60659243Sobrien/*ARGSUSED*/ 607167465Smpint 608167465Smptw_logname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 60959243Sobrien{ 61059243Sobrien struct passwd *pw; 611167465Smp 61259243Sobrien /* 61359243Sobrien * We don't want to get interrupted inside getpwent() 61459243Sobrien * because the yellow pages code is not interruptible, 61559243Sobrien * and if we call endpwent() immediatetely after 61659243Sobrien * (in pintr()) we may be freeing an invalid pointer 61759243Sobrien */ 61859243Sobrien USE(flags); 61959243Sobrien USE(dir); 620167465Smp pintr_disabled++; 621145479Smp#ifdef HAVE_GETPWENT 622145479Smp pw = getpwent(); 623145479Smp#else 62459243Sobrien pw = NULL; 625145479Smp#endif 626167465Smp disabled_cleanup(&pintr_disabled); 62759243Sobrien 62859243Sobrien if (pw == NULL) { 62959243Sobrien#ifdef YPBUGS 63059243Sobrien fix_yp_bugs(); 63159243Sobrien#endif 632167465Smp return 0; 63359243Sobrien } 634167465Smp Strbuf_append(res, str2short(pw->pw_name)); 635167465Smp return 1; 63659243Sobrien} /* end tw_logname_next */ 63759243Sobrien 63859243Sobrien 63959243Sobrien/* tw_logname_end(): 64059243Sobrien * Close the passwd file to finish the logname list 64159243Sobrien */ 64259243Sobrienvoid 643167465Smptw_logname_end(void) 64459243Sobrien{ 64559243Sobrien#ifdef YPBUGS 64659243Sobrien fix_yp_bugs(); 64759243Sobrien#endif 648145479Smp#ifdef HAVE_GETPWENT 64959243Sobrien (void) endpwent(); 650145479Smp#endif 65159243Sobrien} /* end tw_logname_end */ 65259243Sobrien 65359243Sobrien 65459243Sobrien/* tw_grpname_start(): 65559243Sobrien * Initialize grpnames to the beginning of the list 65659243Sobrien */ 65759243Sobrien/*ARGSUSED*/ 65859243Sobrienvoid 659167465Smptw_grpname_start(DIR *dfd, const Char *pat) 66059243Sobrien{ 66159243Sobrien USE(pat); 66259243Sobrien SETDIR(dfd) 663231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 66459243Sobrien (void) setgrent(); /* Open group file */ 66569408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 66659243Sobrien} /* end tw_grpname_start */ 66759243Sobrien 66859243Sobrien 66959243Sobrien/* tw_grpname_next(): 67059243Sobrien * Return the next entry from the group file 67159243Sobrien */ 67259243Sobrien/*ARGSUSED*/ 673167465Smpint 674167465Smptw_grpname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 67559243Sobrien{ 67659243Sobrien struct group *gr; 677167465Smp 67859243Sobrien /* 67959243Sobrien * We don't want to get interrupted inside getgrent() 68059243Sobrien * because the yellow pages code is not interruptible, 68159243Sobrien * and if we call endgrent() immediatetely after 68259243Sobrien * (in pintr()) we may be freeing an invalid pointer 68359243Sobrien */ 68459243Sobrien USE(flags); 68559243Sobrien USE(dir); 686167465Smp pintr_disabled++; 687231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined(__ANDROID__) 688167465Smp errno = 0; 689167465Smp while ((gr = getgrent()) == NULL && errno == EINTR) { 690167465Smp handle_pending_signals(); 691167465Smp errno = 0; 692167465Smp } 69369408Sache#else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */ 69459243Sobrien gr = NULL; 69569408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 696167465Smp disabled_cleanup(&pintr_disabled); 69759243Sobrien 69859243Sobrien if (gr == NULL) { 69959243Sobrien#ifdef YPBUGS 70059243Sobrien fix_yp_bugs(); 70159243Sobrien#endif 702167465Smp return 0; 70359243Sobrien } 704167465Smp Strbuf_append(res, str2short(gr->gr_name)); 705167465Smp return 1; 70659243Sobrien} /* end tw_grpname_next */ 70759243Sobrien 70859243Sobrien 70959243Sobrien/* tw_grpname_end(): 71059243Sobrien * Close the group file to finish the groupname list 71159243Sobrien */ 71259243Sobrienvoid 713167465Smptw_grpname_end(void) 71459243Sobrien{ 71559243Sobrien#ifdef YPBUGS 71659243Sobrien fix_yp_bugs(); 71759243Sobrien#endif 718231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 71959243Sobrien (void) endgrent(); 72069408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 72159243Sobrien} /* end tw_grpname_end */ 72259243Sobrien 72359243Sobrien/* tw_file_start(): 72459243Sobrien * Initialize the directory for the file list 72559243Sobrien */ 72659243Sobrien/*ARGSUSED*/ 72759243Sobrienvoid 728167465Smptw_file_start(DIR *dfd, const Char *pat) 72959243Sobrien{ 73059243Sobrien struct varent *vp; 73159243Sobrien USE(pat); 73259243Sobrien SETDIR(dfd) 73359243Sobrien if ((vp = adrof(STRcdpath)) != NULL) 73459243Sobrien tw_env = vp->vec; 73559243Sobrien} /* end tw_file_start */ 73659243Sobrien 73759243Sobrien 73859243Sobrien/* tw_file_next(): 73959243Sobrien * Return the next file in the directory 74059243Sobrien */ 741167465Smpint 742167465Smptw_file_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 74359243Sobrien{ 744167465Smp int ret = tw_dir_next(res, tw_dir_fd); 745167465Smp if (ret == 0 && (*flags & TW_DIR_OK) != 0) { 74659243Sobrien CLRDIR(tw_dir_fd) 74759243Sobrien while (tw_env && *tw_env) 74859243Sobrien if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL) 74959243Sobrien break; 75059243Sobrien else 75159243Sobrien tw_env++; 752167465Smp 75359243Sobrien if (tw_dir_fd) { 754167465Smp dir->len = 0; 755167465Smp Strbuf_append(dir, *tw_env++); 756167465Smp Strbuf_append1(dir, '/'); 757167465Smp Strbuf_terminate(dir); 758167465Smp ret = tw_dir_next(res, tw_dir_fd); 75959243Sobrien } 76059243Sobrien } 761167465Smp return ret; 76259243Sobrien} /* end tw_file_next */ 76359243Sobrien 76459243Sobrien 76559243Sobrien/* tw_dir_end(): 76659243Sobrien * Clear directory related lists 76759243Sobrien */ 76859243Sobrienvoid 769167465Smptw_dir_end(void) 77059243Sobrien{ 77159243Sobrien CLRDIR(tw_dir_fd) 77259243Sobrien CLRDIR(tw_cmd_state.dfd) 77359243Sobrien} /* end tw_dir_end */ 77459243Sobrien 77559243Sobrien 77659243Sobrien/* tw_item_free(): 77759243Sobrien * Free the item list 77859243Sobrien */ 77959243Sobrienvoid 780167465Smptw_item_free(void) 78159243Sobrien{ 78259243Sobrien tw_str_free(&tw_item); 78359243Sobrien} /* end tw_item_free */ 78459243Sobrien 78559243Sobrien 78659243Sobrien/* tw_item_get(): 78759243Sobrien * Return the list of items 78859243Sobrien */ 78959243SobrienChar ** 790167465Smptw_item_get(void) 79159243Sobrien{ 79259243Sobrien return tw_item.list; 79359243Sobrien} /* end tw_item_get */ 79459243Sobrien 79559243Sobrien 79659243Sobrien/* tw_item_add(): 797167465Smp * Return a new item for a Strbuf_terminate()'d s 79859243Sobrien */ 799167465Smpvoid 800167465Smptw_item_add(const struct Strbuf *s) 80159243Sobrien{ 802167465Smp Char *p; 803167465Smp 804167465Smp p = tw_str_add(&tw_item, s->len + 1); 805167465Smp Strcpy(p, s->s); 80659243Sobrien} /* tw_item_add */ 80759243Sobrien 80859243Sobrien 80959243Sobrien/* tw_item_find(): 81059243Sobrien * Find the string if it exists in the item list 81159243Sobrien * end return it. 81259243Sobrien */ 81359243SobrienChar * 814167465Smptw_item_find(Char *str) 81559243Sobrien{ 816167465Smp size_t i; 81759243Sobrien 81859243Sobrien if (tw_item.list == NULL || str == NULL) 81959243Sobrien return NULL; 82059243Sobrien 82159243Sobrien for (i = 0; i < tw_item.nlist; i++) 82259243Sobrien if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0) 82359243Sobrien return tw_item.list[i]; 82459243Sobrien return NULL; 82559243Sobrien} /* end tw_item_find */ 82659243Sobrien 82759243Sobrien 82859243Sobrien/* tw_vl_start(): 82959243Sobrien * Initialize a variable list 83059243Sobrien */ 83159243Sobrienvoid 832167465Smptw_vl_start(DIR *dfd, const Char *pat) 83359243Sobrien{ 83459243Sobrien SETDIR(dfd) 83559243Sobrien if ((tw_vptr = adrof(pat)) != NULL) { 83659243Sobrien tw_env = tw_vptr->vec; 83759243Sobrien tw_vptr = NULL; 83859243Sobrien } 83959243Sobrien else 84059243Sobrien tw_env = NULL; 84159243Sobrien} /* end tw_vl_start */ 84259243Sobrien 84359243Sobrien 84459243Sobrien/* 84559243Sobrien * Initialize a word list 84659243Sobrien */ 84759243Sobrienvoid 848167465Smptw_wl_start(DIR *dfd, const Char *pat) 84959243Sobrien{ 85059243Sobrien SETDIR(dfd); 85159243Sobrien tw_word = pat; 85259243Sobrien} /* end tw_wl_start */ 85359243Sobrien 85459243Sobrien 85559243Sobrien/* 85659243Sobrien * Return the next word from the word list 85759243Sobrien */ 85859243Sobrien/*ARGSUSED*/ 859167465Smpint 860167465Smptw_wl_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 86159243Sobrien{ 862167465Smp const Char *p; 863167465Smp 864167465Smp USE(dir); 86559243Sobrien USE(flags); 86659243Sobrien if (tw_word == NULL || tw_word[0] == '\0') 867167465Smp return 0; 868167465Smp 86959243Sobrien while (*tw_word && Isspace(*tw_word)) tw_word++; 87059243Sobrien 871167465Smp for (p = tw_word; *tw_word && !Isspace(*tw_word); tw_word++) 87259243Sobrien continue; 873167465Smp if (tw_word == p) 874167465Smp return 0; 875167465Smp Strbuf_appendn(res, p, tw_word - p); 87659243Sobrien if (*tw_word) 877167465Smp tw_word++; 878167465Smp return 1; 87959243Sobrien} /* end tw_wl_next */ 88059243Sobrien 88159243Sobrien 88259243Sobrien/* tw_bind_start(): 88359243Sobrien * Begin the list of the shell bindings 88459243Sobrien */ 88559243Sobrien/*ARGSUSED*/ 88659243Sobrienvoid 887167465Smptw_bind_start(DIR *dfd, const Char *pat) 88859243Sobrien{ 88959243Sobrien USE(pat); 89059243Sobrien SETDIR(dfd) 89159243Sobrien tw_bind = FuncNames; 89259243Sobrien} /* end tw_bind_start */ 89359243Sobrien 89459243Sobrien 89559243Sobrien/* tw_bind_next(): 89659243Sobrien * Begin the list of the shell bindings 89759243Sobrien */ 89859243Sobrien/*ARGSUSED*/ 899167465Smpint 900167465Smptw_bind_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 90159243Sobrien{ 902167465Smp USE(dir); 90359243Sobrien USE(flags); 90459243Sobrien if (tw_bind && tw_bind->name) { 905167465Smp const char *ptr; 906167465Smp 907167465Smp for (ptr = tw_bind->name; *ptr != '\0'; ptr++) 908167465Smp Strbuf_append1(res, *ptr); 90959243Sobrien tw_bind++; 910167465Smp return 1; 91159243Sobrien } 912167465Smp return 0; 91359243Sobrien} /* end tw_bind_next */ 91459243Sobrien 91559243Sobrien 91659243Sobrien/* tw_limit_start(): 91759243Sobrien * Begin the list of the shell limitings 91859243Sobrien */ 91959243Sobrien/*ARGSUSED*/ 92059243Sobrienvoid 921167465Smptw_limit_start(DIR *dfd, const Char *pat) 92259243Sobrien{ 92359243Sobrien USE(pat); 92459243Sobrien SETDIR(dfd) 92559243Sobrien#ifndef HAVENOLIMIT 92659243Sobrien tw_limit = limits; 92759243Sobrien#endif /* ! HAVENOLIMIT */ 92859243Sobrien} /* end tw_limit_start */ 92959243Sobrien 93059243Sobrien 93159243Sobrien/* tw_limit_next(): 93259243Sobrien * Begin the list of the shell limitings 93359243Sobrien */ 93459243Sobrien/*ARGSUSED*/ 935167465Smpint 936167465Smptw_limit_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 93759243Sobrien{ 938167465Smp USE(dir); 939167465Smp USE(flags); 94059243Sobrien#ifndef HAVENOLIMIT 94159243Sobrien if (tw_limit && tw_limit->limname) { 942167465Smp const char *ptr; 943167465Smp 944167465Smp for (ptr = tw_limit->limname; *ptr != '\0'; ptr++) 945167465Smp Strbuf_append1(res, *ptr); 94659243Sobrien tw_limit++; 947167465Smp return 1; 94859243Sobrien } 94959243Sobrien#endif /* ! HAVENOLIMIT */ 950167465Smp return 0; 95159243Sobrien} /* end tw_limit_next */ 95259243Sobrien 95359243Sobrien 95459243Sobrien/* tw_sig_start(): 95559243Sobrien * Begin the list of the shell sigings 95659243Sobrien */ 95759243Sobrien/*ARGSUSED*/ 95859243Sobrienvoid 959167465Smptw_sig_start(DIR *dfd, const Char *pat) 96059243Sobrien{ 96159243Sobrien USE(pat); 96259243Sobrien SETDIR(dfd) 96359243Sobrien tw_index = 0; 96459243Sobrien} /* end tw_sig_start */ 96559243Sobrien 96659243Sobrien 96759243Sobrien/* tw_sig_next(): 96859243Sobrien * Begin the list of the shell sigings 96959243Sobrien */ 97059243Sobrien/*ARGSUSED*/ 971167465Smpint 972167465Smptw_sig_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 97359243Sobrien{ 974167465Smp USE(dir); 97559243Sobrien USE(flags); 97659243Sobrien for (;tw_index < nsig; tw_index++) { 977167465Smp const char *ptr; 97859243Sobrien 97959243Sobrien if (mesg[tw_index].iname == NULL) 98059243Sobrien continue; 98159243Sobrien 982167465Smp for (ptr = mesg[tw_index].iname; *ptr != '\0'; ptr++) 983167465Smp Strbuf_append1(res, *ptr); 98459243Sobrien tw_index++; 985167465Smp return 1; 98659243Sobrien } 987167465Smp return 0; 98859243Sobrien} /* end tw_sig_next */ 98959243Sobrien 99059243Sobrien 99159243Sobrien/* tw_job_start(): 99259243Sobrien * Begin the list of the shell jobings 99359243Sobrien */ 99459243Sobrien/*ARGSUSED*/ 99559243Sobrienvoid 996167465Smptw_job_start(DIR *dfd, const Char *pat) 99759243Sobrien{ 99859243Sobrien USE(pat); 99959243Sobrien SETDIR(dfd) 100059243Sobrien tw_index = 1; 100159243Sobrien} /* end tw_job_start */ 100259243Sobrien 100359243Sobrien 100459243Sobrien/* tw_job_next(): 100559243Sobrien * Begin the list of the shell jobings 100659243Sobrien */ 100759243Sobrien/*ARGSUSED*/ 1008167465Smpint 1009167465Smptw_job_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 101059243Sobrien{ 101159243Sobrien struct process *j; 101259243Sobrien 1013167465Smp USE(dir); 101459243Sobrien USE(flags); 101559243Sobrien for (;tw_index <= pmaxindex; tw_index++) { 101659243Sobrien for (j = proclist.p_next; j != NULL; j = j->p_next) 101759243Sobrien if (j->p_index == tw_index && j->p_procid == j->p_jobid) 101859243Sobrien break; 101959243Sobrien if (j == NULL) 102059243Sobrien continue; 1021167465Smp Strbuf_append(res, j->p_command); 102259243Sobrien tw_index++; 1023167465Smp return 1; 102459243Sobrien } 1025167465Smp return 0; 102659243Sobrien} /* end tw_job_next */ 1027