1 /* $NetBSD: c_ksh.c,v 1.15 2006/04/24 20:00:31 christos Exp $ */
4 * built-in Korn commands: c_*
9 __RCSID("$NetBSD: c_ksh.c,v 1.15 2006/04/24 20:00:31 christos Exp $");
17 #include <sys/cygwin.h>
18 #endif /* __CYGWIN__ */
25 int physical
= Flag(FPHYSICAL
);
26 int cdnode
; /* was a node from cdpath added in? */
27 int printpath
= 0; /* print where we cd'd? */
29 struct tbl
*pwd_s
, *oldpwd_s
;
32 char *dir
, *try, *pwd
;
37 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "LP")) != EOF
)
48 wp
+= builtin_opt
.optind
;
50 if (Flag(FRESTRICTED
)) {
51 bi_errorf("restricted shell - can't cd");
55 pwd_s
= global("PWD");
56 oldpwd_s
= global("OLDPWD");
59 /* No arguments - go home */
60 if ((dir
= str_val(global("HOME"))) == null
) {
61 bi_errorf("no home directory (HOME not set)");
65 /* One argument: - or dir */
67 if (strcmp(dir
, "-") == 0) {
68 dir
= str_val(oldpwd_s
);
70 bi_errorf("no OLDPWD");
76 /* Two arguments - substitute arg1 in PWD for arg2 */
77 int ilen
, olen
, nlen
, elen
;
81 bi_errorf("don't know current directory");
84 /* substitute arg1 for arg2 in current path.
85 * if the first substitution fails because the cd fails
86 * we could try to find another substitution. For now
89 if ((cp
= strstr(current_wd
, wp
[0])) == (char *) 0) {
90 bi_errorf("bad substitution");
93 ilen
= cp
- current_wd
;
96 elen
= strlen(current_wd
+ ilen
+ olen
) + 1;
97 fdir
= dir
= alloc(ilen
+ nlen
+ elen
, ATEMP
);
98 memcpy(dir
, current_wd
, ilen
);
99 memcpy(dir
+ ilen
, wp
[1], nlen
);
100 memcpy(dir
+ ilen
+ nlen
, current_wd
+ ilen
+ olen
, elen
);
103 bi_errorf("too many arguments");
107 Xinit(xs
, xp
, PATH
, ATEMP
);
108 /* xp will have a bogus value after make_path() - set it to 0
109 * so that if it's used, it will cause a dump
113 cdpath
= str_val(global("CDPATH"));
115 cdnode
= make_path(current_wd
, dir
, &cdpath
, &xs
, &phys_path
);
118 rval
= chdir(try = Xstring(xs
, xp
) + phys_path
);
122 simplify_path(Xstring(xs
, xp
));
123 rval
= chdir(try = Xstring(xs
, xp
));
125 } while (rval
< 0 && cdpath
!= (char *) 0);
129 bi_errorf("%s: bad directory", dir
);
131 bi_errorf("%s - %s", try, strerror(errno
));
137 /* Clear out tracked aliases with relative paths */
140 /* Set OLDPWD (note: unsetting OLDPWD does not disable this
141 * setting in at&t ksh)
144 /* Ignore failure (happens if readonly or integer) */
145 setstr(oldpwd_s
, current_wd
, KSH_RETURN_ERROR
);
147 if (!ISABSPATH(Xstring(xs
, xp
))) {
149 /* simplify_path() doesn't know about os/2's drive contexts,
150 * so it can't set current_wd when changing to a:foo.
151 * Handle this by calling getcwd()...
153 pwd
= ksh_get_wd((char *) 0, 0);
159 if (!physical
|| !(pwd
= get_phys_path(Xstring(xs
, xp
))))
161 pwd
= Xstring(xs
, xp
);
166 char ptmp
[PATH
]; /* larger than MAX_PATH */
167 cygwin_conv_to_full_posix_path(pwd
, ptmp
);
168 #else /* __CYGWIN__ */
170 #endif /* __CYGWIN__ */
171 set_current_wd(ptmp
);
172 /* Ignore failure (happens if readonly or integer) */
173 setstr(pwd_s
, ptmp
, KSH_RETURN_ERROR
);
175 set_current_wd(null
);
176 pwd
= Xstring(xs
, xp
);
177 /* XXX unset $PWD? */
179 if (printpath
|| cdnode
)
180 shprintf("%s\n", pwd
);
193 int physical
= Flag(FPHYSICAL
);
194 char *p
, *freep
= NULL
;
196 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "LP")) != EOF
)
207 wp
+= builtin_opt
.optind
;
210 bi_errorf("too many arguments");
214 p
= current_wd
[0] ? (physical
? get_phys_path(current_wd
) : current_wd
)
217 p
= current_wd
[0] ? current_wd
: (char *) 0;
219 if (p
&& eaccess(p
, R_OK
) < 0)
222 freep
= p
= ksh_get_wd((char *) 0, 0);
224 bi_errorf("can't get current directory - %s",
239 #define PO_NL BIT(0) /* print newline */
240 #define PO_EXPAND BIT(1) /* expand backslash sequences */
241 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */
242 #define PO_HIST BIT(3) /* print to history instead of stdout */
243 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
244 #define PO_FSLASH BIT(5) /* swap slash for backslash (for os2 ) */
246 int flags
= PO_EXPAND
|PO_NL
;
252 if (wp
[0][0] == 'e') { /* echo command */
255 /* A compromise between sysV and BSD echo commands:
256 * escape sequences are enabled by default, and
257 * -n, -e and -E are recognized if they appear
258 * in arguments with no illegal options (ie, echo -nq
260 * Different from sysV echo since options are recognized,
261 * different from BSD echo since escape sequences are enabled
265 while ((s
= *wp
) && *s
== '-' && s
[1]) {
272 nflags
&= ~PO_EXPAND
;
274 /* bad option: don't use nflags, print
286 const char *options
= "Rnpfrsu,"; /* added f flag */
288 const char *options
= "Rnprsu,";
290 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != EOF
)
292 case 'R': /* fake BSD echo command */
293 flags
|= PO_PMINUSMINUS
;
310 if ((fd
= coproc_getfd(W_OK
, &emsg
)) < 0) {
311 bi_errorf("-p: %s", emsg
);
323 if (!*(s
= builtin_opt
.optarg
))
325 else if ((fd
= check_fd(s
, W_OK
, &emsg
)) < 0) {
326 bi_errorf("-u: %s: %s", s
, emsg
);
333 if (!(builtin_opt
.info
& GI_MINUSMINUS
)) {
334 /* treat a lone - like -- */
335 if (wp
[builtin_opt
.optind
]
336 && strcmp(wp
[builtin_opt
.optind
], "-") == 0)
337 builtin_opt
.optind
++;
338 } else if (flags
& PO_PMINUSMINUS
)
339 builtin_opt
.optind
--;
340 wp
+= builtin_opt
.optind
;
343 Xinit(xs
, xp
, 128, ATEMP
);
345 while (*wp
!= NULL
) {
348 while ((c
= *s
++) != '\0') {
351 if ((flags
& PO_FSLASH
) && c
== '\\')
357 if ((flags
& PO_EXPAND
) && c
== '\\') {
360 switch ((c
= *s
++)) {
361 /* Oddly enough, \007 seems more portable than
362 * \a (due to HP-UX cc, Ultrix cc, old pcc's,
365 case 'a': c
= '\007'; break;
366 case 'b': c
= '\b'; break;
367 case 'c': flags
&= ~PO_NL
;
368 continue; /* AT&T brain damage */
369 case 'f': c
= '\f'; break;
370 case 'n': c
= '\n'; break;
371 case 'r': c
= '\r'; break;
372 case 't': c
= '\t'; break;
373 case 'v': c
= 0x0B; break;
375 /* Look for an octal number: can have
376 * three digits (not counting the
377 * leading 0). Truly burnt.
380 for (i
= 0; i
< 3; i
++) {
381 if (*s
>= '0' && *s
<= '7')
382 c
= c
*8 + *s
++ - '0';
387 case '\0': s
--; c
= '\\'; break;
401 if (flags
& PO_HIST
) {
404 histsave(source
->line
, Xstring(xs
, xp
), 1);
407 int n
, len
= Xlength(xs
, xp
);
408 int UNINITIALIZED(opipe
);
411 /* Ensure we aren't killed by a SIGPIPE while writing to
412 * a coprocess. at&t ksh doesn't seem to do this (seems
413 * to just check that the co-process is alive, which is
416 if (coproc
.write
>= 0 && coproc
.write
== fd
) {
418 opipe
= block_pipe();
421 for (s
= Xstring(xs
, xp
); len
> 0; ) {
422 n
= write(fd
, s
, len
);
425 if (flags
& PO_COPROC
)
428 if (errno
== EINTR
) {
429 /* allow user to ^C out */
432 if (flags
& PO_COPROC
)
433 opipe
= block_pipe();
438 /* This doesn't really make sense - could
439 * break scripts (print -p generates
442 * coproc_write_close(fd);
451 if (flags
& PO_COPROC
)
465 int pflag
= 0, vflag
= 0, Vflag
= 0;
468 int iam_whence
= wp
[0][0] == 'w';
470 const char *options
= iam_whence
? "pv" : "pvV";
472 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != EOF
)
486 wp
+= builtin_opt
.optind
;
489 fcflags
= FC_BI
| FC_PATH
| FC_FUNC
;
491 /* Note that -p on its own is deal with in comexec() */
493 fcflags
|= FC_DEFPATH
;
494 /* Convert command options to whence options - note that
495 * command -pV uses a different path search than whence -v
496 * or whence -pv. This should be considered a feature.
501 fcflags
&= ~(FC_BI
| FC_FUNC
);
503 while ((vflag
|| ret
== 0) && (id
= *wp
++) != NULL
) {
505 if ((iam_whence
|| vflag
) && !pflag
)
506 tp
= tsearch(&keywords
, id
, hash(id
));
508 tp
= tsearch(&aliases
, id
, hash(id
));
509 if (tp
&& !(tp
->flag
& ISSET
))
513 tp
= findcom(id
, fcflags
);
514 if (vflag
|| (tp
->type
!= CALIAS
&& tp
->type
!= CEXEC
515 && tp
->type
!= CTALIAS
))
520 shprintf(" is a reserved word");
524 shprintf(" is an %salias for ",
525 (tp
->flag
& EXPORT
) ? "exported "
527 if (!iam_whence
&& !vflag
)
528 shprintf("alias %s=", id
);
529 print_value_quoted(tp
->val
.s
);
534 if (tp
->flag
& EXPORT
)
535 shprintf("n exported");
536 if (tp
->flag
& TRACE
)
538 if (!(tp
->flag
& ISSET
)) {
539 shprintf(" undefined");
541 shprintf(" (autoload from %s)",
544 shprintf(" function");
549 shprintf(" is a%s shell builtin",
550 (tp
->flag
& SPEC_BI
) ? " special" : null
);
554 if (tp
->flag
& ISSET
) {
557 if (tp
->type
== CTALIAS
)
559 "a tracked %salias for ",
560 (tp
->flag
& EXPORT
) ?
564 shprintf("%s", tp
->val
.s
);
567 shprintf(" not found");
572 shprintf("%s is *GOK*", id
);
581 /* Deal with command -vV - command -p dealt with in comexec() */
586 /* Let c_whence do the work. Note that c_command() must be
587 * a distinct function from c_whence() (tested in comexec()).
592 /* typeset, export, and readonly */
597 struct block
*l
= e
->loc
;
599 Tflag fset
= 0, fclr
= 0;
600 int thing
= 0, func
= 0, localv
= 0;
601 const char *options
= "L#R#UZ#fi#lprtux"; /* see comment below */
602 char *fieldstr
, *basestr
;
609 case 'e': /* export */
613 case 'r': /* readonly */
618 /* called with 'typeset -' */
620 case 't': /* typeset */
625 fieldstr
= basestr
= (char *) 0;
626 builtin_opt
.flags
|= GF_PLUSOPT
;
627 /* at&t ksh seems to have 0-9 as options, which are multiplied
628 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
629 * sets right justify in a field of 12). This allows options
630 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
631 * does not allow the number to be specified as a separate argument
632 * Here, the number must follow the RLZi option, but is optional
633 * (see the # kludge in ksh_getopt()).
635 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != EOF
) {
640 fieldstr
= builtin_opt
.optarg
;
644 fieldstr
= builtin_opt
.optarg
;
647 /* at&t ksh uses u, but this conflicts with
648 * upper/lower case. If this option is changed,
649 * need to change the -U below as well
655 fieldstr
= builtin_opt
.optarg
;
662 basestr
= builtin_opt
.optarg
;
667 case 'p': /* posix export/readonly -p flag.
668 * typeset -p is the same as typeset (in pdksh);
669 * here for compatibility with ksh93.
680 flag
= UCASEV_AL
; /* upper case / autoload */
688 if (builtin_opt
.info
& GI_PLUS
) {
700 if (fieldstr
&& !bi_getn(fieldstr
, &field
))
703 if (basestr
&& !bi_getn(basestr
, &base
))
706 if (!(builtin_opt
.info
& GI_MINUSMINUS
) && wp
[builtin_opt
.optind
]
707 && (wp
[builtin_opt
.optind
][0] == '-'
708 || wp
[builtin_opt
.optind
][0] == '+')
709 && wp
[builtin_opt
.optind
][1] == '\0')
711 thing
= wp
[builtin_opt
.optind
][0];
712 builtin_opt
.optind
++;
715 if (func
&& ((fset
|fclr
) & ~(TRACE
|UCASEV_AL
|EXPORT
))) {
716 bi_errorf("only -t, -u and -x options may be used with -f");
719 if (wp
[builtin_opt
.optind
]) {
720 /* Take care of exclusions.
721 * At this point, flags in fset are cleared in fclr and vise
722 * versa. This property should be preserved.
724 if (fset
& LCASEV
) /* LCASEV has priority over UCASEV_AL */
726 if (fset
& LJUST
) /* LJUST has priority over RJUST */
728 if ((fset
& (ZEROFIL
|LJUST
)) == ZEROFIL
) { /* -Z implies -ZR */
732 /* Setting these attributes clears the others, unless they
733 * are also set in this command
735 if (fset
& (LJUST
|RJUST
|ZEROFIL
|UCASEV_AL
|LCASEV
|INTEGER
738 (LJUST
|RJUST
|ZEROFIL
|UCASEV_AL
|LCASEV
|INTEGER
742 /* set variables and attributes */
743 if (wp
[builtin_opt
.optind
]) {
750 for (i
= builtin_opt
.optind
; wp
[i
]; i
++) {
752 f
= findfunc(wp
[i
], hash(wp
[i
]),
753 (fset
&UCASEV_AL
) ? TRUE
: FALSE
);
755 /* at&t ksh does ++rval: bogus */
763 fptreef(shl_stdout
, 0,
769 } else if (!typeset(wp
[i
], fset
, fclr
, field
, base
)) {
770 bi_errorf("%s: not identifier", wp
[i
]);
777 /* list variables and attributes */
778 flag
= fset
| fclr
; /* no difference at this point.. */
780 for (l
= e
->loc
; l
; l
= l
->next
) {
781 for (p
= tsort(&l
->funs
); (vp
= *p
++); ) {
782 if (flag
&& (vp
->flag
& flag
) == 0)
785 fptreef(shl_stdout
, 0, vp
->flag
& FKSH
?
788 vp
->name
, vp
->val
.t
);
790 shprintf("%s\n", vp
->name
);
794 for (l
= e
->loc
; l
; l
= l
->next
) {
795 for (p
= tsort(&l
->vars
); (vp
= *p
++); ) {
799 * See if the parameter is set (for arrays, if any
802 for (tvp
= vp
; tvp
; tvp
= tvp
->u
.array
)
803 if (tvp
->flag
& ISSET
) {
808 * Check attributes - note that all array elements
809 * have (should have?) the same attributes, so checking
810 * the first is sufficient.
812 * Report an unset param only if the user has
813 * explicitly given it some attribute (like export);
814 * otherwise, after "echo $FOO", we would report FOO...
816 if (!any_set
&& !(vp
->flag
& USERATTRIB
))
818 if (flag
&& (vp
->flag
& flag
) == 0)
820 for (; vp
; vp
= vp
->u
.array
) {
821 /* Ignore array elements that aren't set unless there
822 * are no set elements, in which case the first is
825 if ((vp
->flag
&ARRAY
) && any_set
&& !(vp
->flag
& ISSET
))
828 if (thing
== 0 && flag
== 0) {
829 /* at&t ksh prints things like export, integer,
830 * leftadj, zerofill, etc., but POSIX says must
831 * be suitable for re-entry...
833 shprintf("typeset ");
834 if ((vp
->flag
&INTEGER
))
836 if ((vp
->flag
&EXPORT
))
838 if ((vp
->flag
&RDONLY
))
840 if ((vp
->flag
&TRACE
))
842 if ((vp
->flag
&LJUST
))
843 shprintf("-L%d ", vp
->u2
.field
);
844 if ((vp
->flag
&RJUST
))
845 shprintf("-R%d ", vp
->u2
.field
);
846 if ((vp
->flag
&ZEROFIL
))
848 if ((vp
->flag
&LCASEV
))
850 if ((vp
->flag
&UCASEV_AL
))
852 if ((vp
->flag
&INT_U
))
854 shprintf("%s\n", vp
->name
);
860 (flag
& EXPORT
) ? "export" : "readonly");
861 if ((vp
->flag
&ARRAY
) && any_set
)
862 shprintf("%s[%d]", vp
->name
, vp
->index
);
864 shprintf("%s", vp
->name
);
865 if (thing
== '-' && (vp
->flag
&ISSET
)) {
866 char *s
= str_val(vp
);
869 /* at&t ksh can't have justified integers.. */
870 if ((vp
->flag
& (INTEGER
|LJUST
|RJUST
))
874 print_value_quoted(s
);
878 /* Only report first `element' of an array with
894 struct table
*t
= &aliases
;
895 int rv
= 0, rflag
= 0, tflag
, Uflag
= 0, pflag
= 0;
900 builtin_opt
.flags
|= GF_PLUSOPT
;
901 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "dprtUx")) != EOF
) {
902 prefix
= builtin_opt
.info
& GI_PLUS
? '+' : '-';
916 case 'U': /* kludge for tracked alias initialization
917 * (don't do a path search, just make an entry)
928 wp
+= builtin_opt
.optind
;
930 if (!(builtin_opt
.info
& GI_MINUSMINUS
) && *wp
931 && (wp
[0][0] == '-' || wp
[0][0] == '+') && wp
[0][1] == '\0')
937 tflag
= t
== &taliases
;
939 /* "hash -r" means reset all the tracked aliases.. */
941 static const char *const args
[] = {
942 "unalias", "-ta", (const char *) 0
947 "alias: -r flag can only be used with -t and without arguments\n");
950 ksh_getopt_reset(&builtin_opt
, GF_ERROR
);
951 return c_unalias((char **)__UNCONST(args
));
958 for (p
= tsort(t
); (ap
= *p
++) != NULL
; )
959 if ((ap
->flag
& (ISSET
|xflag
)) == (ISSET
|xflag
)) {
961 shf_puts("alias ", shl_stdout
);
962 shf_puts(ap
->name
, shl_stdout
);
964 shf_putc('=', shl_stdout
);
965 print_value_quoted(ap
->val
.s
);
971 for (; *wp
!= NULL
; wp
++) {
973 char *val
= strchr(alias
, '=');
979 alias
= str_nsave(alias
, val
++ - alias
, ATEMP
);
981 if (val
== NULL
&& !tflag
&& !xflag
) {
982 ap
= tsearch(t
, alias
, h
);
983 if (ap
!= NULL
&& (ap
->flag
&ISSET
)) {
985 shf_puts("alias ", shl_stdout
);
986 shf_puts(ap
->name
, shl_stdout
);
988 shf_putc('=', shl_stdout
);
989 print_value_quoted(ap
->val
.s
);
993 shprintf("%s alias not found\n", alias
);
998 ap
= tenter(t
, alias
, h
);
999 ap
->type
= tflag
? CTALIAS
: CALIAS
;
1000 /* Are we setting the value or just some flags? */
1001 if ((val
&& !tflag
) || (!val
&& tflag
&& !Uflag
)) {
1002 if (ap
->flag
&ALLOC
) {
1003 ap
->flag
&= ~(ALLOC
|ISSET
);
1004 afree((void*)ap
->val
.s
, APERM
);
1006 /* ignore values for -t (at&t ksh does this) */
1007 newval
= tflag
? search(alias
, path
, X_OK
, (int *) 0)
1010 ap
->val
.s
= str_save(newval
, APERM
);
1011 ap
->flag
|= ALLOC
|ISSET
;
1015 ap
->flag
|= DEFINED
;
1021 afree(alias
, ATEMP
);
1031 register struct table
*t
= &aliases
;
1032 register struct tbl
*ap
;
1033 int rv
= 0, all
= 0;
1036 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "adt")) != EOF
)
1050 wp
+= builtin_opt
.optind
;
1052 for (; *wp
!= NULL
; wp
++) {
1053 ap
= tsearch(t
, *wp
, hash(*wp
));
1058 if (ap
->flag
&ALLOC
) {
1059 ap
->flag
&= ~(ALLOC
|ISSET
);
1060 afree((void*)ap
->val
.s
, APERM
);
1062 ap
->flag
&= ~(DEFINED
|ISSET
|EXPORT
);
1068 for (twalk(&ts
, t
); (ap
= tnext(&ts
)); ) {
1069 if (ap
->flag
&ALLOC
) {
1070 ap
->flag
&= ~(ALLOC
|ISSET
);
1071 afree((void*)ap
->val
.s
, APERM
);
1073 ap
->flag
&= ~(DEFINED
|ISSET
|EXPORT
);
1088 if (wp
[1] == (char *) 0) /* at&t ksh does this */
1089 bi_errorf("no arguments");
1091 for (wp
++; *wp
; wp
++)
1092 if (!evaluate(*wp
, &val
, KSH_RETURN_ERROR
)) {
1093 rv
= 2; /* distinguish error from zero result */
1110 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "lpnz")) != EOF
)
1121 case 'z': /* debugging: print zombies */
1127 wp
+= builtin_opt
.optind
;
1129 if (j_jobs((char *) 0, flag
, nflag
))
1133 if (j_jobs(*wp
, flag
, nflag
))
1144 int bg
= strcmp(*wp
, "bg") == 0;
1145 int UNINITIALIZED(rv
);
1147 if (!Flag(FMONITOR
)) {
1148 bi_errorf("job control not enabled");
1151 if (ksh_getopt(wp
, &builtin_opt
, null
) == '?')
1153 wp
+= builtin_opt
.optind
;
1156 rv
= j_resume(*wp
, bg
);
1158 rv
= j_resume("%%", bg
);
1159 /* POSIX says fg shall return 0 (unless an error occurs).
1160 * at&t ksh returns the exit value of the job...
1162 return (bg
|| Flag(FPOSIX
)) ? 0 : rv
;
1170 static char *kill_fmt_entry
ARGS((void *arg
, int i
, char *buf
, int buflen
));
1172 /* format a single kill item */
1174 kill_fmt_entry(arg
, i
, buf
, buflen
)
1180 struct kill_info
*ki
= (struct kill_info
*) arg
;
1183 if (sigtraps
[i
].name
)
1184 shf_snprintf(buf
, buflen
, "%*d %*s %s",
1186 ki
->name_width
, sigtraps
[i
].name
,
1189 shf_snprintf(buf
, buflen
, "%*d %*d %s",
1191 ki
->name_width
, sigtraps
[i
].signal
,
1201 Trap
*t
= (Trap
*) 0;
1206 /* assume old style options if -digits or -UPPERCASE */
1207 if ((p
= wp
[1]) && *p
== '-'
1208 && (digit(p
[1]) || isupper((unsigned char)p
[1]))) {
1209 if (!(t
= gettrap(p
+ 1, TRUE
))) {
1210 bi_errorf("bad signal `%s'", p
+ 1);
1213 i
= (wp
[2] && strcmp(wp
[2], "--") == 0) ? 3 : 2;
1217 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "ls:")) != EOF
)
1223 if (!(t
= gettrap(builtin_opt
.optarg
, TRUE
))) {
1224 bi_errorf("bad signal `%s'",
1225 builtin_opt
.optarg
);
1232 i
= builtin_opt
.optind
;
1234 if ((lflag
&& t
) || (!wp
[i
] && !lflag
)) {
1235 shf_fprintf(shl_out
,
1236 "usage: kill [ -s signame | -signum | -signame ] {pid|job}...\n\
1237 kill -l [exit_status]\n"
1245 for (; wp
[i
]; i
++) {
1246 if (!bi_getn(wp
[i
], &n
))
1248 if (n
> 128 && n
< 128 + SIGNALS
)
1250 if (n
> 0 && n
< SIGNALS
&& sigtraps
[n
].name
)
1251 shprintf("%s\n", sigtraps
[n
].name
);
1253 shprintf("%d\n", n
);
1255 } else if (Flag(FPOSIX
)) {
1257 for (i
= 1; i
< SIGNALS
; i
++, p
= space
)
1258 if (sigtraps
[i
].name
)
1259 shprintf("%s%s", p
, sigtraps
[i
].name
);
1264 struct kill_info ki
;
1266 for (si
= SIGNALS
, ki
.num_width
= 1; si
>= 10; si
/= 10)
1268 ki
.name_width
= mess_width
= 0;
1269 for (si
= 0; si
< SIGNALS
; si
++) {
1270 w
= sigtraps
[si
].name
?
1271 (int)strlen(sigtraps
[si
].name
) :
1273 if (w
> ki
.name_width
)
1275 w
= strlen(sigtraps
[si
].mess
);
1280 print_columns(shl_stdout
, SIGNALS
- 1,
1281 kill_fmt_entry
, (void *) &ki
,
1282 ki
.num_width
+ ki
.name_width
+ mess_width
+ 3, 1);
1287 sig
= t
? t
->signal
: SIGTERM
;
1288 for (; (p
= wp
[i
]); i
++) {
1292 } else if (!getn(p
, &n
)) {
1293 bi_errorf("%s: arguments must be jobs or process IDs",
1297 /* use killpg if < -1 since -1 does special things for
1298 * some non-killpg-endowed kills
1300 if ((n
< -1 ? killpg(-n
, sig
) : kill(n
, sig
)) < 0) {
1301 bi_errorf("%s: %s", p
, strerror(errno
));
1314 ksh_getopt_reset(&user_opt
,
1315 GF_NONAME
| (Flag(FPOSIX
) ? 0 : GF_PLUSOPT
));
1316 user_opt
.optind
= user_opt
.uoptind
= val
;
1325 const char *options
;
1330 struct tbl
*vq
, *voptarg
;
1332 if (ksh_getopt(wp
, &builtin_opt
, null
) == '?')
1334 wp
+= builtin_opt
.optind
;
1338 bi_errorf("missing options argument");
1344 bi_errorf("missing name argument");
1347 if (!*var
|| *skip_varname(var
, TRUE
)) {
1348 bi_errorf("%s: is not an identifier", var
);
1352 if (e
->loc
->next
== (struct block
*) 0) {
1353 internal_errorf(0, "c_getopts: no argv");
1356 /* Which arguments are we parsing... */
1357 if (*wp
== (char *) 0)
1358 wp
= e
->loc
->next
->argv
;
1360 *--wp
= e
->loc
->next
->argv
[0];
1362 /* Check that our saved state won't cause a core dump... */
1363 for (argc
= 0; wp
[argc
]; argc
++)
1365 if (user_opt
.optind
> argc
1367 && user_opt
.p
> strlen(wp
[user_opt
.optind
- 1])))
1369 bi_errorf("arguments changed since last call");
1373 user_opt
.optarg
= (char *) 0;
1374 optc
= ksh_getopt(wp
, &user_opt
, options
);
1376 if (optc
>= 0 && optc
!= '?' && (user_opt
.info
& GI_PLUS
)) {
1381 /* POSIX says var is set to ? at end-of-options, at&t ksh
1382 * sets it to null - we go with POSIX...
1384 buf
[0] = optc
< 0 ? '?' : optc
;
1388 /* at&t ksh does not change OPTIND if it was an unknown option.
1389 * Scripts counting on this are prone to break... (ie, don't count
1393 user_opt
.uoptind
= user_opt
.optind
;
1396 voptarg
= global("OPTARG");
1397 voptarg
->flag
&= ~RDONLY
; /* at&t ksh clears ro and int */
1398 /* Paranoia: ensure no bizarre results. */
1399 if (voptarg
->flag
& INTEGER
)
1400 typeset("OPTARG", 0, INTEGER
, 0, 0);
1401 if (user_opt
.optarg
== (char *) 0)
1404 /* This can't fail (have cleared readonly/integer) */
1405 setstr(voptarg
, user_opt
.optarg
, KSH_RETURN_ERROR
);
1410 /* Error message already printed (integer, readonly) */
1411 if (!setstr(vq
, buf
, KSH_RETURN_ERROR
))
1414 typeset(var
, EXPORT
, 0, 0, 0);
1416 return optc
< 0 ? 1 : ret
;
1424 int rv
= 0, macro
= 0, list
= 0;
1428 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "lm")) != EOF
)
1439 wp
+= builtin_opt
.optind
;
1441 if (*wp
== NULL
) /* list all */
1442 rv
= x_bind((char*)NULL
, (char*)NULL
, 0, list
);
1444 for (; *wp
!= NULL
; wp
++) {
1445 cp
= strchr(*wp
, '=');
1448 if (x_bind(*wp
, cp
, macro
, 0))
1456 /* A leading = means assignments before command are kept;
1457 * a leading * means a POSIX special builtin;
1458 * a leading + means a POSIX regular builtin
1459 * (* and + should not be combined).
1461 const struct builtin kshbuiltins
[] = {
1462 {"+alias", c_alias
}, /* no =: at&t manual wrong */
1464 {"+command", c_command
},
1466 {"*=export", c_typeset
},
1469 #endif /* HISTORY */
1470 {"+getopts", c_getopts
},
1478 {"*=readonly", c_typeset
},
1479 {"=typeset", c_typeset
},
1480 {"+unalias", c_unalias
},
1481 {"whence", c_whence
},