[Midnightbsd-cvs] src: bin/sh: Bring in changes from CURRENT.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Mon Jun 30 20:20:29 EDT 2008


Log Message:
-----------
Bring in changes from CURRENT.  

This fixes the GNU autotools problems with newer software.

Tags:
----
RELENG_0_2

Modified Files:
--------------
    src/bin/sh:
        TOUR (r1.2 -> r1.2.2.1)
        arith.h (r1.2 -> r1.2.2.1)
        arith.y (r1.2 -> r1.2.2.1)
        builtins.def (r1.2 -> r1.2.2.1)
        cd.c (r1.3 -> r1.3.2.1)
        error.c (r1.2 -> r1.2.2.1)
        eval.c (r1.2 -> r1.2.2.1)
        exec.c (r1.2 -> r1.2.2.1)
        exec.h (r1.2 -> r1.2.2.1)
        expand.c (r1.2 -> r1.2.2.1)
        input.c (r1.2 -> r1.2.2.1)
        jobs.c (r1.2 -> r1.2.2.1)
        jobs.h (r1.2 -> r1.2.2.1)
        main.c (r1.2 -> r1.2.2.1)
        mkbuiltins (r1.2 -> r1.2.2.1)
        options.c (r1.2 -> r1.2.2.1)
        parser.c (r1.2 -> r1.2.2.1)
        parser.h (r1.2 -> r1.2.2.1)
        sh.1 (r1.2 -> r1.2.2.1)
        shell.h (r1.2 -> r1.2.2.1)
        var.c (r1.2 -> r1.2.2.1)
        var.h (r1.2 -> r1.2.2.1)

-------------- next part --------------
Index: mkbuiltins
===================================================================
RCS file: /home/cvs/src/bin/sh/mkbuiltins,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/mkbuiltins -L bin/sh/mkbuiltins -u -r1.2 -r1.2.2.1
--- bin/sh/mkbuiltins
+++ bin/sh/mkbuiltins
@@ -67,9 +67,14 @@
 
 const struct builtincmd builtincmd[] = {'
 awk '{	for (i = 2 ; i <= NF ; i++) {
-		printf "\t{ \"%s\", %d },\n",  $i, NR-1
+		if ($i == "-s") {
+			spc = 1;
+		} else {
+			printf "\t{ \"%s\", %d, %d },\n",  $i, NR-1, spc
+			spc = 0;
+		}
 	}}' $temp
-echo '	{ NULL, 0 }
+echo '	{ NULL, 0, 0 }
 };'
 
 exec > ${objdir}/builtins.h
@@ -86,6 +91,7 @@
 struct builtincmd {
       char *name;
       int code;
+      int special;
 };
 
 extern int (*const builtinfunc[])(int, char **);
Index: expand.c
===================================================================
RCS file: /home/cvs/src/bin/sh/expand.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/expand.c -L bin/sh/expand.c -u -r1.2 -r1.2.2.1
--- bin/sh/expand.c
+++ bin/sh/expand.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.47.2.1 2005/11/06 20:39:47 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.47.2.5 2008/04/27 20:43:26 stefanf Exp $");
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -99,7 +99,7 @@
 STATIC int subevalvar(char *, char *, int, int, int, int);
 STATIC char *evalvar(char *, int);
 STATIC int varisset(char *, int);
-STATIC void varvalue(char *, int, int);
+STATIC void varvalue(char *, int, int, int);
 STATIC void recordregion(int, int, int);
 STATIC void removerecordregions(int); 
 STATIC void ifsbreakup(char *, struct arglist *);
@@ -634,7 +634,7 @@
 	int easy;
 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
 
-	varflags = *p++;
+	varflags = (unsigned char)*p++;
 	subtype = varflags & VSTYPE;
 	var = p;
 	special = 0;
