exec.c revision 1.1 1 /*
2 * execute command tree
3 */
4
5 #include "sh.h"
6 #include "c_test.h"
7 #include <ctype.h>
8 #include "ksh_stat.h"
9
10 /* Does ps4 get parameter substitutions done? */
11 #ifdef KSH
12 # define PS4_SUBSTITUTE(s) substitute((s), 0)
13 #else
14 # define PS4_SUBSTITUTE(s) (s)
15 #endif /* KSH */
16
17 static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap,
18 int volatile flags));
19 static void scriptexec ARGS((struct op *tp, char **ap));
20 static int call_builtin ARGS((struct tbl *tp, char **wp));
21 static int iosetup ARGS((struct ioword *iop, struct tbl *tp));
22 static int herein ARGS((char *hname, int sub));
23 #ifdef KSH
24 static char *do_selectargs ARGS((char **ap, bool_t print_menu));
25 #endif /* KSH */
26 #ifdef KSH
27 static int dbteste_isa ARGS((Test_env *te, Test_meta meta));
28 static const char *dbteste_getopnd ARGS((Test_env *te, Test_op op,
29 int do_eval));
30 static int dbteste_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
31 const char *opnd2, int do_eval));
32 static void dbteste_error ARGS((Test_env *te, int offset, const char *msg));
33 #endif /* KSH */
34 #ifdef OS2
35 static int search_access1 ARGS((const char *path, int mode));
36 #endif /* OS2 */
37
38
39 /*
40 * handle systems that don't have F_SETFD
41 */
42 #ifndef F_SETFD
43 # ifndef MAXFD
44 # define MAXFD 64
45 # endif
46 /* a bit field would be smaller, but this will work */
47 static char clexec_tab[MAXFD+1];
48 #endif
49
50 /*
51 * we now use this function always.
52 */
53 int
54 fd_clexec(fd)
55 int fd;
56 {
57 #ifndef F_SETFD
58 if (fd >= 0 && fd < sizeof(clexec_tab)) {
59 clexec_tab[fd] = 1;
60 return 0;
61 }
62 return -1;
63 #else
64 return fcntl(fd, F_SETFD, 1);
65 #endif
66 }
67
68
69 /*
70 * execute command tree
71 */
72 int
73 execute(t, flags)
74 struct op * volatile t;
75 volatile int flags; /* if XEXEC don't fork */
76 {
77 int i;
78 volatile int rv = 0;
79 int pv[2];
80 char ** volatile ap;
81 char *s, *cp;
82 struct ioword **iowp;
83 struct tbl *tp = NULL;
84
85 if (t == NULL)
86 return 0;
87
88 /* Is this the end of a pipeline? If so, we want to evaluate the
89 * command arguments
90 bool_t eval_done = FALSE;
91 if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {
92 eval_done = TRUE;
93 tp = eval_execute_args(t, &ap);
94 }
95 */
96 if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
97 return exchild(t, flags, -1); /* run in sub-process */
98
99 newenv(E_EXEC);
100 if (trap)
101 runtraps(0);
102
103 if (t->type == TCOM) {
104 /* Clear subst_exstat before argument expansion. Used by
105 * null commands (see comexec()) and by c_set().
106 */
107 subst_exstat = 0;
108
109 /* POSIX says expand command words first, then redirections,
110 * and assignments last..
111 */
112 ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
113 if (Flag(FXTRACE) && ap[0]) {
114 shf_fprintf(shl_out, "%s",
115 PS4_SUBSTITUTE(str_val(global("PS4"))));
116 for (i = 0; ap[i]; i++)
117 shf_fprintf(shl_out, "%s%s", ap[i],
118 ap[i + 1] ? space : newline);
119 shf_flush(shl_out);
120 }
121 if (ap[0])
122 tp = findcom(ap[0], FC_BI|FC_FUNC);
123 }
124
125 if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
126 e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP);
127 /* initialize to not redirected */
128 memset(e->savefd, 0, sizeofN(short, NUFILE));
129 }
130
131 /* do redirection, to be restored in quitenv() */
132 if (t->ioact != NULL)
133 for (iowp = t->ioact; *iowp != NULL; iowp++) {
134 if (iosetup(*iowp, tp) < 0) {
135 exstat = rv = 1;
136 /* Redirection failures for special commands
137 * cause (non-interactive) shell to exit.
138 */
139 if (tp && tp->type == CSHELL
140 && (tp->flag & SPEC_BI))
141 errorf(null);
142 /* Deal with FERREXIT, quitenv(), etc. */
143 goto Break;
144 }
145 }
146
147 switch(t->type) {
148 case TCOM:
149 rv = comexec(t, tp, ap, flags);
150 break;
151
152 case TPAREN:
153 rv = execute(t->left, flags|XFORK);
154 break;
155
156 case TPIPE:
157 flags |= XFORK;
158 flags &= ~XEXEC;
159 e->savefd[0] = savefd(0, 0);
160 (void) ksh_dup2(e->savefd[0], 0, FALSE); /* stdin of first */
161 e->savefd[1] = savefd(1, 0);
162 while (t->type == TPIPE) {
163 openpipe(pv);
164 (void) ksh_dup2(pv[1], 1, FALSE); /* stdout of curr */
165 /* Let exchild() close pv[0] in child
166 * (if this isn't done, commands like
167 * (: ; cat /etc/termcap) | sleep 1
168 * will hang forever).
169 */
170 exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);
171 (void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */
172 closepipe(pv);
173 flags |= XPIPEI;
174 t = t->right;
175 }
176 restfd(1, e->savefd[1]); /* stdout of last */
177 e->savefd[1] = 0; /* no need to re-restore this */
178 /* Let exchild() close 0 in parent, after fork, before wait */
179 i = exchild(t, flags|XPCLOSE, 0);
180 if (!(flags&XBGND) && !(flags&XXCOM))
181 rv = i;
182 break;
183
184 case TLIST:
185 while (t->type == TLIST) {
186 execute(t->left, flags & XERROK);
187 t = t->right;
188 }
189 rv = execute(t, flags & XERROK);
190 break;
191
192 #ifdef KSH
193 case TCOPROC:
194 {
195 # ifdef JOB_SIGS
196 sigset_t omask;
197 # endif /* JOB_SIGS */
198
199 # ifdef JOB_SIGS
200 /* Block sigchild as we are using things changed in the
201 * signal handler
202 */
203 sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
204 e->type = E_ERRH;
205 i = ksh_sigsetjmp(e->jbuf, 0);
206 if (i) {
207 sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
208 quitenv();
209 unwind(i);
210 /*NOTREACHED*/
211 }
212 # endif /* JOB_SIGS */
213 /* Already have a (live) co-process? */
214 if (coproc.job && coproc.write >= 0)
215 errorf("coprocess already exists");
216
217 /* Can we re-use the existing co-process pipe? */
218 coproc_cleanup(TRUE);
219
220 /* do this before opening pipes, in case these fail */
221 e->savefd[0] = savefd(0, 0);
222 e->savefd[1] = savefd(1, 0);
223
224 openpipe(pv);
225 ksh_dup2(pv[0], 0, FALSE);
226 close(pv[0]);
227 coproc.write = pv[1];
228 coproc.job = (void *) 0;
229
230 if (coproc.readw >= 0)
231 ksh_dup2(coproc.readw, 1, FALSE);
232 else {
233 openpipe(pv);
234 coproc.read = pv[0];
235 ksh_dup2(pv[1], 1, FALSE);
236 coproc.readw = pv[1]; /* closed before first read */
237 coproc.njobs = 0;
238 /* create new coprocess id */
239 ++coproc.id;
240 }
241 # ifdef JOB_SIGS
242 sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
243 e->type = E_EXEC; /* no more need for error handler */
244 # endif /* JOB_SIGS */
245
246 /* exchild() closes coproc.* in child after fork,
247 * will also increment coproc.njobs when the
248 * job is actually created.
249 */
250 flags &= ~XEXEC;
251 exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
252 coproc.readw);
253 break;
254 }
255 #endif /* KSH */
256
257 case TASYNC:
258 /* XXX non-optimal, I think - "(foo &)", forks for (),
259 * forks again for async... parent should optimize
260 * this to "foo &"...
261 */
262 rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);
263 break;
264
265 case TOR:
266 case TAND:
267 rv = execute(t->left, XERROK);
268 if (t->right != NULL && (rv == 0) == (t->type == TAND))
269 rv = execute(t->right, flags & XERROK);
270 else
271 flags |= XERROK;
272 break;
273
274 case TBANG:
275 rv = !execute(t->right, XERROK);
276 break;
277
278 #ifdef KSH
279 case TDBRACKET:
280 {
281 Test_env te;
282
283 te.flags = TEF_DBRACKET;
284 te.pos.wp = t->args;
285 te.isa = dbteste_isa;
286 te.getopnd = dbteste_getopnd;
287 te.eval = dbteste_eval;
288 te.error = dbteste_error;
289
290 rv = test_parse(&te);
291 break;
292 }
293 #endif /* KSH */
294
295 case TFOR:
296 #ifdef KSH
297 case TSELECT:
298 {
299 volatile bool_t is_first = TRUE;
300 #endif /* KSH */
301 ap = (t->vars != NULL) ?
302 eval(t->vars, DOBLANK|DOGLOB|DOTILDE)
303 : e->loc->argv + 1;
304 e->type = E_LOOP;
305 while (1) {
306 i = ksh_sigsetjmp(e->jbuf, 0);
307 if (!i)
308 break;
309 if ((e->flags&EF_BRKCONT_PASS)
310 || (i != LBREAK && i != LCONTIN))
311 {
312 quitenv();
313 unwind(i);
314 } else if (i == LBREAK) {
315 rv = 0;
316 goto Break;
317 }
318 }
319 rv = 0; /* in case of a continue */
320 if (t->type == TFOR) {
321 struct tbl *vq;
322
323 while (*ap != NULL) {
324 vq = global(t->str);
325 if (vq->flag & RDONLY)
326 errorf("%s is read only", t->str);
327 setstr(vq, *ap++);
328 rv = execute(t->left, flags & XERROK);
329 }
330 }
331 #ifdef KSH
332 else { /* TSELECT */
333 struct tbl *vq;
334
335 for (;;) {
336 if (!(cp = do_selectargs(ap, is_first))) {
337 rv = 1;
338 break;
339 }
340 is_first = FALSE;
341 vq = global(t->str);
342 if (vq->flag & RDONLY)
343 errorf("%s is read only", t->str);
344 setstr(vq, cp);
345 rv = execute(t->left, flags & XERROK);
346 }
347 }
348 }
349 #endif /* KSH */
350 break;
351
352 case TWHILE:
353 case TUNTIL:
354 e->type = E_LOOP;
355 while (1) {
356 i = ksh_sigsetjmp(e->jbuf, 0);
357 if (!i)
358 break;
359 if ((e->flags&EF_BRKCONT_PASS)
360 || (i != LBREAK && i != LCONTIN))
361 {
362 quitenv();
363 unwind(i);
364 } else if (i == LBREAK) {
365 rv = 0;
366 goto Break;
367 }
368 }
369 rv = 0; /* in case of a continue */
370 while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))
371 rv = execute(t->right, flags & XERROK);
372 break;
373
374 case TIF:
375 case TELIF:
376 if (t->right == NULL)
377 break; /* should be error */
378 rv = execute(t->left, XERROK) == 0 ?
379 execute(t->right->left, flags & XERROK) :
380 execute(t->right->right, flags & XERROK);
381 break;
382
383 case TCASE:
384 cp = evalstr(t->str, DOTILDE);
385 for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
386 for (ap = t->vars; *ap; ap++)
387 if ((s = evalstr(*ap, DOTILDE|DOPAT))
388 && gmatch(cp, s, FALSE))
389 goto Found;
390 break;
391 Found:
392 rv = execute(t->left, flags & XERROK);
393 break;
394
395 case TBRACE:
396 rv = execute(t->left, flags & XERROK);
397 break;
398
399 case TFUNCT:
400 rv = define(t->str, t);
401 break;
402
403 case TTIME:
404 rv = timex(t, flags);
405 break;
406
407 case TEXEC: /* an eval'd TCOM */
408 s = t->args[0];
409 ap = makenv();
410 #ifndef F_SETFD
411 for (i = 0; i < sizeof(clexec_tab); i++)
412 if (clexec_tab[i]) {
413 close(i);
414 clexec_tab[i] = 0;
415 }
416 #endif
417 restoresigs();
418 ksh_execve(t->str, t->args, ap);
419 if (errno == ENOEXEC)
420 scriptexec(t, ap);
421 else
422 errorf("%s: %s", s, strerror(errno));
423 }
424 Break:
425 exstat = rv;
426
427 quitenv(); /* restores IO */
428 if ((flags&XEXEC))
429 exit(rv); /* exit child */
430 if (rv != 0 && !(flags & XERROK)) {
431 if (Flag(FERREXIT))
432 unwind(LERROR);
433 trapsig(SIGERR_);
434 }
435 return rv;
436 }
437
438 /*
439 * execute simple command
440 */
441
442 static int
443 comexec(t, tp, ap, flags)
444 struct op *t;
445 struct tbl *volatile tp;
446 register char **ap;
447 int volatile flags;
448 {
449 int i;
450 int rv = 0;
451 register char *cp;
452 register char **lastp;
453 static struct op texec; /* Must be static (XXX but why?) */
454 int type_flags;
455 int keepasn_ok;
456 int fcflags = FC_BI|FC_FUNC|FC_PATH;
457
458 /* snag the last argument for $_ XXX not the same as at&t ksh,
459 * which only seems to set $_ after a newline (but not in
460 * functions/dot scripts, but in interactive and scipt) -
461 * perhaps save last arg here and set it in shell()?.
462 */
463 if (*(lastp = ap)) {
464 while (*++lastp)
465 ;
466 setstr(typeset("_", LOCAL, 0, 0, 0), *--lastp);
467 }
468
469 /* Deal with the shell builtins builtin, exec and command since
470 * they can be followed by other commands. This must be done before
471 * we know if we should create a local block, which must be done
472 * before we can do a path search (in case the assignments change
473 * PATH).
474 * Odd cases:
475 * FOO=bar exec > /dev/null FOO is kept but not exported
476 * FOO=bar exec foobar FOO is exported
477 * FOO=bar command exec > /dev/null FOO is neither kept nor exported
478 * FOO=bar command FOO is neither kept nor exported
479 * PATH=... foobar use new PATH in foobar search
480 */
481 keepasn_ok = 1;
482 while (tp && tp->type == CSHELL) {
483 fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
484 if (tp->val.f == c_builtin) {
485 if ((cp = *++ap) == NULL) {
486 tp = NULL;
487 break;
488 }
489 tp = findcom(cp, FC_BI);
490 if (tp == NULL)
491 errorf("builtin: %s: not a builtin", cp);
492 continue;
493 } else if (tp->val.f == c_exec) {
494 if (ap[1] == NULL)
495 break;
496 ap++;
497 flags |= XEXEC;
498 } else if (tp->val.f == c_command) {
499 int optc, saw_p = 0;
500
501 /* Ugly dealing with options in two places (here and
502 * in c_command(), but such is life)
503 */
504 ksh_getopt_reset(&builtin_opt, 0);
505 while ((optc = ksh_getopt(ap, &builtin_opt, ":p"))
506 == 'p')
507 saw_p = 1;
508 if (optc != EOF)
509 break; /* command -vV or something */
510 /* don't look for functions */
511 fcflags = FC_BI|FC_PATH;
512 if (saw_p) {
513 if (Flag(FRESTRICTED)) {
514 warningf(TRUE,
515 "command -p: restricted");
516 rv = 1;
517 goto Leave;
518 }
519 fcflags |= FC_DEFPATH;
520 }
521 ap += builtin_opt.optind;
522 /* POSIX says special builtins loose their status
523 * if accessed using command.
524 */
525 keepasn_ok = 0;
526 if (!ap[0]) {
527 /* ensure command with no args exits with 0 */
528 subst_exstat = 0;
529 break;
530 }
531 } else
532 break;
533 tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
534 }
535 if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
536 type_flags = 0;
537 else {
538 /* create new variable/function block */
539 newblock();
540 /* ksh functions don't keep assignments, POSIX functions do. */
541 if (keepasn_ok && tp && tp->type == CFUNC
542 && !(tp->flag & FKSH))
543 type_flags = 0;
544 else
545 type_flags = LOCAL|LOCAL_COPY|EXPORT;
546 }
547 if (Flag(FEXPORT))
548 type_flags |= EXPORT;
549 for (i = 0; t->vars[i]; i++) {
550 cp = evalstr(t->vars[i], DOASNTILDE);
551 if (Flag(FXTRACE)) {
552 if (i == 0)
553 shf_fprintf(shl_out, "%s",
554 PS4_SUBSTITUTE(str_val(global("PS4"))));
555 shf_fprintf(shl_out, "%s%s", cp,
556 t->vars[i + 1] ? space : newline);
557 if (!t->vars[i + 1])
558 shf_flush(shl_out);
559 }
560 typeset(cp, type_flags, 0, 0, 0);
561 }
562
563 if ((cp = *ap) == NULL) {
564 rv = subst_exstat;
565 goto Leave;
566 } else if (!tp) {
567 if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {
568 warningf(TRUE, "%s: restricted", cp);
569 rv = 1;
570 goto Leave;
571 }
572 tp = findcom(cp, fcflags);
573 }
574
575 switch (tp->type) {
576 case CSHELL: /* shell built-in */
577 rv = call_builtin(tp, ap);
578 break;
579
580 case CFUNC: /* function call */
581 {
582 volatile int old_xflag;
583 volatile Tflag old_inuse;
584 const char *volatile old_kshname;
585
586 if (!(tp->flag & ISSET)) {
587 struct tbl *ftp;
588
589 if (!tp->u.fpath) {
590 if (tp->u2.errno_) {
591 warningf(TRUE,
592 "%s: can't find function definition file - %s",
593 cp, strerror(tp->u2.errno_));
594 rv = 126;
595 } else {
596 warningf(TRUE,
597 "%s: can't find function definition file", cp);
598 rv = 127;
599 }
600 break;
601 }
602 if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
603 warningf(TRUE,
604 "%s: can't open function definition file %s - %s",
605 cp, tp->u.fpath, strerror(errno));
606 rv = 127;
607 break;
608 }
609 if (!(ftp = findfunc(cp, hash(cp), FALSE))
610 || !(ftp->flag & ISSET))
611 {
612 warningf(TRUE,
613 "%s: function not defined by %s",
614 cp, tp->u.fpath);
615 rv = 127;
616 break;
617 }
618 tp = ftp;
619 }
620
621 /* ksh functions set $0 to function name, POSIX functions leave
622 * $0 unchanged.
623 */
624 old_kshname = kshname;
625 if (tp->flag & FKSH)
626 kshname = ap[0];
627 e->loc->argv = ap;
628 for (i = 0; *ap++ != NULL; i++)
629 ;
630 e->loc->argc = i - 1;
631 getopts_reset(1);
632
633 old_xflag = Flag(FXTRACE);
634 Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE;
635
636 old_inuse = tp->flag & FINUSE;
637 tp->flag |= FINUSE;
638
639 e->type = E_FUNC;
640 i = ksh_sigsetjmp(e->jbuf, 0);
641 if (i == 0) {
642 /* seems odd to pass XERROK here, but at&t ksh does */
643 exstat = execute(tp->val.t, flags & XERROK);
644 i = LRETURN;
645 }
646 kshname = old_kshname;
647 Flag(FXTRACE) = old_xflag;
648 tp->flag = (tp->flag & ~FINUSE) | old_inuse;
649 /* Were we deleted while executing? If so, free the execution
650 * tree. todo: Unfortunately, the table entry is never re-used
651 * until the lookup table is expanded.
652 */
653 if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
654 if (tp->flag & ALLOC) {
655 tp->flag &= ~ALLOC;
656 tfree(tp->val.t, tp->areap);
657 }
658 tp->flag = 0;
659 }
660 switch (i) {
661 case LRETURN:
662 case LERROR:
663 rv = exstat;
664 break;
665 case LINTR:
666 case LEXIT:
667 case LLEAVE:
668 case LSHELL:
669 quitenv();
670 unwind(i);
671 /*NOTREACHED*/
672 default:
673 quitenv();
674 internal_errorf(1, "CFUNC %d", i);
675 }
676 break;
677 }
678
679 case CEXEC: /* executable command */
680 case CTALIAS: /* tracked alias */
681 if (!(tp->flag&ISSET)) {
682 /* errno_ will be set if the named command was found
683 * but could not be executed (permissions, no execute
684 * bit, directory, etc). Print out a (hopefully)
685 * useful error message and set the exit status to 126.
686 */
687 if (tp->u2.errno_) {
688 warningf(TRUE, "%s: cannot execute - %s", cp,
689 strerror(tp->u2.errno_));
690 rv = 126; /* POSIX */
691 } else {
692 warningf(TRUE, "%s: not found", cp);
693 rv = 127;
694 }
695 break;
696 }
697
698 /* set $_ to program's full path */
699 setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s);
700
701 if (flags&XEXEC) {
702 j_exit();
703 if (!(flags&XBGND) || Flag(FMONITOR)) {
704 setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
705 setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
706 }
707 }
708
709 /* to fork we set up a TEXEC node and call execute */
710 texec.type = TEXEC;
711 texec.left = t; /* for tprint */
712 texec.str = tp->val.s;
713 texec.args = ap;
714 rv = exchild(&texec, flags, -1);
715 break;
716 }
717 Leave:
718 if (flags & XEXEC) {
719 exstat = rv;
720 unwind(LLEAVE);
721 }
722 return rv;
723 }
724
725 static void
726 scriptexec(tp, ap)
727 register struct op *tp;
728 register char **ap;
729 {
730 char *shell;
731
732 shell = str_val(global(EXECSHELL_STR));
733 if (shell && *shell)
734 shell = search(shell, path, X_OK, (int *) 0);
735 if (!shell || !*shell)
736 shell = EXECSHELL;
737
738 *tp->args-- = tp->str;
739 #ifdef SHARPBANG
740 {
741 char buf[LINE];
742 register char *cp;
743 register int fd, n;
744
745 buf[0] = '\0';
746 if ((fd = open(tp->str, O_RDONLY)) >= 0) {
747 if ((n = read(fd, buf, LINE - 1)) > 0)
748 buf[n] = '\0';
749 (void) close(fd);
750 }
751 if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))
752 # ifdef OS2
753 || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7])
754 && (cp = &buf[7]))
755 # endif /* OS2 */
756 )
757 {
758 while (*cp && (*cp == ' ' || *cp == '\t'))
759 cp++;
760 if (*cp && *cp != '\n') {
761 char *a0 = cp, *a1 = (char *) 0;
762 # ifdef OS2
763 char *a2 = cp;
764 # endif /* OS2 */
765
766 while (*cp && *cp != '\n' && *cp != ' '
767 && *cp != '\t')
768 {
769 # ifdef OS2
770 /* Allow shell search without prepended path
771 * if shell with / in pathname cannot be found.
772 * Use / explicitly so \ can be used if explicit
773 * needs to be forced.
774 */
775 if (*cp == '/')
776 a2 = cp + 1;
777 # endif /* OS2 */
778 cp++;
779 }
780 if (*cp && *cp != '\n') {
781 *cp++ = '\0';
782 while (*cp
783 && (*cp == ' ' || *cp == '\t'))
784 cp++;
785 if (*cp && *cp != '\n') {
786 a1 = cp;
787 /* all one argument */
788 while (*cp && *cp != '\n')
789 cp++;
790 }
791 }
792 if (*cp == '\n') {
793 *cp = '\0';
794 if (a1)
795 *tp->args-- = a1;
796 # ifdef OS2
797 if (a0 != a2 && search_access(a0, X_OK, (int *) 0))
798 a0 = a2;
799 # endif /* OS2 */
800 shell = a0;
801 }
802 }
803 # ifdef OS2
804 } else {
805 /* Use ksh documented shell default if present
806 * else use OS2_SHELL which is assumed to need
807 * the /c option and '\' as dir separater.
808 */
809 char *p = shell;
810
811 shell = str_val(global("EXECSHELL"));
812 if (shell && *shell)
813 shell = search(shell, path, X_OK, (int *) 0);
814 if (!shell || !*shell) {
815 shell = p;
816 *tp->args-- = "/c";
817 for (p = tp->str; *p; p++)
818 if (*p == '/')
819 *p = '\\';
820 }
821 # endif /* OS2 */
822 }
823 }
824 #endif /* SHARPBANG */
825 *tp->args = shell;
826
827 ksh_execve(tp->args[0], tp->args, ap);
828
829 /* report both the program that was run and the bogus shell */
830 errorf("%s: %s: %s", tp->str, shell, strerror(errno));
831 }
832
833 int
834 shcomexec(wp)
835 register char **wp;
836 {
837 register struct tbl *tp;
838
839 tp = tsearch(&builtins, *wp, hash(*wp));
840 if (tp == NULL)
841 internal_errorf(1, "shcomexec: %s", *wp);
842 return call_builtin(tp, wp);
843 }
844
845 /*
846 * Search function tables for a function. If create set, a table entry
847 * is created if none is found.
848 */
849 struct tbl *
850 findfunc(name, h, create)
851 const char *name;
852 unsigned int h;
853 int create;
854 {
855 struct block *l;
856 struct tbl *tp = (struct tbl *) 0;
857
858 for (l = e->loc; l; l = l->next) {
859 tp = tsearch(&l->funs, name, h);
860 if (tp)
861 break;
862 if (!l->next && create) {
863 tp = tenter(&l->funs, name, h);
864 tp->flag = DEFINED;
865 tp->type = CFUNC;
866 tp->val.t = (struct op *) 0;
867 break;
868 }
869 }
870 return tp;
871 }
872
873 /*
874 * define function. Returns 1 if function is being undefined (t == 0) and
875 * function did not exist, returns 0 otherwise.
876 */
877 int
878 define(name, t)
879 const char *name;
880 struct op *t;
881 {
882 struct tbl *tp;
883 int was_set = 0;
884
885 while (1) {
886 tp = findfunc(name, hash(name), TRUE);
887
888 if (tp->flag & ISSET)
889 was_set = 1;
890 /* If this function is currently being executed, we zap this
891 * table entry so findfunc() won't see it
892 */
893 if (tp->flag & FINUSE) {
894 tp->name[0] = '\0';
895 tp->flag &= ~DEFINED; /* ensure it won't be found */
896 tp->flag |= FDELETE;
897 } else
898 break;
899 }
900
901 if (tp->flag & ALLOC) {
902 tp->flag &= ~(ISSET|ALLOC);
903 tfree(tp->val.t, tp->areap);
904 }
905
906 if (t == NULL) { /* undefine */
907 tdelete(tp);
908 return was_set ? 0 : 1;
909 }
910
911 tp->val.t = tcopy(t->left, tp->areap);
912 tp->flag |= (ISSET|ALLOC);
913 if (t->u.ksh_func)
914 tp->flag |= FKSH;
915
916 return 0;
917 }
918
919 /*
920 * add builtin
921 */
922 void
923 builtin(name, func)
924 const char *name;
925 int (*func) ARGS((char **));
926 {
927 register struct tbl *tp;
928 Tflag flag;
929
930 /* see if any flags should be set for this builtin */
931 for (flag = 0; ; name++) {
932 if (*name == '=') /* command does variable assignment */
933 flag |= KEEPASN;
934 else if (*name == '*') /* POSIX special builtin */
935 flag |= SPEC_BI;
936 else if (*name == '+') /* POSIX regular builtin */
937 flag |= REG_BI;
938 else
939 break;
940 }
941
942 tp = tenter(&builtins, name, hash(name));
943 tp->flag = DEFINED | flag;
944 tp->type = CSHELL;
945 tp->val.f = func;
946 }
947
948 /*
949 * find command
950 * either function, hashed command, or built-in (in that order)
951 */
952 struct tbl *
953 findcom(name, flags)
954 const char *name;
955 int flags; /* FC_* */
956 {
957 static struct tbl temp;
958 unsigned int h = hash(name);
959 struct tbl *tp = NULL, *tbi;
960 int insert = Flag(FTRACKALL); /* insert if not found */
961 char *fpath; /* for function autoloading */
962 char *npath;
963
964 if (ksh_strchr_dirsep(name) != NULL) {
965 insert = 0;
966 /* prevent FPATH search below */
967 flags &= ~FC_FUNC;
968 goto Search;
969 }
970 tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL;
971 /* POSIX says special builtins first, then functions, then
972 * POSIX regular builtins, then search path...
973 */
974 if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
975 tp = tbi;
976 if (!tp && (flags & FC_FUNC)) {
977 tp = findfunc(name, h, FALSE);
978 if (tp && !(tp->flag & ISSET)) {
979 if ((fpath = str_val(global("FPATH"))) == null) {
980 tp->u.fpath = (char *) 0;
981 tp->u2.errno_ = 0;
982 } else
983 tp->u.fpath = search(name, fpath, R_OK,
984 &tp->u2.errno_);
985 }
986 }
987 if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
988 tp = tbi;
989 /* todo: posix says non-special/non-regular builtins must
990 * be triggered by some user-controllable means like a
991 * special directory in PATH. Requires modifications to
992 * the search() function. Tracked aliases should be
993 * modified to allow tracking of builtin commands.
994 * This should be under control of the FPOSIX flag.
995 * If this is changed, also change c_whence...
996 */
997 if (!tp && (flags & FC_UNREGBI) && tbi)
998 tp = tbi;
999 if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
1000 tp = tsearch(&taliases, name, h);
1001 if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) {
1002 if (tp->flag & ALLOC) {
1003 tp->flag &= ~ALLOC;
1004 afree(tp->val.s, APERM);
1005 }
1006 tp->flag &= ~ISSET;
1007 }
1008 }
1009
1010 Search:
1011 if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET)))
1012 && (flags & FC_PATH))
1013 {
1014 if (!tp) {
1015 if (insert && !(flags & FC_DEFPATH)) {
1016 tp = tenter(&taliases, name, h);
1017 tp->type = CTALIAS;
1018 } else {
1019 tp = &temp;
1020 tp->type = CEXEC;
1021 }
1022 tp->flag = DEFINED; /* make ~ISSET */
1023 }
1024 npath = search(name, flags & FC_DEFPATH ? def_path : path,
1025 X_OK, &tp->u2.errno_);
1026 if (npath) {
1027 tp->val.s = tp == &temp ? npath : str_save(npath, APERM);
1028 tp->flag |= ISSET|ALLOC;
1029 } else if ((flags & FC_FUNC)
1030 && (fpath = str_val(global("FPATH"))) != null
1031 && (npath = search(name, fpath, R_OK,
1032 &tp->u2.errno_)) != (char *) 0)
1033 {
1034 /* An undocumented feature of at&t ksh is that it
1035 * searches FPATH if a command is not found, even
1036 * if the command hasn't been set up as an autoloaded
1037 * function (ie, no typeset -uf).
1038 */
1039 tp = &temp;
1040 tp->type = CFUNC;
1041 tp->flag = DEFINED; /* make ~ISSET */
1042 tp->u.fpath = npath;
1043 }
1044 }
1045 return tp;
1046 }
1047
1048 /*
1049 * flush executable commands with relative paths
1050 */
1051 void
1052 flushcom(all)
1053 int all; /* just relative or all */
1054 {
1055 struct tbl *tp;
1056 struct tstate ts;
1057
1058 for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; )
1059 if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) {
1060 if (tp->flag&ALLOC) {
1061 tp->flag &= ~(ALLOC|ISSET);
1062 afree(tp->val.s, APERM);
1063 }
1064 tp->flag = ~ISSET;
1065 }
1066 }
1067
1068 /* Check if path is something we want to find. Returns -1 for failure. */
1069 int
1070 search_access(path, mode, errnop)
1071 const char *path;
1072 int mode;
1073 int *errnop; /* set if candidate found, but not suitable */
1074 {
1075 #ifndef OS2
1076 int ret, err = 0;
1077 struct stat statb;
1078
1079 if (stat(path, &statb) < 0)
1080 return -1;
1081 ret = eaccess(path, mode);
1082 if (ret < 0)
1083 err = errno; /* File exists, but we can't access it */
1084 else if (mode == X_OK && (!S_ISREG(statb.st_mode)
1085 /* This 'cause access() says root can execute everything */
1086 || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
1087 {
1088 ret = -1;
1089 err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
1090 }
1091 if (err && errnop)
1092 *errnop = err;
1093 return ret;
1094 #else /* !OS2 */
1095 /*
1096 * NOTE: ASSUMES path can be modified and has enough room at the
1097 * end of the string for a suffix (ie, 4 extra characters).
1098 * Certain code knows this (eg, eval.c(globit()),
1099 * exec.c(search())).
1100 */
1101 static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",
1102 ".com", ".bat", (char *) 0
1103 };
1104 static char *rsuffixes[] = { ".ksh", ".", ".sh", ".cmd", ".bat",
1105 (char *) 0
1106 };
1107 int i;
1108 char *mpath = (char *) path;
1109 char *tp = mpath + strlen(mpath);
1110 char *p;
1111 char **sfx;
1112
1113 /* If a suffix has been specified, check if it is one of the
1114 * suffixes that indicate the file is executable - if so, change
1115 * the access test to R_OK...
1116 * This code assumes OS/2 files can have only one suffix...
1117 */
1118 if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) {
1119 if (mode == X_OK)
1120 mode = R_OK;
1121 return search_access1(mpath, mode, errnop);
1122 }
1123 /* Try appending the various suffixes. Different suffixes for
1124 * read and execute 'cause we don't want to read an executable...
1125 */
1126 sfx = mode == R_OK ? rsuffixes : xsuffixes;
1127 for (i = 0; sfx[i]; i++) {
1128 strcpy(tp, p = sfx[i]);
1129 if (search_access1(mpath, R_OK, errnop) == 0)
1130 return 0;
1131 *tp = '\0';
1132 }
1133 return -1;
1134 #endif /* !OS2 */
1135 }
1136
1137 #ifdef OS2
1138 static int
1139 search_access1(path, mode, errnop)
1140 const char *path;
1141 int mode;
1142 int *errnop; /* set if candidate found, but not suitable */
1143 {
1144 int ret, err = 0;
1145 struct stat statb;
1146
1147 if (stat(path, &statb) < 0)
1148 return -1;
1149 ret = eaccess(path, mode);
1150 if (ret < 0)
1151 err = errno; /* File exists, but we can't access it */
1152 else if (!S_ISREG(statb.st_mode)) {
1153 ret = -1;
1154 err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
1155 }
1156 if (err && errnop)
1157 *errnop = err;
1158 return ret;
1159 }
1160 #endif /* OS2 */
1161
1162 /*
1163 * search for command with PATH
1164 */
1165 char *
1166 search(name, path, mode, errnop)
1167 const char *name;
1168 const char *path;
1169 int mode; /* R_OK or X_OK */
1170 int *errnop; /* set if candidate found, but not suitable */
1171 {
1172 const char *sp, *p;
1173 char *xp;
1174 XString xs;
1175 int namelen;
1176
1177 if (errnop)
1178 *errnop = 0;
1179 #ifdef OS2
1180 /* Xinit() allocates 8 additional bytes, so appended suffixes won't
1181 * overflow the memory.
1182 */
1183 namelen = strlen(name) + 1;
1184 Xinit(xs, xp, namelen, ATEMP);
1185 memcpy(Xstring(xs, xp), name, namelen);
1186
1187 if (ksh_strchr_dirsep(name)) {
1188 if (search_access(Xstring(xs, xp), mode, errnop) >= 0)
1189 return Xstring(xs, xp); /* not Xclose() - see above */
1190 Xfree(xs, xp);
1191 return NULL;
1192 }
1193
1194 /* Look in current context always. (os2 style) */
1195 if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1196 return Xstring(xs, xp); /* not Xclose() - xp may be wrong */
1197 #else /* OS2 */
1198 if (ksh_strchr_dirsep(name)) {
1199 if (search_access(name, mode, errnop) == 0)
1200 return (char *) name;
1201 return NULL;
1202 }
1203
1204 namelen = strlen(name) + 1;
1205 Xinit(xs, xp, 128, ATEMP);
1206 #endif /* OS2 */
1207
1208 sp = path;
1209 while (sp != NULL) {
1210 xp = Xstring(xs, xp);
1211 if (!(p = strchr(sp, PATHSEP)))
1212 p = sp + strlen(sp);
1213 if (p != sp) {
1214 XcheckN(xs, xp, p - sp);
1215 memcpy(xp, sp, p - sp);
1216 xp += p - sp;
1217 *xp++ = DIRSEP;
1218 }
1219 sp = p;
1220 XcheckN(xs, xp, namelen);
1221 memcpy(xp, name, namelen);
1222 if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1223 #ifdef OS2
1224 return Xstring(xs, xp); /* Not Xclose() - see above */
1225 #else /* OS2 */
1226 return Xclose(xs, xp + namelen);
1227 #endif /* OS2 */
1228 if (*sp++ == '\0')
1229 sp = NULL;
1230 }
1231 Xfree(xs, xp);
1232 return NULL;
1233 }
1234
1235 static int
1236 call_builtin(tp, wp)
1237 struct tbl *tp;
1238 char **wp;
1239 {
1240 int rv;
1241
1242 builtin_argv0 = wp[0];
1243 builtin_flag = tp->flag;
1244 shf_reopen(1, SHF_WR, shl_stdout);
1245 shl_stdout_ok = 1;
1246 ksh_getopt_reset(&builtin_opt, GF_ERROR);
1247 rv = (*tp->val.f)(wp);
1248 shf_flush(shl_stdout);
1249 shl_stdout_ok = 0;
1250 builtin_flag = 0;
1251 builtin_argv0 = (char *) 0;
1252 return rv;
1253 }
1254
1255 /*
1256 * set up redirection, saving old fd's in e->savefd
1257 */
1258 static int
1259 iosetup(iop, tp)
1260 register struct ioword *iop;
1261 struct tbl *tp;
1262 {
1263 register int u = -1;
1264 char *cp = iop->name;
1265 int iotype = iop->flag & IOTYPE;
1266 int do_open = 1, do_close = 0, UNINITIALIZED(flags);
1267 struct ioword iotmp;
1268 struct stat statb;
1269
1270 if (iotype != IOHERE)
1271 cp = evalonestr(cp, DOTILDE|(Flag(FTALKING) ? DOGLOB : 0));
1272
1273 /* Used for tracing and error messages to print expanded cp */
1274 iotmp = *iop;
1275 iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp;
1276 iotmp.flag |= IONAMEXP;
1277
1278 if (Flag(FXTRACE))
1279 shellf("%s%s\n",
1280 PS4_SUBSTITUTE(str_val(global("PS4"))),
1281 snptreef((char *) 0, 32, "%R", &iotmp));
1282
1283 switch (iotype) {
1284 case IOREAD:
1285 flags = O_RDONLY;
1286 break;
1287
1288 case IOCAT:
1289 flags = O_WRONLY | O_APPEND | O_CREAT;
1290 break;
1291
1292 case IOWRITE:
1293 flags = O_WRONLY | O_CREAT | O_TRUNC;
1294 if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB)
1295 && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
1296 flags |= O_EXCL;
1297 break;
1298
1299 case IORDWR:
1300 flags = O_RDWR | O_CREAT;
1301 break;
1302
1303 case IOHERE:
1304 do_open = 0;
1305 /* herein() returns -2 if error has been printed */
1306 u = herein(cp, iop->flag & IOEVAL);
1307 /* cp may have wrong name */
1308 break;
1309
1310 case IODUP:
1311 {
1312 const char *emsg;
1313
1314 do_open = 0;
1315 if (*cp == '-' && !cp[1]) {
1316 u = 1009; /* prevent error return below */
1317 do_close = 1;
1318 } else if ((u = check_fd(cp,
1319 X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
1320 &emsg)) < 0)
1321 {
1322 warningf(TRUE, "%s: %s",
1323 snptreef((char *) 0, 32, "%R", &iotmp), emsg);
1324 return -1;
1325 }
1326 break;
1327 }
1328 }
1329 if (do_open) {
1330 if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
1331 warningf(TRUE, "%s: restricted", cp);
1332 return -1;
1333 }
1334 u = open(cp, flags, 0666);
1335 #ifdef OS2
1336 if (u < 0 && strcmp(cp, "/dev/null") == 0)
1337 u = open("nul", flags, 0666);
1338 #endif /* OS2 */
1339 }
1340 if (u < 0) {
1341 /* herein() may already have printed message */
1342 if (u == -1)
1343 warningf(TRUE, "cannot %s %s: %s",
1344 iotype == IODUP ? "dup"
1345 : (iotype == IOREAD || iotype == IOHERE) ?
1346 "open" : "create", cp, strerror(errno));
1347 return -1;
1348 }
1349 /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
1350 if (e->savefd[iop->unit] == 0)
1351 /* c_exec() assumes e->savefd[fd] set for any redirections.
1352 * Ask savefd() not to close iop->unit - allows error messages
1353 * to be seen if iop->unit is 2; also means we can't lose
1354 * the fd (eg, both dup2 below and dup2 in restfd() failing).
1355 */
1356 e->savefd[iop->unit] = savefd(iop->unit, 1);
1357
1358 if (do_close)
1359 close(iop->unit);
1360 else if (u != iop->unit) {
1361 if (ksh_dup2(u, iop->unit, TRUE) < 0) {
1362 warningf(TRUE,
1363 "could not finish (dup) redirection %s: %s",
1364 snptreef((char *) 0, 32, "%R", &iotmp),
1365 strerror(errno));
1366 if (iotype != IODUP)
1367 close(u);
1368 return -1;
1369 }
1370 if (iotype != IODUP)
1371 close(u);
1372 #ifdef KSH
1373 /* Touching any co-process fd in an empty exec
1374 * causes the shell to close its copies
1375 */
1376 else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1377 if (iop->flag & IORDUP) /* possible exec <&p */
1378 coproc_read_close(u);
1379 else /* possible exec >&p */
1380 coproc_write_close(u);
1381 }
1382 #endif /* KSH */
1383 }
1384 if (u == 2) /* Clear any write errors */
1385 shf_reopen(2, SHF_WR, shl_out);
1386 return 0;
1387 }
1388
1389 /*
1390 * open here document temp file.
1391 * if unquoted here, expand here temp file into second temp file.
1392 */
1393 static int
1394 herein(hname, sub)
1395 char *hname;
1396 int sub;
1397 {
1398 int fd;
1399
1400 /* ksh -c 'cat << EOF' can cause this... */
1401 if (hname == (char *) 0) {
1402 warningf(TRUE, "here document missing");
1403 return -2; /* special to iosetup(): don't print error */
1404 }
1405 if (sub) {
1406 char *cp;
1407 struct source *s, *volatile osource = source;
1408 struct temp *h;
1409 struct shf *volatile shf;
1410 int i;
1411
1412 /* must be before newenv() 'cause shf uses ATEMP */
1413 shf = shf_open(hname, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
1414 if (shf == NULL)
1415 return -1;
1416 newenv(E_ERRH);
1417 i = ksh_sigsetjmp(e->jbuf, 0);
1418 if (i) {
1419 if (shf)
1420 shf_close(shf);
1421 source = osource;
1422 quitenv(); /* after shf_close() due to alloc */
1423 return -2; /* special to iosetup(): don't print error */
1424 }
1425 /* set up yylex input from here file */
1426 s = pushs(SFILE, ATEMP);
1427 s->u.shf = shf;
1428 source = s;
1429 if (yylex(ONEWORD) != LWORD)
1430 internal_errorf(1, "herein: yylex");
1431 shf_close(shf);
1432 shf = (struct shf *) 0;
1433 cp = evalstr(yylval.cp, 0);
1434
1435 /* write expanded input to another temp file */
1436 h = maketemp(ATEMP);
1437 h->next = e->temps; e->temps = h;
1438 if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0)
1439 /* shf closeed by error handler */
1440 errorf("%s: %s", h->name, strerror(errno));
1441 shf_puts(cp, shf);
1442 if (shf_close(shf) == EOF) {
1443 close(fd);
1444 shf = (struct shf *) 0;
1445 errorf("error writing %s: %s", h->name,
1446 strerror(errno));
1447 }
1448 shf = (struct shf *) 0;
1449
1450 quitenv();
1451 } else {
1452 fd = open(hname, O_RDONLY, 0);
1453 if (fd < 0)
1454 return -1;
1455 }
1456
1457 return fd;
1458 }
1459
1460 #ifdef KSH
1461 /*
1462 * ksh special - the select command processing section
1463 * print the args in column form - assuming that we can
1464 */
1465 static char *
1466 do_selectargs(ap, print_menu)
1467 register char **ap;
1468 bool_t print_menu;
1469 {
1470 static const char *const read_args[] = {
1471 "read", "-r", "REPLY", (char *) 0
1472 };
1473 char *s;
1474 int i, argct;
1475
1476 for (argct = 0; ap[argct]; argct++)
1477 ;
1478 while (1) {
1479 /* Menu is printed if
1480 * - this is the first time around the select loop
1481 * - the user enters a blank line
1482 * - the REPLY parameter is empty
1483 */
1484 if (print_menu || !*str_val(global("REPLY")))
1485 pr_menu(ap);
1486 shellf("%s", str_val(global("PS3")));
1487 if (call_builtin(findcom("read", FC_BI), (char **) read_args))
1488 return (char *) 0;
1489 s = str_val(global("REPLY"));
1490 if (*s) {
1491 i = atoi(s);
1492 return (i >= 1 && i <= argct) ? ap[i - 1] : null;
1493 }
1494 print_menu = 1;
1495 }
1496 }
1497
1498 struct select_menu_info {
1499 char *const *args;
1500 int arg_width;
1501 int num_width;
1502 } info;
1503
1504 static char *select_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
1505
1506 /* format a single select menu item */
1507 static char *
1508 select_fmt_entry(arg, i, buf, buflen)
1509 void *arg;
1510 int i;
1511 char *buf;
1512 int buflen;
1513 {
1514 struct select_menu_info *smi = (struct select_menu_info *) arg;
1515
1516 shf_snprintf(buf, buflen, "%*d) %s",
1517 smi->num_width, i + 1, smi->args[i]);
1518 return buf;
1519 }
1520
1521 /*
1522 * print a select style menu
1523 */
1524 int
1525 pr_menu(ap)
1526 char *const *ap;
1527 {
1528 struct select_menu_info smi;
1529 char *const *pp;
1530 int nwidth, dwidth;
1531 int i, n;
1532
1533 /* Width/column calculations were done once and saved, but this
1534 * means select can't be used recursively so we re-calculate each
1535 * time (could save in a structure that is returned, but its probably
1536 * not worth the bother).
1537 */
1538
1539 /*
1540 * get dimensions of the list
1541 */
1542 for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1543 i = strlen(*pp);
1544 nwidth = (i > nwidth) ? i : nwidth;
1545 }
1546 /*
1547 * we will print an index of the form
1548 * %d)
1549 * in front of each entry
1550 * get the max width of this
1551 */
1552 for (i = n, dwidth = 1; i >= 10; i /= 10)
1553 dwidth++;
1554
1555 smi.args = ap;
1556 smi.arg_width = nwidth;
1557 smi.num_width = dwidth;
1558 print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
1559 dwidth + nwidth + 2);
1560
1561 return n;
1562 }
1563 #endif /* KSH */
1564 #ifdef KSH
1565
1566 /*
1567 * [[ ... ]] evaluation routines
1568 */
1569
1570 extern const char *const dbtest_tokens[];
1571 extern const char db_close[];
1572
1573 /* Test if the current token is a whatever. Accepts the current token if
1574 * it is. Returns 0 if it is not, non-zero if it is (in the case of
1575 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
1576 */
1577 static int
1578 dbteste_isa(te, meta)
1579 Test_env *te;
1580 Test_meta meta;
1581 {
1582 int ret = 0;
1583 int uqword;
1584 char *p;
1585
1586 if (!*te->pos.wp)
1587 return meta == TM_END;
1588
1589 /* unquoted word? */
1590 for (p = *te->pos.wp; *p == CHAR; p += 2)
1591 ;
1592 uqword = *p == EOS;
1593
1594 if (meta == TM_UNOP || meta == TM_BINOP) {
1595 if (uqword) {
1596 char buf[8]; /* longer than the longest operator */
1597 char *q = buf;
1598 for (p = *te->pos.wp; *p == CHAR
1599 && q < &buf[sizeof(buf) - 1];
1600 p += 2)
1601 *q++ = p[1];
1602 *q = '\0';
1603 ret = (int) test_isop(te, meta, buf);
1604 }
1605 } else if (meta == TM_END)
1606 ret = 0;
1607 else
1608 ret = uqword
1609 && strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
1610
1611 /* Accept the token? */
1612 if (ret)
1613 te->pos.wp++;
1614
1615 return ret;
1616 }
1617
1618 static const char *
1619 dbteste_getopnd(te, op, do_eval)
1620 Test_env *te;
1621 Test_op op;
1622 int do_eval;
1623 {
1624 char *s = *te->pos.wp;
1625
1626 if (!s)
1627 return (char *) 0;
1628
1629 te->pos.wp++;
1630
1631 if (!do_eval)
1632 return null;
1633
1634 if (op == TO_STEQL || op == TO_STNEQ)
1635 s = evalstr(s, DOTILDE | DOPAT);
1636 else
1637 s = evalstr(s, DOTILDE);
1638
1639 return s;
1640 }
1641
1642 static int
1643 dbteste_eval(te, op, opnd1, opnd2, do_eval)
1644 Test_env *te;
1645 Test_op op;
1646 const char *opnd1;
1647 const char *opnd2;
1648 int do_eval;
1649 {
1650 return test_eval(te, op, opnd1, opnd2, do_eval);
1651 }
1652
1653 static void
1654 dbteste_error(te, offset, msg)
1655 Test_env *te;
1656 int offset;
1657 const char *msg;
1658 {
1659 te->flags |= TEF_ERROR;
1660 internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
1661 }
1662 #endif /* KSH */
1663