exec.c revision 1.1.1.3 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, int *errnop));
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 cleanup_proc_env();
419 ksh_execve(t->str, t->args, ap);
420 if (errno == ENOEXEC)
421 scriptexec(t, ap);
422 else
423 errorf("%s: %s", s, strerror(errno));
424 }
425 Break:
426 exstat = rv;
427
428 quitenv(); /* restores IO */
429 if ((flags&XEXEC))
430 exit(rv); /* exit child */
431 if (rv != 0 && !(flags & XERROK)) {
432 if (Flag(FERREXIT))
433 unwind(LERROR);
434 trapsig(SIGERR_);
435 }
436 return rv;
437 }
438
439 /*
440 * execute simple command
441 */
442
443 static int
444 comexec(t, tp, ap, flags)
445 struct op *t;
446 struct tbl *volatile tp;
447 register char **ap;
448 int volatile flags;
449 {
450 int i;
451 int rv = 0;
452 register char *cp;
453 register char **lastp;
454 static struct op texec; /* Must be static (XXX but why?) */
455 int type_flags;
456 int keepasn_ok;
457 int fcflags = FC_BI|FC_FUNC|FC_PATH;
458
459 /* snag the last argument for $_ XXX not the same as at&t ksh,
460 * which only seems to set $_ after a newline (but not in
461 * functions/dot scripts, but in interactive and scipt) -
462 * perhaps save last arg here and set it in shell()?.
463 */
464 if (*(lastp = ap)) {
465 while (*++lastp)
466 ;
467 setstr(typeset("_", LOCAL, 0, 0, 0), *--lastp);
468 }
469
470 /* Deal with the shell builtins builtin, exec and command since
471 * they can be followed by other commands. This must be done before
472 * we know if we should create a local block, which must be done
473 * before we can do a path search (in case the assignments change
474 * PATH).
475 * Odd cases:
476 * FOO=bar exec > /dev/null FOO is kept but not exported
477 * FOO=bar exec foobar FOO is exported
478 * FOO=bar command exec > /dev/null FOO is neither kept nor exported
479 * FOO=bar command FOO is neither kept nor exported
480 * PATH=... foobar use new PATH in foobar search
481 */
482 keepasn_ok = 1;
483 while (tp && tp->type == CSHELL) {
484 fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
485 if (tp->val.f == c_builtin) {
486 if ((cp = *++ap) == NULL) {
487 tp = NULL;
488 break;
489 }
490 tp = findcom(cp, FC_BI);
491 if (tp == NULL)
492 errorf("builtin: %s: not a builtin", cp);
493 continue;
494 } else if (tp->val.f == c_exec) {
495 if (ap[1] == NULL)
496 break;
497 ap++;
498 flags |= XEXEC;
499 } else if (tp->val.f == c_command) {
500 int optc, saw_p = 0;
501
502 /* Ugly dealing with options in two places (here and
503 * in c_command(), but such is life)
504 */
505 ksh_getopt_reset(&builtin_opt, 0);
506 while ((optc = ksh_getopt(ap, &builtin_opt, ":p"))
507 == 'p')
508 saw_p = 1;
509 if (optc != EOF)
510 break; /* command -vV or something */
511 /* don't look for functions */
512 fcflags = FC_BI|FC_PATH;
513 if (saw_p) {
514 if (Flag(FRESTRICTED)) {
515 warningf(TRUE,
516 "command -p: restricted");
517 rv = 1;
518 goto Leave;
519 }
520 fcflags |= FC_DEFPATH;
521 }
522 ap += builtin_opt.optind;
523 /* POSIX says special builtins lose their status
524 * if accessed using command.
525 */
526 keepasn_ok = 0;
527 if (!ap[0]) {
528 /* ensure command with no args exits with 0 */
529 subst_exstat = 0;
530 break;
531 }
532 } else
533 break;
534 tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
535 }
536 if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
537 type_flags = 0;
538 else {
539 /* create new variable/function block */
540 newblock();
541 /* ksh functions don't keep assignments, POSIX functions do. */
542 if (keepasn_ok && tp && tp->type == CFUNC
543 && !(tp->flag & FKSH))
544 type_flags = 0;
545 else
546 type_flags = LOCAL|LOCAL_COPY|EXPORT;
547 }
548 if (Flag(FEXPORT))
549 type_flags |= EXPORT;
550 for (i = 0; t->vars[i]; i++) {
551 cp = evalstr(t->vars[i], DOASNTILDE);
552 if (Flag(FXTRACE)) {
553 if (i == 0)
554 shf_fprintf(shl_out, "%s",
555 PS4_SUBSTITUTE(str_val(global("PS4"))));
556 shf_fprintf(shl_out, "%s%s", cp,
557 t->vars[i + 1] ? space : newline);
558 if (!t->vars[i + 1])
559 shf_flush(shl_out);
560 }
561 typeset(cp, type_flags, 0, 0, 0);
562 }
563
564 if ((cp = *ap) == NULL) {
565 rv = subst_exstat;
566 goto Leave;
567 } else if (!tp) {
568 if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {
569 warningf(TRUE, "%s: restricted", cp);
570 rv = 1;
571 goto Leave;
572 }
573 tp = findcom(cp, fcflags);
574 }
575
576 switch (tp->type) {
577 case CSHELL: /* shell built-in */
578 rv = call_builtin(tp, ap);
579 break;
580
581 case CFUNC: /* function call */
582 {
583 volatile int old_xflag;
584 volatile Tflag old_inuse;
585 const char *volatile old_kshname;
586
587 if (!(tp->flag & ISSET)) {
588 struct tbl *ftp;
589
590 if (!tp->u.fpath) {
591 if (tp->u2.errno_) {
592 warningf(TRUE,
593 "%s: can't find function definition file - %s",
594 cp, strerror(tp->u2.errno_));
595 rv = 126;
596 } else {
597 warningf(TRUE,
598 "%s: can't find function definition file", cp);
599 rv = 127;
600 }
601 break;
602 }
603 if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
604 warningf(TRUE,
605 "%s: can't open function definition file %s - %s",
606 cp, tp->u.fpath, strerror(errno));
607 rv = 127;
608 break;
609 }
610 if (!(ftp = findfunc(cp, hash(cp), FALSE))
611 || !(ftp->flag & ISSET))
612 {
613 warningf(TRUE,
614 "%s: function not defined by %s",
615 cp, tp->u.fpath);
616 rv = 127;
617 break;
618 }
619 tp = ftp;
620 }
621
622 /* ksh functions set $0 to function name, POSIX functions leave
623 * $0 unchanged.
624 */
625 old_kshname = kshname;
626 if (tp->flag & FKSH)
627 kshname = ap[0];
628 e->loc->argv = ap;
629 for (i = 0; *ap++ != NULL; i++)
630 ;
631 e->loc->argc = i - 1;
632 getopts_reset(1);
633
634 old_xflag = Flag(FXTRACE);
635 Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE;
636
637 old_inuse = tp->flag & FINUSE;
638 tp->flag |= FINUSE;
639
640 e->type = E_FUNC;
641 i = ksh_sigsetjmp(e->jbuf, 0);
642 if (i == 0) {
643 /* seems odd to pass XERROK here, but at&t ksh does */
644 exstat = execute(tp->val.t, flags & XERROK);
645 i = LRETURN;
646 }
647 kshname = old_kshname;
648 Flag(FXTRACE) = old_xflag;
649 tp->flag = (tp->flag & ~FINUSE) | old_inuse;
650 /* Were we deleted while executing? If so, free the execution
651 * tree. todo: Unfortunately, the table entry is never re-used
652 * until the lookup table is expanded.
653 */
654 if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
655 if (tp->flag & ALLOC) {
656 tp->flag &= ~ALLOC;
657 tfree(tp->val.t, tp->areap);
658 }
659 tp->flag = 0;
660 }
661 switch (i) {
662 case LRETURN:
663 case LERROR:
664 rv = exstat;
665 break;
666 case LINTR:
667 case LEXIT:
668 case LLEAVE:
669 case LSHELL:
670 quitenv();
671 unwind(i);
672 /*NOTREACHED*/
673 default:
674 quitenv();
675 internal_errorf(1, "CFUNC %d", i);
676 }
677 break;
678 }
679
680 case CEXEC: /* executable command */
681 case CTALIAS: /* tracked alias */
682 if (!(tp->flag&ISSET)) {
683 /* errno_ will be set if the named command was found
684 * but could not be executed (permissions, no execute
685 * bit, directory, etc). Print out a (hopefully)
686 * useful error message and set the exit status to 126.
687 */
688 if (tp->u2.errno_) {
689 warningf(TRUE, "%s: cannot execute - %s", cp,
690 strerror(tp->u2.errno_));
691 rv = 126; /* POSIX */
692 } else {
693 warningf(TRUE, "%s: not found", cp);
694 rv = 127;
695 }
696 break;
697 }
698
699 /* set $_ to program's full path */
700 setstr(typeset("_", LOCAL|EXPORT, 0, 0, 0), tp->val.s);
701
702 if (flags&XEXEC) {
703 j_exit();
704 if (!(flags&XBGND) || Flag(FMONITOR)) {
705 setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
706 setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
707 }
708 }
709
710 /* to fork we set up a TEXEC node and call execute */
711 texec.type = TEXEC;
712 texec.left = t; /* for tprint */
713 texec.str = tp->val.s;
714 texec.args = ap;
715 rv = exchild(&texec, flags, -1);
716 break;
717 }
718 Leave:
719 if (flags & XEXEC) {
720 exstat = rv;
721 unwind(LLEAVE);
722 }
723 return rv;
724 }
725
726 static void
727 scriptexec(tp, ap)
728 register struct op *tp;
729 register char **ap;
730 {
731 char *shell;
732
733 shell = str_val(global(EXECSHELL_STR));
734 if (shell && *shell)
735 shell = search(shell, path, X_OK, (int *) 0);
736 if (!shell || !*shell)
737 shell = EXECSHELL;
738
739 *tp->args-- = tp->str;
740 #ifdef SHARPBANG
741 {
742 char buf[LINE];
743 register char *cp;
744 register int fd, n;
745
746 buf[0] = '\0';
747 if ((fd = open(tp->str, O_RDONLY)) >= 0) {
748 if ((n = read(fd, buf, LINE - 1)) > 0)
749 buf[n] = '\0';
750 (void) close(fd);
751 }
752 if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))
753 # ifdef OS2
754 || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7])
755 && (cp = &buf[7]))
756 # endif /* OS2 */
757 )
758 {
759 while (*cp && (*cp == ' ' || *cp == '\t'))
760 cp++;
761 if (*cp && *cp != '\n') {
762 char *a0 = cp, *a1 = (char *) 0;
763 # ifdef OS2
764 char *a2 = cp;
765 # endif /* OS2 */
766
767 while (*cp && *cp != '\n' && *cp != ' '
768 && *cp != '\t')
769 {
770 # ifdef OS2
771 /* Allow shell search without prepended path
772 * if shell with / in pathname cannot be found.
773 * Use / explicitly so \ can be used if explicit
774 * needs to be forced.
775 */
776 if (*cp == '/')
777 a2 = cp + 1;
778 # endif /* OS2 */
779 cp++;
780 }
781 if (*cp && *cp != '\n') {
782 *cp++ = '\0';
783 while (*cp
784 && (*cp == ' ' || *cp == '\t'))
785 cp++;
786 if (*cp && *cp != '\n') {
787 a1 = cp;
788 /* all one argument */
789 while (*cp && *cp != '\n')
790 cp++;
791 }
792 }
793 if (*cp == '\n') {
794 *cp = '\0';
795 if (a1)
796 *tp->args-- = a1;
797 # ifdef OS2
798 if (a0 != a2 && search_access(a0, X_OK, (int *) 0))
799 a0 = a2;
800 # endif /* OS2 */
801 shell = a0;
802 }
803 }
804 # ifdef OS2
805 } else {
806 /* Use ksh documented shell default if present
807 * else use OS2_SHELL which is assumed to need
808 * the /c option and '\' as dir separater.
809 */
810 char *p = shell;
811
812 shell = str_val(global("EXECSHELL"));
813 if (shell && *shell)
814 shell = search(shell, path, X_OK, (int *) 0);
815 if (!shell || !*shell) {
816 shell = p;
817 *tp->args-- = "/c";
818 for (p = tp->str; *p; p++)
819 if (*p == '/')
820 *p = '\\';
821 }
822 # endif /* OS2 */
823 }
824 }
825 #endif /* SHARPBANG */
826 *tp->args = shell;
827
828 ksh_execve(tp->args[0], tp->args, ap);
829
830 /* report both the program that was run and the bogus shell */
831 errorf("%s: %s: %s", tp->str, shell, strerror(errno));
832 }
833
834 int
835 shcomexec(wp)
836 register char **wp;
837 {
838 register struct tbl *tp;
839
840 tp = tsearch(&builtins, *wp, hash(*wp));
841 if (tp == NULL)
842 internal_errorf(1, "shcomexec: %s", *wp);
843 return call_builtin(tp, wp);
844 }
845
846 /*
847 * Search function tables for a function. If create set, a table entry
848 * is created if none is found.
849 */
850 struct tbl *
851 findfunc(name, h, create)
852 const char *name;
853 unsigned int h;
854 int create;
855 {
856 struct block *l;
857 struct tbl *tp = (struct tbl *) 0;
858
859 for (l = e->loc; l; l = l->next) {
860 tp = tsearch(&l->funs, name, h);
861 if (tp)
862 break;
863 if (!l->next && create) {
864 tp = tenter(&l->funs, name, h);
865 tp->flag = DEFINED;
866 tp->type = CFUNC;
867 tp->val.t = (struct op *) 0;
868 break;
869 }
870 }
871 return tp;
872 }
873
874 /*
875 * define function. Returns 1 if function is being undefined (t == 0) and
876 * function did not exist, returns 0 otherwise.
877 */
878 int
879 define(name, t)
880 const char *name;
881 struct op *t;
882 {
883 struct tbl *tp;
884 int was_set = 0;
885
886 while (1) {
887 tp = findfunc(name, hash(name), TRUE);
888
889 if (tp->flag & ISSET)
890 was_set = 1;
891 /* If this function is currently being executed, we zap this
892 * table entry so findfunc() won't see it
893 */
894 if (tp->flag & FINUSE) {
895 tp->name[0] = '\0';
896 tp->flag &= ~DEFINED; /* ensure it won't be found */
897 tp->flag |= FDELETE;
898 } else
899 break;
900 }
901
902 if (tp->flag & ALLOC) {
903 tp->flag &= ~(ISSET|ALLOC);
904 tfree(tp->val.t, tp->areap);
905 }
906
907 if (t == NULL) { /* undefine */
908 tdelete(tp);
909 return was_set ? 0 : 1;
910 }
911
912 tp->val.t = tcopy(t->left, tp->areap);
913 tp->flag |= (ISSET|ALLOC);
914 if (t->u.ksh_func)
915 tp->flag |= FKSH;
916
917 return 0;
918 }
919
920 /*
921 * add builtin
922 */
923 void
924 builtin(name, func)
925 const char *name;
926 int (*func) ARGS((char **));
927 {
928 register struct tbl *tp;
929 Tflag flag;
930
931 /* see if any flags should be set for this builtin */
932 for (flag = 0; ; name++) {
933 if (*name == '=') /* command does variable assignment */
934 flag |= KEEPASN;
935 else if (*name == '*') /* POSIX special builtin */
936 flag |= SPEC_BI;
937 else if (*name == '+') /* POSIX regular builtin */
938 flag |= REG_BI;
939 else
940 break;
941 }
942
943 tp = tenter(&builtins, name, hash(name));
944 tp->flag = DEFINED | flag;
945 tp->type = CSHELL;
946 tp->val.f = func;
947 }
948
949 /*
950 * find command
951 * either function, hashed command, or built-in (in that order)
952 */
953 struct tbl *
954 findcom(name, flags)
955 const char *name;
956 int flags; /* FC_* */
957 {
958 static struct tbl temp;
959 unsigned int h = hash(name);
960 struct tbl *tp = NULL, *tbi;
961 int insert = Flag(FTRACKALL); /* insert if not found */
962 char *fpath; /* for function autoloading */
963 char *npath;
964
965 if (ksh_strchr_dirsep(name) != NULL) {
966 insert = 0;
967 /* prevent FPATH search below */
968 flags &= ~FC_FUNC;
969 goto Search;
970 }
971 tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL;
972 /* POSIX says special builtins first, then functions, then
973 * POSIX regular builtins, then search path...
974 */
975 if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
976 tp = tbi;
977 if (!tp && (flags & FC_FUNC)) {
978 tp = findfunc(name, h, FALSE);
979 if (tp && !(tp->flag & ISSET)) {
980 if ((fpath = str_val(global("FPATH"))) == null) {
981 tp->u.fpath = (char *) 0;
982 tp->u2.errno_ = 0;
983 } else
984 tp->u.fpath = search(name, fpath, R_OK,
985 &tp->u2.errno_);
986 }
987 }
988 if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
989 tp = tbi;
990 /* todo: posix says non-special/non-regular builtins must
991 * be triggered by some user-controllable means like a
992 * special directory in PATH. Requires modifications to
993 * the search() function. Tracked aliases should be
994 * modified to allow tracking of builtin commands.
995 * This should be under control of the FPOSIX flag.
996 * If this is changed, also change c_whence...
997 */
998 if (!tp && (flags & FC_UNREGBI) && tbi)
999 tp = tbi;
1000 if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
1001 tp = tsearch(&taliases, name, h);
1002 if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) {
1003 if (tp->flag & ALLOC) {
1004 tp->flag &= ~ALLOC;
1005 afree(tp->val.s, APERM);
1006 }
1007 tp->flag &= ~ISSET;
1008 }
1009 }
1010
1011 Search:
1012 if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET)))
1013 && (flags & FC_PATH))
1014 {
1015 if (!tp) {
1016 if (insert && !(flags & FC_DEFPATH)) {
1017 tp = tenter(&taliases, name, h);
1018 tp->type = CTALIAS;
1019 } else {
1020 tp = &temp;
1021 tp->type = CEXEC;
1022 }
1023 tp->flag = DEFINED; /* make ~ISSET */
1024 }
1025 npath = search(name, flags & FC_DEFPATH ? def_path : path,
1026 X_OK, &tp->u2.errno_);
1027 if (npath) {
1028 tp->val.s = tp == &temp ? npath : str_save(npath, APERM);
1029 tp->flag |= ISSET|ALLOC;
1030 } else if ((flags & FC_FUNC)
1031 && (fpath = str_val(global("FPATH"))) != null
1032 && (npath = search(name, fpath, R_OK,
1033 &tp->u2.errno_)) != (char *) 0)
1034 {
1035 /* An undocumented feature of at&t ksh is that it
1036 * searches FPATH if a command is not found, even
1037 * if the command hasn't been set up as an autoloaded
1038 * function (ie, no typeset -uf).
1039 */
1040 tp = &temp;
1041 tp->type = CFUNC;
1042 tp->flag = DEFINED; /* make ~ISSET */
1043 tp->u.fpath = npath;
1044 }
1045 }
1046 return tp;
1047 }
1048
1049 /*
1050 * flush executable commands with relative paths
1051 */
1052 void
1053 flushcom(all)
1054 int all; /* just relative or all */
1055 {
1056 struct tbl *tp;
1057 struct tstate ts;
1058
1059 for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; )
1060 if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) {
1061 if (tp->flag&ALLOC) {
1062 tp->flag &= ~(ALLOC|ISSET);
1063 afree(tp->val.s, APERM);
1064 }
1065 tp->flag = ~ISSET;
1066 }
1067 }
1068
1069 /* Check if path is something we want to find. Returns -1 for failure. */
1070 int
1071 search_access(path, mode, errnop)
1072 const char *path;
1073 int mode;
1074 int *errnop; /* set if candidate found, but not suitable */
1075 {
1076 #ifndef OS2
1077 int ret, err = 0;
1078 struct stat statb;
1079
1080 if (stat(path, &statb) < 0)
1081 return -1;
1082 ret = eaccess(path, mode);
1083 if (ret < 0)
1084 err = errno; /* File exists, but we can't access it */
1085 else if (mode == X_OK && (!S_ISREG(statb.st_mode)
1086 /* This 'cause access() says root can execute everything */
1087 || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
1088 {
1089 ret = -1;
1090 err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
1091 }
1092 if (err && errnop)
1093 *errnop = err;
1094 return ret;
1095 #else /* !OS2 */
1096 /*
1097 * NOTE: ASSUMES path can be modified and has enough room at the
1098 * end of the string for a suffix (ie, 4 extra characters).
1099 * Certain code knows this (eg, eval.c(globit()),
1100 * exec.c(search())).
1101 */
1102 static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",
1103 ".com", ".bat", (char *) 0
1104 };
1105 static char *rsuffixes[] = { ".ksh", ".", ".sh", ".cmd", ".bat",
1106 (char *) 0
1107 };
1108 int i;
1109 char *mpath = (char *) path;
1110 char *tp = mpath + strlen(mpath);
1111 char *p;
1112 char **sfx;
1113
1114 /* If a suffix has been specified, check if it is one of the
1115 * suffixes that indicate the file is executable - if so, change
1116 * the access test to R_OK...
1117 * This code assumes OS/2 files can have only one suffix...
1118 */
1119 if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) {
1120 if (mode == X_OK)
1121 mode = R_OK;
1122 return search_access1(mpath, mode, errnop);
1123 }
1124 /* Try appending the various suffixes. Different suffixes for
1125 * read and execute 'cause we don't want to read an executable...
1126 */
1127 sfx = mode == R_OK ? rsuffixes : xsuffixes;
1128 for (i = 0; sfx[i]; i++) {
1129 strcpy(tp, p = sfx[i]);
1130 if (search_access1(mpath, R_OK, errnop) == 0)
1131 return 0;
1132 *tp = '\0';
1133 }
1134 return -1;
1135 #endif /* !OS2 */
1136 }
1137
1138 #ifdef OS2
1139 static int
1140 search_access1(path, mode, errnop)
1141 const char *path;
1142 int mode;
1143 int *errnop; /* set if candidate found, but not suitable */
1144 {
1145 int ret, err = 0;
1146 struct stat statb;
1147
1148 if (stat(path, &statb) < 0)
1149 return -1;
1150 ret = eaccess(path, mode);
1151 if (ret < 0)
1152 err = errno; /* File exists, but we can't access it */
1153 else if (!S_ISREG(statb.st_mode)) {
1154 ret = -1;
1155 err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
1156 }
1157 if (err && errnop)
1158 *errnop = err;
1159 return ret;
1160 }
1161 #endif /* OS2 */
1162
1163 /*
1164 * search for command with PATH
1165 */
1166 char *
1167 search(name, path, mode, errnop)
1168 const char *name;
1169 const char *path;
1170 int mode; /* R_OK or X_OK */
1171 int *errnop; /* set if candidate found, but not suitable */
1172 {
1173 const char *sp, *p;
1174 char *xp;
1175 XString xs;
1176 int namelen;
1177
1178 if (errnop)
1179 *errnop = 0;
1180 #ifdef OS2
1181 /* Xinit() allocates 8 additional bytes, so appended suffixes won't
1182 * overflow the memory.
1183 */
1184 namelen = strlen(name) + 1;
1185 Xinit(xs, xp, namelen, ATEMP);
1186 memcpy(Xstring(xs, xp), name, namelen);
1187
1188 if (ksh_strchr_dirsep(name)) {
1189 if (search_access(Xstring(xs, xp), mode, errnop) >= 0)
1190 return Xstring(xs, xp); /* not Xclose() - see above */
1191 Xfree(xs, xp);
1192 return NULL;
1193 }
1194
1195 /* Look in current context always. (os2 style) */
1196 if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1197 return Xstring(xs, xp); /* not Xclose() - xp may be wrong */
1198 #else /* OS2 */
1199 if (ksh_strchr_dirsep(name)) {
1200 if (search_access(name, mode, errnop) == 0)
1201 return (char *) name;
1202 return NULL;
1203 }
1204
1205 namelen = strlen(name) + 1;
1206 Xinit(xs, xp, 128, ATEMP);
1207 #endif /* OS2 */
1208
1209 sp = path;
1210 while (sp != NULL) {
1211 xp = Xstring(xs, xp);
1212 if (!(p = strchr(sp, PATHSEP)))
1213 p = sp + strlen(sp);
1214 if (p != sp) {
1215 XcheckN(xs, xp, p - sp);
1216 memcpy(xp, sp, p - sp);
1217 xp += p - sp;
1218 *xp++ = DIRSEP;
1219 }
1220 sp = p;
1221 XcheckN(xs, xp, namelen);
1222 memcpy(xp, name, namelen);
1223 if (search_access(Xstring(xs, xp), mode, errnop) == 0)
1224 #ifdef OS2
1225 return Xstring(xs, xp); /* Not Xclose() - see above */
1226 #else /* OS2 */
1227 return Xclose(xs, xp + namelen);
1228 #endif /* OS2 */
1229 if (*sp++ == '\0')
1230 sp = NULL;
1231 }
1232 Xfree(xs, xp);
1233 return NULL;
1234 }
1235
1236 static int
1237 call_builtin(tp, wp)
1238 struct tbl *tp;
1239 char **wp;
1240 {
1241 int rv;
1242
1243 builtin_argv0 = wp[0];
1244 builtin_flag = tp->flag;
1245 shf_reopen(1, SHF_WR, shl_stdout);
1246 shl_stdout_ok = 1;
1247 ksh_getopt_reset(&builtin_opt, GF_ERROR);
1248 rv = (*tp->val.f)(wp);
1249 shf_flush(shl_stdout);
1250 shl_stdout_ok = 0;
1251 builtin_flag = 0;
1252 builtin_argv0 = (char *) 0;
1253 return rv;
1254 }
1255
1256 /*
1257 * set up redirection, saving old fd's in e->savefd
1258 */
1259 static int
1260 iosetup(iop, tp)
1261 register struct ioword *iop;
1262 struct tbl *tp;
1263 {
1264 register int u = -1;
1265 char *cp = iop->name;
1266 int iotype = iop->flag & IOTYPE;
1267 int do_open = 1, do_close = 0, UNINITIALIZED(flags);
1268 struct ioword iotmp;
1269 struct stat statb;
1270
1271 if (iotype != IOHERE)
1272 cp = evalonestr(cp, DOTILDE|(Flag(FTALKING) ? DOGLOB : 0));
1273
1274 /* Used for tracing and error messages to print expanded cp */
1275 iotmp = *iop;
1276 iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp;
1277 iotmp.flag |= IONAMEXP;
1278
1279 if (Flag(FXTRACE))
1280 shellf("%s%s\n",
1281 PS4_SUBSTITUTE(str_val(global("PS4"))),
1282 snptreef((char *) 0, 32, "%R", &iotmp));
1283
1284 switch (iotype) {
1285 case IOREAD:
1286 flags = O_RDONLY;
1287 break;
1288
1289 case IOCAT:
1290 flags = O_WRONLY | O_APPEND | O_CREAT;
1291 break;
1292
1293 case IOWRITE:
1294 flags = O_WRONLY | O_CREAT | O_TRUNC;
1295 if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB)
1296 && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
1297 flags |= O_EXCL;
1298 break;
1299
1300 case IORDWR:
1301 flags = O_RDWR | O_CREAT;
1302 break;
1303
1304 case IOHERE:
1305 do_open = 0;
1306 /* herein() returns -2 if error has been printed */
1307 u = herein(cp, iop->flag & IOEVAL);
1308 /* cp may have wrong name */
1309 break;
1310
1311 case IODUP:
1312 {
1313 const char *emsg;
1314
1315 do_open = 0;
1316 if (*cp == '-' && !cp[1]) {
1317 u = 1009; /* prevent error return below */
1318 do_close = 1;
1319 } else if ((u = check_fd(cp,
1320 X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
1321 &emsg)) < 0)
1322 {
1323 warningf(TRUE, "%s: %s",
1324 snptreef((char *) 0, 32, "%R", &iotmp), emsg);
1325 return -1;
1326 }
1327 break;
1328 }
1329 }
1330 if (do_open) {
1331 if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
1332 warningf(TRUE, "%s: restricted", cp);
1333 return -1;
1334 }
1335 u = open(cp, flags, 0666);
1336 #ifdef OS2
1337 if (u < 0 && strcmp(cp, "/dev/null") == 0)
1338 u = open("nul", flags, 0666);
1339 #endif /* OS2 */
1340 }
1341 if (u < 0) {
1342 /* herein() may already have printed message */
1343 if (u == -1)
1344 warningf(TRUE, "cannot %s %s: %s",
1345 iotype == IODUP ? "dup"
1346 : (iotype == IOREAD || iotype == IOHERE) ?
1347 "open" : "create", cp, strerror(errno));
1348 return -1;
1349 }
1350 /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
1351 if (e->savefd[iop->unit] == 0)
1352 /* c_exec() assumes e->savefd[fd] set for any redirections.
1353 * Ask savefd() not to close iop->unit - allows error messages
1354 * to be seen if iop->unit is 2; also means we can't lose
1355 * the fd (eg, both dup2 below and dup2 in restfd() failing).
1356 */
1357 e->savefd[iop->unit] = savefd(iop->unit, 1);
1358
1359 if (do_close)
1360 close(iop->unit);
1361 else if (u != iop->unit) {
1362 if (ksh_dup2(u, iop->unit, TRUE) < 0) {
1363 warningf(TRUE,
1364 "could not finish (dup) redirection %s: %s",
1365 snptreef((char *) 0, 32, "%R", &iotmp),
1366 strerror(errno));
1367 if (iotype != IODUP)
1368 close(u);
1369 return -1;
1370 }
1371 if (iotype != IODUP)
1372 close(u);
1373 #ifdef KSH
1374 /* Touching any co-process fd in an empty exec
1375 * causes the shell to close its copies
1376 */
1377 else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1378 if (iop->flag & IORDUP) /* possible exec <&p */
1379 coproc_read_close(u);
1380 else /* possible exec >&p */
1381 coproc_write_close(u);
1382 }
1383 #endif /* KSH */
1384 }
1385 if (u == 2) /* Clear any write errors */
1386 shf_reopen(2, SHF_WR, shl_out);
1387 return 0;
1388 }
1389
1390 /*
1391 * open here document temp file.
1392 * if unquoted here, expand here temp file into second temp file.
1393 */
1394 static int
1395 herein(hname, sub)
1396 char *hname;
1397 int sub;
1398 {
1399 int fd;
1400
1401 /* ksh -c 'cat << EOF' can cause this... */
1402 if (hname == (char *) 0) {
1403 warningf(TRUE, "here document missing");
1404 return -2; /* special to iosetup(): don't print error */
1405 }
1406 if (sub) {
1407 char *cp;
1408 struct source *s, *volatile osource = source;
1409 struct temp *h;
1410 struct shf *volatile shf;
1411 int i;
1412
1413 /* must be before newenv() 'cause shf uses ATEMP */
1414 shf = shf_open(hname, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
1415 if (shf == NULL)
1416 return -1;
1417 newenv(E_ERRH);
1418 i = ksh_sigsetjmp(e->jbuf, 0);
1419 if (i) {
1420 if (shf)
1421 shf_close(shf);
1422 source = osource;
1423 quitenv(); /* after shf_close() due to alloc */
1424 return -2; /* special to iosetup(): don't print error */
1425 }
1426 /* set up yylex input from here file */
1427 s = pushs(SFILE, ATEMP);
1428 s->u.shf = shf;
1429 source = s;
1430 if (yylex(ONEWORD) != LWORD)
1431 internal_errorf(1, "herein: yylex");
1432 shf_close(shf);
1433 shf = (struct shf *) 0;
1434 cp = evalstr(yylval.cp, 0);
1435
1436 /* write expanded input to another temp file */
1437 h = maketemp(ATEMP);
1438 h->next = e->temps; e->temps = h;
1439 if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0)
1440 /* shf closeed by error handler */
1441 errorf("%s: %s", h->name, strerror(errno));
1442 shf_puts(cp, shf);
1443 if (shf_close(shf) == EOF) {
1444 close(fd);
1445 shf = (struct shf *) 0;
1446 errorf("error writing %s: %s", h->name,
1447 strerror(errno));
1448 }
1449 shf = (struct shf *) 0;
1450
1451 quitenv();
1452 } else {
1453 fd = open(hname, O_RDONLY, 0);
1454 if (fd < 0)
1455 return -1;
1456 }
1457
1458 return fd;
1459 }
1460
1461 #ifdef KSH
1462 /*
1463 * ksh special - the select command processing section
1464 * print the args in column form - assuming that we can
1465 */
1466 static char *
1467 do_selectargs(ap, print_menu)
1468 register char **ap;
1469 bool_t print_menu;
1470 {
1471 static const char *const read_args[] = {
1472 "read", "-r", "REPLY", (char *) 0
1473 };
1474 char *s;
1475 int i, argct;
1476
1477 for (argct = 0; ap[argct]; argct++)
1478 ;
1479 while (1) {
1480 /* Menu is printed if
1481 * - this is the first time around the select loop
1482 * - the user enters a blank line
1483 * - the REPLY parameter is empty
1484 */
1485 if (print_menu || !*str_val(global("REPLY")))
1486 pr_menu(ap);
1487 shellf("%s", str_val(global("PS3")));
1488 if (call_builtin(findcom("read", FC_BI), (char **) read_args))
1489 return (char *) 0;
1490 s = str_val(global("REPLY"));
1491 if (*s) {
1492 i = atoi(s);
1493 return (i >= 1 && i <= argct) ? ap[i - 1] : null;
1494 }
1495 print_menu = 1;
1496 }
1497 }
1498
1499 struct select_menu_info {
1500 char *const *args;
1501 int arg_width;
1502 int num_width;
1503 } info;
1504
1505 static char *select_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
1506
1507 /* format a single select menu item */
1508 static char *
1509 select_fmt_entry(arg, i, buf, buflen)
1510 void *arg;
1511 int i;
1512 char *buf;
1513 int buflen;
1514 {
1515 struct select_menu_info *smi = (struct select_menu_info *) arg;
1516
1517 shf_snprintf(buf, buflen, "%*d) %s",
1518 smi->num_width, i + 1, smi->args[i]);
1519 return buf;
1520 }
1521
1522 /*
1523 * print a select style menu
1524 */
1525 int
1526 pr_menu(ap)
1527 char *const *ap;
1528 {
1529 struct select_menu_info smi;
1530 char *const *pp;
1531 int nwidth, dwidth;
1532 int i, n;
1533
1534 /* Width/column calculations were done once and saved, but this
1535 * means select can't be used recursively so we re-calculate each
1536 * time (could save in a structure that is returned, but its probably
1537 * not worth the bother).
1538 */
1539
1540 /*
1541 * get dimensions of the list
1542 */
1543 for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
1544 i = strlen(*pp);
1545 nwidth = (i > nwidth) ? i : nwidth;
1546 }
1547 /*
1548 * we will print an index of the form
1549 * %d)
1550 * in front of each entry
1551 * get the max width of this
1552 */
1553 for (i = n, dwidth = 1; i >= 10; i /= 10)
1554 dwidth++;
1555
1556 smi.args = ap;
1557 smi.arg_width = nwidth;
1558 smi.num_width = dwidth;
1559 print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
1560 dwidth + nwidth + 2);
1561
1562 return n;
1563 }
1564 #endif /* KSH */
1565 #ifdef KSH
1566
1567 /*
1568 * [[ ... ]] evaluation routines
1569 */
1570
1571 extern const char *const dbtest_tokens[];
1572 extern const char db_close[];
1573
1574 /* Test if the current token is a whatever. Accepts the current token if
1575 * it is. Returns 0 if it is not, non-zero if it is (in the case of
1576 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
1577 */
1578 static int
1579 dbteste_isa(te, meta)
1580 Test_env *te;
1581 Test_meta meta;
1582 {
1583 int ret = 0;
1584 int uqword;
1585 char *p;
1586
1587 if (!*te->pos.wp)
1588 return meta == TM_END;
1589
1590 /* unquoted word? */
1591 for (p = *te->pos.wp; *p == CHAR; p += 2)
1592 ;
1593 uqword = *p == EOS;
1594
1595 if (meta == TM_UNOP || meta == TM_BINOP) {
1596 if (uqword) {
1597 char buf[8]; /* longer than the longest operator */
1598 char *q = buf;
1599 for (p = *te->pos.wp; *p == CHAR
1600 && q < &buf[sizeof(buf) - 1];
1601 p += 2)
1602 *q++ = p[1];
1603 *q = '\0';
1604 ret = (int) test_isop(te, meta, buf);
1605 }
1606 } else if (meta == TM_END)
1607 ret = 0;
1608 else
1609 ret = uqword
1610 && strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
1611
1612 /* Accept the token? */
1613 if (ret)
1614 te->pos.wp++;
1615
1616 return ret;
1617 }
1618
1619 static const char *
1620 dbteste_getopnd(te, op, do_eval)
1621 Test_env *te;
1622 Test_op op;
1623 int do_eval;
1624 {
1625 char *s = *te->pos.wp;
1626
1627 if (!s)
1628 return (char *) 0;
1629
1630 te->pos.wp++;
1631
1632 if (!do_eval)
1633 return null;
1634
1635 if (op == TO_STEQL || op == TO_STNEQ)
1636 s = evalstr(s, DOTILDE | DOPAT);
1637 else
1638 s = evalstr(s, DOTILDE);
1639
1640 return s;
1641 }
1642
1643 static int
1644 dbteste_eval(te, op, opnd1, opnd2, do_eval)
1645 Test_env *te;
1646 Test_op op;
1647 const char *opnd1;
1648 const char *opnd2;
1649 int do_eval;
1650 {
1651 return test_eval(te, op, opnd1, opnd2, do_eval);
1652 }
1653
1654 static void
1655 dbteste_error(te, offset, msg)
1656 Test_env *te;
1657 int offset;
1658 const char *msg;
1659 {
1660 te->flags |= TEF_ERROR;
1661 internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
1662 }
1663 #endif /* KSH */
1664