Module Name:    src
Committed By:   kre
Date:           Thu May 18 13:53:18 UTC 2017

Modified Files:
        src/bin/sh: options.c options.h sh.1

Log Message:
Command line, and "set" command options processing cleanup.

sh +c "command string"  no longer works (it must be -c)
sh +o   and   sh -o     no longer work (if you could call what they did
                        before working.)  nb: this is without an option name.
-ooo Opt1 Opt2 Opt3     no longer works (set & cmd line), this should be
                        -o Opt1 -o Opt2 -o Opt3   (same with +ooo of course).
-oOpt                   is now supported - option value (name of option in
                        this case) immediately following -o (or +o).
                        (as with other commands that use std opt parsing)
                        Both set comamnd and command line.

In addition, the output from "set +o" has shrunk dramatically, by borrowing
a trick from ksh93 (but implemented in a more traditional syntax).
"set +o" is required to produce a command (or commands) which when executed
later, will return all options to the state they were in when "set +o"
was done.  Previously that was done by generating a set command, with
every option listed (set -o opt +o other-opt ...) to set them all back
to their current setings.   Now we have a new "magic option" ("default")
which sets all options to their default values, so now set +o output
need only be "set -o default -o changed-opt ..." (only the options that
have been changed from their default values need be explicitly mentioned.)
The definition of "default value" for this is the value the shell set the
option to, after startup, after processing the command line (with any
flags, or -o option type settings), but before beginning processing any
user input (incuding startup files, like $ENV etc).

Anyone can execute "set -o default" of course, but only from a "set"
command (it makes no sense at all as a -o option to sh).   This also
causes "set +o" to be slightly more useful as a general command, as
ignoring the "set -o default" part of the result, it lists just those
options that have been altered after sh startup.  There is no +o default.
There isn't an option called "default" at all...

This causes some of the commented out text from sh.1 to become uncommented.


To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/bin/sh/options.c
cvs rdiff -u -r1.25 -r1.26 src/bin/sh/options.h
cvs rdiff -u -r1.141 -r1.142 src/bin/sh/sh.1

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/options.c
diff -u src/bin/sh/options.c:1.47 src/bin/sh/options.c:1.48
--- src/bin/sh/options.c:1.47	Mon May 15 20:00:36 2017
+++ src/bin/sh/options.c	Thu May 18 13:53:18 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: options.c,v 1.47 2017/05/15 20:00:36 kre Exp $	*/
+/*	$NetBSD: options.c,v 1.48 2017/05/18 13:53:18 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)options.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: options.c,v 1.47 2017/05/15 20:00:36 kre Exp $");
+__RCSID("$NetBSD: options.c,v 1.48 2017/05/18 13:53:18 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -88,13 +88,23 @@ void
 procargs(int argc, char **argv)
 {
 	size_t i;
+	int psx;
 
 	argptr = argv;
 	if (argc > 0)
 		argptr++;
+
+	psx = posix;		/* save what we set it to earlier */
+	/*
+	 * option values are mostly boolean 0:off 1:on
+	 * we use 2 (just in this routine) to mean "unknown yet"
+	 */
 	for (i = 0; i < NOPTS; i++)
 		optlist[i].val = 2;
+	posix = psx;		/* restore before processing -o ... */
+
 	options(1);
+
 	if (*argptr == NULL && minusc == NULL)
 		sflag = 1;
 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
@@ -107,12 +117,24 @@ procargs(int argc, char **argv)
 	if (usefork == 2)
 		usefork = 1;
 #endif
-	for (i = 0; i < NOPTS; i++)
-		if (optlist[i].val == 2)
-			optlist[i].val = 0;
 #if DEBUG == 2
-	debug = 1;
+	if (debug == 2)
+		debug = 1;
 #endif
