tw.init.c revision 316957
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) { 12859243Sobrien for (i = 0; i < sl->nlist; i++) 129316957Sdchagin sl->list[i] = sl->buff + (sl->list[i] - ptr); 13059243Sobrien } 131167465Smp disabled_cleanup(&pintr_disabled); 13259243Sobrien } 13359243Sobrien ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff]; 13459243Sobrien sl->nbuff += len; 13559243Sobrien return ptr; 13659243Sobrien} /* tw_str_add */ 13759243Sobrien 13859243Sobrien 13959243Sobrien/* tw_str_free(): 14059243Sobrien * Free a stringlist 14159243Sobrien */ 14259243Sobrienstatic void 143167465Smptw_str_free(stringlist_t *sl) 14459243Sobrien{ 145167465Smp pintr_disabled++; 14659243Sobrien if (sl->list) { 147167465Smp xfree(sl->list); 14859243Sobrien sl->list = NULL; 14959243Sobrien sl->tlist = sl->nlist = 0; 15059243Sobrien } 15159243Sobrien if (sl->buff) { 152167465Smp xfree(sl->buff); 15359243Sobrien sl->buff = NULL; 15459243Sobrien sl->tbuff = sl->nbuff = 0; 15559243Sobrien } 156167465Smp disabled_cleanup(&pintr_disabled); 15759243Sobrien} /* end tw_str_free */ 15859243Sobrien 15959243Sobrien 160167465Smpstatic int 161167465Smptw_dir_next(struct Strbuf *res, DIR *dfd) 16259243Sobrien{ 163145479Smp struct dirent *dirp; 16459243Sobrien 16559243Sobrien if (dfd == NULL) 166167465Smp return 0; 16759243Sobrien 16859243Sobrien if ((dirp = readdir(dfd)) != NULL) { 169167465Smp Strbuf_append(res, str2short(dirp->d_name)); 170167465Smp return 1; 17159243Sobrien } 172167465Smp return 0; 17359243Sobrien} /* end tw_dir_next */ 17459243Sobrien 17559243Sobrien 17659243Sobrien/* tw_cmd_add(): 17759243Sobrien * Add the name to the command list 17859243Sobrien */ 17959243Sobrienstatic void 180167465Smptw_cmd_add(const Char *name) 18159243Sobrien{ 182167465Smp size_t len; 18359243Sobrien 184167465Smp len = Strlen(name) + 2; 18559243Sobrien (void) Strcpy(tw_str_add(&tw_cmd, len), name); 18659243Sobrien} /* end tw_cmd_add */ 18759243Sobrien 18859243Sobrien 18959243Sobrien/* tw_cmd_free(): 19059243Sobrien * Free the command list 19159243Sobrien */ 19259243Sobrienvoid 193167465Smptw_cmd_free(void) 19459243Sobrien{ 19559243Sobrien CLRDIR(tw_dir_fd) 19659243Sobrien tw_str_free(&tw_cmd); 19759243Sobrien tw_cmd_got = 0; 19859243Sobrien} /* end tw_cmd_free */ 19959243Sobrien 20059243Sobrien/* tw_cmd_cmd(): 20159243Sobrien * Add system commands to the command list 20259243Sobrien */ 20359243Sobrienstatic void 204167465Smptw_cmd_cmd(void) 20559243Sobrien{ 206145479Smp DIR *dirp; 207145479Smp struct dirent *dp; 208145479Smp Char *dir = NULL, *name; 209145479Smp Char **pv; 21059243Sobrien struct varent *v = adrof(STRpath); 21159243Sobrien struct varent *recexec = adrof(STRrecognize_only_executables); 212167465Smp size_t len; 21359243Sobrien 21459243Sobrien 215100616Smp if (v == NULL || v->vec == NULL) /* if no path */ 21659243Sobrien return; 21759243Sobrien 21859243Sobrien for (pv = v->vec; *pv; pv++) { 21959243Sobrien if (pv[0][0] != '/') { 22059243Sobrien tw_cmd_got |= TW_FL_REL; 22159243Sobrien continue; 22259243Sobrien } 22359243Sobrien 22459243Sobrien if ((dirp = opendir(short2str(*pv))) == NULL) 22559243Sobrien continue; 22659243Sobrien 227167465Smp cleanup_push(dirp, opendir_cleanup); 228167465Smp if (recexec) { 22959243Sobrien dir = Strspl(*pv, STRslash); 230167465Smp cleanup_push(dir, xfree); 231167465Smp } 23259243Sobrien while ((dp = readdir(dirp)) != NULL) { 23369408Sache#if defined(_UWIN) || defined(__CYGWIN__) 23469408Sache /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns 23569408Sache * the file with the .exe, .com, .bat extension 236231990Smp * 237231990Smp * Same for Cygwin, but only for .exe and .com extension. 23869408Sache */ 239167465Smp len = strlen(dp->d_name); 240167465Smp if (len > 4 && (strcmp(&dp->d_name[len - 4], ".exe") == 0 || 241231990Smp#ifndef __CYGWIN__ 242167465Smp strcmp(&dp->d_name[len - 4], ".bat") == 0 || 243231990Smp#endif /* !__CYGWIN__ */ 244167465Smp strcmp(&dp->d_name[len - 4], ".com") == 0)) 245167465Smp dp->d_name[len - 4] = '\0'; 24669408Sache#endif /* _UWIN || __CYGWIN__ */ 24759243Sobrien /* the call to executable() may make this a bit slow */ 24859243Sobrien name = str2short(dp->d_name); 24959243Sobrien if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0))) 25059243Sobrien continue; 251167465Smp len = Strlen(name); 25259243Sobrien if (name[0] == '#' || /* emacs temp files */ 25359243Sobrien name[0] == '.' || /* .files */ 254167465Smp name[len - 1] == '~' || /* emacs backups */ 255167465Smp name[len - 1] == '%') /* textedit backups */ 25659243Sobrien continue; /* Ignore! */ 25759243Sobrien tw_cmd_add(name); 25859243Sobrien } 259167465Smp cleanup_until(dirp); 26059243Sobrien } 26159243Sobrien} /* end tw_cmd_cmd */ 26259243Sobrien 26359243Sobrien 26459243Sobrien/* tw_cmd_builtin(): 26559243Sobrien * Add builtins to the command list 26659243Sobrien */ 26759243Sobrienstatic void 268167465Smptw_cmd_builtin(void) 26959243Sobrien{ 270167465Smp const struct biltins *bptr; 27159243Sobrien 27259243Sobrien for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) 27359243Sobrien if (bptr->bname) 27459243Sobrien tw_cmd_add(str2short(bptr->bname)); 27569408Sache#ifdef WINNT_NATIVE 27659243Sobrien for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++) 27759243Sobrien if (bptr->bname) 27859243Sobrien tw_cmd_add(str2short(bptr->bname)); 27969408Sache#endif /* WINNT_NATIVE*/ 28059243Sobrien} /* end tw_cmd_builtin */ 28159243Sobrien 28259243Sobrien 28359243Sobrien/* tw_cmd_alias(): 28459243Sobrien * Add aliases to the command list 28559243Sobrien */ 28659243Sobrienstatic void 287167465Smptw_cmd_alias(void) 28859243Sobrien{ 289145479Smp struct varent *p; 290145479Smp struct varent *c; 29159243Sobrien 29259243Sobrien p = &aliases; 29359243Sobrien for (;;) { 29459243Sobrien while (p->v_left) 29559243Sobrien p = p->v_left; 29659243Sobrienx: 29759243Sobrien if (p->v_parent == 0) /* is it the header? */ 29859243Sobrien return; 29959243Sobrien if (p->v_name) 30059243Sobrien tw_cmd_add(p->v_name); 30159243Sobrien if (p->v_right) { 30259243Sobrien p = p->v_right; 30359243Sobrien continue; 30459243Sobrien } 30559243Sobrien do { 30659243Sobrien c = p; 30759243Sobrien p = p->v_parent; 30859243Sobrien } while (p->v_right == c); 30959243Sobrien goto x; 31059243Sobrien } 31159243Sobrien} /* end tw_cmd_alias */ 31259243Sobrien 31359243Sobrien 31459243Sobrien/* tw_cmd_sort(): 31559243Sobrien * Sort the command list removing duplicate elements 31659243Sobrien */ 31759243Sobrienstatic void 318167465Smptw_cmd_sort(void) 31959243Sobrien{ 320167465Smp size_t fwd, i; 32159243Sobrien 322167465Smp pintr_disabled++; 32359243Sobrien /* sort the list. */ 324167465Smp qsort(tw_cmd.list, tw_cmd.nlist, sizeof(Char *), fcompare); 32559243Sobrien 32659243Sobrien /* get rid of multiple entries */ 327167465Smp for (i = 0, fwd = 0; i + 1 < tw_cmd.nlist; i++) { 32859243Sobrien if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */ 32959243Sobrien fwd++; /* increase the forward ref. count */ 33059243Sobrien else if (fwd) 33159243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 33259243Sobrien } 33359243Sobrien /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */ 33459243Sobrien if (fwd) 33559243Sobrien tw_cmd.list[i - fwd] = tw_cmd.list[i]; 33659243Sobrien tw_cmd.nlist -= fwd; 337167465Smp disabled_cleanup(&pintr_disabled); 33859243Sobrien} /* end tw_cmd_sort */ 33959243Sobrien 34059243Sobrien 34159243Sobrien/* tw_cmd_start(): 34259243Sobrien * Get the command list and sort it, if not done yet. 34359243Sobrien * Reset the current pointer to the beginning of the command list 34459243Sobrien */ 34559243Sobrien/*ARGSUSED*/ 34659243Sobrienvoid 347167465Smptw_cmd_start(DIR *dfd, const Char *pat) 34859243Sobrien{ 34959243Sobrien static Char *defpath[] = { STRNULL, 0 }; 35059243Sobrien USE(pat); 35159243Sobrien SETDIR(dfd) 35259243Sobrien if ((tw_cmd_got & TW_FL_CMD) == 0) { 35359243Sobrien tw_cmd_free(); 35459243Sobrien tw_cmd_cmd(); 35559243Sobrien tw_cmd_got |= TW_FL_CMD; 35659243Sobrien } 35759243Sobrien if ((tw_cmd_got & TW_FL_ALIAS) == 0) { 35859243Sobrien tw_cmd_alias(); 35959243Sobrien tw_cmd_got &= ~TW_FL_SORT; 36059243Sobrien tw_cmd_got |= TW_FL_ALIAS; 36159243Sobrien } 36259243Sobrien if ((tw_cmd_got & TW_FL_BUILTIN) == 0) { 36359243Sobrien tw_cmd_builtin(); 36459243Sobrien tw_cmd_got &= ~TW_FL_SORT; 36559243Sobrien tw_cmd_got |= TW_FL_BUILTIN; 36659243Sobrien } 36759243Sobrien if ((tw_cmd_got & TW_FL_SORT) == 0) { 36859243Sobrien tw_cmd_sort(); 36959243Sobrien tw_cmd_got |= TW_FL_SORT; 37059243Sobrien } 37159243Sobrien 37259243Sobrien tw_cmd_state.cur = 0; 37359243Sobrien CLRDIR(tw_cmd_state.dfd) 37459243Sobrien if (tw_cmd_got & TW_FL_REL) { 37559243Sobrien struct varent *vp = adrof(STRpath); 37659243Sobrien if (vp && vp->vec) 37759243Sobrien tw_cmd_state.pathv = vp->vec; 37859243Sobrien else 37959243Sobrien tw_cmd_state.pathv = defpath; 38059243Sobrien } 38159243Sobrien else 38259243Sobrien tw_cmd_state.pathv = defpath; 38359243Sobrien} /* tw_cmd_start */ 38459243Sobrien 38559243Sobrien 38659243Sobrien/* tw_cmd_next(): 38759243Sobrien * Return the next element in the command list or 38859243Sobrien * Look for commands in the relative path components 38959243Sobrien */ 390167465Smpint 391167465Smptw_cmd_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 39259243Sobrien{ 393167465Smp int ret = 0; 394167465Smp Char *ptr; 39559243Sobrien 39659243Sobrien if (tw_cmd_state.cur < tw_cmd.nlist) { 39759243Sobrien *flags = TW_DIR_OK; 398167465Smp Strbuf_append(res, tw_cmd.list[tw_cmd_state.cur++]); 399167465Smp return 1; 40059243Sobrien } 40159243Sobrien 40259243Sobrien /* 40359243Sobrien * We need to process relatives in the path. 40459243Sobrien */ 405167465Smp while ((tw_cmd_state.dfd == NULL || 406231990Smp (res->len = 0, ret = tw_dir_next(res, tw_cmd_state.dfd)) == 0) && 407167465Smp *tw_cmd_state.pathv != NULL) { 40859243Sobrien 40959243Sobrien CLRDIR(tw_cmd_state.dfd) 41059243Sobrien 41159243Sobrien while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/') 41259243Sobrien tw_cmd_state.pathv++; 41359243Sobrien if ((ptr = *tw_cmd_state.pathv) != 0) { 414231990Smp res->len = 0; 415167465Smp Strbuf_append(res, ptr); 416167465Smp ret = 1; 41759243Sobrien /* 41859243Sobrien * We complete directories only on '.' should that 41959243Sobrien * be changed? 42059243Sobrien */ 421167465Smp dir->len = 0; 42259243Sobrien if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) { 42359243Sobrien tw_cmd_state.dfd = opendir("."); 424167465Smp *flags = TW_DIR_OK | TW_EXEC_CHK; 42559243Sobrien } 42659243Sobrien else { 427167465Smp Strbuf_append(dir, *tw_cmd_state.pathv); 428167465Smp Strbuf_append1(dir, '/'); 42959243Sobrien tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv)); 43059243Sobrien *flags = TW_EXEC_CHK; 43159243Sobrien } 432167465Smp Strbuf_terminate(dir); 43359243Sobrien tw_cmd_state.pathv++; 43459243Sobrien } 43559243Sobrien } 436167465Smp return ret; 43759243Sobrien} /* end tw_cmd_next */ 43859243Sobrien 43959243Sobrien 44059243Sobrien/* tw_vptr_start(): 44159243Sobrien * Find the first variable in the variable list 44259243Sobrien */ 44359243Sobrienstatic void 444167465Smptw_vptr_start(struct varent *c) 44559243Sobrien{ 44659243Sobrien tw_vptr = c; /* start at beginning of variable list */ 44759243Sobrien 44859243Sobrien for (;;) { 44959243Sobrien while (tw_vptr->v_left) 45059243Sobrien tw_vptr = tw_vptr->v_left; 45159243Sobrienx: 45259243Sobrien if (tw_vptr->v_parent == 0) { /* is it the header? */ 45359243Sobrien tw_vptr = NULL; 45459243Sobrien return; 45559243Sobrien } 45659243Sobrien if (tw_vptr->v_name) 45759243Sobrien return; /* found first one */ 45859243Sobrien if (tw_vptr->v_right) { 45959243Sobrien tw_vptr = tw_vptr->v_right; 46059243Sobrien continue; 46159243Sobrien } 46259243Sobrien do { 46359243Sobrien c = tw_vptr; 46459243Sobrien tw_vptr = tw_vptr->v_parent; 46559243Sobrien } while (tw_vptr->v_right == c); 46659243Sobrien goto x; 46759243Sobrien } 46859243Sobrien} /* end tw_shvar_start */ 46959243Sobrien 47059243Sobrien 47159243Sobrien/* tw_shvar_next(): 47259243Sobrien * Return the next shell variable 47359243Sobrien */ 47459243Sobrien/*ARGSUSED*/ 475167465Smpint 476167465Smptw_shvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 47759243Sobrien{ 478145479Smp struct varent *p; 479145479Smp struct varent *c; 48059243Sobrien 48159243Sobrien USE(flags); 48259243Sobrien USE(dir); 48359243Sobrien if ((p = tw_vptr) == NULL) 484167465Smp return 0; /* just in case */ 48559243Sobrien 486167465Smp Strbuf_append(res, p->v_name); /* we know that this name is here now */ 48759243Sobrien 48859243Sobrien /* now find the next one */ 48959243Sobrien for (;;) { 49059243Sobrien if (p->v_right) { /* if we can go right */ 49159243Sobrien p = p->v_right; 49259243Sobrien while (p->v_left) 49359243Sobrien p = p->v_left; 49459243Sobrien } 49559243Sobrien else { /* else go up */ 49659243Sobrien do { 49759243Sobrien c = p; 49859243Sobrien p = p->v_parent; 49959243Sobrien } while (p->v_right == c); 50059243Sobrien } 50159243Sobrien if (p->v_parent == 0) { /* is it the header? */ 50259243Sobrien tw_vptr = NULL; 503167465Smp return 1; 50459243Sobrien } 50559243Sobrien if (p->v_name) { 50659243Sobrien tw_vptr = p; /* save state for the next call */ 507167465Smp return 1; 50859243Sobrien } 50959243Sobrien } 51059243Sobrien} /* end tw_shvar_next */ 51159243Sobrien 51259243Sobrien 51359243Sobrien/* tw_envvar_next(): 51459243Sobrien * Return the next environment variable 51559243Sobrien */ 51659243Sobrien/*ARGSUSED*/ 517167465Smpint 518167465Smptw_envvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 51959243Sobrien{ 520167465Smp const Char *ps; 52159243Sobrien 52259243Sobrien USE(flags); 52359243Sobrien USE(dir); 52459243Sobrien if (tw_env == NULL || *tw_env == NULL) 525167465Smp return 0; 526167465Smp for (ps = *tw_env; *ps && *ps != '='; ps++) 52759243Sobrien continue; 528167465Smp Strbuf_appendn(res, *tw_env, ps - *tw_env); 52959243Sobrien tw_env++; 530167465Smp return 1; 53159243Sobrien} /* end tw_envvar_next */ 53259243Sobrien 53359243Sobrien 53459243Sobrien/* tw_var_start(): 53559243Sobrien * Begin the list of the shell and environment variables 53659243Sobrien */ 53759243Sobrien/*ARGSUSED*/ 53859243Sobrienvoid 539167465Smptw_var_start(DIR *dfd, const Char *pat) 54059243Sobrien{ 54159243Sobrien USE(pat); 54259243Sobrien SETDIR(dfd) 54359243Sobrien tw_vptr_start(&shvhed); 54459243Sobrien tw_env = STR_environ; 54559243Sobrien} /* end tw_var_start */ 54659243Sobrien 54759243Sobrien 54859243Sobrien/* tw_alias_start(): 54959243Sobrien * Begin the list of the shell aliases 55059243Sobrien */ 55159243Sobrien/*ARGSUSED*/ 55259243Sobrienvoid 553167465Smptw_alias_start(DIR *dfd, const Char *pat) 55459243Sobrien{ 55559243Sobrien USE(pat); 55659243Sobrien SETDIR(dfd) 55759243Sobrien tw_vptr_start(&aliases); 55859243Sobrien tw_env = NULL; 55959243Sobrien} /* tw_alias_start */ 56059243Sobrien 56159243Sobrien 56259243Sobrien/* tw_complete_start(): 56359243Sobrien * Begin the list of completions 56459243Sobrien */ 56559243Sobrien/*ARGSUSED*/ 56659243Sobrienvoid 567167465Smptw_complete_start(DIR *dfd, const Char *pat) 56859243Sobrien{ 56959243Sobrien USE(pat); 57059243Sobrien SETDIR(dfd) 57159243Sobrien tw_vptr_start(&completions); 57259243Sobrien tw_env = NULL; 57359243Sobrien} /* end tw_complete_start */ 57459243Sobrien 57559243Sobrien 57659243Sobrien/* tw_var_next(): 57759243Sobrien * Return the next shell or environment variable 57859243Sobrien */ 579167465Smpint 580167465Smptw_var_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 58159243Sobrien{ 582167465Smp int ret = 0; 58359243Sobrien 58459243Sobrien if (tw_vptr) 585167465Smp ret = tw_shvar_next(res, dir, flags); 586167465Smp if (ret == 0 && tw_env) 587167465Smp ret = tw_envvar_next(res, dir, flags); 588167465Smp return ret; 58959243Sobrien} /* end tw_var_next */ 59059243Sobrien 59159243Sobrien 59259243Sobrien/* tw_logname_start(): 59359243Sobrien * Initialize lognames to the beginning of the list 59459243Sobrien */ 59559243Sobrien/*ARGSUSED*/ 59659243Sobrienvoid 597167465Smptw_logname_start(DIR *dfd, const Char *pat) 59859243Sobrien{ 59959243Sobrien USE(pat); 60059243Sobrien SETDIR(dfd) 601145479Smp#ifdef HAVE_GETPWENT 60259243Sobrien (void) setpwent(); /* Open passwd file */ 603145479Smp#endif 60459243Sobrien} /* end tw_logname_start */ 60559243Sobrien 60659243Sobrien 60759243Sobrien/* tw_logname_next(): 60859243Sobrien * Return the next entry from the passwd file 60959243Sobrien */ 61059243Sobrien/*ARGSUSED*/ 611167465Smpint 612167465Smptw_logname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 61359243Sobrien{ 61459243Sobrien struct passwd *pw; 615167465Smp 61659243Sobrien /* 61759243Sobrien * We don't want to get interrupted inside getpwent() 61859243Sobrien * because the yellow pages code is not interruptible, 61959243Sobrien * and if we call endpwent() immediatetely after 62059243Sobrien * (in pintr()) we may be freeing an invalid pointer 62159243Sobrien */ 62259243Sobrien USE(flags); 62359243Sobrien USE(dir); 624167465Smp pintr_disabled++; 625145479Smp#ifdef HAVE_GETPWENT 626145479Smp pw = getpwent(); 627145479Smp#else 62859243Sobrien pw = NULL; 629145479Smp#endif 630167465Smp disabled_cleanup(&pintr_disabled); 63159243Sobrien 63259243Sobrien if (pw == NULL) { 63359243Sobrien#ifdef YPBUGS 63459243Sobrien fix_yp_bugs(); 63559243Sobrien#endif 636167465Smp return 0; 63759243Sobrien } 638167465Smp Strbuf_append(res, str2short(pw->pw_name)); 639167465Smp return 1; 64059243Sobrien} /* end tw_logname_next */ 64159243Sobrien 64259243Sobrien 64359243Sobrien/* tw_logname_end(): 64459243Sobrien * Close the passwd file to finish the logname list 64559243Sobrien */ 64659243Sobrienvoid 647167465Smptw_logname_end(void) 64859243Sobrien{ 64959243Sobrien#ifdef YPBUGS 65059243Sobrien fix_yp_bugs(); 65159243Sobrien#endif 652145479Smp#ifdef HAVE_GETPWENT 65359243Sobrien (void) endpwent(); 654145479Smp#endif 65559243Sobrien} /* end tw_logname_end */ 65659243Sobrien 65759243Sobrien 65859243Sobrien/* tw_grpname_start(): 65959243Sobrien * Initialize grpnames to the beginning of the list 66059243Sobrien */ 66159243Sobrien/*ARGSUSED*/ 66259243Sobrienvoid 663167465Smptw_grpname_start(DIR *dfd, const Char *pat) 66459243Sobrien{ 66559243Sobrien USE(pat); 66659243Sobrien SETDIR(dfd) 667231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 66859243Sobrien (void) setgrent(); /* Open group file */ 66969408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 67059243Sobrien} /* end tw_grpname_start */ 67159243Sobrien 67259243Sobrien 67359243Sobrien/* tw_grpname_next(): 67459243Sobrien * Return the next entry from the group file 67559243Sobrien */ 67659243Sobrien/*ARGSUSED*/ 677167465Smpint 678167465Smptw_grpname_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 67959243Sobrien{ 68059243Sobrien struct group *gr; 681167465Smp 68259243Sobrien /* 68359243Sobrien * We don't want to get interrupted inside getgrent() 68459243Sobrien * because the yellow pages code is not interruptible, 68559243Sobrien * and if we call endgrent() immediatetely after 68659243Sobrien * (in pintr()) we may be freeing an invalid pointer 68759243Sobrien */ 68859243Sobrien USE(flags); 68959243Sobrien USE(dir); 690167465Smp pintr_disabled++; 691231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined(__ANDROID__) 692167465Smp errno = 0; 693167465Smp while ((gr = getgrent()) == NULL && errno == EINTR) { 694167465Smp handle_pending_signals(); 695167465Smp errno = 0; 696167465Smp } 69769408Sache#else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */ 69859243Sobrien gr = NULL; 69969408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 700167465Smp disabled_cleanup(&pintr_disabled); 70159243Sobrien 70259243Sobrien if (gr == NULL) { 70359243Sobrien#ifdef YPBUGS 70459243Sobrien fix_yp_bugs(); 70559243Sobrien#endif 706167465Smp return 0; 70759243Sobrien } 708167465Smp Strbuf_append(res, str2short(gr->gr_name)); 709167465Smp return 1; 71059243Sobrien} /* end tw_grpname_next */ 71159243Sobrien 71259243Sobrien 71359243Sobrien/* tw_grpname_end(): 71459243Sobrien * Close the group file to finish the groupname list 71559243Sobrien */ 71659243Sobrienvoid 717167465Smptw_grpname_end(void) 71859243Sobrien{ 71959243Sobrien#ifdef YPBUGS 72059243Sobrien fix_yp_bugs(); 72159243Sobrien#endif 722231990Smp#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__) 72359243Sobrien (void) endgrent(); 72469408Sache#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */ 72559243Sobrien} /* end tw_grpname_end */ 72659243Sobrien 72759243Sobrien/* tw_file_start(): 72859243Sobrien * Initialize the directory for the file list 72959243Sobrien */ 73059243Sobrien/*ARGSUSED*/ 73159243Sobrienvoid 732167465Smptw_file_start(DIR *dfd, const Char *pat) 73359243Sobrien{ 73459243Sobrien struct varent *vp; 73559243Sobrien USE(pat); 73659243Sobrien SETDIR(dfd) 73759243Sobrien if ((vp = adrof(STRcdpath)) != NULL) 73859243Sobrien tw_env = vp->vec; 73959243Sobrien} /* end tw_file_start */ 74059243Sobrien 74159243Sobrien 74259243Sobrien/* tw_file_next(): 74359243Sobrien * Return the next file in the directory 74459243Sobrien */ 745167465Smpint 746167465Smptw_file_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 74759243Sobrien{ 748167465Smp int ret = tw_dir_next(res, tw_dir_fd); 749167465Smp if (ret == 0 && (*flags & TW_DIR_OK) != 0) { 75059243Sobrien CLRDIR(tw_dir_fd) 75159243Sobrien while (tw_env && *tw_env) 75259243Sobrien if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL) 75359243Sobrien break; 75459243Sobrien else 75559243Sobrien tw_env++; 756167465Smp 75759243Sobrien if (tw_dir_fd) { 758167465Smp dir->len = 0; 759167465Smp Strbuf_append(dir, *tw_env++); 760167465Smp Strbuf_append1(dir, '/'); 761167465Smp Strbuf_terminate(dir); 762167465Smp ret = tw_dir_next(res, tw_dir_fd); 76359243Sobrien } 76459243Sobrien } 765167465Smp return ret; 76659243Sobrien} /* end tw_file_next */ 76759243Sobrien 76859243Sobrien 76959243Sobrien/* tw_dir_end(): 77059243Sobrien * Clear directory related lists 77159243Sobrien */ 77259243Sobrienvoid 773167465Smptw_dir_end(void) 77459243Sobrien{ 77559243Sobrien CLRDIR(tw_dir_fd) 77659243Sobrien CLRDIR(tw_cmd_state.dfd) 77759243Sobrien} /* end tw_dir_end */ 77859243Sobrien 77959243Sobrien 78059243Sobrien/* tw_item_free(): 78159243Sobrien * Free the item list 78259243Sobrien */ 78359243Sobrienvoid 784167465Smptw_item_free(void) 78559243Sobrien{ 78659243Sobrien tw_str_free(&tw_item); 78759243Sobrien} /* end tw_item_free */ 78859243Sobrien 78959243Sobrien 79059243Sobrien/* tw_item_get(): 79159243Sobrien * Return the list of items 79259243Sobrien */ 79359243SobrienChar ** 794167465Smptw_item_get(void) 79559243Sobrien{ 79659243Sobrien return tw_item.list; 79759243Sobrien} /* end tw_item_get */ 79859243Sobrien 79959243Sobrien 80059243Sobrien/* tw_item_add(): 801167465Smp * Return a new item for a Strbuf_terminate()'d s 80259243Sobrien */ 803167465Smpvoid 804167465Smptw_item_add(const struct Strbuf *s) 80559243Sobrien{ 806167465Smp Char *p; 807167465Smp 808167465Smp p = tw_str_add(&tw_item, s->len + 1); 809167465Smp Strcpy(p, s->s); 81059243Sobrien} /* tw_item_add */ 81159243Sobrien 81259243Sobrien 81359243Sobrien/* tw_item_find(): 81459243Sobrien * Find the string if it exists in the item list 81559243Sobrien * end return it. 81659243Sobrien */ 81759243SobrienChar * 818167465Smptw_item_find(Char *str) 81959243Sobrien{ 820167465Smp size_t i; 82159243Sobrien 82259243Sobrien if (tw_item.list == NULL || str == NULL) 82359243Sobrien return NULL; 82459243Sobrien 82559243Sobrien for (i = 0; i < tw_item.nlist; i++) 82659243Sobrien if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0) 82759243Sobrien return tw_item.list[i]; 82859243Sobrien return NULL; 82959243Sobrien} /* end tw_item_find */ 83059243Sobrien 83159243Sobrien 83259243Sobrien/* tw_vl_start(): 83359243Sobrien * Initialize a variable list 83459243Sobrien */ 83559243Sobrienvoid 836167465Smptw_vl_start(DIR *dfd, const Char *pat) 83759243Sobrien{ 83859243Sobrien SETDIR(dfd) 83959243Sobrien if ((tw_vptr = adrof(pat)) != NULL) { 84059243Sobrien tw_env = tw_vptr->vec; 84159243Sobrien tw_vptr = NULL; 84259243Sobrien } 84359243Sobrien else 84459243Sobrien tw_env = NULL; 84559243Sobrien} /* end tw_vl_start */ 84659243Sobrien 84759243Sobrien 84859243Sobrien/* 84959243Sobrien * Initialize a word list 85059243Sobrien */ 85159243Sobrienvoid 852167465Smptw_wl_start(DIR *dfd, const Char *pat) 85359243Sobrien{ 85459243Sobrien SETDIR(dfd); 85559243Sobrien tw_word = pat; 85659243Sobrien} /* end tw_wl_start */ 85759243Sobrien 85859243Sobrien 85959243Sobrien/* 86059243Sobrien * Return the next word from the word list 86159243Sobrien */ 86259243Sobrien/*ARGSUSED*/ 863167465Smpint 864167465Smptw_wl_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 86559243Sobrien{ 866167465Smp const Char *p; 867167465Smp 868167465Smp USE(dir); 86959243Sobrien USE(flags); 87059243Sobrien if (tw_word == NULL || tw_word[0] == '\0') 871167465Smp return 0; 872167465Smp 87359243Sobrien while (*tw_word && Isspace(*tw_word)) tw_word++; 87459243Sobrien 875167465Smp for (p = tw_word; *tw_word && !Isspace(*tw_word); tw_word++) 87659243Sobrien continue; 877167465Smp if (tw_word == p) 878167465Smp return 0; 879167465Smp Strbuf_appendn(res, p, tw_word - p); 88059243Sobrien if (*tw_word) 881167465Smp tw_word++; 882167465Smp return 1; 88359243Sobrien} /* end tw_wl_next */ 88459243Sobrien 88559243Sobrien 88659243Sobrien/* tw_bind_start(): 88759243Sobrien * Begin the list of the shell bindings 88859243Sobrien */ 88959243Sobrien/*ARGSUSED*/ 89059243Sobrienvoid 891167465Smptw_bind_start(DIR *dfd, const Char *pat) 89259243Sobrien{ 89359243Sobrien USE(pat); 89459243Sobrien SETDIR(dfd) 89559243Sobrien tw_bind = FuncNames; 89659243Sobrien} /* end tw_bind_start */ 89759243Sobrien 89859243Sobrien 89959243Sobrien/* tw_bind_next(): 90059243Sobrien * Begin the list of the shell bindings 90159243Sobrien */ 90259243Sobrien/*ARGSUSED*/ 903167465Smpint 904167465Smptw_bind_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 90559243Sobrien{ 906167465Smp USE(dir); 90759243Sobrien USE(flags); 90859243Sobrien if (tw_bind && tw_bind->name) { 909167465Smp const char *ptr; 910167465Smp 911167465Smp for (ptr = tw_bind->name; *ptr != '\0'; ptr++) 912167465Smp Strbuf_append1(res, *ptr); 91359243Sobrien tw_bind++; 914167465Smp return 1; 91559243Sobrien } 916167465Smp return 0; 91759243Sobrien} /* end tw_bind_next */ 91859243Sobrien 91959243Sobrien 92059243Sobrien/* tw_limit_start(): 92159243Sobrien * Begin the list of the shell limitings 92259243Sobrien */ 92359243Sobrien/*ARGSUSED*/ 92459243Sobrienvoid 925167465Smptw_limit_start(DIR *dfd, const Char *pat) 92659243Sobrien{ 92759243Sobrien USE(pat); 92859243Sobrien SETDIR(dfd) 92959243Sobrien#ifndef HAVENOLIMIT 93059243Sobrien tw_limit = limits; 93159243Sobrien#endif /* ! HAVENOLIMIT */ 93259243Sobrien} /* end tw_limit_start */ 93359243Sobrien 93459243Sobrien 93559243Sobrien/* tw_limit_next(): 93659243Sobrien * Begin the list of the shell limitings 93759243Sobrien */ 93859243Sobrien/*ARGSUSED*/ 939167465Smpint 940167465Smptw_limit_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 94159243Sobrien{ 942167465Smp USE(dir); 943167465Smp USE(flags); 94459243Sobrien#ifndef HAVENOLIMIT 94559243Sobrien if (tw_limit && tw_limit->limname) { 946167465Smp const char *ptr; 947167465Smp 948167465Smp for (ptr = tw_limit->limname; *ptr != '\0'; ptr++) 949167465Smp Strbuf_append1(res, *ptr); 95059243Sobrien tw_limit++; 951167465Smp return 1; 95259243Sobrien } 95359243Sobrien#endif /* ! HAVENOLIMIT */ 954167465Smp return 0; 95559243Sobrien} /* end tw_limit_next */ 95659243Sobrien 95759243Sobrien 95859243Sobrien/* tw_sig_start(): 95959243Sobrien * Begin the list of the shell sigings 96059243Sobrien */ 96159243Sobrien/*ARGSUSED*/ 96259243Sobrienvoid 963167465Smptw_sig_start(DIR *dfd, const Char *pat) 96459243Sobrien{ 96559243Sobrien USE(pat); 96659243Sobrien SETDIR(dfd) 96759243Sobrien tw_index = 0; 96859243Sobrien} /* end tw_sig_start */ 96959243Sobrien 97059243Sobrien 97159243Sobrien/* tw_sig_next(): 97259243Sobrien * Begin the list of the shell sigings 97359243Sobrien */ 97459243Sobrien/*ARGSUSED*/ 975167465Smpint 976167465Smptw_sig_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 97759243Sobrien{ 978167465Smp USE(dir); 97959243Sobrien USE(flags); 98059243Sobrien for (;tw_index < nsig; tw_index++) { 981167465Smp const char *ptr; 98259243Sobrien 98359243Sobrien if (mesg[tw_index].iname == NULL) 98459243Sobrien continue; 98559243Sobrien 986167465Smp for (ptr = mesg[tw_index].iname; *ptr != '\0'; ptr++) 987167465Smp Strbuf_append1(res, *ptr); 98859243Sobrien tw_index++; 989167465Smp return 1; 99059243Sobrien } 991167465Smp return 0; 99259243Sobrien} /* end tw_sig_next */ 99359243Sobrien 99459243Sobrien 99559243Sobrien/* tw_job_start(): 99659243Sobrien * Begin the list of the shell jobings 99759243Sobrien */ 99859243Sobrien/*ARGSUSED*/ 99959243Sobrienvoid 1000167465Smptw_job_start(DIR *dfd, const Char *pat) 100159243Sobrien{ 100259243Sobrien USE(pat); 100359243Sobrien SETDIR(dfd) 100459243Sobrien tw_index = 1; 100559243Sobrien} /* end tw_job_start */ 100659243Sobrien 100759243Sobrien 100859243Sobrien/* tw_job_next(): 100959243Sobrien * Begin the list of the shell jobings 101059243Sobrien */ 101159243Sobrien/*ARGSUSED*/ 1012167465Smpint 1013167465Smptw_job_next(struct Strbuf *res, struct Strbuf *dir, int *flags) 101459243Sobrien{ 101559243Sobrien struct process *j; 101659243Sobrien 1017167465Smp USE(dir); 101859243Sobrien USE(flags); 101959243Sobrien for (;tw_index <= pmaxindex; tw_index++) { 102059243Sobrien for (j = proclist.p_next; j != NULL; j = j->p_next) 102159243Sobrien if (j->p_index == tw_index && j->p_procid == j->p_jobid) 102259243Sobrien break; 102359243Sobrien if (j == NULL) 102459243Sobrien continue; 1025167465Smp Strbuf_append(res, j->p_command); 102659243Sobrien tw_index++; 1027167465Smp return 1; 102859243Sobrien } 1029167465Smp return 0; 103059243Sobrien} /* end tw_job_next */ 1031