diff -urN stable/8/bin/sh/Makefile head/bin/sh/Makefile --- stable/8/bin/sh/Makefile 2007-11-17 20:53:07.000000000 -0500 +++ head/bin/sh/Makefile 2007-11-17 20:53:07.000000000 -0500 @@ -1,5 +1,5 @@ # @(#)Makefile 8.4 (Berkeley) 5/5/95 -# $FreeBSD: stable/8/bin/sh/Makefile 173718 2007-11-18 01:53:07Z jb $ +# $FreeBSD: head/bin/sh/Makefile 173718 2007-11-18 01:53:07Z jb $ PROG= sh INSTALLFLAGS= -S diff -urN stable/8/bin/sh/TOUR head/bin/sh/TOUR --- stable/8/bin/sh/TOUR 2006-04-16 07:54:01.000000000 -0400 +++ head/bin/sh/TOUR 2006-04-16 07:54:01.000000000 -0400 @@ -1,5 +1,5 @@ # @(#)TOUR 8.1 (Berkeley) 5/31/93 -# $FreeBSD: stable/8/bin/sh/TOUR 157789 2006-04-16 11:54:01Z schweikh $ +# $FreeBSD: head/bin/sh/TOUR 157789 2006-04-16 11:54:01Z schweikh $ NOTE -- This is the original TOUR paper distributed with ash and does not represent the current state of the shell. It is provided anyway diff -urN stable/8/bin/sh/alias.c head/bin/sh/alias.c --- stable/8/bin/sh/alias.c 2009-06-01 06:50:17.801753000 -0400 +++ head/bin/sh/alias.c 2009-12-24 13:41:14.411055000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/alias.c 193221 2009-06-01 10:50:17Z rse $"); +__FBSDID("$FreeBSD: head/bin/sh/alias.c 200956 2009-12-24 18:41:14Z jilles $"); #include #include "shell.h" @@ -52,13 +52,13 @@ STATIC struct alias *atab[ATABSIZE]; STATIC int aliases; -STATIC void setalias(char *, char *); +STATIC void setalias(const char *, const char *); STATIC int unalias(const char *); STATIC struct alias **hashalias(const char *); STATIC void -setalias(char *name, char *val) +setalias(const char *name, const char *val) { struct alias *ap, **app; @@ -176,7 +176,7 @@ } struct alias * -lookupalias(char *name, int check) +lookupalias(const char *name, int check) { struct alias *ap = *hashalias(name); diff -urN stable/8/bin/sh/alias.h head/bin/sh/alias.h --- stable/8/bin/sh/alias.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/alias.h 2009-12-24 13:41:14.411055000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)alias.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/alias.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/alias.h 200956 2009-12-24 18:41:14Z jilles $ */ #define ALIASINUSE 1 @@ -42,7 +42,7 @@ int flag; }; -struct alias *lookupalias(char *, int); +struct alias *lookupalias(const char *, int); int aliascmd(int, char **); int unaliascmd(int, char **); void rmaliases(void); diff -urN stable/8/bin/sh/arith.h head/bin/sh/arith.h --- stable/8/bin/sh/arith.h 2008-04-27 16:46:45.000000000 -0400 +++ head/bin/sh/arith.h 2009-12-24 13:41:14.411055000 -0500 @@ -27,15 +27,15 @@ * SUCH DAMAGE. * * @(#)arith.h 1.1 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/arith.h 178625 2008-04-27 20:46:45Z stefanf $ + * $FreeBSD: head/bin/sh/arith.h 200956 2009-12-24 18:41:14Z jilles $ */ #include "shell.h" #define DIGITS(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3) -extern char *arith_buf, *arith_startbuf; +extern const char *arith_buf, *arith_startbuf; -arith_t arith(char *); +arith_t arith(const char *); void arith_lex_reset(void); int expcmd(int, char **); diff -urN stable/8/bin/sh/arith.y head/bin/sh/arith.y --- stable/8/bin/sh/arith.y 2008-04-27 16:46:45.000000000 -0400 +++ head/bin/sh/arith.y 2010-04-25 16:43:19.108643000 -0400 @@ -38,7 +38,7 @@ #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/arith.y 178625 2008-04-27 20:46:45Z stefanf $"); +__FBSDID("$FreeBSD: head/bin/sh/arith.y 207206 2010-04-25 20:43:19Z jilles $"); #include #include @@ -85,9 +85,9 @@ ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; } | expr ARITH_OR expr - { $$ = $1 ? $1 : $3 ? $3 : 0; } | + { $$ = $1 || $3; } | expr ARITH_AND expr - { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } | + { $$ = $1 && $3; } | expr ARITH_BOR expr { $$ = $1 | $3; } | expr ARITH_BXOR expr @@ -265,7 +265,7 @@ #define YYPARSE_PARAM_TYPE arith_t * #define YYPARSE_PARAM result -char *arith_buf, *arith_startbuf; +const char *arith_buf, *arith_startbuf; int yylex(void); int yyparse(YYPARSE_PARAM_TYPE); @@ -284,10 +284,12 @@ } arith_t -arith(char *s) +arith(const char *s) { arith_t result; + struct stackmark smark; + setstackmark(&smark); arith_buf = arith_startbuf = s; INTOFF; @@ -295,11 +297,13 @@ arith_lex_reset(); /* Reprime lex. */ INTON; + popstackmark(&smark); + return result; } static void -yyerror(char *s) +yyerror(const char *s) { yyerrok; @@ -314,7 +318,7 @@ int expcmd(int argc, char **argv) { - char *p; + const char *p; char *concat; char **ap; arith_t i; @@ -354,7 +358,7 @@ printf("%d\n", exp(argv[1])); } -error(char *s) +error(const char *s) { fprintf(stderr, "exp: %s\n", s); exit(1); diff -urN stable/8/bin/sh/arith_lex.l head/bin/sh/arith_lex.l --- stable/8/bin/sh/arith_lex.l 2009-12-06 17:01:45.088880000 -0500 +++ head/bin/sh/arith_lex.l 2010-04-25 16:43:19.108643000 -0400 @@ -38,7 +38,7 @@ #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/arith_lex.l 200188 2009-12-06 22:01:45Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/arith_lex.l 207206 2010-04-25 20:43:19Z jilles $"); #include @@ -51,13 +51,6 @@ int yylex(void); -struct varname -{ - struct varname *next; - char name[1]; -}; -static struct varname *varnames; - #undef YY_INPUT #define YY_INPUT(buf,result,max) \ result = (*buf = *arith_buf++) ? 1 : YY_NULL; @@ -87,14 +80,11 @@ * If variable doesn't exist, we should initialize * it to zero. */ - struct varname *temp; + char *temp; if (lookupvar(yytext) == NULL) setvarsafe(yytext, "0", 0); - temp = ckmalloc(sizeof(struct varname) + - strlen(yytext)); - temp->next = varnames; - varnames = temp; - yylval.s_value = strcpy(temp->name, yytext); + temp = stalloc(strlen(yytext) + 1); + yylval.s_value = strcpy(temp, yytext); return ARITH_VAR; } @@ -140,15 +130,5 @@ void arith_lex_reset(void) { - struct varname *name, *next; - YY_NEW_FILE; - - name = varnames; - while (name != NULL) { - next = name->next; - ckfree(name); - name = next; - } - varnames = NULL; } diff -urN stable/8/bin/sh/bltin/bltin.h head/bin/sh/bltin/bltin.h --- stable/8/bin/sh/bltin/bltin.h 2005-08-13 11:04:30.000000000 -0400 +++ head/bin/sh/bltin/bltin.h 2005-08-13 11:04:30.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)bltin.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/bltin/bltin.h 149025 2005-08-13 15:04:30Z stefanf $ + * $FreeBSD: head/bin/sh/bltin/bltin.h 149025 2005-08-13 15:04:30Z stefanf $ */ /* diff -urN stable/8/bin/sh/bltin/echo.1 head/bin/sh/bltin/echo.1 --- stable/8/bin/sh/bltin/echo.1 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/bltin/echo.1 2005-01-10 03:39:26.000000000 -0500 @@ -31,7 +31,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)echo.1 8.2 (Berkeley) 5/4/95 -.\" $FreeBSD: stable/8/bin/sh/bltin/echo.1 139969 2005-01-10 08:39:26Z imp $ +.\" $FreeBSD: head/bin/sh/bltin/echo.1 139969 2005-01-10 08:39:26Z imp $ .\" .Dd May 4, 1995 .Dt ECHO 1 diff -urN stable/8/bin/sh/bltin/echo.c head/bin/sh/bltin/echo.c --- stable/8/bin/sh/bltin/echo.c 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/bltin/echo.c 2004-04-06 16:06:54.000000000 -0400 @@ -33,7 +33,7 @@ */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/bltin/echo.c 127958 2004-04-06 20:06:54Z markm $"); +__FBSDID("$FreeBSD: head/bin/sh/bltin/echo.c 127958 2004-04-06 20:06:54Z markm $"); /* * Echo command. diff -urN stable/8/bin/sh/builtins.def head/bin/sh/builtins.def --- stable/8/bin/sh/builtins.def 2006-04-02 14:43:33.000000000 -0400 +++ head/bin/sh/builtins.def 2006-04-02 14:43:33.000000000 -0400 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)builtins.def 8.4 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/builtins.def 157413 2006-04-02 18:43:33Z stefanf $ +# $FreeBSD: head/bin/sh/builtins.def 157413 2006-04-02 18:43:33Z stefanf $ # # This file lists all the builtin commands. The first column is the name diff -urN stable/8/bin/sh/cd.c head/bin/sh/cd.c --- stable/8/bin/sh/cd.c 2010-05-16 06:01:06.549498000 -0400 +++ head/bin/sh/cd.c 2010-04-17 10:35:46.799348000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/cd.c 208134 2010-05-16 10:01:06Z stefanf $"); +__FBSDID("$FreeBSD: head/bin/sh/cd.c 206759 2010-04-17 14:35:46Z jilles $"); #include #include @@ -70,6 +70,7 @@ STATIC char *getcomponent(void); STATIC char *findcwd(char *); STATIC void updatepwd(char *); +STATIC char *getpwd(void); STATIC char *getpwd2(void); STATIC char *curdir = NULL; /* current working directory */ @@ -79,8 +80,8 @@ int cdcmd(int argc, char **argv) { - char *dest; - char *path; + const char *dest; + const char *path; char *p; struct stat statb; int ch, phys, print = 0; @@ -351,7 +352,7 @@ /* * Get the current directory and cache the result in curdir. */ -char * +STATIC char * getpwd(void) { char *p; @@ -374,7 +375,6 @@ STATIC char * getpwd2(void) { - struct stat stdot, stpwd; char *pwd; int i; @@ -387,12 +387,29 @@ break; } - pwd = getenv("PWD"); + return NULL; +} + +/* + * Initialize PWD in a new shell. + * If the shell is interactive, we need to warn if this fails. + */ +void +pwd_init(int warn) +{ + char *pwd; + struct stat stdot, stpwd; + + pwd = lookupvar("PWD"); if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && stat(pwd, &stpwd) != -1 && stdot.st_dev == stpwd.st_dev && stdot.st_ino == stpwd.st_ino) { - return pwd; + if (curdir) + ckfree(curdir); + curdir = savestr(pwd); } - return NULL; + if (getpwd() == NULL && warn) + out2fmt_flush("sh: cannot determine working directory\n"); + setvar("PWD", curdir, VEXPORT); } diff -urN stable/8/bin/sh/cd.h head/bin/sh/cd.h --- stable/8/bin/sh/cd.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/cd.h 2010-04-17 10:35:46.799348000 -0400 @@ -26,9 +26,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: stable/8/bin/sh/cd.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/cd.h 206759 2010-04-17 14:35:46Z jilles $ */ -char *getpwd(void); +void pwd_init(int); int cdcmd (int, char **); int pwdcmd(int, char **); diff -urN stable/8/bin/sh/error.c head/bin/sh/error.c --- stable/8/bin/sh/error.c 2006-02-04 09:37:50.000000000 -0500 +++ head/bin/sh/error.c 2010-01-01 13:17:46.488302000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/error.c 155301 2006-02-04 14:37:50Z schweikh $"); +__FBSDID("$FreeBSD: head/bin/sh/error.c 201366 2010-01-01 18:17:46Z jilles $"); /* * Errors and exceptions. @@ -67,17 +67,21 @@ char *commandname; -static void exverror(int, const char *, va_list) __printf0like(2, 0); +static void exverror(int, const char *, va_list) __printf0like(2, 0) __dead2; /* * Called to raise an exception. Since C doesn't include exceptions, we * just do a longjmp to the exception handler. The type of exception is * stored in the global variable "exception". + * + * Interrupts are disabled; they should be reenabled when the exception is + * caught. */ void exraise(int e) { + INTOFF; if (handler == NULL) abort(); exception = e; @@ -138,8 +142,15 @@ static void exverror(int cond, const char *msg, va_list ap) { - CLEAR_PENDING_INT; - INTOFF; + /* + * An interrupt trumps an error. Certain places catch error + * exceptions or transform them to a plain nonzero exit code + * in child processes, and if an error exception can be handled, + * an interrupt can be handled as well. + * + * exraise() will disable interrupts for the exception handler. + */ + FORCEINTON; #ifdef DEBUG if (msg) @@ -149,8 +160,8 @@ #endif if (msg) { if (commandname) - outfmt(&errout, "%s: ", commandname); - doformat(&errout, msg, ap); + outfmt(out2, "%s: ", commandname); + doformat(out2, msg, ap); out2c('\n'); } flushall(); diff -urN stable/8/bin/sh/error.h head/bin/sh/error.h --- stable/8/bin/sh/error.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/error.h 2009-12-24 15:55:14.498557000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)error.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/error.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/error.h 200967 2009-12-24 20:55:14Z jilles $ */ /* @@ -72,14 +72,16 @@ #define INTOFF suppressint++ #define INTON { if (--suppressint == 0 && intpending) onint(); } +#define is_int_on() suppressint +#define SETINTON(s) suppressint = (s) #define FORCEINTON {suppressint = 0; if (intpending) onint();} #define CLEAR_PENDING_INT intpending = 0 #define int_pending() intpending -void exraise(int); +void exraise(int) __dead2; void onint(void); -void error(const char *, ...) __printf0like(1, 2); -void exerror(int, const char *, ...) __printf0like(2, 3); +void error(const char *, ...) __printf0like(1, 2) __dead2; +void exerror(int, const char *, ...) __printf0like(2, 3) __dead2; /* diff -urN stable/8/bin/sh/eval.c head/bin/sh/eval.c --- stable/8/bin/sh/eval.c 2009-10-11 12:35:12.561852000 -0400 +++ head/bin/sh/eval.c 2010-05-28 18:40:24.781829000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/eval.c 197959 2009-10-11 16:35:12Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/eval.c 208630 2010-05-28 22:40:24Z jilles $"); #include #include @@ -74,7 +74,7 @@ #endif -MKINIT int evalskip; /* set if we are skipping commands */ +int evalskip; /* set if we are skipping commands */ STATIC int skipcount; /* number of levels to skip */ MKINIT int loopnest; /* current loop nesting level */ int funcnest; /* depth of function calls */ @@ -91,6 +91,7 @@ STATIC void evalfor(union node *, int); STATIC void evalcase(union node *, int); STATIC void evalsubshell(union node *, int); +STATIC void evalredir(union node *, int); STATIC void expredir(union node *); STATIC void evalpipe(union node *); STATIC void evalcommand(union node *, int, struct backcmd *); @@ -221,10 +222,7 @@ evaltree(n->nbinary.ch2, flags); break; case NREDIR: - expredir(n->nredir.redirect); - redirect(n->nredir.redirect, REDIR_PUSH); - evaltree(n->nredir.n, flags); - popredir(); + evalredir(n, flags); break; case NSUBSHELL: evalsubshell(n, flags); @@ -407,8 +405,7 @@ flags &=~ EV_TESTED; redirect(n->nredir.redirect, 0); evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ - } - if (! backgnd) { + } else if (! backgnd) { INTOFF; exitstatus = waitforjob(jp, (int *)NULL); INTON; @@ -416,6 +413,46 @@ } +/* + * Evaluate a redirected compound command. + */ + +STATIC void +evalredir(union node *n, int flags) +{ + struct jmploc jmploc; + struct jmploc *savehandler; + volatile int in_redirect = 1; + + expredir(n->nredir.redirect); + savehandler = handler; + if (setjmp(jmploc.loc)) { + int e; + + handler = savehandler; + e = exception; + if (e == EXERROR || e == EXEXEC) { + popredir(); + if (in_redirect) { + exitstatus = 2; + return; + } + } + longjmp(handler->loc, 1); + } else { + INTOFF; + handler = &jmploc; + redirect(n->nredir.redirect, REDIR_PUSH); + in_redirect = 0; + INTON; + evaltree(n->nredir.n, flags); + } + INTOFF; + handler = savehandler; + popredir(); + INTON; +} + /* * Compute the names of the files in a redirection list. @@ -593,10 +630,12 @@ char *savecmdname; struct shparam saveparam; struct localvar *savelocalvars; + struct parsefile *savetopfile; volatile int e; char *lastarg; int realstatus; int do_clearcmdentry; + char *path = pathval(); /* First expand the arguments. */ TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags)); @@ -646,7 +685,7 @@ out2str(ps4val()); for (sp = varlist.list ; sp ; sp = sp->next) { if (sep != 0) - outc(' ', &errout); + out2c(' '); p = sp->text; while (*p != '=' && *p != '\0') out2c(*p++); @@ -658,7 +697,7 @@ } for (sp = arglist.list ; sp ; sp = sp->next) { if (sep != 0) - outc(' ', &errout); + out2c(' '); /* Disambiguate command looking like assignment. */ if (sp == arglist.list && strchr(sp->text, '=') != NULL && @@ -670,7 +709,7 @@ out2qstr(sp->text); sep = ' '; } - outc('\n', &errout); + out2c('\n'); flushout(&errout); } @@ -679,10 +718,10 @@ /* Variable assignment(s) without command */ cmdentry.cmdtype = CMDBUILTIN; cmdentry.u.index = BLTINCMD; - cmdentry.special = 1; + cmdentry.special = 0; } else { static const char PATH[] = "PATH="; - char *path = pathval(); + int cmd_flags = 0, bltinonly = 0; /* * Modify the command lookup path, if a PATH= assignment @@ -713,42 +752,79 @@ do_clearcmdentry = 1; } - find_command(argv[0], &cmdentry, 1, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 127; - flushout(&errout); - return; - } - /* implement the bltin builtin here */ - if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { - for (;;) { - argv++; - if (--argc == 0) + for (;;) { + if (bltinonly) { + cmdentry.u.index = find_builtin(*argv, &cmdentry.special); + if (cmdentry.u.index < 0) { + cmdentry.u.index = BLTINCMD; + argv--; + argc++; break; - if ((cmdentry.u.index = find_builtin(*argv, - &cmdentry.special)) < 0) { - outfmt(&errout, "%s: not found\n", *argv); - exitstatus = 127; - flushout(&errout); - return; } - if (cmdentry.u.index != BLTINCMD) + } else + find_command(argv[0], &cmdentry, cmd_flags, path); + /* implement the bltin and command builtins here */ + if (cmdentry.cmdtype != CMDBUILTIN) + break; + if (cmdentry.u.index == BLTINCMD) { + if (argc == 1) break; - } + argv++; + argc--; + bltinonly = 1; + } else if (cmdentry.u.index == COMMANDCMD) { + if (argc == 1) + break; + if (!strcmp(argv[1], "-p")) { + if (argc == 2) + break; + if (argv[2][0] == '-') { + if (strcmp(argv[2], "--")) + break; + if (argc == 3) + break; + argv += 3; + argc -= 3; + } else { + argv += 2; + argc -= 2; + } + path = _PATH_STDPATH; + clearcmdentry(0); + do_clearcmdentry = 1; + } else if (!strcmp(argv[1], "--")) { + if (argc == 2) + break; + argv += 2; + argc -= 2; + } else if (argv[1][0] == '-') + break; + else { + argv++; + argc--; + } + cmd_flags |= DO_NOFUNC; + bltinonly = 0; + } else + break; } + /* + * Special builtins lose their special properties when + * called via 'command'. + */ + if (cmd_flags & DO_NOFUNC) + cmdentry.special = 0; } /* Fork off a child process if necessary. */ if (cmd->ncmd.backgnd - || (cmdentry.cmdtype == CMDNORMAL + || ((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN) && ((flags & EV_EXIT) == 0 || have_traps())) || ((flags & EV_BACKCMD) != 0 && (cmdentry.cmdtype != CMDBUILTIN || cmdentry.u.index == CDCMD || cmdentry.u.index == DOTCMD - || cmdentry.u.index == EVALCMD)) - || (cmdentry.cmdtype == CMDBUILTIN && - cmdentry.u.index == COMMANDCMD)) { + || cmdentry.u.index == EVALCMD))) { jp = makejob(cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { @@ -775,7 +851,6 @@ #ifdef DEBUG trputs("Shell function: "); trargs(argv); #endif - redirect(cmd->ncmd.redirect, REDIR_PUSH); saveparam = shellparam; shellparam.malloc = 0; shellparam.reset = 1; @@ -786,7 +861,6 @@ savelocalvars = localvars; localvars = NULL; reffunc(cmdentry.u.func); - INTON; savehandler = handler; if (setjmp(jmploc.loc)) { if (exception == EXSHELLPROC) @@ -794,23 +868,27 @@ else { freeparam(&shellparam); shellparam = saveparam; + if (exception == EXERROR || exception == EXEXEC) + popredir(); } unreffunc(cmdentry.u.func); poplocalvars(); localvars = savelocalvars; + funcnest--; handler = savehandler; longjmp(handler->loc, 1); } handler = &jmploc; + funcnest++; + redirect(cmd->ncmd.redirect, REDIR_PUSH); + INTON; for (sp = varlist.list ; sp ; sp = sp->next) mklocal(sp->text); - funcnest++; exitstatus = oexitstatus; if (flags & EV_TESTED) evaltree(getfuncnode(cmdentry.u.func), EV_TESTED); else evaltree(getfuncnode(cmdentry.u.func), 0); - funcnest--; INTOFF; unreffunc(cmdentry.u.func); poplocalvars(); @@ -818,6 +896,7 @@ freeparam(&shellparam); shellparam = saveparam; handler = savehandler; + funcnest--; popredir(); INTON; if (evalskip == SKIPFUNC) { @@ -836,8 +915,10 @@ memout.nextc = memout.buf; memout.bufsize = 64; mode |= REDIR_BACKQ; + cmdentry.special = 0; } savecmdname = commandname; + savetopfile = getcurrentfile(); cmdenviron = varlist.list; e = -1; savehandler = handler; @@ -848,15 +929,25 @@ } handler = &jmploc; redirect(cmd->ncmd.redirect, mode); + /* + * If there is no command word, redirection errors should + * not be fatal but assignment errors should. + */ + if (argc == 0 && !(flags & EV_BACKCMD)) + cmdentry.special = 1; if (cmdentry.special) listsetvar(cmdenviron); + if (argc > 0) + bltinsetlocale(); commandname = argv[0]; argptr = argv + 1; - optptr = NULL; /* initialize nextopt */ + nextopt_optptr = NULL; /* initialize nextopt */ builtin_flags = flags; exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); flushall(); cmddone: + if (argc > 0) + bltinunsetlocale(); cmdenviron = NULL; out1 = &output; out2 = &errout; @@ -868,29 +959,31 @@ } } handler = savehandler; - if (e != -1) { - if ((e != EXERROR && e != EXEXEC) - || cmdentry.special) - exraise(e); - FORCEINTON; - } - if (cmdentry.u.index != EXECCMD) - popredir(); if (flags == EV_BACKCMD) { backcmd->buf = memout.buf; backcmd->nleft = memout.nextc - memout.buf; memout.buf = NULL; } + if (cmdentry.u.index != EXECCMD && + (e == -1 || e == EXERROR || e == EXEXEC)) + popredir(); + if (e != -1) { + if ((e != EXERROR && e != EXEXEC) + || cmdentry.special) + exraise(e); + popfilesupto(savetopfile); + if (flags != EV_BACKCMD) + FORCEINTON; + } } else { #ifdef DEBUG trputs("normal command: "); trargs(argv); #endif - clearredir(); redirect(cmd->ncmd.redirect, 0); for (sp = varlist.list ; sp ; sp = sp->next) setvareq(sp->text, VEXPORT|VSTACK); envp = environment(); - shellexec(argv, envp, pathval(), cmdentry.u.index); + shellexec(argv, envp, path, cmdentry.u.index); /*NOTREACHED*/ } goto out; @@ -946,12 +1039,17 @@ */ /* - * No command given, or a bltin command with no arguments. + * No command given, a bltin command with no arguments, or a bltin command + * with an invalid name. */ int -bltincmd(int argc __unused, char **argv __unused) +bltincmd(int argc, char **argv) { + if (argc > 1) { + out2fmt_flush("%s: not found\n", argv[1]); + return 127; + } /* * Preserve exitstatus of a previous possible redirection * as POSIX mandates @@ -991,23 +1089,18 @@ int commandcmd(int argc, char **argv) { - static char stdpath[] = _PATH_STDPATH; - struct jmploc loc, *old; - struct strlist *sp; - char *path; + const char *path; int ch; int cmd = -1; - for (sp = cmdenviron; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - path = pathval(); + path = bltinlookup("PATH", 1); optind = optreset = 1; opterr = 0; while ((ch = getopt(argc, argv, "pvV")) != -1) { switch (ch) { case 'p': - path = stdpath; + path = _PATH_STDPATH; break; case 'v': cmd = TYPECMD_SMALLV; @@ -1026,24 +1119,16 @@ if (cmd != -1) { if (argc != 1) error("wrong number of arguments"); - return typecmd_impl(2, argv - 1, cmd); - } - if (argc != 0) { - old = handler; - handler = &loc; - if (setjmp(handler->loc) == 0) - shellexec(argv, environment(), path, 0); - handler = old; - if (exception == EXEXEC) - exit(exerrno); - exraise(exception); + return typecmd_impl(2, argv - 1, cmd, path); } + if (argc != 0) + error("commandcmd() called while it should not be"); /* * Do nothing successfully if no command was specified; * ksh also does this. */ - exit(0); + return 0; } @@ -1085,6 +1170,12 @@ int execcmd(int argc, char **argv) { + /* + * Because we have historically not supported any options, + * only treat "--" specially. + */ + if (argc > 1 && strcmp(argv[1], "--") == 0) + argc--, argv++; if (argc > 1) { struct strlist *sp; diff -urN stable/8/bin/sh/eval.h head/bin/sh/eval.h --- stable/8/bin/sh/eval.h 2009-06-13 17:17:45.691358000 -0400 +++ head/bin/sh/eval.h 2009-12-27 13:04:05.764326000 -0500 @@ -30,11 +30,12 @@ * SUCH DAMAGE. * * @(#)eval.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/eval.h 194128 2009-06-13 21:17:45Z jilles $ + * $FreeBSD: head/bin/sh/eval.h 201053 2009-12-27 18:04:05Z jilles $ */ extern char *commandname; /* currently executing command */ extern int exitstatus; /* exit status of last command */ +extern int oexitstatus; /* saved exit status */ extern struct strlist *cmdenviron; /* environment for builtin command */ diff -urN stable/8/bin/sh/exec.c head/bin/sh/exec.c --- stable/8/bin/sh/exec.c 2009-10-11 12:35:12.561852000 -0400 +++ head/bin/sh/exec.c 2010-03-06 11:57:53.405454000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/exec.c 197959 2009-10-11 16:35:12Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/exec.c 204800 2010-03-06 16:57:53Z jilles $"); #include #include @@ -98,7 +98,7 @@ STATIC void tryexec(char *, char **, char **); STATIC void printentry(struct tblentry *, int); -STATIC struct tblentry *cmdlookup(char *, int); +STATIC struct tblentry *cmdlookup(const char *, int); STATIC void delete_cmd_entry(void); @@ -109,7 +109,7 @@ */ void -shellexec(char **argv, char **envp, char *path, int index) +shellexec(char **argv, char **envp, const char *path, int idx) { char *cmdname; int e; @@ -120,7 +120,7 @@ } else { e = ENOENT; while ((cmdname = padvance(&path, argv[0])) != NULL) { - if (--index < 0 && pathopt == NULL) { + if (--idx < 0 && pathopt == NULL) { tryexec(cmdname, argv, envp); if (errno != ENOENT && errno != ENOTDIR) e = errno; @@ -175,13 +175,13 @@ * NULL. */ -char *pathopt; +const char *pathopt; char * -padvance(char **path, char *name) +padvance(const char **path, const char *name) { - char *p, *q; - char *start; + const char *p, *start; + char *q; int len; if (*path == NULL) @@ -248,14 +248,14 @@ && (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) delete_cmd_entry(); - find_command(name, &entry, 1, pathval()); + find_command(name, &entry, DO_ERR, pathval()); if (verbose) { if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ cmdp = cmdlookup(name, 0); if (cmdp != NULL) printentry(cmdp, verbose); else - outfmt(&errout, "%s: not found\n", name); + outfmt(out2, "%s: not found\n", name); } flushall(); } @@ -268,17 +268,17 @@ STATIC void printentry(struct tblentry *cmdp, int verbose) { - int index; - char *path; + int idx; + const char *path; char *name; if (cmdp->cmdtype == CMDNORMAL) { - index = cmdp->param.index; + idx = cmdp->param.index; path = pathval(); do { name = padvance(&path, cmdp->cmdname); stunalloc(name); - } while (--index >= 0); + } while (--idx >= 0); out1str(name); } else if (cmdp->cmdtype == CMDBUILTIN) { out1fmt("builtin %s", cmdp->cmdname); @@ -310,10 +310,11 @@ */ void -find_command(char *name, struct cmdentry *entry, int printerr, char *path) +find_command(const char *name, struct cmdentry *entry, int act, + const char *path) { - struct tblentry *cmdp; - int index; + struct tblentry *cmdp, loc_cmd; + int idx; int prev; char *fullname; struct stat statb; @@ -329,13 +330,19 @@ } /* If name is in the table, and not invalidated by cd, we're done */ - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) - goto success; + if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { + if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC) + cmdp = NULL; + else + goto success; + } /* If %builtin not in path, check for builtin next */ if (builtinloc < 0 && (i = find_builtin(name, &spec)) >= 0) { INTOFF; cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) + cmdp = &loc_cmd; cmdp->cmdtype = CMDBUILTIN; cmdp->param.index = i; cmdp->special = spec; @@ -353,17 +360,19 @@ } e = ENOENT; - index = -1; + idx = -1; loop: while ((fullname = padvance(&path, name)) != NULL) { stunalloc(fullname); - index++; + idx++; if (pathopt) { if (prefix("builtin", pathopt)) { if ((i = find_builtin(name, &spec)) < 0) goto loop; INTOFF; cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) + cmdp = &loc_cmd; cmdp->cmdtype = CMDBUILTIN; cmdp->param.index = i; cmdp->special = spec; @@ -376,8 +385,8 @@ } } /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && index <= prev) { - if (index < prev) + if (fullname[0] == '/' && idx <= prev) { + if (idx < prev) goto loop; TRACE(("searchexec \"%s\": no change\n", name)); goto success; @@ -413,22 +422,25 @@ TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); INTOFF; cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) + cmdp = &loc_cmd; cmdp->cmdtype = CMDNORMAL; - cmdp->param.index = index; + cmdp->param.index = idx; INTON; goto success; } /* We failed. If there was an entry for this command, delete it */ - if (cmdp) + if (cmdp && cmdp->cmdtype != CMDFUNCTION) delete_cmd_entry(); - if (printerr) { + if (act & DO_ERR) { if (e == ENOENT || e == ENOTDIR) outfmt(out2, "%s: not found\n", name); else outfmt(out2, "%s: %s\n", name, strerror(e)); } entry->cmdtype = CMDUNKNOWN; + entry->u.index = 0; return; success: @@ -445,7 +457,7 @@ */ int -find_builtin(char *name, int *special) +find_builtin(const char *name, int *special) { const struct builtincmd *bp; @@ -492,18 +504,18 @@ changepath(const char *newval) { const char *old, *new; - int index; + int idx; int firstchange; int bltin; old = pathval(); new = newval; firstchange = 9999; /* assume no change */ - index = 0; + idx = 0; bltin = -1; for (;;) { if (*old != *new) { - firstchange = index; + firstchange = idx; if ((*old == '\0' && *new == ':') || (*old == ':' && *new == '\0')) firstchange++; @@ -512,9 +524,9 @@ if (*new == '\0') break; if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) - bltin = index; + bltin = idx; if (*new == ':') { - index++; + idx++; } new++, old++; } @@ -607,10 +619,10 @@ STATIC struct tblentry * -cmdlookup(char *name, int add) +cmdlookup(const char *name, int add) { int hashval; - char *p; + const char *p; struct tblentry *cmdp; struct tblentry **pp; @@ -663,7 +675,7 @@ */ void -addcmdentry(char *name, struct cmdentry *entry) +addcmdentry(const char *name, struct cmdentry *entry) { struct tblentry *cmdp; @@ -683,7 +695,7 @@ */ void -defun(char *name, union node *func) +defun(const char *name, union node *func) { struct cmdentry entry; @@ -700,7 +712,7 @@ */ int -unsetfunc(char *name) +unsetfunc(const char *name) { struct tblentry *cmdp; @@ -718,19 +730,21 @@ */ int -typecmd_impl(int argc, char **argv, int cmd) +typecmd_impl(int argc, char **argv, int cmd, const char *path) { struct cmdentry entry; struct tblentry *cmdp; - char **pp; + const char *const *pp; struct alias *ap; int i; - int error = 0; - extern char *const parsekwd[]; + int error1 = 0; + + if (path != pathval()) + clearcmdentry(0); for (i = 1; i < argc; i++) { /* First look at the keywords */ - for (pp = (char **)parsekwd; *pp; pp++) + for (pp = parsekwd; *pp; pp++) if (**pp == *argv[i] && equal(*pp, argv[i])) break; @@ -760,16 +774,17 @@ } else { /* Finally use brute force */ - find_command(argv[i], &entry, 0, pathval()); + find_command(argv[i], &entry, 0, path); } switch (entry.cmdtype) { case CMDNORMAL: { if (strchr(argv[i], '/') == NULL) { - char *path = pathval(), *name; + const char *path2 = path; + char *name; int j = entry.u.index; do { - name = padvance(&path, argv[i]); + name = padvance(&path2, argv[i]); stunalloc(name); } while (--j >= 0); if (cmd == TYPECMD_SMALLV) @@ -790,7 +805,7 @@ if (cmd != TYPECMD_SMALLV) outfmt(out2, "%s: %s\n", argv[i], strerror(errno)); - error |= 127; + error1 |= 127; } } break; @@ -815,11 +830,15 @@ default: if (cmd != TYPECMD_SMALLV) outfmt(out2, "%s: not found\n", argv[i]); - error |= 127; + error1 |= 127; break; } } - return error; + + if (path != pathval()) + clearcmdentry(0); + + return error1; } /* @@ -829,5 +848,5 @@ int typecmd(int argc, char **argv) { - return typecmd_impl(argc, argv, TYPECMD_TYPE); + return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1)); } diff -urN stable/8/bin/sh/exec.h head/bin/sh/exec.h --- stable/8/bin/sh/exec.h 2009-10-11 12:35:12.561852000 -0400 +++ head/bin/sh/exec.h 2010-03-06 11:57:53.405454000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)exec.h 8.3 (Berkeley) 6/8/95 - * $FreeBSD: stable/8/bin/sh/exec.h 197959 2009-10-11 16:35:12Z jilles $ + * $FreeBSD: head/bin/sh/exec.h 204800 2010-03-06 16:57:53Z jilles $ */ /* values of cmdtype */ @@ -57,20 +57,24 @@ }; -extern char *pathopt; /* set by padvance */ +/* action to find_command() */ +#define DO_ERR 0x01 /* prints errors */ +#define DO_NOFUNC 0x02 /* don't return shell functions, for command */ + +extern const char *pathopt; /* set by padvance */ extern int exerrno; /* last exec error */ -void shellexec(char **, char **, char *, int); -char *padvance(char **, char *); +void shellexec(char **, char **, const char *, int) __dead2; +char *padvance(const char **, const char *); int hashcmd(int, char **); -void find_command(char *, struct cmdentry *, int, char *); -int find_builtin(char *, int *); +void find_command(const char *, struct cmdentry *, int, const char *); +int find_builtin(const char *, int *); void hashcd(void); void changepath(const char *); void deletefuncs(void); -void addcmdentry(char *, struct cmdentry *); -void defun(char *, union node *); -int unsetfunc(char *); -int typecmd_impl(int, char **, int); +void addcmdentry(const char *, struct cmdentry *); +void defun(const char *, union node *); +int unsetfunc(const char *); +int typecmd_impl(int, char **, int, const char *); int typecmd(int, char **); void clearcmdentry(int); diff -urN stable/8/bin/sh/expand.c head/bin/sh/expand.c --- stable/8/bin/sh/expand.c 2010-05-16 18:52:51.682053000 -0400 +++ head/bin/sh/expand.c 2010-05-11 19:19:28.413799000 -0400 @@ -38,7 +38,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/expand.c 208174 2010-05-16 22:52:51Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/expand.c 207944 2010-05-11 23:19:28Z jilles $"); #include #include @@ -109,7 +109,7 @@ STATIC void addfname(char *); STATIC struct strlist *expsort(struct strlist *); STATIC struct strlist *msort(struct strlist *, int); -STATIC int pmatch(char *, char *, int); +STATIC int pmatch(const char *, const char *, int); STATIC char *cvtnum(int, char *); STATIC int collate_range_cmp(int, int); @@ -273,8 +273,12 @@ while ((c = *p) != '\0') { switch(c) { - case CTLESC: - return (startp); + case CTLESC: /* This means CTL* are always considered quoted. */ + case CTLVAR: + case CTLBACKQ: + case CTLBACKQ | CTLQUOTE: + case CTLARI: + case CTLENDARI: case CTLQUOTEMARK: return (startp); case ':': @@ -282,6 +286,7 @@ goto done; break; case '/': + case CTLENDVAR: goto done; } p++; @@ -357,7 +362,7 @@ void expari(int flag) { - char *p, *start; + char *p, *q, *start; arith_t result; int begoff; int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); @@ -395,7 +400,9 @@ removerecordregions(begoff); if (quotes) rmescapes(p+2); + q = grabstackstr(expdest); result = arith(p+2); + ungrabstackstr(q, expdest); fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result); while (*p++) ; @@ -503,7 +510,9 @@ int amount; herefd = -1; - argstr(p, 0); + argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || + subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ? + EXP_CASE : 0) | EXP_TILDE); STACKSTRNUL(expdest); herefd = saveherefd; argbackq = saveargbackq; @@ -523,7 +532,7 @@ case VSQUESTION: if (*p != CTLENDVAR) { - outfmt(&errout, "%s\n", startp); + outfmt(out2, "%s\n", startp); error((char *)NULL); } error("%.*s: parameter %snot set", (int)(p - str - 1), @@ -659,7 +668,7 @@ } varlen = 0; startloc = expdest - stackblock(); - if (!set && uflag) { + if (!set && uflag && *var != '@' && *var != '*') { switch (subtype) { case VSNORMAL: case VSTRIMLEFT: @@ -852,7 +861,6 @@ int num; char *p; int i; - extern int oexitstatus; char sep; char **ap; char const *syntax; @@ -976,7 +984,7 @@ char *start; char *p; char *q; - char *ifs; + const char *ifs; const char *ifsspc; int had_param_ch = 0; @@ -1344,7 +1352,7 @@ */ int -patmatch(char *pattern, char *string, int squoted) +patmatch(const char *pattern, const char *string, int squoted) { #ifdef notdef if (pattern[0] == '!' && pattern[1] == '!') @@ -1356,9 +1364,9 @@ STATIC int -pmatch(char *pattern, char *string, int squoted) +pmatch(const char *pattern, const char *string, int squoted) { - char *p, *q; + const char *p, *q; char c; p = pattern; @@ -1406,7 +1414,7 @@ } while (*q++ != '\0'); return 0; case '[': { - char *endp; + const char *endp; int invert, found; char chr; @@ -1510,7 +1518,7 @@ */ int -casematch(union node *pattern, char *val) +casematch(union node *pattern, const char *val) { struct stackmark smark; int result; diff -urN stable/8/bin/sh/expand.h head/bin/sh/expand.h --- stable/8/bin/sh/expand.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/expand.h 2009-12-24 13:41:14.411055000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)expand.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/expand.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/expand.h 200956 2009-12-24 18:41:14Z jilles $ */ struct strlist { @@ -58,7 +58,7 @@ void expandhere(union node *, int); void expandarg(union node *, struct arglist *, int); void expari(int); -int patmatch(char *, char *, int); +int patmatch(const char *, const char *, int); void rmescapes(char *); -int casematch(union node *, char *); +int casematch(union node *, const char *); int wordexpcmd(int, char **); diff -urN stable/8/bin/sh/funcs/cmv head/bin/sh/funcs/cmv --- stable/8/bin/sh/funcs/cmv 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/cmv 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)cmv 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/cmv 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/cmv 139969 2005-01-10 08:39:26Z imp $ # Conditional move--don't replace an existing file. diff -urN stable/8/bin/sh/funcs/dirs head/bin/sh/funcs/dirs --- stable/8/bin/sh/funcs/dirs 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/dirs 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)dirs 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/dirs 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/dirs 139969 2005-01-10 08:39:26Z imp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris diff -urN stable/8/bin/sh/funcs/kill head/bin/sh/funcs/kill --- stable/8/bin/sh/funcs/kill 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/kill 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)kill 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/kill 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/kill 139969 2005-01-10 08:39:26Z imp $ # Convert job names to process ids and then run /bin/kill. diff -urN stable/8/bin/sh/funcs/login head/bin/sh/funcs/login --- stable/8/bin/sh/funcs/login 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/login 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)login 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/login 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/login 139969 2005-01-10 08:39:26Z imp $ # replaces the login builtin in the BSD shell login () exec login "$@" diff -urN stable/8/bin/sh/funcs/newgrp head/bin/sh/funcs/newgrp --- stable/8/bin/sh/funcs/newgrp 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/newgrp 2005-01-10 03:39:26.000000000 -0500 @@ -32,6 +32,6 @@ # SUCH DAMAGE. # # @(#)newgrp 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/newgrp 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/newgrp 139969 2005-01-10 08:39:26Z imp $ newgrp() exec newgrp "$@" diff -urN stable/8/bin/sh/funcs/popd head/bin/sh/funcs/popd --- stable/8/bin/sh/funcs/popd 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/popd 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)popd 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/popd 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/popd 139969 2005-01-10 08:39:26Z imp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris diff -urN stable/8/bin/sh/funcs/pushd head/bin/sh/funcs/pushd --- stable/8/bin/sh/funcs/pushd 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/pushd 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)pushd 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/pushd 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/pushd 139969 2005-01-10 08:39:26Z imp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris diff -urN stable/8/bin/sh/funcs/suspend head/bin/sh/funcs/suspend --- stable/8/bin/sh/funcs/suspend 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/funcs/suspend 2005-01-10 03:39:26.000000000 -0500 @@ -30,7 +30,7 @@ # SUCH DAMAGE. # # @(#)suspend 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/funcs/suspend 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/funcs/suspend 139969 2005-01-10 08:39:26Z imp $ suspend() { local - diff -urN stable/8/bin/sh/histedit.c head/bin/sh/histedit.c --- stable/8/bin/sh/histedit.c 2009-06-23 16:45:12.009544000 -0400 +++ head/bin/sh/histedit.c 2010-06-15 17:58:40.504446000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/histedit.c 194765 2009-06-23 20:45:12Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/histedit.c 209221 2010-06-15 21:58:40Z jilles $"); #include #include @@ -92,12 +92,14 @@ if (hist != NULL) sethistsize(histsizeval()); else - out2str("sh: can't initialize history\n"); + out2fmt_flush("sh: can't initialize history\n"); } if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ /* * turn editing on */ + char *term; + INTOFF; if (el_in == NULL) el_in = fdopen(0, "r"); @@ -107,14 +109,22 @@ el_out = fdopen(2, "w"); if (el_in == NULL || el_err == NULL || el_out == NULL) goto bad; + term = lookupvar("TERM"); + if (term) + setenv("TERM", term, 1); + else + unsetenv("TERM"); el = el_init(arg0, el_in, el_out, el_err); if (el != NULL) { if (hist) el_set(el, EL_HIST, history, hist); el_set(el, EL_PROMPT, getprompt); + el_set(el, EL_ADDFN, "sh-complete", + "Filename completion", + _el_fn_sh_complete); } else { bad: - out2str("sh: can't initialize editing\n"); + out2fmt_flush("sh: can't initialize editing\n"); } INTON; } else if (!editing && el) { @@ -128,6 +138,7 @@ el_set(el, EL_EDITOR, "vi"); else if (Eflag) el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_BIND, "^I", "sh-complete", NULL); el_source(el, NULL); } } else { @@ -160,23 +171,30 @@ } } +void +setterm(const char *term) +{ + if (rootshell && el != NULL && term != NULL) + el_set(el, EL_TERMINAL, term); +} + int histcmd(int argc, char **argv) { int ch; - char *editor = NULL; + const char *editor = NULL; HistEvent he; int lflg = 0, nflg = 0, rflg = 0, sflg = 0; int i, retval; - char *firststr, *laststr; + const char *firststr, *laststr; int first, last, direction; - char *pat = NULL, *repl; + char *pat = NULL, *repl = NULL; static int active = 0; struct jmploc jmploc; struct jmploc *savehandler; char editfilestr[PATH_MAX]; char *volatile editfile; - FILE *efp; + FILE *efp = NULL; int oldhistnum; if (hist == NULL) @@ -336,6 +354,7 @@ if (sflg) { if (displayhist) { out2str(s); + flushout(out2); } evalstring(s, 0); if (displayhist && hist) { @@ -405,7 +424,7 @@ } int -not_fcnumber(char *s) +not_fcnumber(const char *s) { if (s == NULL) return (0); @@ -415,10 +434,10 @@ } int -str_to_event(char *str, int last) +str_to_event(const char *str, int last) { HistEvent he; - char *s = str; + const char *s = str; int relative = 0; int i, retval; diff -urN stable/8/bin/sh/init.h head/bin/sh/init.h --- stable/8/bin/sh/init.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/init.h 2004-04-06 16:06:54.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)init.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/init.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/init.h 127958 2004-04-06 20:06:54Z markm $ */ void init(void); diff -urN stable/8/bin/sh/input.c head/bin/sh/input.c --- stable/8/bin/sh/input.c 2009-06-17 17:58:32.143624000 -0400 +++ head/bin/sh/input.c 2009-12-27 13:04:05.764326000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/input.c 194406 2009-06-17 21:58:32Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/input.c 201053 2009-12-27 18:04:05Z jilles $"); #include /* defines BUFSIZ */ #include @@ -93,7 +93,7 @@ int plinno = 1; /* input line number */ -MKINIT int parsenleft; /* copy of parsefile->nleft */ +int parsenleft; /* copy of parsefile->nleft */ MKINIT int parselleft; /* copy of parsefile->lleft */ char *parsenextc; /* copy of parsefile->nextc */ MKINIT struct parsefile basepf; /* top level input file */ @@ -111,9 +111,9 @@ INCLUDE "input.h" INCLUDE "error.h" -INIT { - extern char basebuf[]; +MKINIT char basebuf[]; +INIT { basepf.nextc = basepf.buf = basebuf; } @@ -215,7 +215,7 @@ if (flags >= 0 && flags & O_NONBLOCK) { flags &=~ O_NONBLOCK; if (fcntl(0, F_SETFL, flags) >= 0) { - out2str("sh: turning off NDELAY mode\n"); + out2fmt_flush("sh: turning off NDELAY mode\n"); goto retry; } } @@ -359,7 +359,7 @@ struct strpush *sp; INTOFF; -/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ +/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/ if (parsefile->strpush) { sp = ckmalloc(sizeof (struct strpush)); sp->prev = parsefile->strpush; @@ -386,7 +386,7 @@ parsenextc = sp->prevstring; parsenleft = sp->prevnleft; parselleft = sp->prevlleft; -/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ +/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/ if (sp->ap) sp->ap->flag &= ~ALIASINUSE; parsefile->strpush = sp->prev; @@ -401,7 +401,7 @@ */ void -setinputfile(char *fname, int push) +setinputfile(const char *fname, int push) { int fd; int fd2; @@ -509,6 +509,32 @@ /* + * Return current file (to go back to it later using popfilesupto()). + */ + +struct parsefile * +getcurrentfile(void) +{ + return parsefile; +} + + +/* + * Pop files until the given file is on top again. Useful for regular + * builtins that read shell commands from files or strings. + * If the given file is not an active file, an error is raised. + */ + +void +popfilesupto(struct parsefile *file) +{ + while (parsefile != file && parsefile != &basepf) + popfile(); + if (parsefile != file) + error("popfilesupto() misused"); +} + +/* * Return to top level. */ diff -urN stable/8/bin/sh/input.h head/bin/sh/input.h --- stable/8/bin/sh/input.h 2009-06-13 17:17:45.691358000 -0400 +++ head/bin/sh/input.h 2009-12-24 13:41:14.411055000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)input.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/input.h 194128 2009-06-13 21:17:45Z jilles $ + * $FreeBSD: head/bin/sh/input.h 200956 2009-12-24 18:41:14Z jilles $ */ /* PEOF (the end of file marker) is defined in syntax.h */ @@ -45,6 +45,8 @@ extern char *parsenextc; /* next character in input buffer */ extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ +struct parsefile; + char *pfgets(char *, int); int pgetc(void); int preadbuffer(void); @@ -52,10 +54,12 @@ void pungetc(void); void pushstring(char *, int, void *); void popstring(void); -void setinputfile(char *, int); +void setinputfile(const char *, int); void setinputfd(int, int); void setinputstring(char *, int); void popfile(void); +struct parsefile *getcurrentfile(void); +void popfilesupto(struct parsefile *); void popallfiles(void); void closescript(void); diff -urN stable/8/bin/sh/jobs.c head/bin/sh/jobs.c --- stable/8/bin/sh/jobs.c 2006-10-07 12:51:16.000000000 -0400 +++ head/bin/sh/jobs.c 2010-06-06 18:27:32.647903000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/jobs.c 163085 2006-10-07 16:51:16Z stefanf $"); +__FBSDID("$FreeBSD: head/bin/sh/jobs.c 208881 2010-06-06 22:27:32Z jilles $"); #include #include @@ -91,8 +91,9 @@ STATIC struct job *getjob(char *); STATIC pid_t dowait(int, struct job *); STATIC pid_t waitproc(int, int *); +STATIC void checkzombies(void); STATIC void cmdtxt(union node *); -STATIC void cmdputs(char *); +STATIC void cmdputs(const char *); #if JOBS STATIC void setcurjob(struct job *); STATIC void deljob(struct job *); @@ -146,7 +147,7 @@ do { /* while we are in the background */ initialpgrp = tcgetpgrp(ttyfd); if (initialpgrp < 0) { -out: out2str("sh: can't access tty; job control turned off\n"); +out: out2fmt_flush("sh: can't access tty; job control turned off\n"); mflag = 0; return; } @@ -400,7 +401,7 @@ struct job *jp; TRACE(("showjobs(%d) called\n", change)); - while (dowait(0, (struct job *)NULL) > 0); + checkzombies(); for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { if (! jp->used) continue; @@ -742,6 +743,8 @@ TRACE(("forkshell(%%%d, %p, %d) called\n", jp - jobtab, (void *)n, mode)); INTOFF; + if (mode == FORK_BG) + checkzombies(); flushall(); pid = fork(); if (pid == -1) { @@ -757,6 +760,7 @@ TRACE(("Child shell %d\n", (int)getpid())); wasroot = rootshell; rootshell = 0; + handler = &main_handler; closescript(); INTON; clear_traps(); @@ -862,6 +866,7 @@ { #if JOBS pid_t mypgrp = getpgrp(); + int propagate_int = jp->jobctl && jp->foreground; #endif int status; int st; @@ -899,6 +904,11 @@ else CLEAR_PENDING_INT; } +#if JOBS + else if (rootshell && iflag && propagate_int && + WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) + kill(getpid(), SIGINT); +#endif INTON; return st; } @@ -1046,7 +1056,7 @@ if (jp->used == 0) continue; if (jp->state == JOBSTOPPED) { - out2str("You have stopped jobs.\n"); + out2fmt_flush("You have stopped jobs.\n"); job_warning = 2; return (1); } @@ -1055,6 +1065,15 @@ return (0); } + +STATIC void +checkzombies(void) +{ + while (njobs > 0 && dowait(0, NULL) > 0) + ; +} + + /* * Return a string identifying a command (to be printed by the * jobs command. @@ -1082,7 +1101,7 @@ { union node *np; struct nodelist *lp; - char *p; + const char *p; int i; char s[2]; @@ -1211,9 +1230,10 @@ STATIC void -cmdputs(char *s) +cmdputs(const char *s) { - char *p, *q; + const char *p; + char *q; char c; int subtype = 0; diff -urN stable/8/bin/sh/jobs.h head/bin/sh/jobs.h --- stable/8/bin/sh/jobs.h 2006-10-07 12:51:16.000000000 -0400 +++ head/bin/sh/jobs.h 2006-10-07 12:51:16.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)jobs.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/jobs.h 163085 2006-10-07 16:51:16Z stefanf $ + * $FreeBSD: head/bin/sh/jobs.h 163085 2006-10-07 16:51:16Z stefanf $ */ /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ diff -urN stable/8/bin/sh/mail.c head/bin/sh/mail.c --- stable/8/bin/sh/mail.c 2005-08-13 04:26:58.000000000 -0400 +++ head/bin/sh/mail.c 2009-12-24 13:41:14.411055000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/mail.c 149017 2005-08-13 08:26:58Z stefanf $"); +__FBSDID("$FreeBSD: head/bin/sh/mail.c 200956 2009-12-24 18:41:14Z jilles $"); /* * Routines to check for mail. (Perhaps make part of main.c?) @@ -72,7 +72,7 @@ chkmail(int silent) { int i; - char *mpath; + const char *mpath; char *p; char *q; struct stackmark smark; diff -urN stable/8/bin/sh/mail.h head/bin/sh/mail.h --- stable/8/bin/sh/mail.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/mail.h 2004-04-06 16:06:54.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)mail.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/mail.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/mail.h 127958 2004-04-06 20:06:54Z markm $ */ void chkmail(int); diff -urN stable/8/bin/sh/main.c head/bin/sh/main.c --- stable/8/bin/sh/main.c 2010-04-20 18:52:28.965483000 -0400 +++ head/bin/sh/main.c 2010-05-28 18:40:24.781829000 -0400 @@ -42,7 +42,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/main.c 206950 2010-04-20 22:52:28Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/main.c 208630 2010-05-28 22:40:24Z jilles $"); #include #include @@ -75,8 +75,9 @@ int rootpid; int rootshell; +struct jmploc main_handler; -STATIC void read_profile(char *); +STATIC void read_profile(const char *); STATIC char *find_dot_file(char *); /* @@ -90,14 +91,13 @@ int main(int argc, char *argv[]) { - struct jmploc jmploc; struct stackmark smark; volatile int state; char *shinit; (void) setlocale(LC_ALL, ""); state = 0; - if (setjmp(jmploc.loc)) { + if (setjmp(main_handler.loc)) { /* * When a shell procedure is executed, we raise the * exception EXSHELLPROC to clean up before executing @@ -143,7 +143,7 @@ else goto state4; } - handler = &jmploc; + handler = &main_handler; #ifdef DEBUG opentrace(); trputs("Shell args: "); trargs(argv); @@ -153,10 +153,7 @@ init(); setstackmark(&smark); procargs(argc, argv); - if (getpwd() == NULL && iflag) - out2str("sh: cannot determine working directory\n"); - if (getpwd() != NULL) - setvar ("PWD", getpwd(), VEXPORT); + pwd_init(iflag); if (iflag) chkmail(1); if (argv[0] && argv[0][0] == '-') { @@ -225,7 +222,7 @@ if (!stoppedjobs()) { if (!Iflag) break; - out2str("\nUse \"exit\" to leave shell.\n"); + out2fmt_flush("\nUse \"exit\" to leave shell.\n"); } numeof++; } else if (n != NULL && nflag == 0) { @@ -250,7 +247,7 @@ */ STATIC void -read_profile(char *name) +read_profile(const char *name) { int fd; @@ -271,7 +268,7 @@ */ void -readcmdfile(char *name) +readcmdfile(const char *name) { int fd; @@ -298,7 +295,7 @@ { static char localname[FILENAME_MAX+1]; char *fullname; - char *path = pathval(); + const char *path = pathval(); struct stat statb; /* don't try this for absolute or relative paths */ @@ -317,14 +314,20 @@ int dotcmd(int argc, char **argv) { - char *fullname; + char *filename, *fullname; if (argc < 2) error("missing filename"); exitstatus = 0; - fullname = find_dot_file(argv[1]); + /* + * Because we have historically not supported any options, + * only treat "--" specially. + */ + filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1]; + + fullname = find_dot_file(filename); setinputfile(fullname, 1); commandname = fullname; cmdloop(0); @@ -336,8 +339,6 @@ int exitcmd(int argc, char **argv) { - extern int oexitstatus; - if (stoppedjobs()) return 0; if (argc > 1) diff -urN stable/8/bin/sh/main.h head/bin/sh/main.h --- stable/8/bin/sh/main.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/main.h 2009-12-25 15:21:35.175590000 -0500 @@ -30,13 +30,14 @@ * SUCH DAMAGE. * * @(#)main.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/main.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/main.h 200998 2009-12-25 20:21:35Z jilles $ */ extern int rootpid; /* pid of main shell */ extern int rootshell; /* true if we aren't a child of the main shell */ +extern struct jmploc main_handler; /* top level exception handler */ -void readcmdfile(char *); +void readcmdfile(const char *); void cmdloop(int); int dotcmd(int, char **); int exitcmd(int, char **); diff -urN stable/8/bin/sh/memalloc.c head/bin/sh/memalloc.c --- stable/8/bin/sh/memalloc.c 2009-06-01 06:50:17.801753000 -0400 +++ head/bin/sh/memalloc.c 2009-12-24 13:41:14.411055000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/memalloc.c 193221 2009-06-01 10:50:17Z rse $"); +__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 200956 2009-12-24 18:41:14Z jilles $"); #include #include "shell.h" @@ -95,7 +95,7 @@ */ char * -savestr(char *s) +savestr(const char *s) { char *p; diff -urN stable/8/bin/sh/memalloc.h head/bin/sh/memalloc.h --- stable/8/bin/sh/memalloc.h 2009-06-01 06:50:17.801753000 -0400 +++ head/bin/sh/memalloc.h 2009-12-24 13:41:14.411055000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/memalloc.h 193221 2009-06-01 10:50:17Z rse $ + * $FreeBSD: head/bin/sh/memalloc.h 200956 2009-12-24 18:41:14Z jilles $ */ #include @@ -51,7 +51,7 @@ pointer ckmalloc(size_t); pointer ckrealloc(pointer, int); void ckfree(pointer); -char *savestr(char *); +char *savestr(const char *); pointer stalloc(int); void stunalloc(pointer); void setstackmark(struct stackmark *); diff -urN stable/8/bin/sh/miscbltin.c head/bin/sh/miscbltin.c --- stable/8/bin/sh/miscbltin.c 2009-06-23 16:57:27.407248000 -0400 +++ head/bin/sh/miscbltin.c 2009-12-27 13:04:05.764326000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/miscbltin.c 194767 2009-06-23 20:57:27Z kib $"); +__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 201053 2009-12-27 18:04:05Z jilles $"); /* * Miscellaneous builtins. @@ -93,7 +93,7 @@ char c; int rflag; char *prompt; - char *ifs; + const char *ifs; char *p; int startword; int status; @@ -254,7 +254,7 @@ int -umaskcmd(int argc __unused, char **argv) +umaskcmd(int argc __unused, char **argv __unused) { char *ap; int mask; diff -urN stable/8/bin/sh/mkbuiltins head/bin/sh/mkbuiltins --- stable/8/bin/sh/mkbuiltins 2006-04-02 14:43:33.000000000 -0400 +++ head/bin/sh/mkbuiltins 2009-12-27 13:04:05.764326000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/mkbuiltins 157413 2006-04-02 18:43:33Z stefanf $ +# $FreeBSD: head/bin/sh/mkbuiltins 201053 2009-12-27 18:04:05Z jilles $ temp=`/usr/bin/mktemp -t ka` havejobs=0 @@ -88,7 +88,7 @@ awk '{ printf "#define %s %d\n", $1, NR-1}' echo ' struct builtincmd { - char *name; + const char *name; int code; int special; }; diff -urN stable/8/bin/sh/mkinit.c head/bin/sh/mkinit.c --- stable/8/bin/sh/mkinit.c 2009-06-01 06:50:17.801753000 -0400 +++ head/bin/sh/mkinit.c 2009-12-27 13:04:05.764326000 -0500 @@ -42,7 +42,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/mkinit.c 193221 2009-06-01 10:50:17Z rse $"); +__FBSDID("$FreeBSD: head/bin/sh/mkinit.c 201053 2009-12-27 18:04:05Z jilles $"); /* * This program scans all the source files for code to handle various @@ -102,9 +102,9 @@ */ struct event { - char *name; /* name of event (e.g. INIT) */ - char *routine; /* name of routine called on event */ - char *comment; /* comment describing routine */ + const char *name; /* name of event (e.g. INIT) */ + const char *routine; /* name of routine called on event */ + const char *comment; /* comment describing routine */ struct text code; /* code for handling event */ }; @@ -140,7 +140,7 @@ }; -char *curfile; /* current file */ +const char *curfile; /* current file */ int linno; /* current line */ char *header_files[200]; /* list of header files */ struct text defines; /* #define statements */ @@ -148,20 +148,20 @@ int amiddecls; /* for formatting */ -void readfile(char *); -int match(char *, char *); -int gooddefine(char *); -void doevent(struct event *, FILE *, char *); +void readfile(const char *); +int match(const char *, const char *); +int gooddefine(const char *); +void doevent(struct event *, FILE *, const char *); void doinclude(char *); void dodecl(char *, FILE *); void output(void); -void addstr(char *, struct text *); +void addstr(const char *, struct text *); void addchar(int, struct text *); void writetext(struct text *, FILE *); -FILE *ckfopen(char *, char *); +FILE *ckfopen(const char *, const char *); void *ckmalloc(size_t); -char *savestr(char *); -void error(char *); +char *savestr(const char *); +void error(const char *); #define equal(s1, s2) (strcmp(s1, s2) == 0) @@ -170,9 +170,9 @@ { char **ap; - header_files[0] = "\"shell.h\""; - header_files[1] = "\"mystring.h\""; - header_files[2] = "\"init.h\""; + header_files[0] = savestr("\"shell.h\""); + header_files[1] = savestr("\"mystring.h\""); + header_files[2] = savestr("\"init.h\""); for (ap = argv + 1 ; *ap ; ap++) readfile(*ap); output(); @@ -186,7 +186,7 @@ */ void -readfile(char *fname) +readfile(const char *fname) { FILE *fp; char line[1024]; @@ -230,9 +230,9 @@ int -match(char *name, char *line) +match(const char *name, const char *line) { - char *p, *q; + const char *p, *q; p = name, q = line; while (*p) { @@ -246,9 +246,9 @@ int -gooddefine(char *line) +gooddefine(const char *line) { - char *p; + const char *p; if (! match("#define", line)) return 0; /* not a define */ @@ -269,11 +269,11 @@ void -doevent(struct event *ep, FILE *fp, char *fname) +doevent(struct event *ep, FILE *fp, const char *fname) { char line[1024]; int indent; - char *p; + const char *p; sprintf(line, "\n /* from %s: */\n", fname); addstr(line, &ep->code); @@ -407,7 +407,7 @@ */ void -addstr(char *s, struct text *text) +addstr(const char *s, struct text *text) { while (*s) { if (--text->nleft < 0) @@ -452,7 +452,7 @@ } FILE * -ckfopen(char *file, char *mode) +ckfopen(const char *file, const char *mode) { FILE *fp; @@ -474,7 +474,7 @@ } char * -savestr(char *s) +savestr(const char *s) { char *p; @@ -484,7 +484,7 @@ } void -error(char *msg) +error(const char *msg) { if (curfile != NULL) fprintf(stderr, "%s:%d: ", curfile, linno); diff -urN stable/8/bin/sh/mknodes.c head/bin/sh/mknodes.c --- stable/8/bin/sh/mknodes.c 2009-10-11 12:35:12.561852000 -0400 +++ head/bin/sh/mknodes.c 2009-08-28 18:41:25.158935000 -0400 @@ -42,7 +42,7 @@ #endif /* not lint */ #endif #include -__FBSDID("$FreeBSD: stable/8/bin/sh/mknodes.c 197959 2009-10-11 16:35:12Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/mknodes.c 196634 2009-08-28 22:41:25Z jilles $"); /* * This program reads the nodetypes file and nodes.c.pat file. It generates diff -urN stable/8/bin/sh/mksyntax.c head/bin/sh/mksyntax.c --- stable/8/bin/sh/mksyntax.c 2009-06-01 07:38:38.880711000 -0400 +++ head/bin/sh/mksyntax.c 2010-04-11 08:24:47.653720000 -0400 @@ -42,7 +42,7 @@ #endif /* not lint */ #endif #include -__FBSDID("$FreeBSD: stable/8/bin/sh/mksyntax.c 193225 2009-06-01 11:38:38Z rse $"); +__FBSDID("$FreeBSD: head/bin/sh/mksyntax.c 206473 2010-04-11 12:24:47Z jilles $"); /* * This program creates syntax.h and syntax.c. @@ -55,8 +55,8 @@ struct synclass { - char *name; - char *comment; + const char *name; + const char *comment; }; /* Syntax classes */ @@ -101,16 +101,16 @@ static FILE *cfile; static FILE *hfile; -static char *syntax[513]; +static const char *syntax[513]; static int base; static int size; /* number of values which a char variable can have */ static int nbits; /* number of bits in a character */ static int digit_contig;/* true if digits are contiguous */ -static void filltable(char *); +static void filltable(const char *); static void init(void); -static void add(char *, char *); -static void print(char *); +static void add(const char *, const char *); +static void print(const char *); static void output_type_macros(void); static void digit_convert(void); @@ -232,7 +232,6 @@ add("\n", "CNL"); add("\\", "CBACK"); add("`", "CBQUOTE"); - add("'", "CSQUOTE"); add("\"", "CDQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); @@ -259,7 +258,7 @@ */ static void -filltable(char *dftval) +filltable(const char *dftval) { int i; @@ -293,7 +292,7 @@ */ static void -add(char *p, char *type) +add(const char *p, const char *type) { while (*p) syntax[*p++ + base] = type; @@ -306,7 +305,7 @@ */ static void -print(char *name) +print(const char *name) { int i; int col; @@ -338,7 +337,7 @@ * contiguous, we can test for them quickly. */ -static char *macro[] = { +static const char *macro[] = { "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)", "#define is_eof(c)\t((c) == PEOF)", "#define is_alpha(c)\t(((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))", @@ -351,7 +350,7 @@ static void output_type_macros(void) { - char **pp; + const char **pp; if (digit_contig) macro[0] = "#define is_digit(c)\t((unsigned int)((c) - '0') <= 9)"; diff -urN stable/8/bin/sh/mktokens head/bin/sh/mktokens --- stable/8/bin/sh/mktokens 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/mktokens 2005-01-10 03:39:26.000000000 -0500 @@ -32,7 +32,7 @@ # SUCH DAMAGE. # # @(#)mktokens 8.1 (Berkeley) 5/31/93 -# $FreeBSD: stable/8/bin/sh/mktokens 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/mktokens 139969 2005-01-10 08:39:26Z imp $ # The following is a list of tokens. The second column is nonzero if the # token marks the end of a list. The third column is the name to print in diff -urN stable/8/bin/sh/myhistedit.h head/bin/sh/myhistedit.h --- stable/8/bin/sh/myhistedit.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/myhistedit.h 2010-06-02 15:16:58.408982000 -0400 @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/myhistedit.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/myhistedit.h 208755 2010-06-02 19:16:58Z jilles $ */ #include @@ -38,8 +38,9 @@ void histedit(void); void sethistsize(const char *); +void setterm(const char *); int histcmd(int, char **); -int not_fcnumber(char *); -int str_to_event(char *, int); +int not_fcnumber(const char *); +int str_to_event(const char *, int); int bindcmd(int, char **); diff -urN stable/8/bin/sh/mystring.c head/bin/sh/mystring.c --- stable/8/bin/sh/mystring.c 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/mystring.c 2009-12-27 13:04:05.764326000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/mystring.c 127958 2004-04-06 20:06:54Z markm $"); +__FBSDID("$FreeBSD: head/bin/sh/mystring.c 201053 2009-12-27 18:04:05Z jilles $"); /* * String functions. @@ -108,7 +108,7 @@ number(const char *s) { if (! is_number(s)) - error("Illegal number: %s", (char *)s); + error("Illegal number: %s", s); return atoi(s); } diff -urN stable/8/bin/sh/mystring.h head/bin/sh/mystring.h --- stable/8/bin/sh/mystring.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/mystring.h 2004-04-06 16:06:54.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)mystring.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/mystring.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/mystring.h 127958 2004-04-06 20:06:54Z markm $ */ #include diff -urN stable/8/bin/sh/nodes.c.pat head/bin/sh/nodes.c.pat --- stable/8/bin/sh/nodes.c.pat 2009-10-11 12:35:12.561852000 -0400 +++ head/bin/sh/nodes.c.pat 2009-08-28 18:41:25.158935000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/nodes.c.pat 197959 2009-10-11 16:35:12Z jilles $ + * $FreeBSD: head/bin/sh/nodes.c.pat 196634 2009-08-28 22:41:25Z jilles $ */ #include diff -urN stable/8/bin/sh/nodetypes head/bin/sh/nodetypes --- stable/8/bin/sh/nodetypes 2005-01-10 03:39:26.000000000 -0500 +++ head/bin/sh/nodetypes 2005-01-10 03:39:26.000000000 -0500 @@ -30,7 +30,7 @@ # SUCH DAMAGE. # # @(#)nodetypes 8.2 (Berkeley) 5/4/95 -# $FreeBSD: stable/8/bin/sh/nodetypes 139969 2005-01-10 08:39:26Z imp $ +# $FreeBSD: head/bin/sh/nodetypes 139969 2005-01-10 08:39:26Z imp $ # This file describes the nodes used in parse trees. Unindented lines # contain a node type followed by a structure tag. Subsequent indented diff -urN stable/8/bin/sh/options.c head/bin/sh/options.c --- stable/8/bin/sh/options.c 2008-08-27 16:16:06.461092000 -0400 +++ head/bin/sh/options.c 2010-04-05 10:15:51.345103000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/options.c 182300 2008-08-27 20:16:06Z stefanf $"); +__FBSDID("$FreeBSD: head/bin/sh/options.c 206182 2010-04-05 14:15:51Z jilles $"); #include #include @@ -64,7 +64,7 @@ struct shparam shellparam; /* current positional parameters */ char **argptr; /* argument list for builtin commands */ char *shoptarg; /* set by nextopt (like getopt) */ -char *optptr; /* used by nextopt */ +char *nextopt_optptr; /* used by nextopt */ char *minusc; /* argument to -c option */ @@ -93,8 +93,11 @@ options(1); if (*argptr == NULL && minusc == NULL) sflag = 1; - if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) + if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) { iflag = 1; + if (Eflag == 2) + Eflag = 1; + } if (mflag == 2) mflag = iflag; for (i = 0; i < NOPTS; i++) @@ -554,12 +557,13 @@ */ int -nextopt(char *optstring) +nextopt(const char *optstring) { - char *p, *q; + char *p; + const char *q; char c; - if ((p = optptr) == NULL || *p == '\0') { + if ((p = nextopt_optptr) == NULL || *p == '\0') { p = *argptr; if (p == NULL || *p != '-' || *++p == '\0') return '\0'; @@ -580,6 +584,6 @@ shoptarg = p; p = NULL; } - optptr = p; + nextopt_optptr = p; return c; } diff -urN stable/8/bin/sh/options.h head/bin/sh/options.h --- stable/8/bin/sh/options.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/options.h 2009-12-27 13:04:05.764326000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)options.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/options.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/options.h 201053 2009-12-27 18:04:05Z jilles $ */ struct shparam { @@ -102,7 +102,7 @@ extern struct shparam shellparam; /* $@ */ extern char **argptr; /* argument list for builtin commands */ extern char *shoptarg; /* set by nextopt */ -extern char *optptr; /* used by nextopt */ +extern char *nextopt_optptr; /* used by nextopt */ void procargs(int, char **); void optschanged(void); @@ -111,5 +111,5 @@ int shiftcmd(int, char **); int setcmd(int, char **); int getoptscmd(int, char **); -int nextopt(char *); +int nextopt(const char *); void getoptsreset(const char *); diff -urN stable/8/bin/sh/output.c head/bin/sh/output.c --- stable/8/bin/sh/output.c 2009-06-19 18:09:55.177892000 -0400 +++ head/bin/sh/output.c 2009-12-24 13:41:14.411055000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/output.c 194516 2009-06-19 22:09:55Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/output.c 200956 2009-12-24 18:41:14Z jilles $"); /* * Shell output routines. We use our own output routines because: @@ -71,7 +71,7 @@ static int doformat_wr(void *, const char *, int); struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; -struct output errout = {NULL, 0, NULL, 100, 2, 0}; +struct output errout = {NULL, 0, NULL, 256, 2, 0}; struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; struct output *out1 = &output; struct output *out2 = &errout; @@ -124,8 +124,6 @@ { while (*p) outc(*p++, file); - if (file == out2) - flushout(file); } /* Like outstr(), but quote for re-input into the shell. */ @@ -255,7 +253,7 @@ } void -dprintf(const char *fmt, ...) +out2fmt_flush(const char *fmt, ...) { va_list ap; @@ -316,7 +314,7 @@ */ int -xwrite(int fd, char *buf, int nbytes) +xwrite(int fd, const char *buf, int nbytes) { int ntry; int i; diff -urN stable/8/bin/sh/output.h head/bin/sh/output.h --- stable/8/bin/sh/output.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/output.h 2010-01-01 13:17:46.488302000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)output.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/output.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/output.h 201366 2010-01-01 18:17:46Z jilles $ */ #ifndef OUTPUT_INCL @@ -46,13 +46,13 @@ short flags; }; -extern struct output output; -extern struct output errout; +extern struct output output; /* to fd 1 */ +extern struct output errout; /* to fd 2 */ extern struct output memout; -extern struct output *out1; -extern struct output *out2; +extern struct output *out1; /* &memout if backquote, otherwise &output */ +extern struct output *out2; /* &memout if backquote with 2>&1, otherwise + &errout */ -void open_mem(char *, int, struct output *); void out1str(const char *); void out1qstr(const char *); void out2str(const char *); @@ -65,10 +65,10 @@ void freestdout(void); void outfmt(struct output *, const char *, ...) __printflike(2, 3); void out1fmt(const char *, ...) __printflike(1, 2); -void dprintf(const char *, ...) __printflike(1, 2); +void out2fmt_flush(const char *, ...) __printflike(1, 2); void fmtstr(char *, int, const char *, ...) __printflike(3, 4); void doformat(struct output *, const char *, va_list) __printflike(2, 0); -int xwrite(int, char *, int); +int xwrite(int, const char *, int); #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) #define out1c(c) outc(c, out1); diff -urN stable/8/bin/sh/parser.c head/bin/sh/parser.c --- stable/8/bin/sh/parser.c 2010-04-20 18:20:31.838359000 -0400 +++ head/bin/sh/parser.c 2010-06-19 06:33:04.993394000 -0400 @@ -36,10 +36,11 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/parser.c 206942 2010-04-20 22:20:31Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/parser.c 209337 2010-06-19 10:33:04Z jilles $"); #include #include +#include #include "shell.h" #include "parser.h" @@ -79,10 +80,13 @@ int striptabs; /* if set, strip leading tabs */ }; +struct parser_temp { + struct parser_temp *next; + void *data; +}; STATIC struct heredoc *heredoclist; /* list of here documents to read */ -STATIC int parsebackquote; /* nonzero if we are inside backquotes */ STATIC int doprompt; /* if set, prompt the user */ STATIC int needprompt; /* true if interactive and at start of line */ STATIC int lasttoken; /* last token read */ @@ -95,6 +99,7 @@ STATIC int quoteflag; /* set if (part of) last token was quoted */ STATIC int startlinno; /* line # where last token started */ STATIC int funclinno; /* line # where the current function started */ +STATIC struct parser_temp *parser_temp; /* XXX When 'noaliases' is set to one, no alias expansion takes place. */ static int noaliases = 0; @@ -114,10 +119,77 @@ STATIC int readtoken1(int, char const *, char *, int); STATIC int noexpand(char *); STATIC void synexpect(int); -STATIC void synerror(char *); +STATIC void synerror(const char *); STATIC void setprompt(int); +STATIC void * +parser_temp_alloc(size_t len) +{ + struct parser_temp *t; + + INTOFF; + t = ckmalloc(sizeof(*t)); + t->data = NULL; + t->next = parser_temp; + parser_temp = t; + t->data = ckmalloc(len); + INTON; + return t->data; +} + + +STATIC void * +parser_temp_realloc(void *ptr, size_t len) +{ + struct parser_temp *t; + + INTOFF; + t = parser_temp; + if (ptr != t->data) + error("bug: parser_temp_realloc misused"); + t->data = ckrealloc(t->data, len); + INTON; + return t->data; +} + + +STATIC void +parser_temp_free_upto(void *ptr) +{ + struct parser_temp *t; + int done = 0; + + INTOFF; + while (parser_temp != NULL && !done) { + t = parser_temp; + parser_temp = t->next; + done = t->data == ptr; + ckfree(t->data); + ckfree(t); + } + INTON; + if (!done) + error("bug: parser_temp_free_upto misused"); +} + + +STATIC void +parser_temp_free_all(void) +{ + struct parser_temp *t; + + INTOFF; + while (parser_temp != NULL) { + t = parser_temp; + parser_temp = t->next; + ckfree(t->data); + ckfree(t); + } + INTON; +} + + /* * Read and parse a command. Returns NEOF on end of file. (NULL is a * valid parse tree indicating a blank line.) @@ -128,6 +200,12 @@ { int t; + /* This assumes the parser is not re-entered, + * which could happen if we add command substitution on PS1/PS2. + */ + parser_temp_free_all(); + heredoclist = NULL; + tokpushback = 0; doprompt = interact; if (doprompt) @@ -864,6 +942,188 @@ } +#define MAXNEST_STATIC 8 +struct tokenstate +{ + const char *syntax; /* *SYNTAX */ + int parenlevel; /* levels of parentheses in arithmetic */ + enum tokenstate_category + { + TSTATE_TOP, + TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */ + TSTATE_VAR_NEW, /* other ${var...}, own dquote state */ + TSTATE_ARITH + } category; +}; + + +/* + * Called to parse command substitutions. + */ + +STATIC char * +parsebackq(char *out, struct nodelist **pbqlist, + int oldstyle, int dblquote, int quoted) +{ + struct nodelist **nlpp; + union node *n; + char *volatile str; + struct jmploc jmploc; + struct jmploc *const savehandler = handler; + int savelen; + int saveprompt; + const int bq_startlinno = plinno; + char *volatile ostr = NULL; + struct parsefile *const savetopfile = getcurrentfile(); + struct heredoc *const saveheredoclist = heredoclist; + struct heredoc *here; + + str = NULL; + if (setjmp(jmploc.loc)) { + popfilesupto(savetopfile); + if (str) + ckfree(str); + if (ostr) + ckfree(ostr); + heredoclist = saveheredoclist; + handler = savehandler; + if (exception == EXERROR) { + startlinno = bq_startlinno; + synerror("Error in command substitution"); + } + longjmp(handler->loc, 1); + } + INTOFF; + savelen = out - stackblock(); + if (savelen > 0) { + str = ckmalloc(savelen); + memcpy(str, stackblock(), savelen); + } + handler = &jmploc; + heredoclist = NULL; + INTON; + if (oldstyle) { + /* We must read until the closing backquote, giving special + treatment to some slashes, and then push the string and + reread it as input, interpreting it normally. */ + char *oout; + int c; + int olen; + + + STARTSTACKSTR(oout); + for (;;) { + if (needprompt) { + setprompt(2); + needprompt = 0; + } + switch (c = pgetc()) { + case '`': + goto done; + + case '\\': + if ((c = pgetc()) == '\n') { + plinno++; + if (doprompt) + setprompt(2); + else + setprompt(0); + /* + * If eating a newline, avoid putting + * the newline into the new character + * stream (via the STPUTC after the + * switch). + */ + continue; + } + if (c != '\\' && c != '`' && c != '$' + && (!dblquote || c != '"')) + STPUTC('\\', oout); + break; + + case '\n': + plinno++; + needprompt = doprompt; + break; + + case PEOF: + startlinno = plinno; + synerror("EOF in backquote substitution"); + break; + + default: + break; + } + STPUTC(c, oout); + } +done: + STPUTC('\0', oout); + olen = oout - stackblock(); + INTOFF; + ostr = ckmalloc(olen); + memcpy(ostr, stackblock(), olen); + setinputstring(ostr, 1); + INTON; + } + nlpp = pbqlist; + while (*nlpp) + nlpp = &(*nlpp)->next; + *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + (*nlpp)->next = NULL; + + if (oldstyle) { + saveprompt = doprompt; + doprompt = 0; + } + + n = list(0); + + if (oldstyle) + doprompt = saveprompt; + else { + if (readtoken() != TRP) + synexpect(TRP); + } + + (*nlpp)->n = n; + if (oldstyle) { + /* + * Start reading from old file again, ignoring any pushed back + * tokens left from the backquote parsing + */ + popfile(); + tokpushback = 0; + } + while (stackblocksize() <= savelen) + growstackblock(); + STARTSTACKSTR(out); + INTOFF; + if (str) { + memcpy(out, str, savelen); + STADJUST(savelen, out); + ckfree(str); + str = NULL; + } + if (ostr) { + ckfree(ostr); + ostr = NULL; + } + here = saveheredoclist; + if (here != NULL) { + while (here->next != NULL) + here = here->next; + here->next = heredoclist; + heredoclist = saveheredoclist; + } + handler = savehandler; + INTON; + if (quoted) + USTPUTC(CTLBACKQ | CTLQUOTE, out); + else + USTPUTC(CTLBACKQ, out); + return out; +} + /* * If eofmark is NULL, read a word or a redirection symbol. If eofmark @@ -880,12 +1140,10 @@ #define CHECKEND() {goto checkend; checkend_return:;} #define PARSEREDIR() {goto parseredir; parseredir_return:;} #define PARSESUB() {goto parsesub; parsesub_return:;} -#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} -#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} #define PARSEARITH() {goto parsearith; parsearith_return:;} STATIC int -readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) +readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs) { int c = firstc; char *out; @@ -893,23 +1151,21 @@ char line[EOFMARKLEN + 1]; struct nodelist *bqlist; int quotef; - int dblquote; - int varnest; /* levels of variables expansion */ - int arinest; /* levels of arithmetic expansion */ - int parenlevel; /* levels of parens in arithmetic */ - int oldstyle; - char const *prevsyntax; /* syntax before arithmetic */ + int newvarnest; + int level; int synentry; + struct tokenstate state_static[MAXNEST_STATIC]; + int maxnest = MAXNEST_STATIC; + struct tokenstate *state = state_static; startlinno = plinno; - dblquote = 0; - if (syntax == DQSYNTAX) - dblquote = 1; quotef = 0; bqlist = NULL; - varnest = 0; - arinest = 0; - parenlevel = 0; + newvarnest = 0; + level = 0; + state[level].syntax = initialsyntax; + state[level].parenlevel = 0; + state[level].category = TSTATE_TOP; STARTSTACKSTR(out); loop: { /* for each line, until end of word */ @@ -917,11 +1173,11 @@ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ - synentry = syntax[c]; + synentry = state[level].syntax[c]; switch(synentry) { case CNL: /* '\n' */ - if (syntax == BASESYNTAX) + if (state[level].syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(c, out); plinno++; @@ -935,7 +1191,7 @@ USTPUTC(c, out); break; case CCTL: - if (eofmark == NULL || dblquote) + if (eofmark == NULL || initialsyntax != SQSYNTAX) USTPUTC(CTLESC, out); USTPUTC(c, out); break; @@ -951,41 +1207,37 @@ else setprompt(0); } else { - if (dblquote && c != '\\' && - c != '`' && c != '$' && - (c != '"' || eofmark != NULL)) + if (state[level].syntax == DQSYNTAX && + c != '\\' && c != '`' && c != '$' && + (c != '"' || (eofmark != NULL && + newvarnest == 0)) && + (c != '}' || state[level].category != TSTATE_VAR_OLD)) USTPUTC('\\', out); if (SQSYNTAX[c] == CCTL) USTPUTC(CTLESC, out); - else if (eofmark == NULL) + else if (eofmark == NULL || + newvarnest > 0) USTPUTC(CTLQUOTEMARK, out); USTPUTC(c, out); quotef++; } break; case CSQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = SQSYNTAX; + USTPUTC(CTLQUOTEMARK, out); + state[level].syntax = SQSYNTAX; break; case CDQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = DQSYNTAX; - dblquote = 1; + USTPUTC(CTLQUOTEMARK, out); + state[level].syntax = DQSYNTAX; break; case CENDQUOTE: - if (eofmark != NULL && arinest == 0 && - varnest == 0) { + if (eofmark != NULL && newvarnest == 0) USTPUTC(c, out); - } else { - if (arinest) { - syntax = ARISYNTAX; - dblquote = 0; - } else if (eofmark == NULL) { - syntax = BASESYNTAX; - dblquote = 0; - } + else { + if (state[level].category == TSTATE_ARITH) + state[level].syntax = ARISYNTAX; + else + state[level].syntax = BASESYNTAX; quotef++; } break; @@ -993,30 +1245,33 @@ PARSESUB(); /* parse substitution */ break; case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; + if (level > 0 && + (state[level].category == TSTATE_VAR_OLD || + state[level].category == TSTATE_VAR_NEW)) { + if (state[level].category == TSTATE_VAR_OLD) + state[level - 1].syntax = state[level].syntax; + else + newvarnest--; + level--; USTPUTC(CTLENDVAR, out); } else { USTPUTC(c, out); } break; case CLP: /* '(' in arithmetic */ - parenlevel++; + state[level].parenlevel++; USTPUTC(c, out); break; case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { + if (state[level].parenlevel > 0) { USTPUTC(c, out); - --parenlevel; + --state[level].parenlevel; } else { if (pgetc() == ')') { - if (--arinest == 0) { + if (level > 0 && + state[level].category == TSTATE_ARITH) { + level--; USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - if (syntax == DQSYNTAX) - dblquote = 1; - else - dblquote = 0; } else USTPUTC(')', out); } else { @@ -1030,12 +1285,15 @@ } break; case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); + out = parsebackq(out, &bqlist, 1, + state[level].syntax == DQSYNTAX && + (eofmark == NULL || newvarnest > 0), + state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX); break; case CEOF: goto endword; /* exit outer loop */ default: - if (varnest == 0) + if (level == 0) goto endword; /* exit outer loop */ USTPUTC(c, out); } @@ -1043,14 +1301,17 @@ } } endword: - if (syntax == ARISYNTAX) + if (state[level].syntax == ARISYNTAX) synerror("Missing '))'"); - if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) + if (state[level].syntax != BASESYNTAX && eofmark == NULL) synerror("Unterminated quoted string"); - if (varnest != 0) { + if (state[level].category == TSTATE_VAR_OLD || + state[level].category == TSTATE_VAR_NEW) { startlinno = plinno; synerror("Missing '}'"); } + if (state != state_static) + parser_temp_free_upto(state); USTPUTC('\0', out); len = out - stackblock(); out = stackblock(); @@ -1073,7 +1334,6 @@ /* end of readtoken routine */ - /* * Check to see whether we are at the end of the here document. When this * is called, c is set to the first character of the next input line. If @@ -1190,7 +1450,11 @@ PARSEARITH(); } else { pungetc(); - PARSEBACKQNEW(); + out = parsebackq(out, &bqlist, 0, + state[level].syntax == DQSYNTAX && + (eofmark == NULL || newvarnest > 0), + state[level].syntax == DQSYNTAX || + state[level].syntax == ARISYNTAX); } } else { USTPUTC(CTLVAR, out); @@ -1245,6 +1509,8 @@ subtype = VSERROR; if (c == '}') pungetc(); + else if (c == '\n' || c == PEOF) + synerror("Unexpected end of line in substitution"); else USTPUTC(c, out); } else { @@ -1261,6 +1527,8 @@ default: p = strchr(types, c); if (p == NULL) { + if (c == '\n' || c == PEOF) + synerror("Unexpected end of line in substitution"); if (flags == VSNUL) STPUTC(':', out); STPUTC(c, out); @@ -1286,192 +1554,74 @@ pungetc(); } STPUTC('=', out); - if (subtype != VSLENGTH && (dblquote || arinest)) + if (subtype != VSLENGTH && (state[level].syntax == DQSYNTAX || + state[level].syntax == ARISYNTAX)) flags |= VSQUOTE; *(stackblock() + typeloc) = subtype | flags; - if (subtype != VSNORMAL) - varnest++; - } - goto parsesub_return; -} - - -/* - * Called to parse command substitutions. Newstyle is set if the command - * is enclosed inside $(...); nlpp is a pointer to the head of the linked - * list of commands (passed by reference), and savelen is the number of - * characters on the top of the stack which must be preserved. - */ - -parsebackq: { - struct nodelist **nlpp; - int savepbq; - union node *n; - char *volatile str; - struct jmploc jmploc; - struct jmploc *const savehandler = handler; - int savelen; - int saveprompt; - const int bq_startlinno = plinno; - - savepbq = parsebackquote; - if (setjmp(jmploc.loc)) { - if (str) - ckfree(str); - parsebackquote = 0; - handler = savehandler; - if (exception == EXERROR) { - startlinno = bq_startlinno; - synerror("Error in command substitution"); - } - longjmp(handler->loc, 1); - } - INTOFF; - str = NULL; - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); - } - handler = &jmploc; - INTON; - if (oldstyle) { - /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ - char *out; - int c; - int savelen; - char *str; - - - STARTSTACKSTR(out); - for (;;) { - if (needprompt) { - setprompt(2); - needprompt = 0; + if (subtype != VSNORMAL) { + if (level + 1 >= maxnest) { + maxnest *= 2; + if (state == state_static) { + state = parser_temp_alloc( + maxnest * sizeof(*state)); + memcpy(state, state_static, + MAXNEST_STATIC * sizeof(*state)); + } else + state = parser_temp_realloc(state, + maxnest * sizeof(*state)); } - switch (c = pgetc()) { - case '`': - goto done; - - case '\\': - if ((c = pgetc()) == '\n') { - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } - if (c != '\\' && c != '`' && c != '$' - && (!dblquote || c != '"')) - STPUTC('\\', out); - break; - - case '\n': - plinno++; - needprompt = doprompt; - break; - - case PEOF: - startlinno = plinno; - synerror("EOF in backquote substitution"); - break; - - default: - break; + level++; + state[level].parenlevel = 0; + if (subtype == VSMINUS || subtype == VSPLUS || + subtype == VSQUESTION || subtype == VSASSIGN) { + /* + * For operators that were in the Bourne shell, + * inherit the double-quote state. + */ + state[level].syntax = state[level - 1].syntax; + state[level].category = TSTATE_VAR_OLD; + } else { + /* + * The other operators take a pattern, + * so go to BASESYNTAX. + * Also, ' and " are now special, even + * in here documents. + */ + state[level].syntax = BASESYNTAX; + state[level].category = TSTATE_VAR_NEW; + newvarnest++; } - STPUTC(c, out); - } -done: - STPUTC('\0', out); - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); - setinputstring(str, 1); - } - } - nlpp = &bqlist; - while (*nlpp) - nlpp = &(*nlpp)->next; - *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - (*nlpp)->next = NULL; - parsebackquote = oldstyle; - - if (oldstyle) { - saveprompt = doprompt; - doprompt = 0; - } - - n = list(0); - - if (oldstyle) - doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } - - (*nlpp)->n = n; - if (oldstyle) { - /* - * Start reading from old file again, ignoring any pushed back - * tokens left from the backquote parsing - */ - popfile(); - tokpushback = 0; - } - while (stackblocksize() <= savelen) - growstackblock(); - STARTSTACKSTR(out); - if (str) { - memcpy(out, str, savelen); - STADJUST(savelen, out); - INTOFF; - ckfree(str); - str = NULL; - INTON; + } } - parsebackquote = savepbq; - handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); - if (oldstyle) - goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; + goto parsesub_return; } + /* * Parse an arithmetic expansion (indicate start of one and set state) */ parsearith: { - if (++arinest == 1) { - prevsyntax = syntax; - syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"',out); - else - USTPUTC(' ',out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); + if (level + 1 >= maxnest) { + maxnest *= 2; + if (state == state_static) { + state = parser_temp_alloc( + maxnest * sizeof(*state)); + memcpy(state, state_static, + MAXNEST_STATIC * sizeof(*state)); + } else + state = parser_temp_realloc(state, + maxnest * sizeof(*state)); } + level++; + state[level].syntax = ARISYNTAX; + state[level].parenlevel = 0; + state[level].category = TSTATE_ARITH; + USTPUTC(CTLARI, out); + if (state[level - 1].syntax == DQSYNTAX) + USTPUTC('"',out); + else + USTPUTC(' ',out); goto parsearith_return; } @@ -1516,9 +1666,9 @@ */ int -goodname(char *name) +goodname(const char *name) { - char *p; + const char *p; p = name; if (! is_name(*p)) @@ -1553,11 +1703,11 @@ STATIC void -synerror(char *msg) +synerror(const char *msg) { if (commandname) - outfmt(&errout, "%s: %d: ", commandname, startlinno); - outfmt(&errout, "Syntax error: %s\n", msg); + outfmt(out2, "%s: %d: ", commandname, startlinno); + outfmt(out2, "Syntax error: %s\n", msg); error((char *)NULL); } @@ -1569,7 +1719,10 @@ #ifndef NO_HISTORY if (!el) #endif + { out2str(getprompt(NULL)); + flushout(out2); + } } /* @@ -1582,13 +1735,14 @@ static char ps[PROMPTLEN]; char *fmt; int i, j, trim; + static char internal_error[] = ""; /* * Select prompt format. */ switch (whichprompt) { case 0: - fmt = ""; + fmt = nullstr; break; case 1: fmt = ps1val(); @@ -1597,7 +1751,7 @@ fmt = ps2val(); break; default: - return ""; + return internal_error; } /* diff -urN stable/8/bin/sh/parser.h head/bin/sh/parser.h --- stable/8/bin/sh/parser.h 2008-05-15 15:55:27.000000000 -0400 +++ head/bin/sh/parser.h 2009-12-27 13:04:05.764326000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)parser.h 8.3 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/parser.h 179022 2008-05-15 19:55:27Z stefanf $ + * $FreeBSD: head/bin/sh/parser.h 201053 2009-12-27 18:04:05Z jilles $ */ /* control characters in argument strings */ @@ -73,9 +73,10 @@ extern int tokpushback; #define NEOF ((union node *)&tokpushback) extern int whichprompt; /* 1 == PS1, 2 == PS2 */ +extern const char *const parsekwd[]; union node *parsecmd(int); void fixredir(union node *, const char *, int); -int goodname(char *); +int goodname(const char *); char *getprompt(void *); diff -urN stable/8/bin/sh/redir.c head/bin/sh/redir.c --- stable/8/bin/sh/redir.c 2009-06-20 16:44:27.958917000 -0400 +++ head/bin/sh/redir.c 2009-11-29 17:33:59.045137000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/redir.c 194560 2009-06-20 20:44:27Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/redir.c 199953 2009-11-29 22:33:59Z jilles $"); #include #include @@ -63,6 +63,7 @@ #define EMPTY -2 /* marks an unused slot in redirtab */ +#define CLOSED -1 /* fd was not open before redir */ #define PIPESIZE 4096 /* amount of buffering in a pipe */ @@ -101,7 +102,6 @@ struct redirtab *sv = NULL; int i; int fd; - int try; char memory[10]; /* file descriptors to write to memory */ for (i = 10 ; --i >= 0 ; ) @@ -116,38 +116,30 @@ } for (n = redir ; n ; n = n->nfile.next) { fd = n->nfile.fd; - try = 0; if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && n->ndup.dupfd == fd) continue; /* redirect from/to same file descriptor */ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { INTOFF; -again: if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { switch (errno) { case EBADF: - if (!try) { - openredirect(n, memory); - try++; - goto again; - } - /* FALLTHROUGH*/ + i = CLOSED; + break; default: INTON; error("%d: %s", fd, strerror(errno)); break; } - } - if (!try) { - sv->renamed[fd] = i; - } + } else + (void)fcntl(i, F_SETFD, FD_CLOEXEC); + sv->renamed[fd] = i; INTON; } if (fd == 0) fd0_redirected++; - if (!try) - openredirect(n, memory); + openredirect(n, memory); } if (memory[1]) out1 = &memout; @@ -166,8 +158,11 @@ /* * We suppress interrupts so that we won't leave open file - * descriptors around. This may not be such a good idea because - * an open of a device or a fifo can block indefinitely. + * descriptors around. Because the signal handler remains + * installed and we do not use system call restart, interrupts + * will still abort blocking opens such as fifos (they will fail + * with EINTR). There is, however, a race condition if an interrupt + * arrives after INTOFF and before open blocks. */ INTOFF; memory[fd] = 0; diff -urN stable/8/bin/sh/redir.h head/bin/sh/redir.h --- stable/8/bin/sh/redir.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/redir.h 2004-04-06 16:06:54.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)redir.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/redir.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/redir.h 127958 2004-04-06 20:06:54Z markm $ */ /* flags passed to redirect */ diff -urN stable/8/bin/sh/sh.1 head/bin/sh/sh.1 --- stable/8/bin/sh/sh.1 2010-04-23 15:26:03.997203000 -0400 +++ head/bin/sh/sh.1 2010-05-24 11:12:12.326105000 -0400 @@ -30,9 +30,9 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95 -.\" $FreeBSD: stable/8/bin/sh/sh.1 207132 2010-04-23 19:26:03Z jilles $ +.\" $FreeBSD: head/bin/sh/sh.1 208505 2010-05-24 15:12:12Z jilles $ .\" -.Dd January 8, 2010 +.Dd May 24, 2010 .Dt SH 1 .Os .Sh NAME @@ -210,7 +210,8 @@ .Xr emacs 1 command line editor (disables the .Fl V -option if it has been set). +option if it has been set; +set automatically when interactive on terminals). .It Fl e Li errexit Exit immediately if any untested command fails in non-interactive mode. The exit status of a command is considered to be @@ -296,7 +297,10 @@ .Ed .It Fl u Li nounset Write a message to standard error when attempting -to expand a variable that is not set, and if the +to expand a variable, a positional parameter or +the special parameter +.Va \&! +that is not set, and if the shell is not interactive, exit immediately. .It Fl V Li vi Enable the built-in @@ -411,11 +415,11 @@ .Pq Ql \en . A backslash preceding a newline is treated as a line continuation. .El -.Ss Reserved Words -Reserved words are words that have special meaning to the +.Ss Keywords +Keywords or reserved words are words that have special meaning to the shell and are recognized at the beginning of a line and after a control operator. -The following are reserved words: +The following are keywords: .Bl -column "doneXX" "elifXX" "elseXX" "untilXX" "whileX" -offset center .It Li \&! Ta { Ta } Ta Ic case Ta Ic do .It Ic done Ta Ic elif Ta Ic else Ta Ic esac Ta Ic fi @@ -425,8 +429,8 @@ An alias is a name and corresponding value set using the .Ic alias built-in command. -Whenever a reserved word may occur (see above), -and after checking for reserved words, the shell +Whenever a keyword may occur (see above), +and after checking for keywords, the shell checks the word to see if it matches an alias. If it does, it replaces it in the input stream with its value. For example, if there is an alias called @@ -465,7 +469,7 @@ document). Essentially though, a line is read and if the first word of the line (or after a control operator) -is not a reserved word, then the shell has recognized a +is not a keyword, then the shell has recognized a simple command. Otherwise, a complex command or some other special construct may have been recognized. @@ -661,11 +665,11 @@ performing any searches. .It The shell searches each entry in the -.Ev PATH -environment variable +.Va PATH +variable in turn for the command. The value of the -.Ev PATH +.Va PATH variable should be a series of entries separated by colons. Each entry consists of a @@ -691,7 +695,7 @@ .In sys/signal.h . .Ss Complex Commands Complex commands are combinations of simple commands -with control operators or reserved words, together creating a larger complex +with control operators or keywords, together creating a larger complex command. More generally, a command is one of the following: .Bl -item -offset indent @@ -735,7 +739,7 @@ If the pipeline is not in the background (discussed later), the shell waits for all commands to complete. .Pp -If the reserved word +If the keyword .Ic !\& does not precede the pipeline, the exit status is the exit status of the last command specified @@ -1036,13 +1040,9 @@ .Ic set built-in command can also be used to set or reset them. .Ss Special Parameters -A special parameter is a parameter denoted by a special one-character -name. -The special parameters recognized by the -.Nm -shell of -.Fx -are shown in the following list, exactly as they would appear in input +Special parameters are parameters denoted by a single special character +or the digit zero. +They are shown in the following list, exactly as they would appear in input typed by the user or in the source of a shell script. .Bl -hang .It Li $* @@ -1109,6 +1109,84 @@ .It Li $0 (zero) Expands to the name of the shell or shell script. .El +.Ss Special Variables +The following variables are set by the shell or +have special meaning to it: +.Bl -tag -width ".Va HISTSIZE" +.It Va CDPATH +The search path used with the +.Ic cd +built-in. +.It Va EDITOR +The fallback editor used with the +.Ic fc +built-in. +If not set, the default editor is +.Xr ed 1 . +.It Va FCEDIT +The default editor used with the +.Ic fc +built-in. +.It Va HISTSIZE +The number of previous commands that are accessible. +.It Va HOME +The user's home directory, +used in tilde expansion and as a default directory for the +.Ic cd +built-in. +.It Va IFS +Input Field Separators. +This is normally set to +.Aq space , +.Aq tab , +and +.Aq newline . +See the +.Sx White Space Splitting +section for more details. +.It Va LINENO +The current line number in the script or function. +.It Va MAIL +The name of a mail file, that will be checked for the arrival of new +mail. +Overridden by +.Va MAILPATH . +.It Va MAILPATH +A colon +.Pq Ql \&: +separated list of file names, for the shell to check for incoming +mail. +This variable overrides the +.Va MAIL +setting. +There is a maximum of 10 mailboxes that can be monitored at once. +.It Va PATH +The default search path for executables. +See the +.Sx Path Search +section for details. +.It Va PPID +The parent process ID of the invoked shell. +This is set at startup +unless this variable is in the environment. +A later change of parent process ID is not reflected. +A subshell retains the same value of +.Va PPID . +.It Va PS1 +The primary prompt string, which defaults to +.Dq Li "$ " , +unless you are the superuser, in which case it defaults to +.Dq Li "# " . +.It Va PS2 +The secondary prompt string, which defaults to +.Dq Li "> " . +.It Va PS4 +The prefix for the trace output (if +.Fl x +is active). +The default is +.Dq Li "+ " . +.El .Ss Word Expansions This clause describes the various expansions that are performed on words. @@ -1162,7 +1240,7 @@ username is missing (as in .Pa ~/foobar ) , the tilde is replaced with the value of the -.Ev HOME +.Va HOME variable (the current user's home directory). .Ss Parameter Expansion The format for parameter expansion is as follows: @@ -1175,10 +1253,20 @@ .Ql } . Any .Ql } -escaped by a backslash or within a quoted string, and characters in +escaped by a backslash or within a single-quoted string, and characters in embedded arithmetic expansions, command substitutions, and variable expansions, are not examined in determining the matching .Ql } . +Except for the variants with +.Ql + , +.Ql - , +.Ql = +or +.Ql ?\& , +any +.Ql } +within a double-quoted string is also not examined in determining the matching +.Ql } . .Pp The simplest form for parameter expansion is: .Pp @@ -1262,6 +1350,14 @@ In the parameter expansions shown previously, use of the colon in the format results in a test for a parameter that is unset or null; omission of the colon results in a test for a parameter that is only unset. +.Pp +The +.Ar word +inherits the type of quoting +(unquoted, double-quoted or here-document) +from the surroundings, +with the exception that a backslash that quotes a closing brace is removed +during quote removal. .Bl -tag -width indent .It Li ${# Ns Ar parameter Ns Li } String Length. @@ -1469,10 +1565,10 @@ .Ql / characters, it is used as is. Otherwise, the shell searches the -.Ev PATH +.Va PATH for the file. If it is not found in the -.Ev PATH , +.Va PATH , it is sought in the current working directory. .It Ic \&[ A built-in equivalent of @@ -1516,7 +1612,7 @@ Switch to the specified .Ar directory , or to the directory specified in the -.Ev HOME +.Va HOME environment variable if no .Ar directory is specified. @@ -1527,17 +1623,17 @@ or .Pa .. , then the directories listed in the -.Ev CDPATH +.Va CDPATH variable will be searched for the specified .Ar directory . If -.Ev CDPATH +.Va CDPATH is unset, the current directory is searched. The format of -.Ev CDPATH +.Va CDPATH is the same as that of -.Ev PATH . +.Va PATH . In an interactive shell, the .Ic cd @@ -1545,7 +1641,7 @@ that it actually switched to if this is different from the name that the user gave. These may be different either because the -.Ev CDPATH +.Va CDPATH mechanism was used or because a symbolic link was crossed. .Pp If the @@ -1568,16 +1664,18 @@ .It Ic command Oo Fl p Oc Op Ar utility Op Ar argument ... .It Ic command Oo Fl v | V Oc Op Ar utility The first form of invocation executes the specified +.Ar utility , +ignoring shell functions in the search. +If .Ar utility -as a simple command (see the -.Sx Simple Commands -section). +is a special builtin, +it is executed as if it were a regular builtin. .Pp If the .Fl p option is specified, the command search is performed using a default value of -.Ev PATH +.Va PATH that is guaranteed to find all of the standard utilities. .Pp If the @@ -1736,20 +1834,20 @@ .Ar editor string is a command name, subject to search via the -.Ev PATH +.Va PATH variable. The value in the -.Ev FCEDIT +.Va FCEDIT variable is used as a default when .Fl e is not specified. If -.Ev FCEDIT +.Va FCEDIT is null or unset, the value of the -.Ev EDITOR +.Va EDITOR variable is used. If -.Ev EDITOR +.Va EDITOR is null or unset, .Xr ed 1 is used as the editor. @@ -1783,7 +1881,7 @@ Select the commands to list or edit. The number of previous commands that can be accessed are determined by the value of the -.Ev HISTSIZE +.Va HISTSIZE variable. The value of .Ar first @@ -1814,12 +1912,12 @@ .El .El .Pp -The following environment variables affect the execution of +The following variables affect the execution of .Ic fc : -.Bl -tag -width ".Ev HISTSIZE" -.It Ev FCEDIT +.Bl -tag -width ".Va HISTSIZE" +.It Va FCEDIT Name of the editor to use for history editing. -.It Ev HISTSIZE +.It Va HISTSIZE The number of previous commands that are accessible. .El .It Ic fg Op Ar job @@ -2285,74 +2383,27 @@ .Sh ENVIRONMENT The following environment variables affect the execution of .Nm : -.Bl -tag -width ".Ev HISTSIZE" -.It Ev CDPATH -The search path used with the -.Ic cd -built-in. -.It Ev EDITOR -The fallback editor used with the -.Ic fc -built-in. -If not set, the default editor is -.Xr ed 1 . -.It Ev FCEDIT -The default editor used with the -.Ic fc -built-in. -.It Ev HISTSIZE -The number of previous commands that are accessible. -.It Ev HOME -The starting directory of -.Nm . -.It Ev IFS -Input Field Separators. -This is normally set to -.Aq space , -.Aq tab , -and -.Aq newline . -See the -.Sx White Space Splitting -section for more details. -.It Ev MAIL -The name of a mail file, that will be checked for the arrival of new -mail. -Overridden by -.Ev MAILPATH . -.It Ev MAILPATH -A colon -.Pq Ql \&: -separated list of file names, for the shell to check for incoming -mail. -This environment setting overrides the -.Ev MAIL -setting. -There is a maximum of 10 mailboxes that can be monitored at once. -.It Ev PATH -The default search path for executables. -See the -.Sx Path Search -section for details. -.It Ev PS1 -The primary prompt string, which defaults to -.Dq Li "$ " , -unless you are the superuser, in which case it defaults to -.Dq Li "# " . -.It Ev PS2 -The secondary prompt string, which defaults to -.Dq Li "> " . -.It Ev PS4 -The prefix for the trace output (if -.Fl x -is active). -The default is -.Dq Li "+ " . +.Bl -tag -width ".Ev LANGXXXXXX" +.It Ev ENV +Initialization file for interactive shells. +.It Ev LANG , Ev LC_* +Locale settings. +These are inherited by children of the shell, +and is used in a limited manner by the shell itself. +.It Ev PWD +An absolute pathname for the current directory, +possibly containing symbolic links. +This is used and updated by the shell. .It Ev TERM The default terminal setting for the shell. This is inherited by children of the shell, and is used in the history editing modes. .El +.Pp +Additionally, all environment variables are turned into shell variables +at startup, +which may affect the shell as described under +.Sx Special Variables . .Sh EXIT STATUS Errors that are detected by the shell, such as a syntax error, will cause the shell to exit with a non-zero exit status. diff -urN stable/8/bin/sh/shell.h head/bin/sh/shell.h --- stable/8/bin/sh/shell.h 2008-04-27 16:46:45.000000000 -0400 +++ head/bin/sh/shell.h 2008-04-27 16:46:45.000000000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)shell.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/shell.h 178625 2008-04-27 20:46:45Z stefanf $ + * $FreeBSD: head/bin/sh/shell.h 178625 2008-04-27 20:46:45Z stefanf $ */ #ifndef SHELL_H_ diff -urN stable/8/bin/sh/show.c head/bin/sh/show.c --- stable/8/bin/sh/show.c 2006-04-14 09:59:03.000000000 -0400 +++ head/bin/sh/show.c 2009-12-24 13:41:14.411055000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/show.c 157750 2006-04-14 13:59:03Z schweikh $"); +__FBSDID("$FreeBSD: head/bin/sh/show.c 200956 2009-12-24 18:41:14Z jilles $"); #include #include @@ -307,7 +307,7 @@ void -trputs(char *s) +trputs(const char *s) { if (tracefile == NULL) return; diff -urN stable/8/bin/sh/show.h head/bin/sh/show.h --- stable/8/bin/sh/show.h 2004-04-06 16:06:54.000000000 -0400 +++ head/bin/sh/show.h 2009-12-24 13:41:14.411055000 -0500 @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)show.h 1.1 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/show.h 127958 2004-04-06 20:06:54Z markm $ + * $FreeBSD: head/bin/sh/show.h 200956 2009-12-24 18:41:14Z jilles $ */ void showtree(union node *); @@ -35,6 +35,6 @@ void sh_trace(const char *, ...) __printflike(1, 2); void trargs(char **); void trputc(int); -void trputs(char *); +void trputs(const char *); void opentrace(void); #endif diff -urN stable/8/bin/sh/trap.c head/bin/sh/trap.c --- stable/8/bin/sh/trap.c 2009-06-13 17:10:41.755841000 -0400 +++ head/bin/sh/trap.c 2009-11-21 15:44:34.304188000 -0500 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/trap.c 194127 2009-06-13 21:10:41Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/trap.c 199641 2009-11-21 20:44:34Z jilles $"); #include #include @@ -149,6 +149,7 @@ { char *action; int signo; + int errors = 0; if (argc <= 1) { for (signo = 0 ; signo < sys_nsig ; signo++) { @@ -183,8 +184,10 @@ } } while (*argv) { - if ((signo = sigstring_to_signum(*argv)) == -1) - error("bad signal %s", *argv); + if ((signo = sigstring_to_signum(*argv)) == -1) { + out2fmt_flush("trap: bad signal %s\n", *argv); + errors = 1; + } INTOFF; if (action) action = savestr(action); @@ -196,7 +199,7 @@ INTON; argv++; } - return 0; + return errors; } @@ -244,7 +247,8 @@ setsignal(int signo) { int action; - sig_t sig, sigact = SIG_DFL; + sig_t sigact = SIG_DFL; + struct sigaction sa; char *t; if ((t = trap[signo]) == NULL) @@ -320,9 +324,10 @@ case S_IGN: sigact = SIG_IGN; break; } *t = action; - sig = signal(signo, sigact); - if (sig != SIG_ERR && action == S_CATCH) - siginterrupt(signo, 1); + sa.sa_handler = sigact; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(signo, &sa, NULL); } diff -urN stable/8/bin/sh/trap.h head/bin/sh/trap.h --- stable/8/bin/sh/trap.h 2009-06-13 17:10:41.755841000 -0400 +++ head/bin/sh/trap.h 2009-12-24 15:55:14.498557000 -0500 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)trap.h 8.3 (Berkeley) 6/5/95 - * $FreeBSD: stable/8/bin/sh/trap.h 194127 2009-06-13 21:10:41Z jilles $ + * $FreeBSD: head/bin/sh/trap.h 200967 2009-12-24 20:55:14Z jilles $ */ extern int pendingsigs; @@ -45,4 +45,4 @@ void onsig(int); void dotrap(void); void setinteractive(int); -void exitshell(int); +void exitshell(int) __dead2; diff -urN stable/8/bin/sh/var.c head/bin/sh/var.c --- stable/8/bin/sh/var.c 2010-04-20 18:52:28.965483000 -0400 +++ head/bin/sh/var.c 2010-06-02 15:16:58.408982000 -0400 @@ -36,7 +36,7 @@ #endif #endif /* not lint */ #include -__FBSDID("$FreeBSD: stable/8/bin/sh/var.c 206950 2010-04-20 22:52:28Z jilles $"); +__FBSDID("$FreeBSD: head/bin/sh/var.c 208755 2010-06-02 19:16:58Z jilles $"); #include #include @@ -73,13 +73,14 @@ struct varinit { struct var *var; int flags; - char *text; + const char *text; void (*func)(const char *); }; #ifndef NO_HISTORY struct var vhistsize; +struct var vterm; #endif struct var vifs; struct var vmail; @@ -94,27 +95,31 @@ STATIC const struct varinit varinit[] = { #ifndef NO_HISTORY - { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", + { &vhistsize, VUNSET, "HISTSIZE=", sethistsize }, #endif - { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", + { &vifs, 0, "IFS= \t\n", NULL }, - { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", + { &vmail, VUNSET, "MAIL=", NULL }, - { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", + { &vmpath, VUNSET, "MAILPATH=", NULL }, - { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, + { &vpath, 0, "PATH=" _PATH_DEFPATH, changepath }, - { &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=", + { &vppid, VUNSET, "PPID=", NULL }, /* * vps1 depends on uid */ - { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", + { &vps2, 0, "PS2=> ", NULL }, - { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ", + { &vps4, 0, "PS4=+ ", NULL }, - { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", +#ifndef NO_HISTORY + { &vterm, VUNSET, "TERM=", + setterm }, +#endif + { &voptind, 0, "OPTIND=1", getoptsreset }, { NULL, 0, NULL, NULL } @@ -122,9 +127,17 @@ STATIC struct var *vartab[VTABSIZE]; -STATIC struct var **hashvar(char *); -STATIC int varequal(char *, char *); -STATIC int localevar(char *); +STATIC const char *const locale_names[7] = { + "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", + "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL +}; +STATIC const int locale_categories[7] = { + LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0 +}; + +STATIC struct var **hashvar(const char *); +STATIC int varequal(const char *, const char *); +STATIC int localevar(const char *); /* * Initialize the variable symbol tables and import the environment. @@ -132,9 +145,9 @@ #ifdef mkinit INCLUDE "var.h" +MKINIT char **environ; INIT { char **envp; - extern char **environ; initvar(); for (envp = environ ; *envp ; envp++) { @@ -164,8 +177,8 @@ vpp = hashvar(ip->text); vp->next = *vpp; *vpp = vp; - vp->text = ip->text; - vp->flags = ip->flags; + vp->text = __DECONST(char *, ip->text); + vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED; vp->func = ip->func; } } @@ -176,7 +189,7 @@ vpp = hashvar("PS1="); vps1.next = *vpp; *vpp = &vps1; - vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; + vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# "); vps1.flags = VSTRFIXED|VTEXTFIXED; } if ((vppid.flags & VEXPORT) == 0) { @@ -190,12 +203,14 @@ */ int -setvarsafe(char *name, char *val, int flags) +setvarsafe(const char *name, const char *val, int flags) { struct jmploc jmploc; struct jmploc *const savehandler = handler; int err = 0; + int inton; + inton = is_int_on(); if (setjmp(jmploc.loc)) err = 1; else { @@ -203,6 +218,7 @@ setvar(name, val, flags); } handler = savehandler; + SETINTON(inton); return err; } @@ -212,9 +228,9 @@ */ void -setvar(char *name, char *val, int flags) +setvar(const char *name, const char *val, int flags) { - char *p, *q; + const char *p; int len; int namelen; char *nameeq; @@ -242,25 +258,20 @@ } else { len += strlen(val); } - p = nameeq = ckmalloc(len); - q = name; - while (--namelen >= 0) - *p++ = *q++; - *p++ = '='; - *p = '\0'; + nameeq = ckmalloc(len); + memcpy(nameeq, name, namelen); + nameeq[namelen] = '='; if (val) - scopy(val, p); + scopy(val, nameeq + namelen + 1); + else + nameeq[namelen + 1] = '\0'; setvareq(nameeq, flags); } STATIC int -localevar(char *s) +localevar(const char *s) { - static char *lnames[7] = { - "ALL", "COLLATE", "CTYPE", "MONETARY", - "NUMERIC", "TIME", NULL - }; - char **ss; + const char *const *ss; if (*s != 'L') return 0; @@ -268,8 +279,10 @@ return 1; if (strncmp(s + 1, "C_", 2) != 0) return 0; - for (ss = lnames; *ss ; ss++) - if (varequal(s + 3, *ss)) + if (varequal(s + 3, "ALL")) + return 1; + for (ss = locale_names; *ss ; ss++) + if (varequal(s + 3, *ss + 3)) return 1; return 0; } @@ -280,7 +293,7 @@ * pointer into environ where the string should not be manipulated. */ static void -change_env(char *s, int set) +change_env(const char *s, int set) { char *eqp; char *ss; @@ -391,7 +404,7 @@ */ char * -lookupvar(char *name) +lookupvar(const char *name) { struct var *v; @@ -414,7 +427,7 @@ */ char * -bltinlookup(char *name, int doall) +bltinlookup(const char *name, int doall) { struct strlist *sp; struct var *v; @@ -435,6 +448,61 @@ } +/* + * Set up locale for a builtin (LANG/LC_* assignments). + */ +void +bltinsetlocale(void) +{ + struct strlist *lp; + int act = 0; + char *loc, *locdef; + int i; + + for (lp = cmdenviron ; lp ; lp = lp->next) { + if (localevar(lp->text)) { + act = 1; + break; + } + } + if (!act) + return; + loc = bltinlookup("LC_ALL", 0); + INTOFF; + if (loc != NULL) { + setlocale(LC_ALL, loc); + INTON; + return; + } + locdef = bltinlookup("LANG", 0); + for (i = 0; locale_names[i] != NULL; i++) { + loc = bltinlookup(locale_names[i], 0); + if (loc == NULL) + loc = locdef; + if (loc != NULL) + setlocale(locale_categories[i], loc); + } + INTON; +} + +/* + * Undo the effect of bltinlocaleset(). + */ +void +bltinunsetlocale(void) +{ + struct strlist *lp; + + INTOFF; + for (lp = cmdenviron ; lp ; lp = lp->next) { + if (localevar(lp->text)) { + setlocale(LC_ALL, ""); + return; + } + } + INTON; +} + /* * Generate a list of exported variables. This routine is used to construct @@ -472,9 +540,9 @@ * VSTACK set since these are currently allocated on the stack. */ -#ifdef mkinit MKINIT void shprocvar(void); +#ifdef mkinit SHELLPROC { shprocvar(); } @@ -798,7 +866,7 @@ */ int -unsetvar(char *s) +unsetvar(const char *s) { struct var **vpp; struct var *vp; @@ -838,7 +906,7 @@ */ STATIC struct var ** -hashvar(char *p) +hashvar(const char *p) { unsigned int hashval; @@ -857,7 +925,7 @@ */ STATIC int -varequal(char *p, char *q) +varequal(const char *p, const char *q) { while (*p == *q++) { if (*p++ == '=') diff -urN stable/8/bin/sh/var.h head/bin/sh/var.h --- stable/8/bin/sh/var.h 2006-06-15 03:00:49.000000000 -0400 +++ head/bin/sh/var.h 2010-06-02 15:16:58.408982000 -0400 @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * @(#)var.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: stable/8/bin/sh/var.h 159632 2006-06-15 07:00:49Z stefanf $ + * $FreeBSD: head/bin/sh/var.h 208755 2010-06-02 19:16:58Z jilles $ */ /* @@ -77,6 +77,7 @@ extern struct var vps4; #ifndef NO_HISTORY extern struct var vhistsize; +extern struct var vterm; #endif /* @@ -96,19 +97,21 @@ #define optindval() (voptind.text + 7) #ifndef NO_HISTORY #define histsizeval() (vhistsize.text + 9) +#define termval() (vterm.text + 5) #endif #define mpathset() ((vmpath.flags & VUNSET) == 0) void initvar(void); -void setvar(char *, char *, int); +void setvar(const char *, const char *, int); void setvareq(char *, int); struct strlist; void listsetvar(struct strlist *); -char *lookupvar(char *); -char *bltinlookup(char *, int); +char *lookupvar(const char *); +char *bltinlookup(const char *, int); +void bltinsetlocale(void); +void bltinunsetlocale(void); char **environment(void); -void shprocvar(void); int showvarscmd(int, char **); int exportcmd(int, char **); int localcmd(int, char **); @@ -116,5 +119,5 @@ void poplocalvars(void); int setvarcmd(int, char **); int unsetcmd(int, char **); -int unsetvar(char *); -int setvarsafe(char *, char *, int); +int unsetvar(const char *); +int setvarsafe(const char *, const char *, int); diff -urN stable/8/include/histedit.h head/include/histedit.h --- stable/8/include/histedit.h 2007-06-11 02:25:19.000000000 -0400 +++ head/include/histedit.h 2010-06-15 17:34:57.534333000 -0400 @@ -31,7 +31,7 @@ * * @(#)histedit.h 8.2 (Berkeley) 1/3/94 * $NetBSD: histedit.h,v 1.32 2007/06/10 20:20:28 christos Exp $ - * $FreeBSD: stable/8/include/histedit.h 170547 2007-06-11 06:25:19Z stefanf $ + * $FreeBSD: head/include/histedit.h 209219 2010-06-15 21:34:57Z jilles $ */ /* @@ -105,9 +105,8 @@ */ int el_set(EditLine *, int, ...); int el_get(EditLine *, int, ...); -#if 0 unsigned char _el_fn_complete(EditLine *, int); -#endif +unsigned char _el_fn_sh_complete(EditLine *, int); /* * el_set/el_get parameters diff -urN stable/8/lib/libedit/Makefile head/lib/libedit/Makefile --- stable/8/lib/libedit/Makefile 2009-07-19 13:25:24.703896000 -0400 +++ head/lib/libedit/Makefile 2010-06-13 13:04:42.741765000 -0400 @@ -1,12 +1,13 @@ # $NetBSD: Makefile,v 1.34 2005/05/28 12:02:53 lukem Exp $ # @(#)Makefile 8.1 (Berkeley) 6/4/93 -# $FreeBSD: stable/8/lib/libedit/Makefile 195767 2009-07-19 17:25:24Z kensmith $ +# $FreeBSD: head/lib/libedit/Makefile 209136 2010-06-13 17:04:42Z jilles $ LIB= edit SHLIB_MAJOR= 7 SHLIBDIR?= /lib -OSRCS= chared.c common.c el.c emacs.c fcns.c help.c hist.c key.c map.c \ +OSRCS= chared.c common.c el.c emacs.c fcns.c filecomplete.c help.c \ + hist.c key.c map.c \ parse.c prompt.c read.c refresh.c search.c sig.c term.c tty.c vi.c DPADD= ${LIBNCURSES} @@ -35,6 +36,8 @@ CFLAGS+= #-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH CFLAGS+= #-DDEBUG_PASTE -DDEBUG_EDIT +WARNS?= 1 + AHDR= vi.h emacs.h common.h ASRC= ${.CURDIR}/vi.c ${.CURDIR}/emacs.c ${.CURDIR}/common.c diff -urN stable/8/lib/libedit/TEST/test.c head/lib/libedit/TEST/test.c --- stable/8/lib/libedit/TEST/test.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/TEST/test.c 2005-08-07 16:55:59.000000000 -0400 @@ -40,7 +40,7 @@ static char sccsid[] = "@(#)test.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ __RCSID("$NetBSD: test.c,v 1.18 2005/06/01 11:37:52 lukem Exp $"); -__FBSDID("$FreeBSD: stable/8/lib/libedit/TEST/test.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/TEST/test.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * test.c: A little test program diff -urN stable/8/lib/libedit/chared.c head/lib/libedit/chared.c --- stable/8/lib/libedit/chared.c 2005-08-09 09:31:59.000000000 -0400 +++ head/lib/libedit/chared.c 2005-08-09 09:31:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/chared.c 148897 2005-08-09 13:31:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/chared.c 148897 2005-08-09 13:31:59Z stefanf $"); /* * chared.c: Character editor utilities diff -urN stable/8/lib/libedit/chared.h head/lib/libedit/chared.h --- stable/8/lib/libedit/chared.h 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/chared.h 2007-03-11 14:30:22.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)chared.h 8.1 (Berkeley) 6/4/93 * $NetBSD: chared.h,v 1.17 2006/03/06 21:11:56 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/chared.h 167457 2007-03-11 18:30:22Z stefanf $ + * $FreeBSD: head/lib/libedit/chared.h 167457 2007-03-11 18:30:22Z stefanf $ */ /* diff -urN stable/8/lib/libedit/common.c head/lib/libedit/common.c --- stable/8/lib/libedit/common.c 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/common.c 2007-03-11 14:30:22.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/common.c 167457 2007-03-11 18:30:22Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/common.c 167457 2007-03-11 18:30:22Z stefanf $"); /* * common.c: Common Editor functions diff -urN stable/8/lib/libedit/editline.3 head/lib/libedit/editline.3 --- stable/8/lib/libedit/editline.3 2007-06-10 15:06:09.000000000 -0400 +++ head/lib/libedit/editline.3 2010-04-14 15:08:06.333546000 -0400 @@ -13,9 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of The NetBSD Foundation nor the names of its -.\" contributors may be used to endorse or promote products derived -.\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -29,11 +26,11 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: stable/8/lib/libedit/editline.3 170511 2007-06-10 19:06:09Z stefanf $ +.\" $FreeBSD: head/lib/libedit/editline.3 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd January 12, 2007 -.Os .Dt EDITLINE 3 +.Os .Sh NAME .Nm editline , .Nm el_init , diff -urN stable/8/lib/libedit/editrc.5 head/lib/libedit/editrc.5 --- stable/8/lib/libedit/editrc.5 2007-03-11 04:41:01.000000000 -0400 +++ head/lib/libedit/editrc.5 2010-04-14 15:08:06.333546000 -0400 @@ -13,9 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of The NetBSD Foundation nor the names of its -.\" contributors may be used to endorse or promote products derived -.\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -29,11 +26,11 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: stable/8/lib/libedit/editrc.5 167444 2007-03-11 08:41:01Z stefanf $ +.\" $FreeBSD: head/lib/libedit/editrc.5 206622 2010-04-14 19:08:06Z uqs $ .\" .Dd October 18, 2003 -.Os .Dt EDITRC 5 +.Os .Sh NAME .Nm editrc .Nd configuration file for editline library diff -urN stable/8/lib/libedit/el.c head/lib/libedit/el.c --- stable/8/lib/libedit/el.c 2007-06-10 15:06:09.000000000 -0400 +++ head/lib/libedit/el.c 2007-06-10 15:06:09.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/el.c 170511 2007-06-10 19:06:09Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/el.c 170511 2007-06-10 19:06:09Z stefanf $"); /* * el.c: EditLine interface functions diff -urN stable/8/lib/libedit/el.h head/lib/libedit/el.h --- stable/8/lib/libedit/el.h 2007-06-10 15:06:09.000000000 -0400 +++ head/lib/libedit/el.h 2007-06-10 15:06:09.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)el.h 8.1 (Berkeley) 6/4/93 * $NetBSD: el.h,v 1.17 2006/12/15 22:13:33 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/el.h 170511 2007-06-10 19:06:09Z stefanf $ + * $FreeBSD: head/lib/libedit/el.h 170511 2007-06-10 19:06:09Z stefanf $ */ /* diff -urN stable/8/lib/libedit/emacs.c head/lib/libedit/emacs.c --- stable/8/lib/libedit/emacs.c 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/emacs.c 2007-03-11 14:30:22.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/emacs.c 167457 2007-03-11 18:30:22Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/emacs.c 167457 2007-03-11 18:30:22Z stefanf $"); /* * emacs.c: Emacs functions diff -urN stable/8/lib/libedit/filecomplete.c head/lib/libedit/filecomplete.c --- stable/8/lib/libedit/filecomplete.c 1969-12-31 19:00:00.000000000 -0500 +++ head/lib/libedit/filecomplete.c 2010-06-15 18:23:21.565992000 -0400 @@ -0,0 +1,667 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $NetBSD: filecomplete.c,v 1.19 2010/06/01 18:20:26 christos Exp $ + */ + +#include +__FBSDID("$FreeBSD: head/lib/libedit/filecomplete.c 209224 2010-06-15 22:23:21Z jilles $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "el.h" +#include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "filecomplete.h" + +static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', + '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; +/* Tilde is deliberately omitted here, we treat it specially. */ +static char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; + + +/********************************/ +/* completion functions */ + +/* + * does tilde expansion of strings of type ``~user/foo'' + * if ``user'' isn't valid user name or ``txt'' doesn't start + * w/ '~', returns pointer to strdup()ed copy of ``txt'' + * + * it's callers's responsibility to free() returned string + */ +char * +fn_tilde_expand(const char *txt) +{ + struct passwd pwres, *pass; + char *temp; + size_t len = 0; + char pwbuf[1024]; + + if (txt[0] != '~') + return (strdup(txt)); + + temp = strchr(txt + 1, '/'); + if (temp == NULL) { + temp = strdup(txt + 1); + if (temp == NULL) + return NULL; + } else { + len = temp - txt + 1; /* text until string after slash */ + temp = malloc(len); + if (temp == NULL) + return NULL; + (void)strncpy(temp, txt + 1, len - 2); + temp[len - 2] = '\0'; + } + if (temp[0] == 0) { + if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } else { + if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) + pass = NULL; + } + free(temp); /* value no more needed */ + if (pass == NULL) + return (strdup(txt)); + + /* update pointer txt to point at string immediately following */ + /* first slash */ + txt += len; + + temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); + + return (temp); +} + + +/* + * return first found file name starting by the ``text'' or NULL if no + * such file can be found + * value of ``state'' is ignored + * + * it's caller's responsibility to free returned string + */ +char * +fn_filename_completion_function(const char *text, int state) +{ + static DIR *dir = NULL; + static char *filename = NULL, *dirname = NULL, *dirpath = NULL; + static size_t filename_len = 0; + struct dirent *entry; + char *temp; + size_t len; + + if (state == 0 || dir == NULL) { + temp = strrchr(text, '/'); + if (temp) { + char *nptr; + temp++; + nptr = realloc(filename, strlen(temp) + 1); + if (nptr == NULL) { + free(filename); + filename = NULL; + return NULL; + } + filename = nptr; + (void)strcpy(filename, temp); + len = temp - text; /* including last slash */ + + nptr = realloc(dirname, len + 1); + if (nptr == NULL) { + free(dirname); + dirname = NULL; + return NULL; + } + dirname = nptr; + (void)strncpy(dirname, text, len); + dirname[len] = '\0'; + } else { + free(filename); + if (*text == 0) + filename = NULL; + else { + filename = strdup(text); + if (filename == NULL) + return NULL; + } + free(dirname); + dirname = NULL; + } + + if (dir != NULL) { + (void)closedir(dir); + dir = NULL; + } + + /* support for ``~user'' syntax */ + + free(dirpath); + dirpath = NULL; + if (dirname == NULL) { + if ((dirname = strdup("")) == NULL) + return NULL; + dirpath = strdup("./"); + } else if (*dirname == '~') + dirpath = fn_tilde_expand(dirname); + else + dirpath = strdup(dirname); + + if (dirpath == NULL) + return NULL; + + dir = opendir(dirpath); + if (!dir) + return (NULL); /* cannot open the directory */ + + /* will be used in cycle */ + filename_len = filename ? strlen(filename) : 0; + } + + /* find the match */ + while ((entry = readdir(dir)) != NULL) { + /* skip . and .. */ + if (entry->d_name[0] == '.' && (!entry->d_name[1] + || (entry->d_name[1] == '.' && !entry->d_name[2]))) + continue; + if (filename_len == 0) + break; + /* otherwise, get first entry where first */ + /* filename_len characters are equal */ + if (entry->d_name[0] == filename[0] + && entry->d_namlen >= filename_len + && strncmp(entry->d_name, filename, + filename_len) == 0) + break; + } + + if (entry) { /* match found */ + len = entry->d_namlen; + + temp = malloc(strlen(dirname) + len + 1); + if (temp == NULL) + return NULL; + (void)sprintf(temp, "%s%s", dirname, entry->d_name); + } else { + (void)closedir(dir); + dir = NULL; + temp = NULL; + } + + return (temp); +} + + +static const char * +append_char_function(const char *name) +{ + struct stat stbuf; + char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; + const char *rs = " "; + + if (stat(expname ? expname : name, &stbuf) == -1) + goto out; + if (S_ISDIR(stbuf.st_mode)) + rs = "/"; +out: + if (expname) + free(expname); + return rs; +} + + +/* + * returns list of completions for text given + * non-static for readline. + */ +char ** completion_matches(const char *, char *(*)(const char *, int)); +char ** +completion_matches(const char *text, char *(*genfunc)(const char *, int)) +{ + char **match_list = NULL, *retstr, *prevstr; + size_t match_list_len, max_equal, which, i; + size_t matches; + + matches = 0; + match_list_len = 1; + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { + /* allow for list terminator here */ + if (matches + 3 >= match_list_len) { + char **nmatch_list; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; + nmatch_list = realloc(match_list, + match_list_len * sizeof(char *)); + if (nmatch_list == NULL) { + free(match_list); + return NULL; + } + match_list = nmatch_list; + + } + match_list[++matches] = retstr; + } + + if (!match_list) + return NULL; /* nothing found */ + + /* find least denominator and insert it to match_list[0] */ + which = 2; + prevstr = match_list[1]; + max_equal = strlen(prevstr); + for (; which <= matches; which++) { + for (i = 0; i < max_equal && + prevstr[i] == match_list[which][i]; i++) + continue; + max_equal = i; + } + + retstr = malloc(max_equal + 1); + if (retstr == NULL) { + free(match_list); + return NULL; + } + (void)strncpy(retstr, match_list[1], max_equal); + retstr[max_equal] = '\0'; + match_list[0] = retstr; + + /* add NULL as last pointer to the array */ + match_list[matches + 1] = (char *) NULL; + + return (match_list); +} + + +/* + * Sort function for qsort(). Just wrapper around strcasecmp(). + */ +static int +_fn_qsort_string_compare(const void *i1, const void *i2) +{ + const char *s1 = ((const char * const *)i1)[0]; + const char *s2 = ((const char * const *)i2)[0]; + + return strcasecmp(s1, s2); +} + + +/* + * Display list of strings in columnar format on readline's output stream. + * 'matches' is list of strings, 'len' is number of strings in 'matches', + * 'max' is maximum length of string in 'matches'. + */ +void +fn_display_match_list(EditLine *el, char **matches, size_t len, size_t max) +{ + size_t i, idx, limit, count; + int screenwidth = el->el_term.t_size.h; + + /* + * Find out how many entries can be put on one line, count + * with two spaces between strings. + */ + limit = screenwidth / (max + 2); + if (limit == 0) + limit = 1; + + /* how many lines of output */ + count = len / limit; + if (count * limit < len) + count++; + + /* Sort the items if they are not already sorted. */ + qsort(&matches[1], len, sizeof(char *), _fn_qsort_string_compare); + + idx = 1; + for(; count > 0; count--) { + int more = limit > 0 && matches[0]; + for(i = 0; more; idx++) { + more = ++i < limit && matches[idx + 1]; + (void)fprintf(el->el_outfile, "%-*s%s", (int)max, + matches[idx], more ? " " : ""); + } + (void)fprintf(el->el_outfile, "\n"); + } +} + + +/* + * Complete the word at or before point, + * 'what_to_do' says what to do with the completion. + * \t means do standard completion. + * `?' means list the possible completions. + * `*' means insert all of the possible completions. + * `!' means to do standard completion, and list all possible completions if + * there is more than one. + * + * Note: '*' support is not implemented + * '!' could never be invoked + */ +int +fn_complete(EditLine *el, + char *(*complet_func)(const char *, int), + char **(*attempted_completion_function)(const char *, int, int), + const char *word_break, const char *special_prefixes, + const char *(*app_func)(const char *), size_t query_items, + int *completion_type, int *over, int *point, int *end, + const char *(*find_word_start_func)(const char *, const char *), + char *(*dequoting_func)(const char *), + char *(*quoting_func)(const char *)) +{ + const LineInfo *li; + char *temp; + char *dequoted_temp; + char **matches; + const char *ctemp; + size_t len; + int what_to_do = '\t'; + int retval = CC_NORM; + + if (el->el_state.lastcmd == el->el_state.thiscmd) + what_to_do = '?'; + + /* readline's rl_complete() has to be told what we did... */ + if (completion_type != NULL) + *completion_type = what_to_do; + + if (!complet_func) + complet_func = fn_filename_completion_function; + if (!app_func) + app_func = append_char_function; + + /* We now look backwards for the start of a filename/variable word */ + li = el_line(el); + if (find_word_start_func) + ctemp = find_word_start_func(li->buffer, li->cursor); + else { + ctemp = li->cursor; + while (ctemp > li->buffer + && !strchr(word_break, ctemp[-1]) + && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) + ctemp--; + } + + len = li->cursor - ctemp; +#if defined(__SSP__) || defined(__SSP_ALL__) + temp = malloc(sizeof(*temp) * (len + 1)); + if (temp == NULL) + return retval; +#else + temp = alloca(sizeof(*temp) * (len + 1)); +#endif + (void)strncpy(temp, ctemp, len); + temp[len] = '\0'; + + if (dequoting_func) { + dequoted_temp = dequoting_func(temp); + if (dequoted_temp == NULL) + return retval; + } else + dequoted_temp = NULL; + + /* these can be used by function called in completion_matches() */ + /* or (*attempted_completion_function)() */ + if (point != 0) + *point = (int)(li->cursor - li->buffer); + if (end != NULL) + *end = (int)(li->lastchar - li->buffer); + + if (attempted_completion_function) { + int cur_off = (int)(li->cursor - li->buffer); + matches = (*attempted_completion_function) (dequoted_temp ? dequoted_temp : temp, + (int)(cur_off - len), cur_off); + } else + matches = 0; + if (!attempted_completion_function || + (over != NULL && !*over && !matches)) + matches = completion_matches(dequoted_temp ? dequoted_temp : temp, complet_func); + + if (over != NULL) + *over = 0; + + if (matches) { + int i; + size_t matches_num, maxlen, match_len, match_display=1; + + retval = CC_REFRESH; + /* + * Only replace the completed string with common part of + * possible matches if there is possible completion. + */ + if (matches[0][0] != '\0') { + char *quoted_match; + if (quoting_func) { + quoted_match = quoting_func(matches[0]); + if (quoted_match == NULL) + goto free_matches; + } else + quoted_match = NULL; + + el_deletestr(el, (int) len); + el_insertstr(el, quoted_match ? quoted_match : matches[0]); + + free(quoted_match); + } + + if (what_to_do == '?') + goto display_matches; + + if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { + /* + * We found exact match. Add a space after + * it, unless we do filename completion and the + * object is a directory. + */ + el_insertstr(el, (*app_func)(matches[0])); + } else if (what_to_do == '!') { + display_matches: + /* + * More than one match and requested to list possible + * matches. + */ + + for(i = 1, maxlen = 0; matches[i]; i++) { + match_len = strlen(matches[i]); + if (match_len > maxlen) + maxlen = match_len; + } + matches_num = i - 1; + + /* newline to get on next line from command line */ + (void)fprintf(el->el_outfile, "\n"); + + /* + * If there are too many items, ask user for display + * confirmation. + */ + if (matches_num > query_items) { + (void)fprintf(el->el_outfile, + "Display all %zu possibilities? (y or n) ", + matches_num); + (void)fflush(el->el_outfile); + if (getc(stdin) != 'y') + match_display = 0; + (void)fprintf(el->el_outfile, "\n"); + } + + if (match_display) + fn_display_match_list(el, matches, matches_num, + maxlen); + retval = CC_REDISPLAY; + } else if (matches[0][0]) { + /* + * There was some common match, but the name was + * not complete enough. Next tab will print possible + * completions. + */ + el_beep(el); + } else { + /* lcd is not a valid object - further specification */ + /* is needed */ + el_beep(el); + retval = CC_NORM; + } + +free_matches: + /* free elements of array and the array itself */ + for (i = 0; matches[i]; i++) + free(matches[i]); + free(matches); + matches = NULL; + } + free(dequoted_temp); +#if defined(__SSP__) || defined(__SSP_ALL__) + free(temp); +#endif + return retval; +} + + +/* + * el-compatible wrapper around rl_complete; needed for key binding + */ +/* ARGSUSED */ +unsigned char +_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) +{ + return (unsigned char)fn_complete(el, NULL, NULL, + break_chars, NULL, NULL, 100, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL); +} + + +static const char * +sh_find_word_start(const char *buffer, const char *cursor) +{ + const char *word_start = buffer; + + while (buffer < cursor) { + if (*buffer == '\\') + buffer++; + else if (strchr(break_chars, *buffer)) + word_start = buffer + 1; + + buffer++; + } + + return word_start; +} + + +static char * +sh_quote(const char *str) +{ + const char *src; + int extra_len = 0; + char *quoted_str, *dst; + + if (*str == '-' || *str == '+') + extra_len += 2; + for (src = str; *src != '\0'; src++) + if (strchr(break_chars, *src) || + strchr(extra_quote_chars, *src)) + extra_len++; + + quoted_str = malloc(sizeof(*quoted_str) * + (strlen(str) + extra_len + 1)); + if (quoted_str == NULL) + return NULL; + + dst = quoted_str; + if (*str == '-' || *str == '+') + *dst++ = '.', *dst++ = '/'; + for (src = str; *src != '\0'; src++) { + if (strchr(break_chars, *src) || + strchr(extra_quote_chars, *src)) + *dst++ = '\\'; + *dst++ = *src; + } + *dst = '\0'; + + return quoted_str; +} + + +static char * +sh_dequote(const char *str) +{ + char *dequoted_str, *dst; + + /* save extra space to replace \~ with ./~ */ + dequoted_str = malloc(sizeof(*dequoted_str) * (strlen(str) + 1 + 1)); + if (dequoted_str == NULL) + return NULL; + + dst = dequoted_str; + + /* dequote \~ at start as ./~ */ + if (*str == '\\' && str[1] == '~') { + str++; + *dst++ = '.'; + *dst++ = '/'; + } + + while (*str) { + if (*str == '\\') + str++; + if (*str) + *dst++ = *str++; + } + *dst = '\0'; + + return dequoted_str; +} + + +/* + * completion function using sh quoting rules; for key binding + */ +/* ARGSUSED */ +unsigned char +_el_fn_sh_complete(EditLine *el, int ch __attribute__((__unused__))) +{ + return (unsigned char)fn_complete(el, NULL, NULL, + break_chars, NULL, NULL, 100, + NULL, NULL, NULL, NULL, + sh_find_word_start, sh_dequote, sh_quote); +} diff -urN stable/8/lib/libedit/filecomplete.h head/lib/libedit/filecomplete.h --- stable/8/lib/libedit/filecomplete.h 1969-12-31 19:00:00.000000000 -0500 +++ head/lib/libedit/filecomplete.h 2010-06-15 17:34:57.534333000 -0400 @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jaromir Dolecek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $NetBSD: filecomplete.h,v 1.9 2009/12/30 22:37:40 christos Exp $ + * $FreeBSD: head/lib/libedit/filecomplete.h 209219 2010-06-15 21:34:57Z jilles $ + */ +#ifndef _FILECOMPLETE_H_ +#define _FILECOMPLETE_H_ + +int fn_complete(EditLine *, + char *(*)(const char *, int), + char **(*)(const char *, int, int), + const char *, const char *, const char *(*)(const char *), size_t, + int *, int *, int *, int *, + const char *(*)(const char *, const char *), + char *(*)(const char *), + char *(*)(const char *)); + +void fn_display_match_list(EditLine *, char **, size_t, size_t); +char *fn_tilde_expand(const char *); +char *fn_filename_completion_function(const char *, int); + +#endif diff -urN stable/8/lib/libedit/hist.c head/lib/libedit/hist.c --- stable/8/lib/libedit/hist.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/hist.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/hist.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/hist.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * hist.c: History access functions diff -urN stable/8/lib/libedit/hist.h head/lib/libedit/hist.h --- stable/8/lib/libedit/hist.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/hist.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)hist.h 8.1 (Berkeley) 6/4/93 * $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $ - * $FreeBSD: stable/8/lib/libedit/hist.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/hist.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/history.c head/lib/libedit/history.c --- stable/8/lib/libedit/history.c 2007-03-11 17:47:40.000000000 -0400 +++ head/lib/libedit/history.c 2007-03-11 17:47:40.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/history.c 167464 2007-03-11 21:47:40Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/history.c 167464 2007-03-11 21:47:40Z stefanf $"); /* * hist.c: History access functions diff -urN stable/8/lib/libedit/key.c head/lib/libedit/key.c --- stable/8/lib/libedit/key.c 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/key.c 2007-03-11 14:30:22.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/key.c 167457 2007-03-11 18:30:22Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/key.c 167457 2007-03-11 18:30:22Z stefanf $"); /* * key.c: This module contains the procedures for maintaining diff -urN stable/8/lib/libedit/key.h head/lib/libedit/key.h --- stable/8/lib/libedit/key.h 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/key.h 2007-03-11 14:30:22.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)key.h 8.1 (Berkeley) 6/4/93 * $NetBSD: key.h,v 1.10 2006/03/23 20:22:51 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/key.h 167457 2007-03-11 18:30:22Z stefanf $ + * $FreeBSD: head/lib/libedit/key.h 167457 2007-03-11 18:30:22Z stefanf $ */ /* diff -urN stable/8/lib/libedit/makelist head/lib/libedit/makelist --- stable/8/lib/libedit/makelist 2005-10-04 17:59:29.000000000 -0400 +++ head/lib/libedit/makelist 2005-10-04 17:59:29.000000000 -0400 @@ -1,6 +1,6 @@ #!/bin/sh - # $NetBSD: makelist,v 1.10 2005/08/08 14:04:49 christos Exp $ -# $FreeBSD: stable/8/lib/libedit/makelist 150947 2005-10-04 21:59:29Z stefanf $ +# $FreeBSD: head/lib/libedit/makelist 150947 2005-10-04 21:59:29Z stefanf $ # # Copyright (c) 1992, 1993 # The Regents of the University of California. All rights reserved. diff -urN stable/8/lib/libedit/map.c head/lib/libedit/map.c --- stable/8/lib/libedit/map.c 2007-03-11 17:47:40.000000000 -0400 +++ head/lib/libedit/map.c 2007-03-11 17:47:40.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/map.c 167464 2007-03-11 21:47:40Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/map.c 167464 2007-03-11 21:47:40Z stefanf $"); /* * map.c: Editor function definitions diff -urN stable/8/lib/libedit/map.h head/lib/libedit/map.h --- stable/8/lib/libedit/map.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/map.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)map.h 8.1 (Berkeley) 6/4/93 * $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $ - * $FreeBSD: stable/8/lib/libedit/map.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/map.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/parse.c head/lib/libedit/parse.c --- stable/8/lib/libedit/parse.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/parse.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/parse.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/parse.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * parse.c: parse an editline extended command diff -urN stable/8/lib/libedit/parse.h head/lib/libedit/parse.h --- stable/8/lib/libedit/parse.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/parse.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)parse.h 8.1 (Berkeley) 6/4/93 * $NetBSD: parse.h,v 1.6 2005/05/29 04:58:15 lukem Exp $ - * $FreeBSD: stable/8/lib/libedit/parse.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/parse.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/prompt.c head/lib/libedit/prompt.c --- stable/8/lib/libedit/prompt.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/prompt.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/prompt.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/prompt.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * prompt.c: Prompt printing functions diff -urN stable/8/lib/libedit/prompt.h head/lib/libedit/prompt.h --- stable/8/lib/libedit/prompt.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/prompt.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)prompt.h 8.1 (Berkeley) 6/4/93 * $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $ - * $FreeBSD: stable/8/lib/libedit/prompt.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/prompt.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/read.c head/lib/libedit/read.c --- stable/8/lib/libedit/read.c 2007-03-11 17:47:40.000000000 -0400 +++ head/lib/libedit/read.c 2007-03-11 17:47:40.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/read.c 167464 2007-03-11 21:47:40Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/read.c 167464 2007-03-11 21:47:40Z stefanf $"); /* * read.c: Clean this junk up! This is horrible code. diff -urN stable/8/lib/libedit/read.h head/lib/libedit/read.h --- stable/8/lib/libedit/read.h 2007-03-11 04:41:01.000000000 -0400 +++ head/lib/libedit/read.h 2010-03-02 02:25:20.369016000 -0500 @@ -13,9 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -30,7 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. * * $NetBSD: read.h,v 1.5 2006/08/21 12:45:30 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/read.h 167444 2007-03-11 08:41:01Z stefanf $ + * $FreeBSD: head/lib/libedit/read.h 204555 2010-03-02 07:25:20Z joel $ */ /* diff -urN stable/8/lib/libedit/refresh.c head/lib/libedit/refresh.c --- stable/8/lib/libedit/refresh.c 2005-12-04 04:34:56.000000000 -0500 +++ head/lib/libedit/refresh.c 2005-12-04 04:34:56.000000000 -0500 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/refresh.c 153079 2005-12-04 09:34:56Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/refresh.c 153079 2005-12-04 09:34:56Z stefanf $"); /* * refresh.c: Lower level screen refreshing functions diff -urN stable/8/lib/libedit/refresh.h head/lib/libedit/refresh.h --- stable/8/lib/libedit/refresh.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/refresh.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)refresh.h 8.1 (Berkeley) 6/4/93 * $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $ - * $FreeBSD: stable/8/lib/libedit/refresh.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/refresh.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/search.c head/lib/libedit/search.c --- stable/8/lib/libedit/search.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/search.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/search.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/search.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * search.c: History and character search functions diff -urN stable/8/lib/libedit/search.h head/lib/libedit/search.h --- stable/8/lib/libedit/search.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/search.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)search.h 8.1 (Berkeley) 6/4/93 * $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/search.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/search.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/sig.c head/lib/libedit/sig.c --- stable/8/lib/libedit/sig.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/sig.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/sig.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/sig.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * sig.c: Signal handling stuff. diff -urN stable/8/lib/libedit/sig.h head/lib/libedit/sig.h --- stable/8/lib/libedit/sig.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/sig.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)sig.h 8.1 (Berkeley) 6/4/93 * $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $ - * $FreeBSD: stable/8/lib/libedit/sig.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/sig.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/sys.h head/lib/libedit/sys.h --- stable/8/lib/libedit/sys.h 2005-08-10 09:41:31.000000000 -0400 +++ head/lib/libedit/sys.h 2005-08-10 09:41:31.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)sys.h 8.1 (Berkeley) 6/4/93 * $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/sys.h 148924 2005-08-10 13:41:31Z stefanf $ + * $FreeBSD: head/lib/libedit/sys.h 148924 2005-08-10 13:41:31Z stefanf $ */ /* diff -urN stable/8/lib/libedit/term.c head/lib/libedit/term.c --- stable/8/lib/libedit/term.c 2007-06-10 15:06:09.000000000 -0400 +++ head/lib/libedit/term.c 2007-06-10 15:06:09.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/term.c 170511 2007-06-10 19:06:09Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/term.c 170511 2007-06-10 19:06:09Z stefanf $"); /* * term.c: Editor/termcap-curses interface diff -urN stable/8/lib/libedit/term.h head/lib/libedit/term.h --- stable/8/lib/libedit/term.h 2007-06-10 15:06:09.000000000 -0400 +++ head/lib/libedit/term.h 2007-06-10 15:06:09.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)term.h 8.1 (Berkeley) 6/4/93 * $NetBSD: term.h,v 1.18 2006/11/24 00:01:17 christos Exp $ - * $FreeBSD: stable/8/lib/libedit/term.h 170511 2007-06-10 19:06:09Z stefanf $ + * $FreeBSD: head/lib/libedit/term.h 170511 2007-06-10 19:06:09Z stefanf $ */ /* diff -urN stable/8/lib/libedit/tokenizer.c head/lib/libedit/tokenizer.c --- stable/8/lib/libedit/tokenizer.c 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/tokenizer.c 2005-08-07 16:55:59.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/tokenizer.c 148834 2005-08-07 20:55:59Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/tokenizer.c 148834 2005-08-07 20:55:59Z stefanf $"); /* * tokenize.c: Bourne shell like tokenizer diff -urN stable/8/lib/libedit/tty.c head/lib/libedit/tty.c --- stable/8/lib/libedit/tty.c 2007-03-11 17:47:40.000000000 -0400 +++ head/lib/libedit/tty.c 2007-03-11 17:47:40.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/tty.c 167464 2007-03-11 21:47:40Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/tty.c 167464 2007-03-11 21:47:40Z stefanf $"); /* * tty.c: tty interface stuff diff -urN stable/8/lib/libedit/tty.h head/lib/libedit/tty.h --- stable/8/lib/libedit/tty.h 2005-08-07 16:55:59.000000000 -0400 +++ head/lib/libedit/tty.h 2005-08-07 16:55:59.000000000 -0400 @@ -31,7 +31,7 @@ * * @(#)tty.h 8.1 (Berkeley) 6/4/93 * $NetBSD: tty.h,v 1.11 2005/06/01 11:37:52 lukem Exp $ - * $FreeBSD: stable/8/lib/libedit/tty.h 148834 2005-08-07 20:55:59Z stefanf $ + * $FreeBSD: head/lib/libedit/tty.h 148834 2005-08-07 20:55:59Z stefanf $ */ /* diff -urN stable/8/lib/libedit/vi.c head/lib/libedit/vi.c --- stable/8/lib/libedit/vi.c 2007-03-11 14:30:22.000000000 -0400 +++ head/lib/libedit/vi.c 2007-03-11 14:30:22.000000000 -0400 @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint && not SCCSID */ #include -__FBSDID("$FreeBSD: stable/8/lib/libedit/vi.c 167457 2007-03-11 18:30:22Z stefanf $"); +__FBSDID("$FreeBSD: head/lib/libedit/vi.c 167457 2007-03-11 18:30:22Z stefanf $"); /* * vi.c: Vi mode commands.