tw.init.c revision 69408
1189647Sdelphij/* $Header: /src/pub/tcsh/tw.init.c,v 3.27 2000/11/11 23:03:40 christos Exp $ */
2129203Scognet/*
3129203Scognet * tw.init.c: Handle lists of things to complete
4129203Scognet */
5129203Scognet/*-
6129203Scognet * Copyright (c) 1980, 1991 The Regents of the University of California.
7129203Scognet * All rights reserved.
8129203Scognet *
9129203Scognet * Redistribution and use in source and binary forms, with or without
10129203Scognet * modification, are permitted provided that the following conditions
11129203Scognet * are met:
12129203Scognet * 1. Redistributions of source code must retain the above copyright
13129203Scognet *    notice, this list of conditions and the following disclaimer.
14129203Scognet * 2. Redistributions in binary form must reproduce the above copyright
15129203Scognet *    notice, this list of conditions and the following disclaimer in the
16129203Scognet *    documentation and/or other materials provided with the distribution.
17129203Scognet * 3. All advertising materials mentioning features or use of this software
18129203Scognet *    must display the following acknowledgement:
19129203Scognet *	This product includes software developed by the University of
20129203Scognet *	California, Berkeley and its contributors.
21129203Scognet * 4. Neither the name of the University nor the names of its contributors
22129203Scognet *    may be used to endorse or promote products derived from this software
23129203Scognet *    without specific prior written permission.
24129203Scognet *
25129203Scognet * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26129203Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27129203Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28129203Scognet * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29129203Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30129203Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31129203Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32129203Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33129203Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34129203Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35129203Scognet * SUCH DAMAGE.
36129203Scognet */
37129203Scognet#include "sh.h"
38129203Scognet
39129203ScognetRCSID("$Id: tw.init.c,v 3.27 2000/11/11 23:03:40 christos Exp $")
40129203Scognet
41129203Scognet#include "tw.h"
42129203Scognet#include "ed.h"
43129203Scognet#include "tc.h"
44129203Scognet#include "sh.proc.h"
45129203Scognet
46129203Scognet#if !defined(NSIG) && defined(SIGMAX)
47129203Scognet# define NSIG (SIGMAX+1)
48129203Scognet#endif /* !NSIG && SIGMAX */
49129203Scognet#if !defined(NSIG) && defined(_NSIG)
50129203Scognet# define NSIG _NSIG
51129203Scognet#endif /* !NSIG && _NSIG */
52129203Scognet
53129203Scognet#define TW_INCR	128
54129203Scognet
55129203Scognettypedef struct {
56129203Scognet    Char **list, 			/* List of command names	*/
57	  *buff;			/* Space holding command names	*/
58    int    nlist, 			/* Number of items		*/
59           nbuff,			/* Current space in name buf	*/
60           tlist,			/* Total space in list		*/
61	   tbuff;			/* Total space in name buf	*/
62} stringlist_t;
63
64
65static struct varent *tw_vptr = NULL;	/* Current shell variable 	*/
66static Char **tw_env = NULL;		/* Current environment variable */
67static Char  *tw_word;			/* Current word pointer		*/
68static struct KeyFuncs *tw_bind = NULL;	/* List of the bindings		*/
69#ifndef HAVENOLIMIT
70static struct limits *tw_limit = NULL;	/* List of the resource limits	*/
71#endif /* HAVENOLIMIT */
72static int tw_index = 0;		/* signal and job index		*/
73static DIR   *tw_dir_fd = NULL;		/* Current directory descriptor	*/
74static Char   tw_retname[MAXPATHLEN+1];	/* Return buffer		*/
75static int    tw_cmd_got = 0;		/* What we need to do		*/
76static stringlist_t tw_cmd  = { NULL, NULL, 0, 0, 0, 0 };
77static stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 };
78#define TW_FL_CMD	0x01
79#define TW_FL_ALIAS	0x02
80#define TW_FL_BUILTIN	0x04
81#define TW_FL_SORT	0x08
82#define TW_FL_REL	0x10
83
84static struct {				/* Current element pointer	*/
85    int    cur;				/* Current element number	*/
86    Char **pathv;			/* Current element in path	*/
87    DIR   *dfd;				/* Current directory descriptor	*/
88} tw_cmd_state;
89
90
91#ifdef BSDSIGS
92static sigmask_t tw_omask;
93# define TW_HOLD()	tw_omask = sigblock(sigmask(SIGINT))
94# define TW_RELS()	(void) sigsetmask(tw_omask)
95#else /* !BSDSIGS */
96# define TW_HOLD()	(void) sighold(SIGINT)
97# define TW_RELS()	(void) sigrelse(SIGINT)
98#endif /* BSDSIGS */
99
100#define SETDIR(dfd) \
101    { \
102	tw_dir_fd = dfd; \
103	if (tw_dir_fd != NULL) \
104	    rewinddir(tw_dir_fd); \
105    }
106
107#define CLRDIR(dfd) \
108    if (dfd != NULL) { \
109	TW_HOLD(); \
110	(void) closedir(dfd); \
111	dfd = NULL; \
112	TW_RELS(); \
113    }
114
115static Char	*tw_str_add		__P((stringlist_t *, int));
116static void	 tw_str_free		__P((stringlist_t *));
117static Char     *tw_dir_next		__P((DIR *));
118static void	 tw_cmd_add 		__P((Char *name));
119static void 	 tw_cmd_cmd		__P((void));
120static void	 tw_cmd_builtin		__P((void));
121static void	 tw_cmd_alias		__P((void));
122static void	 tw_cmd_sort		__P((void));
123static void 	 tw_vptr_start		__P((struct varent *));
124
125
126/* tw_str_add():
127 *	Add an item to the string list
128 */
129static Char *
130tw_str_add(sl, len)
131    stringlist_t *sl;
132    int len;
133{
134    Char *ptr;
135
136    if (sl->tlist <= sl->nlist) {
137	TW_HOLD();
138	sl->tlist += TW_INCR;
139	sl->list = sl->list ?
140		    (Char **) xrealloc((ptr_t) sl->list,
141				       (size_t) (sl->tlist * sizeof(Char *))) :
142		    (Char **) xmalloc((size_t) (sl->tlist * sizeof(Char *)));
143	TW_RELS();
144    }
145    if (sl->tbuff <= sl->nbuff + len) {
146	int i;
147	ptr = sl->buff;
148
149	TW_HOLD();
150	sl->tbuff += TW_INCR + len;
151	sl->buff = sl->buff ?
152		    (Char *) xrealloc((ptr_t) sl->buff,
153				      (size_t) (sl->tbuff * sizeof(Char))) :
154		    (Char *) xmalloc((size_t) (sl->tbuff * sizeof(Char)));
155	/* Re-thread the new pointer list, if changed */
156	if (ptr != NULL && ptr != sl->buff) {
157	    int offs = (int) (sl->buff - ptr);
158	    for (i = 0; i < sl->nlist; i++)
159		sl->list[i] += offs;
160	}
161	TW_RELS();
162    }
163    ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff];
164    sl->nbuff += len;
165    return ptr;
166} /* tw_str_add */
167
168
169/* tw_str_free():
170 *	Free a stringlist
171 */
172static void
173tw_str_free(sl)
174    stringlist_t *sl;
175{
176    TW_HOLD();
177    if (sl->list) {
178	xfree((ptr_t) sl->list);
179	sl->list = NULL;
180	sl->tlist = sl->nlist = 0;
181    }
182    if (sl->buff) {
183	xfree((ptr_t) sl->buff);
184	sl->buff = NULL;
185	sl->tbuff = sl->nbuff = 0;
186    }
187    TW_RELS();
188} /* end tw_str_free */
189
190
191static Char *
192tw_dir_next(dfd)
193    DIR *dfd;
194{
195    register struct dirent *dirp;
196
197    if (dfd == NULL)
198	return NULL;
199
200    if ((dirp = readdir(dfd)) != NULL) {
201	(void) Strcpy(tw_retname, str2short(dirp->d_name));
202	return (tw_retname);
203    }
204    return NULL;
205} /* end tw_dir_next */
206
207
208/* tw_cmd_add():
209 *	Add the name to the command list
210 */
211static void
212tw_cmd_add(name)
213    Char *name;
214{
215    int len;
216
217    len = (int) Strlen(name) + 2;
218    (void) Strcpy(tw_str_add(&tw_cmd, len), name);
219} /* end tw_cmd_add */
220
221
222/* tw_cmd_free():
223 *	Free the command list
224 */
225void
226tw_cmd_free()
227{
228    CLRDIR(tw_dir_fd)
229    tw_str_free(&tw_cmd);
230    tw_cmd_got = 0;
231} /* end tw_cmd_free */
232
233/* tw_cmd_cmd():
234 *	Add system commands to the command list
235 */
236static void
237tw_cmd_cmd()
238{
239    register DIR *dirp;
240    register struct dirent *dp;
241    register Char *dir = NULL, *name;
242    register Char **pv;
243    struct varent *v = adrof(STRpath);
244    struct varent *recexec = adrof(STRrecognize_only_executables);
245    int len;
246
247
248    if (v == NULL) /* if no path */
249	return;
250
251    for (pv = v->vec; *pv; pv++) {
252	if (pv[0][0] != '/') {
253	    tw_cmd_got |= TW_FL_REL;
254	    continue;
255	}
256
257	if ((dirp = opendir(short2str(*pv))) == NULL)
258	    continue;
259
260	if (recexec)
261	    dir = Strspl(*pv, STRslash);
262	while ((dp = readdir(dirp)) != NULL) {
263#if defined(_UWIN) || defined(__CYGWIN__)
264	    /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
265	     * the file with the .exe, .com, .bat extension
266	     */
267	    size_t ext = strlen(dp->d_name) - 4;
268	    if ((ext > 0) && (strcmp(&dp->d_name[ext], ".exe") == 0 ||
269		strcmp(&dp->d_name[ext], ".bat") == 0 ||
270		strcmp(&dp->d_name[ext], ".com") == 0))
271		dp->d_name[ext] = '\0';
272#endif /* _UWIN || __CYGWIN__ */
273	    /* the call to executable() may make this a bit slow */
274	    name = str2short(dp->d_name);
275	    if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0)))
276		continue;
277            len = (int) Strlen(name) + 2;
278            if (name[0] == '#' ||	/* emacs temp files	*/
279		name[0] == '.' ||	/* .files		*/
280		name[len - 3] == '~' ||	/* emacs backups	*/
281		name[len - 3] == '%')	/* textedit backups	*/
282                continue;		/* Ignore!		*/
283            tw_cmd_add(name);
284	}
285	(void) closedir(dirp);
286	if (recexec)
287	    xfree((ptr_t) dir);
288    }
289} /* end tw_cmd_cmd */
290
291
292/* tw_cmd_builtin():
293 *	Add builtins to the command list
294 */
295static void
296tw_cmd_builtin()
297{
298    register struct biltins *bptr;
299
300    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++)
301	if (bptr->bname)
302	    tw_cmd_add(str2short(bptr->bname));
303#ifdef WINNT_NATIVE
304    for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++)
305	if (bptr->bname)
306	    tw_cmd_add(str2short(bptr->bname));
307#endif /* WINNT_NATIVE*/
308} /* end tw_cmd_builtin */
309
310
311/* tw_cmd_alias():
312 *	Add aliases to the command list
313 */
314static void
315tw_cmd_alias()
316{
317    register struct varent *p;
318    register struct varent *c;
319
320    p = &aliases;
321    for (;;) {
322	while (p->v_left)
323	    p = p->v_left;
324x:
325	if (p->v_parent == 0) /* is it the header? */
326	    return;
327	if (p->v_name)
328	    tw_cmd_add(p->v_name);
329	if (p->v_right) {
330	    p = p->v_right;
331	    continue;
332	}
333	do {
334	    c = p;
335	    p = p->v_parent;
336	} while (p->v_right == c);
337	goto x;
338    }
339} /* end tw_cmd_alias */
340
341
342/* tw_cmd_sort():
343 *	Sort the command list removing duplicate elements
344 */
345static void
346tw_cmd_sort()
347{
348    int fwd, i;
349
350    TW_HOLD();
351    /* sort the list. */
352    qsort((ptr_t) tw_cmd.list, (size_t) tw_cmd.nlist, sizeof(Char *),
353	  (int (*) __P((const void *, const void *))) fcompare);
354
355    /* get rid of multiple entries */
356    for (i = 0, fwd = 0; i < tw_cmd.nlist - 1; i++) {
357	if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */
358	    fwd++;		/* increase the forward ref. count */
359	else if (fwd)
360	    tw_cmd.list[i - fwd] = tw_cmd.list[i];
361    }
362    /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */
363    if (fwd)
364	tw_cmd.list[i - fwd] = tw_cmd.list[i];
365    tw_cmd.nlist -= fwd;
366    TW_RELS();
367} /* end tw_cmd_sort */
368
369
370/* tw_cmd_start():
371 *	Get the command list and sort it, if not done yet.
372 *	Reset the current pointer to the beginning of the command list
373 */
374/*ARGSUSED*/
375void
376tw_cmd_start(dfd, pat)
377    DIR *dfd;
378    Char *pat;
379{
380    static Char *defpath[] = { STRNULL, 0 };
381    USE(pat);
382    SETDIR(dfd)
383    if ((tw_cmd_got & TW_FL_CMD) == 0) {
384	tw_cmd_free();
385	tw_cmd_cmd();
386	tw_cmd_got |= TW_FL_CMD;
387    }
388    if ((tw_cmd_got & TW_FL_ALIAS) == 0) {
389	tw_cmd_alias();
390	tw_cmd_got &= ~TW_FL_SORT;
391	tw_cmd_got |= TW_FL_ALIAS;
392    }
393    if ((tw_cmd_got & TW_FL_BUILTIN) == 0) {
394	tw_cmd_builtin();
395	tw_cmd_got &= ~TW_FL_SORT;
396	tw_cmd_got |= TW_FL_BUILTIN;
397    }
398    if ((tw_cmd_got & TW_FL_SORT) == 0) {
399	tw_cmd_sort();
400	tw_cmd_got |= TW_FL_SORT;
401    }
402
403    tw_cmd_state.cur = 0;
404    CLRDIR(tw_cmd_state.dfd)
405    if (tw_cmd_got & TW_FL_REL) {
406	struct varent *vp = adrof(STRpath);
407	if (vp && vp->vec)
408	    tw_cmd_state.pathv = vp->vec;
409	else
410	    tw_cmd_state.pathv = defpath;
411    }
412    else
413	tw_cmd_state.pathv = defpath;
414} /* tw_cmd_start */
415
416
417/* tw_cmd_next():
418 *	Return the next element in the command list or
419 *	Look for commands in the relative path components
420 */
421Char *
422tw_cmd_next(dir, flags)
423    Char *dir;
424    int  *flags;
425{
426    Char *ptr = NULL;
427
428    if (tw_cmd_state.cur < tw_cmd.nlist) {
429	*flags = TW_DIR_OK;
430	return tw_cmd.list[tw_cmd_state.cur++];
431    }
432
433    /*
434     * We need to process relatives in the path.
435     */
436    while (((tw_cmd_state.dfd == NULL) ||
437	    ((ptr = tw_dir_next(tw_cmd_state.dfd)) == NULL)) &&
438	   (*tw_cmd_state.pathv != NULL)) {
439
440        CLRDIR(tw_cmd_state.dfd)
441
442	while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/')
443	    tw_cmd_state.pathv++;
444	if ((ptr = *tw_cmd_state.pathv) != 0) {
445	    /*
446	     * We complete directories only on '.' should that
447	     * be changed?
448	     */
449	    if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) {
450		*dir = '\0';
451		tw_cmd_state.dfd = opendir(".");
452		*flags = TW_DIR_OK | TW_EXEC_CHK;
453	    }
454	    else {
455		copyn(dir, *tw_cmd_state.pathv, FILSIZ);
456		catn(dir, STRslash, FILSIZ);
457		tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv));
458		*flags = TW_EXEC_CHK;
459	    }
460	    tw_cmd_state.pathv++;
461	}
462    }
463    return ptr;
464} /* end tw_cmd_next */
465
466
467/* tw_vptr_start():
468 *	Find the first variable in the variable list
469 */
470static void
471tw_vptr_start(c)
472    struct varent *c;
473{
474    tw_vptr = c;		/* start at beginning of variable list */
475
476    for (;;) {
477	while (tw_vptr->v_left)
478	    tw_vptr = tw_vptr->v_left;
479x:
480	if (tw_vptr->v_parent == 0) {	/* is it the header? */
481	    tw_vptr = NULL;
482	    return;
483	}
484	if (tw_vptr->v_name)
485	    return;		/* found first one */
486	if (tw_vptr->v_right) {
487	    tw_vptr = tw_vptr->v_right;
488	    continue;
489	}
490	do {
491	    c = tw_vptr;
492	    tw_vptr = tw_vptr->v_parent;
493	} while (tw_vptr->v_right == c);
494	goto x;
495    }
496} /* end tw_shvar_start */
497
498
499/* tw_shvar_next():
500 *	Return the next shell variable
501 */
502/*ARGSUSED*/
503Char *
504tw_shvar_next(dir, flags)
505    Char *dir;
506    int	 *flags;
507{
508    register struct varent *p;
509    register struct varent *c;
510    register Char *cp;
511
512    USE(flags);
513    USE(dir);
514    if ((p = tw_vptr) == NULL)
515	return (NULL);		/* just in case */
516
517    cp = p->v_name;		/* we know that this name is here now */
518
519    /* now find the next one */
520    for (;;) {
521	if (p->v_right) {	/* if we can go right */
522	    p = p->v_right;
523	    while (p->v_left)
524		p = p->v_left;
525	}
526	else {			/* else go up */
527	    do {
528		c = p;
529		p = p->v_parent;
530	    } while (p->v_right == c);
531	}
532	if (p->v_parent == 0) {	/* is it the header? */
533	    tw_vptr = NULL;
534	    return (cp);
535	}
536	if (p->v_name) {
537	    tw_vptr = p;	/* save state for the next call */
538	    return (cp);
539	}
540    }
541} /* end tw_shvar_next */
542
543
544/* tw_envvar_next():
545 *	Return the next environment variable
546 */
547/*ARGSUSED*/
548Char *
549tw_envvar_next(dir, flags)
550    Char *dir;
551    int *flags;
552{
553    Char   *ps, *pd;
554
555    USE(flags);
556    USE(dir);
557    if (tw_env == NULL || *tw_env == NULL)
558	return (NULL);
559    for (ps = *tw_env, pd = tw_retname;
560	 *ps && *ps != '=' && pd <= &tw_retname[MAXPATHLEN]; *pd++ = *ps++)
561	continue;
562    *pd = '\0';
563    tw_env++;
564    return (tw_retname);
565} /* end tw_envvar_next */
566
567
568/* tw_var_start():
569 *	Begin the list of the shell and environment variables
570 */
571/*ARGSUSED*/
572void
573tw_var_start(dfd, pat)
574    DIR *dfd;
575    Char *pat;
576{
577    USE(pat);
578    SETDIR(dfd)
579    tw_vptr_start(&shvhed);
580    tw_env = STR_environ;
581} /* end tw_var_start */
582
583
584/* tw_alias_start():
585 *	Begin the list of the shell aliases
586 */
587/*ARGSUSED*/
588void
589tw_alias_start(dfd, pat)
590    DIR *dfd;
591    Char *pat;
592{
593    USE(pat);
594    SETDIR(dfd)
595    tw_vptr_start(&aliases);
596    tw_env = NULL;
597} /* tw_alias_start */
598
599
600/* tw_complete_start():
601 *	Begin the list of completions
602 */
603/*ARGSUSED*/
604void
605tw_complete_start(dfd, pat)
606    DIR *dfd;
607    Char *pat;
608{
609    extern struct varent completions;
610
611    USE(pat);
612    SETDIR(dfd)
613    tw_vptr_start(&completions);
614    tw_env = NULL;
615} /* end tw_complete_start */
616
617
618/* tw_var_next():
619 *	Return the next shell or environment variable
620 */
621Char *
622tw_var_next(dir, flags)
623    Char *dir;
624    int  *flags;
625{
626    Char *ptr = NULL;
627
628    if (tw_vptr)
629	ptr = tw_shvar_next(dir, flags);
630    if (!ptr && tw_env)
631	ptr = tw_envvar_next(dir, flags);
632    return ptr;
633} /* end tw_var_next */
634
635
636/* tw_logname_start():
637 *	Initialize lognames to the beginning of the list
638 */
639/*ARGSUSED*/
640void
641tw_logname_start(dfd, pat)
642    DIR *dfd;
643    Char *pat;
644{
645    USE(pat);
646    SETDIR(dfd)
647#if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE)
648    (void) setpwent();	/* Open passwd file */
649#endif /* !_VMS_POSIX && !WINNT_NATIVE */
650} /* end tw_logname_start */
651
652
653/* tw_logname_next():
654 *	Return the next entry from the passwd file
655 */
656/*ARGSUSED*/
657Char *
658tw_logname_next(dir, flags)
659    Char *dir;
660    int  *flags;
661{
662    static Char retname[MAXPATHLEN];
663    struct passwd *pw;
664    /*
665     * We don't want to get interrupted inside getpwent()
666     * because the yellow pages code is not interruptible,
667     * and if we call endpwent() immediatetely after
668     * (in pintr()) we may be freeing an invalid pointer
669     */
670    USE(flags);
671    USE(dir);
672    TW_HOLD();
673#if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE)
674    /* ISC does not declare getpwent()? */
675    pw = (struct passwd *) getpwent();
676#else /* _VMS_POSIX || WINNT_NATIVE */
677    pw = NULL;
678#endif /* !_VMS_POSIX && !WINNT_NATIVE */
679    TW_RELS();
680
681    if (pw == NULL) {
682#ifdef YPBUGS
683	fix_yp_bugs();
684#endif
685	return (NULL);
686    }
687    (void) Strcpy(retname, str2short(pw->pw_name));
688    return (retname);
689} /* end tw_logname_next */
690
691
692/* tw_logname_end():
693 *	Close the passwd file to finish the logname list
694 */
695void
696tw_logname_end()
697{
698#ifdef YPBUGS
699    fix_yp_bugs();
700#endif
701#if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE)
702   (void) endpwent();
703#endif /* !_VMS_POSIX && !WINNT_NATIVE */
704} /* end tw_logname_end */
705
706
707/* tw_grpname_start():
708 *	Initialize grpnames to the beginning of the list
709 */
710/*ARGSUSED*/
711void
712tw_grpname_start(dfd, pat)
713    DIR *dfd;
714    Char *pat;
715{
716    USE(pat);
717    SETDIR(dfd)
718#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE)
719    (void) setgrent();	/* Open group file */
720#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
721} /* end tw_grpname_start */
722
723
724/* tw_grpname_next():
725 *	Return the next entry from the group file
726 */
727/*ARGSUSED*/
728Char *
729tw_grpname_next(dir, flags)
730    Char *dir;
731    int  *flags;
732{
733    static Char retname[MAXPATHLEN];
734    struct group *gr;
735    /*
736     * We don't want to get interrupted inside getgrent()
737     * because the yellow pages code is not interruptible,
738     * and if we call endgrent() immediatetely after
739     * (in pintr()) we may be freeing an invalid pointer
740     */
741    USE(flags);
742    USE(dir);
743    TW_HOLD();
744#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE)
745    gr = (struct group *) getgrent();
746#else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */
747    gr = NULL;
748#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
749    TW_RELS();
750
751    if (gr == NULL) {
752#ifdef YPBUGS
753	fix_yp_bugs();
754#endif
755	return (NULL);
756    }
757    (void) Strcpy(retname, str2short(gr->gr_name));
758    return (retname);
759} /* end tw_grpname_next */
760
761
762/* tw_grpname_end():
763 *	Close the group file to finish the groupname list
764 */
765void
766tw_grpname_end()
767{
768#ifdef YPBUGS
769    fix_yp_bugs();
770#endif
771#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE)
772   (void) endgrent();
773#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
774} /* end tw_grpname_end */
775
776/* tw_file_start():
777 *	Initialize the directory for the file list
778 */
779/*ARGSUSED*/
780void
781tw_file_start(dfd, pat)
782    DIR *dfd;
783    Char *pat;
784{
785    struct varent *vp;
786    USE(pat);
787    SETDIR(dfd)
788    if ((vp = adrof(STRcdpath)) != NULL)
789	tw_env = vp->vec;
790} /* end tw_file_start */
791
792
793/* tw_file_next():
794 *	Return the next file in the directory
795 */
796Char *
797tw_file_next(dir, flags)
798    Char *dir;
799    int  *flags;
800{
801    Char *ptr = tw_dir_next(tw_dir_fd);
802    if (ptr == NULL && (*flags & TW_DIR_OK) != 0) {
803	CLRDIR(tw_dir_fd)
804	while (tw_env && *tw_env)
805	    if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL)
806		break;
807	    else
808		tw_env++;
809
810	if (tw_dir_fd) {
811	    copyn(dir, *tw_env++, MAXPATHLEN);
812	    catn(dir, STRslash, MAXPATHLEN);
813	    ptr = tw_dir_next(tw_dir_fd);
814	}
815    }
816    return ptr;
817} /* end tw_file_next */
818
819
820/* tw_dir_end():
821 *	Clear directory related lists
822 */
823void
824tw_dir_end()
825{
826   CLRDIR(tw_dir_fd)
827   CLRDIR(tw_cmd_state.dfd)
828} /* end tw_dir_end */
829
830
831/* tw_item_free():
832 *	Free the item list
833 */
834void
835tw_item_free()
836{
837    tw_str_free(&tw_item);
838} /* end tw_item_free */
839
840
841/* tw_item_get():
842 *	Return the list of items
843 */
844Char **
845tw_item_get()
846{
847    return tw_item.list;
848} /* end tw_item_get */
849
850
851/* tw_item_add():
852 *	Return a new item
853 */
854Char *
855tw_item_add(len)
856    int len;
857{
858     return tw_str_add(&tw_item, len);
859} /* tw_item_add */
860
861
862/* tw_item_find():
863 *      Find the string if it exists in the item list
864 *	end return it.
865 */
866Char *
867tw_item_find(str)
868    Char    *str;
869{
870    int i;
871
872    if (tw_item.list == NULL || str == NULL)
873	return NULL;
874
875    for (i = 0; i < tw_item.nlist; i++)
876	if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0)
877	    return tw_item.list[i];
878    return NULL;
879} /* end tw_item_find */
880
881
882/* tw_vl_start():
883 *	Initialize a variable list
884 */
885void
886tw_vl_start(dfd, pat)
887    DIR *dfd;
888    Char *pat;
889{
890    SETDIR(dfd)
891    if ((tw_vptr = adrof(pat)) != NULL) {
892	tw_env = tw_vptr->vec;
893	tw_vptr = NULL;
894    }
895    else
896	tw_env = NULL;
897} /* end tw_vl_start */
898
899
900/*
901 * Initialize a word list
902 */
903void
904tw_wl_start(dfd, pat)
905    DIR *dfd;
906    Char *pat;
907{
908    SETDIR(dfd);
909    tw_word = pat;
910} /* end tw_wl_start */
911
912
913/*
914 * Return the next word from the word list
915 */
916/*ARGSUSED*/
917Char *
918tw_wl_next(dir, flags)
919    Char *dir;
920    int *flags;
921{
922    USE(flags);
923    if (tw_word == NULL || tw_word[0] == '\0')
924	return NULL;
925
926    while (*tw_word && Isspace(*tw_word)) tw_word++;
927
928    for (dir = tw_word; *tw_word && !Isspace(*tw_word); tw_word++)
929	continue;
930    if (*tw_word)
931	*tw_word++ = '\0';
932    return *dir ? dir : NULL;
933} /* end tw_wl_next */
934
935
936/* tw_bind_start():
937 *	Begin the list of the shell bindings
938 */
939/*ARGSUSED*/
940void
941tw_bind_start(dfd, pat)
942    DIR *dfd;
943    Char *pat;
944{
945    USE(pat);
946    SETDIR(dfd)
947    tw_bind = FuncNames;
948} /* end tw_bind_start */
949
950
951/* tw_bind_next():
952 *	Begin the list of the shell bindings
953 */
954/*ARGSUSED*/
955Char *
956tw_bind_next(dir, flags)
957    Char *dir;
958    int *flags;
959{
960    char *ptr;
961    USE(flags);
962    if (tw_bind && tw_bind->name) {
963	for (ptr = tw_bind->name, dir = tw_retname;
964	     (*dir++ = (Char) *ptr++) != '\0';)
965	    continue;
966	tw_bind++;
967	return(tw_retname);
968    }
969    return NULL;
970} /* end tw_bind_next */
971
972
973/* tw_limit_start():
974 *	Begin the list of the shell limitings
975 */
976/*ARGSUSED*/
977void
978tw_limit_start(dfd, pat)
979    DIR *dfd;
980    Char *pat;
981{
982    USE(pat);
983    SETDIR(dfd)
984#ifndef HAVENOLIMIT
985    tw_limit = limits;
986#endif /* ! HAVENOLIMIT */
987} /* end tw_limit_start */
988
989
990/* tw_limit_next():
991 *	Begin the list of the shell limitings
992 */
993/*ARGSUSED*/
994Char *
995tw_limit_next(dir, flags)
996    Char *dir;
997    int *flags;
998{
999#ifndef HAVENOLIMIT
1000    char *ptr;
1001    if (tw_limit && tw_limit->limname) {
1002	for (ptr = tw_limit->limname, dir = tw_retname;
1003	     (*dir++ = (Char) *ptr++) != '\0';)
1004	    continue;
1005	tw_limit++;
1006	return(tw_retname);
1007    }
1008#endif /* ! HAVENOLIMIT */
1009    USE(flags);
1010    return NULL;
1011} /* end tw_limit_next */
1012
1013
1014/* tw_sig_start():
1015 *	Begin the list of the shell sigings
1016 */
1017/*ARGSUSED*/
1018void
1019tw_sig_start(dfd, pat)
1020    DIR *dfd;
1021    Char *pat;
1022{
1023    USE(pat);
1024    SETDIR(dfd)
1025    tw_index = 0;
1026} /* end tw_sig_start */
1027
1028
1029/* tw_sig_next():
1030 *	Begin the list of the shell sigings
1031 */
1032/*ARGSUSED*/
1033Char *
1034tw_sig_next(dir, flags)
1035    Char *dir;
1036    int *flags;
1037{
1038    char *ptr;
1039    extern int nsig;
1040    USE(flags);
1041    for (;tw_index < nsig; tw_index++) {
1042
1043	if (mesg[tw_index].iname == NULL)
1044	    continue;
1045
1046	for (ptr = mesg[tw_index].iname, dir = tw_retname;
1047	     (*dir++ = (Char) *ptr++) != '\0';)
1048	    continue;
1049	tw_index++;
1050	return(tw_retname);
1051    }
1052    return NULL;
1053} /* end tw_sig_next */
1054
1055
1056/* tw_job_start():
1057 *	Begin the list of the shell jobings
1058 */
1059/*ARGSUSED*/
1060void
1061tw_job_start(dfd, pat)
1062    DIR *dfd;
1063    Char *pat;
1064{
1065    USE(pat);
1066    SETDIR(dfd)
1067    tw_index = 1;
1068} /* end tw_job_start */
1069
1070
1071/* tw_job_next():
1072 *	Begin the list of the shell jobings
1073 */
1074/*ARGSUSED*/
1075Char *
1076tw_job_next(dir, flags)
1077    Char *dir;
1078    int *flags;
1079{
1080    Char *ptr;
1081    struct process *j;
1082
1083    USE(flags);
1084    for (;tw_index <= pmaxindex; tw_index++) {
1085	for (j = proclist.p_next; j != NULL; j = j->p_next)
1086	    if (j->p_index == tw_index && j->p_procid == j->p_jobid)
1087		break;
1088	if (j == NULL)
1089	    continue;
1090	for (ptr = j->p_command, dir = tw_retname; (*dir++ = *ptr++) != '\0';)
1091	    continue;
1092	*dir = '\0';
1093	tw_index++;
1094	return(tw_retname);
1095    }
1096    return NULL;
1097} /* end tw_job_next */
1098