Merge tag 'mksh-R53' into HEAD

Conflicts:
    exec.c
This commit is contained in:
KO Myung-Hun 2016-08-13 15:05:49 +09:00
commit d4be6d4358
23 changed files with 1612 additions and 1024 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.698 2016/06/25 23:49:12 tg Exp $'
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.702 2016/08/10 18:20:16 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016
@ -596,7 +596,6 @@ else
check_categories="$check_categories shell:legacy-yes"
add_cppflags -DMKSH_LEGACY_MODE
HAVE_PERSISTENT_HISTORY=0
HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1 # from sh.h
fi
if test x"$srcdir" = x"."; then
@ -691,7 +690,6 @@ case $TARGET_OS in
: "${HAVE_CAN_OTWO=0}"
add_cppflags -DMKSH_NO_SIGSETJMP
add_cppflags -DMKSH_TYPEDEF_SIG_ATOMIC_T=int
add_cppflags -DMKSH_CONSERVATIVE_FDS
;;
AIX)
add_cppflags -D_ALL_SOURCE
@ -721,7 +719,6 @@ Coherent)
add_cppflags -DMKSH__NO_SYMLINK
check_categories="$check_categories nosymlink"
add_cppflags -DMKSH__NO_SETEUGID
add_cppflags -DMKSH_CONSERVATIVE_FDS
add_cppflags -DMKSH_DISABLE_TTY_WARNING
;;
CYGWIN*)
@ -737,7 +734,6 @@ FreeBSD)
FreeMiNT)
oswarn="; it has minor issues"
add_cppflags -D_GNU_SOURCE
add_cppflags -DMKSH_CONSERVATIVE_FDS
: "${HAVE_SETLOCALE_CTYPE=0}"
;;
GNU)
@ -787,14 +783,12 @@ MidnightBSD)
Minix-vmd)
add_cppflags -DMKSH__NO_SETEUGID
add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_CONSERVATIVE_FDS
add_cppflags -D_MINIX_SOURCE
oldish_ed=no-stderr-ed # no /bin/ed, maybe see below
: "${HAVE_SETLOCALE_CTYPE=0}"
;;
Minix3)
add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_CONSERVATIVE_FDS
add_cppflags -DMKSH_NO_LIMITS
add_cppflags -D_POSIX_SOURCE -D_POSIX_1_SOURCE=2 -D_MINIX
oldish_ed=no-stderr-ed # /usr/bin/ed(!) is broken
@ -825,12 +819,10 @@ NEXTSTEP)
oswarn="; it needs libposix.a"
;;
esac
add_cppflags -DMKSH_CONSERVATIVE_FDS
;;
Ninix3)
# similar to Minix3
add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_CONSERVATIVE_FDS
add_cppflags -DMKSH_NO_LIMITS
# but no idea what else could be needed
oswarn="; it has unknown issues"
@ -900,7 +892,6 @@ SCO_SV)
oswarn="$oswarn$nl$TARGET_OS ${TARGET_OSREV}, please tell me what to do"
;;
esac
add_cppflags -DMKSH_CONSERVATIVE_FDS
: "${HAVE_SYS_SIGLIST=0}${HAVE__SYS_SIGLIST=0}"
;;
skyos)
@ -918,12 +909,10 @@ syllable)
ULTRIX)
: "${CC=cc -YPOSIX}"
add_cppflags -DMKSH_TYPEDEF_SSIZE_T=int
add_cppflags -DMKSH_CONSERVATIVE_FDS
: "${HAVE_SETLOCALE_CTYPE=0}"
;;
UnixWare|UNIX_SV)
# SCO UnixWare
add_cppflags -DMKSH_CONSERVATIVE_FDS
: "${HAVE_SYS_SIGLIST=0}${HAVE__SYS_SIGLIST=0}"
;;
UWIN*)
@ -1116,6 +1105,7 @@ clang)
:*) ;;
*:) CCC_LD=$CCC_CC; export CCC_LD ;;
esac
: "${HAVE_STRING_POOLING=i1}"
;;
dec)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
@ -1132,6 +1122,7 @@ gcc)
vv '|' 'echo `$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS \
-dumpmachine` gcc`$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN \
$LIBS -dumpversion`'
: "${HAVE_STRING_POOLING=i2}"
;;
hpcc)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -V conftest.c $LIBS"
@ -1528,6 +1519,16 @@ if test 1 = $i; then
ac_flags 1 fwrapv -fwrapv
fi
# “on demand” means: GCC version >= 4
fd='if to rely on compiler for string pooling'
ac_cache string_pooling || case $HAVE_STRING_POOLING in
2) fx=' (on demand, cached)' ;;
i1) fv=1 ;;
i2) fv=2; fx=' (on demand)' ;;
esac
ac_testdone
test x"$HAVE_STRING_POOLING" = x"0" || ac_cppflags
phase=x
# The following tests run with -Werror or similar (all compilers) if possible
NOWARN=$DOWARN
@ -1635,7 +1636,6 @@ if ac_ifcpp 'ifdef MKSH_SMALL' isset_MKSH_SMALL '' \
: "${HAVE_NICE=0}"
: "${HAVE_PERSISTENT_HISTORY=0}"
check_categories="$check_categories smksh"
HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1 # from sh.h
fi
ac_ifcpp 'if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)' \
isset_MKSH_BINSH '' 'if invoking as sh should be handled specially' && \
@ -1648,12 +1648,6 @@ ac_ifcpp 'ifdef MKSH_NOPROSPECTOFWORK' isset_MKSH_NOPROSPECTOFWORK '' \
check_categories="$check_categories arge nojsig"
ac_ifcpp 'ifdef MKSH_ASSUME_UTF8' isset_MKSH_ASSUME_UTF8 '' \
'if the default UTF-8 mode is specified' && : "${HAVE_SETLOCALE_CTYPE=0}"
if ac_ifcpp 'ifdef MKSH_CONSERVATIVE_FDS' isset_MKSH_CONSERVATIVE_FDS '' \
'if traditional/conservative fd use is requested'; then
check_categories="$check_categories convfds"
else
echo >&2 "WARNING: not building with -DMKSH_CONSERVATIVE_FDS is deprecated"
fi
#ac_ifcpp 'ifdef MKSH_DISABLE_DEPRECATED' isset_MKSH_DISABLE_DEPRECATED '' \
# "if deprecated features are to be omitted" && \
# check_categories="$check_categories nodeprecated"
@ -2350,7 +2344,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
add_cppflags -DMKSH_BUILD_R=523
add_cppflags -DMKSH_BUILD_R=530
$e $bi$me: Finished configuration testing, now producing output.$ao
@ -2506,7 +2500,7 @@ echo tcfn=$mkshexe >>Rebuild.sh
echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh
if test $cm = makefile; then
extras='emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h'
extras='emacsfn.h exprtok.h rlimits.opt sh.h sh_flags.opt var_spec.h'
test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc"
gens= genq=
for file in $optfiles; do
@ -2656,9 +2650,7 @@ MKSH_A4PB force use of arc4random_pushb
MKSH_ASSUME_UTF8 (0=disabled, 1=enabled; default: unset)
MKSH_BINSHPOSIX if */sh or */-sh, enable set -o posix
MKSH_BINSHREDUCED if */sh or */-sh, enable set -o sh
MKSH_CLRTOEOL_STRING "\033[K"
MKSH_CLS_STRING "\033[;H\033[J"
MKSH_CONSERVATIVE_FDS fd 0-9 for scripts, shell only up to 31 (soon default)
MKSH_DEFAULT_EXECSHELL "/bin/sh" (do not change)
MKSH_DEFAULT_PROFILEDIR "/etc" (do not change)
MKSH_DEFAULT_TMPDIR "/tmp" (do not change)

