xref: /freebsd/contrib/tcsh/tw.init.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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 
39 RCSID("$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 
55 typedef 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 
65 static struct varent *tw_vptr = NULL;	/* Current shell variable 	*/
66 static Char **tw_env = NULL;		/* Current environment variable */
67 static Char  *tw_word;			/* Current word pointer		*/
68 static struct KeyFuncs *tw_bind = NULL;	/* List of the bindings		*/
69 #ifndef HAVENOLIMIT
70 static struct limits *tw_limit = NULL;	/* List of the resource limits	*/
71 #endif /* HAVENOLIMIT */
72 static int tw_index = 0;		/* signal and job index		*/
73 static DIR   *tw_dir_fd = NULL;		/* Current directory descriptor	*/
74 static Char   tw_retname[MAXPATHLEN+1];	/* Return buffer		*/
75 static int    tw_cmd_got = 0;		/* What we need to do		*/
76 static stringlist_t tw_cmd  = { NULL, NULL, 0, 0, 0, 0 };
77 static 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 
84 static 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
92 static 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 
115 static Char	*tw_str_add		__P((stringlist_t *, int));
116 static void	 tw_str_free		__P((stringlist_t *));
117 static Char     *tw_dir_next		__P((DIR *));
118 static void	 tw_cmd_add 		__P((Char *name));
119 static void 	 tw_cmd_cmd		__P((void));
120 static void	 tw_cmd_builtin		__P((void));
121 static void	 tw_cmd_alias		__P((void));
122 static void	 tw_cmd_sort		__P((void));
123 static void 	 tw_vptr_start		__P((struct varent *));
124 
125 
126 /* tw_str_add():
127  *	Add an item to the string list
128  */
129 static Char *
130 tw_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  */
172 static void
173 tw_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 
191 static Char *
192 tw_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  */
211 static void
212 tw_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  */
225 void
226 tw_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  */
236 static void
237 tw_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  */
285 static void
286 tw_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  */
304 static void
305 tw_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;
314 x:
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  */
335 static void
336 tw_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*/
365 void
366 tw_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  */
411 Char *
412 tw_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  */
460 static void
461 tw_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;
469 x:
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*/
493 Char *
494 tw_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*/
538 Char *
539 tw_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*/
562 void
563 tw_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*/
578 void
579 tw_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*/
594 void
595 tw_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  */
611 Char *
612 tw_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*/
630 void
631 tw_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*/
647 Char *
648 tw_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  */
685 void
686 tw_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*/
701 void
702 tw_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*/
718 Char *
719 tw_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  */
755 void
756 tw_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*/
770 void
771 tw_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  */
786 Char *
787 tw_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  */
813 void
814 tw_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  */
824 void
825 tw_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  */
834 Char **
835 tw_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  */
844 Char *
845 tw_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  */
856 Char *
857 tw_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  */
875 void
876 tw_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  */
893 void
894 tw_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*/
907 Char *
908 tw_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*/
930 void
931 tw_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*/
945 Char *
946 tw_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*/
967 void
968 tw_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*/
984 Char *
985 tw_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*/
1008 void
1009 tw_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*/
1023 Char *
1024 tw_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*/
1050 void
1051 tw_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*/
1065 Char *
1066 tw_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