@@ -670,7 +670,7 @@
 	if (set && subtype != VSPLUS) {
 		/* insert the value of the variable */
 		if (special) {
-			varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
+			varvalue(var, varflags & VSQUOTE, subtype, flag);
 			if (subtype == VSLENGTH) {
 				varlen = expdest - stackblock() - startloc;
 				STADJUST(-varlen, expdest);
@@ -764,6 +764,11 @@
 			goto record;
 		break;
 
+	case VSERROR:
+		c = p - var - 1;
+		error("${%.*s%s}: Bad substitution", c, var,
+		    (c > 0 && *p != CTLENDVAR) ? "..." : "");
+
 	default:
 		abort();
 	}
@@ -837,7 +842,7 @@
  */
 
 STATIC void
-varvalue(char *name, int quoted, int allow_split)
+varvalue(char *name, int quoted, int subtype, int flag)
 {
 	int num;
 	char *p;
@@ -849,7 +854,7 @@
 
 #define STRTODEST(p) \
 	do {\
-	if (allow_split) { \
+	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
 		syntax = quoted? DQSYNTAX : BASESYNTAX; \
 		while (*p) { \
 			if (syntax[(int)*p] == CCTL) \
@@ -884,7 +889,7 @@
 		}
 		break;
 	case '@':
-		if (allow_split && quoted) {
+		if (flag & EXP_FULL && quoted) {
 			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
 				STRTODEST(p);
 				if (*ap)
Index: exec.c
===================================================================
RCS file: /home/cvs/src/bin/sh/exec.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/exec.c -L bin/sh/exec.c -u -r1.2 -r1.2.2.1
--- bin/sh/exec.c
+++ bin/sh/exec.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.25.2.1 2005/11/06 20:39:47 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.25.2.3 2007/02/04 10:42:30 stefanf Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -85,6 +85,7 @@
 struct tblentry {
 	struct tblentry *next;	/* next entry in hash chain */
 	union param param;	/* definition of builtin function */
+	int special;		/* flag for special builtin commands */
 	short cmdtype;		/* index identifying command */
 	char rehash;		/* if set, cd done since entry created */
 	char cmdname[ARB];	/* name of command */
@@ -318,6 +319,7 @@
 	struct stat statb;
 	int e;
 	int i;
+	int spec;
 
 	/* If name contains a slash, don't use the hash table */
 	if (strchr(name, '/') != NULL) {
@@ -331,11 +333,12 @@
 		goto success;
 
 	/* If %builtin not in path, check for builtin next */
-	if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
+	if (builtinloc < 0 && (i = find_builtin(name, &spec)) >= 0) {
 		INTOFF;
 		cmdp = cmdlookup(name, 1);
 		cmdp->cmdtype = CMDBUILTIN;
 		cmdp->param.index = i;
+		cmdp->special = spec;
 		INTON;
 		goto success;
 	}
@@ -357,12 +360,13 @@
 		index++;
 		if (pathopt) {
 			if (prefix("builtin", pathopt)) {
-				if ((i = find_builtin(name)) < 0)
+				if ((i = find_builtin(name, &spec)) < 0)
 					goto loop;
 				INTOFF;
 				cmdp = cmdlookup(name, 1);
 				cmdp->cmdtype = CMDBUILTIN;
 				cmdp->param.index = i;
+				cmdp->special = spec;
 				INTON;
 				goto success;
 			} else if (prefix("func", pathopt)) {
@@ -431,6 +435,7 @@
 	cmdp->rehash = 0;
 	entry->cmdtype = cmdp->cmdtype;
 	entry->u = cmdp->param;
+	entry->special = cmdp->special;
 }
 
 
@@ -440,13 +445,15 @@
  */
 
 int
-find_builtin(char *name)
+find_builtin(char *name, int *special)
 {
 	const struct builtincmd *bp;
 
 	for (bp = builtincmd ; bp->name ; bp++) {
-		if (*bp->name == *name && equal(bp->name, name))
+		if (*bp->name == *name && equal(bp->name, name)) {
+			*special = bp->special;
 			return bp->code;
+		}
 	}
 	return -1;
 }
@@ -774,14 +781,17 @@
 						" a tracked alias for" : "",
 					    name);
 			} else {
-				if (access(argv[i], X_OK) == 0) {
+				if (eaccess(argv[i], X_OK) == 0) {
 					if (cmd == TYPECMD_SMALLV)
 						out1fmt("%s\n", argv[i]);
 					else
 						out1fmt(" is %s\n", argv[i]);
+				} else {
+					if (cmd != TYPECMD_SMALLV)
+						out1fmt(": %s\n",
+						    strerror(errno));
+					error |= 127;
 				}
-				else
-					out1fmt(": %s\n", strerror(errno));
 			}
 			break;
 		}
Index: error.c
===================================================================
RCS file: /home/cvs/src/bin/sh/error.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/error.c -L bin/sh/error.c -u -r1.2 -r1.2.2.1
--- bin/sh/error.c
+++ bin/sh/error.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/error.c,v 1.25 2004/04/06 20:06:51 markm Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/error.c,v 1.26 2006/02/04 14:37:50 schweikh Exp $");
 
 /*
  * Errors and exceptions.
@@ -119,7 +119,7 @@
 	 * This doesn't seem to be needed, since main() emits a newline.
 	 */
 #if 0
-	if (tcgetpgrp(0) == getpid())	
+	if (tcgetpgrp(0) == getpid())
 		write(STDERR_FILENO, "\n", 1);
 #endif
 	if (rootshell && iflag)
Index: exec.h
===================================================================
RCS file: /home/cvs/src/bin/sh/exec.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/exec.h -L bin/sh/exec.h -u -r1.2 -r1.2.2.1
--- bin/sh/exec.h
+++ bin/sh/exec.h
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)exec.h	8.3 (Berkeley) 6/8/95
- * $FreeBSD: src/bin/sh/exec.h,v 1.12.8.1 2005/11/06 20:39:47 stefanf Exp $
+ * $FreeBSD: src/bin/sh/exec.h,v 1.12.8.2 2006/06/03 15:38:07 stefanf Exp $
  */
 
 /* values of cmdtype */
@@ -53,6 +53,7 @@
 		int index;
 		union node *func;
 	} u;
+	int special;
 };
 
 
@@ -63,7 +64,7 @@
 char *padvance(char **, char *);
 int hashcmd(int, char **);
 void find_command(char *, struct cmdentry *, int, char *);
-int find_builtin(char *);
+int find_builtin(char *, int *);
 void hashcd(void);
 void changepath(const char *);
 void deletefuncs(void);
Index: arith.h
===================================================================
RCS file: /home/cvs/src/bin/sh/arith.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/arith.h -L bin/sh/arith.h -u -r1.2 -r1.2.2.1
--- bin/sh/arith.h
+++ bin/sh/arith.h
@@ -28,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)arith.h	1.1 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/arith.h,v 1.9.8.1 2005/11/06 20:39:47 stefanf Exp $
+ * $FreeBSD: src/bin/sh/arith.h,v 1.9.8.3 2008/04/27 20:43:26 stefanf Exp $
  */
 
 extern char *arith_buf, *arith_startbuf;
Index: var.h
===================================================================
RCS file: /home/cvs/src/bin/sh/var.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/var.h -L bin/sh/var.h -u -r1.2 -r1.2.2.1
--- bin/sh/var.h
+++ bin/sh/var.h
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)var.h	8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/var.h,v 1.12 2004/04/06 20:06:51 markm Exp $
+ * $FreeBSD: src/bin/sh/var.h,v 1.12.8.1 2006/11/22 00:11:11 stefanf Exp $
  */
 
 /*
@@ -75,6 +75,7 @@
 extern struct var vppid;
 extern struct var vps1;
 extern struct var vps2;
+extern struct var vps4;
 #ifndef NO_HISTORY
 extern struct var vhistsize;
 #endif
@@ -92,6 +93,7 @@
 #define pathval()	(vpath.text + 5)
 #define ps1val()	(vps1.text + 4)
 #define ps2val()	(vps2.text + 4)
+#define ps4val()	(vps4.text + 4)
 #define optindval()	(voptind.text + 7)
 #ifndef NO_HISTORY
 #define histsizeval()	(vhistsize.text + 9)
Index: options.c
===================================================================
RCS file: /home/cvs/src/bin/sh/options.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/options.c -L bin/sh/options.c -u -r1.2 -r1.2.2.1
--- bin/sh/options.c
+++ bin/sh/options.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.23.2.1 2005/11/06 20:39:48 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.23.2.3 2008/04/20 18:08:46 stefanf Exp $");
 
 #include <signal.h>
 #include <unistd.h>
@@ -375,7 +375,7 @@
 	if (argc > 1)
 		n = number(argv[1]);
 	if (n > shellparam.nparam)
-		error("can't shift that many");
+		return 1;
 	INTOFF;
 	shellparam.nparam -= n;
 	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
@@ -384,7 +384,7 @@
 	}
 	ap2 = shellparam.p;
 	while ((*ap2++ = *ap1++) != NULL);
-	shellparam.optnext = NULL;
+	shellparam.reset = 1;
 	INTON;
 	return 0;
 }
@@ -406,6 +406,7 @@
 	if (*argptr != NULL) {
 		setparam(argptr);
 	}
+	shellparam.reset = 1;
 	INTON;
 	return 0;
 }
@@ -415,7 +416,6 @@
 getoptsreset(const char *value)
 {
 	if (number(value) == 1) {
-		shellparam.optnext = NULL;
 		shellparam.reset = 1;
 	}
 }
Index: main.c
===================================================================
RCS file: /home/cvs/src/bin/sh/main.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/main.c -L bin/sh/main.c -u -r1.2 -r1.2.2.1
--- bin/sh/main.c
+++ bin/sh/main.c
@@ -43,7 +43,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26.8.2 2006/11/22 00:23:09 stefanf Exp $");
 
 #include <stdio.h>
 #include <signal.h>
@@ -210,7 +210,7 @@
 		inter = 0;
 		if (iflag && top) {
 			inter++;
-			showjobs(1, 0, 0);
+			showjobs(1, SHOWJOBS_DEFAULT);
 			chkmail(0);
 			flushout(&output);
 		}
@@ -315,19 +315,21 @@
 dotcmd(int argc, char **argv)
 {
 	struct strlist *sp;
+	char *fullname;
+
+	if (argc < 2)
+		error("missing filename");
+
 	exitstatus = 0;
 
 	for (sp = cmdenviron; sp ; sp = sp->next)
 		setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
 
-	if (argc >= 2) {		/* That's what SVR2 does */
-		char *fullname = find_dot_file(argv[1]);
-
-		setinputfile(fullname, 1);
-		commandname = fullname;
-		cmdloop(0);
-		popfile();
-	}
+	fullname = find_dot_file(argv[1]);
+	setinputfile(fullname, 1);
+	commandname = fullname;
+	cmdloop(0);
+	popfile();
 	return exitstatus;
 }
 
Index: jobs.h
===================================================================
RCS file: /home/cvs/src/bin/sh/jobs.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/jobs.h -L bin/sh/jobs.h -u -r1.2 -r1.2.2.1
--- bin/sh/jobs.h
+++ bin/sh/jobs.h
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)jobs.h	8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/jobs.h,v 1.18 2004/04/06 20:06:51 markm Exp $
+ * $FreeBSD: src/bin/sh/jobs.h,v 1.18.8.1 2006/11/22 00:23:09 stefanf Exp $
  */
 
 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