107
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.739 2016/06/26 00:44:55 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.750 2016/08/10 18:20:03 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
@(#)MIRBSD KSH R52 2016/06/25
@(#)MIRBSD KSH R53 2016/08/04
description:
Check version of shell.
stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
@(#)LEGACY KSH R52 2016/06/25
@(#)LEGACY KSH R53 2016/08/04
description:
Check version of legacy shell.
stdin:
@ -359,6 +359,18 @@ stdin:
expected-stdout:
20
---
name: arith-prec-1
description:
Prove arithmetic expressions with embedded parameter
substitutions cannot be parsed ahead of time
stdin:
a='3 + 4'
print 1 $((2 * a)) .
print 2 $((2 * $a)) .
expected-stdout:
1 14 .
2 10 .
---
name: arith-div-assoc-1
description:
Check associativity of division operator
@ -1779,6 +1791,41 @@ stdin:
expected-stdout:
1 .
---
name: expand-slashes-1
description:
Check that side effects in substring replacement are handled correctly
stdin:
foo=n1n1n1n2n3
i=2
n=1
echo 1 ${foo//n$((n++))/[$((++i))]} .
echo 2 $n , $i .
expected-stdout:
1 [3][3][3]n2n3 .
2 2 , 3 .
---
name: expand-slashes-2
description:
Check that side effects in substring replacement are handled correctly
stdin:
foo=n1n1n1n2n3
i=2
n=1
echo 1 ${foo@/n$((n++))/[$((++i))]} .
echo 2 $n , $i .
expected-stdout:
1 [3]n1n1[4][5] .
2 5 , 5 .
---
name: expand-slashes-3
description:
Check that we can access the replaced string
stdin:
foo=n1n1n1n2n3
echo 1 ${foo@/n[12]/[$KSH_MATCH]} .
expected-stdout:
1 [n1][n1][n1][n2]n3 .
---
name: eglob-bad-1
description:
Check that globbing isn't done when glob has syntax error
@ -6370,6 +6417,12 @@ expected-stdout:
ac_space=' '
ac_newline=$'\n'
---
name: regression-67
description:
Check that we can both break and use source on the same line
stdin:
for s in s; do break; done; print -s s
---
name: readonly-0
description:
Ensure readonly is honoured for assignments and unset
@ -9118,6 +9171,16 @@ stdin:
expected-stdout-pattern:
/^4 3 2 <> <\0>$/
---
name: print-array
description:
Check that print -A works as expected
stdin:
print -An 0x20AC 0xC3 0xBC 8#101
set -U
print -A 0x20AC 0xC3 0xBC 8#102
expected-stdout:
¬Ã¼¬ÃƒÂ¼B
---
name: print-escapes
description:
Check backslash expansion by the print builtin
@ -9304,6 +9367,17 @@ expected-exit: e != 0
expected-stderr-pattern:
/\.: missing argument.*\n.*source: missing argument/
---
name: dot-errorlevel
description:
Ensure dot resets $?
stdin:
:>dotfile
(exit 42)
. ./dotfile
echo 1 $? .
expected-stdout:
1 0 .
---
name: alias-function-no-conflict
description:
make aliases not conflict with function definitions
@ -10116,29 +10190,6 @@ expected-stdout:
2 = bar .
3 = bar .
---
name: mkshiop-1
description:
Check for support of more than 9 file descriptors
category: !convfds
stdin:
read -u10 foo 10<<< bar
echo x$foo
expected-stdout:
xbar
---
name: mkshiop-2
description:
Check for support of more than 9 file descriptors
category: !convfds
stdin:
exec 12>foo
print -u12 bar
echo baz >&12
cat foo
expected-stdout:
bar
baz
---
name: oksh-eval
description:
Check expansions.
@ -10373,6 +10424,8 @@ name: fd-cloexec-1
description:
Verify that file descriptors > 2 are private for Korn shells
AT&T ksh93 does this still, which means we must keep it as well
XXX fails on some old Perl installations
need-pass: no
category: shell:legacy-no
stdin:
cat >cld <<-EOF
@ -10391,6 +10444,8 @@ name: fd-cloexec-2
description:
Verify that file descriptors > 2 are not private for POSIX shells
See Debian Bug #154540, Closes: #499139
XXX fails on some old Perl installations
need-pass: no
stdin:
cat >cld <<-EOF
#!$__perlname

View File

@ -1,5 +1,5 @@
# $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.105 2016/04/09 16:33:23 tg Exp $
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.108 2016/07/26 22:03:41 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016
@ -40,8 +40,8 @@ PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
(( e )) && REPLY+="$e|"
REPLY+=${USER}@${HOSTNAME%%.*}:
\typeset d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/\~}
\typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
\typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
d=${d%/}; \typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d
@ -365,8 +365,8 @@ function Lbafh_finish {
((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
((Lbafh_v << 1) & 0xFEFEFEFE) ))
((# Lbafh_v = t ^ (t >>> 8) ^ (Lbafh_v >>> 8) ^ \
(Lbafh_v >>> 16) ^ (Lbafh_v >>> 24) ))
((# Lbafh_v = t ^ (t ^> 8) ^ (Lbafh_v ^> 8) ^ \
(Lbafh_v ^> 16) ^ (Lbafh_v ^> 24) ))
\:
}
@ -478,6 +478,7 @@ function enable {
# accumulate functions from dot.mkshrc, in definition order
i_func[nfunc++]=hd
i_func[nfunc++]=chpwd
i_func[nfunc++]=cd
i_func[nfunc++]=cd_csh
i_func[nfunc++]=dirs
i_func[nfunc++]=popd

474
edit.c
View File

@ -28,7 +28,7 @@
#ifndef MKSH_NO_CMDLINE_EDITING
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.296 2016/05/05 22:56:12 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.306 2016/08/01 18:42:40 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
@ -39,21 +39,28 @@ __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.296 2016/05/05 22:56:12 tg Exp $");
#ifndef MKSH_CLS_STRING
#define MKSH_CLS_STRING "\033[;H\033[J"
#endif
#ifndef MKSH_CLRTOEOL_STRING
#define MKSH_CLRTOEOL_STRING "\033[K"
#endif
/* tty driver characters we are interested in */
typedef struct {
int erase;
int kill;
int werase;
int intr;
int quit;
int eof;
} X_chars;
#define EDCHAR_DISABLED 0xFFFFU
#define EDCHAR_INITIAL 0xFFFEU
static struct {
unsigned short erase;
unsigned short kill;
unsigned short werase;
unsigned short intr;
unsigned short quit;
unsigned short eof;
} edchars;
static X_chars edchars;
#define isched(x,e) ((unsigned short)(unsigned char)(x) == (e))
#define isedchar(x) (!((x) & ~0xFF))
#ifndef _POSIX_VDISABLE
#define toedchar(x) ((unsigned short)(unsigned char)(x))
#else
#define toedchar(x) (((_POSIX_VDISABLE != -1) && ((x) == _POSIX_VDISABLE)) ? \
((unsigned short)EDCHAR_DISABLED) : \
((unsigned short)(unsigned char)(x)))
#endif
/* x_cf_glob() flags */
#define XCF_COMMAND BIT(0) /* Do command completion */
@ -68,6 +75,10 @@ static int xx_cols; /* for Emacs mode */
static int modified; /* buffer has been "modified" */
static char *holdbufp; /* place to hold last edit buffer */
/* 0=dumb 1=tmux (for now) */
static bool x_term_mode;
static void x_adjust(void);
static int x_getc(void);
static void x_putcf(int);
static void x_modified(void);
@ -78,7 +89,7 @@ static int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
static size_t x_longest_prefix(int, char * const *);
static void x_glob_hlp_add_qchar(char *);
static char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
static int x_basename(const char *, const char *);
static size_t x_basename(const char *, const char *);
static void x_free_words(int, char **);
static int x_escape(const char *, size_t, int (*)(const char *, size_t));
static int x_emacs(char *);
@ -102,7 +113,6 @@ static int x_command_glob(int, char *, char ***);
static int x_locate_word(const char *, int, int, int *, bool *);
static int x_e_getmbc(char *);
static int x_e_rebuildline(const char *);
/* +++ generic editing functions +++ */
@ -152,7 +162,7 @@ x_getc(void)
/* redraw line in Emacs mode */
xx_cols = x_cols;
x_init_prompt(false);
x_e_rebuildline(MKSH_CLRTOEOL_STRING);
x_adjust();
}
}
#endif
@ -230,7 +240,7 @@ static void
x_print_expansions(int nwords, char * const *words, bool is_command)
{
bool use_copy = false;
int prefix_len;
size_t prefix_len;
XPtrV l = { NULL, 0, 0 };
/*
@ -336,7 +346,7 @@ x_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
*--cp = '/';
} else {
/* ok, expand and replace */
cp = shf_smprintf("%s/%s", dp, cp);
cp = shf_smprintf(Tf_sSs, dp, cp);
if (magic_flag)
afree(s, ATEMP);
s = cp;
@ -439,8 +449,8 @@ x_file_glob(int *flagsp, char *toglob, char ***wordsp)
/* Data structure used in x_command_glob() */
struct path_order_info {
char *word;
int base;
int path_order;
size_t base;
size_t path_order;
};
/* Compare routine used in x_command_glob() */
@ -451,8 +461,13 @@ path_order_cmp(const void *aa, const void *bb)
const struct path_order_info *b = (const struct path_order_info *)bb;
int t;
t = strcmp(a->word + a->base, b->word + b->base);
return (t ? t : a->path_order - b->path_order);
if ((t = strcmp(a->word + a->base, b->word + b->base)))
return (t);
if (a->path_order > b->path_order)
return (1);
if (a->path_order < b->path_order)
return (-1);
return (0);
}
static int
@ -475,7 +490,7 @@ x_command_glob(int flags, char *toglob, char ***wordsp)
glob_table(pat, &w, &l->funs);
glob_path(flags, pat, &w, path);
if ((fpath = str_val(global("FPATH"))) != null)
if ((fpath = str_val(global(TFPATH))) != null)
glob_path(flags, pat, &w, fpath);
nwords = XPsize(w);
@ -720,7 +735,7 @@ x_free_words(int nwords, char **words)
* /// 2
* 0
*/
static int
static size_t
x_basename(const char *s, const char *se)
{
const char *p;
@ -832,12 +847,11 @@ static int
x_escape(const char *s, size_t len, int (*putbuf_func)(const char *, size_t))
{
size_t add = 0, wlen = len;
const char *ifs = str_val(local("IFS", 0));
int rval = 0;
while (wlen - add > 0)
if (vstrchr("\"#$&'()*:;<=>?[\\`{|}", s[add]) ||
vstrchr(ifs, s[add])) {
ctype(s[add], C_IFS)) {
if (putbuf_func(s, add) != 0) {
rval = -1;
break;
@ -965,7 +979,6 @@ static size_t x_fword(bool);
static void x_goto(char *);
static char *x_bs0(char *, char *) MKSH_A_PURE;
static void x_bs3(char **);
static int x_size_str(char *);
static int x_size2(char *, char **);
static void x_zots(char *);
static void x_zotc3(char **);
@ -976,12 +989,11 @@ static int x_search_dir(int);
#endif
static int x_match(char *, char *);
static void x_redraw(int);
static void x_push(int);
static void x_push(size_t);
static char *x_mapin(const char *, Area *);
static char *x_mapout(int);
static void x_mapout2(int, char **);
static void x_print(int, int);
static void x_adjust(void);
static void x_e_ungetc(int);
static int x_e_getc(void);
static void x_e_putc2(int);
@ -991,6 +1003,7 @@ static void x_e_puts(const char *);
static int x_fold_case(int);
#endif
static char *x_lastcp(void);
static void x_lastpos(void);
static void do_complete(int, Comp_type);
static size_t x_nb2nc(size_t) MKSH_A_PURE;
@ -1126,6 +1139,7 @@ static struct x_defbindings const x_defbindings[] = {
#endif
#ifndef MKSH_SMALL
/* more non-standard ones */
{ XFUNC_eval_region, 1, CTRL('E') },
{ XFUNC_edit_line, 2, 'e' }
#endif
};
@ -1187,6 +1201,12 @@ x_e_getmbc(char *sbuf)
return (pos);
}
/*
* minimum required space to work with on a line - if the prompt
* leaves less space than this on a line, the prompt is truncated
*/
#define MIN_EDIT_SPACE 7
static void
x_init_prompt(bool doprint)
{
@ -1379,15 +1399,9 @@ x_ins(const char *s)
x_lastcp();
x_adj_ok = tobool(xcp >= xlp);
x_zots(cp);
/* has x_adjust() been called? */
if (adj == x_adj_done) {
/* no */
cp = xlp;
while (cp > xcp)
x_bs3(&cp);
}
if (xlp == xep - 1)
x_redraw(xx_cols);
if (adj == x_adj_done)
/* x_adjust() has not been called */
x_lastpos();
x_adj_ok = true;
return (0);
}
@ -1494,10 +1508,7 @@ x_delete(size_t nc, bool push)
/*x_goto(xcp);*/
x_adj_ok = true;
xlp_valid = false;
cp = x_lastcp();
while (cp > xcp)
x_bs3(&cp);
x_lastpos();
x_modified();
return;
}
@ -1616,15 +1627,6 @@ x_bs3(char **p)
x_e_putc2('\b');
}
static int
x_size_str(char *cp)
{
int size = 0;
while (*cp)
size += x_size2(cp, &cp);
return (size);
}
static int
x_size2(char *cp, char **dcp)
{
@ -1660,7 +1662,7 @@ x_zotc3(char **cp)
if (c == '\t') {
/* Kludge, tabs are always four spaces. */
x_e_puts(" ");
x_e_puts(T4spaces);
(*cp)++;
} else if (ISCTRL(c) && /* but not C1 */ c < 0x80) {
x_e_putc2('^');
@ -1774,9 +1776,11 @@ x_newline(int c MKSH_A_UNUSED)
static int
x_end_of_text(int c MKSH_A_UNUSED)
{
char tmp = edchars.eof;
char *cp = &tmp;
unsigned char tmp;
char *cp = (void *)&tmp;
tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
(unsigned char)CTRL('D');
x_zotc3(&cp);
x_putc('\r');
x_putc('\n');
@ -1830,7 +1834,6 @@ x_goto_hist(int c MKSH_A_UNUSED)
static void
x_load_hist(char **hp)
{
int oldsize;
char *sp = NULL;
if (hp == histptr + 1) {
@ -1843,17 +1846,12 @@ x_load_hist(char **hp)
if (sp == NULL)
sp = *hp;
x_histp = hp;
oldsize = x_size_str(xbuf);
if (modified)
strlcpy(holdbufp, xbuf, LINE);
strlcpy(xbuf, sp, xend - xbuf);
xbp = xbuf;
xep = xcp = xbuf + strlen(xbuf);
xlp_valid = false;
if (xep <= x_lastcp()) {
x_redraw(oldsize);
}
x_goto(xep);
x_adjust();
modified = 0;
}
@ -1956,7 +1954,7 @@ x_search_hist(int c)
}
}
if (offset < 0)
x_redraw(-1);
x_redraw('\n');
return (KSTD);
}
@ -2031,18 +2029,13 @@ x_match(char *str, char *pat)
static int
x_del_line(int c MKSH_A_UNUSED)
{
int i, j;
*xep = 0;
i = xep - xbuf;
j = x_size_str(xbuf);
xcp = xbuf;
x_push(i);
x_push(xep - (xcp = xbuf));
xlp = xbp = xep = xbuf;
xlp_valid = true;
*xcp = 0;
xmp = NULL;
x_redraw(j);
x_redraw('\r');
x_modified();
return (KSTD);
}
@ -2064,89 +2057,82 @@ x_mv_begin(int c MKSH_A_UNUSED)
static int
x_draw_line(int c MKSH_A_UNUSED)
{
x_redraw(-1);
return (KSTD);
}
static int
x_e_rebuildline(const char *clrstr)
{
shf_puts(clrstr, shl_out);
x_adjust();
x_redraw('\n');
return (KSTD);
}
static int
x_cls(int c MKSH_A_UNUSED)
{
return (x_e_rebuildline(MKSH_CLS_STRING));
shf_puts(MKSH_CLS_STRING, shl_out);
x_redraw(0);
return (KSTD);
}
/*
* Redraw (part of) the line. If limit is < 0, the everything is redrawn
* on a NEW line, otherwise limit is the screen column up to which needs
* redrawing.
* clear line from x_col (current cursor position) to xx_cols - 2,
* then output lastch, then go back to x_col; if lastch is space,
* clear with termcap instead of spaces, or not if line_was_cleared;
* lastch MUST be an ASCII character with wcwidth(lastch) == 1
*/
static void
x_redraw(int limit)
x_clrtoeol(int lastch, bool line_was_cleared)
{
int i, j;
char *cp;
int col;
if (lastch == ' ' && !line_was_cleared && x_term_mode == 1) {
shf_puts("\033[K", shl_out);
line_was_cleared = true;
}
if (lastch == ' ' && line_was_cleared)
return;
col = x_col;
while (col < (xx_cols - 2)) {
x_putc(' ');
++col;
}
x_putc(lastch);
++col;
while (col > x_col) {
x_putc('\b');
--col;
}
}
/* output the prompt, assuming a line has just been started */
static void
x_pprompt(void)
{
if (prompt_trunc != -1)
pprompt(prompt, prompt_trunc);
x_col = pwidth;
}
/* output CR, then redraw the line, clearing to EOL if needed (cr ≠ 0, LF) */
static void
x_redraw(int cr)
{
int lch;
x_adj_ok = false;
if (limit == -1)
x_e_putc2('\n');
else
x_e_putc2('\r');
/* clear the line */
x_e_putc2(cr ? cr : '\r');
x_flush();
if (xbp == xbuf) {
if (prompt_trunc != -1)
pprompt(prompt, prompt_trunc);
x_col = pwidth;
}
/* display the prompt */
if (xbp == xbuf)
x_pprompt();
x_displen = xx_cols - 2 - x_col;
/* display the line content */
xlp_valid = false;
x_zots(xbp);
if (xbp != xbuf || xep > xlp)
limit = xx_cols;
if (limit >= 0) {
if (xep > xlp)
/* we fill the line */
i = 0;
else {
char *cpl = xbp;
i = limit;
while (cpl < xlp)
i -= x_size2(cpl, &cpl);
}
j = 0;
while ((j < i) || (x_col < (xx_cols - 2))) {
if (!(x_col < (xx_cols - 2)))
break;
x_e_putc2(' ');
j++;
}
i = ' ';
if (xep > xlp) {
/* more off screen */
if (xbp > xbuf)
i = '*';
else
i = '>';
} else if (xbp > xbuf)
i = '<';
x_e_putc2(i);
j++;
while (j--)
x_e_putc2('\b');
}
cp = xlp;
while (cp > xcp)
x_bs3(&cp);
/* check whether there is more off-screen */
lch = xep > xlp ? (xbp > xbuf ? '*' : '>') : (xbp > xbuf) ? '<' : ' ';
/* clear the rest of the line */
x_clrtoeol(lch, !cr || cr == '\n');
/* go back to actual cursor position */
x_lastpos();
x_adj_ok = true;
return;
}
static int
@ -2264,7 +2250,7 @@ x_kill(int c MKSH_A_UNUSED)
}
static void
x_push(int nchars)
x_push(size_t nchars)
{
afree(killstack[killsp], AEDIT);
strndupx(killstack[killsp], xcp, nchars, AEDIT);
@ -2281,7 +2267,7 @@ x_yank(int c MKSH_A_UNUSED)
killtp--;
if (killstack[killtp] == 0) {
x_e_puts("\nnothing to yank");
x_redraw(-1);
x_redraw('\n');
return (KSTD);
}
xmp = xcp;
@ -2298,7 +2284,7 @@ x_meta_yank(int c MKSH_A_UNUSED)
killstack[killtp] == 0) {
killtp = killsp;
x_e_puts("\nyank something first");
x_redraw(-1);
x_redraw('\n');
return (KSTD);
}
len = strlen(killstack[killtp]);
@ -2447,7 +2433,7 @@ x_print(int prefix, int key)
shprintf("%s%s = ", x_mapout(key), (f & 0x80) ? "~" : "");
if (XFUNC_VALUE(f) != XFUNC_ins_string)
#endif
shprintf("%s\n", x_ftab[XFUNC_VALUE(f)].xf_name);
shprintf(Tf_sN, x_ftab[XFUNC_VALUE(f)].xf_name);
#ifndef MKSH_SMALL
else
shprintf("'%s'\n", x_atab[prefix][key]);
@ -2479,7 +2465,7 @@ x_bind(const char *a1, const char *a2,
if (list) {
for (f = 0; f < NELEM(x_ftab); f++)
if (!(x_ftab[f].xf_flags & XF_NOBIND))
shprintf("%s\n", x_ftab[f].xf_name);
shprintf(Tf_sN, x_ftab[f].xf_name);
return (0);
}
if (a1 == NULL) {
@ -2713,7 +2699,7 @@ x_expand(int c MKSH_A_UNUSED)
i = 0;
while (i < nwords) {
if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
(++i < nwords && x_ins(" ") < 0)) {
(++i < nwords && x_ins(T1space) < 0)) {
x_e_putc2(7);
return (KSTD);
}
@ -2798,7 +2784,7 @@ do_complete(
*/
if (nwords == 1 && !mksh_dirsep(words[0][nlen - 1]) &&
!(flags & XCF_IS_NOSPACE)) {
x_ins(" ");
x_ins(T1space);
}
x_free_words(nwords, words);
@ -2858,7 +2844,7 @@ x_adjust(void)
x_adjust_out:
xlp_valid = false;
x_redraw(xx_cols);
x_redraw('\r');
x_flush();
}
@ -3019,7 +3005,6 @@ x_set_arg(int c)
static int
x_comment(int c MKSH_A_UNUSED)
{
int oldsize = x_size_str(xbuf);
ssize_t len = xep - xbuf;
int ret = x_do_comment(xbuf, xend - xbuf, &len);
@ -3030,7 +3015,7 @@ x_comment(int c MKSH_A_UNUSED)
xep = xbuf + len;
*xep = '\0';
xcp = xbp = xbuf;
x_redraw(oldsize);
x_redraw('\r');
if (ret > 0)
return (x_newline('\n'));
}
@ -3042,15 +3027,13 @@ x_version(int c MKSH_A_UNUSED)
{
char *o_xbuf = xbuf, *o_xend = xend;
char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
int lim = x_lastcp() - xbp;
size_t vlen;
char *v;
strdupx(v, KSH_VERSION, ATEMP);
xbuf = xbp = xcp = v;
xend = xep = v + (vlen = strlen(v));
x_redraw(lim);
xend = xep = v + strlen(v);
x_redraw('\r');
x_flush();
c = x_e_getc();
@ -3059,7 +3042,7 @@ x_version(int c MKSH_A_UNUSED)
xbp = o_xbp;
xep = o_xep;
xcp = o_xcp;
x_redraw((int)vlen);
x_redraw('\r');
if (c < 0)
return (KSTD);
@ -3088,7 +3071,7 @@ x_edit_line(int c MKSH_A_UNUSED)
x_arg = source->line - (histptr - x_histp);
}
if (x_arg)
shf_snprintf(xbuf, xend - xbuf, "%s %d",
shf_snprintf(xbuf, xend - xbuf, Tf_sd,
"fc -e ${VISUAL:-${EDITOR:-vi}} --", x_arg);
else
strlcpy(xbuf, "fc -e ${VISUAL:-${EDITOR:-vi}} --", xend - xbuf);
@ -3263,22 +3246,10 @@ x_fold_case(int c)
* NAME:
* x_lastcp - last visible char
*
* SYNOPSIS:
* x_lastcp()
*
* DESCRIPTION:
* This function returns a pointer to that char in the
* edit buffer that will be the last displayed on the
* screen. The sequence:
*
* cp = x_lastcp();
* while (cp > xcp)
* x_bs3(&cp);
*
* Will position the cursor correctly on the screen.
*
* RETURN VALUE:
* cp or NULL
* screen.
*/
static char *
x_lastcp(void)
@ -3300,6 +3271,16 @@ x_lastcp(void)
return (xlp);
}
/* correctly position the cursor on the screen from end of visible area */
static void
x_lastpos(void)
{
char *cp = x_lastcp();
while (cp > xcp)
x_bs3(&cp);
}
static void
x_mode(bool onoff)
{
@ -3312,13 +3293,13 @@ x_mode(bool onoff)
if (onoff) {
x_mkraw(tty_fd, NULL, false);
edchars.erase = tty_state.c_cc[VERASE];
edchars.kill = tty_state.c_cc[VKILL];
edchars.intr = tty_state.c_cc[VINTR];
edchars.quit = tty_state.c_cc[VQUIT];
edchars.eof = tty_state.c_cc[VEOF];
edchars.erase = toedchar(tty_state.c_cc[VERASE]);
edchars.kill = toedchar(tty_state.c_cc[VKILL]);
edchars.intr = toedchar(tty_state.c_cc[VINTR]);
edchars.quit = toedchar(tty_state.c_cc[VQUIT]);
edchars.eof = toedchar(tty_state.c_cc[VEOF]);
#ifdef VWERASE
edchars.werase = tty_state.c_cc[VWERASE];
edchars.werase = toedchar(tty_state.c_cc[VWERASE]);
#else
edchars.werase = 0;
#endif
@ -3336,33 +3317,17 @@ x_mode(bool onoff)
if (!edchars.werase)
edchars.werase = CTRL('W');
#ifdef _POSIX_VDISABLE
/* Convert unset values to internal 'unset' value */
if (edchars.erase == _POSIX_VDISABLE)
edchars.erase = -1;
if (edchars.kill == _POSIX_VDISABLE)
edchars.kill = -1;
if (edchars.intr == _POSIX_VDISABLE)
edchars.intr = -1;
if (edchars.quit == _POSIX_VDISABLE)
edchars.quit = -1;
if (edchars.eof == _POSIX_VDISABLE)
edchars.eof = -1;
if (edchars.werase == _POSIX_VDISABLE)
edchars.werase = -1;
#endif
if (edchars.erase >= 0) {
if (isedchar(edchars.erase)) {
bind_if_not_bound(0, edchars.erase, XFUNC_del_back);
bind_if_not_bound(1, edchars.erase, XFUNC_del_bword);
}
if (edchars.kill >= 0)
if (isedchar(edchars.kill))
bind_if_not_bound(0, edchars.kill, XFUNC_del_line);
if (edchars.werase >= 0)
if (isedchar(edchars.werase))
bind_if_not_bound(0, edchars.werase, XFUNC_del_bword);
if (edchars.intr >= 0)
if (isedchar(edchars.intr))
bind_if_not_bound(0, edchars.intr, XFUNC_abort);
if (edchars.quit >= 0)
if (isedchar(edchars.quit))
bind_if_not_bound(0, edchars.quit, XFUNC_noop);
} else
mksh_tcset(tty_fd, &tty_state);
@ -3601,16 +3566,19 @@ x_vi(char *buf)
if (c == -1)
break;
if (state != VLIT) {
if (c == edchars.intr || c == edchars.quit) {
if (isched(c, edchars.intr) ||
isched(c, edchars.quit)) {
/* pretend we got an interrupt */
x_vi_zotc(c);
x_flush();
trapsig(c == edchars.intr ? SIGINT : SIGQUIT);
trapsig(isched(c, edchars.intr) ?
SIGINT : SIGQUIT);
x_mode(false);
unwind(LSHELL);
} else if (c == edchars.eof && state != VVERSION) {
} else if (isched(c, edchars.eof) &&
state != VVERSION) {
if (es->linelen == 0) {
x_vi_zotc(edchars.eof);
x_vi_zotc(c);
c = -1;
break;
}
@ -3797,7 +3765,7 @@ vi_hook(int ch)
memcpy(srchpat, locpat, srchlen + 1);
}
state = VCMD;
} else if (ch == edchars.erase || ch == CTRL('h')) {
} else if (isched(ch, edchars.erase) || ch == CTRL('h')) {
if (srchlen != 0) {
srchlen--;
es->linelen -= char_len(locpat[srchlen]);
@ -3808,13 +3776,13 @@ vi_hook(int ch)
restore_cbuf();
state = VNORMAL;
refresh(0);
} else if (ch == edchars.kill) {
} else if (isched(ch, edchars.kill)) {
srchlen = 0;
es->linelen = 1;
es->cursor = 1;
refresh(0);
return (0);
} else if (ch == edchars.werase) {
} else if (isched(ch, edchars.werase)) {
unsigned int i, n;
struct edstate new_es, *save_es;
@ -3968,7 +3936,7 @@ vi_insert(int ch)
{
int tcursor;
if (ch == edchars.erase || ch == CTRL('h')) {
if (isched(ch, edchars.erase) || ch == CTRL('h')) {
if (insert == REPLACE) {
if (es->cursor == undo->cursor) {
vi_error();
@ -3994,7 +3962,7 @@ vi_insert(int ch)
expanded = NONE;
return (0);
}
if (ch == edchars.kill) {
if (isched(ch, edchars.kill)) {
if (es->cursor != 0) {
inslen = 0;
memmove(es->cbuf, &es->cbuf[es->cursor],
@ -4005,7 +3973,7 @@ vi_insert(int ch)
expanded = NONE;
return (0);
}
if (ch == edchars.werase) {
if (isched(ch, edchars.werase)) {
if (es->cursor != 0) {
tcursor = backword(1);
memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
@ -4376,7 +4344,7 @@ vi_cmd(int argcnt, const char *cmd)
(hlast - hnum);
}
if (argcnt)
shf_snprintf(es->cbuf, es->cbufsize, "%s %d",
shf_snprintf(es->cbuf, es->cbufsize, Tf_sd,
"fc -e ${VISUAL:-${EDITOR:-vi}} --",
argcnt);
else
@ -4505,7 +4473,7 @@ vi_cmd(int argcnt, const char *cmd)
argcnt++;
p++;
}
if (putbuf(" ", 1, false) != 0 ||
if (putbuf(T1space, 1, false) != 0 ||
putbuf(sp, argcnt, false) != 0) {
if (es->cursor != 0)
es->cursor--;
@ -5110,9 +5078,7 @@ redraw_line(bool newl)
x_putc('\r');
x_putc('\n');
}
if (prompt_trunc != -1)
pprompt(prompt, prompt_trunc);
x_col = pwidth;
x_pprompt();
morec = ' ';
}
@ -5267,9 +5233,7 @@ ed_mov_opt(int col, char *wb)
if (col < x_col) {
if (col + 1 < x_col - col) {
x_putc('\r');
if (prompt_trunc != -1)
pprompt(prompt, prompt_trunc);
x_col = pwidth;
x_pprompt();
while (x_col++ < col)
x_putcf(*wb++);
} else {
@ -5323,7 +5287,7 @@ expand_word(int cmd)
rval = -1;
break;
}
if (++i < nwords && putbuf(" ", 1, false) != 0) {
if (++i < nwords && putbuf(T1space, 1, false) != 0) {
rval = -1;
break;
}
@ -5441,7 +5405,7 @@ complete_word(int cmd, int count)
*/
if (match_len > 0 && !mksh_dirsep(match[match_len - 1]) &&
!(flags & XCF_IS_NOSPACE))
rval = putbuf(" ", 1, false);
rval = putbuf(T1space, 1, false);
}
x_free_words(nwords, words);
@ -5511,12 +5475,11 @@ x_init(void)
int i, j;
/*
* Set edchars to -2 to force initial binding, except
* we need default values for some deficient systems
* set edchars to force initial binding, except we need
* default values for ^W for some deficient systems
*/
edchars.erase = edchars.kill = edchars.intr = edchars.quit =
edchars.eof = -2;
/* ^W */
edchars.eof = EDCHAR_INITIAL;
edchars.werase = 027;
/* command line editing specific memory allocation */
@ -5552,4 +5515,89 @@ x_done(void)
afreeall(AEDIT);
}
#endif
void
x_initterm(const char *termtype)
{
/* default must be 0 (bss) */
x_term_mode = 0;
/* this is what tmux uses, don't ask me about it */
if (!strcmp(termtype, "screen") || !strncmp(termtype, "screen-", 7))
x_term_mode = 1;
}
#ifndef MKSH_SMALL
static char *
x_eval_region_helper(const char *cmd, size_t len)
{
char * volatile cp;
newenv(E_ERRH);
if (!kshsetjmp(e->jbuf)) {
char *wds = alloc(len + 3, ATEMP);
wds[0] = FUNSUB;
memcpy(wds + 1, cmd, len);
wds[len + 1] = '\0';
wds[len + 2] = EOS;
cp = evalstr(wds, DOSCALAR);
strdupx(cp, cp, AEDIT);
} else
cp = NULL;
quitenv(NULL);
return (cp);
}
static int
x_eval_region(int c MKSH_A_UNUSED)
{
char *evbeg, *evend, *cp;
size_t newlen;
/* only for LINE overflow checking */
size_t restlen;
if (xmp == NULL) {
evbeg = xbuf;
evend = xep;
} else if (xmp < xcp) {
evbeg = xmp;
evend = xcp;
} else {
evbeg = xcp;
evend = xmp;
}
x_e_putc2('\r');
x_clrtoeol(' ', false);
x_flush();
x_mode(false);
cp = x_eval_region_helper(evbeg, evend - evbeg);
x_mode(true);
if (cp == NULL) {
/* command cannot be parsed */
x_eval_region_err:
x_e_putc2(7);
x_redraw('\r');
return (KSTD);
}
newlen = strlen(cp);
restlen = xep - evend;
/* check for LINE overflow, until this is dynamically allocated */
if (evbeg + newlen + restlen >= xend)
goto x_eval_region_err;
xmp = evbeg;
xcp = evbeg + newlen;
xep = xcp + restlen;
memmove(xcp, evend, restlen + /* NUL */ 1);
memcpy(xmp, cp, newlen);
afree(cp, AEDIT);
x_adjust();
x_modified();
return (KSTD);
}
#endif /* !MKSH_SMALL */
#endif /* !MKSH_NO_CMDLINE_EDITING */

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2009, 2010, 2015
* Copyright (c) 2009, 2010, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -19,7 +19,7 @@
*/
#if defined(EMACSFN_DEFNS)
__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.7 2015/12/12 21:08:44 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.9 2016/07/26 21:50:30 tg Exp $");
#define FN(cname,sname,flags) static int x_##cname(int);
#elif defined(EMACSFN_ENUMS)
#define FN(cname,sname,flags) XFUNC_##cname,
@ -54,6 +54,9 @@ FN(end_of_text, "eot", 0)
FN(enumerate, "list", 0)
FN(eot_del, "eot-or-delete", XF_ARG)
FN(error, "error", 0)
#ifndef MKSH_SMALL
FN(eval_region, "evaluate-region", 0)
#endif
FN(expand, "expand-file", 0)
#ifndef MKSH_SMALL
FN(fold_capitalise, "capitalize-word", XF_ARG)

123
eval.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.189 2016/06/26 00:44:57 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.192 2016/08/01 21:38:01 tg Exp $");
/*
* string expansion
@ -186,7 +186,7 @@ evalonestr(const char *cp, int f)
rv = (char *) *XPptrv(w);
break;
default:
rv = evalstr(cp, f&~DOGLOB);
rv = evalstr(cp, f & ~DOGLOB);
break;
}
XPfree(w);
@ -381,9 +381,9 @@ expand(
/* ({) the } or x is already skipped */
if (end < wdscan(beg, EOS))
*end = EOS;
str = snptreef(NULL, 64, "%S", beg);
str = snptreef(NULL, 64, Tf_S, beg);
afree(beg, ATEMP);
errorf("%s: %s", str, Tbadsubst);
errorf(Tf_sD_s, str, Tbadsubst);
}
if (f & DOBLANK)
doblank++;
@ -478,12 +478,14 @@ expand(
strndupx(x.str, beg, num, ATEMP);
goto do_CSUBST;
}
case 0x100 | '/':
case '/': {
char *s, *p, *d, *sbeg, *end;
char *pat, *rrep;
char *pat = NULL, *rrep = null;
char fpat = 0, *tpat1, *tpat2;
char *ws, *wpat, *wrep;
s = wdcopy(sp, ATEMP);
s = ws = wdcopy(sp, ATEMP);
p = s + (wdscan(sp, ADELIM) - sp);
d = s + (wdscan(sp, CSUBST) - sp);
p[-2] = EOS;
@ -492,16 +494,24 @@ expand(
else
d[-2] = EOS;
sp += (d ? d : p) - s - 1;
if (!(stype & 0x80) &&
if (!(stype & 0x180) &&
s[0] == CHAR &&
(s[1] == '#' || s[1] == '%'))
fpat = s[1];
pat = evalstr(s + (fpat ? 2 : 0),
DOTILDE | DOSCALAR | DOPAT);
rrep = d ? evalstr(p,
DOTILDE | DOSCALAR) : null;
afree(s, ATEMP);
wpat = s + (fpat ? 2 : 0);
wrep = d ? p : NULL;
if (!(stype & 0x100)) {
rrep = wrep ? evalstr(wrep,
DOTILDE | DOSCALAR) :
null;
}
/* prepare string on which to work */
strdupx(s, str_val(st->var), ATEMP);
sbeg = s;
again_search:
pat = evalstr(wpat,
DOTILDE | DOSCALAR | DOPAT);
/* check for special cases */
if (!*pat && !fpat) {
/*
@ -510,19 +520,15 @@ expand(
*/
goto no_repl;
}
if ((stype & 0x80) &&
if ((stype & 0x180) &&
gmatchx(null, pat, false)) {
/*
* pattern matches empty
* string => don't loop
*/
stype &= ~0x80;
stype &= ~0x180;
}
/* prepare string on which to work */
strdupx(s, str_val(st->var), ATEMP);
sbeg = s;
/* first see if we have any match at all */
if (fpat == '#') {
/* anchor at the beginning */
@ -567,13 +573,27 @@ expand(
break;
p--;
}
strndupx(end, sbeg, p - sbeg, ATEMP);
record_match(end);
afree(end, ATEMP);
if (stype & 0x100) {
if (rrep != null)
afree(rrep, ATEMP);
rrep = wrep ? evalstr(wrep,
DOTILDE | DOSCALAR) :
null;
}
strndupx(end, s, sbeg - s, ATEMP);
d = shf_smprintf("%s%s%s", end, rrep, p);
d = shf_smprintf(Tf_sss, end, rrep, p);
afree(end, ATEMP);
sbeg = d + (sbeg - s) + strlen(rrep);
afree(s, ATEMP);
s = d;
if (stype & 0x80)
if (stype & 0x100) {
afree(tpat1, ATEMP);
afree(pat, ATEMP);
goto again_search;
} else if (stype & 0x80)
goto again_repl;
end_repl:
afree(tpat1, ATEMP);
@ -582,6 +602,7 @@ expand(
afree(pat, ATEMP);
if (rrep != null)
afree(rrep, ATEMP);
afree(ws, ATEMP);
goto do_CSUBST;
}
case '#':
@ -729,10 +750,11 @@ expand(
case '?':
dp = Xrestpos(ds, dp, st->base);
errorf("%s: %s", st->var->name,
errorf(Tf_sD_s, st->var->name,
debunk(dp, dp, strlen(dp) + 1));
break;
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1134,10 +1156,10 @@ varsub(Expand *xp, const char *sp, const char *word,
}
}
if (Flag(FNOUNSET) && c == 0 && !zero_ok)
errorf("%s: parameter not set", sp);
errorf(Tf_parm, sp);
/* unqualified variable/string substitution */
*stypep = 0;
xp->str = shf_smprintf("%d", c);
xp->str = shf_smprintf(Tf_d, c);
return (XSUB);
}
if (stype == '!' && c != '\0' && *word == CSUBST) {
@ -1207,6 +1229,7 @@ varsub(Expand *xp, const char *sp, const char *word,
case '#':
case '?':
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1237,6 +1260,7 @@ varsub(Expand *xp, const char *sp, const char *word,
case '#':
case '?':
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1249,7 +1273,7 @@ varsub(Expand *xp, const char *sp, const char *word,
for (; vp; vp = vp->u.array) {
if (!(vp->flag&ISSET))
continue;
XPput(wv, c == '!' ? shf_smprintf("%lu",
XPput(wv, c == '!' ? shf_smprintf(Tf_lu,
arrayindex(vp)) :
str_val(vp));
}
@ -1277,18 +1301,18 @@ varsub(Expand *xp, const char *sp, const char *word,
c = stype & 0x7F;
/* test the compiler's code generator */
if (((stype < 0x100) && (ctype(c, C_SUBOP2) || c == '/' ||
if (((stype < 0x100) && (ctype(c, C_SUBOP2) ||
(((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
(state != XARG || (ifs0 || xp->split ?
(xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
c == '=' || c == '-' || c == '?' : c == '+'))) ||
stype == (0x80 | '0') || stype == (0x100 | '#') ||
stype == (0x100 | 'Q'))
stype == (0x100 | 'Q') || (stype & 0x7F) == '/')
/* expand word instead of variable value */
state = XBASE;
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
(ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
errorf("%s: parameter not set", sp);
errorf(Tf_parm, sp);
*stypep = stype;
*slenp = slen;
return (state);
@ -1331,8 +1355,8 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
shf = shf_open(name = evalstr(io->ioname, DOTILDE),
O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
if (shf == NULL)
warningf(!Flag(FTALKING), "%s: %s %s: %s",
name, "can't open", "$(<...) input",
warningf(!Flag(FTALKING), Tf_sD_s_sD_s,
name, Tcant_open, "$(<...) input",
cstrerror(errno));
break;
case IOHERE:
@ -1348,8 +1372,8 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
shf = NULL;
break;
default:
errorf("%s: %s", T_funny_command,
snptreef(NULL, 32, "%R", io));
errorf(Tf_sD_s, T_funny_command,
snptreef(NULL, 32, Tft_R, io));
}
} else if (fn == FUNSUB) {
int ofd1;
@ -1361,8 +1385,8 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
*/
maketemp(ATEMP, TT_FUNSUB, &tf);
if (!tf->shf) {
errorf("can't %s temporary file %s: %s",
"create", tf->tffn, cstrerror(errno));
errorf(Tf_temp,
Tcreate, tf->tffn, cstrerror(errno));
}
/* extract shf from temporary file, unlink and free it */
shf = tf->shf;
@ -1420,6 +1444,7 @@ trimsub(char *str, char *pat, int how)
for (p = str; p <= end; p += utf_ptradj(p)) {
c = *p; *p = '\0';
if (gmatchx(str, pat, false)) {
record_match(str);
*p = c;
return (p);
}
@ -1431,6 +1456,7 @@ trimsub(char *str, char *pat, int how)
for (p = end; p >= str; p--) {
c = *p; *p = '\0';
if (gmatchx(str, pat, false)) {
record_match(str);
*p = c;
return (p);
}
@ -1458,6 +1484,7 @@ trimsub(char *str, char *pat, int how)
for (p = str; p <= end; p++)
if (gmatchx(p, pat, false)) {
trimsub_match:
record_match(p);
strndupx(end, str, p - str, ATEMP);
return (end);
}
@ -1612,7 +1639,7 @@ globit(XString *xs, /* dest string */
/* xp = *xpp; copy_non_glob() may have re-alloc'd xs */
*xp = '\0';
prefix_len = Xlength(*xs, xp);
dirp = opendir(prefix_len ? Xstring(*xs, xp) : ".");
dirp = opendir(prefix_len ? Xstring(*xs, xp) : Tdot);
if (dirp == NULL)
goto Nodir;
while ((d = readdir(dirp)) != NULL) {
@ -1714,24 +1741,40 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
*
* based on a version by Arnold Robbins
*/
char *
do_tilde(char *cp)
{
char *dp = null;
#ifndef MKSH_NOPWNAM
bool do_simplify = true;
#endif
if (cp[0] == '\0')
dp = str_val(global("HOME"));
else if (cp[0] == '+' && cp[1] == '\0')
dp = str_val(global("PWD"));
dp = str_val(global(TPWD));
else if (ksh_isdash(cp))
dp = str_val(global("OLDPWD"));
dp = str_val(global(TOLDPWD));
#ifndef MKSH_NOPWNAM
else
else {
dp = homedir(cp);
do_simplify = false;
}
#endif
/* If HOME, PWD or OLDPWD are not set, don't expand ~ */
return (dp == null ? NULL : dp);
/* if parameters aren't set, don't expand ~ */
if (dp == NULL || dp == null)
return (NULL);
/* simplify parameters as if cwd upon entry */
#ifndef MKSH_NOPWNAM
if (do_simplify)
#endif
{
strdupx(dp, dp, ATEMP);
simplify_path(dp);
}
return (dp);
}
#ifndef MKSH_NOPWNAM

177
exec.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.175 2016/06/26 00:44:58 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.179 2016/08/01 21:38:02 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@ -107,7 +107,7 @@ execute(struct op * volatile t,
if ((rv = herein(t->ioact[0], &cp) /*? 1 : 0*/))
cp = NULL;
dp = shf_smprintf("%s%s", evalstr(t->vars[0],
dp = shf_smprintf(Tf_ss, evalstr(t->vars[0],
DOASNTILDE | DOSCALAR), rv ? null : cp);
typeset(dp, Flag(FEXPORT) ? EXPORT : 0, 0, 0, 0);
/* free the expanded value */
@ -390,6 +390,7 @@ execute(struct op * volatile t,
for (ap = (const char **)t->vars; *ap; ap++) {
if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
gmatchx(ccp, s, false))) {
record_match(ccp);
rv = execute(t->left, flags & XERROK,
xerrok);
i = 0;
@ -441,7 +442,7 @@ execute(struct op * volatile t,
if (rv == ENOEXEC)
scriptexec(t, (const char **)up);
else
errorf("%s: %s", t->str, cstrerror(rv));
errorf(Tf_sD_s, t->str, cstrerror(rv));
}
Break:
exstat = rv & 0xFF;
@ -532,12 +533,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
break;
}
if ((tp = findcom(cp, FC_BI)) == NULL)
errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
if (tp->type == CSHELL && (tp->val.f == c_cat
#ifdef MKSH_PRINTF_BUILTIN
|| tp->val.f == c_printf
#endif
))
errorf(Tf_sD_sD_s, Tbuiltin, cp, Tnot_found);
if (tp->type == CSHELL && (tp->flag & LOW_BI))
break;
continue;
} else if (tp->val.f == c_exec) {
@ -577,7 +574,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
fcflags = FC_BI|FC_PATH;
if (saw_p) {
if (Flag(FRESTRICTED)) {
warningf(true, "%s: %s",
warningf(true, Tf_sD_s,
"command -p", "restricted");
rv = 1;
goto Leave;
@ -595,29 +592,21 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
subst_exstat = 0;
break;
}
} else if (tp->val.f == c_cat) {
} else if (tp->flag & LOW_BI) {
/* if we have any flags, do not use the builtin */
if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
if ((ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
/* argument, begins with -, is not - or -- */
(ap[1][1] != '-' || ap[1][2] != '\0')) {
struct tbl *ext_cat;
(ap[1][1] != '-' || ap[1][2] != '\0')) ||
/* always prefer the external utility */
(tp->flag & LOWER_BI)) {
struct tbl *ext_cmd;
ext_cat = findcom(Tcat, FC_PATH | FC_FUNC);
if (ext_cat && (ext_cat->type != CTALIAS ||
(ext_cat->flag & ISSET)))
tp = ext_cat;
ext_cmd = findcom(tp->name, FC_PATH | FC_FUNC);
if (ext_cmd && (ext_cmd->type != CTALIAS ||
(ext_cmd->flag & ISSET)))
tp = ext_cmd;
}
break;
#ifdef MKSH_PRINTF_BUILTIN
} else if (tp->val.f == c_printf) {
struct tbl *ext_printf;
ext_printf = findcom(Tprintf, FC_PATH | FC_FUNC);
if (ext_printf && (ext_printf->type != CTALIAS ||
(ext_printf->flag & ISSET)))
tp = ext_printf;
break;
#endif
} else if (tp->val.f == c_trap) {
t->u.evalflags &= ~DOTCOMEXEC;
break;
@ -686,7 +675,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
goto Leave;
} else if (!tp) {
if (Flag(FRESTRICTED) && mksh_vstrchr_dirsep(cp)) {
warningf(true, "%s: %s", cp, "restricted");
warningf(true, Tf_sD_s, cp, "restricted");
rv = 1;
goto Leave;
}
@ -715,40 +704,30 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
struct tbl *ftp;
if (!tp->u.fpath) {
fpath_error:
rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
warningf(true, "%s: %s %s: %s", cp,
"can't find", "function definition file",
warningf(true, Tf_sD_s_sD_s, cp,
Tcant_find, Tfile_fd,
cstrerror(tp->u2.errnov));
break;
}
if (include(tp->u.fpath, 0, NULL, false) < 0) {
if (!strcmp(cp, Tcat)) {
no_cat_in_FPATH:
tp = findcom(Tcat, FC_BI);
goto do_call_builtin;
}
#ifdef MKSH_PRINTF_BUILTIN
if (!strcmp(cp, Tprintf)) {
no_printf_in_FPATH:
tp = findcom(Tprintf, FC_BI);
goto do_call_builtin;
}
#endif
warningf(true, "%s: %s %s %s: %s", cp,
"can't open", "function definition file",
tp->u.fpath, cstrerror(errno));
rv = 127;
break;
}
if (!(ftp = findfunc(cp, hash(cp), false)) ||
errno = 0;
if (include(tp->u.fpath, 0, NULL, false) < 0 ||
!(ftp = findfunc(cp, hash(cp), false)) ||
!(ftp->flag & ISSET)) {
if (!strcmp(cp, Tcat))
goto no_cat_in_FPATH;
#ifdef MKSH_PRINTF_BUILTIN
if (!strcmp(cp, Tprintf))
goto no_printf_in_FPATH;
#endif
warningf(true, "%s: %s %s", cp,
rv = errno;
if ((ftp = findcom(cp, FC_BI)) &&
(ftp->type == CSHELL) &&
(ftp->flag & LOW_BI)) {
tp = ftp;
goto do_call_builtin;
}
if (rv) {
tp->u2.errnov = rv;
cp = tp->u.fpath;
goto fpath_error;
}
warningf(true, Tf_sD_s_s, cp,
"function not defined by", tp->u.fpath);
rv = 127;
break;
@ -829,7 +808,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
/* NOTREACHED */
default:
quitenv(NULL);
internal_errorf("%s %d", "CFUNC", i);
internal_errorf(Tf_sd, "CFUNC", i);
}
break;
}
@ -841,10 +820,10 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
if (!(tp->flag&ISSET)) {
if (tp->u2.errnov == ENOENT) {
rv = 127;
warningf(true, "%s: %s", cp, "not found");
warningf(true, Tf_sD_s, cp, Tnot_found);
} else {
rv = 126;
warningf(true, "%s: %s: %s", cp, "can't execute",
warningf(true, Tf_sD_sD_s, cp, "can't execute",
cstrerror(tp->u2.errnov));
}
break;
@ -898,7 +877,7 @@ scriptexec(struct op *tp, const char **ap)
#endif
union mksh_ccphack args, cap;
sh = str_val(global("EXECSHELL"));
sh = str_val(global(TEXECSHELL));
if (sh && *sh)
sh = search_path(sh, path, X_OK, NULL);
if (!sh || !*sh)
@ -1025,7 +1004,7 @@ scriptexec(struct op *tp, const char **ap)
execve(args.rw[0], args.rw, cap.rw);
/* report both the programme that was run and the bogus interpreter */
errorf("%s: %s: %s", tp->str, sh, cstrerror(errno));
errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno));
}
int
@ -1122,23 +1101,38 @@ builtin(const char *name, int (*func) (const char **))
uint32_t flag = DEFINED;
/* see if any flags should be set for this builtin */
while (1) {
if (*name == '=')
/* command does variable assignment */
flag |= KEEPASN;
else if (*name == '*')
/* POSIX special builtin */
flag |= SPEC_BI;
else
break;
name++;
flags_loop:
switch (*name) {
case '=':
/* command does variable assignment */
flag |= KEEPASN;
break;
case '*':
/* POSIX special builtin */
flag |= SPEC_BI;
break;
case '~':
/* external utility overrides built-in utility, always */
flag |= LOWER_BI;
/* FALLTHROUGH */
case '!':
/* external utility overrides built-in utility, with flags */
flag |= LOW_BI;
break;
default:
goto flags_seen;
}
++name;
goto flags_loop;
flags_seen:
/* enter into the builtins hash table */
tp = ktenter(&builtins, name, hash(name));
tp->flag = flag;
tp->type = CSHELL;
tp->val.f = func;
/* return name, for direct builtin call check in main.c */
return (name);
}
@ -1174,7 +1168,7 @@ findcom(const char *name, int flags)
if (!tp && (flags & FC_FUNC)) {
tp = findfunc(name, h, false);
if (tp && !(tp->flag & ISSET)) {
if ((fpath = str_val(global("FPATH"))) == null) {
if ((fpath = str_val(global(TFPATH))) == null) {
tp->u.fpath = NULL;
tp->u2.errnov = ENOENT;
} else
@ -1219,7 +1213,7 @@ findcom(const char *name, int flags)
afree(npath.rw, ATEMP);
tp->flag |= ISSET|ALLOC;
} else if ((flags & FC_FUNC) &&
(fpath = str_val(global("FPATH"))) != null &&
(fpath = str_val(global(TFPATH))) != null &&
(npath.ro = search_path(name, fpath, R_OK,
&tp->u2.errnov)) != NULL) {
/*
@ -1363,7 +1357,7 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
int rv;
if (!tp)
internal_errorf("%s: %s", where, wp[0]);
internal_errorf(Tf_sD_s, where, wp[0]);
builtin_argv0 = wp[0];
builtin_spec = tobool(!resetspec &&
/*XXX odd use of KEEPASN */
@ -1403,7 +1397,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
if (Flag(FXTRACE)) {
change_xtrace(2, false);
fptreef(shl_xtrace, 0, "%R", &iotmp);
fptreef(shl_xtrace, 0, Tft_R, &iotmp);
change_xtrace(1, false);
}
@ -1464,8 +1458,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
&emsg)) < 0) {
char *sp;
warningf(true, "%s: %s",
(sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
warningf(true, Tf_sD_s,
(sp = snptreef(NULL, 32, Tft_R, &iotmp)), emsg);
afree(sp, ATEMP);
return (-1);
}
@ -1478,7 +1472,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
if (do_open) {
if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
warningf(true, "%s: %s", cp, "restricted");
warningf(true, Tf_sD_s, cp, "restricted");
return (-1);
}
u = binopen3(cp, flags, 0666);
@ -1496,10 +1490,10 @@ iosetup(struct ioword *iop, struct tbl *tp)
/* herein() may already have printed message */
if (u == -1) {
u = errno;
warningf(true, "can't %s %s: %s",
warningf(true, Tf_cant,
iotype == IODUP ? "dup" :
(iotype == IOREAD || iotype == IOHERE) ?
"open" : "create", cp, cstrerror(u));
Topen : Tcreate, cp, cstrerror(u));
}
return (-1);
}
@ -1527,9 +1521,8 @@ iosetup(struct ioword *iop, struct tbl *tp)
char *sp;
eno = errno;
warningf(true, "%s %s: %s",
"can't finish (dup) redirection",
(sp = snptreef(NULL, 32, "%R", &iotmp)),
warningf(true, Tf_s_sD_s, Tredirection_dup,
(sp = snptreef(NULL, 32, Tft_R, &iotmp)),
cstrerror(eno));
afree(sp, ATEMP);
if (iotype != IODUP)
@ -1620,8 +1613,8 @@ herein(struct ioword *iop, char **resbuf)
h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
if (!(shf = h->shf) || (fd = binopen3(h->tffn, O_RDONLY, 0)) < 0) {
i = errno;
warningf(true, "can't %s temporary file %s: %s",
!shf ? "create" : "open", h->tffn, cstrerror(i));
warningf(true, Tf_temp,
!shf ? Tcreate : Topen, h->tffn, cstrerror(i));
if (shf)
shf_close(shf);
/* special to iosetup(): don't print error */
@ -1637,8 +1630,8 @@ herein(struct ioword *iop, char **resbuf)
if (shf_close(shf) == -1) {
i = errno;
close(fd);
warningf(true, "can't %s temporary file %s: %s",
"write", h->tffn, cstrerror(i));
warningf(true, Tf_temp,
Twrite, h->tffn, cstrerror(i));
/* special to iosetup(): don't print error */
return (-2);
}
@ -1654,7 +1647,7 @@ static const char *
do_selectargs(const char **ap, bool print_menu)
{
static const char *read_args[] = {
"read", "-r", "REPLY", NULL
Tread, "-r", "REPLY", NULL
};
char *s;
int i, argct;
@ -1670,8 +1663,8 @@ do_selectargs(const char **ap, bool print_menu)
*/
if (print_menu || !*str_val(global("REPLY")))
pr_menu(ap);
shellf("%s", str_val(global("PS3")));
if (call_builtin(findcom("read", FC_BI), read_args, Tselect,
shellf(Tf_s, str_val(global("PS3")));
if (call_builtin(findcom(Tread, FC_BI), read_args, Tselect,
false))
return (NULL);
if (*(s = str_val(global("REPLY"))))

149
expr.c
View File

@ -23,50 +23,16 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.85 2016/05/05 22:56:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.88 2016/07/27 00:55:27 tg Exp $");
/* the order of these enums is constrained by the order of opinfo[] */
enum token {
/* some (long) unary operators */
O_PLUSPLUS = 0, O_MINUSMINUS,
/* binary operators */
O_EQ, O_NE,
/* assignments are assumed to be in range O_ASN .. O_BORASN */
O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
#ifndef MKSH_LEGACY_MODE
O_ROLASN, O_RORASN,
#endif
O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
/* binary non-assignment operators */
#ifndef MKSH_LEGACY_MODE
O_ROL, O_ROR,
#endif
O_LSHIFT, O_RSHIFT,
O_LE, O_GE, O_LT, O_GT,
O_LAND,
O_LOR,
O_TIMES, O_DIV, O_MOD,
O_PLUS, O_MINUS,
O_BAND,
O_BXOR,
O_BOR,
O_TERN,
O_COMMA,
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
O_BNOT, O_LNOT,
/* misc */
OPEN_PAREN, CLOSE_PAREN, CTERN,
/* things that don't appear in the opinfo[] table */
VAR, LIT, END, BAD
};
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
#define EXPRTOK_DEFNS
#include "exprtok.h"
/* precisions; used to be enum prec but we do arithmetics on it */
#define P_PRIMARY 0 /* VAR, LIT, (), ! ~ ++ -- */
#define P_MULT 1 /* * / % */
#define P_ADD 2 /* + - */
#define P_SHIFT 3 /* <<< >>> << >> */
#define P_SHIFT 3 /* ^< ^> << >> */
#define P_RELATION 4 /* < <= > >= */
#define P_EQUALITY 5 /* == != */
#define P_BAND 6 /* & */
@ -75,72 +41,29 @@ enum token {
#define P_LAND 9 /* && */
#define P_LOR 10 /* || */
#define P_TERN 11 /* ?: */
/* = += -= *= /= %= <<<= >>>= <<= >>= &= ^= |= */
/* = += -= *= /= %= ^<= ^>= <<= >>= &= ^= |= */
#define P_ASSIGN 12
#define P_COMMA 13 /* , */
#define MAX_PREC P_COMMA
struct opinfo {
char name[5];
/* name length */
uint8_t len;
/* precedence: lower is higher */
uint8_t prec;
enum token {
#define EXPRTOK_ENUM
#include "exprtok.h"
};
/*
* Tokens in this table must be ordered so the longest are first
* (eg, += before +). If you change something, change the order
* of enum token too.
*/
static const struct opinfo opinfo[] = {
{ "++", 2, P_PRIMARY }, /* before + */
{ "--", 2, P_PRIMARY }, /* before - */
{ "==", 2, P_EQUALITY }, /* before = */
{ "!=", 2, P_EQUALITY }, /* before ! */
{ "=", 1, P_ASSIGN }, /* keep assigns in a block */
{ "*=", 2, P_ASSIGN },
{ "/=", 2, P_ASSIGN },
{ "%=", 2, P_ASSIGN },
{ "+=", 2, P_ASSIGN },
{ "-=", 2, P_ASSIGN },
#ifndef MKSH_LEGACY_MODE
{ "<<<=", 4, P_ASSIGN }, /* before <<< */
{ ">>>=", 4, P_ASSIGN }, /* before >>> */
#endif
{ "<<=", 3, P_ASSIGN },
{ ">>=", 3, P_ASSIGN },
{ "&=", 2, P_ASSIGN },
{ "^=", 2, P_ASSIGN },
{ "|=", 2, P_ASSIGN },
#ifndef MKSH_LEGACY_MODE
{ "<<<", 3, P_SHIFT }, /* before << */
{ ">>>", 3, P_SHIFT }, /* before >> */
#endif
{ "<<", 2, P_SHIFT },
{ ">>", 2, P_SHIFT },
{ "<=", 2, P_RELATION },
{ ">=", 2, P_RELATION },
{ "<", 1, P_RELATION },
{ ">", 1, P_RELATION },
{ "&&", 2, P_LAND },
{ "||", 2, P_LOR },
{ "*", 1, P_MULT },
{ "/", 1, P_MULT },
{ "%", 1, P_MULT },
{ "+", 1, P_ADD },
{ "-", 1, P_ADD },
{ "&", 1, P_BAND },
{ "^", 1, P_BXOR },
{ "|", 1, P_BOR },
{ "?", 1, P_TERN },
{ ",", 1, P_COMMA },
{ "~", 1, P_PRIMARY },
{ "!", 1, P_PRIMARY },
{ "(", 1, P_PRIMARY },
{ ")", 1, P_PRIMARY },
{ ":", 1, P_PRIMARY },
{ "", 0, P_PRIMARY }
static const char opname[][4] = {
#define EXPRTOK_NAME
#include "exprtok.h"
};
static const uint8_t oplen[] = {
#define EXPRTOK_LEN
#include "exprtok.h"
};
static const uint8_t opprec[] = {
#define EXPRTOK_PREC
#include "exprtok.h"
};
typedef struct expr_state {
@ -272,35 +195,35 @@ evalerr(Expr_state *es, enum error_type type, const char *str)
s = tbuf;
break;
default:
s = opinfo[(int)es->tok].name;
s = opname[(int)es->tok];
}
warningf(true, "%s: %s '%s'", es->expression,
"unexpected", s);
warningf(true, Tf_sD_s_qs, es->expression,
Tunexpected, s);
break;
case ET_BADLIT:
warningf(true, "%s: %s '%s'", es->expression,
warningf(true, Tf_sD_s_qs, es->expression,
"bad number", str);
break;
case ET_RECURSIVE:
warningf(true, "%s: %s '%s'", es->expression,
warningf(true, Tf_sD_s_qs, es->expression,
"expression recurses on parameter", str);
break;
case ET_LVALUE:
warningf(true, "%s: %s %s",
warningf(true, Tf_sD_s_s,
es->expression, str, "requires lvalue");
break;
case ET_RDONLY:
warningf(true, "%s: %s %s",
warningf(true, Tf_sD_s_s,
es->expression, str, "applied to read-only variable");
break;
default: /* keep gcc happy */
case ET_STR:
warningf(true, "%s: %s", es->expression, str);
warningf(true, Tf_sD_s, es->expression, str);
break;
}
unwind(LAEXPR);
@ -402,7 +325,7 @@ evalexpr(Expr_state *es, unsigned int prec)
vl = evalexpr(es, prec - 1);
while ((int)(op = es->tok) >= (int)O_EQ && (int)op <= (int)O_COMMA &&
opinfo[(int)op].prec == prec) {
opprec[(int)op] == prec) {
exprtoken(es);
vasn = vl;
if (op != O_ASN)
@ -698,11 +621,11 @@ exprtoken(Expr_state *es)
} else {
int i, n0;
for (i = 0; (n0 = opinfo[i].name[0]); i++)
if (c == n0 && strncmp(cp, opinfo[i].name,
(size_t)opinfo[i].len) == 0) {
for (i = 0; (n0 = opname[i][0]); i++)
if (c == n0 && strncmp(cp, opname[i],
(size_t)oplen[i]) == 0) {
es->tok = (enum token)i;
cp += opinfo[i].len;
cp += oplen[i];
break;
}
if (!n0)
@ -716,9 +639,9 @@ assign_check(Expr_state *es, enum token op, struct tbl *vasn)
{
if (es->tok == END || !vasn ||
(vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE)))
evalerr(es, ET_LVALUE, opinfo[(int)op].name);
evalerr(es, ET_LVALUE, opname[(int)op]);
else if (vasn->flag & RDONLY)
evalerr(es, ET_RDONLY, opinfo[(int)op].name);
evalerr(es, ET_RDONLY, opname[(int)op]);
}
struct tbl *

123
exprtok.h Normal file
View File

@ -0,0 +1,123 @@
/*-
* Copyright (c) 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#if defined(EXPRTOK_DEFNS)
__RCSID("$MirOS: src/bin/mksh/exprtok.h,v 1.1 2016/07/27 00:55:27 tg Exp $");
/* see range comment below */
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
#define FN(name, len, prec, enum) /* nothing */
#define F1(enum) /* nothing */
#elif defined(EXPRTOK_ENUM)
#define F0(name, len, prec, enum) enum = 0,
#define FN(name, len, prec, enum) enum,
#define F1(enum) enum,
#define F2(enum) enum,
#define F9(enum) enum
#elif defined(EXPRTOK_NAME)
#define FN(name, len, prec, enum) name,
#define F1(enum) ""
#elif defined(EXPRTOK_LEN)
#define FN(name, len, prec, enum) len,
#define F1(enum) 0
#elif defined(EXPRTOK_PREC)
#define FN(name, len, prec, enum) prec,
#define F1(enum) P_PRIMARY
#endif
#ifndef F0
#define F0 FN
#endif
#ifndef F2
#define F2(enum) /* nothing */
#define F9(enum) /* nothing */
#endif
/* tokens must be ordered so the longest are first (e.g. += before +) */
/* some (long) unary operators */
FN("++", 2, P_PRIMARY, O_PLUSPLUS = 0) /* before + */
FN("--", 2, P_PRIMARY, O_MINUSMINUS) /* before - */
/* binary operators */
FN("==", 2, P_EQUALITY, O_EQ) /* before = */
FN("!=", 2, P_EQUALITY, O_NE) /* before ! */
/* assignments are assumed to be in range O_ASN .. O_BORASN */
FN("=", 1, P_ASSIGN, O_ASN)
FN("*=", 2, P_ASSIGN, O_TIMESASN)
FN("/-", 2, P_ASSIGN, O_DIVASN)
FN("%=", 2, P_ASSIGN, O_MODASN)
FN("+=", 2, P_ASSIGN, O_PLUSASN)
FN("-=", 2, P_ASSIGN, O_MINUSASN)
#ifndef MKSH_LEGACY_MODE
FN("^<=", 3, P_ASSIGN, O_ROLASN) /* before ^< */
FN("^>=", 3, P_ASSIGN, O_RORASN) /* before ^> */
#endif
FN("<<=", 3, P_ASSIGN, O_LSHIFTASN)
FN(">>=", 3, P_ASSIGN, O_RSHIFTASN)
FN("&=", 2, P_ASSIGN, O_BANDASN)
FN("^=", 2, P_ASSIGN, O_BXORASN)
FN("|=", 2, P_ASSIGN, O_BORASN)
/* binary non-assignment operators */
#ifndef MKSH_LEGACY_MODE
FN("^<", 2, P_SHIFT, O_ROL) /* before ^ */
FN("^>", 2, P_SHIFT, O_ROR) /* before ^ */
#endif
FN("<<", 2, P_SHIFT, O_LSHIFT)
FN(">>", 2, P_SHIFT, O_RSHIFT)
FN("<=", 2, P_RELATION, O_LE)
FN(">=", 2, P_RELATION, O_GE)
FN("<", 1, P_RELATION, O_LT)
FN(">", 1, P_RELATION, O_GT)
FN("&&", 2, P_LAND, O_LAND)
FN("||", 2, P_LOR, O_LOR)
FN("*", 1, P_MULT, O_TIMES)
FN("/", 1, P_MULT, O_DIV)
FN("%", 1, P_MULT, O_MOD)
FN("+", 1, P_ADD, O_PLUS)
FN("-", 1, P_ADD, O_MINUS)
FN("&", 1, P_BAND, O_BAND)
FN("^", 1, P_BXOR, O_BXOR)
FN("|", 1, P_BOR, O_BOR)
FN("?", 1, P_TERN, O_TERN)
FN(",", 1, P_COMMA, O_COMMA)
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
FN("~", 1, P_PRIMARY, O_BNOT)
FN("!", 1, P_PRIMARY, O_LNOT)
/* misc */
FN("(", 1, P_PRIMARY, OPEN_PAREN)
FN(")", 1, P_PRIMARY, CLOSE_PAREN)
FN(":", 1, P_PRIMARY, CTERN)
/* things that don't appear in the opinfo[] table */
F1(VAR) /*XXX should be F2 */
F2(LIT)
F2(END)
F9(BAD)
#undef FN
#undef F0
#undef F1
#undef F2
#undef F9
#undef EXPRTOK_DEFNS
#undef EXPRTOK_ENUM
#undef EXPRTOK_NAME
#undef EXPRTOK_LEN
#undef EXPRTOK_PREC

258
funcs.c
View File

@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.297 2016/06/26 00:44:25 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.305 2016/08/01 21:38:02 tg Exp $");
#if HAVE_KILLPG
/*
@ -73,7 +73,7 @@ bi_getn(const char *as, int *ai)
int rv;
if (!(rv = getn(as, ai)))
bi_errorf("%s: %s", as, "bad number");
bi_errorf(Tf_sD_s, as, "bad number");
return (rv);
}
@ -94,15 +94,15 @@ c_false(const char **wp MKSH_A_UNUSED)
* A leading * means a POSIX special builtin.
*/
const struct builtin mkshbuiltins[] = {
{"*=.", c_dot},
{Tsgdot, c_dot},
{"*=:", c_true},
{"[", c_test},
{Tbracket, c_test},
/* no =: AT&T manual wrong */
{Talias, c_alias},
{"*=break", c_brkcont},
{Tgbuiltin, c_builtin},
{Tcat, c_cat},
{"cd", c_cd},
{Tbcat, c_cat},
{Tcd, c_cd},
/* dash compatibility hack */
{"chdir", c_cd},
{Tcommand, c_command},
@ -112,32 +112,32 @@ const struct builtin mkshbuiltins[] = {
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
{Tsgexport, c_typeset},
{"false", c_false},
{Tfalse, c_false},
{"fc", c_fc},
{"getopts", c_getopts},
{Tgetopts, c_getopts},
{"=global", c_typeset},
{"jobs", c_jobs},
{Tjobs, c_jobs},
{"kill", c_kill},
{"let", c_let},
{"let]", c_let},
{"print", c_print},
{"pwd", c_pwd},
{"read", c_read},
{Tread, c_read},
{Tsgreadonly, c_typeset},
{"realpath", c_realpath},
{"rename", c_rename},
{"!realpath", c_realpath},
{"~rename", c_rename},
{"*=return", c_exitreturn},
{Tsgset, c_set},
{"*=shift", c_shift},
{"=source", c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
{"suspend", c_suspend},
{Tsuspend, c_suspend},
#endif
{"test", c_test},
{"*=times", c_times},
{"*=trap", c_trap},
{"true", c_true},
{T_typeset, c_typeset},
{Ttrue, c_true},
{Tgtypeset, c_typeset},
{"ulimit", c_ulimit},
{"umask", c_umask},
{Tunalias, c_unalias},
@ -145,8 +145,8 @@ const struct builtin mkshbuiltins[] = {
{"=wait", c_wait},
{"whence", c_whence},
#ifndef MKSH_UNEMPLOYED
{"bg", c_fgbg},
{"fg", c_fgbg},
{Tbg, c_fgbg},
{Tfg, c_fgbg},
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
{"bind", c_bind},
@ -155,7 +155,7 @@ const struct builtin mkshbuiltins[] = {
{"mknod", c_mknod},
#endif
#ifdef MKSH_PRINTF_BUILTIN
{Tprintf, c_printf},
{"~printf", c_printf},
#endif
#if HAVE_SELECT
{"sleep", c_sleep},
@ -255,7 +255,7 @@ c_pwd(const char **wp)
wp += builtin_opt.optind;
if (wp[0]) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) :
@ -264,11 +264,11 @@ c_pwd(const char **wp)
if (p && access(p, R_OK) < 0)
p = NULL;
if (!p && !(p = allocd = ksh_get_wd())) {
bi_errorf("%s: %s", "can't determine current directory",
bi_errorf(Tf_sD_s, "can't determine current directory",
cstrerror(errno));
return (1);
}
shprintf("%s\n", p);
shprintf(Tf_sN, p);
afree(allocd, ATEMP);
return (0);
}
@ -288,6 +288,9 @@ c_print(const char **wp)
bool po_nl = true, po_exp = true;
/* print to history instead of file descriptor / stdout */
bool po_hist = false;
/* print characters */
bool po_char = false;
char ts[4];
if (wp[0][0] == 'e') {
/* "echo" builtin */
@ -352,13 +355,16 @@ c_print(const char **wp)
}
} else {
/* "print" builtin */
const char *opts = "npRrsu,";
const char *opts = "AnpRrsu,";
const char *emsg;
/* print a "--" argument */
bool po_pminusminus = false;
while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (c) {
case 'A':
po_char = true;
break;
case 'e':
po_exp = true;
break;
@ -367,7 +373,7 @@ c_print(const char **wp)
break;
case 'p':
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
bi_errorf("-p: %s", emsg);
bi_errorf(Tf_coproc, emsg);
return (1);
}
break;
@ -407,7 +413,23 @@ c_print(const char **wp)
Xinit(xs, xp, 128, ATEMP);
if (*wp != NULL) {
if (*wp != NULL && po_char) {
mksh_ari_t wc;
do {
if (!evaluate(*wp, &wc, KSH_RETURN_ERROR, true))
return (1);
Xcheck(xs, xp);
if (UTFMODE) {
ts[utf_wctomb(ts, wc)] = 0;
c = 0;
do {
Xput(xs, xp, ts[c]);
} while (ts[++c]);
} else
Xput(xs, xp, wc & 0xFF);
} while (*++wp);
} else if (*wp != NULL) {
print_read_arg:
s = *wp;
while ((c = *s++) != '\0') {
@ -432,8 +454,6 @@ c_print(const char **wp)
}
} else if ((unsigned int)c > 0xFF) {
/* generic function returned Unicode */
char ts[4];
ts[utf_wctomb(ts, c - 0x100)] = 0;
c = 0;
do {
@ -519,7 +539,7 @@ c_whence(const char **wp)
int optc;
bool pflag = false, vflag = false;
while ((optc = ksh_getopt(wp, &builtin_opt, "pv")) != -1)
while ((optc = ksh_getopt(wp, &builtin_opt, Tpv)) != -1)
switch (optc) {
case 'p':
pflag = true;
@ -543,8 +563,7 @@ c_command(const char **wp)
int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE;
bool vflag = false;
/* options not sorted to facilitate string pooling */
while ((optc = ksh_getopt(wp, &builtin_opt, "Vpv")) != -1)
while ((optc = ksh_getopt(wp, &builtin_opt, TpVv)) != -1)
switch (optc) {
case 'p':
fcflags |= FC_DEFPATH;
@ -630,7 +649,7 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
shf_puts(tp->val.s, shl_stdout);
} else {
if (vflag)
shprintf("%s not found", id);
shprintf(Tnot_found_s, id);
rv = 1;
}
break;
@ -795,7 +814,7 @@ c_typeset(const char **wp)
return (1);
if (basestr) {
if (!getn(basestr, &base)) {
bi_errorf("%s: %s", "bad integer base", basestr);
bi_errorf(Tf_sD_s, "bad integer base", basestr);
return (1);
}
if (base < 1 || base > 36)
@ -878,7 +897,7 @@ c_typeset(const char **wp)
shf_putc('\n', shl_stdout);
}
} else if (!typeset(wp[i], fset, fclr, field, base)) {
bi_errorf("%s: %s", wp[i], "is not an identifier");
bi_errorf(Tf_sD_s, wp[i], Tnot_ident);
return (1);
}
}
@ -975,7 +994,7 @@ c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
/* no arguments */
if (!thing && !flag) {
if (any_set == 1) {
shprintf("%s %s %s\n", Tset, "-A", vp->name);
shprintf(Tf_s_s_sN, Tset, "-A", vp->name);
any_set = 2;
}
/*
@ -983,31 +1002,31 @@ c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
* leftadj, zerofill, etc., but POSIX says must
* be suitable for re-entry...
*/
shprintf("%s %s", Ttypeset, "");
shprintf(Tf_s_s, Ttypeset, "");
if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
shprintf("-%c ", 'n');
shprintf(Tf__c_, 'n');
if ((vp->flag & INTEGER))
shprintf("-%c ", 'i');
shprintf(Tf__c_, 'i');
if ((vp->flag & EXPORT))
shprintf("-%c ", 'x');
shprintf(Tf__c_, 'x');
if ((vp->flag & RDONLY))
shprintf("-%c ", 'r');
shprintf(Tf__c_, 'r');
if ((vp->flag & TRACE))
shprintf("-%c ", 't');
shprintf(Tf__c_, 't');
if ((vp->flag & LJUST))
shprintf("-L%d ", vp->u2.field);
if ((vp->flag & RJUST))
shprintf("-R%d ", vp->u2.field);
if ((vp->flag & ZEROFIL))
shprintf("-%c ", 'Z');
shprintf(Tf__c_, 'Z');
if ((vp->flag & LCASEV))
shprintf("-%c ", 'l');
shprintf(Tf__c_, 'l');
if ((vp->flag & UCASEV_AL))
shprintf("-%c ", 'u');
shprintf(Tf__c_, 'u');
if ((vp->flag & INT_U))
shprintf("-%c ", 'U');
shprintf(Tf__c_, 'U');
} else if (pflag) {
shprintf("%s %s", istset ? Ttypeset :
shprintf(Tf_s_s, istset ? Ttypeset :
(flag & EXPORT) ? Texport : Treadonly, "");
}
if (any_set)
@ -1113,7 +1132,7 @@ c_alias(const char **wp)
for (p = ktsort(t); (ap = *p++) != NULL; )
if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
if (pflag)
shprintf("%s ", Talias);
shprintf(Tf_s_, Talias);
shf_puts(ap->name, shl_stdout);
if (prefix != '+') {
shf_putc('=', shl_stdout);
@ -1138,7 +1157,7 @@ c_alias(const char **wp)
ap = ktsearch(t, alias, h);
if (ap != NULL && (ap->flag&ISSET)) {
if (pflag)
shprintf("%s ", Talias);
shprintf(Tf_s_, Talias);
shf_puts(ap->name, shl_stdout);
if (prefix != '+') {
shf_putc('=', shl_stdout);
@ -1146,8 +1165,7 @@ c_alias(const char **wp)
}
shf_putc('\n', shl_stdout);
} else {
shprintf("%s %s %s\n", alias, Talias,
"not found");
shprintf(Tf_s_s_sN, alias, Talias, Tnot_found);
rv = 1;
}
continue;
@ -1251,7 +1269,7 @@ c_let(const char **wp)
if (wp[1] == NULL)
/* AT&T ksh does this */
bi_errorf("no arguments");
bi_errorf(Tno_args);
else
for (wp++; *wp; wp++)
if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) {
@ -1302,7 +1320,7 @@ c_jobs(const char **wp)
int
c_fgbg(const char **wp)
{
bool bg = strcmp(*wp, "bg") == 0;
bool bg = strcmp(*wp, Tbg) == 0;
int rv = 0;
if (!Flag(FMONITOR)) {
@ -1347,7 +1365,7 @@ c_kill(const char **wp)
if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) ||
ksh_isupper(p[1]))) {
if (!(t = gettrap(p + 1, false, false))) {
bi_errorf("bad signal '%s'", p + 1);
bi_errorf(Tbad_sig_s, p + 1);
return (1);
}
i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
@ -1362,7 +1380,7 @@ c_kill(const char **wp)
case 's':
if (!(t = gettrap(builtin_opt.optarg,
true, false))) {
bi_errorf("bad signal '%s'",
bi_errorf(Tbad_sig_s,
builtin_opt.optarg);
return (1);
}
@ -1392,9 +1410,9 @@ c_kill(const char **wp)
n -= 128;
#endif
if (n > 0 && n < ksh_NSIG)
shprintf("%s\n", sigtraps[n].name);
shprintf(Tf_sN, sigtraps[n].name);
else
shprintf("%d\n", n);
shprintf(Tf_dN, n);
}
} else if (Flag(FPOSIX)) {
n = 1;
@ -1439,12 +1457,12 @@ c_kill(const char **wp)
if (j_kill(p, sig))
rv = 1;
} else if (!getn(p, &n)) {
bi_errorf("%s: %s", p,
bi_errorf(Tf_sD_s, p,
"arguments must be jobs or process IDs");
rv = 1;
} else {
if (mksh_kill(n, sig) < 0) {
bi_errorf("%s: %s", p, cstrerror(errno));
bi_errorf(Tf_sD_s, p, cstrerror(errno));
rv = 1;
}
}
@ -1476,22 +1494,22 @@ c_getopts(const char **wp)
opts = *wp++;
if (!opts) {
bi_errorf("missing %s argument", "options");
bi_errorf(Tf_sD_s, "options", Tno_args);
return (1);
}
var = *wp++;
if (!var) {
bi_errorf("missing %s argument", "name");
bi_errorf(Tf_sD_s, Tname, Tno_args);
return (1);
}
if (!*var || *skip_varname(var, true)) {
bi_errorf("%s: %s", var, "is not an identifier");
bi_errorf(Tf_sD_s, var, Tnot_ident);
return (1);
}
if (e->loc->next == NULL) {
internal_warningf("%s: %s", "c_getopts", "no argv");
internal_warningf(Tf_sD_s, Tgetopts, Tno_args);
return (1);
}
/* Which arguments are we parsing... */
@ -1636,7 +1654,7 @@ c_shift(const char **wp)
/* nothing to do */
return (0);
} else if (n < 0) {
bi_errorf("%s: %s", arg, "bad number");
bi_errorf(Tf_sD_s, arg, "bad number");
return (1);
}
if (l->argc < n) {
@ -1676,7 +1694,7 @@ c_umask(const char **wp)
old_umask = ~old_umask;
p = buf;
for (i = 0; i < 3; i++) {
*p++ = "ugo"[i];
*p++ = Tugo[i];
*p++ = '=';
for (j = 0; j < 3; j++)
if (old_umask & (1 << (8 - (3*i + j))))
@ -1684,7 +1702,7 @@ c_umask(const char **wp)
*p++ = ',';
}
p[-1] = '\0';
shprintf("%s\n", buf);
shprintf(Tf_sN, buf);
} else
shprintf("%#3.3o\n", (unsigned int)old_umask);
} else {
@ -1712,7 +1730,7 @@ c_umask(const char **wp)
new_umask = old_umask;
positions = 0;
while (*cp) {
while (*cp && vstrchr("augo", *cp))
while (*cp && vstrchr(Taugo, *cp))
switch (*cp++) {
case 'a':
positions |= 0111;
@ -1789,13 +1807,13 @@ int
c_dot(const char **wp)
{
const char *file, *cp, **argv;
int argc, i, errcode;
int argc, rv, errcode;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return (1);
if ((cp = wp[builtin_opt.optind]) == NULL) {
bi_errorf("missing argument");
bi_errorf(Tno_args);
return (1);
}
file = search_path(cp, path, R_OK, &errcode);
@ -1803,7 +1821,7 @@ c_dot(const char **wp)
search_access(cp, R_OK) == 0)
file = cp;
if (!file) {
bi_errorf("%s: %s", cp, cstrerror(errcode));
bi_errorf(Tf_sD_s, cp, cstrerror(errcode));
return (1);
}
@ -1818,12 +1836,17 @@ c_dot(const char **wp)
argc = 0;
argv = NULL;
}
if ((i = include(file, argc, argv, false)) < 0) {
/* SUSv4: OR with a high value never written otherwise */
exstat |= 0x4000;
if ((rv = include(file, argc, argv, false)) < 0) {
/* should not happen */
bi_errorf("%s: %s", cp, cstrerror(errno));
bi_errorf(Tf_sD_s, cp, cstrerror(errno));
return (1);
}
return (i);
if (exstat & 0x4000)
/* detect old exstat, use 0 in that case */
rv = 0;
return (rv);
}
int
@ -1901,7 +1924,7 @@ c_read(const char **wp)
break;
case 'p':
if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
bi_errorf("-p: %s", ccp);
bi_errorf(Tf_coproc, ccp);
return (2);
}
break;
@ -1914,7 +1937,7 @@ c_read(const char **wp)
#if HAVE_SELECT
case 't':
if (parse_usec(builtin_opt.optarg, &tv)) {
bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno),
bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno),
builtin_opt.optarg);
return (2);
}
@ -1925,7 +1948,7 @@ c_read(const char **wp)
if (!builtin_opt.optarg[0])
fd = 0;
else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
bi_errorf("%s: %s: %s", "-u", builtin_opt.optarg, ccp);
bi_errorf(Tf_sD_sD_s, "-u", builtin_opt.optarg, ccp);
return (2);
}
break;
@ -1937,7 +1960,7 @@ c_read(const char **wp)
*--wp = REPLY;
if (intoarray && wp[1] != NULL) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (2);
}
@ -1997,7 +2020,7 @@ c_read(const char **wp)
/* fake EOF read; all cases return 1 */
goto c_read_didread;
default:
bi_errorf("%s: %s", Tselect, cstrerror(errno));
bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
rv = 2;
goto c_read_out;
}
@ -2014,7 +2037,7 @@ c_read(const char **wp)
/* pretend the read was killed */
} else {
/* unexpected error */
bi_errorf("%s", cstrerror(errno));
bi_errorf(Tf_s, cstrerror(errno));
}
rv = 2;
goto c_read_out;
@ -2116,7 +2139,7 @@ c_read(const char **wp)
subarray = last_lookup_was_array;
if (vp->flag & RDONLY) {
c_read_splitro:
bi_errorf("read-only: %s", *wp);
bi_errorf(Tf_ro, *wp);
c_read_spliterr:
rv = 2;
afree(cp, ATEMP);
@ -2344,7 +2367,7 @@ c_trap(const char **wp)
if (p->trap) {
shf_puts("trap -- ", shl_stdout);
print_value_quoted(shl_stdout, p->trap);
shprintf(" %s\n", p->name);
shprintf(Tf__sN, p->name);
}
++p;
} while (i--);
@ -2366,8 +2389,7 @@ c_trap(const char **wp)
i = 0;
while (*wp)
if (!(p = gettrap(*wp++, true, true))) {
warningf(true, "%s: bad signal '%s'",
builtin_argv0, wp[-1]);
warningf(true, Tbad_sig_ss, builtin_argv0, wp[-1]);
i = 1;
} else
settrap(p, s);
@ -2412,7 +2434,7 @@ c_exitreturn(const char **wp)
/* NOTREACHED */
c_exitreturn_err:
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
@ -2561,7 +2583,7 @@ c_unset(const char **wp)
afree(cp, ATEMP);
if ((vp->flag&RDONLY)) {
warningf(true, "read-only: %s", vp->name);
warningf(true, Tf_ro, vp->name);
rv = 1;
} else
unset(vp, optc);
@ -2591,13 +2613,13 @@ c_times(const char **wp MKSH_A_UNUSED)
getrusage(RUSAGE_SELF, &usage);
p_time(shl_stdout, false, usage.ru_utime.tv_sec,
usage.ru_utime.tv_usec, 0, null, " ");
usage.ru_utime.tv_usec, 0, null, T1space);
p_time(shl_stdout, false, usage.ru_stime.tv_sec,
usage.ru_stime.tv_usec, 0, null, "\n");
getrusage(RUSAGE_CHILDREN, &usage);
p_time(shl_stdout, false, usage.ru_utime.tv_sec,
usage.ru_utime.tv_usec, 0, null, " ");
usage.ru_utime.tv_usec, 0, null, T1space);
p_time(shl_stdout, false, usage.ru_stime.tv_sec,
usage.ru_stime.tv_usec, 0, null, "\n");
@ -2656,17 +2678,17 @@ timex(struct op *t, int f, volatile int *xerrok)
timersub(&tv1, &tv0, &tv1);
if (tf & TF_POSIX)
p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec,
5, "real ", "\n");
5, Treal_sp1, "\n");
else
p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec,
5, null, " real ");
5, null, Treal_sp2);
}
if (tf & TF_POSIX)
p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec,
5, "user ", "\n");
5, Tuser_sp1, "\n");
else
p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec,
5, null, " user ");
5, null, Tuser_sp2);
if (tf & TF_POSIX)
p_time(shl_out, true, systime.tv_sec, systime.tv_usec,
5, "sys ", "\n");
@ -2694,11 +2716,11 @@ timex_hook(struct op *t, char **volatile *app)
t->str[0] |= TF_POSIX;
break;
case '?':
errorf("time: -%s %s", opt.optarg,
"unknown option");
errorf(Tf_optfoo, Ttime, Tcolsp,
opt.optarg[0], Tunknown_option);
case ':':
errorf("time: -%s %s", opt.optarg,
"requires an argument");
errorf(Tf_optfoo, Ttime, Tcolsp,
opt.optarg[0], Treq_arg);
}
/* Copy command words down over options. */
if (opt.optind != 0) {
@ -2788,28 +2810,28 @@ c_mknod(const char **wp)
majnum = strtoul(argv[2], &c, 0);
if ((c == argv[2]) || (*c != '\0')) {
bi_errorf("non-numeric %s %s '%s'", "device", "major", argv[2]);
bi_errorf(Tf_nonnum, "device", "major", argv[2]);
goto c_mknod_err;
}
minnum = strtoul(argv[3], &c, 0);
if ((c == argv[3]) || (*c != '\0')) {
bi_errorf("non-numeric %s %s '%s'", "device", "minor", argv[3]);
bi_errorf(Tf_nonnum, "device", "minor", argv[3]);
goto c_mknod_err;
}
dv = makedev(majnum, minnum);
if ((unsigned long)(major(dv)) != majnum) {
bi_errorf("%s %s too large: %lu", "device", "major", majnum);
bi_errorf(Tf_toolarge, "device", "major", majnum);
goto c_mknod_err;
}
if ((unsigned long)(minor(dv)) != minnum) {
bi_errorf("%s %s too large: %lu", "device", "minor", minnum);
bi_errorf(Tf_toolarge, "device", "minor", minnum);
goto c_mknod_err;
}
if (mknod(argv[0], mode, dv))
goto c_mknod_failed;
} else if (mkfifo(argv[0], mode)) {
c_mknod_failed:
bi_errorf("%s: %s", argv[0], cstrerror(errno));
bi_errorf(Tf_sD_s, argv[0], cstrerror(errno));
c_mknod_err:
rv = 1;
}
@ -2867,7 +2889,7 @@ c_test(const char **wp)
for (argc = 0; wp[argc]; argc++)
;
if (strcmp(wp[0], "[") == 0) {
if (strcmp(wp[0], Tbracket) == 0) {
if (strcmp(wp[--argc], "]") != 0) {
bi_errorf("missing ]");
return (T_ERR_EXIT);
@ -3188,14 +3210,20 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
/* = */
case TO_STEQL:
if (te->flags & TEF_DBRACKET)
return (gmatchx(opnd1, opnd2, false));
if (te->flags & TEF_DBRACKET) {
if ((i = gmatchx(opnd1, opnd2, false)))
record_match(opnd1);
return (i);
}
return (strcmp(opnd1, opnd2) == 0);
/* != */
case TO_STNEQ:
if (te->flags & TEF_DBRACKET)
return (!gmatchx(opnd1, opnd2, false));
if (te->flags & TEF_DBRACKET) {
if ((i = gmatchx(opnd1, opnd2, false)))
record_match(opnd1);
return (!i);
}
return (strcmp(opnd1, opnd2) != 0);
/* < */
@ -3352,7 +3380,7 @@ test_primary(Test_env *te, bool do_eval)
/* unary expression */
opnd1 = (*te->getopnd)(te, op, do_eval);
if (!opnd1) {
(*te->error)(te, -1, "missing argument");
(*te->error)(te, -1, Tno_args);
return (0);
}
@ -3428,9 +3456,9 @@ ptest_error(Test_env *te, int ofs, const char *msg)
te->flags |= TEF_ERROR;
if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs]))
bi_errorf("%s: %s", op, msg);
bi_errorf(Tf_sD_s, op, msg);
else
bi_errorf("%s", msg);
bi_errorf(Tf_s, msg);
}
#ifndef MKSH_NO_LIMITS
@ -3558,7 +3586,7 @@ c_ulimit(const char **wp)
found:
if (wp[builtin_opt.optind]) {
if (all || wp[builtin_opt.optind + 1]) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
@ -3659,7 +3687,7 @@ c_rename(const char **wp)
bi_errorf(Tsynerr);
else if ((rv = rename(wp[0], wp[1])) != 0) {
rv = errno;
bi_errorf("%s: %s", "failed", cstrerror(rv));
bi_errorf(Tf_sD_s, "failed", cstrerror(rv));
}
return (rv);
@ -3682,11 +3710,11 @@ c_realpath(const char **wp)
bi_errorf(Tsynerr);
else if ((buf = do_realpath(wp[0])) == NULL) {
rv = errno;
bi_errorf("%s: %s", wp[0], cstrerror(rv));
bi_errorf(Tf_sD_s, wp[0], cstrerror(rv));
if ((unsigned int)rv > 255)
rv = 255;
} else {
shprintf("%s\n", buf);
shprintf(Tf_sN, buf);
afree(buf, ATEMP);
rv = 0;
}
@ -3732,7 +3760,7 @@ c_cat(const char **wp)
if (ksh_isdash(fn))
fd = STDIN_FILENO;
else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
bi_errorf("%s: %s", fn, cstrerror(errno));
bi_errorf(Tf_sD_s, fn, cstrerror(errno));
rv = 1;
continue;
}
@ -3749,7 +3777,7 @@ c_cat(const char **wp)
continue;
}
/* an error occured during reading */
bi_errorf("%s: %s", fn, cstrerror(errno));
bi_errorf(Tf_sD_s, fn, cstrerror(errno));
rv = 1;
break;
} else if (n == 0)
@ -3774,7 +3802,7 @@ c_cat(const char **wp)
rv = ksh_sigmask(SIGPIPE);
} else {
/* an error occured during writing */
bi_errorf("%s: %s", "<stdout>",
bi_errorf(Tf_sD_s, "<stdout>",
cstrerror(errno));
rv = 1;
}
@ -3809,7 +3837,7 @@ c_sleep(const char **wp)
if (!wp[0] || wp[1])
bi_errorf(Tsynerr);
else if (parse_usec(wp[0], &tv))
bi_errorf("%s: %s '%s'", Tsynerr, cstrerror(errno), wp[0]);
bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno), wp[0]);
else {
#ifndef MKSH_NOPROSPECTOFWORK
sigset_t omask, bmask;
@ -3839,7 +3867,7 @@ c_sleep(const char **wp)
*/
rv = 0;
else
bi_errorf("%s: %s", Tselect, cstrerror(errno));
bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
#ifndef MKSH_NOPROSPECTOFWORK
/* this will re-schedule signal delivery */
sigprocmask(SIG_SETMASK, &omask, NULL);
@ -3854,7 +3882,7 @@ static int
c_suspend(const char **wp)
{
if (wp[1] != NULL) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
if (Flag(FLOGIN)) {

View File

@ -27,7 +27,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.156 2016/03/04 14:26:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.158 2016/08/04 20:31:00 tg Exp $");
Trap sigtraps[ksh_NSIG + 1];
static struct sigaction Sigact_ign;
@ -69,12 +69,6 @@ static int histfd = -1;
static off_t histfsize;
#endif
static const char Tnot_in_history[] = "not in history";
#define Thistory (Tnot_in_history + 7)
static const char TFCEDIT_dollaru[] = "${FCEDIT:-/bin/ed} $_";
#define Tspdollaru (TFCEDIT_dollaru + 18)
/* HISTSIZE default: size of saved history, persistent or standard */
#ifdef MKSH_SMALL
#define MKSH_DEFHISTSIZE 255
@ -153,7 +147,7 @@ c_fc(const char **wp)
else if (!last)
last = p;
else {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
break;
@ -183,7 +177,7 @@ c_fc(const char **wp)
if (!first && (first = *wp))
wp++;
if (last || *wp) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
@ -239,7 +233,7 @@ c_fc(const char **wp)
if (!last && (last = *wp))
wp++;
if (*wp) {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (1);
}
if (!first) {
@ -278,7 +272,7 @@ c_fc(const char **wp)
for (hp = rflag ? hlast : hfirst;
hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) {
if (!nflag)
shf_fprintf(shl_stdout, "%lu",
shf_fprintf(shl_stdout, Tf_lu,
(unsigned long)hist_source->line -
(unsigned long)(histptr - hp));
shf_putc('\t', shl_stdout);
@ -290,7 +284,7 @@ c_fc(const char **wp)
*t++ = '\n';
s = t;
}
shf_fprintf(shl_stdout, "%s\n", s);
shf_fprintf(shl_stdout, Tf_sN, s);
}
shf_flush(shl_stdout);
return (0);
@ -300,32 +294,22 @@ c_fc(const char **wp)
tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps);
if (!(shf = tf->shf)) {
bi_errorf("can't %s temporary file %s: %s",
"create", tf->tffn, cstrerror(errno));
bi_errorf(Tf_temp, Tcreate, tf->tffn, cstrerror(errno));
return (1);
}
for (hp = rflag ? hlast : hfirst;
hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
shf_fprintf(shf, "%s\n", *hp);
shf_fprintf(shf, Tf_sN, *hp);
if (shf_close(shf) == -1) {
bi_errorf("can't %s temporary file %s: %s",
"write", tf->tffn, cstrerror(errno));
bi_errorf(Tf_temp, Twrite, tf->tffn, cstrerror(errno));
return (1);
}
/* Ignore setstr errors here (arbitrary) */
setstr(local("_", false), tf->tffn, KSH_RETURN_ERROR);
/* XXX: source should not get trashed by this.. */
{
Source *sold = source;
int ret;
ret = command(editor ? editor : TFCEDIT_dollaru, 0);
source = sold;
if (ret)
return (ret);
}
if ((optc = command(editor ? editor : TFCEDIT_dollaru, 0)))
return (optc);
{
struct stat statb;
@ -334,16 +318,15 @@ c_fc(const char **wp)
ssize_t n;
if (!(shf = shf_open(tf->tffn, O_RDONLY, 0, 0))) {
bi_errorf("can't %s temporary file %s: %s",
"open", tf->tffn, cstrerror(errno));
bi_errorf(Tf_temp, Topen, tf->tffn, cstrerror(errno));
return (1);
}
if (stat(tf->tffn, &statb) < 0)
n = 128;
else if ((off_t)statb.st_size > MKSH_MAXHISTFSIZE) {
bi_errorf("%s %s too large: %lu", Thistory,
"file", (unsigned long)statb.st_size);
bi_errorf(Tf_toolarge, Thistory,
Tfile, (unsigned long)statb.st_size);
goto errout;
} else
n = (size_t)statb.st_size + 1;
@ -354,8 +337,8 @@ c_fc(const char **wp)
XcheckN(xs, xp, Xlength(xs, xp));
}
if (n < 0) {
bi_errorf("can't %s temporary file %s: %s",
"read", tf->tffn, cstrerror(shf_errno(shf)));
bi_errorf(Tf_temp, Tread, tf->tffn,
cstrerror(shf_errno(shf)));
errout:
shf_close(shf);
return (1);
@ -372,8 +355,6 @@ static int
hist_execute(char *cmd, Area *areap)
{
static int last_line = -1;
Source *sold;
int ret;
/* Back up over last histsave */
if (histptr >= history && last_line != hist_source->line) {
@ -388,7 +369,7 @@ hist_execute(char *cmd, Area *areap)
afree(cmd, areap);
cmd = *histptr;
/* pdksh says POSIX doesnt say this is done, testsuite needs it */
shellf("%s\n", cmd);
shellf(Tf_sN, cmd);
/*-
* Commands are executed here instead of pushing them onto the
@ -397,11 +378,7 @@ hist_execute(char *cmd, Area *areap)
* X=y fc -e - 42 2> /dev/null
* are to effect the repeated commands environment.
*/
/* XXX: source should not get trashed by this.. */
sold = source;
ret = command(cmd, 0);
source = sold;
return (ret);
return (command(cmd, 0));
}
/*
@ -420,18 +397,18 @@ hist_get(const char *str, bool approx, bool allow_cur)
if (approx)
hp = hist_get_oldest();
else {
bi_errorf("%s: %s", str, Tnot_in_history);
bi_errorf(Tf_sD_s, str, Tnot_in_history);
hp = NULL;
}
} else if ((size_t)hp > (size_t)histptr) {
if (approx)
hp = hist_get_newest(allow_cur);
else {
bi_errorf("%s: %s", str, Tnot_in_history);
bi_errorf(Tf_sD_s, str, Tnot_in_history);
hp = NULL;
}
} else if (!allow_cur && hp == histptr) {
bi_errorf("%s: %s", str, "invalid range");
bi_errorf(Tf_sD_s, str, "invalid range");
hp = NULL;
}
} else {
@ -439,7 +416,7 @@ hist_get(const char *str, bool approx, bool allow_cur)
/* the -1 is to avoid the current fc command */
if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0)
bi_errorf("%s: %s", str, Tnot_in_history);
bi_errorf(Tf_sD_s, str, Tnot_in_history);
else
hp = &history[n];
}
@ -852,7 +829,7 @@ hist_init(Source *s)
goto retry;
}
if (hs != hist_init_retry)
bi_errorf("can't %s %s: %s",
bi_errorf(Tf_cant,
"unlink HISTFILE", hname, cstrerror(errno));
histfsize = 0;
return;
@ -1063,7 +1040,7 @@ inittraps(void)
}
}
if (sigtraps[i].name == null)
sigtraps[i].name = shf_smprintf("%d", i);
sigtraps[i].name = shf_smprintf(Tf_d, i);
#if HAVE_SYS_SIGLIST
sigtraps[i].mess = sys_siglist[i];
#elif HAVE_STRSIGNAL
@ -1073,7 +1050,7 @@ inittraps(void)
#endif
if ((sigtraps[i].mess == NULL) ||
(sigtraps[i].mess[0] == '\0'))
sigtraps[i].mess = shf_smprintf("%s %d",
sigtraps[i].mess = shf_smprintf(Tf_sd,
"Signal", i);
}
sigtraps[ksh_SIGEXIT].signal = ksh_SIGEXIT;

80
jobs.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.120 2016/03/04 14:26:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.121 2016/07/25 00:04:44 tg Exp $");
#if HAVE_KILLPG
#define mksh_killpg killpg
@ -238,11 +238,11 @@ j_suspend(void)
mksh_tcset(tty_fd, &tty_state);
if (restore_ttypgrp >= 0) {
if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) {
warningf(false, "%s: %s failed: %s",
"j_suspend", "tcsetpgrp", cstrerror(errno));
warningf(false, Tf_ssfaileds,
Tj_suspend, "tcsetpgrp", cstrerror(errno));
} else if (setpgid(0, restore_ttypgrp) < 0) {
warningf(false, "%s: %s failed: %s",
"j_suspend", "setpgid", cstrerror(errno));
warningf(false, Tf_ssfaileds,
Tj_suspend, "setpgid", cstrerror(errno));
}
}
}
@ -259,12 +259,12 @@ j_suspend(void)
if (ttypgrp_ok) {
if (restore_ttypgrp >= 0) {
if (setpgid(0, kshpid) < 0) {
warningf(false, "%s: %s failed: %s",
"j_suspend", "setpgid", cstrerror(errno));
warningf(false, Tf_ssfaileds,
Tj_suspend, "setpgid", cstrerror(errno));
ttypgrp_ok = false;
} else if (tcsetpgrp(tty_fd, kshpid) < 0) {
warningf(false, "%s: %s failed: %s",
"j_suspend", "tcsetpgrp", cstrerror(errno));
warningf(false, Tf_ssfaileds,
Tj_suspend, "tcsetpgrp", cstrerror(errno));
ttypgrp_ok = false;
}
}
@ -349,7 +349,7 @@ j_change(void)
pid_t ttypgrp;
if ((ttypgrp = tcgetpgrp(tty_fd)) < 0) {
warningf(false, "%s: %s failed: %s",
warningf(false, Tf_ssfaileds,
"j_init", "tcgetpgrp",
cstrerror(errno));
ttypgrp_ok = false;
@ -365,12 +365,12 @@ j_change(void)
SS_RESTORE_DFL|SS_FORCE);
if (ttypgrp_ok && kshpgrp != kshpid) {
if (setpgid(0, kshpid) < 0) {
warningf(false, "%s: %s failed: %s",
warningf(false, Tf_ssfaileds,
"j_init", "setpgid", cstrerror(errno));
ttypgrp_ok = false;
} else {
if (tcsetpgrp(tty_fd, kshpid) < 0) {
warningf(false, "%s: %s failed: %s",
warningf(false, Tf_ssfaileds,
"j_init", "tcsetpgrp",
cstrerror(errno));
ttypgrp_ok = false;
@ -381,7 +381,7 @@ j_change(void)
}
#ifndef MKSH_DISABLE_TTY_WARNING
if (use_tty && !ttypgrp_ok)
warningf(false, "%s: %s", "warning",
warningf(false, Tf_sD_s, "warning",
"won't have full job control");
#endif
} else {
@ -415,7 +415,7 @@ ksh_nice(int ness)
errno = 0;
/* this is gonna annoy users; complain to your distro, people! */
if (nice(ness) == -1 && (eno = errno) != 0)
warningf(false, "%s: %s", "bgnice", cstrerror(eno));
warningf(false, Tf_sD_s, "bgnice", cstrerror(eno));
#else
(void)nice(ness);
#endif
@ -625,7 +625,7 @@ exchild(struct op *t, int flags,
if (Flag(FTALKING)) {
shf_fprintf(shl_out, "[%d]", j->job);
for (p = j->proc_list; p; p = p->next)
shf_fprintf(shl_out, " %d",
shf_fprintf(shl_out, Tf__d,
(int)p->pid);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
@ -677,9 +677,9 @@ waitlast(void)
j = last_job;
if (!j || !(j->flags & JF_STARTED)) {
if (!j)
warningf(true, "%s: %s", "waitlast", "no last job");
warningf(true, Tf_sD_s, "waitlast", "no last job");
else
internal_warningf("%s: %s", "waitlast", "not started");
internal_warningf(Tf_sD_s, "waitlast", Tnot_started);
#ifndef MKSH_NOPROSPECTOFWORK
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
@ -739,7 +739,7 @@ waitfor(const char *cp, int *sigp)
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
if (ecode != JL_NOSUCH)
bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]);
return (-1);
}
@ -773,14 +773,14 @@ j_kill(const char *cp, int sig)
#ifndef MKSH_NOPROSPECTOFWORK
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]);
return (1);
}
if (j->pgrp == 0) {
/* started when !Flag(FMONITOR) */
if (kill_job(j, sig) < 0) {
bi_errorf("%s: %s", cp, cstrerror(errno));
bi_errorf(Tf_sD_s, cp, cstrerror(errno));
rv = 1;
}
} else {
@ -789,7 +789,7 @@ j_kill(const char *cp, int sig)
mksh_killpg(j->pgrp, SIGCONT);
#endif
if (mksh_killpg(j->pgrp, sig) < 0) {
bi_errorf("%s: %s", cp, cstrerror(errno));
bi_errorf(Tf_sD_s, cp, cstrerror(errno));
rv = 1;
}
}
@ -816,7 +816,7 @@ j_resume(const char *cp, int bg)
if ((j = j_lookup(cp, &ecode)) == NULL) {
sigprocmask(SIG_SETMASK, &omask, NULL);
bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]);
return (1);
}
@ -861,7 +861,7 @@ j_resume(const char *cp, int bg)
if (j->flags & JF_SAVEDTTY)
mksh_tcset(tty_fd, &tty_state);
sigprocmask(SIG_SETMASK, &omask, NULL);
bi_errorf("%s %s(%d, %ld) failed: %s",
bi_errorf(Tf_ldfailed,
"fg: 1st", "tcsetpgrp", tty_fd,
(long)((j->flags & JF_SAVEDTTYPGRP) ?
j->saved_ttypgrp : j->pgrp),
@ -883,12 +883,12 @@ j_resume(const char *cp, int bg)
if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
mksh_tcset(tty_fd, &tty_state);
if (ttypgrp_ok && tcsetpgrp(tty_fd, kshpgrp) < 0)
warningf(true, "%s %s(%d, %ld) failed: %s",
warningf(true, Tf_ldfailed,
"fg: 2nd", "tcsetpgrp", tty_fd,
(long)kshpgrp, cstrerror(errno));
}
sigprocmask(SIG_SETMASK, &omask, NULL);
bi_errorf("%s %s: %s", "can't continue job",
bi_errorf(Tf_s_sD_s, "can't continue job",
cp, cstrerror(eno));
return (1);
}
@ -957,7 +957,7 @@ j_jobs(const char *cp, int slp,
#ifndef MKSH_NOPROSPECTOFWORK
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
bi_errorf(Tf_sD_s, cp, lookup_msgs[ecode]);
return (1);
}
} else
@ -977,7 +977,7 @@ j_jobs(const char *cp, int slp,
for (j = job_list; j; j = tmp) {
tmp = j->next;
if (j->flags & JF_REMOVE)
remove_job(j, "jobs");
remove_job(j, Tjobs);
}
#ifndef MKSH_NOPROSPECTOFWORK
sigprocmask(SIG_SETMASK, &omask, NULL);
@ -1051,7 +1051,7 @@ j_set_async(Job *j)
if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE)
remove_job(async_job, "async");
if (!(j->flags & JF_STARTED)) {
internal_warningf("%s: %s", "j_async", "job not started");
internal_warningf(Tf_sD_s, "j_async", Tjob_not_started);
return;
}
async_job = j;
@ -1175,7 +1175,7 @@ j_waitj(Job *j,
(j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0)
j->flags |= JF_SAVEDTTYPGRP;
if (tcsetpgrp(tty_fd, kshpgrp) < 0)
warningf(true, "%s %s(%d, %ld) failed: %s",
warningf(true, Tf_ldfailed,
"j_waitj:", "tcsetpgrp", tty_fd,
(long)kshpgrp, cstrerror(errno));
if (j->state == PSTOPPED) {
@ -1538,7 +1538,7 @@ j_print(Job *j, int how, struct shf *shf)
* group leader (ie, !FMONITOR). We arbitrarily return
* last pid (which is what $! returns).
*/
shf_fprintf(shf, "%d\n", (int)(j->pgrp ? j->pgrp :
shf_fprintf(shf, Tf_dN, (int)(j->pgrp ? j->pgrp :
(j->last_proc ? j->last_proc->pid : 0)));
return;
}
@ -1626,10 +1626,10 @@ j_print(Job *j, int how, struct shf *shf)
while (p && p->state == state && p->status == status) {
if (how == JP_LONG)
shf_fprintf(shf, "%s%5d %-20s %s%s", filler,
(int)p->pid, " ", p->command,
(int)p->pid, T1space, p->command,
p->next ? "|" : null);
else if (how == JP_MEDIUM)
shf_fprintf(shf, " %s%s", p->command,
shf_fprintf(shf, Tf__ss, p->command,
p->next ? "|" : null);
p = p->next;
}
@ -1803,7 +1803,7 @@ remove_job(Job *j, const char *where)
curr = *prev;
}
if (curr != j) {
internal_warningf("remove_job: job %s (%s)", "not found", where);
internal_warningf("remove_job: job %s (%s)", Tnot_found, where);
return;
}
*prev = curr->next;
@ -1892,22 +1892,22 @@ tty_init_talking(void)
break;
case 1:
#ifndef MKSH_DISABLE_TTY_WARNING
warningf(false, "%s: %s %s: %s",
"No controlling tty", "open", "/dev/tty",
cstrerror(errno));
warningf(false, Tf_sD_s_sD_s,
"No controlling tty", Topen, T_devtty, cstrerror(errno));
#endif
break;
case 2:
#ifndef MKSH_DISABLE_TTY_WARNING
warningf(false, "%s: %s", "can't find tty fd", cstrerror(errno));
warningf(false, Tf_sD_s_s, Tcant_find, Ttty_fd,
cstrerror(errno));
#endif
break;
case 3:
warningf(false, "%s: %s failed: %s", "j_ttyinit",
"dup of tty fd", cstrerror(errno));
warningf(false, Tf_ssfaileds, "j_ttyinit",
Ttty_fd_dupof, cstrerror(errno));
break;
case 4:
warningf(false, "%s: %s: %s", "j_ttyinit",
warningf(false, Tf_sD_sD_s, "j_ttyinit",
"can't set close-on-exec flag", cstrerror(errno));
break;
}

36
lex.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.225 2016/06/25 23:55:00 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.228 2016/08/01 21:38:03 tg Exp $");
/*
* states while lexing word
@ -462,10 +462,12 @@ yylex(int cf)
break;
}
} else if (c == '/') {
c2 = ADELIM;
parse_adelim_slash:
*wp++ = CHAR;
*wp++ = c;
if ((c = getsc()) == '/') {
*wp++ = ADELIM;
*wp++ = c2;
*wp++ = c;
} else
ungetsc(c);
@ -475,6 +477,13 @@ yylex(int cf)
statep->ls_adelim.num = 1;
statep->nparen = 0;
break;
} else if (c == '@') {
c2 = getsc();
ungetsc(c2);
if (c2 == '/') {
c2 = CHAR;
goto parse_adelim_slash;
}
}
/*
* If this is a trim operation,
@ -887,20 +896,11 @@ yylex(int cf)
#ifndef MKSH_LEGACY_MODE
(c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
#endif
c == '<' || c == '>')) {
c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 ||
(c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) {
struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
if (Xlength(ws, wp) == 0)
iop->unit = c == '<' ? 0 : 1;
else for (iop->unit = 0, c2 = 0; c2 < Xlength(ws, wp); c2 += 2) {
if (dp[c2] != CHAR)
goto no_iop;
if (!ksh_isdigit(dp[c2 + 1]))
goto no_iop;
iop->unit = iop->unit * 10 + ksh_numdig(dp[c2 + 1]);
if (iop->unit >= FDBASE)
goto no_iop;
}
iop->unit = c2 == 2 ? ksh_numdig(dp[1]) : c == '<' ? 0 : 1;
if (c == '&') {
if ((c2 = getsc()) != '>') {
@ -988,7 +988,7 @@ yylex(int cf)
++p;
else
/* ksh -c 'cat <<EOF' can cause this */
yyerror("here document '%s' unclosed\n",
yyerror(Tf_heredoc,
evalstr((*p)->delim, 0));
}
return (c);
@ -1163,7 +1163,7 @@ readhere(struct ioword *iop)
while (c != '\n') {
if (!c)
/* oops, reached EOF */
yyerror("here document '%s' unclosed\n", eof);
yyerror(Tf_heredoc, eof);
/* store character */
Xcheck(xs, xp);
Xput(xs, xp, c);
@ -1263,7 +1263,7 @@ getsc_uu(void)
s->start = s->str = "\n";
s->type = SEOF;
} else {
s->start = s->str = " ";
s->start = s->str = T1space;
s->type = SWORDS;
}
break;
@ -1474,7 +1474,7 @@ set_prompt(int to, Source *s)
if (*ps1 != '!' || *++ps1 == '!')
shf_putchar(*ps1++, shf);
else
shf_fprintf(shf, "%lu", s ?
shf_fprintf(shf, Tf_lu, s ?
(unsigned long)s->line + 1 : 0UL);
ps1 = shf_sclose(shf);
saved_lineno = current_lineno;

7
lksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/lksh.1,v 1.17 2016/02/11 20:12:09 tg Exp $
.\" $MirOS: src/bin/mksh/lksh.1,v 1.18 2016/08/10 18:20:05 tg Exp $
.\"-
.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016
.\" mirabilos <m@mirbsd.org>
@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: February 11 2016 $
.Dd $Mdocdate: August 10 2016 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@ -241,9 +241,6 @@ Division of the largest negative number by \-1 is Undefined Behaviour.
The compiler is permitted to delete all data and crash the system
if Undefined Behaviour occurs (see above for an example).
.It
.Nm
only offers the traditional ten file descriptors to scripts.
.It
.\"XXX TODO: move this to FPOSIX
The rotation arithmetic operators are not available.
.It

81
main.c
View File

@ -34,7 +34,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.310 2016/02/26 21:53:36 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.317 2016/08/04 20:51:35 tg Exp $");
extern char **environ;
@ -63,7 +63,7 @@ static const char initsubs[] =
static const char *initcoms[] = {
Ttypeset, "-r", initvsn, NULL,
Ttypeset, "-x", "HOME", "PATH", "SHELL", NULL,
Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
Talias,
"integer=\\typeset -i",
@ -82,12 +82,12 @@ static const char *initcoms[] = {
/* this is what AT&T ksh seems to track, with the addition of emacs */
Talias, "-tU",
Tcat, "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
"make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL,
"make", "mv", "pr", "rm", "sed", Tsh, "vi", "who", NULL,
NULL
};
static const char *restr_com[] = {
Ttypeset, "-r", "PATH", "ENV", "SHELL", NULL
Ttypeset, "-r", TPATH, "ENV", TSHELL, NULL
};
static bool initio_done;
@ -149,7 +149,7 @@ chvt_reinit(void)
}
static const char *empty_argv[] = {
"mksh", NULL
Tmksh, NULL
};
static uint8_t
@ -317,7 +317,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
#endif
/*
* this is uniform across all OSes unless it
* breaks somewhere; don't try to optimise,
* breaks somewhere hard; don't try to optimise,
* e.g. add stuff for Interix or remove /usr
* for HURD, because e.g. Debian GNU/HURD is
* "keeping a regular /usr"; this is supposed
@ -333,7 +333,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
* Set PATH to def_path (will set the path global variable).
* (import of environment below will probably change this setting).
*/
vp = global("PATH");
vp = global(TPATH);
/* setstr can't fail here */
setstr(vp, def_path, KSH_RETURN_ERROR);
@ -366,11 +366,11 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
substitute(initsubs, 0);
/* Figure out the current working directory and set $PWD */
vp = global("PWD");
vp = global(TPWD);
cp = str_val(vp);
/* Try to use existing $PWD if it is valid */
set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp, ".",
true)) ? cp : NULL);
set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp,
Tdot, true)) ? cp : NULL);
if (current_wd[0])
simplify_path(current_wd);
/* Only set pwd if we know where we are or if it had a bogus value */
@ -440,7 +440,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
} else if (Flag(FCOMMAND)) {
s = pushs(SSTRINGCMDLINE, ATEMP);
if (!(s->start = s->str = argv[argi++]))
errorf("-c %s", "requires an argument");
errorf(Tf_optfoo, "", "", 'c', Treq_arg);
while (*s->str) {
if (*s->str != ' ' && ctype(*s->str, C_QUOTE))
break;
@ -475,7 +475,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
SHF_MAPHI | SHF_CLEXEC);
if (s->u.shf == NULL) {
shl_stdout_ok = false;
warningf(true, "%s: %s", s->file, cstrerror(errno));
warningf(true, Tf_sD_s, s->file, cstrerror(errno));
/* mandated by SUSv4 */
exstat = 127;
unwind(LERROR);
@ -738,12 +738,15 @@ include(const char *name, int argc, const char **argv, bool intr_ok)
int
command(const char *comm, int line)
{
Source *s;
Source *s, *sold = source;
int rv;
s = pushs(SSTRING, ATEMP);
s->start = s->str = comm;
s->line = line;
return (shell(s, false));
rv = shell(s, false);
source = sold;
return (rv);
}
/*
@ -914,13 +917,6 @@ unwind(int i)
/* FALLTHROUGH */
default:
quitenv(NULL);
/*
* quitenv() may have reclaimed the memory
* used by source which will end badly when
* we jump to a function that expects it to
* be valid
*/
source = NULL;
}
}
}
@ -1091,15 +1087,25 @@ reclaim(void)
remove_temps(e->temps);
e->temps = NULL;
/*
* if the memory backing source is reclaimed, things
* will end up badly when a function expecting it to
* be valid is run; a NULL pointer is easily debugged
*/
if (source && source->areap == &e->area)
source = NULL;
afreeall(&e->area);
}
static void
remove_temps(struct temp *tp)
{
for (; tp != NULL; tp = tp->next)
while (tp) {
if (tp->pid == procpid)
unlink(tp->tffn);
tp = tp->next;
}
}
/*
@ -1133,7 +1139,7 @@ tty_init_fd(void)
goto got_fd;
}
#endif
if ((fd = open("/dev/tty", O_RDWR, 0)) >= 0) {
if ((fd = open(T_devtty, O_RDWR, 0)) >= 0) {
do_close = true;
goto got_fd;
}
@ -1190,13 +1196,13 @@ vwarningf(unsigned int flags, const char *fmt, va_list ap)
{
if (fmt) {
if (flags & VWARNINGF_INTERNAL)
shf_fprintf(shl_out, "internal error: ");
shf_fprintf(shl_out, Tf_sD_, "internal error");
if (flags & VWARNINGF_ERRORPREFIX)
error_prefix(tobool(flags & VWARNINGF_FILELINE));
if ((flags & VWARNINGF_BUILTIN) &&
/* not set when main() calls parse_args() */
builtin_argv0 && builtin_argv0 != kshname)
shf_fprintf(shl_out, "%s: ", builtin_argv0);
shf_fprintf(shl_out, Tf_sD_, builtin_argv0);
shf_vfprintf(shl_out, fmt, ap);
shf_putchar('\n', shl_out);
}
@ -1305,7 +1311,7 @@ error_prefix(bool fileline)
/* Avoid foo: foo[2]: ... */
if (!fileline || !source || !source->file ||
strcmp(source->file, kshname) != 0)
shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
shf_fprintf(shl_out, Tf_sD_, kshname + (*kshname == '-'));
if (fileline && source && source->file != NULL) {
shf_fprintf(shl_out, "%s[%lu]: ", source->file,
(unsigned long)(source->errline ?
@ -1375,7 +1381,7 @@ initio(void)
if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
errorf("cannot get home directory");
lfp = shf_smprintf("%s/mksh-dbg.txt", lfp);
lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
}
if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
@ -1479,25 +1485,20 @@ closepipe(int *pv)
int
check_fd(const char *name, int mode, const char **emsgp)
{
int fd = 0, fl;
int fd, fl;
if (name[0] == 'p' && !name[1])
if (!name[0] || name[1])
goto illegal_fd_name;
if (name[0] == 'p')
return (coproc_getfd(mode, emsgp));
while (ksh_isdigit(*name)) {
fd = fd * 10 + ksh_numdig(*name);
if (fd >= FDBASE) {
if (emsgp)
*emsgp = "file descriptor too large";
return (-1);
}
++name;
}
if (*name) {
if (!ksh_isdigit(name[0])) {
illegal_fd_name:
if (emsgp)
*emsgp = "illegal file descriptor name";
return (-1);
}
if ((fl = fcntl(fd, F_GETFL, 0)) < 0) {
if ((fl = fcntl((fd = ksh_numdig(name[0])), F_GETFL, 0)) < 0) {
if (emsgp)
*emsgp = "bad file descriptor";
return (-1);

65
misc.c
View File

@ -30,7 +30,7 @@
#include <grp.h>
#endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.242 2016/03/04 14:26:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.245 2016/08/01 18:42:42 tg Exp $");
#define KSH_CHVT_FLAG
#ifdef MKSH_SMALL
@ -78,12 +78,12 @@ static int make_path(const char *, const char *, char **, XString *, int *);
void
setctypes(const char *s, int t)
{
unsigned int i;
if (t & C_IFS) {
for (i = 0; i < UCHAR_MAX + 1; i++)
unsigned int i = 0;
while (++i <= UCHAR_MAX)
chtypes[i] &= ~C_IFS;
/* include \0 in C_IFS */
/* include '\0' in C_IFS */
chtypes[0] |= C_IFS;
}
while (*s != 0)
@ -354,7 +354,7 @@ change_xtrace(unsigned char newval, bool dosnapshot)
*/
int
parse_args(const char **argv,
/* OF_CMDLINE or OF_SET */
/* OF_FIRSTTIME, OF_CMDLINE, or OF_SET */
int what,
bool *setargsp)
{
@ -443,7 +443,8 @@ parse_args(const char **argv,
else if ((i != (size_t)-1) && (OFF(i) & what))
change_flag((enum sh_flag)i, what, set);
else {
bi_errorf("%s: %s", go.optarg, "bad option");
bi_errorf(Tf_sD_s, go.optarg,
Tunknown_option);
return (-1);
}
break;
@ -504,7 +505,7 @@ parse_args(const char **argv,
if (*array)
ccp = skip_varname(array, false);
if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
bi_errorf("%s: %s", array, "is not an identifier");
bi_errorf(Tf_sD_s, array, Tnot_ident);
return (-1);
}
}
@ -1038,10 +1039,10 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
go->buf[0] = c;
go->optarg = go->buf;
} else {
warningf(true, "%s%s-%c: %s",
warningf(true, Tf_optfoo,
(go->flags & GF_NONAME) ? "" : argv[0],
(go->flags & GF_NONAME) ? "" : ": ", c,
"unknown option");
(go->flags & GF_NONAME) ? "" : Tcolsp,
c, Tunknown_option);
if (go->flags & GF_ERROR)
bi_errorfz();
}
@ -1066,10 +1067,10 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
go->optarg = go->buf;
return (':');
}
warningf(true, "%s%s-%c: %s",
warningf(true, Tf_optfoo,
(go->flags & GF_NONAME) ? "" : argv[0],
(go->flags & GF_NONAME) ? "" : ": ", c,
"requires an argument");
(go->flags & GF_NONAME) ? "" : Tcolsp,
c, Treq_arg);
if (go->flags & GF_ERROR)
bi_errorfz();
return ('?');
@ -1428,7 +1429,7 @@ do_realpath(const char *upath)
/* upath is a relative pathname, prepend cwd */
if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
return (NULL);
ipath = shf_smprintf("%s%s%s", tp, "/", upath);
ipath = shf_smprintf(Tf_sss, tp, "/", upath);
afree(tp, ATEMP);
}
@ -1526,7 +1527,7 @@ do_realpath(const char *upath)
* otherwise continue with currently resolved prefix
*/
/* append rest of current input path to link target */
tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
tp = shf_smprintf(Tf_sss, ldest, *ip ? "/" : "", ip);
afree(ipath, ATEMP);
ip = ipath = tp;
if (!mksh_abspath(ldest)) {
@ -1831,12 +1832,12 @@ c_cd(const char **wp)
wp += builtin_opt.optind;
if (Flag(FRESTRICTED)) {
bi_errorf("restricted shell - can't cd");
bi_errorf(Tcant_cd);
return (2);
}
pwd_s = global("PWD");
oldpwd_s = global("OLDPWD");
pwd_s = global(TPWD);
oldpwd_s = global(TOLDPWD);
if (!wp[0]) {
/* No arguments - go home */
@ -1852,7 +1853,7 @@ c_cd(const char **wp)
allocd = NULL;
dir = str_val(oldpwd_s);
if (dir == null) {
bi_errorf("no OLDPWD");
bi_errorf(Tno_OLDPWD);
return (2);
}
printpath = true;
@ -1892,7 +1893,7 @@ c_cd(const char **wp)
memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
printpath = true;
} else {
bi_errorf("too many arguments");
bi_errorf(Ttoo_many_args);
return (2);
}
@ -1916,9 +1917,9 @@ c_cd(const char **wp)
if (rv < 0) {
if (cdnode)
bi_errorf("%s: %s", dir, "bad directory");
bi_errorf(Tf_sD_s, dir, "bad directory");
else
bi_errorf("%s: %s", tryp, cstrerror(errno));
bi_errorf(Tf_sD_s, tryp, cstrerror(errno));
afree(allocd, ATEMP);
Xfree(xs, xp);
return (2);
@ -1967,7 +1968,7 @@ c_cd(const char **wp)
rv = 1;
}
if (printpath || cdnode)
shprintf("%s\n", pwd);
shprintf(Tf_sN, pwd);
afree(allocd, ATEMP);
Xfree(xs, xp);
@ -2002,18 +2003,18 @@ chvt(const Getopt *go)
memmove(cp + 1, cp, /* /dev/tty */ 8);
dv = cp + 1;
if (stat(dv, &sb)) {
errorf("%s: %s: %s", "chvt",
errorf(Tf_sD_sD_s, "chvt",
"can't find tty", go->optarg);
}
}
}
if (!(sb.st_mode & S_IFCHR))
errorf("%s: %s: %s", "chvt", "not a char device", dv);
errorf(Tf_sD_sD_s, "chvt", "not a char device", dv);
#ifndef MKSH_DISABLE_REVOKE_WARNING
#if HAVE_REVOKE
if (revoke(dv))
#endif
warningf(false, "%s: %s %s", "chvt",
warningf(false, Tf_sD_s_s, "chvt",
"new shell is potentially insecure, can't revoke",
dv);
#endif
@ -2022,13 +2023,13 @@ chvt(const Getopt *go)
if ((fd = binopen2(dv, O_RDWR)) < 0) {
sleep(1);
if ((fd = binopen2(dv, O_RDWR)) < 0) {
errorf("%s: %s %s", "chvt", "can't open", dv);
errorf(Tf_sD_s_s, "chvt", Tcant_open, dv);
}
}
if (go->optarg[0] != '!') {
switch (fork()) {
case -1:
errorf("%s: %s %s", "chvt", "fork", "failed");
errorf(Tf_sD_s_s, "chvt", "fork", "failed");
case 0:
break;
default:
@ -2036,12 +2037,12 @@ chvt(const Getopt *go)
}
}
if (setsid() == -1)
errorf("%s: %s %s", "chvt", "setsid", "failed");
errorf(Tf_sD_s_s, "chvt", "setsid", "failed");
if (go->optarg[0] != '-') {
if (ioctl(fd, TIOCSCTTY, NULL) == -1)
errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
errorf(Tf_sD_s_s, "chvt", "TIOCSCTTY", "failed");
if (tcflush(fd, TCIOFLUSH))
errorf("%s: %s %s", "chvt", "TCIOFLUSH", "failed");
errorf(Tf_sD_s_s, "chvt", "TCIOFLUSH", "failed");
}
ksh_dup2(fd, 0, false);
ksh_dup2(fd, 1, false);

214
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.399 2016/06/25 23:52:06 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.413 2016/08/10 18:20:05 tg Exp $
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -76,7 +76,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: June 25 2016 $
.Dd $Mdocdate: August 10 2016 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@ -1682,6 +1682,25 @@ Inefficiently implemented, may be slow.
.Pp
.Sm off
.It Xo
.Pf ${ Ar name
.Pf @/ Ar pattern / Ar string No }
.Xc
.Sm on
The same as
.Sm off
.Xo
.Pf ${ Ar name
.Pf // Ar pattern / Ar string No } ,
.Xc
.Sm on
except that both
.Ar pattern
and
.Ar string
are expanded anew for each iteration.
.Pp
.Sm off
.It Xo
.Pf ${ Ar name : Ns Ar pos
.Pf : Ns Ar len Ns }
.Xc
@ -1854,12 +1873,16 @@ binding to the actual terminal size in favour of the provided value.
If this parameter is found to be set after any profile files are executed, the
expanded value is used as a shell startup file.
It typically contains function and alias definitions.
.It Ev ERRNO
Integer value of the shell's
.Va errno
variable.
It indicates the reason the last system call failed.
Not yet implemented.
.It Ev EPOCHREALTIME
Time since the epoch, as returned by
.Xr gettimeofday 2 ,
formatted as decimal
.Va tv_sec
followed by a dot
.Pq Sq \&.
and
.Va tv_usec
padded to exactly six decimal digits.
.It Ev EXECSHELL
If set, this parameter is assumed to contain the shell that is to be used to
execute commands that
@ -1929,6 +1952,70 @@ The effective group id of the shell.
The real group id of the shell.
.It Ev KSHUID
The real user id of the shell.
.It Ev KSH_MATCH
The last matched string.
In a future version, this will be an indexed array,
with indexes 1 and up capturing matching groups.
Set by string comparisons (== and !=) in double-bracket test
expressions when a match is found (when != returns false), by
.Ic case
when a match is encountered, and by the substitution operations
.Sm off
.Xo
.Pf ${ Ar x
.Pf # Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf ## Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf % Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf %% Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf / Ar pat / Ar rpl No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf /# Ar pat / Ar rpl No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf /% Ar pat / Ar rpl No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf // Ar pat / Ar rpl No } ,
.Sm on
.Xc
and
.Sm off
.Xo
.Pf ${ Ar x
.Pf @/ Ar pat / Ar rpl No } .
.Sm on
.Xc
See the end of the Emacs editing mode documentation for an example.
.It Ev KSH_VERSION
The name and version of the shell (read-only).
See also the version commands in
@ -1944,16 +2031,6 @@ Set to the number of lines on the terminal or window.
Always set, defaults to 24.
See
.Ev COLUMNS .
.It Ev EPOCHREALTIME
Time since the epoch, as returned by
.Xr gettimeofday 2 ,
formatted as decimal
.Va tv_sec
followed by a dot
.Pq Sq \&.
and
.Va tv_usec
padded to exactly six decimal digits.
.It Ev OLDPWD
The previous working directory.
Unset if
@ -2138,7 +2215,7 @@ If the login name is empty,
.Ql + ,
or
.Ql \- ,
the value of the
the simplified value of the
.Ev HOME ,
.Ev PWD ,
or
@ -2463,12 +2540,6 @@ indicating the file descriptor associated with the output of the current
co-process; or the character
.Ql \- ,
indicating standard input is to be closed.
.Pp
Note that the current version of
.Nm
supports some two-digit fd numbers in some environments;
this feature is deprecated and will be removed from a subsequent release
in favour of a ksh93-/perl-style "named file descriptors" feature.
.It \*(Gt& Ns Ar fd
Same as
.Ic \*(Lt& ,
@ -2573,7 +2644,7 @@ Unary operators:
Binary operators:
.Bd -literal -offset indent
,
= += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt= \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
= += \-= *= /= %= \*(Lt\*(Lt= \*(Gt\*(Gt= \*(ha\*(Lt= \*(ha\*(Gt= &= \*(ha= \*(Ba=
\*(Ba\*(Ba
&&
\*(Ba
@ -2581,7 +2652,7 @@ Binary operators:
&
== !=
\*(Lt \*(Lt= \*(Gt \*(Gt=
\*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt \*(Lt\*(Lt \*(Gt\*(Gt
\*(Lt\*(Lt \*(Gt\*(Gt \*(ha\*(Lt \*(ha\*(Gt
+ \-
* / %
.Ed
@ -2602,7 +2673,7 @@ Integer constants may be specified with arbitrary bases using the notation
.Ar base Ns # Ns Ar number ,
where
.Ar base
is a decimal integer specifying the base, and
is a decimal integer specifying the base (up to 36), and
.Ar number
is a number in the specified base.
Additionally, base-16 integers may be specified by prefixing them with
@ -2610,10 +2681,11 @@ Additionally, base-16 integers may be specified by prefixing them with
.Pq case-insensitive
in all forms of arithmetic expressions, except as numeric arguments to the
.Ic test
built-in command.
built-in utility.
Prefixing numbers with a sole digit zero
.Pq Sq 0
does not cause interpretation as octal, as that's unsafe to do.
does not cause interpretation as octal (except in POSIX mode,
as required by the standard), as that's unsafe to do.
.Pp
As a special
.Nm mksh
@ -2670,8 +2742,8 @@ The result is the value of the expression on the right-hand side.
.It =
Assignment; the variable on the left is set to the value on the right.
.It Xo
.No += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt=
.No \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
.No += \-= *= /= %= \*(Lt\*(Lt= \*(Gt\*(Gt=
.No \*(ha\*(Lt= \*(ha\*(Gt= &= \*(ha= \*(Ba=
.Xc
Assignment operators.
.Sm off
@ -2721,20 +2793,14 @@ not.
Less than or equal, greater than, greater than or equal.
See
.Ic \*(Lt .
.It \*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt
Rotate left (right); the result is similar to shift (see
.Ic \*(Lt\*(Lt )
.It \*(Lt\*(Lt \*(Gt\*(Gt
Shift left (right); the result is the left argument with its bits
arithmetically (signed operation) or logically (unsigned expression)
shifted left (right) by the amount given in the right argument.
.It \*(ha\*(Lt \*(ha\*(Gt
Rotate left (right); the result is similar to shift,
except that the bits shifted out at one end are shifted in
at the other end, instead of zero or sign bits.
.Pp
.Em Note :
These operators are deprecated; in a subsequent mksh release,
.Ic \*(ha\*(Lt No and Ic \*(ha\*(Gt
.No will replace them, and Ic \*(Gt\*(Gt\*(Gt
will be an arithmetic right shift.
.It \*(Lt\*(Lt \*(Gt\*(Gt
Shift left (right); the result is the left argument with its bits logically
shifted left (right) by the amount given in the right argument.
.It + \- * /
Addition, subtraction, multiplication, and division.
.It %
@ -3714,7 +3780,7 @@ however, distributors may have added this as builtin as a speed hack.
.Pp
.It Xo
.Ic print
.Oo Fl nprsu Ns Oo Ar n Oc \*(Ba
.Oo Fl Anprsu Ns Oo Ar n Oc \*(Ba
.Fl R Op Fl en Oc
.Op Ar argument ...
.Xc
@ -3750,6 +3816,10 @@ and the
option prints to the co-process (see
.Sx Co-processes
above).
The
.Fl A
option prints the character corresponding to each
.Ar argument Ns 's value .
.Pp
The
.Fl R
@ -3977,6 +4047,9 @@ it's also checked for existence and whether it is a directory; otherwise,
.Ic realpath
returns 0 if the pathname either exists or can be created immediately,
i.e. all but the last component exist and are directories.
For calls from the shell, if any options are given, an external
.Xr realpath 1
utility is preferred over the builtin.
.Pp
.It Xo
.Ic rename
@ -3988,9 +4061,10 @@ Renames the file
to
.Ar to .
Both must be complete pathnames and on the same device.
This builtin is intended for emergency situations where
.Pa /bin/mv
becomes unusable, and directly calls
An external utility is preferred over this builtin,
which is intended for emergency situations
.Pq where Pa /bin/mv No becomes unusable
and directly calls
.Xr rename 2 .
.Pp
.It Ic return Op Ar status
@ -5351,7 +5425,7 @@ The
builtin does not interpret backslashes and only supports the exact option
.Dq Fl n .
.It
\&... (list is incomplete and may change for R53)
\&... (list is incomplete and may change for R54)
.El
.Ss SH mode
Compatibility mode; intended for use with legacy scripts that
@ -5372,7 +5446,35 @@ The
builtin does not interpret backslashes and only supports the exact option
.Dq Fl n .
.It
\&... (list is incomplete and may change for R53)
The substitution operations
.Sm off
.Xo
.Pf ${ Ar x
.Pf # Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf ## Ar pat No } ,
.Sm on
.Xc
.Sm off
.Xo
.Pf ${ Ar x
.Pf % Ar pat No } ,
.Sm on
.Xc
and
.Sm off
.Xo
.Pf ${ Ar x
.Pf %% Ar pat No }
.Sm on
.Xc
wrongly do not require a parenthesis to be escaped and do not parse extglobs.
.It
\&... (list is incomplete and may change for R54)
.El
.Ss Interactive input line editing
The shell supports three modes of reading command lines from a
@ -5619,6 +5721,11 @@ otherwise,
.Ic delete\-char\-forward .
.It error: (not bound)
Error (ring the bell).
.It evaluate\-region: \*(ha[\*(haE
Evaluates the text between the mark and the cursor position
.Pq the entire line if no mark is set
as function substitution (if it cannot be parsed, the editing state is
unchanged and the bell is rung to signal an error); $? is updated accordingly.
.It exchange\-point\-and\-mark: \*(haX\*(haX
Places the cursor where the mark is and sets the mark to where the cursor was.
.It expand\-file: \*(ha[*
@ -5799,6 +5906,11 @@ Immediately after a
.Ic yank ,
replaces the inserted text string with the next previously killed text string.
.El
.Pp
The tab completion escapes characters the same way as the following code:
.Bd -literal
print \-nr \-\- "${x@/[\e"\-\e$\e&\-*:\-?[\e\e\e\`{\-\e}${IFS\-$\*(aq \et\en\*(aq}]/\e\e$KSH_MATCH}"
.Ed
.Ss Vi editing mode
.Em Note:
The vi command-line editing mode is orphaned, yet still functional.
@ -6612,7 +6724,7 @@ for the in-memory portion of the history is slow, should use
.Xr memmove 3 .
.Pp
This document attempts to describe
.Nm mksh\ R52d
.Nm mksh\ R53
and up,
.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as

441
sh.h
View File

@ -175,9 +175,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.774 2016/06/26 00:44:59 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.785 2016/08/10 18:20:18 tg Exp $");
#endif
#define MKSH_VERSION "R52 2016/06/25"
#define MKSH_VERSION "R53 2016/08/04"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@ -578,7 +578,7 @@ char *ucstrstr(char *, const char *);
#define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif
#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 523)
#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 530)
#error Must run Build.sh to compile this.
extern void thiswillneverbedefinedIhope(void);
int
@ -634,17 +634,11 @@ im_sorry_dave(void)
#ifndef MKSH_NO_CMDLINE_EDITING
#define MKSH_NO_CMDLINE_EDITING /* defined */
#endif
#ifndef MKSH_CONSERVATIVE_FDS
#define MKSH_CONSERVATIVE_FDS /* defined */
#endif
#undef MKSH_S_NOVI
#define MKSH_S_NOVI 1
#endif
#ifdef MKSH_SMALL
#ifndef MKSH_CONSERVATIVE_FDS
#define MKSH_CONSERVATIVE_FDS /* defined */
#endif
#ifndef MKSH_NOPWNAM
#define MKSH_NOPWNAM /* defined */
#endif
@ -661,14 +655,8 @@ im_sorry_dave(void)
#define MKSH_UNEMPLOYED 1
#endif
/* these shall be smaller than 100 */
#ifdef MKSH_CONSERVATIVE_FDS
#define NUFILE 32 /* Number of user-accessible files */
#define FDBASE 10 /* First file usable by Shell */
#else
#define NUFILE 56 /* Number of user-accessible files */
#define FDBASE 24 /* First file usable by Shell */
#endif
/*
* simple grouping allocator
@ -844,53 +832,320 @@ EXTERN struct {
#define OF_FIRSTTIME 0x10 /* as early as possible, once */
#define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
/* trust GCC to have string pooling; -Wformat bitches otherwise */
/*XXX TODO: make this with a .gen file plus not imake-style */
/* null value for variable; comparison pointer for unset */
EXTERN char null[] E_INIT("");
/* helpers for string pooling */
#if defined(__GNUC__)
#define Tsynerr "syntax error"
#define Tintovfl "integer overflow %zu %c %zu prevented"
#define Toomem "can't allocate %zu data bytes"
#else
EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
EXTERN const char Tsynerr[] E_INIT("syntax error");
/* string pooling: do we rely on the compiler? */
#ifndef HAVE_STRING_POOLING
/* no, we use our own, saves quite some space */
#elif HAVE_STRING_POOLING == 2
/* “on demand” */
#ifdef __GNUC__
/* only for GCC 4 or later, older ones can get by without */
#if __GNUC__ < 4
#undef HAVE_STRING_POOLING
#endif
EXTERN const char Tselect[] E_INIT("select");
EXTERN const char T_typeset[] E_INIT("=typeset");
#define Ttypeset (T_typeset + 1) /* "typeset" */
#else
/* not GCC, default to on */
#endif
#elif HAVE_STRING_POOLING == 0
/* default to on, unless explicitly set to 0 */
#undef HAVE_STRING_POOLING
#endif
#ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
EXTERN const char T4spaces[] E_INIT(" ");
#define T1space (T4spaces + 3)
EXTERN const char Tcolsp[] E_INIT(": ");
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7)
EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
#define Tspdollaru (TFCEDIT_dollaru + 18)
EXTERN const char Tsgdot[] E_INIT("*=.");
EXTERN const char Taugo[] E_INIT("augo");
EXTERN const char Tbracket[] E_INIT("[");
#define Tdot (Tsgdot + 2)
EXTERN const char Talias[] E_INIT("alias");
EXTERN const char Tunalias[] E_INIT("unalias");
EXTERN const char Tcat[] E_INIT("cat");
EXTERN const char Tbadsubst[] E_INIT("bad substitution");
EXTERN const char Tbg[] E_INIT("bg");
EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
#define Tbsize (Tbad_bsize + 12)
EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
#define Tbad_sig_s (Tbad_sig_ss + 4)
EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1)
EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd");
EXTERN const char Tcant_find[] E_INIT("can't find");
EXTERN const char Tcant_open[] E_INIT("can't open");
#define Tbytes (Toomem + 24)
EXTERN const char Tbcat[] E_INIT("!cat");
#define Tcat (Tbcat + 1)
#define Tcd (Tcant_cd + 25)
EXTERN const char Tcommand[] E_INIT("command");
EXTERN const char Tcreate[] E_INIT("create");
EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
EXTERN const char Tsgexport[] E_INIT("*=export");
#define Texport (Tsgexport + 2)
#ifdef __OS2__
EXTERN const char Textproc[] E_INIT("extproc");
#endif
#ifdef MKSH_PRINTF_BUILTIN
EXTERN const char Tprintf[] E_INIT("printf");
#endif
EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tsgset + 2) /* "set" */
EXTERN const char Tsgexport[] E_INIT("*=export");
#define Texport (Tsgexport + 2) /* "export" */
EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
#define Treadonly (Tsgreadonly + 2) /* "readonly" */
EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1) /* "function" */
EXTERN const char T_funny_command[] E_INIT("funny $() command");
#define Tcommand (T_funny_command + 10) /* "command" */
#if defined(__GNUC__)
#define Tfg_badsubst "fileglob: bad substitution"
#else
EXTERN const char Tfalse[] E_INIT("false");
EXTERN const char Tfg[] E_INIT("fg");
EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution");
EXTERN const char Tfile[] E_INIT("file");
EXTERN const char Tfile_fd[] E_INIT("function definition file");
EXTERN const char TFPATH[] E_INIT("FPATH");
EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1)
EXTERN const char T_funny_command[] E_INIT("funny $() command");
EXTERN const char Tgetopts[] E_INIT("getopts");
EXTERN const char Thistory[] E_INIT("history");
EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
EXTERN const char Tjobs[] E_INIT("jobs");
EXTERN const char Tjob_not_started[] E_INIT("job not started");
EXTERN const char Tmksh[] E_INIT("mksh");
EXTERN const char Tname[] E_INIT("name");
EXTERN const char Tno_args[] E_INIT("missing argument");
EXTERN const char Tno_OLDPWD[] E_INIT("no OLDPWD");
EXTERN const char Tnot_ident[] E_INIT("is not an identifier");
EXTERN const char Tnot_in_history[] E_INIT("not in history");
EXTERN const char Tnot_found_s[] E_INIT("%s not found");
#define Tnot_found (Tnot_found_s + 3)
#define Tnot_started (Tjob_not_started + 4)
#define TOLDPWD (Tno_OLDPWD + 3)
#define Topen (Tcant_open + 6)
#define TPATH (TFPATH + 1)
EXTERN const char Tpv[] E_INIT("pv");
EXTERN const char TpVv[] E_INIT("Vpv");
#define TPWD (Tno_OLDPWD + 6)
EXTERN const char Tread[] E_INIT("read");
EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
#define Treadonly (Tsgreadonly + 2)
EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
#define Tredirection (Tredirection_dup + 19)
EXTERN const char Treal_sp1[] E_INIT("real ");
EXTERN const char Treal_sp2[] E_INIT(" real ");
EXTERN const char Treq_arg[] E_INIT("requires an argument");
EXTERN const char Tselect[] E_INIT("select");
EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tsgset + 2)
#define Tsh (Tmksh + 2)
#define TSHELL (TEXECSHELL + 4)
EXTERN const char Tshf_read[] E_INIT("shf_read");
EXTERN const char Tshf_write[] E_INIT("shf_write");
EXTERN const char Tj_suspend[] E_INIT("j_suspend");
#define Tsuspend (Tj_suspend + 2)
EXTERN const char Tsynerr[] E_INIT("syntax error");
EXTERN const char Ttime[] E_INIT("time");
EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
EXTERN const char Ttrue[] E_INIT("true");
EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
#define Ttty_fd (Ttty_fd_dupof + 7)
EXTERN const char Tgtypeset[] E_INIT("=typeset");
#define Ttypeset (Tgtypeset + 1)
#define Tugo (Taugo + 1)
EXTERN const char Tunalias[] E_INIT("unalias");
#define Tunexpected (TELIF_unexpected + 6)
EXTERN const char Tunknown_option[] E_INIT("unknown option");
EXTERN const char Tuser_sp1[] E_INIT("user ");
EXTERN const char Tuser_sp2[] E_INIT(" user ");
#define Twrite (Tshf_write + 4)
EXTERN const char Tf__S[] E_INIT(" %S");
EXTERN const char Tf__d[] E_INIT(" %d");
EXTERN const char Tf__ss[] E_INIT(" %s%s");
EXTERN const char Tf__sN[] E_INIT(" %s\n");
EXTERN const char Tf_sSs[] E_INIT("%s/%s");
EXTERN const char Tf_T[] E_INIT("%T");
EXTERN const char Tf_dN[] E_INIT("%d\n");
EXTERN const char Tf_s_[] E_INIT("%s ");
EXTERN const char Tf_s_T[] E_INIT("%s %T");
EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
EXTERN const char Tf_s_s[] E_INIT("%s %s");
EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s");
EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
EXTERN const char Tf_sD_[] E_INIT("%s: ");
EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
EXTERN const char Tf_parm[] E_INIT("%s: parameter not set");
EXTERN const char Tf_coproc[] E_INIT("-p: %s");
EXTERN const char Tf_cant[] E_INIT("can't %s %s: %s");
EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed\n");
#if HAVE_MKNOD
EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
#endif
#define Tbadsubst (Tfg_badsubst + 10) /* "bad substitution" */
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */
EXTERN const char Tf_S_[] E_INIT("%S ");
#define Tf_S (Tf__S + 1)
EXTERN const char Tf_lu[] E_INIT("%lu");
EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu");
EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s");
#define Tf_ss (Tf__ss + 1)
EXTERN const char Tf_sss[] E_INIT("%s%s%s");
EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s");
EXTERN const char Tf_toomany[] E_INIT("too many %ss\n");
EXTERN const char Tf_sd[] E_INIT("%s %d");
#define Tf_s (Tf__ss + 3)
EXTERN const char Tft_end[] E_INIT("%;");
EXTERN const char Tft_R[] E_INIT("%R");
#define Tf_d (Tf__d + 1)
EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'");
EXTERN const char Tf_ro[] E_INIT("read-only: %s");
EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
EXTERN const char Tf_temp[] E_INIT("can't %s temporary file %s: %s");
EXTERN const char Tf_ssfaileds[] E_INIT("%s: %s failed: %s");
EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s");
EXTERN const char Tf__c_[] E_INIT("-%c ");
EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s");
#define Tf_sN (Tf__sN + 1)
#define Tf_sD_s (Tf_s_sD_s + 3)
EXTERN const char T_devtty[] E_INIT("/dev/tty");
#else /* helpers for string pooling */
#define T4spaces " "
#define T1space " "
#define Tcolsp ": "
#define TC_LEX1 "|&;<>() \t\n"
#define TC_IFSWS " \t\n"
#define TFCEDIT_dollaru "${FCEDIT:-/bin/ed} $_"
#define Tspdollaru " $_"
#define Tsgdot "*=."
#define Taugo "augo"
#define Tbracket "["
#define Tdot "."
#define Talias "alias"
#define Tbadsubst "bad substitution"
#define Tbg "bg"
#define Tbad_bsize "bad shf/buf/bsize"
#define Tbsize "bsize"
#define Tbad_sig_ss "%s: bad signal '%s'"
#define Tbad_sig_s "bad signal '%s'"
#define Tgbuiltin "=builtin"
#define Tbuiltin "builtin"
#define Toomem "can't allocate %zu data bytes"
#define Tcant_cd "restricted shell - can't cd"
#define Tcant_find "can't find"
#define Tcant_open "can't open"
#define Tbytes "bytes"
#define Tbcat "!cat"
#define Tcat "cat"
#define Tcd "cd"
#define Tcommand "command"
#define Tcreate "create"
#define TELIF_unexpected "TELIF unexpected"
#define TEXECSHELL "EXECSHELL"
#define Tsgexport "*=export"
#define Texport "export"
#ifdef __OS2__
#define Textproc "extproc"
#endif
#define Tfalse "false"
#define Tfg "fg"
#define Tfg_badsubst "fileglob: bad substitution"
#define Tfile "file"
#define Tfile_fd "function definition file"
#define TFPATH "FPATH"
#define T_function " function"
#define Tfunction "function"
#define T_funny_command "funny $() command"
#define Tgetopts "getopts"
#define Thistory "history"
#define Tintovfl "integer overflow %zu %c %zu prevented"
#define Tjobs "jobs"
#define Tjob_not_started "job not started"
#define Tmksh "mksh"
#define Tname "name"
#define Tno_args "missing argument"
#define Tno_OLDPWD "no OLDPWD"
#define Tnot_ident "is not an identifier"
#define Tnot_in_history "not in history"
#define Tnot_found_s "%s not found"
#define Tnot_found "not found"
#define Tnot_started "not started"
#define TOLDPWD "OLDPWD"
#define Topen "open"
#define TPATH "PATH"
#define Tpv "pv"
#define TpVv "Vpv"
#define TPWD "PWD"
#define Tread "read"
#define Tsgreadonly "*=readonly"
#define Treadonly "readonly"
#define Tredirection_dup "can't finish (dup) redirection"
#define Tredirection "redirection"
#define Treal_sp1 "real "
#define Treal_sp2 " real "
#define Treq_arg "requires an argument"
#define Tselect "select"
#define Tsgset "*=set"
#define Tset "set"
#define Tsh "sh"
#define TSHELL "SHELL"
#define Tshf_read "shf_read"
#define Tshf_write "shf_write"
#define Tj_suspend "j_suspend"
#define Tsuspend "suspend"
#define Tsynerr "syntax error"
#define Ttime "time"
#define Ttoo_many_args "too many arguments"
#define Ttrue "true"
#define Ttty_fd_dupof "dup of tty fd"
#define Ttty_fd "tty fd"
#define Tgtypeset "=typeset"
#define Ttypeset "typeset"
#define Tugo "ugo"
#define Tunalias "unalias"
#define Tunexpected "unexpected"
#define Tunknown_option "unknown option"
#define Tuser_sp1 "user "
#define Tuser_sp2 " user "
#define Twrite "write"
#define Tf__S " %S"
#define Tf__d " %d"
#define Tf__ss " %s%s"
#define Tf__sN " %s\n"
#define Tf_sSs "%s/%s"
#define Tf_T "%T"
#define Tf_dN "%d\n"
#define Tf_s_ "%s "
#define Tf_s_T "%s %T"
#define Tf_s_s_sN "%s %s %s\n"
#define Tf_s_s "%s %s"
#define Tf_s_sD_s "%s %s: %s"
#define Tf_optfoo "%s%s-%c: %s"
#define Tf_sD_ "%s: "
#define Tf_szs "%s: %zd %s"
#define Tf_parm "%s: parameter not set"
#define Tf_coproc "-p: %s"
#define Tf_cant "can't %s %s: %s"
#define Tf_heredoc "here document '%s' unclosed\n"
#if HAVE_MKNOD
#define Tf_nonnum "non-numeric %s %s '%s'"
#endif
#define Tf_S_ "%S "
#define Tf_S "%S"
#define Tf_lu "%lu"
#define Tf_toolarge "%s %s too large: %lu"
#define Tf_ldfailed "%s %s(%d, %ld) failed: %s"
#define Tf_ss "%s%s"
#define Tf_sss "%s%s%s"
#define Tf_sD_s_sD_s "%s: %s %s: %s"
#define Tf_toomany "too many %ss\n"
#define Tf_sd "%s %d"
#define Tf_s "%s"
#define Tft_end "%;"
#define Tft_R "%R"
#define Tf_d "%d"
#define Tf_sD_s_qs "%s: %s '%s'"
#define Tf_ro "read-only: %s"
#define Tf_flags "%s: flags 0x%X"
#define Tf_temp "can't %s temporary file %s: %s"
#define Tf_ssfaileds "%s: %s failed: %s"
#define Tf_sD_sD_s "%s: %s: %s"
#define Tf__c_ "-%c "
#define Tf_sD_s_s "%s: %s %s"
#define Tf_sN "%s\n"
#define Tf_sD_s "%s: %s"
#define T_devtty "/dev/tty"
#endif /* end of string pooling */
typedef uint8_t Temp_type;
/* expanded heredoc */
@ -1087,18 +1342,9 @@ EXTERN char *current_wd;
#else
#define LINE (16384 - ALLOC_OVERHEAD)
#endif
/*
* Minimum required space to work with on a line - if the prompt leaves
* less space than this on a line, the prompt is truncated.
*/
#define MIN_EDIT_SPACE 7
/*
* Minimum allowed value for x_cols: 2 for prompt, 3 for " < " at end of line
*/
#define MIN_COLS (2 + MIN_EDIT_SPACE + 3)
#define MIN_LINS 3
EXTERN mksh_ari_t x_cols E_INIT(80); /* tty columns */
EXTERN mksh_ari_t x_lins E_INIT(24); /* tty lines */
/* columns and lines of the tty */
EXTERN mksh_ari_t x_cols E_INIT(80);
EXTERN mksh_ari_t x_lins E_INIT(24);
/* Determine the location of the system (common) profile */
@ -1127,7 +1373,7 @@ EXTERN mksh_ari_t x_lins E_INIT(24); /* tty lines */
(shf)->rnleft--, *(shf)->rp++ : \
shf_getchar(shf))
#define shf_putc_i(c, shf) ((shf)->wnleft == 0 ? \
shf_putchar((c), (shf)) : \
shf_putchar((uint8_t)(c), (shf)) : \
((shf)->wnleft--, *(shf)->wp++ = (c)))
#define shf_eof(shf) ((shf)->flags & SHF_EOF)
#define shf_error(shf) ((shf)->flags & SHF_ERROR)
@ -1252,6 +1498,9 @@ EXTERN bool last_lookup_was_array;
#define FDELETE BIT(10) /* function deleted while it was executing */
#define FKSH BIT(11) /* function defined with function x (vs x()) */
#define SPEC_BI BIT(12) /* a POSIX special builtin */
#define LOWER_BI BIT(13) /* (with LOW_BI) override even w/o flags */
#define LOW_BI BIT(14) /* external utility overrides built-in one */
/*
* Attributes that can be set by the user (used to decide if an unset
* param should be repoted by set/typeset). Does not include ARRAY or
@ -1489,9 +1738,14 @@ struct ioword {
#define X_EXTRA 20 /* this many extra bytes in X string */
typedef struct XString {
char *end, *beg; /* end, begin of string */
size_t len; /* length */
Area *areap; /* area to allocate/free from */
/* begin of string */
char *beg;
/* length of allocated area, minus safety margin */
size_t len;
/* end of string */
char *end;
/* memory area used */
Area *areap;
} XString;
typedef char *XStringP;
@ -1577,24 +1831,39 @@ typedef struct {
typedef struct source Source;
struct source {
const char *str; /* input pointer */
const char *start; /* start of current buffer */
/* input buffer */
XString xs;
/* memory area, also checked in reclaim() */
Area *areap;
/* stacked source */
Source *next;
/* input pointer */
const char *str;
/* start of current buffer */
const char *start;
/* input file name */
const char *file;
/* extra data */
union {
const char **strv; /* string [] */
struct shf *shf; /* shell file */
struct tbl *tblp; /* alias (SF_HASALIAS) */
char *freeme; /* also for SREREAD */
/* string[] */
const char **strv;
/* shell file */
struct shf *shf;
/* alias (SF_HASALIAS) */
struct tbl *tblp;
/* (also for SREREAD) */
char *freeme;
} u;
const char *file; /* input file name */
int type; /* input type */
int line; /* line number */
int errline; /* line the error occurred on (0 if not set) */
int flags; /* SF_* */
Area *areap;
Source *next; /* stacked source */
XString xs; /* input buffer */
char ugbuf[2]; /* buffer for ungetsc() (SREREAD) and
* alias (SALIAS) */
/* flags */
int flags;
/* input type */
int type;
/* line number */
int line;
/* line the error occurred on (0 if not set) */
int errline;
/* buffer for ungetsc() (SREREAD) and alias (SALIAS) */
char ugbuf[2];
};
/* Source.type values */
@ -1731,6 +2000,7 @@ void x_done(void);
int x_read(char *);
#endif
void x_mkraw(int, mksh_ttyst *, bool);
void x_initterm(const char *);
/* eval.c */
char *substitute(const char *, int);
char **eval(const char **, int);
@ -2077,6 +2347,7 @@ uint32_t chvt_rndsetup(const void *, size_t) MKSH_A_PURE;
mksh_ari_t rndget(void);
void rndset(unsigned long);
void rndpush(const void *);
void record_match(const char *);
enum Test_op {
/* non-operator */

32
shf.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.74 2016/05/17 15:36:35 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.76 2016/07/25 00:04:47 tg Exp $");
/* flags to shf_emptybuf() */
#define EB_READSW 0x01 /* about to switch to reading */
@ -119,7 +119,7 @@ shf_open_hlp(int fd, int *sflagsp, const char *where)
}
if (!(sflags & (SHF_RD | SHF_WR)))
internal_errorf("%s: %s", where, "missing read/write");
internal_errorf(Tf_sD_s, where, "missing read/write");
}
/* Set up the shf structure for a file descriptor. Doesn't fail. */
@ -167,7 +167,7 @@ shf_reopen(int fd, int sflags, struct shf *shf)
shf_open_hlp(fd, &sflags, "shf_reopen");
if (!shf || !shf->buf || shf->bsize < bsize)
internal_errorf("%s: %s", "shf_reopen", "bad shf/buf/bsize");
internal_errorf(Tf_sD_s, "shf_reopen", Tbad_bsize);
/* assumes shf->buf and shf->bsize already set up */
shf->fd = fd;
@ -197,7 +197,7 @@ shf_sopen(char *buf, ssize_t bsize, int sflags, struct shf *shf)
{
/* can't have a read+write string */
if (!(!(sflags & SHF_RD) ^ !(sflags & SHF_WR)))
internal_errorf("%s: flags 0x%X", "shf_sopen",
internal_errorf(Tf_flags, "shf_sopen",
(unsigned int)sflags);
if (!shf) {
@ -293,7 +293,7 @@ shf_flush(struct shf *shf)
return ((shf->flags & SHF_WR) ? -1 : 0);
if (shf->fd < 0)
internal_errorf("%s: %s", "shf_flush", "no fd");
internal_errorf(Tf_sD_s, "shf_flush", "no fd");
if (shf->flags & SHF_ERROR) {
errno = shf->errnosv;
@ -324,7 +324,7 @@ shf_emptybuf(struct shf *shf, int flags)
int ret = 0;
if (!(shf->flags & SHF_STRING) && shf->fd < 0)
internal_errorf("%s: %s", "shf_emptybuf", "no fd");
internal_errorf(Tf_sD_s, "shf_emptybuf", "no fd");
if (shf->flags & SHF_ERROR) {
errno = shf->errnosv;
@ -410,7 +410,7 @@ shf_fillbuf(struct shf *shf)
return (0);
if (shf->fd < 0)
internal_errorf("%s: %s", "shf_fillbuf", "no fd");
internal_errorf(Tf_sD_s, "shf_fillbuf", "no fd");
if (shf->flags & (SHF_EOF | SHF_ERROR)) {
if (shf->flags & SHF_ERROR)
@ -453,11 +453,11 @@ shf_read(char *buf, ssize_t bsize, struct shf *shf)
ssize_t ncopy, orig_bsize = bsize;
if (!(shf->flags & SHF_RD))
internal_errorf("%s: flags 0x%X", "shf_read",
internal_errorf(Tf_flags, Tshf_read,
(unsigned int)shf->flags);
if (bsize <= 0)
internal_errorf("%s: %s %zd", "shf_write", "bsize", bsize);
internal_errorf(Tf_szs, Tshf_read, bsize, Tbsize);
while (bsize > 0) {
if (shf->rnleft == 0 &&
@ -491,7 +491,7 @@ shf_getse(char *buf, ssize_t bsize, struct shf *shf)
char *orig_buf = buf;
if (!(shf->flags & SHF_RD))
internal_errorf("%s: flags 0x%X", "shf_getse",
internal_errorf(Tf_flags, "shf_getse",
(unsigned int)shf->flags);
if (bsize <= 0)
@ -528,7 +528,7 @@ int
shf_getchar(struct shf *shf)
{
if (!(shf->flags & SHF_RD))
internal_errorf("%s: flags 0x%X", "shf_getchar",
internal_errorf(Tf_flags, "shf_getchar",
(unsigned int)shf->flags);
if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0))
@ -545,7 +545,7 @@ int
shf_ungetc(int c, struct shf *shf)
{
if (!(shf->flags & SHF_RD))
internal_errorf("%s: flags 0x%X", "shf_ungetc",
internal_errorf(Tf_flags, "shf_ungetc",
(unsigned int)shf->flags);
if ((shf->flags & SHF_ERROR) || c == -1 ||
@ -583,7 +583,7 @@ int
shf_putchar(int c, struct shf *shf)
{
if (!(shf->flags & SHF_WR))
internal_errorf("%s: flags 0x%X", "shf_putchar",
internal_errorf(Tf_flags, "shf_putchar",
(unsigned int)shf->flags);
if (c == -1)
@ -594,7 +594,7 @@ shf_putchar(int c, struct shf *shf)
ssize_t n;
if (shf->fd < 0)
internal_errorf("%s: %s", "shf_putchar", "no fd");
internal_errorf(Tf_sD_s, "shf_putchar", "no fd");
if (shf->flags & SHF_ERROR) {
errno = shf->errnosv;
return (-1);
@ -639,11 +639,11 @@ shf_write(const char *buf, ssize_t nbytes, struct shf *shf)
ssize_t n, ncopy, orig_nbytes = nbytes;
if (!(shf->flags & SHF_WR))
internal_errorf("%s: flags 0x%X", "shf_write",
internal_errorf(Tf_flags, Tshf_write,
(unsigned int)shf->flags);
if (nbytes < 0)
internal_errorf("%s: %s %zd", "shf_write", "nbytes", nbytes);
internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes);
/* Don't buffer if buffer is empty and we're writting a large amount. */
if ((ncopy = shf->wnleft) &&

33
syn.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.111 2016/02/26 21:24:58 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.114 2016/08/04 20:32:14 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@ -208,7 +208,7 @@ synio(int cf)
iop->ioflag |= IOEVAL;
}
if (herep > &heres[HERES - 1])
yyerror("too many %ss\n", "<<");
yyerror(Tf_toomany, "<<");
*herep++ = iop;
} else
iop->ioname = yylval.cp;
@ -217,16 +217,7 @@ synio(int cf)
char *cp;
nextiop = alloc(sizeof(*iop), ATEMP);
#ifdef MKSH_CONSERVATIVE_FDS
nextiop->ioname = cp = alloc(3, ATEMP);
#else
nextiop->ioname = cp = alloc(5, ATEMP);
if (iop->unit > 9) {
*cp++ = CHAR;
*cp++ = digits_lc[iop->unit / 10];
}
#endif
*cp++ = CHAR;
*cp++ = digits_lc[iop->unit % 10];
*cp = EOS;
@ -312,8 +303,8 @@ get_command(int cf)
case REDIR:
while ((iop = synio(cf)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many %ss\n",
"redirection");
yyerror(Tf_toomany,
Tredirection);
iops[iopn++] = iop;
}
break;
@ -512,7 +503,7 @@ get_command(int cf)
while ((iop = synio(syniocf)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many %ss\n", "redirection");
yyerror(Tf_toomany, Tredirection);
iops[iopn++] = iop;
}
@ -813,7 +804,7 @@ static const struct tokeninfo {
{ "done", DONE, true },
{ "in", IN, true },
{ Tfunction, FUNCTION, true },
{ "time", TIME, true },
{ Ttime, TIME, true },
{ "{", '{', true },
{ Tcbrace, '}', true },
{ "!", BANG, true },
@ -860,7 +851,7 @@ syntaxerr(const char *what)
int c;
if (!what)
what = "unexpected";
what = Tunexpected;
REJECT;
c = token(0);
Again:
@ -877,11 +868,11 @@ syntaxerr(const char *what)
/* NOTREACHED */
case LWORD:
s = snptreef(NULL, 32, "%S", yylval.cp);
s = snptreef(NULL, 32, Tf_S, yylval.cp);
break;
case REDIR:
s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
s = snptreef(redir, sizeof(redir), Tft_R, yylval.iop);
break;
default:
@ -973,9 +964,11 @@ assign_command(const char *s, bool docommand)
static int
inalias(struct source *s)
{
for (; s && s->type == SALIAS; s = s->next)
while (s && s->type == SALIAS) {
if (!(s->flags & SF_ALIASEND))
return (1);
s = s->next;
}
return (0);
}
@ -1188,7 +1181,7 @@ yyrecursive(int subtype MKSH_A_UNUSED)
yyrecursive_pop(false);
/* t->left because nested(TPAREN, ...) hides our goodies there */
cp = snptreef(NULL, 0, "%T", t->left);
cp = snptreef(NULL, 0, Tf_T, t->left);
tfree(t, ATEMP);
return (cp);

42
tree.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.85 2016/06/26 00:09:35 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.86 2016/07/25 00:04:48 tg Exp $");
#define INDENT 8
@ -74,20 +74,20 @@ ptree(struct op *t, int indent, struct shf *shf)
ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) ||
/* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR &&
ccp[3] == '=' && ccp[4] == EOS))) {
fptreef(shf, indent, "%S", t->vars[0]);
fptreef(shf, indent, Tf_S, t->vars[0]);
break;
}
if (t->vars) {
w = (const char **)t->vars;
while (*w)
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, Tf_S_, *w++);
} else
shf_puts("#no-vars# ", shf);
if (t->args) {
w = t->args;
while (*w)
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, Tf_S_, *w++);
} else
shf_puts("#no-args# ", shf);
break;
@ -119,7 +119,7 @@ ptree(struct op *t, int indent, struct shf *shf)
w = t->args;
shf_puts("[[", shf);
while (*w)
fptreef(shf, indent, " %S", *w++);
fptreef(shf, indent, Tf__S, *w++);
shf_puts(" ]] ", shf);
break;
case TSELECT:
@ -130,8 +130,8 @@ ptree(struct op *t, int indent, struct shf *shf)
shf_puts("in ", shf);
w = (const char **)t->vars;
while (*w)
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, "%;");
fptreef(shf, indent, Tf_S_, *w++);
fptreef(shf, indent, Tft_end);
}
fptreef(shf, indent + INDENT, "do%N%T", t->left);
fptreef(shf, indent, "%;done ");
@ -151,11 +151,9 @@ ptree(struct op *t, int indent, struct shf *shf)
}
fptreef(shf, indent, "%Nesac ");
break;
#ifdef DEBUG
case TELIF:
internal_errorf("TELIF in tree.c:ptree() unexpected");
internal_errorf(TELIF_unexpected);
/* FALLTHROUGH */
#endif
case TIF:
i = 2;
t1 = t;
@ -163,19 +161,19 @@ ptree(struct op *t, int indent, struct shf *shf)
do {
t1 = t1->right;
i = 0;
fptreef(shf, indent, "%;");
fptreef(shf, indent, Tft_end);
process_TIF:
/* 5 == strlen("elif ") */
fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
t1 = t1->right;
if (t1->left != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent, Tft_end);
fptreef(shf, indent + INDENT, "%s%N%T",
"then", t1->left);
}
} while (t1->right && t1->right->type == TELIF);
if (t1->right != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent, Tft_end);
fptreef(shf, indent + INDENT, "%s%N%T",
"else", t1->right);
}
@ -184,10 +182,10 @@ ptree(struct op *t, int indent, struct shf *shf)
case TWHILE:
case TUNTIL:
/* 6 == strlen("while "/"until ") */
fptreef(shf, indent + 6, "%s %T",
fptreef(shf, indent + 6, Tf_s_T,
(t->type == TWHILE) ? "while" : "until",
t->left);
fptreef(shf, indent, "%;");
fptreef(shf, indent, Tft_end);
fptreef(shf, indent + INDENT, "do%N%T", t->right);
fptreef(shf, indent, "%;done ");
break;
@ -207,7 +205,7 @@ ptree(struct op *t, int indent, struct shf *shf)
fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
break;
case TTIME:
fptreef(shf, indent, "%s %T", "time", t->left);
fptreef(shf, indent, Tf_s_T, Ttime, t->left);
break;
default:
shf_puts("<botch>", shf);
@ -229,7 +227,7 @@ ptree(struct op *t, int indent, struct shf *shf)
iop->heredoc) {
shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
fptreef(shf, indent, Tf_s,
evalstr(iop->delim, 0));
need_nl = true;
}
@ -258,7 +256,7 @@ pioact(struct shf *shf, struct ioword *iop)
(type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
iop->unit + 1;
if (iop->unit != expected)
shf_fprintf(shf, "%d", (int)iop->unit);
shf_fprintf(shf, Tf_d, (int)iop->unit);
switch (type) {
case IOREAD:
@ -472,7 +470,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
break;
case 'd':
/* signed decimal */
shf_fprintf(shf, "%d", va_arg(va, int));
shf_fprintf(shf, Tf_d, va_arg(va, int));
break;
case 'u':
/* unsigned decimal */
@ -768,7 +766,7 @@ vistree(char *dst, size_t sz, struct op *t)
size_t n;
buf = alloc(sz + 16, ATEMP);
snptreef(buf, sz + 16, "%T", t);
snptreef(buf, sz + 16, Tf_T, t);
cp = buf;
vist_loop:
if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
@ -1107,7 +1105,7 @@ dumptree(struct shf *shf, struct op *t)
goto dumpleftandout;
OPEN(TFUNCT)
shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
t->u.ksh_func ? "true" : "false");
t->u.ksh_func ? Ttrue : Tfalse);
goto dumpleftandout;
OPEN(TTIME)
goto dumpleftandout;
@ -1134,7 +1132,7 @@ dumptree(struct shf *shf, struct op *t)
break;
OPEN(TEOF)
dumpunexpected:
shf_puts("unexpected", shf);
shf_puts(Tunexpected, shf);
break;
OPEN(TELIF)
goto dumpunexpected;

58
var.c
View File

@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.202 2016/05/05 22:56:15 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.207 2016/08/01 21:38:07 tg Exp $");
/*-
* Variables
@ -133,7 +133,7 @@ initvar(void)
struct tbl *tp;
ktinit(APERM, &specials,
/* currently 14 specials: 75% of 32 = 2^5 */
/* currently 15 specials: 75% of 32 = 2^5 */
5);
while (i < V_MAX - 1) {
tp = ktenter(&specials, initvar_names[i],
@ -193,7 +193,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
char *cp;
/* gotcha! */
cp = shf_smprintf("%s%s", str_val(vp), p);
cp = shf_smprintf(Tf_ss, str_val(vp), p);
afree(ap, ATEMP);
n = ap = cp;
goto redo_from_ref;
@ -249,7 +249,7 @@ global(const char *n)
if (ksh_isdigit(c)) {
if (getn(vn, &c)) {
/* main.c:main_init() says 12 */
shf_snprintf(vp->name, 12, "%d", c);
shf_snprintf(vp->name, 12, Tf_d, c);
if (c <= l->argc) {
/* setstr can't fail here */
setstr(vp, l->argv[c],
@ -441,7 +441,7 @@ setstr(struct tbl *vq, const char *s, int error_ok)
error_ok &= ~0x4;
if ((vq->flag & RDONLY) && !no_ro_check) {
warningf(true, "read-only: %s", vq->name);
warningf(true, Tf_ro, vq->name);
if (!error_ok)
errorfxz(2);
return (0);
@ -773,7 +773,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
}
if (*val == '[') {
if (new_refflag != SRF_NOP)
errorf("%s: %s", var,
errorf(Tf_sD_s, var,
"reference variable can't be an array");
len = array_ref_len(val);
if (len == 0)
@ -849,7 +849,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
goto nameref_rhs_checked;
}
nameref_empty:
errorf("%s: %s", var, "empty nameref target");
errorf(Tf_sD_s, var, "empty nameref target");
}
len = (*ccp == '[') ? array_ref_len(ccp) : 0;
if (ccp[len]) {
@ -858,14 +858,14 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
* junk after it" and "invalid array"; in the
* latter case, len is also 0 and points to '['
*/
errorf("%s: %s", qval,
errorf(Tf_sD_s, qval,
"nameref target not a valid parameter name");
}
nameref_rhs_checked:
/* prevent nameref loops */
while (qval) {
if (!strcmp(qval, tvar))
errorf("%s: %s", qval,
errorf(Tf_sD_s, qval,
"expression recurses on parameter");
varsearch(e->loc, &vp, qval, hash(qval));
qval = NULL;
@ -875,9 +875,9 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
}
/* prevent typeset from creating a local PATH/ENV/SHELL */
if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 ||
strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
errorf("%s: %s", tvar, "restricted");
if (Flag(FRESTRICTED) && (strcmp(tvar, TPATH) == 0 ||
strcmp(tvar, "ENV") == 0 || strcmp(tvar, TSHELL) == 0))
errorf(Tf_sD_s, tvar, "restricted");
innermost_refflag = new_refflag;
vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) :
@ -914,7 +914,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
if ((vpbase->flag & RDONLY) &&
(val || clr || (set & ~EXPORT)))
/* XXX check calls - is error here ok by POSIX? */
errorfx(2, "read-only: %s", tvar);
errorfx(2, Tf_ro, tvar);
afree(tvar, ATEMP);
/* most calls are with set/clr == 0 */
@ -987,7 +987,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
char *tval;
if (vappend) {
tval = shf_smprintf("%s%s", str_val(vp), val);
tval = shf_smprintf(Tf_ss, str_val(vp), val);
val = tval;
} else
tval = NULL;
@ -1205,6 +1205,10 @@ unspecial(const char *name)
static time_t seconds; /* time SECONDS last set */
static mksh_uari_t user_lineno; /* what user set $LINENO to */
/* minimum values from the OS we consider sane, lowered for R53 */
#define MIN_COLS 4
#define MIN_LINS 2
static void
getspec(struct tbl *vp)
{
@ -1305,6 +1309,11 @@ setspec(struct tbl *vp)
/* clear tracked aliases */
flushcom(true);
return;
#ifndef MKSH_NO_CMDLINE_EDITING
case V_TERM:
x_initterm(str_val(vp));
return;
#endif
case V_TMPDIR:
afree(tmpdir, APERM);
tmpdir = NULL;
@ -1342,7 +1351,7 @@ setspec(struct tbl *vp)
if (getint(vp, &num, false) == -1) {
s = str_val(vp);
if (st != V_RANDOM)
errorf("%s: %s: %s", vp->name, "bad number", s);
errorf(Tf_sD_sD_s, vp->name, "bad number", s);
num.u = hash(s);
}
vp->flag |= SPECIAL;
@ -1421,6 +1430,11 @@ unsetspec(struct tbl *vp)
/* clear tracked aliases */
flushcom(true);
break;
#ifndef MKSH_NO_CMDLINE_EDITING
case V_TERM:
x_initterm(null);
return;
#endif
case V_TMPDIR:
/* should not become unspecial */
if (tmpdir) {
@ -1546,7 +1560,7 @@ set_array(const char *var, bool reset, const char **vals)
/* Note: AT&T ksh allows set -A but not set +A of a read-only var */
if ((vp->flag&RDONLY))
errorfx(2, "read-only: %s", ccp);
errorfx(2, Tf_ro, ccp);
/* This code is quite non-optimal */
if (reset) {
/* trash existing values and attributes */
@ -1744,3 +1758,15 @@ rndpush(const void *s)
BAFHUpdateOctet_reg(h, 0);
qh_state = h;
}
/* record last glob match */
void
record_match(const char *istr)
{
struct tbl *vp;
vp = local("KSH_MATCH", false);
unset(vp, 1);
vp->flag = DEFINED | RDONLY;
setstr(vp, istr, 0x4);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2009, 2011, 2012
* Copyright (c) 2009, 2011, 2012, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -19,7 +19,7 @@
*/
#if defined(VARSPEC_DEFNS)
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.7 2015/12/12 21:08:44 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.9 2016/07/25 21:02:13 tg Exp $");
#define FN(name) /* nothing */
#elif defined(VARSPEC_ENUMS)
#define FN(name) V_##name,
@ -53,6 +53,9 @@ FN(OPTIND)
FN(PATH)
FN(RANDOM)
FN(SECONDS)
#ifndef MKSH_NO_CMDLINE_EDITING
FN(TERM)
#endif
FN(TMOUT)
FN(TMPDIR)