• more comment and int→bool cleanup, add and improve some comments

• in interactive mode, always look up {LC_{ALL,CTYPE},LANG} environment
  variables if setlocale/nl_langinfo(CODESET) doesn’t suffice
• add the ability to call any builtin (some don't make sense or wouldn't
  work) directly by analysing argv[0]
• for direct builtin calls, the {LC_{ALL,CTYPE},LANG} environment
  variables determine utf8-mode, even if MKSH_ASSUME_UTF8 was set
• when called as builtin, echo behaves POSIXish
• add domainname as alias for true on MirBSD only, to be able to link it
• sync mksh Makefiles with Build.sh output
• adjust manpage wrt release plans
• link some things to mksh now that we have callable builtins:
  bin/echo bin/kill bin/pwd bin/sleep (exact matches)
  bin/test bin/[ (were scripts before)
  bin/domainname=usr/bin/true usr/bin/false (move to /bin/ now)
• drop linked utilities and, except for echo and kill, their manpages
• adjust instbin and link a few more there as well
This commit is contained in:
tg 2011-02-11 01:18:23 +00:00
parent 81b80af47a
commit a796512040
10 changed files with 425 additions and 232 deletions

View File

@ -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 <tg@mirbsd.org>
#
# 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

View File

@ -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:

162
exec.c
View File

@ -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=<<EOF' */
if (
/* we have zero arguments, i.e. no programme to run */
@ -474,14 +476,16 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
volatile int rv = 0;
const char *cp;
const char **lastp;
static struct op texec; /* Must be static (XXX but why?) */
/* Must be static (XXX but why?) */
static struct op texec;
int type_flags;
int keepasn_ok;
int fcflags = FC_BI|FC_FUNC|FC_PATH;
bool bourne_function_call = false;
struct block *l_expand, *l_assign;
/* snag the last argument for $_ XXX not the same as AT&T ksh,
/*
* snag the last argument for $_ XXX not the same as AT&T ksh,
* which only seems to set $_ after a newline (but not in
* functions/dot scripts, but in interactive and script) -
* perhaps save last arg here and set it in shell()?.
@ -494,7 +498,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
KSH_RETURN_ERROR);
}
/* Deal with the shell builtins builtin, exec and command since
/**
* Deal with the shell builtins builtin, exec and command since
* they can be followed by other commands. This must be done before
* we know if we should create a local block which must be done
* before we can do a path search (in case the assignments change
@ -527,14 +532,16 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
} else if (tp->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 <sys/param.h> */
/* 64 == MAXINTERP in MirBSD <sys/param.h> */
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];

16
funcs.c
View File

@ -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)
{

274
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h>
#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)) {

129
misc.c
View File

@ -29,9 +29,10 @@
#include <grp.h>
#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)

24
mksh.1
View File

@ -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 ,

8
sh.h
View File

@ -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 *);

View File

@ -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)

8
var.c
View File

@ -26,7 +26,7 @@
#include <sys/sysctl.h>
#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);