@@ -75,6 +75,13 @@
 #endif
 };
 
+enum {
+	SHOWJOBS_DEFAULT,	/* job number, status, command */
+	SHOWJOBS_VERBOSE,	/* job number, PID, status, command */
+	SHOWJOBS_PIDS,		/* PID only */
+	SHOWJOBS_PGIDS		/* PID of the group leader only */
+};
+
 extern pid_t backgndpid;	/* pid of last background process */
 extern int job_warning;		/* user was warned about stopped jobs */
 extern int in_waitcmd;		/* are we in waitcmd()? */
@@ -85,7 +92,7 @@
 int fgcmd(int, char **);
 int bgcmd(int, char **);
 int jobscmd(int, char **);
-void showjobs(int, int, int);
+void showjobs(int, int);
 int waitcmd(int, char **);
 int jobidcmd(int, char **);
 struct job *makejob(union node *, int);
Index: TOUR
===================================================================
RCS file: /home/cvs/src/bin/sh/TOUR,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/TOUR -L bin/sh/TOUR -u -r1.2 -r1.2.2.1
--- bin/sh/TOUR
+++ bin/sh/TOUR
@@ -23,8 +23,8 @@
 programs that generate source code.  A complete list of these
 programs is:
 
-        program         intput files        generates
-        -------         ------------        ---------
+        program         input files         generates
+        -------         -----------         ---------
         mkbuiltins      builtins            builtins.h builtins.c
         mkinit          *.c                 init.c
         mknodes         nodetypes           nodes.h nodes.c
@@ -92,7 +92,7 @@
 EXINT exception to return to the main command loop.  (Exception:
 EXINT is not raised if the user traps interrupts using the trap
 command.)  The INTOFF and INTON macros (defined in exception.h)
-provide uninterruptable critical sections.  Between the execution
+provide uninterruptible critical sections.  Between the execution
 of INTOFF and the execution of INTON, interrupt signals will be
 held for later delivery.  INTOFF and INTON can be nested.
 
@@ -111,7 +111,7 @@
         p = stackptr;
         *p++ = c;       /* repeated as many times as needed */
         stackptr = p;
-The folloing three macros (defined in memalloc.h) perform these
+The following three macros (defined in memalloc.h) perform these
 operations, but grow the stack if you run off the end:
         STARTSTACKSTR(p);
         STPUTC(c, p);   /* repeated as many times as needed */
@@ -120,7 +120,7 @@
 We now start a top-down look at the code:
 
 MAIN.C:  The main routine performs some initialization, executes
-the user's profile if necessary, and calls cmdloop.  Cmdloop is
+the user's profile if necessary, and calls cmdloop.  Cmdloop
 repeatedly parses and executes commands.
 
 OPTIONS.C:  This file contains the option processing code.  It is
@@ -179,7 +179,7 @@
         VSQUESTION          ${var?text}
         VSQUESTION|VSNUL    ${var:?text}
         VSASSIGN            ${var=text}
-        VSASSIGN|VSNUL      ${var=text}
+        VSASSIGN|VSNUL      ${var:=text}
 
 In addition, the type field will have the VSQUOTE flag set if the
 variable is enclosed in double quotes.  The name of the variable
@@ -205,7 +205,7 @@
 field can be written without any processing).  Other here docu-
 ments, and words which are not subject to splitting and file name
 generation, have the CTLESC characters removed during the vari-
