kernel - Deal with lost IPIs (VM related)
[dragonfly.git] / contrib / tcsh-6 / tw.init.c
blob68adbb941761012b043674b667c0b076b0937afd
1 /* $Header: /p/tcsh/cvsroot/tcsh/tw.init.c,v 3.42 2011/04/17 14:49:30 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.
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. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$tcsh: tw.init.c,v 3.42 2011/04/17 14:49:30 christos Exp $")
37 #include "tw.h"
38 #include "ed.h"
39 #include "tc.h"
40 #include "sh.proc.h"
42 #define TW_INCR 128
44 typedef struct {
45 Char **list, /* List of command names */
46 *buff; /* Space holding command names */
47 size_t nlist, /* Number of items */
48 nbuff, /* Current space in name buf */
49 tlist, /* Total space in list */
50 tbuff; /* Total space in name buf */
51 } stringlist_t;
54 static struct varent *tw_vptr = NULL; /* Current shell variable */
55 static Char **tw_env = NULL; /* Current environment variable */
56 static const Char *tw_word; /* Current word pointer */
57 static struct KeyFuncs *tw_bind = NULL; /* List of the bindings */
58 #ifndef HAVENOLIMIT
59 static struct limits *tw_limit = NULL; /* List of the resource limits */
60 #endif /* HAVENOLIMIT */
61 static int tw_index = 0; /* signal and job index */
62 static DIR *tw_dir_fd = NULL; /* Current directory descriptor */
63 static int tw_cmd_got = 0; /* What we need to do */
64 static stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 };
65 static stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 };
66 #define TW_FL_CMD 0x01
67 #define TW_FL_ALIAS 0x02
68 #define TW_FL_BUILTIN 0x04
69 #define TW_FL_SORT 0x08
70 #define TW_FL_REL 0x10
72 static struct { /* Current element pointer */
73 size_t cur; /* Current element number */
74 Char **pathv; /* Current element in path */
75 DIR *dfd; /* Current directory descriptor */
76 } tw_cmd_state;
79 #define SETDIR(dfd) \
80 { \
81 tw_dir_fd = dfd; \
82 if (tw_dir_fd != NULL) \
83 rewinddir(tw_dir_fd); \
86 #define CLRDIR(dfd) \
87 if (dfd != NULL) { \
88 pintr_disabled++; \
89 xclosedir(dfd); \
90 dfd = NULL; \
91 disabled_cleanup(&pintr_disabled); \
94 static Char *tw_str_add (stringlist_t *, size_t);
95 static void tw_str_free (stringlist_t *);
96 static int tw_dir_next (struct Strbuf *, DIR *);
97 static void tw_cmd_add (const Char *name);
98 static void tw_cmd_cmd (void);
99 static void tw_cmd_builtin (void);
100 static void tw_cmd_alias (void);
101 static void tw_cmd_sort (void);
102 static void tw_vptr_start (struct varent *);
105 /* tw_str_add():
106 * Add an item to the string list
108 static Char *
109 tw_str_add(stringlist_t *sl, size_t len)
111 Char *ptr;
113 if (sl->tlist <= sl->nlist) {
114 pintr_disabled++;
115 sl->tlist += TW_INCR;
116 sl->list = xrealloc(sl->list, sl->tlist * sizeof(Char *));
117 disabled_cleanup(&pintr_disabled);
119 if (sl->tbuff <= sl->nbuff + len) {
120 size_t i;
122 ptr = sl->buff;
123 pintr_disabled++;
124 sl->tbuff += TW_INCR + len;
125 sl->buff = xrealloc(sl->buff, sl->tbuff * sizeof(Char));
126 /* Re-thread the new pointer list, if changed */
127 if (ptr != NULL && ptr != sl->buff) {
128 intptr_t offs = sl->buff - ptr;
129 for (i = 0; i < sl->nlist; i++)
130 sl->list[i] += offs;
132 disabled_cleanup(&pintr_disabled);
134 ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff];
135 sl->nbuff += len;
136 return ptr;
137 } /* tw_str_add */
140 /* tw_str_free():
141 * Free a stringlist
143 static void
144 tw_str_free(stringlist_t *sl)
146 pintr_disabled++;
147 if (sl->list) {
148 xfree(sl->list);
149 sl->list = NULL;
150 sl->tlist = sl->nlist = 0;
152 if (sl->buff) {
153 xfree(sl->buff);
154 sl->buff = NULL;
155 sl->tbuff = sl->nbuff = 0;
157 disabled_cleanup(&pintr_disabled);
158 } /* end tw_str_free */
161 static int
162 tw_dir_next(struct Strbuf *res, DIR *dfd)
164 struct dirent *dirp;
166 if (dfd == NULL)
167 return 0;
169 if ((dirp = readdir(dfd)) != NULL) {
170 Strbuf_append(res, str2short(dirp->d_name));
171 return 1;
173 return 0;
174 } /* end tw_dir_next */
177 /* tw_cmd_add():
178 * Add the name to the command list
180 static void
181 tw_cmd_add(const Char *name)
183 size_t len;
185 len = Strlen(name) + 2;
186 (void) Strcpy(tw_str_add(&tw_cmd, len), name);
187 } /* end tw_cmd_add */
190 /* tw_cmd_free():
191 * Free the command list
193 void
194 tw_cmd_free(void)
196 CLRDIR(tw_dir_fd)
197 tw_str_free(&tw_cmd);
198 tw_cmd_got = 0;
199 } /* end tw_cmd_free */
201 /* tw_cmd_cmd():
202 * Add system commands to the command list
204 static void
205 tw_cmd_cmd(void)
207 DIR *dirp;
208 struct dirent *dp;
209 Char *dir = NULL, *name;
210 Char **pv;
211 struct varent *v = adrof(STRpath);
212 struct varent *recexec = adrof(STRrecognize_only_executables);
213 size_t len;
216 if (v == NULL || v->vec == NULL) /* if no path */
217 return;
219 for (pv = v->vec; *pv; pv++) {
220 if (pv[0][0] != '/') {
221 tw_cmd_got |= TW_FL_REL;
222 continue;
225 if ((dirp = opendir(short2str(*pv))) == NULL)
226 continue;
228 cleanup_push(dirp, opendir_cleanup);
229 if (recexec) {
230 dir = Strspl(*pv, STRslash);
231 cleanup_push(dir, xfree);
233 while ((dp = readdir(dirp)) != NULL) {
234 #if defined(_UWIN) || defined(__CYGWIN__)
235 /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
236 * the file with the .exe, .com, .bat extension
238 * Same for Cygwin, but only for .exe and .com extension.
240 len = strlen(dp->d_name);
241 if (len > 4 && (strcmp(&dp->d_name[len - 4], ".exe") == 0 ||
242 #ifndef __CYGWIN__
243 strcmp(&dp->d_name[len - 4], ".bat") == 0 ||
244 #endif /* !__CYGWIN__ */
245 strcmp(&dp->d_name[len - 4], ".com") == 0))
246 dp->d_name[len - 4] = '\0';
247 #endif /* _UWIN || __CYGWIN__ */
248 /* the call to executable() may make this a bit slow */
249 name = str2short(dp->d_name);
250 if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0)))
251 continue;
252 len = Strlen(name);
253 if (name[0] == '#' || /* emacs temp files */
254 name[0] == '.' || /* .files */
255 name[len - 1] == '~' || /* emacs backups */
256 name[len - 1] == '%') /* textedit backups */
257 continue; /* Ignore! */
258 tw_cmd_add(name);
260 cleanup_until(dirp);
262 } /* end tw_cmd_cmd */
265 /* tw_cmd_builtin():
266 * Add builtins to the command list
268 static void
269 tw_cmd_builtin(void)
271 const struct biltins *bptr;
273 for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++)
274 if (bptr->bname)
275 tw_cmd_add(str2short(bptr->bname));
276 #ifdef WINNT_NATIVE
277 for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++)
278 if (bptr->bname)
279 tw_cmd_add(str2short(bptr->bname));
280 #endif /* WINNT_NATIVE*/
281 } /* end tw_cmd_builtin */
284 /* tw_cmd_alias():
285 * Add aliases to the command list
287 static void
288 tw_cmd_alias(void)
290 struct varent *p;
291 struct varent *c;
293 p = &aliases;
294 for (;;) {
295 while (p->v_left)
296 p = p->v_left;
298 if (p->v_parent == 0) /* is it the header? */
299 return;
300 if (p->v_name)
301 tw_cmd_add(p->v_name);
302 if (p->v_right) {
303 p = p->v_right;
304 continue;
306 do {
307 c = p;
308 p = p->v_parent;
309 } while (p->v_right == c);
310 goto x;
312 } /* end tw_cmd_alias */
315 /* tw_cmd_sort():
316 * Sort the command list removing duplicate elements
318 static void
319 tw_cmd_sort(void)
321 size_t fwd, i;
323 pintr_disabled++;
324 /* sort the list. */
325 qsort(tw_cmd.list, tw_cmd.nlist, sizeof(Char *), fcompare);
327 /* get rid of multiple entries */
328 for (i = 0, fwd = 0; i + 1 < tw_cmd.nlist; i++) {
329 if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */
330 fwd++; /* increase the forward ref. count */
331 else if (fwd)
332 tw_cmd.list[i - fwd] = tw_cmd.list[i];
334 /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */
335 if (fwd)
336 tw_cmd.list[i - fwd] = tw_cmd.list[i];
337 tw_cmd.nlist -= fwd;
338 disabled_cleanup(&pintr_disabled);
339 } /* end tw_cmd_sort */
342 /* tw_cmd_start():
343 * Get the command list and sort it, if not done yet.
344 * Reset the current pointer to the beginning of the command list
346 /*ARGSUSED*/
347 void
348 tw_cmd_start(DIR *dfd, const Char *pat)
350 static Char *defpath[] = { STRNULL, 0 };
351 USE(pat);
352 SETDIR(dfd)
353 if ((tw_cmd_got & TW_FL_CMD) == 0) {
354 tw_cmd_free();
355 tw_cmd_cmd();
356 tw_cmd_got |= TW_FL_CMD;
358 if ((tw_cmd_got & TW_FL_ALIAS) == 0) {
359 tw_cmd_alias();
360 tw_cmd_got &= ~TW_FL_SORT;
361 tw_cmd_got |= TW_FL_ALIAS;
363 if ((tw_cmd_got & TW_FL_BUILTIN) == 0) {
364 tw_cmd_builtin();
365 tw_cmd_got &= ~TW_FL_SORT;
366 tw_cmd_got |= TW_FL_BUILTIN;
368 if ((tw_cmd_got & TW_FL_SORT) == 0) {
369 tw_cmd_sort();
370 tw_cmd_got |= TW_FL_SORT;
373 tw_cmd_state.cur = 0;
374 CLRDIR(tw_cmd_state.dfd)
375 if (tw_cmd_got & TW_FL_REL) {
376 struct varent *vp = adrof(STRpath);
377 if (vp && vp->vec)
378 tw_cmd_state.pathv = vp->vec;
379 else
380 tw_cmd_state.pathv = defpath;
382 else
383 tw_cmd_state.pathv = defpath;
384 } /* tw_cmd_start */
387 /* tw_cmd_next():
388 * Return the next element in the command list or
389 * Look for commands in the relative path components
392 tw_cmd_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
394 int ret = 0;
395 Char *ptr;
397 if (tw_cmd_state.cur < tw_cmd.nlist) {
398 *flags = TW_DIR_OK;
399 Strbuf_append(res, tw_cmd.list[tw_cmd_state.cur++]);
400 return 1;
404 * We need to process relatives in the path.
406 while ((tw_cmd_state.dfd == NULL ||
407 (res->len = 0, ret = tw_dir_next(res, tw_cmd_state.dfd)) == 0) &&
408 *tw_cmd_state.pathv != NULL) {
410 CLRDIR(tw_cmd_state.dfd)
412 while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/')
413 tw_cmd_state.pathv++;
414 if ((ptr = *tw_cmd_state.pathv) != 0) {
415 res->len = 0;
416 Strbuf_append(res, ptr);
417 ret = 1;
419 * We complete directories only on '.' should that
420 * be changed?
422 dir->len = 0;
423 if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) {
424 tw_cmd_state.dfd = opendir(".");
425 *flags = TW_DIR_OK | TW_EXEC_CHK;
427 else {
428 Strbuf_append(dir, *tw_cmd_state.pathv);
429 Strbuf_append1(dir, '/');
430 tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv));
431 *flags = TW_EXEC_CHK;
433 Strbuf_terminate(dir);
434 tw_cmd_state.pathv++;
437 return ret;
438 } /* end tw_cmd_next */
441 /* tw_vptr_start():
442 * Find the first variable in the variable list
444 static void
445 tw_vptr_start(struct varent *c)
447 tw_vptr = c; /* start at beginning of variable list */
449 for (;;) {
450 while (tw_vptr->v_left)
451 tw_vptr = tw_vptr->v_left;
453 if (tw_vptr->v_parent == 0) { /* is it the header? */
454 tw_vptr = NULL;
455 return;
457 if (tw_vptr->v_name)
458 return; /* found first one */
459 if (tw_vptr->v_right) {
460 tw_vptr = tw_vptr->v_right;
461 continue;
463 do {
464 c = tw_vptr;
465 tw_vptr = tw_vptr->v_parent;
466 } while (tw_vptr->v_right == c);
467 goto x;
469 } /* end tw_shvar_start */
472 /* tw_shvar_next():
473 * Return the next shell variable
475 /*ARGSUSED*/
477 tw_shvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
479 struct varent *p;
480 struct varent *c;
482 USE(flags);
483 USE(dir);
484 if ((p = tw_vptr) == NULL)
485 return 0; /* just in case */
487 Strbuf_append(res, p->v_name); /* we know that this name is here now */
489 /* now find the next one */
490 for (;;) {
491 if (p->v_right) { /* if we can go right */
492 p = p->v_right;
493 while (p->v_left)
494 p = p->v_left;
496 else { /* else go up */
497 do {
498 c = p;
499 p = p->v_parent;
500 } while (p->v_right == c);
502 if (p->v_parent == 0) { /* is it the header? */
503 tw_vptr = NULL;
504 return 1;
506 if (p->v_name) {
507 tw_vptr = p; /* save state for the next call */
508 return 1;
511 } /* end tw_shvar_next */
514 /* tw_envvar_next():
515 * Return the next environment variable
517 /*ARGSUSED*/
519 tw_envvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
521 const Char *ps;
523 USE(flags);
524 USE(dir);
525 if (tw_env == NULL || *tw_env == NULL)
526 return 0;
527 for (ps = *tw_env; *ps && *ps != '='; ps++)
528 continue;
529 Strbuf_appendn(res, *tw_env, ps - *tw_env);
530 tw_env++;
531 return 1;
532 } /* end tw_envvar_next */
535 /* tw_var_start():
536 * Begin the list of the shell and environment variables
538 /*ARGSUSED*/
539 void
540 tw_var_start(DIR *dfd, const Char *pat)
542 USE(pat);
543 SETDIR(dfd)
544 tw_vptr_start(&shvhed);
545 tw_env = STR_environ;
546 } /* end tw_var_start */
549 /* tw_alias_start():
550 * Begin the list of the shell aliases
552 /*ARGSUSED*/
553 void
554 tw_alias_start(DIR *dfd, const Char *pat)
556 USE(pat);
557 SETDIR(dfd)
558 tw_vptr_start(&aliases);
559 tw_env = NULL;
560 } /* tw_alias_start */
563 /* tw_complete_start():
564 * Begin the list of completions
566 /*ARGSUSED*/
567 void
568 tw_complete_start(DIR *dfd, const Char *pat)
570 USE(pat);
571 SETDIR(dfd)
572 tw_vptr_start(&completions);
573 tw_env = NULL;
574 } /* end tw_complete_start */
577 /* tw_var_next():
578 * Return the next shell or environment variable
581 tw_var_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
583 int ret = 0;
585 if (tw_vptr)
586 ret = tw_shvar_next(res, dir, flags);
587 if (ret == 0 && tw_env)
588 ret = tw_envvar_next(res, dir, flags);
589 return ret;
590 } /* end tw_var_next */
593 /* tw_logname_start():
594 * Initialize lognames to the beginning of the list
596 /*ARGSUSED*/
597 void
598 tw_logname_start(DIR *dfd, const Char *pat)
600 USE(pat);
601 SETDIR(dfd)
602 #ifdef HAVE_GETPWENT
603 (void) setpwent(); /* Open passwd file */
604 #endif
605 } /* end tw_logname_start */
608 /* tw_logname_next():
609 * Return the next entry from the passwd file
611 /*ARGSUSED*/
613 tw_logname_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
615 struct passwd *pw;
618 * We don't want to get interrupted inside getpwent()
619 * because the yellow pages code is not interruptible,
620 * and if we call endpwent() immediatetely after
621 * (in pintr()) we may be freeing an invalid pointer
623 USE(flags);
624 USE(dir);
625 pintr_disabled++;
626 #ifdef HAVE_GETPWENT
627 pw = getpwent();
628 #else
629 pw = NULL;
630 #endif
631 disabled_cleanup(&pintr_disabled);
633 if (pw == NULL) {
634 #ifdef YPBUGS
635 fix_yp_bugs();
636 #endif
637 return 0;
639 Strbuf_append(res, str2short(pw->pw_name));
640 return 1;
641 } /* end tw_logname_next */
644 /* tw_logname_end():
645 * Close the passwd file to finish the logname list
647 void
648 tw_logname_end(void)
650 #ifdef YPBUGS
651 fix_yp_bugs();
652 #endif
653 #ifdef HAVE_GETPWENT
654 (void) endpwent();
655 #endif
656 } /* end tw_logname_end */
659 /* tw_grpname_start():
660 * Initialize grpnames to the beginning of the list
662 /*ARGSUSED*/
663 void
664 tw_grpname_start(DIR *dfd, const Char *pat)
666 USE(pat);
667 SETDIR(dfd)
668 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__)
669 (void) setgrent(); /* Open group file */
670 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
671 } /* end tw_grpname_start */
674 /* tw_grpname_next():
675 * Return the next entry from the group file
677 /*ARGSUSED*/
679 tw_grpname_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
681 struct group *gr;
684 * We don't want to get interrupted inside getgrent()
685 * because the yellow pages code is not interruptible,
686 * and if we call endgrent() immediatetely after
687 * (in pintr()) we may be freeing an invalid pointer
689 USE(flags);
690 USE(dir);
691 pintr_disabled++;
692 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined(__ANDROID__)
693 errno = 0;
694 while ((gr = getgrent()) == NULL && errno == EINTR) {
695 handle_pending_signals();
696 errno = 0;
698 #else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */
699 gr = NULL;
700 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
701 disabled_cleanup(&pintr_disabled);
703 if (gr == NULL) {
704 #ifdef YPBUGS
705 fix_yp_bugs();
706 #endif
707 return 0;
709 Strbuf_append(res, str2short(gr->gr_name));
710 return 1;
711 } /* end tw_grpname_next */
714 /* tw_grpname_end():
715 * Close the group file to finish the groupname list
717 void
718 tw_grpname_end(void)
720 #ifdef YPBUGS
721 fix_yp_bugs();
722 #endif
723 #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__)
724 (void) endgrent();
725 #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
726 } /* end tw_grpname_end */
728 /* tw_file_start():
729 * Initialize the directory for the file list
731 /*ARGSUSED*/
732 void
733 tw_file_start(DIR *dfd, const Char *pat)
735 struct varent *vp;
736 USE(pat);
737 SETDIR(dfd)
738 if ((vp = adrof(STRcdpath)) != NULL)
739 tw_env = vp->vec;
740 } /* end tw_file_start */
743 /* tw_file_next():
744 * Return the next file in the directory
747 tw_file_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
749 int ret = tw_dir_next(res, tw_dir_fd);
750 if (ret == 0 && (*flags & TW_DIR_OK) != 0) {
751 CLRDIR(tw_dir_fd)
752 while (tw_env && *tw_env)
753 if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL)
754 break;
755 else
756 tw_env++;
758 if (tw_dir_fd) {
759 dir->len = 0;
760 Strbuf_append(dir, *tw_env++);
761 Strbuf_append1(dir, '/');
762 Strbuf_terminate(dir);
763 ret = tw_dir_next(res, tw_dir_fd);
766 return ret;
767 } /* end tw_file_next */
770 /* tw_dir_end():
771 * Clear directory related lists
773 void
774 tw_dir_end(void)
776 CLRDIR(tw_dir_fd)
777 CLRDIR(tw_cmd_state.dfd)
778 } /* end tw_dir_end */
781 /* tw_item_free():
782 * Free the item list
784 void
785 tw_item_free(void)
787 tw_str_free(&tw_item);
788 } /* end tw_item_free */
791 /* tw_item_get():
792 * Return the list of items
794 Char **
795 tw_item_get(void)
797 return tw_item.list;
798 } /* end tw_item_get */
801 /* tw_item_add():
802 * Return a new item for a Strbuf_terminate()'d s
804 void
805 tw_item_add(const struct Strbuf *s)
807 Char *p;
809 p = tw_str_add(&tw_item, s->len + 1);
810 Strcpy(p, s->s);
811 } /* tw_item_add */
814 /* tw_item_find():
815 * Find the string if it exists in the item list
816 * end return it.
818 Char *
819 tw_item_find(Char *str)
821 size_t i;
823 if (tw_item.list == NULL || str == NULL)
824 return NULL;
826 for (i = 0; i < tw_item.nlist; i++)
827 if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0)
828 return tw_item.list[i];
829 return NULL;
830 } /* end tw_item_find */
833 /* tw_vl_start():
834 * Initialize a variable list
836 void
837 tw_vl_start(DIR *dfd, const Char *pat)
839 SETDIR(dfd)
840 if ((tw_vptr = adrof(pat)) != NULL) {
841 tw_env = tw_vptr->vec;
842 tw_vptr = NULL;
844 else
845 tw_env = NULL;
846 } /* end tw_vl_start */
850 * Initialize a word list
852 void
853 tw_wl_start(DIR *dfd, const Char *pat)
855 SETDIR(dfd);
856 tw_word = pat;
857 } /* end tw_wl_start */
861 * Return the next word from the word list
863 /*ARGSUSED*/
865 tw_wl_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
867 const Char *p;
869 USE(dir);
870 USE(flags);
871 if (tw_word == NULL || tw_word[0] == '\0')
872 return 0;
874 while (*tw_word && Isspace(*tw_word)) tw_word++;
876 for (p = tw_word; *tw_word && !Isspace(*tw_word); tw_word++)
877 continue;
878 if (tw_word == p)
879 return 0;
880 Strbuf_appendn(res, p, tw_word - p);
881 if (*tw_word)
882 tw_word++;
883 return 1;
884 } /* end tw_wl_next */
887 /* tw_bind_start():
888 * Begin the list of the shell bindings
890 /*ARGSUSED*/
891 void
892 tw_bind_start(DIR *dfd, const Char *pat)
894 USE(pat);
895 SETDIR(dfd)
896 tw_bind = FuncNames;
897 } /* end tw_bind_start */
900 /* tw_bind_next():
901 * Begin the list of the shell bindings
903 /*ARGSUSED*/
905 tw_bind_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
907 USE(dir);
908 USE(flags);
909 if (tw_bind && tw_bind->name) {
910 const char *ptr;
912 for (ptr = tw_bind->name; *ptr != '\0'; ptr++)
913 Strbuf_append1(res, *ptr);
914 tw_bind++;
915 return 1;
917 return 0;
918 } /* end tw_bind_next */
921 /* tw_limit_start():
922 * Begin the list of the shell limitings
924 /*ARGSUSED*/
925 void
926 tw_limit_start(DIR *dfd, const Char *pat)
928 USE(pat);
929 SETDIR(dfd)
930 #ifndef HAVENOLIMIT
931 tw_limit = limits;
932 #endif /* ! HAVENOLIMIT */
933 } /* end tw_limit_start */
936 /* tw_limit_next():
937 * Begin the list of the shell limitings
939 /*ARGSUSED*/
941 tw_limit_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
943 USE(dir);
944 USE(flags);
945 #ifndef HAVENOLIMIT
946 if (tw_limit && tw_limit->limname) {
947 const char *ptr;
949 for (ptr = tw_limit->limname; *ptr != '\0'; ptr++)
950 Strbuf_append1(res, *ptr);
951 tw_limit++;
952 return 1;
954 #endif /* ! HAVENOLIMIT */
955 return 0;
956 } /* end tw_limit_next */
959 /* tw_sig_start():
960 * Begin the list of the shell sigings
962 /*ARGSUSED*/
963 void
964 tw_sig_start(DIR *dfd, const Char *pat)
966 USE(pat);
967 SETDIR(dfd)
968 tw_index = 0;
969 } /* end tw_sig_start */
972 /* tw_sig_next():
973 * Begin the list of the shell sigings
975 /*ARGSUSED*/
977 tw_sig_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
979 USE(dir);
980 USE(flags);
981 for (;tw_index < nsig; tw_index++) {
982 const char *ptr;
984 if (mesg[tw_index].iname == NULL)
985 continue;
987 for (ptr = mesg[tw_index].iname; *ptr != '\0'; ptr++)
988 Strbuf_append1(res, *ptr);
989 tw_index++;
990 return 1;
992 return 0;
993 } /* end tw_sig_next */
996 /* tw_job_start():
997 * Begin the list of the shell jobings
999 /*ARGSUSED*/
1000 void
1001 tw_job_start(DIR *dfd, const Char *pat)
1003 USE(pat);
1004 SETDIR(dfd)
1005 tw_index = 1;
1006 } /* end tw_job_start */
1009 /* tw_job_next():
1010 * Begin the list of the shell jobings
1012 /*ARGSUSED*/
1014 tw_job_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
1016 struct process *j;
1018 USE(dir);
1019 USE(flags);
1020 for (;tw_index <= pmaxindex; tw_index++) {
1021 for (j = proclist.p_next; j != NULL; j = j->p_next)
1022 if (j->p_index == tw_index && j->p_procid == j->p_jobid)
1023 break;
1024 if (j == NULL)
1025 continue;
1026 Strbuf_append(res, j->p_command);
1027 tw_index++;
1028 return 1;
1030 return 0;
1031 } /* end tw_job_next */