/contrib/tcsh/tw.init.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1031 lines · 689 code · 134 blank · 208 comment · 193 complexity · 3b3d67317d34a4bc0a34b20bff15b070 MD5 · raw file

  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.
  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. 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.
  20. *
  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.
  32. */
  33. #include "sh.h"
  34. RCSID("$tcsh: tw.init.c,v 3.42 2011/04/17 14:49:30 christos Exp $")
  35. #include "tw.h"
  36. #include "ed.h"
  37. #include "tc.h"
  38. #include "sh.proc.h"
  39. #define TW_INCR 128
  40. typedef struct {
  41. Char **list, /* List of command names */
  42. *buff; /* Space holding command names */
  43. size_t nlist, /* Number of items */
  44. nbuff, /* Current space in name buf */
  45. tlist, /* Total space in list */
  46. tbuff; /* Total space in name buf */
  47. } stringlist_t;
  48. static struct varent *tw_vptr = NULL; /* Current shell variable */
  49. static Char **tw_env = NULL; /* Current environment variable */
  50. static const Char *tw_word; /* Current word pointer */
  51. static struct KeyFuncs *tw_bind = NULL; /* List of the bindings */
  52. #ifndef HAVENOLIMIT
  53. static struct limits *tw_limit = NULL; /* List of the resource limits */
  54. #endif /* HAVENOLIMIT */
  55. static int tw_index = 0; /* signal and job index */
  56. static DIR *tw_dir_fd = NULL; /* Current directory descriptor */
  57. static int tw_cmd_got = 0; /* What we need to do */
  58. static stringlist_t tw_cmd = { NULL, NULL, 0, 0, 0, 0 };
  59. static stringlist_t tw_item = { NULL, NULL, 0, 0, 0, 0 };
  60. #define TW_FL_CMD 0x01
  61. #define TW_FL_ALIAS 0x02
  62. #define TW_FL_BUILTIN 0x04
  63. #define TW_FL_SORT 0x08
  64. #define TW_FL_REL 0x10
  65. static struct { /* Current element pointer */
  66. size_t cur; /* Current element number */
  67. Char **pathv; /* Current element in path */
  68. DIR *dfd; /* Current directory descriptor */
  69. } tw_cmd_state;
  70. #define SETDIR(dfd) \
  71. { \
  72. tw_dir_fd = dfd; \
  73. if (tw_dir_fd != NULL) \
  74. rewinddir(tw_dir_fd); \
  75. }
  76. #define CLRDIR(dfd) \
  77. if (dfd != NULL) { \
  78. pintr_disabled++; \
  79. xclosedir(dfd); \
  80. dfd = NULL; \
  81. disabled_cleanup(&pintr_disabled); \
  82. }
  83. static Char *tw_str_add (stringlist_t *, size_t);
  84. static void tw_str_free (stringlist_t *);
  85. static int tw_dir_next (struct Strbuf *, DIR *);
  86. static void tw_cmd_add (const Char *name);
  87. static void tw_cmd_cmd (void);
  88. static void tw_cmd_builtin (void);
  89. static void tw_cmd_alias (void);
  90. static void tw_cmd_sort (void);
  91. static void tw_vptr_start (struct varent *);
  92. /* tw_str_add():
  93. * Add an item to the string list
  94. */
  95. static Char *
  96. tw_str_add(stringlist_t *sl, size_t len)
  97. {
  98. Char *ptr;
  99. if (sl->tlist <= sl->nlist) {
  100. pintr_disabled++;
  101. sl->tlist += TW_INCR;
  102. sl->list = xrealloc(sl->list, sl->tlist * sizeof(Char *));
  103. disabled_cleanup(&pintr_disabled);
  104. }
  105. if (sl->tbuff <= sl->nbuff + len) {
  106. size_t i;
  107. ptr = sl->buff;
  108. pintr_disabled++;
  109. sl->tbuff += TW_INCR + len;
  110. sl->buff = xrealloc(sl->buff, sl->tbuff * sizeof(Char));
  111. /* Re-thread the new pointer list, if changed */
  112. if (ptr != NULL && ptr != sl->buff) {
  113. intptr_t offs = sl->buff - ptr;
  114. for (i = 0; i < sl->nlist; i++)
  115. sl->list[i] += offs;
  116. }
  117. disabled_cleanup(&pintr_disabled);
  118. }
  119. ptr = sl->list[sl->nlist++] = &sl->buff[sl->nbuff];
  120. sl->nbuff += len;
  121. return ptr;
  122. } /* tw_str_add */
  123. /* tw_str_free():
  124. * Free a stringlist
  125. */
  126. static void
  127. tw_str_free(stringlist_t *sl)
  128. {
  129. pintr_disabled++;
  130. if (sl->list) {
  131. xfree(sl->list);
  132. sl->list = NULL;
  133. sl->tlist = sl->nlist = 0;
  134. }
  135. if (sl->buff) {
  136. xfree(sl->buff);
  137. sl->buff = NULL;
  138. sl->tbuff = sl->nbuff = 0;
  139. }
  140. disabled_cleanup(&pintr_disabled);
  141. } /* end tw_str_free */
  142. static int
  143. tw_dir_next(struct Strbuf *res, DIR *dfd)
  144. {
  145. struct dirent *dirp;
  146. if (dfd == NULL)
  147. return 0;
  148. if ((dirp = readdir(dfd)) != NULL) {
  149. Strbuf_append(res, str2short(dirp->d_name));
  150. return 1;
  151. }
  152. return 0;
  153. } /* end tw_dir_next */
  154. /* tw_cmd_add():
  155. * Add the name to the command list
  156. */
  157. static void
  158. tw_cmd_add(const Char *name)
  159. {
  160. size_t len;
  161. len = Strlen(name) + 2;
  162. (void) Strcpy(tw_str_add(&tw_cmd, len), name);
  163. } /* end tw_cmd_add */
  164. /* tw_cmd_free():
  165. * Free the command list
  166. */
  167. void
  168. tw_cmd_free(void)
  169. {
  170. CLRDIR(tw_dir_fd)
  171. tw_str_free(&tw_cmd);
  172. tw_cmd_got = 0;
  173. } /* end tw_cmd_free */
  174. /* tw_cmd_cmd():
  175. * Add system commands to the command list
  176. */
  177. static void
  178. tw_cmd_cmd(void)
  179. {
  180. DIR *dirp;
  181. struct dirent *dp;
  182. Char *dir = NULL, *name;
  183. Char **pv;
  184. struct varent *v = adrof(STRpath);
  185. struct varent *recexec = adrof(STRrecognize_only_executables);
  186. size_t len;
  187. if (v == NULL || v->vec == NULL) /* if no path */
  188. return;
  189. for (pv = v->vec; *pv; pv++) {
  190. if (pv[0][0] != '/') {
  191. tw_cmd_got |= TW_FL_REL;
  192. continue;
  193. }
  194. if ((dirp = opendir(short2str(*pv))) == NULL)
  195. continue;
  196. cleanup_push(dirp, opendir_cleanup);
  197. if (recexec) {
  198. dir = Strspl(*pv, STRslash);
  199. cleanup_push(dir, xfree);
  200. }
  201. while ((dp = readdir(dirp)) != NULL) {
  202. #if defined(_UWIN) || defined(__CYGWIN__)
  203. /* Turn foo.{exe,com,bat} into foo since UWIN's readdir returns
  204. * the file with the .exe, .com, .bat extension
  205. *
  206. * Same for Cygwin, but only for .exe and .com extension.
  207. */
  208. len = strlen(dp->d_name);
  209. if (len > 4 && (strcmp(&dp->d_name[len - 4], ".exe") == 0 ||
  210. #ifndef __CYGWIN__
  211. strcmp(&dp->d_name[len - 4], ".bat") == 0 ||
  212. #endif /* !__CYGWIN__ */
  213. strcmp(&dp->d_name[len - 4], ".com") == 0))
  214. dp->d_name[len - 4] = '\0';
  215. #endif /* _UWIN || __CYGWIN__ */
  216. /* the call to executable() may make this a bit slow */
  217. name = str2short(dp->d_name);
  218. if (dp->d_ino == 0 || (recexec && !executable(dir, name, 0)))
  219. continue;
  220. len = Strlen(name);
  221. if (name[0] == '#' || /* emacs temp files */
  222. name[0] == '.' || /* .files */
  223. name[len - 1] == '~' || /* emacs backups */
  224. name[len - 1] == '%') /* textedit backups */
  225. continue; /* Ignore! */
  226. tw_cmd_add(name);
  227. }
  228. cleanup_until(dirp);
  229. }
  230. } /* end tw_cmd_cmd */
  231. /* tw_cmd_builtin():
  232. * Add builtins to the command list
  233. */
  234. static void
  235. tw_cmd_builtin(void)
  236. {
  237. const struct biltins *bptr;
  238. for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++)
  239. if (bptr->bname)
  240. tw_cmd_add(str2short(bptr->bname));
  241. #ifdef WINNT_NATIVE
  242. for (bptr = nt_bfunc; bptr < &nt_bfunc[nt_nbfunc]; bptr++)
  243. if (bptr->bname)
  244. tw_cmd_add(str2short(bptr->bname));
  245. #endif /* WINNT_NATIVE*/
  246. } /* end tw_cmd_builtin */
  247. /* tw_cmd_alias():
  248. * Add aliases to the command list
  249. */
  250. static void
  251. tw_cmd_alias(void)
  252. {
  253. struct varent *p;
  254. struct varent *c;
  255. p = &aliases;
  256. for (;;) {
  257. while (p->v_left)
  258. p = p->v_left;
  259. x:
  260. if (p->v_parent == 0) /* is it the header? */
  261. return;
  262. if (p->v_name)
  263. tw_cmd_add(p->v_name);
  264. if (p->v_right) {
  265. p = p->v_right;
  266. continue;
  267. }
  268. do {
  269. c = p;
  270. p = p->v_parent;
  271. } while (p->v_right == c);
  272. goto x;
  273. }
  274. } /* end tw_cmd_alias */
  275. /* tw_cmd_sort():
  276. * Sort the command list removing duplicate elements
  277. */
  278. static void
  279. tw_cmd_sort(void)
  280. {
  281. size_t fwd, i;
  282. pintr_disabled++;
  283. /* sort the list. */
  284. qsort(tw_cmd.list, tw_cmd.nlist, sizeof(Char *), fcompare);
  285. /* get rid of multiple entries */
  286. for (i = 0, fwd = 0; i + 1 < tw_cmd.nlist; i++) {
  287. if (Strcmp(tw_cmd.list[i], tw_cmd.list[i + 1]) == 0) /* garbage */
  288. fwd++; /* increase the forward ref. count */
  289. else if (fwd)
  290. tw_cmd.list[i - fwd] = tw_cmd.list[i];
  291. }
  292. /* Fix fencepost error -- Theodore Ts'o <tytso@athena.mit.edu> */
  293. if (fwd)
  294. tw_cmd.list[i - fwd] = tw_cmd.list[i];
  295. tw_cmd.nlist -= fwd;
  296. disabled_cleanup(&pintr_disabled);
  297. } /* end tw_cmd_sort */
  298. /* tw_cmd_start():
  299. * Get the command list and sort it, if not done yet.
  300. * Reset the current pointer to the beginning of the command list
  301. */
  302. /*ARGSUSED*/
  303. void
  304. tw_cmd_start(DIR *dfd, const Char *pat)
  305. {
  306. static Char *defpath[] = { STRNULL, 0 };
  307. USE(pat);
  308. SETDIR(dfd)
  309. if ((tw_cmd_got & TW_FL_CMD) == 0) {
  310. tw_cmd_free();
  311. tw_cmd_cmd();
  312. tw_cmd_got |= TW_FL_CMD;
  313. }
  314. if ((tw_cmd_got & TW_FL_ALIAS) == 0) {
  315. tw_cmd_alias();
  316. tw_cmd_got &= ~TW_FL_SORT;
  317. tw_cmd_got |= TW_FL_ALIAS;
  318. }
  319. if ((tw_cmd_got & TW_FL_BUILTIN) == 0) {
  320. tw_cmd_builtin();
  321. tw_cmd_got &= ~TW_FL_SORT;
  322. tw_cmd_got |= TW_FL_BUILTIN;
  323. }
  324. if ((tw_cmd_got & TW_FL_SORT) == 0) {
  325. tw_cmd_sort();
  326. tw_cmd_got |= TW_FL_SORT;
  327. }
  328. tw_cmd_state.cur = 0;
  329. CLRDIR(tw_cmd_state.dfd)
  330. if (tw_cmd_got & TW_FL_REL) {
  331. struct varent *vp = adrof(STRpath);
  332. if (vp && vp->vec)
  333. tw_cmd_state.pathv = vp->vec;
  334. else
  335. tw_cmd_state.pathv = defpath;
  336. }
  337. else
  338. tw_cmd_state.pathv = defpath;
  339. } /* tw_cmd_start */
  340. /* tw_cmd_next():
  341. * Return the next element in the command list or
  342. * Look for commands in the relative path components
  343. */
  344. int
  345. tw_cmd_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  346. {
  347. int ret = 0;
  348. Char *ptr;
  349. if (tw_cmd_state.cur < tw_cmd.nlist) {
  350. *flags = TW_DIR_OK;
  351. Strbuf_append(res, tw_cmd.list[tw_cmd_state.cur++]);
  352. return 1;
  353. }
  354. /*
  355. * We need to process relatives in the path.
  356. */
  357. while ((tw_cmd_state.dfd == NULL ||
  358. (res->len = 0, ret = tw_dir_next(res, tw_cmd_state.dfd)) == 0) &&
  359. *tw_cmd_state.pathv != NULL) {
  360. CLRDIR(tw_cmd_state.dfd)
  361. while (*tw_cmd_state.pathv && tw_cmd_state.pathv[0][0] == '/')
  362. tw_cmd_state.pathv++;
  363. if ((ptr = *tw_cmd_state.pathv) != 0) {
  364. res->len = 0;
  365. Strbuf_append(res, ptr);
  366. ret = 1;
  367. /*
  368. * We complete directories only on '.' should that
  369. * be changed?
  370. */
  371. dir->len = 0;
  372. if (ptr[0] == '\0' || (ptr[0] == '.' && ptr[1] == '\0')) {
  373. tw_cmd_state.dfd = opendir(".");
  374. *flags = TW_DIR_OK | TW_EXEC_CHK;
  375. }
  376. else {
  377. Strbuf_append(dir, *tw_cmd_state.pathv);
  378. Strbuf_append1(dir, '/');
  379. tw_cmd_state.dfd = opendir(short2str(*tw_cmd_state.pathv));
  380. *flags = TW_EXEC_CHK;
  381. }
  382. Strbuf_terminate(dir);
  383. tw_cmd_state.pathv++;
  384. }
  385. }
  386. return ret;
  387. } /* end tw_cmd_next */
  388. /* tw_vptr_start():
  389. * Find the first variable in the variable list
  390. */
  391. static void
  392. tw_vptr_start(struct varent *c)
  393. {
  394. tw_vptr = c; /* start at beginning of variable list */
  395. for (;;) {
  396. while (tw_vptr->v_left)
  397. tw_vptr = tw_vptr->v_left;
  398. x:
  399. if (tw_vptr->v_parent == 0) { /* is it the header? */
  400. tw_vptr = NULL;
  401. return;
  402. }
  403. if (tw_vptr->v_name)
  404. return; /* found first one */
  405. if (tw_vptr->v_right) {
  406. tw_vptr = tw_vptr->v_right;
  407. continue;
  408. }
  409. do {
  410. c = tw_vptr;
  411. tw_vptr = tw_vptr->v_parent;
  412. } while (tw_vptr->v_right == c);
  413. goto x;
  414. }
  415. } /* end tw_shvar_start */
  416. /* tw_shvar_next():
  417. * Return the next shell variable
  418. */
  419. /*ARGSUSED*/
  420. int
  421. tw_shvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  422. {
  423. struct varent *p;
  424. struct varent *c;
  425. USE(flags);
  426. USE(dir);
  427. if ((p = tw_vptr) == NULL)
  428. return 0; /* just in case */
  429. Strbuf_append(res, p->v_name); /* we know that this name is here now */
  430. /* now find the next one */
  431. for (;;) {
  432. if (p->v_right) { /* if we can go right */
  433. p = p->v_right;
  434. while (p->v_left)
  435. p = p->v_left;
  436. }
  437. else { /* else go up */
  438. do {
  439. c = p;
  440. p = p->v_parent;
  441. } while (p->v_right == c);
  442. }
  443. if (p->v_parent == 0) { /* is it the header? */
  444. tw_vptr = NULL;
  445. return 1;
  446. }
  447. if (p->v_name) {
  448. tw_vptr = p; /* save state for the next call */
  449. return 1;
  450. }
  451. }
  452. } /* end tw_shvar_next */
  453. /* tw_envvar_next():
  454. * Return the next environment variable
  455. */
  456. /*ARGSUSED*/
  457. int
  458. tw_envvar_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  459. {
  460. const Char *ps;
  461. USE(flags);
  462. USE(dir);
  463. if (tw_env == NULL || *tw_env == NULL)
  464. return 0;
  465. for (ps = *tw_env; *ps && *ps != '='; ps++)
  466. continue;
  467. Strbuf_appendn(res, *tw_env, ps - *tw_env);
  468. tw_env++;
  469. return 1;
  470. } /* end tw_envvar_next */
  471. /* tw_var_start():
  472. * Begin the list of the shell and environment variables
  473. */
  474. /*ARGSUSED*/
  475. void
  476. tw_var_start(DIR *dfd, const Char *pat)
  477. {
  478. USE(pat);
  479. SETDIR(dfd)
  480. tw_vptr_start(&shvhed);
  481. tw_env = STR_environ;
  482. } /* end tw_var_start */
  483. /* tw_alias_start():
  484. * Begin the list of the shell aliases
  485. */
  486. /*ARGSUSED*/
  487. void
  488. tw_alias_start(DIR *dfd, const Char *pat)
  489. {
  490. USE(pat);
  491. SETDIR(dfd)
  492. tw_vptr_start(&aliases);
  493. tw_env = NULL;
  494. } /* tw_alias_start */
  495. /* tw_complete_start():
  496. * Begin the list of completions
  497. */
  498. /*ARGSUSED*/
  499. void
  500. tw_complete_start(DIR *dfd, const Char *pat)
  501. {
  502. USE(pat);
  503. SETDIR(dfd)
  504. tw_vptr_start(&completions);
  505. tw_env = NULL;
  506. } /* end tw_complete_start */
  507. /* tw_var_next():
  508. * Return the next shell or environment variable
  509. */
  510. int
  511. tw_var_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  512. {
  513. int ret = 0;
  514. if (tw_vptr)
  515. ret = tw_shvar_next(res, dir, flags);
  516. if (ret == 0 && tw_env)
  517. ret = tw_envvar_next(res, dir, flags);
  518. return ret;
  519. } /* end tw_var_next */
  520. /* tw_logname_start():
  521. * Initialize lognames to the beginning of the list
  522. */
  523. /*ARGSUSED*/
  524. void
  525. tw_logname_start(DIR *dfd, const Char *pat)
  526. {
  527. USE(pat);
  528. SETDIR(dfd)
  529. #ifdef HAVE_GETPWENT
  530. (void) setpwent(); /* Open passwd file */
  531. #endif
  532. } /* end tw_logname_start */
  533. /* tw_logname_next():
  534. * Return the next entry from the passwd file
  535. */
  536. /*ARGSUSED*/
  537. int
  538. tw_logname_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  539. {
  540. struct passwd *pw;
  541. /*
  542. * We don't want to get interrupted inside getpwent()
  543. * because the yellow pages code is not interruptible,
  544. * and if we call endpwent() immediatetely after
  545. * (in pintr()) we may be freeing an invalid pointer
  546. */
  547. USE(flags);
  548. USE(dir);
  549. pintr_disabled++;
  550. #ifdef HAVE_GETPWENT
  551. pw = getpwent();
  552. #else
  553. pw = NULL;
  554. #endif
  555. disabled_cleanup(&pintr_disabled);
  556. if (pw == NULL) {
  557. #ifdef YPBUGS
  558. fix_yp_bugs();
  559. #endif
  560. return 0;
  561. }
  562. Strbuf_append(res, str2short(pw->pw_name));
  563. return 1;
  564. } /* end tw_logname_next */
  565. /* tw_logname_end():
  566. * Close the passwd file to finish the logname list
  567. */
  568. void
  569. tw_logname_end(void)
  570. {
  571. #ifdef YPBUGS
  572. fix_yp_bugs();
  573. #endif
  574. #ifdef HAVE_GETPWENT
  575. (void) endpwent();
  576. #endif
  577. } /* end tw_logname_end */
  578. /* tw_grpname_start():
  579. * Initialize grpnames to the beginning of the list
  580. */
  581. /*ARGSUSED*/
  582. void
  583. tw_grpname_start(DIR *dfd, const Char *pat)
  584. {
  585. USE(pat);
  586. SETDIR(dfd)
  587. #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__)
  588. (void) setgrent(); /* Open group file */
  589. #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
  590. } /* end tw_grpname_start */
  591. /* tw_grpname_next():
  592. * Return the next entry from the group file
  593. */
  594. /*ARGSUSED*/
  595. int
  596. tw_grpname_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  597. {
  598. struct group *gr;
  599. /*
  600. * We don't want to get interrupted inside getgrent()
  601. * because the yellow pages code is not interruptible,
  602. * and if we call endgrent() immediatetely after
  603. * (in pintr()) we may be freeing an invalid pointer
  604. */
  605. USE(flags);
  606. USE(dir);
  607. pintr_disabled++;
  608. #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined(__ANDROID__)
  609. errno = 0;
  610. while ((gr = getgrent()) == NULL && errno == EINTR) {
  611. handle_pending_signals();
  612. errno = 0;
  613. }
  614. #else /* _VMS_POSIX || _OSD_POSIX || WINNT_NATIVE */
  615. gr = NULL;
  616. #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
  617. disabled_cleanup(&pintr_disabled);
  618. if (gr == NULL) {
  619. #ifdef YPBUGS
  620. fix_yp_bugs();
  621. #endif
  622. return 0;
  623. }
  624. Strbuf_append(res, str2short(gr->gr_name));
  625. return 1;
  626. } /* end tw_grpname_next */
  627. /* tw_grpname_end():
  628. * Close the group file to finish the groupname list
  629. */
  630. void
  631. tw_grpname_end(void)
  632. {
  633. #ifdef YPBUGS
  634. fix_yp_bugs();
  635. #endif
  636. #if !defined(_VMS_POSIX) && !defined(_OSD_POSIX) && !defined(WINNT_NATIVE) && !defined (__ANDROID__)
  637. (void) endgrent();
  638. #endif /* !_VMS_POSIX && !_OSD_POSIX && !WINNT_NATIVE */
  639. } /* end tw_grpname_end */
  640. /* tw_file_start():
  641. * Initialize the directory for the file list
  642. */
  643. /*ARGSUSED*/
  644. void
  645. tw_file_start(DIR *dfd, const Char *pat)
  646. {
  647. struct varent *vp;
  648. USE(pat);
  649. SETDIR(dfd)
  650. if ((vp = adrof(STRcdpath)) != NULL)
  651. tw_env = vp->vec;
  652. } /* end tw_file_start */
  653. /* tw_file_next():
  654. * Return the next file in the directory
  655. */
  656. int
  657. tw_file_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  658. {
  659. int ret = tw_dir_next(res, tw_dir_fd);
  660. if (ret == 0 && (*flags & TW_DIR_OK) != 0) {
  661. CLRDIR(tw_dir_fd)
  662. while (tw_env && *tw_env)
  663. if ((tw_dir_fd = opendir(short2str(*tw_env))) != NULL)
  664. break;
  665. else
  666. tw_env++;
  667. if (tw_dir_fd) {
  668. dir->len = 0;
  669. Strbuf_append(dir, *tw_env++);
  670. Strbuf_append1(dir, '/');
  671. Strbuf_terminate(dir);
  672. ret = tw_dir_next(res, tw_dir_fd);
  673. }
  674. }
  675. return ret;
  676. } /* end tw_file_next */
  677. /* tw_dir_end():
  678. * Clear directory related lists
  679. */
  680. void
  681. tw_dir_end(void)
  682. {
  683. CLRDIR(tw_dir_fd)
  684. CLRDIR(tw_cmd_state.dfd)
  685. } /* end tw_dir_end */
  686. /* tw_item_free():
  687. * Free the item list
  688. */
  689. void
  690. tw_item_free(void)
  691. {
  692. tw_str_free(&tw_item);
  693. } /* end tw_item_free */
  694. /* tw_item_get():
  695. * Return the list of items
  696. */
  697. Char **
  698. tw_item_get(void)
  699. {
  700. return tw_item.list;
  701. } /* end tw_item_get */
  702. /* tw_item_add():
  703. * Return a new item for a Strbuf_terminate()'d s
  704. */
  705. void
  706. tw_item_add(const struct Strbuf *s)
  707. {
  708. Char *p;
  709. p = tw_str_add(&tw_item, s->len + 1);
  710. Strcpy(p, s->s);
  711. } /* tw_item_add */
  712. /* tw_item_find():
  713. * Find the string if it exists in the item list
  714. * end return it.
  715. */
  716. Char *
  717. tw_item_find(Char *str)
  718. {
  719. size_t i;
  720. if (tw_item.list == NULL || str == NULL)
  721. return NULL;
  722. for (i = 0; i < tw_item.nlist; i++)
  723. if (tw_item.list[i] != NULL && Strcmp(tw_item.list[i], str) == 0)
  724. return tw_item.list[i];
  725. return NULL;
  726. } /* end tw_item_find */
  727. /* tw_vl_start():
  728. * Initialize a variable list
  729. */
  730. void
  731. tw_vl_start(DIR *dfd, const Char *pat)
  732. {
  733. SETDIR(dfd)
  734. if ((tw_vptr = adrof(pat)) != NULL) {
  735. tw_env = tw_vptr->vec;
  736. tw_vptr = NULL;
  737. }
  738. else
  739. tw_env = NULL;
  740. } /* end tw_vl_start */
  741. /*
  742. * Initialize a word list
  743. */
  744. void
  745. tw_wl_start(DIR *dfd, const Char *pat)
  746. {
  747. SETDIR(dfd);
  748. tw_word = pat;
  749. } /* end tw_wl_start */
  750. /*
  751. * Return the next word from the word list
  752. */
  753. /*ARGSUSED*/
  754. int
  755. tw_wl_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  756. {
  757. const Char *p;
  758. USE(dir);
  759. USE(flags);
  760. if (tw_word == NULL || tw_word[0] == '\0')
  761. return 0;
  762. while (*tw_word && Isspace(*tw_word)) tw_word++;
  763. for (p = tw_word; *tw_word && !Isspace(*tw_word); tw_word++)
  764. continue;
  765. if (tw_word == p)
  766. return 0;
  767. Strbuf_appendn(res, p, tw_word - p);
  768. if (*tw_word)
  769. tw_word++;
  770. return 1;
  771. } /* end tw_wl_next */
  772. /* tw_bind_start():
  773. * Begin the list of the shell bindings
  774. */
  775. /*ARGSUSED*/
  776. void
  777. tw_bind_start(DIR *dfd, const Char *pat)
  778. {
  779. USE(pat);
  780. SETDIR(dfd)
  781. tw_bind = FuncNames;
  782. } /* end tw_bind_start */
  783. /* tw_bind_next():
  784. * Begin the list of the shell bindings
  785. */
  786. /*ARGSUSED*/
  787. int
  788. tw_bind_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  789. {
  790. USE(dir);
  791. USE(flags);
  792. if (tw_bind && tw_bind->name) {
  793. const char *ptr;
  794. for (ptr = tw_bind->name; *ptr != '\0'; ptr++)
  795. Strbuf_append1(res, *ptr);
  796. tw_bind++;
  797. return 1;
  798. }
  799. return 0;
  800. } /* end tw_bind_next */
  801. /* tw_limit_start():
  802. * Begin the list of the shell limitings
  803. */
  804. /*ARGSUSED*/
  805. void
  806. tw_limit_start(DIR *dfd, const Char *pat)
  807. {
  808. USE(pat);
  809. SETDIR(dfd)
  810. #ifndef HAVENOLIMIT
  811. tw_limit = limits;
  812. #endif /* ! HAVENOLIMIT */
  813. } /* end tw_limit_start */
  814. /* tw_limit_next():
  815. * Begin the list of the shell limitings
  816. */
  817. /*ARGSUSED*/
  818. int
  819. tw_limit_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  820. {
  821. USE(dir);
  822. USE(flags);
  823. #ifndef HAVENOLIMIT
  824. if (tw_limit && tw_limit->limname) {
  825. const char *ptr;
  826. for (ptr = tw_limit->limname; *ptr != '\0'; ptr++)
  827. Strbuf_append1(res, *ptr);
  828. tw_limit++;
  829. return 1;
  830. }
  831. #endif /* ! HAVENOLIMIT */
  832. return 0;
  833. } /* end tw_limit_next */
  834. /* tw_sig_start():
  835. * Begin the list of the shell sigings
  836. */
  837. /*ARGSUSED*/
  838. void
  839. tw_sig_start(DIR *dfd, const Char *pat)
  840. {
  841. USE(pat);
  842. SETDIR(dfd)
  843. tw_index = 0;
  844. } /* end tw_sig_start */
  845. /* tw_sig_next():
  846. * Begin the list of the shell sigings
  847. */
  848. /*ARGSUSED*/
  849. int
  850. tw_sig_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  851. {
  852. USE(dir);
  853. USE(flags);
  854. for (;tw_index < nsig; tw_index++) {
  855. const char *ptr;
  856. if (mesg[tw_index].iname == NULL)
  857. continue;
  858. for (ptr = mesg[tw_index].iname; *ptr != '\0'; ptr++)
  859. Strbuf_append1(res, *ptr);
  860. tw_index++;
  861. return 1;
  862. }
  863. return 0;
  864. } /* end tw_sig_next */
  865. /* tw_job_start():
  866. * Begin the list of the shell jobings
  867. */
  868. /*ARGSUSED*/
  869. void
  870. tw_job_start(DIR *dfd, const Char *pat)
  871. {
  872. USE(pat);
  873. SETDIR(dfd)
  874. tw_index = 1;
  875. } /* end tw_job_start */
  876. /* tw_job_next():
  877. * Begin the list of the shell jobings
  878. */
  879. /*ARGSUSED*/
  880. int
  881. tw_job_next(struct Strbuf *res, struct Strbuf *dir, int *flags)
  882. {
  883. struct process *j;
  884. USE(dir);
  885. USE(flags);
  886. for (;tw_index <= pmaxindex; tw_index++) {
  887. for (j = proclist.p_next; j != NULL; j = j->p_next)
  888. if (j->p_index == tw_index && j->p_procid == j->p_jobid)
  889. break;
  890. if (j == NULL)
  891. continue;
  892. Strbuf_append(res, j->p_command);
  893. tw_index++;
  894. return 1;
  895. }
  896. return 0;
  897. } /* end tw_job_next */