-able and command substitution phase.  Words which are subject
+able and command substitution phase.  Words which are subject to
 splitting and file name generation have the CTLESC characters re-
 moved as part of the file name phase.
 
@@ -213,7 +213,7 @@
         eval.c     The top level routines.
         redir.c    Code to handle redirection of input and output.
         jobs.c     Code to handle forking, waiting, and job control.
-        exec.c     Code to to path searches and the actual exec sys call.
+        exec.c     Code to do path searches and the actual exec sys call.
         expand.c   Code to evaluate arguments.
         var.c      Maintains the variable symbol table.  Called from expand.c.
 
@@ -233,7 +233,7 @@
 REDIR.C:  Ash allows file descriptors to be redirected and then
 restored without forking off a child process.  This is accom-
 plished by duplicating the original file descriptors.  The redir-
-tab structure records where the file descriptors have be dupli-
+tab structure records where the file descriptors have been dupli-
 cated to.
 
 EXEC.C:  The routine find_command locates a command, and enters
@@ -284,8 +284,8 @@
 tered throughout the code, depending on which location appears
 most appropriate.  They can be recognized because their names al-
 ways end in "cmd".  The mapping from names to procedures is
-specified in the file builtins, which is processed by the mkbuil-
-tins command.
+specified in the file builtins, which is processed by the mkbuilt-
+ins command.
 
 A builtin command is invoked with argc and argv set up like a
 normal program.  A builtin command is allowed to overwrite its
Index: eval.c
===================================================================
RCS file: /home/cvs/src/bin/sh/eval.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/eval.c -L bin/sh/eval.c -u -r1.2 -r1.2.2.1
--- bin/sh/eval.c
+++ bin/sh/eval.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42.8.2 2005/12/26 15:43:54 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42.8.6 2007/10/26 10:23:27 stefanf Exp $");
 
 #include <paths.h>
 #include <signal.h>
@@ -368,6 +368,7 @@
 	setstackmark(&smark);
 	arglist.lastp = &arglist.list;
 	oexitstatus = exitstatus;
+	exitstatus = 0;
 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
@@ -644,14 +645,19 @@
 
 	/* Print the command if xflag is set. */
 	if (xflag) {
-		outc('+', &errout);
+		char sep = 0;
+		out2str(ps4val());
 		for (sp = varlist.list ; sp ; sp = sp->next) {
-			outc(' ', &errout);
+			if (sep != 0)
+				outc(' ', &errout);
 			out2str(sp->text);
+			sep = ' ';
 		}
 		for (sp = arglist.list ; sp ; sp = sp->next) {
-			outc(' ', &errout);
+			if (sep != 0)
+				outc(' ', &errout);
 			out2str(sp->text);
+			sep = ' ';
 		}
 		outc('\n', &errout);
 		flushout(&errout);
@@ -659,8 +665,10 @@
 
 	/* Now locate the command. */
 	if (argc == 0) {
+		/* Variable assignment(s) without command */
 		cmdentry.cmdtype = CMDBUILTIN;
 		cmdentry.u.index = BLTINCMD;
+		cmdentry.special = 1;
 	} else {
 		static const char PATH[] = "PATH=";
 		char *path = pathval();
@@ -706,7 +714,8 @@
 				argv++;
 				if (--argc == 0)
 					break;
-				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
+				if ((cmdentry.u.index = find_builtin(*argv,
+				    &cmdentry.special)) < 0) {
 					outfmt(&errout, "%s: not found\n", *argv);
 					exitstatus = 127;
 					flushout(&errout);
@@ -813,7 +822,6 @@
 			memout.bufsize = 64;
 			mode |= REDIR_BACKQ;
 		}
-		redirect(cmd->ncmd.redirect, mode);
 		savecmdname = commandname;
 		cmdenviron = varlist.list;
 		e = -1;
@@ -824,6 +832,9 @@
 		}
 		savehandler = handler;
 		handler = &jmploc;
+		redirect(cmd->ncmd.redirect, mode);
+		if (cmdentry.special)
+			listsetvar(cmdenviron);
 		commandname = argv[0];
 		argptr = argv + 1;
 		optptr = NULL;			/* initialize nextopt */
@@ -843,14 +854,7 @@
 		handler = savehandler;
 		if (e != -1) {
 			if ((e != EXERROR && e != EXEXEC)
-			   || cmdentry.u.index == BLTINCMD
-			   || cmdentry.u.index == DOTCMD
-			   || cmdentry.u.index == EVALCMD
-#ifndef NO_HISTORY
-			   || cmdentry.u.index == HISTCMD
-#endif
-			   || cmdentry.u.index == EXECCMD
-			   || cmdentry.u.index == COMMANDCMD)
+			    || cmdentry.special)
 				exraise(e);
 			FORCEINTON;
 		}