+	/*
+	 * Any options not dealt with as special cases just above,
+	 * and which were not set on the command line, are set to
+	 * their expected default values (mostly "off")
+	 *
+	 * then as each option is initialised, save its setting now
+	 * as its "default" value for future use ("set -o default").
+	 */
+	for (i = 0; i < NOPTS; i++) {
+		if (optlist[i].val == 2)
+			optlist[i].val = optlist[i].dflt;
+		optlist[i].dflt = optlist[i].val;
+	}
+
 	arg0 = argv[0];
 	if (sflag == 0 && minusc == NULL) {
 		commandname = argv[0];
@@ -187,13 +209,20 @@ options(int cmdline)
 			break;
 		}
 		while ((c = *p++) != '\0') {
-			if (c == 'c' && cmdline) {
+			if (val == 1 && c == 'c' && cmdline) {
 				/* command is after shell args*/
 				minusc = empty;
 			} else if (c == 'o') {
-				minus_o(*argptr, val);
-				if (*argptr)
-					argptr++;
+				if (*p != '\0')
+					minus_o(p, val + (cmdline ? val : 0));
+				else if (*argptr)
+					minus_o(*argptr++,
+					    val + (cmdline ? val : 0));
+				else if (!cmdline)
+					minus_o(NULL, val);
+				else
+					error("arg for %co missing", "+-"[val]);
+				break;
 #ifdef DEBUG
 			} else if (c == 'D') {
 				if (*p) {
@@ -250,12 +279,14 @@ minus_o(char *name, int val)
 			out1c('\n');
 			for (i = 0; i < NOPTS; i++) {
 				if (optlist[i].name)
-				    out1fmt("%-16s%s\n", optlist[i].name,
+				    out1fmt("%-19s %s\n", optlist[i].name,
 					optlist[i].val ? "on" : "off");
 			}
 		} else {
-			out1str("set");
+			out1str("set -o default");
 			for (i = 0; i < NOPTS; i++) {
+				if (optlist[i].val == optlist[i].dflt)
+					continue;
 				if (optlist[i].name)
 				    out1fmt(" %co %s",
 					"+-"[optlist[i].val], optlist[i].name);
@@ -266,12 +297,19 @@ minus_o(char *name, int val)
 			out1c('\n');
 		}
 	} else {
+		if (val == 1 && equal(name, "default")) { /* special case */
+			for (i = 0; i < NOPTS; i++)
+				set_opt_val(i, optlist[i].dflt);
+			return;
+		}
+		if (val)
+			val = 1;
 		for (i = 0; i < NOPTS; i++)
 			if (optlist[i].name && equal(name, optlist[i].name)) {
 				set_opt_val(i, val);
 				return;
 			}
-		error("Illegal option -o %s", name);
+		error("Illegal option %co %s", "+-"[val], name);
 	}
 }
 
@@ -286,7 +324,7 @@ setoption(int flag, int val)
 			set_opt_val( i, val );
 			return;
 		}
-	error("Illegal option -%c", flag);
+	error("Illegal option %c%c", "+-"[val], flag);
 	/* NOTREACHED */
 }
 

Index: src/bin/sh/options.h
diff -u src/bin/sh/options.h:1.25 src/bin/sh/options.h:1.26
--- src/bin/sh/options.h:1.25	Thu Mar 31 16:16:35 2016
+++ src/bin/sh/options.h	Thu May 18 13:53:18 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: options.h,v 1.25 2016/03/31 16:16:35 christos Exp $	*/
+/*	$NetBSD: options.h,v 1.26 2017/05/18 13:53:18 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -43,23 +43,29 @@ struct shparam {
 	char *optptr;		/* used by getopts */
 };
 
-
+/*
+ * Note that option default values can be changed at shell startup
+ * depending upon the environment in which the shell is running.
+ */
 struct optent {
 	const char *name;		/* for set -o <name> */
 	const char letter;		/* set [+/-]<letter> and $- */
 	const char opt_set;		/* mutually exclusive option set */
 	unsigned char val;		/* value of <letter>flag */
+	unsigned char dflt;		/* default value of flag */
 };
 
 /* Those marked [U] are required by posix, but have no effect! */
 
 #ifdef DEFINE_OPTIONS
