diff --git a/Makefile b/Makefile index 66975ba..6ac0b6d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -# $MirOS: src/bin/mksh/Makefile,v 1.85 2011/01/30 02:28:31 tg Exp $ +# $MirOS: src/bin/mksh/Makefile,v 1.86 2011/02/11 01:18:14 tg Exp $ #- -# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 # Thorsten Glaser # # Provided that these terms and disclaimer and all copyright notices @@ -30,8 +30,10 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 \ -DHAVE_ATTRIBUTE_BOUNDED=1 -DHAVE_ATTRIBUTE_FORMAT=1 \ -DHAVE_ATTRIBUTE_NONNULL=1 -DHAVE_ATTRIBUTE_NORETURN=1 \ -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 \ - -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 \ - -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_SYSMACROS_H=0 -DHAVE_GRP_H=1 \ + -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 \ + -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 \ + -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_SELECT_H=1 \ + -DHAVE_SYS_SYSMACROS_H=0 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 \ -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 \ -DHAVE_STDBOOL_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 \ -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 \ @@ -41,9 +43,10 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 \ -DHAVE_GETRUSAGE=1 -DHAVE_KILLPG=1 -DHAVE_MKNOD=0 \ -DHAVE_MKSTEMP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=1 \ -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 \ - -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRCASESTR=1 \ - -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \ - -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=1 + -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 \ + -DHAVE_STRCASESTR=1 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 \ + -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \ + -DHAVE_PERSISTENT_HISTORY=1 COPTS+= -std=gnu99 -Wall .endif @@ -54,8 +57,14 @@ SRCS+= printf.c CPPFLAGS+= -DMKSH_PRINTF_BUILTIN .endif -LINKS+= ${BINDIR}/${PROG} ${BINDIR}/sh -MLINKS+= ${PROG}.1 sh.1 +MANLINKS= [ false pwd sh sleep test true +BINLINKS= ${MANLINKS} echo domainname kill +.for _i in ${BINLINKS} +LINKS+= ${BINDIR}/${PROG} ${BINDIR}/${_i} +.endfor +.for _i in ${MANLINKS} +MLINKS+= ${PROG}.1 ${_i}.1 +.endfor regress: ${PROG} check.pl check.t -rm -rf regress-dir diff --git a/check.t b/check.t index 5d400d7..c839aa4 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.406 2011/02/09 13:08:24 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.407 2011/02/11 01:18:15 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -25,7 +25,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R39 2011/02/09 + @(#)MIRBSD KSH R39 2011/02/11 description: Check version of shell. stdin: diff --git a/exec.c b/exec.c index 72ade4e..3ade2e2 100644 --- a/exec.c +++ b/exec.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.85 2011/01/30 01:35:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.86 2011/02/11 01:18:16 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL "/bin/sh" @@ -44,7 +44,8 @@ static void dbteste_error(Test_env *, int, const char *); */ int execute(struct op * volatile t, - volatile int flags, /* if XEXEC don't fork */ + /* if XEXEC don't fork */ + volatile int flags, volatile int * volatile xerrok) { int i; @@ -72,7 +73,8 @@ execute(struct op * volatile t, if (trap) runtraps(0); - if (t->type == TCOM /* we want to run an executable... */) { + /* we want to run an executable, do some variance checks */ + if (t->type == TCOM) { /* check if this is 'var=<val.f == c_command) { int optc, saw_p = 0; - /* Ugly dealing with options in two places (here and - * in c_command(), but such is life) + /* + * Ugly dealing with options in two places (here + * and in c_command(), but such is life) */ ksh_getopt_reset(&builtin_opt, 0); while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p') saw_p = 1; if (optc != EOF) - break; /* command -vV or something */ + /* command -vV or something */ + break; /* don't look for functions */ fcflags = FC_BI|FC_PATH; if (saw_p) { @@ -547,7 +554,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, fcflags |= FC_DEFPATH; } ap += builtin_opt.optind; - /* POSIX says special builtins lose their status + /* + * POSIX says special builtins lose their status * if accessed using command. */ keepasn_ok = 0; @@ -626,11 +634,14 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } switch (tp->type) { - case CSHELL: /* shell built-in */ + + /* shell built-in */ + case CSHELL: rv = call_builtin(tp, (const char **)ap); break; - case CFUNC: { /* function call */ + /* function call */ + case CFUNC: { volatile unsigned char old_xflag; volatile Tflag old_inuse; const char * volatile old_kshname; @@ -671,8 +682,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, tp = ftp; } - /* ksh functions set $0 to function name, POSIX functions leave - * $0 unchanged. + /* + * ksh functions set $0 to function name, POSIX + * functions leave $0 unchanged. */ old_kshname = kshname; if (tp->flag & FKSH) @@ -683,7 +695,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, for (i = 0; *ap++ != NULL; i++) ; e->loc->argc = i - 1; - /* ksh-style functions handle getopts sanely, + /* + * ksh-style functions handle getopts sanely, * Bourne/POSIX functions are insane... */ if (tp->flag & FKSH) { @@ -708,9 +721,10 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, kshname = old_kshname; Flag(FXTRACE) = old_xflag; tp->flag = (tp->flag & ~FINUSE) | old_inuse; - /* Were we deleted while executing? If so, free the execution - * tree. todo: Unfortunately, the table entry is never re-used - * until the lookup table is expanded. + /* + * Were we deleted while executing? If so, free the + * execution tree. TODO: Unfortunately, the table entry + * is never re-used until the lookup table is expanded. */ if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) { if (tp->flag & ALLOC) { @@ -738,10 +752,13 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, break; } - case CEXEC: /* executable command */ - case CTALIAS: /* tracked alias */ + /* executable command */ + case CEXEC: + /* tracked alias */ + case CTALIAS: if (!(tp->flag&ISSET)) { - /* errno_ will be set if the named command was found + /* + * errno_ will be set if the named command was found * but could not be executed (permissions, no execute * bit, directory, etc). Print out a (hopefully) * useful error message and set the exit status to 126. @@ -749,7 +766,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, if (tp->u2.errno_) { warningf(true, "%s: %s: %s", cp, "can't execute", strerror(tp->u2.errno_)); - rv = 126; /* POSIX */ + /* POSIX */ + rv = 126; } else { warningf(true, "%s: %s", cp, "not found"); rv = 127; @@ -776,7 +794,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* to fork we set up a TEXEC node and call execute */ texec.type = TEXEC; - texec.left = t; /* for tprint */ + /* for tprint */ + texec.left = t; texec.str = tp->val.s; texec.args = ap; rv = exchild(&texec, flags, xerrok, -1); @@ -796,7 +815,8 @@ scriptexec(struct op *tp, const char **ap) const char *sh; #ifndef MKSH_SMALL unsigned char *cp; - char buf[64]; /* 64 == MAXINTERP in MirBSD */ + /* 64 == MAXINTERP in MirBSD */ + char buf[64]; int fd; #endif union mksh_ccphack args, cap; @@ -932,12 +952,14 @@ define(const char *name, struct op *t) if (tp->flag & ISSET) was_set = true; - /* If this function is currently being executed, we zap this - * table entry so findfunc() won't see it + /* + * If this function is currently being executed, we zap + * this table entry so findfunc() won't see it */ if (tp->flag & FINUSE) { tp->name[0] = '\0'; - tp->flag &= ~DEFINED; /* ensure it won't be found */ + /* ensure it won't be found */ + tp->flag &= ~DEFINED; tp->flag |= FDELETE; } else break; @@ -948,7 +970,8 @@ define(const char *name, struct op *t) tfree(tp->val.t, tp->areap); } - if (t == NULL) { /* undefine */ + if (t == NULL) { + /* undefine */ ktdelete(tp); return (was_set ? 0 : 1); } @@ -964,7 +987,7 @@ define(const char *name, struct op *t) /* * add builtin */ -void +const char * builtin(const char *name, int (*func) (const char **)) { struct tbl *tp; @@ -972,11 +995,14 @@ builtin(const char *name, int (*func) (const char **)) /* see if any flags should be set for this builtin */ for (flag = 0; ; name++) { - if (*name == '=') /* command does variable assignment */ + if (*name == '=') + /* command does variable assignment */ flag |= KEEPASN; - else if (*name == '*') /* POSIX special builtin */ + else if (*name == '*') + /* POSIX special builtin */ flag |= SPEC_BI; - else if (*name == '+') /* POSIX regular builtin */ + else if (*name == '+') + /* POSIX regular builtin */ flag |= REG_BI; else break; @@ -986,6 +1012,8 @@ builtin(const char *name, int (*func) (const char **)) tp->flag = DEFINED | flag; tp->type = CSHELL; tp->val.f = func; + + return (name); } /* @@ -998,8 +1026,10 @@ findcom(const char *name, int flags) static struct tbl temp; uint32_t h = hash(name); struct tbl *tp = NULL, *tbi; - unsigned char insert = Flag(FTRACKALL); /* insert if not found */ - char *fpath; /* for function autoloading */ + /* insert if not found */ + unsigned char insert = Flag(FTRACKALL); + /* for function autoloading */ + char *fpath; union mksh_cchack npath; if (vstrchr(name, '/')) { @@ -1009,7 +1039,8 @@ findcom(const char *name, int flags) goto Search; } tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL; - /* POSIX says special builtins first, then functions, then + /* + * POSIX says special builtins first, then functions, then * POSIX regular builtins, then search path... */ if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI)) @@ -1051,7 +1082,8 @@ findcom(const char *name, int flags) tp = &temp; tp->type = CEXEC; } - tp->flag = DEFINED; /* make ~ISSET */ + /* make ~ISSET */ + tp->flag = DEFINED; } npath.ro = search(name, flags & FC_DEFPATH ? def_path : path, X_OK, &tp->u2.errno_); @@ -1064,14 +1096,16 @@ findcom(const char *name, int flags) (fpath = str_val(global("FPATH"))) != null && (npath.ro = search(name, fpath, R_OK, &tp->u2.errno_)) != NULL) { - /* An undocumented feature of AT&T ksh is that it - * searches FPATH if a command is not found, even - * if the command hasn't been set up as an autoloaded - * function (ie, no typeset -uf). + /* + * An undocumented feature of AT&T ksh is that + * it searches FPATH if a command is not found, + * even if the command hasn't been set up as an + * autoloaded function (ie, no typeset -uf). */ tp = &temp; tp->type = CFUNC; - tp->flag = DEFINED; /* make ~ISSET */ + /* make ~ISSET */ + tp->flag = DEFINED; tp->u.fpath = npath.ro; } } @@ -1080,9 +1114,10 @@ findcom(const char *name, int flags) /* * flush executable commands with relative paths + * (just relative or all?) */ void -flushcom(int all) /* just relative or all */ +flushcom(bool all) { struct tbl *tp; struct tstate ts; @@ -1100,7 +1135,8 @@ flushcom(int all) /* just relative or all */ /* Check if path is something we want to find. Returns -1 for failure. */ int search_access(const char *lpath, int mode, - int *errnop) /* set if candidate found, but not suitable */ + /* set if candidate found, but not suitable */ + int *errnop) { int ret, err = 0; struct stat statb; @@ -1109,7 +1145,8 @@ search_access(const char *lpath, int mode, return (-1); ret = access(lpath, mode); if (ret < 0) - err = errno; /* File exists, but we can't access it */ + /* File exists, but we can't access it */ + err = errno; else if (mode == X_OK && (!S_ISREG(statb.st_mode) || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) { /* This 'cause access() says root can execute everything */ @@ -1126,8 +1163,10 @@ search_access(const char *lpath, int mode, */ const char * search(const char *name, const char *lpath, - int mode, /* R_OK or X_OK */ - int *errnop) /* set if candidate found, but not suitable */ + /* R_OK or X_OK */ + int mode, + /* set if candidate found, but not suitable */ + int *errnop) { const char *sp, *p; char *xp; @@ -1223,7 +1262,8 @@ iosetup(struct ioword *iop, struct tbl *tp) case IOWRITE: flags = O_WRONLY | O_CREAT | O_TRUNC; - /* The stat() is here to allow redirections to + /* + * The stat() is here to allow redirections to * things like /dev/null without error. */ if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) && @@ -1247,7 +1287,8 @@ iosetup(struct ioword *iop, struct tbl *tp) do_open = 0; if (*cp == '-' && !cp[1]) { - u = 1009; /* prevent error return below */ + /* prevent error return below */ + u = 1009; do_close = 1; } else if ((u = check_fd(cp, X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK), @@ -1257,7 +1298,8 @@ iosetup(struct ioword *iop, struct tbl *tp) return (-1); } if (u == iop->unit) - return (0); /* "dup from" == "dup to" */ + /* "dup from" == "dup to" */ + return (0); break; } } @@ -1286,7 +1328,8 @@ iosetup(struct ioword *iop, struct tbl *tp) if (u == iop->unit) e->savefd[iop->unit] = -1; else - /* c_exec() assumes e->savefd[fd] set for any + /* + * c_exec() assumes e->savefd[fd] set for any * redirections. Ask savefd() not to close iop->unit; * this allows error messages to be seen if iop->unit * is 2; also means we can't lose the fd (eg, both @@ -1312,17 +1355,21 @@ iosetup(struct ioword *iop, struct tbl *tp) } if (iotype != IODUP) close(u); - /* Touching any co-process fd in an empty exec + /* + * Touching any co-process fd in an empty exec * causes the shell to close its copies */ else if (tp && tp->type == CSHELL && tp->val.f == c_exec) { - if (iop->flag & IORDUP) /* possible exec <&p */ + if (iop->flag & IORDUP) + /* possible exec <&p */ coproc_read_close(u); - else /* possible exec >&p */ + else + /* possible exec >&p */ coproc_write_close(u); } } - if (u == 2) /* Clear any write errors */ + if (u == 2) + /* Clear any write errors */ shf_reopen(2, SHF_WR, shl_out); return (0); } @@ -1434,7 +1481,8 @@ do_selectargs(const char **ap, bool print_menu) for (argct = 0; ap[argct]; argct++) ; while (1) { - /* Menu is printed if + /*- + * Menu is printed if * - this is the first time around the select loop * - the user enters a blank line * - the REPLY parameter is empty @@ -1573,8 +1621,10 @@ dbteste_isa(Test_env *te, Test_meta meta) if (meta == TM_UNOP || meta == TM_BINOP) { if (uqword) { - char buf[8]; /* longer than the longest operator */ + /* longer than the longest operator */ + char buf[8]; char *q = buf; + for (p = *te->pos.wp; *p == CHAR && q < &buf[sizeof(buf) - 1]; p += 2) *q++ = p[1]; diff --git a/funcs.c b/funcs.c index b1c20c2..fcbb379 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.169 2011/02/11 00:41:34 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.170 2011/02/11 01:18:17 tg Exp $"); #if HAVE_KILLPG /* @@ -126,6 +126,10 @@ const struct builtin mkshbuiltins[] = { {"rename", c_rename}, #if HAVE_SELECT {"sleep", c_sleep}, +#endif +#ifdef __MirBSD__ + /* alias to "true" for historical reasons */ + {"domainname", c_label}, #endif {NULL, (int (*)(const char **))NULL} }; @@ -497,7 +501,7 @@ c_cd(const char **wp) allocd = NULL; /* Clear out tracked aliases with relative paths */ - flushcom(0); + flushcom(false); /* * Set OLDPWD (note: unsetting OLDPWD does not disable this @@ -590,7 +594,7 @@ c_print(const char **wp) if (wp[0][0] == 'e') { /* echo builtin */ wp++; - if (Flag(FPOSIX) || Flag(FSH)) { + if (Flag(FPOSIX) || Flag(FSH) || Flag(FAS_BUILTIN)) { /* Debian Policy 10.4 compliant "echo" builtin */ if (*wp && !strcmp(*wp, "-n")) { /* we recognise "-n" only as the first arg */ @@ -1844,7 +1848,11 @@ c_bind(const char **wp) return (rv); } -/* :, false and true (and ulimit if MKSH_NO_LIMITS) */ +/** + * :, false and true + * ulimit if MKSH_NO_LIMITS + * domainname on MirBSD (hysterical raisins, just don't ask) + */ int c_label(const char **wp) { diff --git a/main.c b/main.c index 3bcbb92..dbb455a 100644 --- a/main.c +++ b/main.c @@ -33,7 +33,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.175 2011/01/21 21:07:11 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.176 2011/02/11 01:18:18 tg Exp $"); extern char **environ; @@ -67,7 +67,8 @@ static const char *initcoms[] = { T_alias, "integer=typeset -i", T_local_typeset, - "hash=alias -t", /* not "alias -t --": hash -r needs to work */ + /* not "alias -t --": hash -r needs to work */ + "hash=alias -t", "type=whence -v", #if !defined(ANDROID) && !defined(MKSH_UNEMPLOYED) /* not in Android for political reasons */ @@ -111,12 +112,18 @@ rndsetup(void) char *cp; cp = alloc(sizeof(*bufptr) - ALLOC_SIZE, APERM); - bufptr = (void *)(cp - ALLOC_SIZE); /* undo what alloc() did */ - bufptr->dataptr = &rndsetupstate; /* PIE or something */ - bufptr->stkptr = &bufptr; /* ASLR in Win/Lin */ - bufptr->mallocptr = bufptr; /* randomised malloc in BSD */ - sigsetjmp(bufptr->jbuf, 1); /* glibc pointer guard */ - gettimeofday(&bufptr->tv, &bufptr->tz); /* introduce variation */ + /* undo what alloc() did to the malloc result address */ + bufptr = (void *)(cp - ALLOC_SIZE); + /* PIE or something similar provides us with deltas here */ + bufptr->dataptr = &rndsetupstate; + /* ASLR in at least Windows, Linux, some BSDs */ + bufptr->stkptr = &bufptr; + /* randomised malloc in BSD (and possibly others) */ + bufptr->mallocptr = bufptr; + /* glibc pointer guard */ + sigsetjmp(bufptr->jbuf, 1); + /* introduce variation */ + gettimeofday(&bufptr->tv, &bufptr->tz); oaat1_init_impl(h); /* variation through pid, ppid, and the works */ @@ -138,14 +145,18 @@ chvt_reinit(void) kshppid = getppid(); } +static const char *empty_argv[] = { + "mksh", NULL +}; + int main(int argc, const char *argv[]) { int argi, i; - Source *s; + Source *s = NULL; struct block *l; unsigned char restricted, errexit, utf_flag; - const char **wp; + const char *ccp, **wp; struct tbl *vp; struct stat s_stdin; #if !defined(_PATH_DEFPATH) && defined(_CS_PATH) @@ -158,16 +169,13 @@ main(int argc, const char *argv[]) /* make sure argv[] is sane */ if (!*argv) { - static const char *empty_argv[] = { - "mksh", NULL - }; - argv = empty_argv; argc = 1; } - kshname = *argv; + kshname = argv[0]; - ainit(&aperm); /* initialise permanent Area */ + /* initialise permanent Area */ + ainit(&aperm); /* set up base environment */ env.type = E_NONE; @@ -178,9 +186,41 @@ main(int argc, const char *argv[]) /* Do this first so output routines (eg, errorf, shellf) can work */ initio(); - argi = parse_args(argv, OF_FIRSTTIME, NULL); - if (argi < 0) - return (1); + /* determine the basename (without '-' or path) of the executable */ + ccp = kshname; + goto begin_parse_kshname; + while ((i = ccp[argi++])) { + if (i == '/') { + ccp += argi; + begin_parse_kshname: + argi = 0; + if (*ccp == '-') + ++ccp; + } + } + if (!*ccp) + ccp = empty_argv[0]; + + /* define built-in commands and see if we were called as one */ + ktinit(&builtins, APERM, + /* must be 80% of 2^n (currently 44 builtins) */ 64); + for (i = 0; mkshbuiltins[i].name != NULL; i++) + if (!strcmp(ccp, builtin(mkshbuiltins[i].name, + mkshbuiltins[i].func))) + Flag(FAS_BUILTIN) = 1; + + if (!Flag(FAS_BUILTIN)) { + /* check for -T option early */ + argi = parse_args(argv, OF_FIRSTTIME, NULL); + if (argi < 0) + return (1); + +#ifdef MKSH_BINSHREDUCED + /* set FSH if we're called as -sh or /bin/sh or so */ + if (!strcmp(ccp, "sh")) + change_flag(FSH, OF_FIRSTTIME, 1); +#endif + } initvar(); @@ -200,12 +240,6 @@ main(int argc, const char *argv[]) /* define shell keywords */ initkeywords(); - /* define built-in commands */ - ktinit(&builtins, APERM, - /* must be 80% of 2^n (currently 44 builtins) */ 64); - for (i = 0; mkshbuiltins[i].name != NULL; i++) - builtin(mkshbuiltins[i].name, mkshbuiltins[i].func); - init_histvec(); #ifdef _PATH_DEFPATH @@ -260,28 +294,13 @@ main(int argc, const char *argv[]) Flag(FVITABCOMPLETE) = 1; #endif -#ifdef MKSH_BINSHREDUCED - /* set FSH if we're called as -sh or /bin/sh or so */ - { - const char *cc; - - cc = kshname; - i = 0; argi = 0; - while (cc[i] != '\0') - /* the following line matches '-' and '/' ;-) */ - if ((cc[i++] | 2) == '/') - argi = i; - if (((cc[argi] | 0x20) == 's') && ((cc[argi + 1] | 0x20) == 'h')) - change_flag(FSH, OF_FIRSTTIME, 1); - } -#endif - /* import environment */ if (environ != NULL) for (wp = (const char **)environ; *wp != NULL; wp++) typeset(*wp, IMPORT | EXPORT, 0, 0, 0); - typeset(initifs, 0, 0, 0, 0); /* for security */ + /* for security */ + typeset(initifs, 0, 0, 0, 0); /* assign default shell variable values */ substitute(initsubs, 0); @@ -356,15 +375,20 @@ main(int argc, const char *argv[]) /* this to note if utf-8 mode is set on command line (see below) */ UTFMODE = 2; - argi = parse_args(argv, OF_CMDLINE, NULL); - if (argi < 0) - return (1); + if (!Flag(FAS_BUILTIN)) { + argi = parse_args(argv, OF_CMDLINE, NULL); + if (argi < 0) + return (1); + } /* process this later only, default to off (hysterical raisins) */ utf_flag = UTFMODE; UTFMODE = 0; - if (Flag(FCOMMAND)) { + if (Flag(FAS_BUILTIN)) { + /* auto-detect from environment variables, always */ + utf_flag = 3; + } else if (Flag(FCOMMAND)) { s = pushs(SSTRING, ATEMP); if (!(s->start = s->str = argv[argi++])) errorf("%s %s", "-c", "requires an argument"); @@ -410,37 +434,17 @@ main(int argc, const char *argv[]) /* initialise job control */ j_init(); - /* set: 0/1; unset: 2->0 */ - UTFMODE = utf_flag & 1; /* Do this after j_init(), as tty_fd is not initialised until then */ if (Flag(FTALKING)) { if (utf_flag == 2) { #ifndef MKSH_ASSUME_UTF8 -#define isuc(x) (((x) != NULL) && \ - (stristr((x), "UTF-8") || stristr((x), "utf8"))) - /* Check if we're in a UTF-8 locale */ - const char *ccp; - -#if HAVE_SETLOCALE_CTYPE - ccp = setlocale(LC_CTYPE, ""); -#if HAVE_LANGINFO_CODESET - if (!isuc(ccp)) - ccp = nl_langinfo(CODESET); -#endif -#else - /* these were imported from environ earlier */ - ccp = str_val(global("LC_ALL")); - if (ccp == null) - ccp = str_val(global("LC_CTYPE")); - if (ccp == null) - ccp = str_val(global("LANG")); -#endif - UTFMODE = isuc(ccp); -#undef isuc + /* auto-detect from locale or environment */ + utf_flag = 4; #elif MKSH_ASSUME_UTF8 - UTFMODE = 1; + utf_flag = 1; #else - UTFMODE = 0; + /* always disable UTF-8 (for interactive) */ + utf_flag = 0; #endif } x_init(); @@ -453,10 +457,62 @@ main(int argc, const char *argv[]) #endif l = e->loc; - l->argv = &argv[argi - 1]; - l->argc = argc - argi; - l->argv[0] = kshname; - getopts_reset(1); + if (Flag(FAS_BUILTIN)) { + l->argc = argc; + l->argv = argv; + l->argv[0] = ccp; + } else { + l->argc = argc - argi; + l->argv = &argv[argi - 1]; + l->argv[0] = kshname; + getopts_reset(1); + } + + /* divine the initial state of the utf8-mode Flag */ +#define isuc(x) (((x) != NULL) && \ + (stristr((x), "UTF-8") || stristr((x), "utf8"))) + ccp = null; + switch (utf_flag) { + + /* auto-detect from locale or environment */ + case 4: +#if HAVE_SETLOCALE_CTYPE + ccp = setlocale(LC_CTYPE, ""); +#if HAVE_LANGINFO_CODESET + if (!isuc(ccp)) + ccp = nl_langinfo(CODESET); +#endif + if (!isuc(ccp)) + ccp = null; + /* FALLTHROUGH */ +#endif + + /* auto-detect from environment */ + case 3: + /* these were imported from environ earlier */ + if (ccp == null) + ccp = str_val(global("LC_ALL")); + if (ccp == null) + ccp = str_val(global("LC_CTYPE")); + if (ccp == null) + ccp = str_val(global("LANG")); + UTFMODE = isuc(ccp); + break; + + /* not set on command line, not FTALKING */ + case 2: + /* unknown values */ + default: + utf_flag = 0; + /* FALLTHROUGH */ + + /* known values */ + case 1: + case 0: + UTFMODE = utf_flag; + break; + } +#undef isuc /* Disable during .profile/ENV reading */ restricted = Flag(FRESTRICTED); @@ -505,7 +561,11 @@ main(int argc, const char *argv[]) hist_init(s); alarm_init(); } else - Flag(FTRACKALL) = 1; /* set after ENV */ + /* set after ENV */ + Flag(FTRACKALL) = 1; + + if (Flag(FAS_BUILTIN)) + return (shcomexec(l->argv)); /* doesn't return */ shell(s, true); @@ -543,7 +603,8 @@ include(const char *name, int argc, const char **argv, int intr_ok) switch (i) { case LRETURN: case LERROR: - return (exstat & 0xff); /* see below */ + /* see below */ + return (exstat & 0xFF); case LINTR: /* * intr_ok is set if we are including .profile or $ENV. @@ -575,7 +636,8 @@ include(const char *name, int argc, const char **argv, int intr_ok) e->loc->argv = old_argv; e->loc->argc = old_argc; } - return (i & 0xff); /* & 0xff to ensure value not -1 */ + /* & 0xff to ensure value not -1 */ + return (i & 0xFF); } /* spawn a command into a shell optionally keeping track of the line number */ @@ -603,7 +665,8 @@ shell(Source * volatile s, volatile int toplevel) Source *volatile old_source = source; int i; - s->flags |= SF_FIRST; /* enable UTF-8 BOM check */ + /* enable UTF-8 BOM check */ + s->flags |= SF_FIRST; newenv(E_PARSE); if (interactive) @@ -611,7 +674,8 @@ shell(Source * volatile s, volatile int toplevel) i = sigsetjmp(e->jbuf, 0); if (i) { switch (i) { - case LINTR: /* we get here if SIGINT not caught or ignored */ + case LINTR: + /* we get here if SIGINT not caught or ignored */ case LERROR: case LSHELL: if (interactive) { @@ -641,7 +705,8 @@ shell(Source * volatile s, volatile int toplevel) case LRETURN: source = old_source; quitenv(NULL); - unwind(i); /* keep on going */ + /* keep on going */ + unwind(i); /* NOTREACHED */ default: source = old_source; @@ -745,7 +810,8 @@ newenv(int type) * so first get the actually used memory, then assign it */ cp = alloc(sizeof(struct env) - ALLOC_SIZE, ATEMP); - ep = (void *)(cp - ALLOC_SIZE); /* undo what alloc() did */ + /* undo what alloc() did to the malloc result address */ + ep = (void *)(cp - ALLOC_SIZE); /* initialise public members of struct env (not the ALLOC_ITEM) */ ainit(&ep->area); ep->oenv = e; @@ -772,7 +838,8 @@ quitenv(struct shf *shf) /* if ep->savefd[fd] < 0, means fd was closed */ if (ep->savefd[fd]) restfd(fd, ep->savefd[fd]); - if (ep->savefd[2]) /* Clear any write errors */ + if (ep->savefd[2]) + /* Clear any write errors */ shf_reopen(2, SHF_WR, shl_out); } /* @@ -780,7 +847,8 @@ quitenv(struct shf *shf) * Either main shell is exiting or cleanup_parents_env() was called. */ if (ep->oenv == NULL) { - if (ep->type == E_NONE) { /* Main shell exiting? */ + if (ep->type == E_NONE) { + /* Main shell exiting? */ #if HAVE_PERSISTENT_HISTORY if (Flag(FTALKING)) hist_finish(); @@ -946,7 +1014,9 @@ errorf(const char *fmt, ...) { va_list va; - shl_stdout_ok = false; /* debugging: note that stdout not valid */ + /* debugging: note that stdout not valid */ + shl_stdout_ok = false; + exstat = 1; if (*fmt != 1) { error_prefix(true); @@ -982,12 +1052,14 @@ bi_errorf(const char *fmt, ...) { va_list va; - shl_stdout_ok = false; /* debugging: note that stdout not valid */ + /* debugging: note that stdout not valid */ + shl_stdout_ok = false; + exstat = 1; if (*fmt != 1) { error_prefix(true); /* not set when main() calls parse_args() */ - if (builtin_argv0) + if (builtin_argv0 && builtin_argv0 != kshname) shf_fprintf(shl_out, "%s: ", builtin_argv0); va_start(va, fmt); shf_vfprintf(shl_out, fmt, va); @@ -1058,7 +1130,8 @@ shellf(const char *fmt, ...) { va_list va; - if (!initio_done) /* shl_out may not be set up yet... */ + if (!initio_done) + /* shl_out may not be set up yet... */ return; va_start(va, fmt); shf_vfprintf(shl_out, fmt, va); @@ -1094,9 +1167,11 @@ struct shf shf_iob[3]; void initio(void) { - shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */ + /* force buffer allocation */ + shf_fdopen(1, SHF_WR, shl_stdout); shf_fdopen(2, SHF_WR, shl_out); - shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */ + /* force buffer allocation */ + shf_fdopen(2, SHF_WR, shl_spare); initio_done = 1; } @@ -1110,7 +1185,7 @@ ksh_dup2(int ofd, int nfd, bool errok) errorf("too many files open in shell"); #ifdef __ultrix - /* XXX imake style */ + /*XXX imake style */ if (rv >= 0) fcntl(nfd, F_SETFD, 0); #endif @@ -1119,8 +1194,8 @@ ksh_dup2(int ofd, int nfd, bool errok) } /* - * move fd from user space (0<=fd<10) to shell space (fd>=10), - * set close-on-exec flag. + * Move fd from user space (0 <= fd < 10) to shell space (fd >= 10), + * set close-on-exec flag. See FDBASE in sh.h, maybe 24 not 10 here. */ short savefd(int fd) @@ -1141,10 +1216,12 @@ restfd(int fd, int ofd) { if (fd == 2) shf_flush(&shf_iob[fd]); - if (ofd < 0) /* original fd closed */ + if (ofd < 0) + /* original fd closed */ close(fd); else if (fd != ofd) { - ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */ + /*XXX: what to do if this dup fails? */ + ksh_dup2(ofd, fd, true); close(ofd); } } @@ -1366,11 +1443,14 @@ texpand(struct table *tp, size_t nsize) for (i = 0; i < nsize; i++) ntblp[i] = NULL; tp->size = nsize; - tp->nfree = (nsize * 4) / 5; /* table can get 80% full */ + /* table can get 80% full */ + tp->nfree = (nsize * 4) / 5; tp->tbls = ntblp; if (otblp == NULL) return; - nsize--; /* from here on nsize := mask */ + + /* from here on nsize := mask */ + nsize--; for (i = 0; i < osize; i++) if ((tblp = otblp[i]) != NULL) { if ((tblp->flag & DEFINED)) { diff --git a/misc.c b/misc.c index 5c737a3..e03c17d 100644 --- a/misc.c +++ b/misc.c @@ -29,9 +29,10 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.150 2011/01/21 21:04:45 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.151 2011/02/11 01:18:19 tg Exp $"); -unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */ +/* type bits for unsigned char */ +unsigned char chtypes[UCHAR_MAX + 1]; static int do_gmatch(const unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *); @@ -62,7 +63,8 @@ setctypes(const char *s, int t) if (t & C_IFS) { for (i = 0; i < UCHAR_MAX + 1; i++) chtypes[i] &= ~C_IFS; - chtypes[0] |= C_IFS; /* include \0 in C_IFS */ + /* include \0 in C_IFS */ + chtypes[0] |= C_IFS; } while (*s != 0) chtypes[(unsigned char)*s++] |= t; @@ -79,7 +81,8 @@ initctypes(void) chtypes[c] |= C_ALPHA; chtypes['_'] |= C_ALPHA; setctypes("0123456789", C_DIGIT); - setctypes(" \t\n|&;<>()", C_LEX1); /* \0 added automatically */ + /* \0 added automatically */ + setctypes(" \t\n|&;<>()", C_LEX1); setctypes("*@#!$-?", C_VAR1); setctypes(" \t\n", C_IFSWS); setctypes("=-+?", C_SUBOP1); @@ -209,7 +212,8 @@ change_flag(enum sh_flag f, int what, unsigned int newval) unsigned char oldval; oldval = Flag(f); - Flag(f) = newval ? 1 : 0; /* needed for tristates */ + /* needed for tristates */ + Flag(f) = newval ? 1 : 0; #ifndef MKSH_UNEMPLOYED if (f == FMONITOR) { if (what != OF_CMDLINE && newval != oldval) @@ -256,12 +260,14 @@ change_flag(enum sh_flag f, int what, unsigned int newval) } } -/* Parse command line & set command arguments. Returns the index of +/* + * Parse command line and set command arguments. Returns the index of * non-option arguments, -1 if there is an error. */ int parse_args(const char **argv, - int what, /* OF_CMDLINE or OF_SET */ + /* OF_CMDLINE or OF_SET */ + int what, bool *setargsp) { static char cmd_opts[NELEM(options) + 5]; /* o:T:\0 */ @@ -304,7 +310,8 @@ parse_args(const char **argv, if (what == OF_CMDLINE) { const char *p = argv[0], *q; - /* Set FLOGIN before parsing options so user can clear + /* + * Set FLOGIN before parsing options so user can clear * flag using +l. */ if (*p != '-') @@ -332,7 +339,8 @@ parse_args(const char **argv, if (what == OF_FIRSTTIME) break; if (go.optarg == NULL) { - /* lone -o: print options + /* + * lone -o: print options * * Note that on the command line, -o requires * an option (ie, can't get here if what is @@ -351,7 +359,8 @@ parse_args(const char **argv, } #endif if ((i != (size_t)-1) && set == Flag(i)) - /* Don't check the context if the flag + /* + * Don't check the context if the flag * isn't changing - makes "set -o interactive" * work if you're already interactive. Needed * if the output of "set +o" is to be used. @@ -495,7 +504,8 @@ gmatchx(const char *s, const char *p, bool isfile) se = s + strlen(s); pe = p + strlen(p); - /* isfile is false iff no syntax check has been done on + /* + * isfile is false iff no syntax check has been done on * the pattern. If check fails, just to a strcmp(). */ if (!isfile && !has_globbing(p, pe)) { @@ -509,7 +519,8 @@ gmatchx(const char *s, const char *p, bool isfile) (const unsigned char *) p, (const unsigned char *) pe)); } -/* Returns if p is a syntacticly correct globbing pattern, false +/** + * Returns if p is a syntacticly correct globbing pattern, false * if it contains no pattern characters or if there is a syntax error. * Syntax errors are: * - [ with no closing ] @@ -517,14 +528,14 @@ gmatchx(const char *s, const char *p, bool isfile) * - [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d)) */ /*XXX -- if no magic, - if dest given, copy to dst - return ? -- if magic && (no globbing || syntax error) - debunk to dst - return ? -- return ? -*/ + * - if no magic, + * if dest given, copy to dst + * return ? + * - if magic && (no globbing || syntax error) + * debunk to dst + * return ? + * - return ? + */ int has_globbing(const char *xp, const char *xpe) { @@ -532,42 +543,46 @@ has_globbing(const char *xp, const char *xpe) const unsigned char *pe = (const unsigned char *) xpe; int c; int nest = 0, bnest = 0; - int saw_glob = 0; - int in_bracket = 0; /* inside [...] */ + bool saw_glob = false; + /* inside [...] */ + bool in_bracket = false; for (; p < pe; p++) { if (!ISMAGIC(*p)) continue; if ((c = *++p) == '*' || c == '?') - saw_glob = 1; + saw_glob = true; else if (c == '[') { if (!in_bracket) { - saw_glob = 1; - in_bracket = 1; + saw_glob = true; + in_bracket = true; if (ISMAGIC(p[1]) && p[2] == NOT) p += 2; if (ISMAGIC(p[1]) && p[2] == ']') p += 2; } - /* XXX Do we need to check ranges here? POSIX Q */ + /*XXX Do we need to check ranges here? POSIX Q */ } else if (c == ']') { if (in_bracket) { - if (bnest) /* [a*(b]) */ + if (bnest) + /* [a*(b]) */ return (0); - in_bracket = 0; + in_bracket = false; } } else if ((c & 0x80) && vstrchr("*+?@! ", c & 0x7f)) { - saw_glob = 1; + saw_glob = true; if (in_bracket) bnest++; else nest++; } else if (c == '|') { - if (in_bracket && !bnest) /* *(a[foo|bar]) */ + if (in_bracket && !bnest) + /* *(a[foo|bar]) */ return (0); } else if (c == /*(*/ ')') { if (in_bracket) { - if (!bnest--) /* *(a[b)c] */ + if (!bnest--) + /* *(a[b)c] */ return (0); } else if (nest) nest--; @@ -629,8 +644,11 @@ do_gmatch(const unsigned char *s, const unsigned char *se, * [*+?@!](pattern|pattern|..) * This is also needed for ${..%..}, etc. */ - case 0x80|'+': /* matches one or more times */ - case 0x80|'*': /* matches zero or more times */ + + /* matches one or more times */ + case 0x80|'+': + /* matches zero or more times */ + case 0x80|'*': if (!(prest = pat_scan(p, pe, 0))) return (0); s--; @@ -652,9 +670,12 @@ do_gmatch(const unsigned char *s, const unsigned char *se, } return (0); - case 0x80|'?': /* matches zero or once */ - case 0x80|'@': /* matches one of the patterns */ - case 0x80|' ': /* simile for @ */ + /* matches zero or once */ + case 0x80|'?': + /* matches one of the patterns */ + case 0x80|'@': + /* simile for @ */ + case 0x80|' ': if (!(prest = pat_scan(p, pe, 0))) return (0); s--; @@ -675,7 +696,8 @@ do_gmatch(const unsigned char *s, const unsigned char *se, } return (0); - case 0x80|'!': /* matches none of the patterns */ + /* matches none of the patterns */ + case 0x80|'!': if (!(prest = pat_scan(p, pe, 0))) return (0); s--; @@ -733,7 +755,8 @@ cclass(const unsigned char *p, int sub) return (sub == '[' ? orig_p : NULL); if (ISMAGIC(p[0]) && p[1] == '-' && (!ISMAGIC(p[2]) || p[3] != ']')) { - p += 2; /* MAGIC- */ + /* MAGIC- */ + p += 2; d = *p++; if (ISMAGIC(d)) { d = *p++; @@ -789,7 +812,8 @@ ksh_getopt_reset(Getopt *go, int flags) } -/* getopt() used for shell built-in commands, the getopts command, and +/** + * getopt() used for shell built-in commands, the getopts command, and * command line options. * A leading ':' in options means don't print errors, instead return '?' * or ':' and set go->optarg to the offending option character. @@ -830,7 +854,8 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) return (-1); } if (arg == NULL || - ((flag != '-' ) && /* neither a - nor a + (if + allowed) */ + ((flag != '-' ) && + /* neither a - nor a + (if + allowed) */ (!(go->flags & GF_PLUSOPT) || flag != '+')) || (c = arg[1]) == '\0') { go->p = 0; @@ -856,7 +881,8 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) } return ('?'); } - /* : means argument must be present, may be part of option argument + /** + * : means argument must be present, may be part of option argument * or the next argument * ; same as : but argument may be missing * , means argument is part of option argument, and may be null. @@ -888,7 +914,8 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) go->optarg = argv[go->optind - 1] + go->p; go->p = 0; } else if (*o == '#') { - /* argument is optional and may be attached or unattached + /* + * argument is optional and may be attached or unattached * but must start with a digit. optarg is set to 0 if the * argument is missing. */ @@ -909,7 +936,8 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) return (c); } -/* print variable/alias value using necessary quotes +/* + * print variable/alias value using necessary quotes * (POSIX says they should be suitable for re-entry...) * No trailing newline is printed. */ @@ -1025,8 +1053,9 @@ strip_nuls(char *buf, int nbytes) { char *dst; - /* nbytes check because some systems (older FreeBSDs) have a buggy - * memchr() + /* + * nbytes check because some systems (older FreeBSDs) have a + * buggy memchr() */ if (nbytes && (dst = memchr(buf, '\0', nbytes))) { char *end = buf + nbytes; @@ -1116,7 +1145,7 @@ ksh_get_wd(size_t *dlen) return (ret); } -/* +/** * Makes a filename into result using the following algorithm. * - make result NULL * - if file starts with '/', append file to result & set cdpathp to NULL @@ -1133,7 +1162,8 @@ ksh_get_wd(size_t *dlen) */ int make_path(const char *cwd, const char *file, - char **cdpathp, /* & of : separated list */ + /* & of : separated list */ + char **cdpathp, XString *xsp, int *phys_pathp) { @@ -1218,7 +1248,8 @@ simplify_path(char *pathl) if ((isrooted = pathl[0] == '/')) very_start++; - /* Before After + /*- + * Before After * /foo/ /foo * /foo/../../bar /bar * /foo/./blah/.. /foo @@ -1571,7 +1602,7 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int)) /* FALLTHROUGH */ case 'x': i = cstyle ? -1 : 2; - /* + /** * x: look for a hexadecimal number with up to * two (C style: arbitrary) digits; convert * to raw octet (C style: Unicode if >0xFF) diff --git a/mksh.1 b/mksh.1 index ac34602..c79eefe 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.249 2011/02/11 00:41:35 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.250 2011/02/11 01:18:19 tg Exp $ .\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -162,6 +162,8 @@ .Op Ar argument ... .Oc .Ek +.Nm builtin-name +.Op Ar argument ... .Sh DESCRIPTION .Nm is a command interpreter intended for both interactive and shell @@ -170,6 +172,9 @@ Its command language is a superset of the .Xr sh C shell language and largely compatible to the original Korn shell. .Pp +Most builtins can be called directly, for example if a link points from its +name to the shell; not all make sense, have been tested or work at all though. +.Pp The options are as follows: .Bl -tag -width Ds .It Fl c Ar string @@ -3176,8 +3181,8 @@ If the .Ic posix or .Ic sh -option is set, only the first argument is treated as an option, and only -if it is exactly +option is set or this is a direct builtin call, only the first argument +is treated as an option, and only if it is exactly .Dq Fl n . Backslash interpretation is disabled. .Pp @@ -3865,7 +3870,9 @@ is used). Enable UTF-8 support in the .Sx Emacs editing mode and internal string handling functions. -This is enabled automatically for interactive shells if your system supports +This flag is disabled by default, but can be enabled by setting it on the +shell command line; is enabled automatically for interactive shells if +requested at compile time, your system supports .Fn setlocale LC_CTYPE \&"" and optionally .Fn nl_langinfo CODESET , @@ -3878,8 +3885,10 @@ environment variables, and at least one of these returns something that matches .Dq UTF\-8 or -.Dq utf8 , -or if the input begins with a UTF-8 Byte Order Mark. +.Dq utf8 +case-insensitively; for direct builtin calls depending on the +aforementioned environment variables; or for stdin or scripts, +if the input begins with a UTF-8 Byte Order Mark. .It Fl u \*(Ba Ic nounset Referencing of an unset parameter, other than .Dq $@ @@ -3904,7 +3913,7 @@ the value of .It Ic arc4random Deprecated, will be removed in .Nm -R40. +R41. Do not use, emits a warning to stderr. .It Ic bgnice Background jobs are run with lower priority. @@ -4052,6 +4061,7 @@ Suspends execution for a minimum of the .Ar seconds specified as positive decimal value with an optional fractional part. Signal delivery may continue execution earlier. +.Pp .It Ic source Ar file Op Ar arg ... Like .Ic \&. Po Do dot Dc Pc , diff --git a/sh.h b/sh.h index 514ca94..40d22c0 100644 --- a/sh.h +++ b/sh.h @@ -154,9 +154,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.429 2011/02/11 00:41:37 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.430 2011/02/11 01:18:22 tg Exp $"); #endif -#define MKSH_VERSION "R39 2011/02/09" +#define MKSH_VERSION "R39 2011/02/11" #ifndef MKSH_INCLUDES_ONLY @@ -1459,9 +1459,9 @@ int execute(struct op * volatile, volatile int, volatile int * volatile); int shcomexec(const char **); struct tbl *findfunc(const char *, uint32_t, bool); int define(const char *, struct op *); -void builtin(const char *, int (*)(const char **)); +const char *builtin(const char *, int (*)(const char **)); struct tbl *findcom(const char *, int); -void flushcom(int); +void flushcom(bool); const char *search(const char *, const char *, int, int *); int search_access(const char *, int, int *); int pr_menu(const char * const *); diff --git a/sh_flags.h b/sh_flags.h index aa5481e..ee8f865 100644 --- a/sh_flags.h +++ b/sh_flags.h @@ -1,5 +1,5 @@ #if defined(SHFLAGS_DEFNS) -__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.7 2010/07/13 13:07:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.8 2011/02/11 01:18:23 tg Exp $"); #define FN(sname,cname,ochar,flags) /* nothing */ #elif defined(SHFLAGS_ENUMS) #define FN(sname,cname,ochar,flags) cname, @@ -135,6 +135,9 @@ FN(NULL, FCOMMAND, 'c', OF_CMDLINE) * anonymous flags: used internally by shell only (not visible to user) */ +/* ./. direct builtin call (divined from argv[0] multi-call binary) */ +FN(NULL, FAS_BUILTIN, 0, OF_INTERNAL) + /* ./. (internal) initial shell was interactive */ FN(NULL, FTALKING_I, 0, OF_INTERNAL) diff --git a/var.c b/var.c index aeb3e41..1ea9db5 100644 --- a/var.c +++ b/var.c @@ -26,7 +26,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.115 2011/01/21 21:04:48 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.116 2011/02/11 01:18:23 tg Exp $"); /* * Variables @@ -1084,7 +1084,8 @@ setspec(struct tbl *vp) afree(path, APERM); s = str_val(vp); strdupx(path, s, APERM); - flushcom(1); /* clear tracked aliases */ + /* clear tracked aliases */ + flushcom(true); return; case V_IFS: setctypes(s = str_val(vp), C_IFS); @@ -1182,7 +1183,8 @@ unsetspec(struct tbl *vp) if (path) afree(path, APERM); strdupx(path, def_path, APERM); - flushcom(1); /* clear tracked aliases */ + /* clear tracked aliases */ + flushcom(true); break; case V_IFS: setctypes(" \t\n", C_IFS);