@@ -912,7 +916,7 @@
 {
 	struct cmdentry entry;
 
-	if (n->type == NCMD && n->ncmd.args)
+	if (n && n->type == NCMD && n->ncmd.args)
 		if (goodname(n->ncmd.args->narg.text))
 			find_command(n->ncmd.args->narg.text, &entry, 0,
 				     pathval());
@@ -926,14 +930,12 @@
  */
 
 /*
- * No command given, or a bltin command with no arguments.  Set the
- * specified variables.
+ * No command given, or a bltin command with no arguments.
  */
 
 int
 bltincmd(int argc __unused, char **argv __unused)
 {
-	listsetvar(cmdenviron);
 	/*
 	 * Preserve exitstatus of a previous possible redirection
 	 * as POSIX mandates
Index: parser.h
===================================================================
RCS file: /home/cvs/src/bin/sh/parser.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/parser.h -L bin/sh/parser.h -u -r1.2 -r1.2.2.1
--- bin/sh/parser.h
+++ bin/sh/parser.h
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)parser.h	8.3 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/parser.h,v 1.10 2004/04/06 20:06:51 markm Exp $
+ * $FreeBSD: src/bin/sh/parser.h,v 1.10.8.1 2006/11/22 00:26:06 stefanf Exp $
  */
 
 /* control characters in argument strings */
@@ -61,6 +61,7 @@
 #define VSTRIMRIGHT	0x8		/* ${var%pattern} */
 #define VSTRIMRIGHTMAX 	0x9		/* ${var%%pattern} */
 #define VSLENGTH	0xa		/* ${#var} */
+#define VSERROR		0xb		/* Syntax error, issue when expanded */
 
 
 /*
Index: builtins.def
===================================================================
RCS file: /home/cvs/src/bin/sh/builtins.def,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/builtins.def -L bin/sh/builtins.def -u -r1.2 -r1.2.2.1
--- bin/sh/builtins.def
+++ bin/sh/builtins.def
@@ -37,13 +37,15 @@
 
 #
 # This file lists all the builtin commands.  The first column is the name
-# of a C routine.  The -j flag, if present, specifies that this command
-# is to be excluded from systems without job control, and the -h flag,
-# if present specifies that this command is to be excluded from systems
-# based on the NO_HISTORY compile-time symbol.  The rest of the line
-# specifies the command name or names used to run the command.  The entry
-# for bltincmd, which is run when the user does not specify a command, must
-# come first.
+# of a C routine.
+# The -j flag specifies that this command is to be excluded from systems
+# without job control.
+# The -h flag specifies that this command is to be excluded from systems
+# based on the NO_HISTORY compile-time symbol.
+# The -s flag specifies that this is a POSIX 'special built-in' command.
+# The rest of the line specifies the command name or names used to run the
+# command.  The entry for bltincmd, which is run when the user does not specify
+# a command, must come first.
 #
 # NOTE: bltincmd must come first!
 
@@ -51,16 +53,16 @@
 aliascmd	alias
 bgcmd -j	bg
 bindcmd		bind
-breakcmd	break continue
+breakcmd	-s break -s continue
 cdcmd		cd chdir
 commandcmd	command
-dotcmd		.
+dotcmd		-s .
 echocmd		echo
-evalcmd		eval
-execcmd		exec
-exitcmd		exit
+evalcmd		-s eval
+execcmd		-s exec
+exitcmd		-s exit
 expcmd		exp let
-exportcmd	export readonly
+exportcmd	-s export -s readonly
 #exprcmd		expr
 falsecmd	false
 fgcmd -j	fg
@@ -73,18 +75,18 @@
 #printfcmd	printf
 pwdcmd		pwd
 readcmd		read
-returncmd	return
-setcmd		set
+returncmd	-s return
+setcmd		-s set
 setvarcmd	setvar
-shiftcmd	shift
+shiftcmd	-s shift
 testcmd		test [
-timescmd	times
-trapcmd		trap
-truecmd		: true
+timescmd	-s times
+trapcmd		-s trap
+truecmd		-s : true
 typecmd		type
 ulimitcmd	ulimit
 umaskcmd	umask
 unaliascmd	unalias
-unsetcmd	unset
+unsetcmd	-s unset
 waitcmd		wait
 wordexpcmd	wordexp
Index: parser.c
===================================================================
RCS file: /home/cvs/src/bin/sh/parser.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/parser.c -L bin/sh/parser.c -u -r1.2 -r1.2.2.1
--- bin/sh/parser.c
+++ bin/sh/parser.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.52.2.1 2005/11/06 20:39:48 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.52.2.3 2006/11/22 00:26:06 stefanf Exp $");
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -953,6 +953,7 @@
 					USTPUTC('\\', out);
 					pungetc();
 				} else if (c == '\n') {
+					plinno++;
 					if (doprompt)
 						setprompt(2);
 					else
@@ -1228,12 +1229,17 @@
 				c = pgetc();
 			}
 		} else {
-			if (! is_special(c))
-badsub:				synerror("Bad substitution");
-			USTPUTC(c, out);
-			c = pgetc();
+			if (! is_special(c)) {
+				subtype = VSERROR;
+				if (c == '}')
+					pungetc();
+				else
+					USTPUTC(c, out);
+			} else {
+				USTPUTC(c, out);
+				c = pgetc();
+			}
 		}
-		STPUTC('=', out);
 		flags = 0;
 		if (subtype == 0) {
 			switch (c) {
@@ -1243,9 +1249,13 @@
 				/*FALLTHROUGH*/
 			default:
 				p = strchr(types, c);
-				if (p == NULL)
-					goto badsub;
-				subtype = p - types + VSNORMAL;
+				if (p == NULL) {
+					if (flags == VSNUL)
+						STPUTC(':', out);
+					STPUTC(c, out);
+					subtype = VSERROR;
+				} else
+					subtype = p - types + VSNORMAL;
 				break;
 			case '%':
 			case '#':
@@ -1261,9 +1271,10 @@
 					break;
 				}
 			}
-		} else {
+		} else if (subtype != VSERROR) {
 			pungetc();
 		}
+		STPUTC('=', out);
 		if (subtype != VSLENGTH && (dblquote || arinest))
 			flags |= VSQUOTE;
 		*(stackblock() + typeloc) = subtype | flags;
Index: jobs.c
===================================================================
RCS file: /home/cvs/src/bin/sh/jobs.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/jobs.c -L bin/sh/jobs.c -u -r1.2 -r1.2.2.1
--- bin/sh/jobs.c
+++ bin/sh/jobs.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.68.2.2 2006/01/12 05:24:46 maxim Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.68.2.3 2006/11/22 00:23:09 stefanf Exp $");
 
 #include <fcntl.h>
 #include <signal.h>
@@ -99,7 +99,7 @@
 STATIC void deljob(struct job *);
 STATIC struct job *getcurjob(struct job *);
 #endif
