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