Merge tag 'mksh-R53' into HEAD
Conflicts: exec.c
This commit is contained in:
commit
d4be6d4358
38
Build.sh
38
Build.sh
@ -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
107
check.t
@ -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:
|
||||
¬Ã¼A€Ã¼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
|
||||
|
11
dot.mkshrc
11
dot.mkshrc
@ -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
474
edit.c
@ -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 */
|
||||
|
@ -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
123
eval.c
@ -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
177
exec.c
@ -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
149
expr.c
@ -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
123
exprtok.h
Normal 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
258
funcs.c
@ -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)) {
|
||||
|
73
histrap.c
73
histrap.c
@ -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 doesn’t 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
80
jobs.c
@ -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
36
lex.c
@ -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
7
lksh.1
@ -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
81
main.c
@ -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
65
misc.c
@ -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
214
mksh.1
@ -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
441
sh.h
@ -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
32
shf.c
@ -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
33
syn.c
@ -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
42
tree.c
@ -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
58
var.c
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user