-STATIC void showjob(struct job *, pid_t, int, int);
+STATIC void showjob(struct job *, pid_t, int);
 
 
 /*
@@ -266,18 +266,21 @@
 jobscmd(int argc, char *argv[])
 {
 	char *id;
-	int ch, sformat, lformat;
+	int ch, mode;
 
 	optind = optreset = 1;
 	opterr = 0;
-	sformat = lformat = 0;
-	while ((ch = getopt(argc, argv, "ls")) != -1) {
+	mode = SHOWJOBS_DEFAULT;
+	while ((ch = getopt(argc, argv, "lps")) != -1) {
 		switch (ch) {
 		case 'l':
-			lformat = 1;
+			mode = SHOWJOBS_VERBOSE;
+			break;
+		case 'p':
+			mode = SHOWJOBS_PGIDS;
 			break;
 		case 's':
-			sformat = 1;
+			mode = SHOWJOBS_PIDS;
 			break;
 		case '?':
 		default:
@@ -288,24 +291,25 @@
 	argv += optind;
 
 	if (argc == 0)
-		showjobs(0, sformat, lformat);
+		showjobs(0, mode);
 	else
 		while ((id = *argv++) != NULL)
-			showjob(getjob(id), 0, sformat, lformat);
+			showjob(getjob(id), 0, mode);
 
 	return (0);
 }
 
 STATIC void
-showjob(struct job *jp, pid_t pid, int sformat, int lformat)
+showjob(struct job *jp, pid_t pid, int mode)
 {
 	char s[64];
 	struct procstat *ps;
 	struct job *j;
 	int col, curr, i, jobno, prev, procno;
+	pid_t ppid;
 	char c;
 
-	procno = jp->nprocs;
+	procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
 	jobno = jp - jobtab + 1;
 	curr = prev = 0;
 #if JOBS
@@ -316,11 +320,13 @@
 	}
 #endif
 	for (ps = jp->ps ; ; ps++) {	/* for each process */
-		if (sformat) {
-			out1fmt("%d\n", (int)ps->pid);
+		if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
+			ppid = (mode == SHOWJOBS_PIDS) ? ps->pid :
+			    getpgid(ps->pid);
+			out1fmt("%d\n", (int)ppid);
 			goto skip;
 		}
-		if (!lformat && ps != jp->ps && pid == 0)
+		if (mode != SHOWJOBS_VERBOSE && ps != jp->ps && pid == 0)
 			goto skip;
 		if (pid != 0 && pid != ps->pid)
 			goto skip;
@@ -336,7 +342,7 @@
 			fmtstr(s, 64, "    %c ", c);
 		out1str(s);
 		col = strlen(s);
