tw.init.c revision 59243
1/* $Header: /src/pub/tcsh/tw.init.c,v 3.25 1998/10/25 15:10:50 christos Exp $ */
2/*
3 * tw.init.c: Handle lists of things to complete
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: tw.init.c,v 3.25 1998/10/25 15:10:50 christos Exp $")
40
41#include "tw.h"
42#include "ed.h"
43#include "tc.h"
44#include "sh.proc.h"
45
46#if !defined(NSIG) && defined(SIGMAX)
47# define NSIG (SIGMAX+1)
48#endif /* !NSIG && SIGMAX */
49#if !defined(NSIG) && defined(_NSIG)
50# define NSIG _NSIG
51#endif /* !NSIG && _NSIG */
52
53#define TW_INCR	128
54
55typedef struct {
56    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	    /* the call to executable() may make this a bit slow */
264	    name = str2short(dp->d_name);
265	    if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0)))
266		continue;
267            len = (int) Strlen(name) + 2;
268            if (name[0] == '#' ||	/* emacs temp files	*/
269		name[0] == '.' ||	/* .files		*/
270		name[len - 3] == '~' ||	/* emacs backups	*/
271		name[len - 3] == '%')	/* textedit backups	*/
272                continue;		/* Ignore!		*/
273            tw_cmd_add(name);
274	}
275	(void) closedir(dirp);
276	if (recexec)
277	    xfree((ptr_t) dir);
278    }
279} /* end tw_cmd_cmd */
280
281
282/* tw_cmd_builtin():
283 *	Add builtins to the command list
284 */
285static void
286tw_cmd_builtin()
287{
288    register struct biltins *bptr;
289
290    for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++)
291	if (bptr->bname)
292	    tw_cmd_add(str2short(bptr->bname));
293#ifdef WINNT
294    for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++)
295	if (bptr->bname)
296	    tw_cmd_add(str2short(bptr->bname));
297#endif /* WINNT*/
298} /* end tw_cmd_builtin */
299
300
301/* tw_cmd_alias():
302 *	Add aliases to the command list
303 */
304static void
305tw_cmd_alias()
306{
307    register struct varent *p;
308    register struct varent *c;
309
310    p = &aliases;
311    for (;;) {
312	while (p->v_left)
313	    p = p->v_left;
314x:
315	if (p->v_parent == 0) /* is it the header? */
316	    return;
317	if (p->v_name)
318	    tw_cmd_add(p->v_name);
319	if (p->v_right) {
320	    p = p->v_right;
321	    continue;
322	}
323	do {
324	    c = p;
325	    p = p->v_parent;
326	} while (p->v_right == c);
327	goto x;
328    }
329} /* end tw_cmd_alias */
330
331
332/* tw_cmd_sort():
333 *	Sort the command list removing duplicate elements
334 */
335static void
336tw_cmd_sort()
337{
338    int fwd, i;
339
340    TW_HOLD();
341    /* sort the list. */
342    qsort((ptr_t) tw_cmd.list, (size_t) tw_cmd.nlist, sizeof(Char *),
343	  (int (*) __P((const void *, const void *))) fcompare);
344
345    /* get rid of multiple entries */
346    for (i = 0, fwd = 0; i < tw_cmd.nlist - 1; i++) {
347	if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */
348	    fwd++;		/* increase the forward ref. count */
349	else if (fwd)
350	    tw_cmd.list[i - fwd] = tw_cmd.list[i];
351    }
352    /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */
353    if (fwd)
354	tw_cmd.list[i - fwd] = tw_cmd.list[i];
355    tw_cmd.nlist -= fwd;
356    TW_RELS();
357} /* end tw_cmd_sort */
358
359
360/* tw_cmd_start():
361 *	Get the command list and sort it, if not done yet.
362 *	Reset the current pointer to the beginning of the command list
363 */
364/*ARGSUSED*/
365void
366tw_cmd_start(dfd, pat)
367    DIR *dfd;
368    Char *pat;
369{
370    static Char *defpath[] = { STRNULL, 0 };
371    USE(pat);
372    SETDIR(dfd)
373    if ((tw_cmd_got & TW_FL_CMD) == 0) {
374	tw_cmd_free();
375	tw_cmd_cmd();
376	tw_cmd_got |= TW_FL_CMD;
377    }
378    if ((tw_cmd_got & TW_FL_ALIAS) == 0) {
379	tw_cmd_alias();
380	tw_cmd_got &= ~TW_FL_SORT;
381	tw_cmd_got |= TW_FL_ALIAS;
382    }
383    if ((tw_cmd_got & TW_FL_BUILTIN) == 0) {
384	tw_cmd_builtin();
385	tw_cmd_got &= ~TW_FL_SORT;
386	tw_cmd_got |= TW_FL_BUILTIN;
387    }
388    if ((tw_cmd_got & TW_FL_SORT) == 0) {
389	tw_cmd_sort();
390	tw_cmd_got |= TW_FL_SORT;
391    }
392
393    tw_cmd_state.cur = 0;
394    CLRDIR(tw_cmd_state.dfd)
395    if (tw_cmd_got & TW_FL_REL) {
396	struct varent *vp = adrof(STRpath);
397	if (vp && vp->vec)
398	    tw_cmd_state.pathv = vp->vec;
399	else
400	    tw_cmd_state.pathv = defpath;
401    }
402    else
403	tw_cmd_state.pathv = defpath;
404} /* tw_cmd_start */
405
406
407/* tw_cmd_next():
408 *	Return the next element in the command list or
409 *	Look for commands in the relative path components
410 */
411Char *
412tw_cmd_next(dir, flags)
413    Char *dir;
414    int  *flags;
415{
416    Char *ptr = NULL;
417
418    if (tw_cmd_state.cur < tw_cmd.nlist) {
419	*flags = TW_DIR_OK;
420	return tw_cmd.list[tw_cmd_state.cur++];
421    }
422
423    /*
424     * We need to process relatives in the path.
425     */
426    while (((tw_cmd_state.dfd == NULL) ||
427	    ((ptr = tw_dir_next(tw_cmd_state.dfd)) == NULL)) &&
428	   (*tw_cmd_state.pathv != NULL)) {
429
430        CLRDIR(tw_cmd_state.dfd)
431
432	while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/')
433	    tw_cmd_state.pathv++;
434	if ((ptr = *tw_cmd_state.pathv) != 0) {
435	    /*
436	     * We complete directories only on '.' should that
437	     * be changed?
438	     */
439	    if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) {
440		*dir = '\0';
441		tw_cmd_state.dfd = opendir(".");
442		*flags = TW_DIR_OK | TW_EXEC_CHK;
443	    }
444	    else {
445		copyn(dir, *tw_cmd_state.pathv, FILSIZ);
446		catn(dir, STRslash, FILSIZ);
447		tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv));
448		*flags = TW_EXEC_CHK;
449	    }
450	    tw_cmd_state.pathv++;
451	}
452    }
453    return ptr;
454} /* end tw_cmd_next */
455
456
457/* tw_vptr_start():
458 *	Find the first variable in the variable list
459 */
460static void
461tw_vptr_start(c)
462    struct varent *c;
463{
464    tw_vptr = c;		/* start at beginning of variable list */
465
466    for (;;) {
467	while (tw_vptr->v_left)
468	    tw_vptr = tw_vptr->v_left;
469x:
470	if (tw_vptr->v_parent == 0) {	/* is it the header? */
471	    tw_vptr = NULL;
472	    return;
473	}
474	if (tw_vptr->v_name)
475	    return;		/* found first one */
476	if (tw_vptr->v_right) {
477	    tw_vptr = tw_vptr->v_right;
478	    continue;
479	}
480	do {
481	    c = tw_vptr;
482	    tw_vptr = tw_vptr->v_parent;
483	} while (tw_vptr->v_right == c);
484	goto x;
485    }
486} /* end tw_shvar_start */
487
488
489/* tw_shvar_next():
490 *	Return the next shell variable
491 */
492/*ARGSUSED*/
493Char *
494tw_shvar_next(dir, flags)
495    Char *dir;
496    int	 *flags;
497{
498    register struct varent *p;
499    register struct varent *c;
500    register Char *cp;
501
502    USE(flags);
503    USE(dir);
504    if ((p = tw_vptr) == NULL)
505	return (NULL);		/* just in case */
506
507    cp = p->v_name;		/* we know that this name is here now */
508
509    /* now find the next one */
510    for (;;) {
511	if (p->v_right) {	/* if we can go right */
512	    p = p->v_right;
513	    while (p->v_left)
514		p = p->v_left;
515	}
516	else {			/* else go up */
517	    do {
518		c = p;
519		p = p->v_parent;
520	    } while (p->v_right == c);
521	}
522	if (p->v_parent == 0) {	/* is it the header? */
523	    tw_vptr = NULL;
524	    return (cp);
525	}
526	if (p->v_name) {
527	    tw_vptr = p;	/* save state for the next call */
528	    return (cp);
529	}
530    }
531} /* end tw_shvar_next */
532
533
534/* tw_envvar_next():
535 *	Return the next environment variable
536 */
537/*ARGSUSED*/
538Char *
539tw_envvar_next(dir, flags)
540    Char *dir;
541    int *flags;
542{
543    Char   *ps, *pd;
544
545    USE(flags);
546    USE(dir);
547    if (tw_env == NULL || *tw_env == NULL)
548	return (NULL);
549    for (ps = *tw_env, pd = tw_retname;
550	 *ps && *ps != '=' && pd <= &tw_retname[MAXPATHLEN]; *pd++ = *ps++)
551	continue;
552    *pd = '\0';
553    tw_env++;
554    return (tw_retname);
555} /* end tw_envvar_next */
556
557
558/* tw_var_start():
559 *	Begin the list of the shell and environment variables
560 */
561/*ARGSUSED*/
562void
563tw_var_start(dfd, pat)
564    DIR *dfd;
565    Char *pat;
566{
567    USE(pat);
568    SETDIR(dfd)
569    tw_vptr_start(&shvhed);
570    tw_env = STR_environ;
571} /* end tw_var_start */
572
573
574/* tw_alias_start():
575 *	Begin the list of the shell aliases
576 */
577/*ARGSUSED*/
578void
579tw_alias_start(dfd, pat)
580    DIR *dfd;
581    Char *pat;
582{
583    USE(pat);
584    SETDIR(dfd)
585    tw_vptr_start(&aliases);
586    tw_env = NULL;
587} /* tw_alias_start */
588
589
590/* tw_complete_start():
591 *	Begin the list of completions
592 */
593/*ARGSUSED*/
594void
595tw_complete_start(dfd, pat)
596    DIR *dfd;
597    Char *pat;
598{
599    extern struct varent completions;
600
601    USE(pat);
602    SETDIR(dfd)
603    tw_vptr_start(&completions);
604    tw_env = NULL;
605} /* end tw_complete_start */
606
607
608/* tw_var_next():
609 *	Return the next shell or environment variable
610 */
611Char *
612tw_var_next(dir, flags)
613    Char *dir;
614    int  *flags;
615{
616    Char *ptr = NULL;
617
618    if (tw_vptr)
619	ptr = tw_shvar_next(dir, flags);
620    if (!ptr && tw_env)
621	ptr = tw_envvar_next(dir, flags);
622    return ptr;
623} /* end tw_var_next */
624
625
626/* tw_logname_start():
627 *	Initialize lognames to the beginning of the list
628 */
629/*ARGSUSED*/
630void
631tw_logname_start(dfd, pat)
632    DIR *dfd;
633    Char *pat;
634{
635    USE(pat);
636    SETDIR(dfd)
637#if !defined(_VMS_POSIX) && !defined(WINNT)
638    (void) setpwent();	/* Open passwd file */
639#endif /* !_VMS_POSIX && !WINNT */
640} /* end tw_logname_start */
641
642
643/* tw_logname_next():
644 *	Return the next entry from the passwd file
645 */
646/*ARGSUSED*/
647Char *
648tw_logname_next(dir, flags)
649    Char *dir;
650    int  *flags;
651{
652    static Char retname[MAXPATHLEN];
653    struct passwd *pw;
654    /*
655     * We don't want to get interrupted inside getpwent()
656     * because the yellow pages code is not interruptible,
657     * and if we call endpwent() immediatetely after
658     * (in pintr()) we may be freeing an invalid pointer
659     */
660    USE(flags);
661    USE(dir);
662    TW_HOLD();
663#if !defined(_VMS_POSIX) && !defined(WINNT)
664    /* ISC does not declare getpwent()? */
665    pw = (struct passwd *) getpwent();
666#else /* _VMS_POSIX || WINNT */
667    pw = NULL;
668#endif /* !_VMS_POSIX && !WINNT */
669    TW_RELS();
670
671    if (pw == NULL) {
672#ifdef YPBUGS
673	fix_yp_bugs();
674#endif
675	return (NULL);
676    }
677    (void) Strcpy(retname, str2short(pw->pw_name));
678    return (retname);
679} /* end tw_logname_next */
680
681
682/* tw_logname_end():
683 *	Close the passwd file to finish the logname list
684 */
685void
686tw_logname_end()
687{
688#ifdef YPBUGS
689    fix_yp_bugs();
690#endif
691#if !defined(_VMS_POSIX) && !defined(WINNT)
692   (void) endpwent();
693#endif /* !_VMS_POSIX && !WINNT */
694} /* end tw_logname_end */
695
696
697/* tw_grpname_start():
698 *	Initialize grpnames to the beginning of the list
699 */
700/*ARGSUSED*/
701void
702tw_grpname_start(dfd, pat)
703    DIR *dfd;
704    Char *pat;
705{
706    USE(pat);
707    SETDIR(dfd)
708#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT)
709    (void) setgrent();	/* Open group file */
710#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT */
711} /* end tw_grpname_start */
712
713
714/* tw_grpname_next():
715 *	Return the next entry from the group file
716 */
717/*ARGSUSED*/
718Char *
719tw_grpname_next(dir, flags)
720    Char *dir;
721    int  *flags;
722{
723    static Char retname[MAXPATHLEN];
724    struct group *gr;
725    /*
726     * We don't want to get interrupted inside getgrent()
727     * because the yellow pages code is not interruptible,
728     * and if we call endgrent() immediatetely after
729     * (in pintr()) we may be freeing an invalid pointer
730     */
731    USE(flags);
732    USE(dir);
733    TW_HOLD();
734#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT)
735    gr = (struct group *) getgrent();
736#else /* _VMS_POSIX || _OSD_POSIX || WINNT */
737    gr = NULL;
738#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT */
739    TW_RELS();
740
741    if (gr == NULL) {
742#ifdef YPBUGS
743	fix_yp_bugs();
744#endif
745	return (NULL);
746    }
747    (void) Strcpy(retname, str2short(gr->gr_name));
748    return (retname);
749} /* end tw_grpname_next */
750
751
752/* tw_grpname_end():
753 *	Close the group file to finish the groupname list
754 */
755void
756tw_grpname_end()
757{
758#ifdef YPBUGS
759    fix_yp_bugs();
760#endif
761#if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT)
762   (void) endgrent();
763#endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT */
764} /* end tw_grpname_end */
765
766/* tw_file_start():
767 *	Initialize the directory for the file list
768 */
769/*ARGSUSED*/
770void
771tw_file_start(dfd, pat)
772    DIR *dfd;
773    Char *pat;
774{
775    struct varent *vp;
776    USE(pat);
777    SETDIR(dfd)
778    if ((vp = adrof(STRcdpath)) != NULL)
779	tw_env = vp->vec;
780} /* end tw_file_start */
781
782
783/* tw_file_next():
784 *	Return the next file in the directory
785 */
786Char *
787tw_file_next(dir, flags)
788    Char *dir;
789    int  *flags;
790{
791    Char *ptr = tw_dir_next(tw_dir_fd);
792    if (ptr == NULL && (*flags & TW_DIR_OK) != 0) {
793	CLRDIR(tw_dir_fd)
794	while (tw_env && *tw_env)
795	    if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL)
796		break;
797	    else
798		tw_env++;
799
800	if (tw_dir_fd) {
801	    copyn(dir, *tw_env++, MAXPATHLEN);
802	    catn(dir, STRslash, MAXPATHLEN);
803	    ptr = tw_dir_next(tw_dir_fd);
804	}
805    }
806    return ptr;
807} /* end tw_file_next */
808
809
810/* tw_dir_end():
811 *	Clear directory related lists
812 */
813void
814tw_dir_end()
815{
816   CLRDIR(tw_dir_fd)
817   CLRDIR(tw_cmd_state.dfd)
818} /* end tw_dir_end */
819
820
821/* tw_item_free():
822 *	Free the item list
823 */
824void
825tw_item_free()
826{
827    tw_str_free(&tw_item);
828} /* end tw_item_free */
829
830
831/* tw_item_get():
832 *	Return the list of items
833 */
834Char **
835tw_item_get()
836{
837    return tw_item.list;
838} /* end tw_item_get */
839
840
841/* tw_item_add():
842 *	Return a new item
843 */
844Char *
845tw_item_add(len)
846    int len;
847{
848     return tw_str_add(&tw_item, len);
849} /* tw_item_add */
850
851
852/* tw_item_find():
853 *      Find the string if it exists in the item list
854 *	end return it.
855 */
856Char *
857tw_item_find(str)
858    Char    *str;
859{
860    int i;
861
862    if (tw_item.list == NULL || str == NULL)
863	return NULL;
864
865    for (i = 0; i < tw_item.nlist; i++)
866	if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0)
867	    return tw_item.list[i];
868    return NULL;
869} /* end tw_item_find */
870
871
872/* tw_vl_start():
873 *	Initialize a variable list
874 */
875void
876tw_vl_start(dfd, pat)
877    DIR *dfd;
878    Char *pat;
879{
880    SETDIR(dfd)
881    if ((tw_vptr = adrof(pat)) != NULL) {
882	tw_env = tw_vptr->vec;
883	tw_vptr = NULL;
884    }
885    else
886	tw_env = NULL;
887} /* end tw_vl_start */
888
889
890/*
891 * Initialize a word list
892 */
893void
894tw_wl_start(dfd, pat)
895    DIR *dfd;
896    Char *pat;
897{
898    SETDIR(dfd);
899    tw_word = pat;
900} /* end tw_wl_start */
901
902
903/*
904 * Return the next word from the word list
905 */
906/*ARGSUSED*/
907Char *
908tw_wl_next(dir, flags)
909    Char *dir;
910    int *flags;
911{
912    USE(flags);
913    if (tw_word == NULL || tw_word[0] == '\0')
914	return NULL;
915
916    while (*tw_word && Isspace(*tw_word)) tw_word++;
917
918    for (dir = tw_word; *tw_word && !Isspace(*tw_word); tw_word++)
919	continue;
920    if (*tw_word)
921	*tw_word++ = '\0';
922    return *dir ? dir : NULL;
923} /* end tw_wl_next */
924
925
926/* tw_bind_start():
927 *	Begin the list of the shell bindings
928 */
929/*ARGSUSED*/
930void
931tw_bind_start(dfd, pat)
932    DIR *dfd;
933    Char *pat;
934{
935    USE(pat);
936    SETDIR(dfd)
937    tw_bind = FuncNames;
938} /* end tw_bind_start */
939
940
941/* tw_bind_next():
942 *	Begin the list of the shell bindings
943 */
944/*ARGSUSED*/
945Char *
946tw_bind_next(dir, flags)
947    Char *dir;
948    int *flags;
949{
950    char *ptr;
951    USE(flags);
952    if (tw_bind && tw_bind->name) {
953	for (ptr = tw_bind->name, dir = tw_retname;
954	     (*dir++ = (Char) *ptr++) != '\0';)
955	    continue;
956	tw_bind++;
957	return(tw_retname);
958    }
959    return NULL;
960} /* end tw_bind_next */
961
962
963/* tw_limit_start():
964 *	Begin the list of the shell limitings
965 */
966/*ARGSUSED*/
967void
968tw_limit_start(dfd, pat)
969    DIR *dfd;
970    Char *pat;
971{
972    USE(pat);
973    SETDIR(dfd)
974#ifndef HAVENOLIMIT
975    tw_limit = limits;
976#endif /* ! HAVENOLIMIT */
977} /* end tw_limit_start */
978
979
980/* tw_limit_next():
981 *	Begin the list of the shell limitings
982 */
983/*ARGSUSED*/
984Char *
985tw_limit_next(dir, flags)
986    Char *dir;
987    int *flags;
988{
989#ifndef HAVENOLIMIT
990    char *ptr;
991    if (tw_limit && tw_limit->limname) {
992	for (ptr = tw_limit->limname, dir = tw_retname;
993	     (*dir++ = (Char) *ptr++) != '\0';)
994	    continue;
995	tw_limit++;
996	return(tw_retname);
997    }
998#endif /* ! HAVENOLIMIT */
999    USE(flags);
1000    return NULL;
1001} /* end tw_limit_next */
1002
1003
1004/* tw_sig_start():
1005 *	Begin the list of the shell sigings
1006 */
1007/*ARGSUSED*/
1008void
1009tw_sig_start(dfd, pat)
1010    DIR *dfd;
1011    Char *pat;
1012{
1013    USE(pat);
1014    SETDIR(dfd)
1015    tw_index = 0;
1016} /* end tw_sig_start */
1017
1018
1019/* tw_sig_next():
1020 *	Begin the list of the shell sigings
1021 */
1022/*ARGSUSED*/
1023Char *
1024tw_sig_next(dir, flags)
1025    Char *dir;
1026    int *flags;
1027{
1028    char *ptr;
1029    extern int nsig;
1030    USE(flags);
1031    for (;tw_index < nsig; tw_index++) {
1032
1033	if (mesg[tw_index].iname == NULL)
1034	    continue;
1035
1036	for (ptr = mesg[tw_index].iname, dir = tw_retname;
1037	     (*dir++ = (Char) *ptr++) != '\0';)
1038	    continue;
1039	tw_index++;
1040	return(tw_retname);
1041    }
1042    return NULL;
1043} /* end tw_sig_next */
1044
1045
1046/* tw_job_start():
1047 *	Begin the list of the shell jobings
1048 */
1049/*ARGSUSED*/
1050void
1051tw_job_start(dfd, pat)
1052    DIR *dfd;
1053    Char *pat;
1054{
1055    USE(pat);
1056    SETDIR(dfd)
1057    tw_index = 1;
1058} /* end tw_job_start */
1059
1060
1061/* tw_job_next():
1062 *	Begin the list of the shell jobings
1063 */
1064/*ARGSUSED*/
1065Char *
1066tw_job_next(dir, flags)
1067    Char *dir;
1068    int *flags;
1069{
1070    Char *ptr;
1071    struct process *j;
1072
1073    USE(flags);
1074    for (;tw_index <= pmaxindex; tw_index++) {
1075	for (j = proclist.p_next; j != NULL; j = j->p_next)
1076	    if (j->p_index == tw_index && j->p_procid == j->p_jobid)
1077		break;
1078	if (j == NULL)
1079	    continue;
1080	for (ptr = j->p_command, dir = tw_retname; (*dir++ = *ptr++) != '\0';)
1081	    continue;
1082	*dir = '\0';
1083	tw_index++;
1084	return(tw_retname);
1085    }
1086    return NULL;
1087} /* end tw_job_next */
1088