From 2182ecfa08cf1da7f0c4b55fd23935c792d7d74c Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 8 Feb 2021 17:16:43 +0000 Subject: [PATCH] Fix compile/regress fails on compiling without SHOPT_* options Many compile-time options were broken so that they could not be turned off without causing compile errors and/or regression test failures. This commit now allows the following to be disabled: SHOPT_2DMATCH # two dimensional ${.sh.match} for ${var//pat/str} SHOPT_BGX # one SIGCHLD trap per completed job SHOPT_BRACEPAT # C-shell {...,...} expansions (, required) SHOPT_ESH # emacs/gmacs edit mode SHOPT_HISTEXPAND # csh-style history file expansions SHOPT_MULTIBYTE # multibyte character handling SHOPT_NAMESPACE # allow namespaces SHOPT_STATS # add .sh.stats variable SHOPT_VSH # vi edit mode The following still break ksh when disabled: SHOPT_FIXEDARRAY # fixed dimension indexed array SHOPT_RAWONLY # make viraw the only vi mode SHOPT_TYPEDEF # enable typeset type definitions Compiling without SHOPT_RAWONLY just gives four regression test failures in pty.sh, but turning off SHOPT_FIXEDARRAY and SHOPT_TYPEDEF causes compilation to fail. I've managed to tweak the code to make it compile without those two options, but then dozens of regression test failures occur, often in things nothing directly to do with those options. It looks like the separation between the code for these options and the rest was never properly maintained. Making it possible to disable SHOPT_FIXEDARRAY and SHOPT_TYPEDEF may involve major refactoring and testing and may not be worth it. This commit has far too many tweaks to list. Notables fixes are: src/cmd/ksh93/data/builtins.c, src/cmd/ksh93/data/options.c: - Do not compile in the shell options and documentation for disabled features (braceexpand, emacs/gmacs, vi/viraw), so the shell is not left with no-op options and inaccurate self-doc. src/cmd/ksh93/data/lexstates.c: - Comment the state tables to associte them with their IDs. - In the ST_MACRO table (sh_lexstate9[]), do not make the S_BRACE state for position 123 (ASCII for '{') conditional upon SHOPT_BRACEPAT (brace expansion), otherwise disabling this causes glob patterns of the form {3}(x) (matching 3 x'es) to stop working as well -- and that is ksh globbing, not brace expansion. src/cmd/ksh93/edit/edit.c: ed_read(): - Fixed a bug: SIGWINCH was not handled by the gmacs edit mode. src/cmd/ksh93/sh/name.c: nv_putval(): - The -L/-R left/right adjustment options to typeset do not count zero-width characters. This is the behaviour with SHOPT_MULTIBYTE enabled, regardless of locale. Of course, what a zero-width character is depends on the locale, but control characters are always considered zero-width. So, to avoid a regression, add some fallback code for non-SHOPT_MULTIBYTE builds that skips ASCII control characters (as per iscntrl(3)) so they are still considered to have zero width. src/cmd/ksh93/tests/shtests: - Export the SHOPT_* macros from SHOPT.sh to the tests as environment variables, so the tests can check for them and decide whether or how to run tests based on the compile-time options that the tested binary was presumably compiled with. - Do not run the C.UTF-8 tests if SHOPT_MULTIBYTE is not enabled. src/cmd/ksh93/tests/*.sh: - Add a bunch of checks for SHOPT_* env vars. Since most should have a value 0 (off) or 1 (on), the form ((SHOPT_FOO)) is a convenient way to use them as arithmetic booleans. .github/workflows/ci.yml: - Make GitHub do more testing: run two locale tests (Dutch and Japanese UTF-8 locales), then disable all the SHOPTs that we can currently disable, recompile ksh, and run the tests again. --- .github/workflows/ci.yml | 7 +++ src/cmd/ksh93/RELEASE | 4 +- src/cmd/ksh93/bltins/print.c | 2 +- src/cmd/ksh93/bltins/typeset.c | 2 +- src/cmd/ksh93/data/builtins.c | 10 +++- src/cmd/ksh93/data/lexstates.c | 20 ++++++-- src/cmd/ksh93/data/options.c | 8 +++ src/cmd/ksh93/data/variables.c | 4 +- src/cmd/ksh93/edit/completion.c | 12 +++++ src/cmd/ksh93/edit/edit.c | 66 ++++++++++++++++++------ src/cmd/ksh93/edit/emacs.c | 4 ++ src/cmd/ksh93/edit/vi.c | 5 +- src/cmd/ksh93/include/defs.h | 4 +- src/cmd/ksh93/include/edit.h | 16 +++--- src/cmd/ksh93/include/jobs.h | 4 +- src/cmd/ksh93/include/lexstates.h | 1 + src/cmd/ksh93/include/national.h | 2 + src/cmd/ksh93/include/shell.h | 4 ++ src/cmd/ksh93/include/variables.h | 2 +- src/cmd/ksh93/sh/args.c | 42 ++++++++++------ src/cmd/ksh93/sh/expand.c | 4 -- src/cmd/ksh93/sh/fault.c | 16 ++++-- src/cmd/ksh93/sh/init.c | 37 +++++++++++--- src/cmd/ksh93/sh/jobs.c | 24 ++++----- src/cmd/ksh93/sh/lex.c | 4 ++ src/cmd/ksh93/sh/macro.c | 12 ++++- src/cmd/ksh93/sh/name.c | 21 +++++++- src/cmd/ksh93/sh/nvtree.c | 2 + src/cmd/ksh93/sh/xec.c | 24 +++++++-- src/cmd/ksh93/tests/basic.sh | 2 +- src/cmd/ksh93/tests/glob.sh | 3 +- src/cmd/ksh93/tests/io.sh | 7 +-- src/cmd/ksh93/tests/locale.sh | 22 +++++++- src/cmd/ksh93/tests/math.sh | 27 ++++++++-- src/cmd/ksh93/tests/namespace.sh | 5 ++ src/cmd/ksh93/tests/options.sh | 20 +++++--- src/cmd/ksh93/tests/pty.sh | 84 ++++++++++++++----------------- src/cmd/ksh93/tests/shtests | 20 ++++++-- src/cmd/ksh93/tests/substring.sh | 11 +++- src/cmd/ksh93/tests/variables.sh | 6 ++- 40 files changed, 413 insertions(+), 157 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8da245115..97f68f3e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,4 +16,11 @@ jobs: run: | export TZ=UTC ulimit -n 1024 + script -q -e -c "bin/shtests" && + LANG=nl_NL.UTF-8 script -q -e -c "bin/shtests --locale --nocompile" && + LANG=ja_JP.UTF-8 script -q -e -c "bin/shtests --locale --nocompile" && + sed --regexp-extended --in-place=.orig \ + '/^SHOPT (2DMATCH|AUDIT|BGX|BRACEPAT|DYNAMIC|EDPREDICT|ESH|HISTEXPAND|MULTIBYTE|NAMESPACE|OPTIMIZE|SUID_EXEC|STATS|VSH)=/ s/=1/=0/' \ + src/cmd/ksh93/SHOPT.sh && + bin/package make && script -q -e -c "bin/shtests" diff --git a/src/cmd/ksh93/RELEASE b/src/cmd/ksh93/RELEASE index 8b06db054..2faf28a49 100644 --- a/src/cmd/ksh93/RELEASE +++ b/src/cmd/ksh93/RELEASE @@ -616,10 +616,10 @@ 10-09-29 A bug in which loading a function from FPATH could leave a file descriptor open has been fixed. 10-09-28 +A new compile option SHOPT_FIXEDARRAY has been added and is being - evaluation. It allows fixed sized indexed arrays be to defined + evaluated. It allows fixed sized indexed arrays be to defined using "typeset array[dim1][dim2]...[dimn]". Fixed sized arrays are used the same way indexed arrays are. Currently, only fixed - arrays of fixed objects (float, int, and justifies objects) are + arrays of fixed objects (float, int, and justified objects) are supported. 10-09-22 A bug which could cause an exception when a function with static variables was redefined has been fixed. diff --git a/src/cmd/ksh93/bltins/print.c b/src/cmd/ksh93/bltins/print.c index 443e6c83a..981ab642d 100644 --- a/src/cmd/ksh93/bltins/print.c +++ b/src/cmd/ksh93/bltins/print.c @@ -649,7 +649,7 @@ static int varname(const char *str, int n) } for(;n > 0; n-=len) { -#ifdef SHOPT_MULTIBYTE +#if SHOPT_MULTIBYTE len = mbsize(str); c = mbchar(str); #else diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c index fdc685f57..79f271bdf 100644 --- a/src/cmd/ksh93/bltins/typeset.c +++ b/src/cmd/ksh93/bltins/typeset.c @@ -346,7 +346,7 @@ int b_typeset(int argc,register char *argv[],Shbltin_t *context) case 'r': flag |= NV_RDONLY; break; -#ifdef SHOPT_TYPEDEF +#if SHOPT_TYPEDEF case 'S': sflag=1; break; diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index 676c1286b..193633342 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -207,13 +207,19 @@ const char sh_set[] = "The value of \aoption\a must be one of the following:]{" "[+allexport?Equivalent to \b-a\b.]" "[+bgnice?Runs background jobs at lower priorities.]" +#if SHOPT_BRACEPAT "[+braceexpand?Equivalent to \b-B\b.] " +#endif +#if SHOPT_ESH "[+emacs?Enables/disables \bemacs\b editing mode.]" +#endif "[+errexit?Equivalent to \b-e\b.]" "[+globstar?Equivalent to \b-G\b.]" +#if SHOPT_ESH "[+gmacs?Enables/disables \bgmacs\b editing mode. \bgmacs\b " "editing mode is the same as \bemacs\b editing mode " "except for the handling of \b^T\b.]" +#endif #if SHOPT_HISTEXPAND "[+histexpand?Equivalent to \b-H\b.]" #endif @@ -245,9 +251,11 @@ const char sh_set[] = "as if \b-x\b were enabled but not executed.]" "[+trackall?Equivalent to \b-h\b.]" "[+verbose?Equivalent to \b-v\b.]" +#if SHOPT_VSH "[+vi?Enables/disables \bvi\b editing mode.]" "[+viraw?Does not use canonical input mode when using \bvi\b " "edit mode.]" +#endif "[+xtrace?Equivalent to \b-x\b.]" "}" "[p?Privileged mode. Disabling \b-p\b sets the effective user id to the " @@ -1831,7 +1839,7 @@ const char sh_opttypeset[] = "notation. \an\a specifies the number of significant figures when the " "value is expanded.]" -#ifdef SHOPT_TYPEDEF +#if SHOPT_TYPEDEF "[h]:[string?Used within a type definition to provide a help string " "for variable \aname\a. Otherwise, it is ignored.]" "[S?Used with a type definition to indicate that the variable is shared by " diff --git a/src/cmd/ksh93/data/lexstates.c b/src/cmd/ksh93/data/lexstates.c index 4f257a38c..7fa143758 100644 --- a/src/cmd/ksh93/data/lexstates.c +++ b/src/cmd/ksh93/data/lexstates.c @@ -24,8 +24,10 @@ #include "FEATURE/options" #include "lexstates.h" +/* The ST_* state table names are defined in include/lexstates.h */ /* + * ST_BEGIN (0) * This is the initial state for tokens */ static const char sh_lexstate0[256] = @@ -77,6 +79,7 @@ static const char sh_lexstate0[256] = }; /* + * ST_NAME * This state is for identifiers */ static const char sh_lexstate1[256] = @@ -123,6 +126,9 @@ static const char sh_lexstate1[256] = S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, S_REG, }; +/* + * ST_NORM + */ static const char sh_lexstate2[256] = { S_EOF, 0, 0, 0, 0, 0, 0, 0, @@ -151,6 +157,7 @@ static const char sh_lexstate2[256] = }; /* + * ST_LIT * for skipping over '...' */ static const char sh_lexstate3[256] = @@ -172,6 +179,7 @@ static const char sh_lexstate3[256] = }; /* + * ST_QUOTE * for skipping over "..." and `...` */ static const char sh_lexstate4[256] = @@ -195,6 +203,7 @@ static const char sh_lexstate4[256] = }; /* + * ST_NESTED, ST_QNEST * for skipping over ?(...), [...] */ static const char sh_lexstate5[256] = @@ -218,6 +227,7 @@ static const char sh_lexstate5[256] = }; /* + * ST_DOL * Defines valid expansion characters */ static const char sh_lexstate6[256] = @@ -265,6 +275,7 @@ static const char sh_lexstate6[256] = }; /* + * ST_BRACE * for skipping over ${...} until modifier */ static const char sh_lexstate7[256] = @@ -308,6 +319,7 @@ static const char sh_lexstate7[256] = }; /* + * ST_DOLNAME * This state is for $name */ static const char sh_lexstate8[256] = @@ -351,6 +363,7 @@ static const char sh_lexstate8[256] = }; /* + * ST_MACRO * This is used for macro expansion */ static const char sh_lexstate9[256] = @@ -370,13 +383,12 @@ static const char sh_lexstate9[256] = S_GRAVE,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -#if SHOPT_BRACEPAT 0, 0, 0, S_BRACE,S_PAT, S_ENDCH,0, 0 -#else - 0, 0, 0, 0, S_PAT, S_ENDCH,0, 0 -#endif /* SHOPT_BRACEPAT */ }; +/* + * This must be kept synchronous with all the above and the ST_* definitions in lexstates.h + */ const char *sh_lexrstates[ST_NONE] = { sh_lexstate0, sh_lexstate1, sh_lexstate2, sh_lexstate3, diff --git a/src/cmd/ksh93/data/options.c b/src/cmd/ksh93/data/options.c index 785a8e81f..c4e35aa32 100644 --- a/src/cmd/ksh93/data/options.c +++ b/src/cmd/ksh93/data/options.c @@ -32,14 +32,20 @@ const Shtable_t shtab_options[] = { "allexport", SH_ALLEXPORT, "bgnice", SH_BGNICE, +#if SHOPT_BRACEPAT "braceexpand", SH_BRACEEXPAND, +#endif "noclobber", SH_NOCLOBBER, +#if SHOPT_ESH "emacs", SH_EMACS, +#endif "errexit", SH_ERREXIT, "noexec", SH_NOEXEC, "noglob", SH_NOGLOB, "globstar", SH_GLOBSTARS, +#if SHOPT_ESH "gmacs", SH_GMACS, +#endif #if SHOPT_HISTEXPAND "histexpand", SH_HISTEXPAND, #endif @@ -65,8 +71,10 @@ const Shtable_t shtab_options[] = "trackall", SH_TRACKALL, "nounset", SH_NOUNSET, "verbose", SH_VERBOSE, +#if SHOPT_VSH "vi", SH_VI, "viraw", SH_VIRAW, +#endif "xtrace", SH_XTRACE, "", 0 }; diff --git a/src/cmd/ksh93/data/variables.c b/src/cmd/ksh93/data/variables.c index cadada6fd..76999d0a1 100644 --- a/src/cmd/ksh93/data/variables.c +++ b/src/cmd/ksh93/data/variables.c @@ -32,6 +32,8 @@ /* * This is the list of built-in shell variables and default values * and default attributes. + * + * The order must be kept synchronous with the defines in include/variables.h. */ const struct shtable2 shtab_variables[] = @@ -109,7 +111,7 @@ const struct shtable2 shtab_variables[] = const char *nv_discnames[] = { "get", "set", "append", "unset", "getn", 0 }; -#ifdef SHOPT_STATS +#if SHOPT_STATS const Shtable_t shtab_stats[] = { "arg_cachehits", STAT_ARGHITS, diff --git a/src/cmd/ksh93/edit/completion.c b/src/cmd/ksh93/edit/completion.c index dd9dd3980..1efc09b69 100644 --- a/src/cmd/ksh93/edit/completion.c +++ b/src/cmd/ksh93/edit/completion.c @@ -240,10 +240,18 @@ int ed_expand(Edit_t *ep, char outbuff[],int *cur,int *eol,int mode, int count) *eol = ed_external((genchar*)outbuff,outbuff); } #endif /* SHOPT_MULTIBYTE */ +#if SHOPT_VSH out = outbuff + *cur + (sh_isoption(SH_VI)!=0); +#else + out = outbuff + *cur; +#endif if(out[-1]=='"' || out[-1]=='\'') { +#if SHOPT_VSH rval = -(sh_isoption(SH_VI)!=0); +#else + rval = 0; +#endif goto done; } comptr->comtyp = COMSCAN; @@ -565,6 +573,10 @@ int ed_fulledit(Edit_t *ep) } cp = strcopy((char*)ep->e_inbuf,e_runvi); cp = strcopy(cp, fmtbase((long)ep->e_hline,10,0)); +#if SHOPT_VSH ep->e_eol = ((unsigned char*)cp - (unsigned char*)ep->e_inbuf)-(sh_isoption(SH_VI)!=0); +#else + ep->e_eol = ((unsigned char*)cp - (unsigned char*)ep->e_inbuf); +#endif return(0); } diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index f198e8955..35d0f182d 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -59,9 +59,11 @@ static char KILL_LINE[20] = { ESC, '[', 'J', 0 }; #if SHOPT_MULTIBYTE # define is_cntrl(c) ((c<=STRIP) && iscntrl(c)) # define is_print(c) ((c&~STRIP) || isprint(c)) +# define genlen(str) ed_genlen(str) #else # define is_cntrl(c) iscntrl(c) # define is_print(c) isprint(c) +# define genlen(str) strlen(str) #endif #if (CC_NATIVE == CC_ASCII) @@ -147,11 +149,9 @@ static char KILL_LINE[20] = { ESC, '[', 'J', 0 }; #ifdef future static int compare(const char*, const char*, int); #endif /* future */ -#if SHOPT_VSH || SHOPT_ESH -# define ttyparm (ep->e_ttyparm) -# define nttyparm (ep->e_nttyparm) - static const char bellchr[] = "\a"; /* bell char */ -#endif /* SHOPT_VSH || SHOPT_ESH */ +#define ttyparm (ep->e_ttyparm) +#define nttyparm (ep->e_nttyparm) +static const char bellchr[] = "\a"; /* bell char */ /* @@ -227,7 +227,6 @@ int tty_set(int fd, int action, struct termios *tty) return(0); } -#if SHOPT_ESH || SHOPT_VSH /*{ TTY_COOKED( fd ) * * This routine will set the tty in cooked mode. @@ -561,6 +560,7 @@ void ed_ringbell(void) write(ERRIO,bellchr,1); } +#if SHOPT_ESH || SHOPT_VSH /* * send a carriage return line feed to the terminal */ @@ -579,7 +579,9 @@ void ed_crlf(register Edit_t *ep) ed_putchar(ep,'\n'); ed_flush(ep); } - +#endif /* SHOPT_ESH || SHOPT_VSH */ + +#if SHOPT_ESH || SHOPT_VSH /* ED_SETUP( max_prompt_size ) * * This routine sets up the prompt string @@ -640,7 +642,15 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) ep->e_hismax = ep->e_hismin = ep->e_hloff = 0; } ep->e_hline = ep->e_hismax; +#if SHOPT_ESH && SHOPT_VSH if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) +#elif SHOPT_ESH + if(!sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) +#elif SHOPT_VSH + if(!sh_isoption(SH_VI)) +#else + if(1) +#endif /* SHOPT_ESH && SHOPT_VSH */ ep->e_wsize = MAXLINE; else ep->e_wsize = ed_window()-2; @@ -795,6 +805,7 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) ep->e_default = 0; } } +#endif /* SHOPT_ESH || SHOPT_VSH */ static void ed_putstring(register Edit_t *ep, const char *str) { @@ -840,7 +851,15 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) { if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP)) goto done; - if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS))) +#if SHOPT_ESH && SHOPT_VSH + if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))) +#elif SHOPT_ESH + if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))) +#elif SHOPT_VSH + if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && sh_isoption(SH_VI)) +#else + if(0) +#endif { Edpos_t lastpos; int n, rows, newsize; @@ -881,8 +900,7 @@ int ed_read(void *context, int fd, char *buff, int size, int reedit) buff[2] = 'a'; return(3); } - if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI)) - buff[0] = cntl('L'); + buff[0] = cntl('L'); return(1); } else @@ -1115,13 +1133,16 @@ int ed_getchar(register Edit_t *ep,int mode) return(c); } +#if SHOPT_ESH || SHOPT_VSH void ed_ungetchar(Edit_t *ep,register int c) { if (ep->e_lookahead < LOOKAHEAD) ep->e_lbuf[ep->e_lookahead++] = c; return; } +#endif /* SHOPT_ESH || SHOPT_VSH */ +#if SHOPT_ESH || SHOPT_VSH /* * put a character into the output buffer */ @@ -1162,7 +1183,9 @@ void ed_putchar(register Edit_t *ep,register int c) else ep->e_outptr = dp; } +#endif /* SHOPT_ESH || SHOPT_VSH */ +#if SHOPT_ESH || SHOPT_VSH /* * returns the line and column corresponding to offset in the physical buffer * if is non-zero and <= , then correspodning will start the search @@ -1211,7 +1234,9 @@ Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos) pos.col = col; return(pos); } +#endif /* SHOPT_ESH || SHOPT_VSH */ +#if SHOPT_ESH || SHOPT_VSH int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first) { static int oldline; @@ -1261,7 +1286,7 @@ int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int m = ep->e_winsz+1-plen; ed_putchar(ep,'\n'); n = plen; - if(m < ed_genlen(physical)) + if(m < genlen(physical)) { while(physical[m] && n-->0) ed_putchar(ep,physical[m++]); @@ -1311,7 +1336,9 @@ int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register ed_putchar(ep,physical[old++]); return(new); } +#endif /* SHOPT_ESH || SHOPT_VSH */ +#if SHOPT_ESH || SHOPT_VSH /* * copy virtual to physical and return the index for cursor in physical buffer */ @@ -1375,8 +1402,9 @@ int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int ep->e_peol = dp-phys; return(r); } +#endif /* SHOPT_ESH || SHOPT_VSH */ -#if SHOPT_MULTIBYTE +#if (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE /* * convert external representation to an array of genchars * and can be the same @@ -1400,7 +1428,9 @@ int ed_internal(const char *src, genchar *dest) *dp = 0; return(dp-(wchar_t*)dest); } +#endif /* (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE */ +#if SHOPT_MULTIBYTE /* * convert internal representation into character array . * The and may be the same. @@ -1439,7 +1469,9 @@ int ed_external(const genchar *src, char *dest) *dp = 0; return(dp-dest); } +#endif /* SHOPT_MULTIBYTE */ +#if (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE /* * copy to */ @@ -1450,7 +1482,9 @@ void ed_gencpy(genchar *dp,const genchar *sp) sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); while(*dp++ = *sp++); } +#endif /* (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE */ +#if (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE /* * copy at most items from to */ @@ -1461,8 +1495,9 @@ void ed_genncpy(register genchar *dp,register const genchar *sp, int n) sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar)); while(n-->0 && (*dp++ = *sp++)); } +#endif /* (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE */ -#endif /* SHOPT_MULTIBYTE */ +#if (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE /* * find the string length of */ @@ -1474,7 +1509,7 @@ int ed_genlen(register const genchar *str) while(*sp++); return(sp-str-1); } -#endif /* SHOPT_ESH || SHOPT_VSH */ +#endif /* (SHOPT_ESH || SHOPT_VSH) && SHOPT_MULTIBYTE */ #ifdef future /* @@ -1776,6 +1811,7 @@ int ed_histgen(Edit_t *ep,const char *pattern) return(ep->hmax=ac); } +#if SHOPT_ESH || SHOPT_VSH void ed_histlist(Edit_t *ep,int n) { Histmatch_t *mp,**mpp = ep->hlist+ep->hoff; @@ -1828,6 +1864,8 @@ void ed_histlist(Edit_t *ep,int n) } ed_flush(ep); } +#endif /* SHOPT_ESH || SHOPT_VSH */ + #endif /* SHOPT_EDPREDICT */ void *ed_open(Shell_t *shp) diff --git a/src/cmd/ksh93/edit/emacs.c b/src/cmd/ksh93/edit/emacs.c index 46c753264..007f7fec1 100644 --- a/src/cmd/ksh93/edit/emacs.c +++ b/src/cmd/ksh93/edit/emacs.c @@ -61,6 +61,8 @@ One line screen editor for any program * but you can use them to separate features. */ +#if SHOPT_ESH + #include #include "FEATURE/cmds" #if KSHELL @@ -1600,3 +1602,5 @@ static int _isword(register int c) return((c&~STRIP) || isalnum(c) || c=='_'); } #endif /* SHOPT_MULTIBYTE */ + +#endif /* SHOPT_ESH */ diff --git a/src/cmd/ksh93/edit/vi.c b/src/cmd/ksh93/edit/vi.c index 8ab7583e3..0f31b57a6 100644 --- a/src/cmd/ksh93/edit/vi.c +++ b/src/cmd/ksh93/edit/vi.c @@ -28,6 +28,7 @@ * cbosgd!pds -*/ +#if SHOPT_VSH #if KSHELL # include "defs.h" @@ -252,7 +253,7 @@ int ed_viread(void *context, int fd, register char *shbuf, int nchar, int reedit /*** Change the eol characters to '\r' and eof ***/ /* in addition to '\n' and make eof an ESC */ if(tty_alt(ERRIO) < 0) - return(reexit?reedit:ed_read(context, fd, shbuf, nchar,0)); + return(reedit?reedit:ed_read(context, fd, shbuf, nchar,0)); #ifdef FIORDCHK ioctl(fd,FIORDCHK,&vp->typeahead); @@ -2783,3 +2784,5 @@ static int getrchar(register Vi_t *vp) c = ed_getchar(vp->ed,2); return(c); } + +#endif /* SHOPT_VSH */ diff --git a/src/cmd/ksh93/include/defs.h b/src/cmd/ksh93/include/defs.h index b3f854986..c94160de0 100644 --- a/src/cmd/ksh93/include/defs.h +++ b/src/cmd/ksh93/include/defs.h @@ -316,7 +316,9 @@ struct shared #define SH_INTESTCMD 20 /* set while test/[ command is being run */ #define SH_XARG 21 /* set while in xarg (command -x) mode */ +#if SHOPT_BRACEPAT #define SH_BRACEEXPAND 42 +#endif #define SH_POSIX 46 #define SH_MULTILINE 47 @@ -451,7 +453,7 @@ extern const char e_dict[]; #define PRINT_NO_HEADER 0x04 /* omit listing header */ #define PRINT_TABLE 0x10 /* table of all options */ -#ifdef SHOPT_STATS +#if SHOPT_STATS /* performance statistics */ # define STAT_ARGHITS 0 # define STAT_ARGEXPAND 1 diff --git a/src/cmd/ksh93/include/edit.h b/src/cmd/ksh93/include/edit.h index b167e3aaf..4fbb194b5 100644 --- a/src/cmd/ksh93/include/edit.h +++ b/src/cmd/ksh93/include/edit.h @@ -31,9 +31,6 @@ #include "FEATURE/options" #include "FEATURE/locale" -#if !SHOPT_VSH && !SHOPT_ESH -# define ed_winsize() (SEARCHSIZE) -#else #if !KSHELL # include @@ -231,11 +228,12 @@ extern int ed_setcursor(Edit_t*, genchar*, int, int, int); extern void ed_gencpy(genchar*,const genchar*); extern void ed_genncpy(genchar*,const genchar*,int); extern int ed_genlen(const genchar*); - extern int ed_setwidth(const char*); # endif /* SHOPT_MULTIBYTE */ #if SHOPT_EDPREDICT - extern int ed_histgen(Edit_t*, const char*); - extern void ed_histlist(Edit_t*, int); + extern int ed_histgen(Edit_t*, const char*); +# if SHOPT_ESH || SHOPT_VSH + extern void ed_histlist(Edit_t*, int); +# endif /* SHOPT_ESH || SHOPT_VSH */ #endif /* SHOPT_EDPREDICT */ extern const char e_runvi[]; @@ -269,7 +267,7 @@ extern const char e_runvi[]; #define HIST_FLAG_RETURN_MASK (HIST_EVENT|HIST_PRINT|HIST_ERROR) extern int hist_expand(const char *, char **); -#endif -#endif -#endif +#endif /* SHOPT_HISTEXPAND */ + +#endif /* !SEARCHSIZE */ diff --git a/src/cmd/ksh93/include/jobs.h b/src/cmd/ksh93/include/jobs.h index ddd169b63..7dd01085c 100644 --- a/src/cmd/ksh93/include/jobs.h +++ b/src/cmd/ksh93/include/jobs.h @@ -89,7 +89,7 @@ struct jobs unsigned int in_critical; /* >0 => in critical region */ int savesig; /* active signal */ int numpost; /* number of posted jobs */ -#ifdef SHOPT_BGX +#if SHOPT_BGX int numbjob; /* number of background jobs */ #endif /* SHOPT_BGX */ short fd; /* tty descriptor number */ @@ -169,7 +169,7 @@ extern int job_wait(pid_t); extern int job_post(Shell_t*,pid_t,pid_t); extern void *job_subsave(void); extern void job_subrestore(void*); -#ifdef SHOPT_BGX +#if SHOPT_BGX extern void job_chldtrap(Shell_t*, const char*,int); #endif /* SHOPT_BGX */ #ifdef JOBS diff --git a/src/cmd/ksh93/include/lexstates.h b/src/cmd/ksh93/include/lexstates.h index c83a5e0c2..6370ae79e 100644 --- a/src/cmd/ksh93/include/lexstates.h +++ b/src/cmd/ksh93/include/lexstates.h @@ -66,6 +66,7 @@ #define S_ESC2 41 /* escape character inside '...' */ /* These are the lexical state table names */ +/* See lexstates.c (ST_NONE must be last) */ #define ST_BEGIN 0 #define ST_NAME 1 #define ST_NORM 2 diff --git a/src/cmd/ksh93/include/national.h b/src/cmd/ksh93/include/national.h index 4c1888b7b..d5956c132 100644 --- a/src/cmd/ksh93/include/national.h +++ b/src/cmd/ksh93/include/national.h @@ -34,4 +34,6 @@ extern int sh_strchr(const char*,const char*); +#else +# define sh_strchr(s,c) strchr(s,*(c)) #endif /* SHOPT_MULTIBYTE */ diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h index 15f32059d..becb19330 100644 --- a/src/cmd/ksh93/include/shell.h +++ b/src/cmd/ksh93/include/shell.h @@ -77,14 +77,18 @@ typedef union Shnode_u Shnode_t; #define SH_NOCLOBBER 14 #define SH_MARKDIRS 15 #define SH_BGNICE 16 +#if SHOPT_VSH #define SH_VI 17 #define SH_VIRAW 18 +#endif #define SH_TFLAG 19 #define SH_TRACKALL 20 #define SH_SFLAG 21 #define SH_NOEXEC 22 +#if SHOPT_ESH #define SH_GMACS 24 #define SH_EMACS 25 +#endif #define SH_PRIVILEGED 26 #define SH_NOLOG 28 #define SH_NOTIFY 29 diff --git a/src/cmd/ksh93/include/variables.h b/src/cmd/ksh93/include/variables.h index 6fff7921c..76c409159 100644 --- a/src/cmd/ksh93/include/variables.h +++ b/src/cmd/ksh93/include/variables.h @@ -25,7 +25,7 @@ #include "FEATURE/options" #include "FEATURE/dynamic" -/* The following defines are coordinated with data in data/variables.c */ +/* The following defines must be kept synchronous with shtab_variables[] in data/variables.c */ #define PATHNOD (shgd->bltin_nodes) #define PS1NOD (shgd->bltin_nodes+1) diff --git a/src/cmd/ksh93/sh/args.c b/src/cmd/ksh93/sh/args.c index 527639d4d..fc830ab81 100644 --- a/src/cmd/ksh93/sh/args.c +++ b/src/cmd/ksh93/sh/args.c @@ -40,16 +40,6 @@ #if SHOPT_KIA || SHOPT_DEVFD # include "io.h" #endif -#if SHOPT_PFSH -# define PFSHOPT "P" -#else -# define PFSHOPT -#endif -#if SHOPT_HISTEXPAND -# define HFLAG "H" -#else -# define HFLAG "" -#endif #define SORT 1 #define PRINT 2 @@ -57,7 +47,19 @@ static char *null; /* The following order is determined by sh_optset */ -static const char optksh[] = PFSHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; +static const char optksh[] = +#if SHOPT_PFSH + "P" +#endif + "Dircabefhkmnpstuvx" +#if SHOPT_BRACEPAT + "B" +#endif + "CGEl" +#if SHOPT_HISTEXPAND + "H" +#endif + ; static const int flagval[] = { #if SHOPT_PFSH @@ -66,8 +68,11 @@ static const int flagval[] = SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG, SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL, SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG, - SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER, - SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, + SH_NOUNSET, SH_VERBOSE, SH_XTRACE, +#if SHOPT_BRACEPAT + SH_BRACEEXPAND, +#endif + SH_NOCLOBBER, SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, #if SHOPT_HISTEXPAND SH_HISTEXPAND, #endif @@ -231,12 +236,21 @@ int sh_argopts(int argc,register char *argv[], void *context) } if(f) { +#if SHOPT_ESH && SHOPT_VSH if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) { off_option(&newflags,SH_VI); off_option(&newflags,SH_EMACS); off_option(&newflags,SH_GMACS); } +#elif SHOPT_ESH + if(o==SH_EMACS || o==SH_GMACS) + { + off_option(&newflags,SH_EMACS); + off_option(&newflags,SH_GMACS); + } + +#endif /* SHOPT_ESH && SHOPT_VSH */ on_option(&newflags,o); off_option(&ap->sh->offoptions,o); } @@ -567,7 +581,7 @@ void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask) sfputc(sfstdout,'\n'); return; } -#if SHOPT_RAWONLY +#if SHOPT_VSH && SHOPT_RAWONLY on_option(&oflags,SH_VIRAW); #endif if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */ diff --git a/src/cmd/ksh93/sh/expand.c b/src/cmd/ksh93/sh/expand.c index a9726101c..145306b29 100644 --- a/src/cmd/ksh93/sh/expand.c +++ b/src/cmd/ksh93/sh/expand.c @@ -42,10 +42,6 @@ #include "io.h" #include "path.h" -#if !SHOPT_BRACEPAT -# define SHOPT_BRACEPAT 0 -#endif - #if KSHELL # define argbegin argnxt.cp static const char *sufstr; diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 91378ed7e..e50758c44 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -413,7 +413,7 @@ void sh_chktrap(Shell_t* shp) } if(shp->sigflag[SIGALRM]&SH_SIGALRM) sh_timetraps(shp); -#ifdef SHOPT_BGX +#if SHOPT_BGX if((shp->sigflag[SIGCHLD]&SH_SIGTRAP) && shp->st.trapcom[SIGCHLD]) job_chldtrap(shp,shp->st.trapcom[SIGCHLD],1); #endif /* SHOPT_BGX */ @@ -421,7 +421,7 @@ void sh_chktrap(Shell_t* shp) { if(sig==cursig) continue; -#ifdef SHOPT_BGX +#if SHOPT_BGX if(sig==SIGCHLD) continue; #endif /* SHOPT_BGX */ @@ -626,9 +626,17 @@ void sh_done(void *ptr, register int sig) sh_accend(); #endif /* SHOPT_ACCT */ #if SHOPT_VSH || SHOPT_ESH - if(mbwide()||sh_isoption(SH_EMACS)||sh_isoption(SH_VI)||sh_isoption(SH_GMACS)) - tty_cooked(-1); + if(mbwide() +#if SHOPT_ESH + || sh_isoption(SH_EMACS) + || sh_isoption(SH_GMACS) #endif +#if SHOPT_VSH + || sh_isoption(SH_VI) +#endif + ) + tty_cooked(-1); +#endif /* SHOPT_VSH || SHOPT_ESH */ #ifdef JOBS if((sh_isoption(SH_INTERACTIVE) && shp->login_sh) || (!sh_isoption(SH_INTERACTIVE) && (sig==SIGHUP))) job_walk(sfstderr, job_hup, SIGHUP, NIL(char**)); diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index f7aa10966..c77df551b 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -178,8 +178,10 @@ typedef struct _init_ Namfun_t CDPATH_init; Namfun_t SHELL_init; Namfun_t ENV_init; +#if SHOPT_VSH || SHOPT_ESH Namfun_t VISUAL_init; Namfun_t EDITOR_init; +#endif Namfun_t HISTFILE_init; Namfun_t HISTSIZE_init; Namfun_t OPTINDEX_init; @@ -227,6 +229,7 @@ static char *nospace(int unused) return(NIL(char*)); } +#if SHOPT_VSH || SHOPT_ESH /* Trap for VISUAL and EDITOR variables */ static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) { @@ -239,22 +242,34 @@ static void put_ed(register Namval_t* np,const char *val,int flags,Namfun_t *fp) goto done; /* turn on vi or emacs option if editor name is either*/ cp = path_basename(cp); +#if SHOPT_VSH if(strmatch(cp,"*[Vv][Ii]*")) newopt=SH_VI; - else if(strmatch(cp,"*gmacs*")) +#endif +#if SHOPT_VSH && SHOPT_ESH + else +#endif +#if SHOPT_ESH + if(strmatch(cp,"*gmacs*")) newopt=SH_GMACS; else if(strmatch(cp,"*macs*")) newopt=SH_EMACS; +#endif if(newopt) { +#if SHOPT_VSH sh_offoption(SH_VI); +#endif +#if SHOPT_ESH sh_offoption(SH_EMACS); sh_offoption(SH_GMACS); +#endif sh_onoption(newopt); } done: nv_putv(np, val, flags, fp); } +#endif /* SHOPT_VSH || SHOPT_ESH */ /* Trap for HISTFILE and HISTSIZE variables */ static void put_history(register Namval_t* np,const char *val,int flags,Namfun_t *fp) @@ -727,11 +742,11 @@ void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t mat Namarr_t *ap = nv_arrayptr(SH_MATCHNOD); Namarr_t *ap_save = ap; shp->subshell = 0; -#ifndef SHOPT_2DMATCH +#if !SHOPT_2DMATCH index = 0; #else if(index==0) -#endif /* SHOPT_2DMATCH */ +#endif /* !SHOPT_2DMATCH */ { if(ap->hdr.next != &mp->hdr) { @@ -759,7 +774,7 @@ void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t mat mp->v = v; mp->first = match[0]; } -#ifdef SHOPT_2DMATCH +#if SHOPT_2DMATCH else { if(index==1) @@ -882,7 +897,9 @@ static const Namdisc_t SH_VERSION_disc = { 0, 0, get_version, nget_version }; static const Namdisc_t IFS_disc = { sizeof(struct ifs), put_ifs, get_ifs }; const Namdisc_t RESTRICTED_disc = { sizeof(Namfun_t), put_restricted }; static const Namdisc_t CDPATH_disc = { sizeof(Namfun_t), put_cdpath }; +#if SHOPT_VSH || SHOPT_ESH static const Namdisc_t EDITOR_disc = { sizeof(Namfun_t), put_ed }; +#endif static const Namdisc_t HISTFILE_disc = { sizeof(Namfun_t), put_history }; static const Namdisc_t OPTINDEX_disc = { sizeof(Namfun_t), put_optindex, 0, nget_optindex, 0, 0, clone_optindex }; static const Namdisc_t SECONDS_disc = { sizeof(struct seconds), put_seconds, get_seconds, nget_seconds }; @@ -1416,7 +1433,7 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit) /* set[ug]id scripts require the -p flag */ if(shp->gd->userid!=shp->gd->euserid || shp->gd->groupid!=shp->gd->egroupid) { -#ifdef SHOPT_P_SUID +#if SHOPT_P_SUID /* require sh -p to run setuid and/or setgid */ if(!sh_isoption(SH_PRIVILEGED) && shp->gd->userid >= SHOPT_P_SUID) { @@ -1548,14 +1565,18 @@ int sh_reinit(char *argv[]) #endif /* SHOPT_NAMESPACE */ if(sh_isoption(SH_TRACKALL)) on_option(&opt,SH_TRACKALL); +#if SHOPT_ESH if(sh_isoption(SH_EMACS)) on_option(&opt,SH_EMACS); if(sh_isoption(SH_GMACS)) on_option(&opt,SH_GMACS); +#endif +#if SHOPT_VSH if(sh_isoption(SH_VI)) on_option(&opt,SH_VI); if(sh_isoption(SH_VIRAW)) on_option(&opt,SH_VIRAW); +#endif shp->options = opt; /* set up new args */ if(argv) @@ -1607,7 +1628,7 @@ Namfun_t *nv_cover(register Namval_t *np) static const char *shdiscnames[] = { "tilde", 0}; -#ifdef SHOPT_STATS +#if SHOPT_STATS struct Stats { Namfun_t hdr; @@ -1735,10 +1756,12 @@ static Init_t *nv_init(Shell_t *shp) ip->SHELL_init.nofree = 1; ip->ENV_init.disc = &RESTRICTED_disc; ip->ENV_init.nofree = 1; +#if SHOPT_VSH || SHOPT_ESH ip->VISUAL_init.disc = &EDITOR_disc; ip->VISUAL_init.nofree = 1; ip->EDITOR_init.disc = &EDITOR_disc; ip->EDITOR_init.nofree = 1; +#endif ip->HISTFILE_init.disc = &HISTFILE_disc; ip->HISTFILE_init.nofree = 1; ip->HISTSIZE_init.disc = &HISTFILE_disc; @@ -1781,8 +1804,10 @@ static Init_t *nv_init(Shell_t *shp) nv_stack(CDPNOD, &ip->CDPATH_init); nv_stack(SHELLNOD, &ip->SHELL_init); nv_stack(ENVNOD, &ip->ENV_init); +#if SHOPT_VSH || SHOPT_ESH nv_stack(VISINOD, &ip->VISUAL_init); nv_stack(EDITNOD, &ip->EDITOR_init); +#endif nv_stack(HISTFILE, &ip->HISTFILE_init); nv_stack(HISTSIZE, &ip->HISTSIZE_init); nv_stack(OPTINDNOD, &ip->OPTINDEX_init); diff --git a/src/cmd/ksh93/sh/jobs.c b/src/cmd/ksh93/sh/jobs.c index 6952b9d71..8a4097fca 100644 --- a/src/cmd/ksh93/sh/jobs.c +++ b/src/cmd/ksh93/sh/jobs.c @@ -129,7 +129,7 @@ struct back_save #define P_COREDUMP 0100 #define P_DISOWN 0200 #define P_FG 0400 -#ifdef SHOPT_BGX +#if SHOPT_BGX #define P_BG 01000 #endif /* SHOPT_BGX */ @@ -194,7 +194,7 @@ static struct back_save bck; typedef int (*Waitevent_f)(int,long,int); -#ifdef SHOPT_BGX +#if SHOPT_BGX void job_chldtrap(Shell_t *shp, const char *trap, int unpost) { register struct process *pw,*pwnext; @@ -404,7 +404,7 @@ int job_reap(register int sig) if(WEXITSTATUS(wstat) > pw->p_exitmin) pw->p_exit = WEXITSTATUS(wstat); } -#ifdef SHOPT_BGX +#if SHOPT_BGX if((pw->p_flag&P_DONE) && (pw->p_flag&P_BG)) { job.numbjob--; @@ -443,7 +443,7 @@ int job_reap(register int sig) if(!px && sh_isoption(SH_INTERACTIVE)) tcsetpgrp(JOBTTY,job.mypid); } -#ifndef SHOPT_BGX +#if !SHOPT_BGX if(!shp->intrap && shp->st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid))) { shp->sigflag[SIGCHLD] |= SH_SIGTRAP; @@ -454,7 +454,7 @@ int job_reap(register int sig) if(errno==ECHILD) { errno = oerrno; -#ifdef SHOPT_BGX +#if SHOPT_BGX job.numbjob = 0; #endif /* SHOPT_BGX */ nochild = 1; @@ -1188,7 +1188,7 @@ void job_clear(void) init_savelist(); job.pwlist = NIL(struct process*); job.numpost=0; -#ifdef SHOPT_BGX +#if SHOPT_BGX job.numbjob = 0; #endif /* SHOPT_BGX */ job.waitall = 0; @@ -1210,7 +1210,7 @@ int job_post(Shell_t *shp,pid_t pid, pid_t join) { register struct process *pw; register History_t *hp = shp->gd->hist_ptr; -#ifdef SHOPT_BGX +#if SHOPT_BGX int val,bg=0; #else int val; @@ -1222,7 +1222,7 @@ int job_post(Shell_t *shp,pid_t pid, pid_t join) return(0); } job_lock(); -#ifdef SHOPT_BGX +#if SHOPT_BGX if(join==1) { join = 0; @@ -1314,7 +1314,7 @@ int job_post(Shell_t *shp,pid_t pid, pid_t join) else pw->p_flag |= (P_DONE|P_NOTIFY); } -#ifdef SHOPT_BGX +#if SHOPT_BGX if(bg) { if(pw->p_flag&P_DONE) @@ -1610,7 +1610,7 @@ int job_switch(register struct process *pw,int bgflag) { sfprintf(outfile,"[%d]\t",(int)pw->p_job); sh.bckpid = pw->p_pid; -#ifdef SHOPT_BGX +#if SHOPT_BGX pw->p_flag |= P_BG; #endif msg = "&"; @@ -1634,7 +1634,7 @@ int job_switch(register struct process *pw,int bgflag) } job.waitall = 1; pw->p_flag |= P_FG; -#ifdef SHOPT_BGX +#if SHOPT_BGX pw->p_flag &= ~P_BG; #endif job_wait(pw->p_pid); @@ -1703,7 +1703,7 @@ static struct process *job_unpost(register struct process *pwtop,int notify) pwtop = pw = job_byjid((int)pwtop->p_job); if(!pw) return(0); -#ifdef SHOPT_BGX +#if SHOPT_BGX if(pw->p_flag&P_BG) return(pw); #endif /* SHOPT_BGX */ diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c index 6baa0cc10..31614b42c 100644 --- a/src/cmd/ksh93/sh/lex.c +++ b/src/cmd/ksh93/sh/lex.c @@ -1252,12 +1252,14 @@ int sh_lex(Lex_t* lp) /* check for reserved word { or } */ if(lp->lex.reservok && state[n]==S_BREAK && isfirst) break; +#if SHOPT_BRACEPAT if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK && !lp->lex.incase && !lp->lex.intest && !lp->lex.skipword) { wordflags |= ARG_EXP; } +#endif if(c==RBRACE && n==LPAREN) goto epat; break; @@ -1892,8 +1894,10 @@ static int here_copy(Lex_t *lp,register struct ionod *iop) sfputc(sp,'\\'); } } +#if SHOPT_MULTIBYTE if(LEN < 1) LEN = 1; +#endif bufp = fcseek(-LEN); } else diff --git a/src/cmd/ksh93/sh/macro.c b/src/cmd/ksh93/sh/macro.c index 5a740b4f0..3512acd0a 100644 --- a/src/cmd/ksh93/sh/macro.c +++ b/src/cmd/ksh93/sh/macro.c @@ -508,8 +508,10 @@ static void copyto(register Mac_t *mp,int endch, int newquote) sfputc(stkp,ESCAPE); break; } +#if SHOPT_BRACEPAT else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.')) break; +#endif else if(mp->split && endch && !mp->quote && !mp->lit) { if(c) @@ -763,15 +765,21 @@ static void copyto(register Mac_t *mp,int endch, int newquote) case S_BRACE: if(!(mp->quote || mp->lit)) { +#if SHOPT_BRACEPAT mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND); +#else + mp->patfound = 0; +#endif brace++; } pattern: if(!mp->pattern || !(mp->quote || mp->lit)) { /* mark beginning of {a,b} */ +#if SHOPT_BRACEPAT if(n==S_BRACE && endch==0 && mp->pattern) mp->pattern=4; +#endif if(n==S_SLASH && mp->pattern==2) mp->pattern=3; break; @@ -1102,7 +1110,7 @@ retry1: { if(c=='#') type = M_SIZE; -#ifdef SHOPT_TYPEDEF +#if SHOPT_TYPEDEF else if(c=='@') { type = M_TYPE; @@ -1410,7 +1418,7 @@ retry1: if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF)) addsub = 1; } -#ifdef SHOPT_TYPEDEF +#if SHOPT_TYPEDEF else if(type==M_TYPE) { Namval_t *nq = nv_type(np); diff --git a/src/cmd/ksh93/sh/name.c b/src/cmd/ksh93/sh/name.c index 7e4487a9a..2ea2d009e 100644 --- a/src/cmd/ksh93/sh/name.c +++ b/src/cmd/ksh93/sh/name.c @@ -1053,8 +1053,15 @@ Namval_t *nv_create(const char *name, Dt_t *root, int flags, Namfun_t *dp) } else cp = sp; - if((c = *cp)=='.' || (c=='[' && nv_isarray(np)) || (n&ARRAY_FILL) || ((ap || (flags&NV_ASSIGN)) && (flags&NV_ARRAY))) + if((c = *cp)=='.' + || (c=='[' && nv_isarray(np)) + || (n&ARRAY_FILL) + || (( +#if SHOPT_FIXEDARRAY + ap || +#endif + (flags&NV_ASSIGN)) && (flags&NV_ARRAY))) { int m = cp-sp; sub = m?nv_getsub(np):0; @@ -1839,6 +1846,18 @@ void nv_putval(register Namval_t *np, const char *string, int flags) #if SHOPT_MULTIBYTE if(size) size = ja_size((char*)sp,size,nv_isattr(np,NV_RJUST|NV_ZFILL)); +#else + /* fallback: consider control characters to have zero width */ + if(size) + { + char *c = (char*)sp; + int s = size; + for( ; *c && s; c++) + if(iscntrl(*c)) + size++; + else + s--; + } #endif /* SHOPT_MULTIBYTE */ } if(!up->cp || *up->cp==0) diff --git a/src/cmd/ksh93/sh/nvtree.c b/src/cmd/ksh93/sh/nvtree.c index 4e5c375b6..7b5be9824 100644 --- a/src/cmd/ksh93/sh/nvtree.c +++ b/src/cmd/ksh93/sh/nvtree.c @@ -752,12 +752,14 @@ static void outval(char *name, const char *vname, struct Walk *wp) { Namarr_t *ap; nv_attribute(np,wp->out,"typeset",'='); +#if SHOPT_FIXEDARRAY if((ap=nv_arrayptr(np)) && ap->fixed) { sfprintf(wp->out,"%s",name); nv_arrfixed(np,wp->out,0,(char*)0); sfputc(wp->out,';'); } +#endif } nv_outname(wp->out,name,-1); if((np->nvalue.cp && np->nvalue.cp!=Empty) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE)) || nv_isvtree(np)) diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index a3fba2907..d388069f5 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -1240,7 +1240,12 @@ int sh_exec(register const Shnode_t *t, int flags) int jmpval, save_prompt; int was_nofork = execflg?sh_isstate(SH_NOFORK):0; struct checkpt *buffp = (struct checkpt*)stkalloc(shp->stk,sizeof(struct checkpt)); - volatile unsigned long was_vi=0, was_emacs=0, was_gmacs=0; +#if SHOPT_VSH + volatile unsigned long was_vi=0; +#endif +#if SHOPT_ESH + volatile unsigned long was_emacs=0, was_gmacs=0; +#endif struct stat statb; bp = &shp->bltindata; save_ptr = bp->ptr; @@ -1252,12 +1257,16 @@ int sh_exec(register const Shnode_t *t, int flags) * disable editors for built-in * versions of commands on PATH */ +#if SHOPT_VSH was_vi = sh_isoption(SH_VI); + sh_offoption(SH_VI); +#endif +#if SHOPT_ESH was_emacs = sh_isoption(SH_EMACS); was_gmacs = sh_isoption(SH_GMACS); - sh_offoption(SH_VI); sh_offoption(SH_EMACS); sh_offoption(SH_GMACS); +#endif } if(execflg) sh_onstate(SH_NOFORK); @@ -1392,12 +1401,17 @@ int sh_exec(register const Shnode_t *t, int flags) shp->bltinfun = 0; if(buffp->olist) free_list(buffp->olist); +#if SHOPT_VSH if(was_vi) sh_onoption(SH_VI); - else if(was_emacs) + else +#endif +#if SHOPT_ESH + if(was_emacs) sh_onoption(SH_EMACS); else if(was_gmacs) sh_onoption(SH_GMACS); +#endif if(scope) sh_unscope(shp); bp->ptr = (void*)save_ptr; @@ -1555,7 +1569,7 @@ int sh_exec(register const Shnode_t *t, int flags) job.parent=parent=0; else { -#ifdef SHOPT_BGX +#if SHOPT_BGX int maxjob; if(((type&(FAMP|FINT)) == (FAMP|FINT)) && (maxjob=nv_getnum(JOBMAXNOD))>0) { @@ -2856,7 +2870,7 @@ pid_t _sh_fork(Shell_t *shp,register pid_t parent,int flags,int *jobid) shp->cpid = parent; if(!postid && job.curjobid && (flags&FPOU)) postid = job.curpgid; -#ifdef SHOPT_BGX +#if SHOPT_BGX if(!postid && (flags&(FAMP|FINT)) == (FAMP|FINT)) postid = 1; myjob = job_post(shp,parent,postid); diff --git a/src/cmd/ksh93/tests/basic.sh b/src/cmd/ksh93/tests/basic.sh index 405a02215..552e8f015 100755 --- a/src/cmd/ksh93/tests/basic.sh +++ b/src/cmd/ksh93/tests/basic.sh @@ -285,7 +285,7 @@ word=$(print $'foo\nbar' | ( read line; "$bincat") ) if [[ $word != bar ]] then err_exit "pipe to ( read line; $bincat) not working" fi -if [[ $(print x{a,b}y) != 'xay xby' ]] +if ((SHOPT_BRACEPAT)) && [[ $(print x{a,b}y) != 'xay xby' ]] then err_exit 'brace expansion not working' fi if [[ $(for i in foo bar diff --git a/src/cmd/ksh93/tests/glob.sh b/src/cmd/ksh93/tests/glob.sh index 9502dcb32..c96003d24 100755 --- a/src/cmd/ksh93/tests/glob.sh +++ b/src/cmd/ksh93/tests/glob.sh @@ -316,7 +316,8 @@ function test_sub } alias test_sub='test_sub $LINENO' -set --noglob --nobraceexpand +set --noglob +((SHOPT_BRACEPAT)) && set --nobraceexpand subject='A regular expressions test' diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh index 468817bdc..d74404b8b 100755 --- a/src/cmd/ksh93/tests/io.sh +++ b/src/cmd/ksh93/tests/io.sh @@ -698,10 +698,11 @@ got=$(export tmp; "$SHELL" -ec \ # ====== # Redirections of the form {varname}>file stopped working if brace expansion was turned off -set +B -{ redirect {v}>$tmp/v.out && echo ok >&$v; } 2>/dev/null -set -B +((SHOPT_BRACEPAT)) && set +B +{ redirect {v}>$tmp/v.out && echo ok >&$v; } 2>/dev/null && redirect {v}>&- +((SHOPT_BRACEPAT)) && set -B [[ -r $tmp/v.out && $(<$tmp/v.out) == ok ]] || err_exit '{varname}>file not working with brace expansion turned off' + # ...and they didn't work in subshells: https://github.com/ksh93/ksh/issues/167 (redirect {v}>$tmp/v.out; echo ok2 >&$v) 2>/dev/null [[ -r $tmp/v.out && $(<$tmp/v.out) == ok2 ]] || err_exit 'redirect {varname}>file not working in a subshell' diff --git a/src/cmd/ksh93/tests/locale.sh b/src/cmd/ksh93/tests/locale.sh index 7d8d2e8b0..85b4cc374 100755 --- a/src/cmd/ksh93/tests/locale.sh +++ b/src/cmd/ksh93/tests/locale.sh @@ -38,11 +38,12 @@ b=$($SHELL -c '(LC_ALL=debug / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, b=$($SHELL -c '(LC_ALL=debug; / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") [[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" +if((SHOPT_MULTIBYTE)); then # test shift-jis \x81\x40 ... \x81\x7E encodings # (shift char followed by 7 bit ascii) typeset -i16 chr -for locale in $(PATH=/bin:/usr/bin locale -a 2>/dev/null | grep -i jis) +for locale in $(command -p locale -a 2>/dev/null | grep -i jis) do export LC_ALL=$locale for ((chr=0x40; chr<=0x7E; chr++)) do c=${chr#16#} @@ -56,11 +57,16 @@ do export LC_ALL=$locale done done done +fi # SHOPT_MULTIBYTE # this locale is supported by ast on all platforms # EU for { decimal_point="," thousands_sep="." } +if((SHOPT_MULTIBYTE)); then locale=C_EU.UTF-8 +else +locale=C_EU +fi export LC_ALL=C @@ -104,7 +110,11 @@ fi #$SHELL -c 'export LANG='$locale'; printf "\u[20ac]\u[20ac]" > $tmp/two_euro_chars.txt' printf $'\342\202\254\342\202\254' > $tmp/two_euro_chars.txt +if((SHOPT_MULTIBYTE)); then exp="6 2 6" +else +exp="6 6 6" +fi # SHOPT_MULTIBYTE set -- $($SHELL -c " if builtin wc 2>/dev/null || builtin -f cmd wc 2>/dev/null then unset LC_CTYPE @@ -191,6 +201,7 @@ got="$(&1) [[ $got == "$exp" ]] || err_exit "multibyte variable definition/expansion failed -- expected '$exp', got '$got'" @@ -198,6 +209,7 @@ got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'function \u[5929]\n{\nprint OK;\n}; \u[ [[ $got == "$exp" ]] || err_exit "multibyte ksh function definition/execution failed -- expected '$exp', got '$got'" got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]()\n{\nprint OK;\n}; \u[5929]' 2>&1) [[ $got == "$exp" ]] || err_exit "multibyte posix function definition/execution failed -- expected '$exp', got '$got'" +fi # SHOPT_MULTIBYTE # this locale is supported by ast on all platforms # mainly used to debug multibyte and message translation code @@ -205,6 +217,7 @@ got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]()\n{\nprint OK;\n}; \u[5929]' locale=debug +if((SHOPT_MULTIBYTE)); then if [[ "$(LC_ALL=$locale $SHELL <<- \+EOF+ x=a<1z>b<2yx>c print ${#x} @@ -212,6 +225,7 @@ if [[ "$(LC_ALL=$locale $SHELL <<- \+EOF+ ]] then err_exit '${#x} not working with multibyte locales' fi +fi # SHOPT_MULTIBYTE dir=_not_found_ exp=2 @@ -243,9 +257,11 @@ do for cmd in "($lc=$locale;cd $dir)" "$lc=$locale;cd $dir;unset $lc" "function done done +if((SHOPT_MULTIBYTE)); then exp=123 got=$(LC_ALL=debug $SHELL -c "a<2A@>z=$exp; print \$a<2A@>z") [[ $got == $exp ]] || err_exit "multibyte debug locale \$a<2A@>z failed -- expected '$exp', got '$got'" +fi # SHOPT_MULTIBYTE unset LC_ALL LC_MESSAGES export LANG=debug @@ -297,7 +313,11 @@ x=$( LC_ALL=debug $SHELL ./script$$.1) x=$(LC_ALL=debug $SHELL -c 'x="a<2b|>c";print -r -- ${#x}') +if((SHOPT_MULTIBYTE)); then (( x == 3 )) || err_exit 'character length of multibyte character should be 3' +else +(( x == 7 )) || err_exit 'character length of multibyte character should be 7 with SHOPT_MULTIBYTE disabled' +fi # SHOPT_MULTIBYTE x=$(LC_ALL=debug $SHELL -c 'typeset -R10 x="a<2b|>c";print -r -- "${x}"') [[ $x == ' a<2b|>c' ]] || err_exit 'typeset -R10 should begin with three spaces' x=$(LC_ALL=debug $SHELL -c 'typeset -L10 x="a<2b|>c";print -r -- "${x}"') diff --git a/src/cmd/ksh93/tests/math.sh b/src/cmd/ksh93/tests/math.sh index f2b304cc2..2e4c948b9 100755 --- a/src/cmd/ksh93/tests/math.sh +++ b/src/cmd/ksh93/tests/math.sh @@ -198,8 +198,27 @@ test_has_iszero # printf formatting options as well as checking for correct float scaling # of the fractional parts. +if ((SHOPT_BRACEPAT)) +then set -- {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +else set -- 0.0000 0.0001 0.0009 0.0010 0.0011 0.0019 0.0090 0.0091 0.0099 \ + 0.0900 0.0901 0.0909 0.0910 0.0911 0.0919 0.0990 0.0991 0.0999 \ + 0.9000 0.9001 0.9009 0.9010 0.9011 0.9019 0.9090 0.9091 0.9099 \ + 0.9900 0.9901 0.9909 0.9910 0.9911 0.9919 0.9990 0.9991 0.9999 \ + 1.0000 1.0001 1.0009 1.0010 1.0011 1.0019 1.0090 1.0091 1.0099 \ + 1.0900 1.0901 1.0909 1.0910 1.0911 1.0919 1.0990 1.0991 1.0999 \ + 1.9000 1.9001 1.9009 1.9010 1.9011 1.9019 1.9090 1.9091 1.9099 \ + 1.9900 1.9901 1.9909 1.9910 1.9911 1.9919 1.9990 1.9991 1.9999 \ + -0.0000 -0.0001 -0.0009 -0.0010 -0.0011 -0.0019 -0.0090 -0.0091 -0.0099 \ + -0.0900 -0.0901 -0.0909 -0.0910 -0.0911 -0.0919 -0.0990 -0.0991 -0.0999 \ + -0.9000 -0.9001 -0.9009 -0.9010 -0.9011 -0.9019 -0.9090 -0.9091 -0.9099 \ + -0.9900 -0.9901 -0.9909 -0.9910 -0.9911 -0.9919 -0.9990 -0.9991 -0.9999 \ + -1.0000 -1.0001 -1.0009 -1.0010 -1.0011 -1.0019 -1.0090 -1.0091 -1.0099 \ + -1.0900 -1.0901 -1.0909 -1.0910 -1.0911 -1.0919 -1.0990 -1.0991 -1.0999 \ + -1.9000 -1.9001 -1.9009 -1.9010 -1.9011 -1.9019 -1.9090 -1.9091 -1.9099 \ + -1.9900 -1.9901 -1.9909 -1.9910 -1.9911 -1.9919 -1.9990 -1.9991 -1.9999 +fi unset i tf pf; typeset -F 3 tf -for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +for i do tf=$i pf=${ printf '%.3f' tf ;} if [[ $tf != "$pf" ]] @@ -207,7 +226,7 @@ do tf=$i fi done unset i tf pf; typeset -lF 3 tf -for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +for i do tf=$i pf=${ printf '%.3Lf' tf ;} if [[ $tf != "$pf" ]] @@ -215,7 +234,7 @@ do tf=$i fi done unset i tf pf; typeset -E 3 tf -for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +for i do tf=$i pf=${ printf '%.3g' tf ;} if [[ $tf != "$pf" ]] @@ -223,7 +242,7 @@ do tf=$i fi done unset i tf pf; typeset -lE 3 tf -for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +for i do tf=$i pf=${ printf '%.3Lg' tf ;} if [[ $tf != "$pf" ]] diff --git a/src/cmd/ksh93/tests/namespace.sh b/src/cmd/ksh93/tests/namespace.sh index 7848b2b5f..3d6027965 100755 --- a/src/cmd/ksh93/tests/namespace.sh +++ b/src/cmd/ksh93/tests/namespace.sh @@ -30,6 +30,11 @@ integer Errors=0 [[ -d $tmp && -w $tmp && $tmp == "$PWD" ]] || { err\_exit "$LINENO" '$tmp not set; run this from shtests. Aborting.'; exit 1; } +if((!SHOPT_NAMESPACE)) +then err\_exit "$LINENO" 'warning: shell compiled without SHOPT_NAMESPACE; skipping tests' + exit 0 +fi + foo=abc typeset -C bar=(x=3 y=4 t=7) typeset -A z=([abc]=qqq) diff --git a/src/cmd/ksh93/tests/options.sh b/src/cmd/ksh93/tests/options.sh index 53a1b349b..d3e26445a 100755 --- a/src/cmd/ksh93/tests/options.sh +++ b/src/cmd/ksh93/tests/options.sh @@ -202,20 +202,21 @@ rm .profile # { exec interactive login_shell restricted xtrace } in the following test -for opt in \ +set -- \ allexport all-export all_export \ bgnice bg-nice bg_nice \ - clobber emacs \ + clobber \ errexit err-exit err_exit \ glob \ globstar glob-star glob_star \ - gmacs \ ignoreeof ignore-eof ignore_eof \ keyword log markdirs monitor notify \ pipefail pipe-fail pipe_fail \ trackall track-all track_all \ - unset verbose vi \ - viraw vi-raw vi_raw + unset verbose +((SHOPT_ESH)) && set -- "$@" emacs gmacs +((SHOPT_VSH)) && set -- "$@" vi viraw vi-raw vi_raw +for opt do old=$opt if [[ ! -o $opt ]] then old=no$opt @@ -394,15 +395,16 @@ got=$( [[ $got == @((12|21)(12|21)) ]] || err_exit "& job delayed by --pipefail, expected '$exp', got '$got'" $SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' > $tmp/.profile -for i in i l r s D E a b e f h k n t u v x B C G H +for i in i l r s D E a b e f h k n t u v x $(let SHOPT_BRACEPAT && echo B) C G $(let SHOPT_HISTEXPAND && echo H) do HOME=$tmp ENV=/./dev/null $SHELL -$i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not in \$-" [[ \$- == *$i* ]] || exit 1 ++EOF++ done -letters=ilrabefhknuvxBCGE +letters=ilrabefhknuvx$(let SHOPT_BRACEPAT && echo B)CGE integer j=0 for i in interactive login restricted allexport notify errexit \ - noglob trackall keyword noexec nounset verbose xtrace braceexpand \ + noglob trackall keyword noexec nounset verbose xtrace \ + $(let SHOPT_BRACEPAT && echo braceexpand) \ noclobber globstar rc do HOME=$tmp ENV=/./dev/null $SHELL -o $i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" [[ \$- == *${letters:j:1}* ]] || exit 1 @@ -551,6 +553,7 @@ fi # ====== # Brace expansion could not be turned off in command substitutions (rhbz#1078698) +if((SHOPT_BRACEPAT)); then set -B expect='test{1,2}' actual=$(set +B; echo `echo test{1,2}`) @@ -562,6 +565,7 @@ actual=$(set +B; echo $(echo test{1,2})) actual=$(set +B; echo ${ echo test{1,2}; }) [[ $actual == "$expect" ]] || err_exit 'Brace expansion not turned off in ${ comsub; }' \ "(expected $(printf %q "$expect"), got $(printf %q "$actual"))" +fi # SHOPT_BRACEPAT # ====== # ksh 93u+ did not correctly handle the combination of pipefail and (errexit or the ERR trap). diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index cb63ab608..a13223119 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -23,7 +23,9 @@ # called 'pty', which allows for scripting interactive sessions and which is # installed in arch/*/bin while building. To understand these tests, first # read the pty manual by running: arch/*/bin/pty --man - +# +# Do not globally set the locale; these tests must pass for all locales. +# # The # err_exit # comments are to enable shtests to count the tests. # the trickiest part of the tests is avoiding typeahead @@ -52,19 +54,18 @@ stty erase ^H kill ^X bintrue=$(whence -p true) -x=$( $SHELL <<- \EOF +x=$( "$SHELL" 2>&1 <<- \EOF trap 'exit 0' EXIT bintrue=$(whence -p true) set -o monitor { - eval $'set -o vi\npty $bintrue' + eval $'command set -o vi 2>/dev/null\npty $bintrue' } < /dev/null & pid=$! - #sleep 1 jobs kill $$ EOF ) -[[ $x == *Stop* ]] && err_exit 'monitor mode enabled incorrectly causes job to stop' +[[ $x == *Stop* ]] && err_exit "monitor mode enabled incorrectly causes job to stop (got $(printf %q "$x"))" if [[ -o xtrace ]] then debug=--debug=1 @@ -86,7 +87,10 @@ function tst done } -export PS1=':test-!: ' PS2='> ' PS4=': ' ENV=/./dev/null EXINIT= HISTFILE= TERM=dumb VISUAL=vi LC_ALL=C +# VISUAL, or if that is not set, EDITOR, automatically sets vi, gmacs or emacs mode if +# its value matches *[Vv][Ii]*, *gmacs* or *macs*, respectively. See put_ed() in init.c. +unset EDITOR +export VISUAL=vi PS1=':test-!: ' PS2='> ' PS4=': ' ENV=/./dev/null EXINIT= HISTFILE= TERM=dumb if ! pty $bintrue < /dev/null then err_exit pty command hangs on $bintrue -- tests skipped @@ -163,7 +167,7 @@ u (Killed|Done) ! # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 091(C) # If the User Portability Utilities Option is supported and shell @@ -179,7 +183,7 @@ u ^hello\r?\n$ ! # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 093(C) # If the User Portability Utilities Option is supported and shell @@ -195,7 +199,7 @@ u ^goodbye\r?\n$ ! # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 094(C) # If the User Portability Utilities Option is supported and shell @@ -242,7 +246,7 @@ r history fi # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 097(C) # If the User Portability Utilities Option is supported and shell @@ -303,7 +307,7 @@ u ^ok\r?\n$ ! # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 101(C) # If the User Portability Utilities Option is supported and shell @@ -368,7 +372,7 @@ if [[ $(id -u) == 0 ]] then print -u2 "\t${Command}[$LINENO]: warning: running as root: skipping test POSIX sh 111(C)" else # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 111(C) # If the User Portability Utilities Option is supported and shell @@ -395,7 +399,7 @@ fi # It is left here for re-enabling temporarily if related changes in ksh need testing. : <<\end_disabled # err_(don't count me)_exit # -TMPDIR=/tmp tst $LINENO <<"!" +((SHOPT_VSH)) && TMPDIR=/tmp tst $LINENO <<"!" L POSIX sh 137(C) # If the User Portability Utilities Option is supported and shell @@ -420,7 +424,7 @@ if [[ $(id -u) == 0 ]] then print -u2 "\t${Command}[$LINENO]: warning: running as root: skipping test POSIX sh 251(C)" else # err_exit # -tst $LINENO <<"!" +((SHOPT_VSH)) && tst $LINENO <<"!" L POSIX sh 251(C) # If the User Portability Utilities Option is supported and shell @@ -480,6 +484,7 @@ disabled # err_exit # # Test file name completion in vi mode +if((SHOPT_VSH)); then mkdir "/tmp/fakehome_$$" && tst $LINENO <] [-author?Glenn Fowler ] @@ -270,8 +270,8 @@ case $SHELL in *) SHELL=$(whence $SHELL);; esac PATH=$( - PATH=/run/current-system/sw/bin:/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin:$PATH - getconf PATH 2>/dev/null || { builtin getconf 2>/dev/null && getconf PATH; } + builtin getconf 2>/dev/null || PATH=/run/current-system/sw/bin:/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin:$PATH + getconf PATH 2>/dev/null ) || PATH=/bin:/usr/bin if [[ -d /usr/ucb ]] then PATH=$PATH:/usr/ucb @@ -310,6 +310,18 @@ fi # (some tests must unset or modify $HISTFILE, so set $HOME instead) export HOME=$tmp +# make the SHOPT_* macros available to the tests as environment variables +SHOPT() +{ + [[ $1 == *=* ]] && eval "export SHOPT_${ printf %q "${1%%=*}"; }=${ printf %q "${1#*=}"; }" +} +. "${SHOPTFILE:-../SHOPT.sh}" +unset -f SHOPT +if (( !SHOPT_MULTIBYTE && utf8 && !posix && !compile )) +then echo "The -u/--utf8 option is unavailable as SHOPT_MULTIBYTE is turned off in ${SHOPTFILE:-SHOPT.sh}." >&2 + exit 1 +fi + if (( compile )) then if whence $SHCOMP > /dev/null then : @@ -352,7 +364,7 @@ do [[ $i == *.sh ]] || i+='.sh' if (( posix || utf8 )) then locales= (( posix )) && locales+=" ${LANG:-C}" - [[ $utf8 == 0 || $i == $setslocale ]] || locales+=" C.UTF-8" + [[ $utf8 == 0 || $i == $setslocale ]] || ((!SHOPT_MULTIBYTE)) || locales+=" C.UTF-8" for lang in $locales do o=$u tmp_s=$tmp/$u.$lang diff --git a/src/cmd/ksh93/tests/substring.sh b/src/cmd/ksh93/tests/substring.sh index 19a0099d2..7b6594453 100755 --- a/src/cmd/ksh93/tests/substring.sh +++ b/src/cmd/ksh93/tests/substring.sh @@ -260,8 +260,12 @@ fi if [[ ${var//+(\S)/Q} != 'Q Q' ]] then err_exit '${var//+(\S)/Q} not workding' fi + var=$($SHELL -c 'v=/vin:/usr/vin r=vin; : ${v//vin/${r//v/b}};typeset -p .sh.match') 2> /dev/null -[[ $var == 'typeset -a .sh.match=((vin vin) )' ]] || err_exit '.sh.match not correct when replacement pattern contains a substring match' +((SHOPT_2DMATCH)) && exp='typeset -a .sh.match=((vin vin) )' || exp='typeset -a .sh.match=(vin)' +[[ $var == "$exp" ]] || err_exit '.sh.match not correct when replacement pattern contains a substring match' \ + "(expected $(printf %q "$exp"), got $(printf %q "$var"))" + foo='foo+bar+' [[ $(print -r -- ${foo//+/'|'}) != 'foo|bar|' ]] && err_exit "\${foobar//+/'|'}" [[ $(print -r -- ${foo//+/"|"}) != 'foo|bar|' ]] && err_exit '${foobar//+/"|"}' @@ -523,7 +527,8 @@ fi string='foo(d:\nt\box\something)bar' expected='d:\nt\box\something' [[ ${string/*\(+([!\)])\)*/\1} == "$expected" ]] || err_exit "substring expansion failed '${string/*\(+([!\)])\)*/\1}' returned -- '$expected' expected" -if [[ $($SHELL -c $'export LC_ALL=C.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 ]] +if ((SHOPT_MULTIBYTE)) && + [[ $($SHELL -c $'export LC_ALL=C.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 ]] then LC_ALL=C.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'multibyte ${var:offset:len} not working correctly' fi { $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' @@ -581,6 +586,7 @@ do i=$1 done #multibyte locale tests +if((SHOPT_MULTIBYTE)); then x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:0:1}" == a || err_exit ${x:0:1} should be a' x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:1}" == "<2b|>" || err_exit ${x:1:1} should be <2b|>' x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:3:1}" == "<3d|\\>" || err_exit ${x:3:1} should be <3d|\>' @@ -591,6 +597,7 @@ x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x: -2:1}" == "<3d|\\>" || err x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:3}" == "<2b|>c<3d|\\>" || err_exit ${x:1:3} should be <2b|>c<3d|\>' x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:20}" == "<2b|>c<3d|\\>e" || err_exit ${x:1:20} should be <2b|>c<3d|\>e' x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x#??}" == "c<3d|\\>e" || err_exit "${x#??} should be c<3d|\>e' +fi # SHOPT_MULTIBYTE x='a one and a two' [[ "${x//~(E)\<.\>/}" == ' one and two' ]] || err_exit "\< and \> not working in with ere's" diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 144f22c22..5309b04a9 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -717,7 +717,11 @@ actual=$( expect=$'4\n3\n3\n2\n1' [[ $actual == "$expect" ]] || err_exit "\${.sh.subshell} failure (expected $(printf %q "$expect"), got $(printf %q "$actual"))" -set -- {1..32768} +unset IFS +if ((SHOPT_BRACEPAT)) && command set -o braceexpand +then set -- {1..32768} +else set -- $(awk 'BEGIN { for(i=1;i<=32768;i++) print i; }') +fi (( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#" set --