-		if (lformat) {
+		if (mode == SHOWJOBS_VERBOSE) {
 			fmtstr(s, 64, "%d ", (int)ps->pid);
 			out1str(s);
 			col += strlen(s);
@@ -389,7 +395,7 @@
  */
 
 void
-showjobs(int change, int sformat, int lformat)
+showjobs(int change, int mode)
 {
 	int jobno;
 	struct job *jp;
@@ -405,7 +411,7 @@
 		}
 		if (change && ! jp->changed)
 			continue;
-		showjob(jp, 0, sformat, lformat);
+		showjob(jp, 0, mode);
 		jp->changed = 0;
 		if (jp->state == JOBDONE) {
 			freejob(jp);
@@ -993,7 +999,7 @@
 					out1str(" (core dumped)");
 				out1c('\n');
 			} else
-				showjob(thisjob, pid, 0, 0);
+				showjob(thisjob, pid, SHOWJOBS_DEFAULT);
 		}
 	} else {
 		TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
Index: shell.h
===================================================================
RCS file: /home/cvs/src/bin/sh/shell.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/shell.h -L bin/sh/shell.h -u -r1.2 -r1.2.2.1
--- bin/sh/shell.h
+++ bin/sh/shell.h
@@ -31,9 +31,14 @@
  * SUCH DAMAGE.
  *
  *	@(#)shell.h	8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $
+ * $FreeBSD: src/bin/sh/shell.h,v 1.18 2008/04/27 20:46:45 stefanf Exp $
  */
 
+#ifndef SHELL_H_
+#define SHELL_H_
+
+#include <inttypes.h>
+
 /*
  * The follow should be set to reflect the type of system you have:
  *	JOBS -> 1 if you have Berkeley job control, 0 otherwise.
@@ -51,10 +56,10 @@
 /*
  * Type of used arithmetics. SUSv3 requires us to have at least signed long.
  */
-typedef long arith_t;
-#define	ARITH_FORMAT_STR  "%ld"
-#define	atoarith_t(arg)  strtol(arg, NULL, 0)
-#define	strtoarith_t(nptr, endptr, base)  strtol(nptr, endptr, base)
+typedef intmax_t arith_t;
+#define	ARITH_FORMAT_STR  "%" PRIdMAX
+#define	atoarith_t(arg)  strtoimax(arg, NULL, 0)
+#define	strtoarith_t(nptr, endptr, base)  strtoimax(nptr, endptr, base)
 
 typedef void *pointer;
 #define STATIC  static
@@ -69,3 +74,5 @@
 #else
 #define TRACE(param)
 #endif
+
+#endif /* !SHELL_H_ */
Index: sh.1
===================================================================
RCS file: /home/cvs/src/bin/sh/sh.1,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/sh.1 -L bin/sh/sh.1 -u -r1.2 -r1.2.2.1
--- bin/sh/sh.1
+++ bin/sh/sh.1
@@ -33,7 +33,7 @@
 .\" $FreeBSD: src/bin/sh/sh.1,v 1.102.2.2 2005/12/26 15:43:54 stefanf Exp $
 .\" $MidnightBSD$
 .\"
-.Dd December 8, 2005
+.Dd June 29, 2008
 .Dt SH 1
 .Os
 .Sh NAME
@@ -306,8 +306,9 @@
 Useful for debugging.
 .It Fl x Li xtrace
 Write each command
-(preceded by
-.Dq Li "+ " )
+(preceded by the value of the 
+.Ev PS4
+variable)
 to standard error before it is executed.
 Useful for debugging.
 .El
@@ -363,6 +364,13 @@
 .It Li <& Ta Li >& Ta Li <<- Ta Li >|
 .El
 .El
+.Pp
+The character
+.Ql #
+introduces a comment if used at the beginning of a word.
+The word starting with
+.Ql #
+and the rest of the line are ignored.
 .Ss Quoting
 Quoting is used to remove the special meaning of certain characters
 or words to the shell, such as operators, whitespace, keywords,
@@ -854,6 +862,10 @@
 separated by
 .Dq Li \&|
 characters.
+The exit code of the
+.Ic case
+command is the exit code of the last command executed in the list or
+zero if no patterns were matched.
 .Ss Grouping Commands Together
 Commands may be grouped by writing either
 .Bd -literal -offset indent
@@ -1354,9 +1366,8 @@
 are built-in because they need to perform some operation
 that cannot be performed by a separate process.
 In addition to
-these, a built-in version of the
-.Xr test 1
-command is provided for efficiency.
+these, built-in versions of essential utilities
+are provided for efficiency.
 .Bl -tag -width indent
 .It Ic \&:
 A null command that returns a 0 (true) exit value.
@@ -1378,6 +1389,9 @@
 If it is not found in the
 .Ev PATH ,
 it is sought in the current working directory.
+.It Ic \&[
+A built-in equivalent of
+.Xr test 1 .
 .It Ic alias Oo Ar name Ns Oo = Ns Ar string Oc ... Oc
 If
 .Ar name Ns = Ns Ar string
@@ -1612,6 +1626,8 @@
 option is specified, the exported variables are printed as
 .Dq Ic export Ar name Ns = Ns Ar value
 lines, suitable for re-input to the shell.
+.It Ic false
+A null command that returns a non-zero (false) exit value.
 .It Ic fc Oo Fl e Ar editor Oc Op Ar first Op Ar last
 .It Ic fc Fl l Oo Fl nr Oc Op Ar first Op Ar last
 .It Ic fc Fl s Oo Ar old Ns = Ns Ar new Oc Op Ar first
@@ -1766,7 +1782,7 @@
 If the
 .Ar job
 argument is omitted, use the current job.
-.It Ic jobs Oo Fl ls Oc Op Ar job ...
+.It Ic jobs Oo Fl lps Oc Op Ar job ...
 Print information about the specified jobs, or all jobs if no
 .Ar job
 argument is given.
@@ -1776,8 +1792,13 @@
 .Fl l
 option is specified, the PID of each job is also printed.
 If the
+.Fl p
+option is specified, only the process IDs for the process group leaders
+are printed, one per line.
+If the
 .Fl s
-option is specified, only the PIDs of the jobs are printed, one per line.
+option is specified, only the PIDs of the job commands are printed, one per
+line.
 .It Ic local Oo Ar variable ... Oc Op Fl
 See the
 .Sx Functions
@@ -1952,6 +1973,9 @@
 the value of $2 to the value of $3, and so on,
 decreasing the value of $# by one.
 If there are zero positional parameters, shifting does not do anything.
+.It Ic test
+A built-in equivalent of
+.Xr test 1 .
 .It Ic times
 Print the amount of time spent executing the shell and its children.
 The first output line shows the user and system times for the shell
@@ -1989,6 +2013,8 @@
 causes the
 .Ic trap
 command to display a list of valid signal names.
+.It Ic true
+A null command that returns a 0 (true) exit value.
 .It Ic type Op Ar name ...
 Interpret each
 .Ar name
@@ -2191,6 +2217,12 @@
 .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 "+ " .
 .It Ev TERM
 The default terminal setting for the shell.
 This is inherited by children of the shell, and is used in the history
@@ -2222,8 +2254,23 @@
 .Sh HISTORY
 A
 .Nm
-command appeared in
+command, the Thompson shell, appeared in
 .At v1 .
+It was superseded in
+.At v7
+by the Bourne shell, which inherited the name
+.Nm .
+.Pp
+This version of
+.Nm
+was rewritten in 1989 under the
+.Bx
+license after the Bourne shell from
+.At V.4 .
+.Sh AUTHORS
+This version of
+.Nm
+was originally written by Kenneth Almquist.
 .Sh BUGS
 The
 .Nm
Index: arith.y
===================================================================
RCS file: /home/cvs/src/bin/sh/arith.y,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/arith.y -L bin/sh/arith.y -u -r1.2 -r1.2.2.1
--- bin/sh/arith.y
+++ bin/sh/arith.y
@@ -40,7 +40,7 @@
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19.8.1 2005/11/06 20:39:47 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19.8.3 2008/04/27 20:43:26 stefanf Exp $");
 
 #include <limits.h>
 #include <stdio.h>
Index: input.c
===================================================================
RCS file: /home/cvs/src/bin/sh/input.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/input.c -L bin/sh/input.c -u -r1.2 -r1.2.2.1
--- bin/sh/input.c
+++ bin/sh/input.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22.8.1 2006/06/03 15:38:07 stefanf Exp $");
 
 #include <stdio.h>	/* defines BUFSIZ */
 #include <fcntl.h>
@@ -185,14 +185,23 @@
 retry:
 #ifndef NO_HISTORY
 	if (parsefile->fd == 0 && el) {
-		const char *rl_cp;
+		static const char *rl_cp;
+		static int el_len;
 
-		rl_cp = el_gets(el, &nr);
+		if (rl_cp == NULL)
+			rl_cp = el_gets(el, &el_len);
 		if (rl_cp == NULL)
 			nr = 0;
 		else {
-			/* XXX - BUFSIZE should redesign so not necessary */
-			(void) strcpy(parsenextc, rl_cp);
+			nr = el_len;
+			if (nr > BUFSIZ - 1)
+				nr = BUFSIZ - 1;
+			memcpy(parsenextc, rl_cp, nr);
+			if (nr != el_len) {
+				el_len -= nr;
+				rl_cp += nr;
+			} else
+				rl_cp = NULL;
 		}
 	} else
 #endif
Index: cd.c
===================================================================
RCS file: /home/cvs/src/bin/sh/cd.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -L bin/sh/cd.c -L bin/sh/cd.c -u -r1.3 -r1.3.2.1
--- bin/sh/cd.c
+++ bin/sh/cd.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34.8.2 2008/04/20 18:08:12 stefanf Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -69,7 +69,9 @@
 STATIC int cdphysical(char *);
 STATIC int docd(char *, int, int);
 STATIC char *getcomponent(void);
-STATIC int updatepwd(char *);
+STATIC char *findcwd(char *);
+STATIC void updatepwd(char *);
+STATIC char *getpwd2(char *, size_t);
 
 STATIC char *curdir = NULL;	/* current working directory */
 STATIC char *prevdir;		/* previous working directory */
@@ -202,10 +204,11 @@
 	}
 
 	INTOFF;
-	if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) {
+	if ((p = findcwd(badstat ? NULL : dest)) == NULL || chdir(p) < 0) {
 		INTON;
 		return (-1);
 	}
+	updatepwd(p);
 	INTON;
 	return (0);
 }
@@ -213,12 +216,14 @@
 STATIC int
 cdphysical(char *dest)
 {
+	char *p;
 
 	INTOFF;
-	if (chdir(dest) < 0 || updatepwd(NULL) < 0) {
+	if (chdir(dest) < 0 || (p = findcwd(NULL)) == NULL) {
 		INTON;
 		return (-1);
 	}
+	updatepwd(p);
 	INTON;
 	return (0);
 }
@@ -248,38 +253,20 @@
 }
 
 
-/*
- * Update curdir (the name of the current directory) in response to a
- * cd command.  We also call hashcd to let the routines in exec.c know
- * that the current directory has changed.
- */
-STATIC int
-updatepwd(char *dir)
+STATIC char *
+findcwd(char *dir)
 {
 	char *new;
 	char *p;
 
-	hashcd();				/* update command hash table */
-
 	/*
 	 * If our argument is NULL, we don't know the current directory
 	 * any more because we traversed a symbolic link or something
 	 * we couldn't stat().
 	 */
 	if (dir == NULL || curdir == NULL)  {
-		if (prevdir)
-			ckfree(prevdir);
-		INTOFF;
-		prevdir = curdir;
-		curdir = NULL;
-		if (getpwd() == NULL) {
-			INTON;
-			return (-1);
-		}
-		setvar("PWD", curdir, VEXPORT);
-		setvar("OLDPWD", prevdir, VEXPORT);
-		INTON;
-		return (0);
+		p = stalloc(PATH_MAX);
+		return getpwd2(p, PATH_MAX);
 	}
 	cdcomppath = stalloc(strlen(dir) + 1);
 	scopy(dir, cdcomppath);
@@ -303,16 +290,25 @@
 	if (new == stackblock())
 		STPUTC('/', new);
 	STACKSTRNUL(new);
-	INTOFF;
+	return stackblock();
+}
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.  We also call hashcd to let the routines in exec.c know
+ * that the current directory has changed.
+ */
+STATIC void
+updatepwd(char *dir)
+{
+	hashcd();				/* update command hash table */
+
 	if (prevdir)
 		ckfree(prevdir);
 	prevdir = curdir;
-	curdir = savestr(stackblock());
+	curdir = savestr(dir);
 	setvar("PWD", curdir, VEXPORT);
 	setvar("OLDPWD", prevdir, VEXPORT);
-	INTON;
-
-	return (0);
 }
 
 int
@@ -356,17 +352,31 @@
 }
 
 /*
- * Find out what the current directory is. If we already know the current
- * directory, this routine returns immediately.
+ * Get the current directory and cache the result in curdir.
  */
 char *
 getpwd(void)
 {
 	char buf[PATH_MAX];
+	char *p;
 
 	if (curdir)
 		return curdir;
-	if (getcwd(buf, sizeof(buf)) == NULL) {
+
+	p = getpwd2(buf, sizeof(buf));
+	if (p != NULL)
+		curdir = savestr(p);
+
+	return curdir;
+}
+
+/*
+ * Return the current directory.
+ */
+STATIC char *
+getpwd2(char *buf, size_t size)
+{
+	if (getcwd(buf, size) == NULL) {
 		char *pwd = getenv("PWD");
 		struct stat stdot, stpwd;
 
@@ -374,12 +384,9 @@
 		    stat(pwd, &stpwd) != -1 &&
 		    stdot.st_dev == stpwd.st_dev &&
 		    stdot.st_ino == stpwd.st_ino) {
-			curdir = savestr(pwd);
-			return curdir;
+			return pwd;
 		}
 		return NULL;
 	}
-	curdir = savestr(buf);
-
-	return curdir;
+	return buf;
 }