-#define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0},
+#define DEF_OPTS_D(name,letter,opt_set,dflt) {name, letter, opt_set, 0, dflt },
 struct optent optlist[] = {
 #else
-#define DEF_OPTS(name, letter, opt_set)
+#define DEF_OPTS_D(name,letter,opt_set,dflt)
 #endif
-#define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0)
+#define DEF_OPTS(name,letter,opt_set)	DEF_OPTS_D(name, letter, opt_set, 0)
+#define DEF_OPT(name,letter)		DEF_OPTS_D(name, letter, 0, 0)
+#define DEF_OPT_D(name,letter,dflt)	DEF_OPTS_D(name, letter, 0, dflt)
 
 DEF_OPT( "errexit",	'e' )	/* exit on error */
 #define eflag optlist[0].val
@@ -113,7 +119,7 @@ DEF_OPT( "debug",	0 )	/* enable debug pr
 #endif
 
 #ifdef DEFINE_OPTIONS
-	{ 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0 },
 };
 #define NOPTS (sizeof optlist / sizeof optlist[0] - 1)
 int sizeof_optlist = sizeof optlist;

Index: src/bin/sh/sh.1
diff -u src/bin/sh/sh.1:1.141 src/bin/sh/sh.1:1.142
--- src/bin/sh/sh.1:1.141	Sun May 14 17:27:05 2017
+++ src/bin/sh/sh.1	Thu May 18 13:53:18 2017
@@ -1,4 +1,4 @@
-.\"	$NetBSD: sh.1,v 1.141 2017/05/14 17:27:05 kre Exp $
+.\"	$NetBSD: sh.1,v 1.142 2017/05/18 13:53:18 kre Exp $
 .\" Copyright (c) 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
@@ -212,8 +212,8 @@ Specifying a dash
 turns the option on, while using a plus
 .Dq +
 disables the option.
-The following options can be set from the command line or
-with the
+The following options can be set from the command line and,
+unless otherwise stated, with the
 .Ic set
 built-in (described later).
 .Bl -tag -width \-WXXlineno_fn_relativeXX -offset indent
@@ -2231,33 +2231,40 @@ If options are given, it sets the specif
 flags, or clears them as described in the
 .Sx Argument List Processing
 section.
-.\" In addition to the options listed there,
-.\" when the
-.\" .Dq "option name"
-.\" given to
-.\" .Fl o
-.\" is
-.\" .Cm default
-.\" all of the options are reset to the values they had immediately
-.\" after
-.\" .Nm
-.\" initialization, before any startup scripts had been processed.
-.\" While this may be of use to users or scripts, its primary purpose
-.\" is for use in the output of
-.\" .Dq Ic set Cm +o ,
-.\" to avoid that command needing to list every available option.
-.\" There is no
-.\" .Cm +o default .
+In addition to the options listed there,
+when the
+.Dq "option name"
+given to
+.Ic set Fl o
+is
+.Cm default
+all of the options are reset to the values they had immediately
+after
+.Nm
+initialization, before any startup scripts, or other input, had been processed.
+While this may be of use to users or scripts, its primary purpose
+is for use in the output of
+.Dq Ic set Cm +o ,
+to avoid that command needing to list every available option.
+There is no
+.Cm +o default .
 .Pp
 The fourth use of the set command is to set the values of the shell's
 positional parameters to the specified arguments.
 To change the positional
 parameters without changing any options, use
-.Dq --
+.Dq -\|-
 as the first argument to set.
 If no following arguments are present, the set command
 will clear all the positional parameters (equivalent to executing
 .Dq shift $# . )
+Otherwise the following arguments become
+.Do \&$1 Dc Ns \&,
+.Do \&$2 Dc Ns \&,
+\&...,
+and
+.Dq \&$#
+is set to the number of arguments present.
 .It setvar Ar variable Ar value
 Assigns value to variable.
 (In general it is better to write

Reply via email to