Index: var.c
===================================================================
RCS file: /home/cvs/src/bin/sh/var.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -L bin/sh/var.c -L bin/sh/var.c -u -r1.2 -r1.2.2.1
--- bin/sh/var.c
+++ bin/sh/var.c
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.27.2.1 2005/11/06 20:39:48 stefanf Exp $");
+__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.27.2.3 2006/11/22 00:11:11 stefanf Exp $");
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -89,6 +89,7 @@
 struct var vppid;
 struct var vps1;
 struct var vps2;
+struct var vps4;
 struct var vvers;
 STATIC struct var voptind;
 
@@ -112,6 +113,8 @@
 	 */
 	{ &vps2,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",
 	  NULL },
+	{ &vps4,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",
+	  NULL },
 	{ &voptind,	VSTRFIXED|VTEXTFIXED,		"OPTIND=1",
 	  getoptsreset },
 	{ NULL,	0,				NULL,
@@ -480,6 +483,21 @@
 }
 
 
+static int
+var_compare(const void *a, const void *b)
+{
+	const char *const *sa, *const *sb;
+
+	sa = a;
+	sb = b;
+	/*
+	 * This compares two var=value strings which creates a different
+	 * order from what you would probably expect.  POSIX is somewhat
+	 * ambiguous on what should be sorted exactly.
+	 */
+	return strcoll(*sa, *sb);
+}
+
 
 /*
  * Command to list all variables which are set.  Currently this command
@@ -493,18 +511,41 @@
 	struct var **vpp;
 	struct var *vp;
 	const char *s;
+	const char **vars;
+	int i, n;
 
-	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-		for (vp = *vpp ; vp ; vp = vp->next) {
-			if (vp->flags & VUNSET)
-				continue;
-			for (s = vp->text; *s != '='; s++)
-				out1c(*s);
-			out1c('=');
-			out1qstr(s + 1);
-			out1c('\n');
+	/*
+	 * POSIX requires us to sort the variables.
+	 */
+	n = 0;
+	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+		for (vp = *vpp; vp; vp = vp->next) {
+			if (!(vp->flags & VUNSET))
+				n++;
+		}
+	}
+
+	INTON;
+	vars = ckmalloc(n * sizeof(*vars));
+	i = 0;
+	for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+		for (vp = *vpp; vp; vp = vp->next) {
+			if (!(vp->flags & VUNSET))
+				vars[i++] = vp->text;
 		}
 	}
+
+	qsort(vars, n, sizeof(*vars), var_compare);
+	for (i = 0; i < n; i++) {
+		for (s = vars[i]; *s != '='; s++)
+			out1c(*s);
+		out1c('=');
+		out1qstr(s + 1);
+		out1c('\n');
+	}
+	ckfree(vars);
+	INTOFF;
+
 	return 0;
 }
 


More information about the Midnightbsd-cvs mailing list