zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: sticky emulation
@ 2009-02-10 23:03 Peter Stephenson
  2009-02-11  3:18 ` Bart Schaefer
  0 siblings, 1 reply; 10+ messages in thread
From: Peter Stephenson @ 2009-02-10 23:03 UTC (permalink / raw)
  To: Zsh hackers list

This is how I envision (and have already described, at least briefly)
sticky emulation for functions working.  This does not yet have
documentation, nor a way of setting or querying sticky emulation for
individual functions.  It will have at least the former if it gets
committed.

There's a certain amount of administrative reorganisation of emulation
flags here which isn't important; the key parts are in doshfunc() (the
hunks containing references to "restore_sticky").  Pretty much
everything else is straightforward---as discussed, "emulate ... -c"
always causes sticky emulation to be set.

Note that sticky emulation is not propagated to autoloaded functions,
neither when the autoload is set up nor when they are loaded, nor does
autoloading a function provide the same sort of firewall as sticky
emulation.  Defining a function with the special "functions" parameter
is treated the same as defining a function inline in the normal way.

Sticky emulation does propagate to functions defined within sticky
emulation functions---this is inevitable:  there should be no difference
between whether a function was defined within the initial "emulate" or
within a function defined there but called later.

>From the previous discussions, I think the most controversial features
(though I'm happy these are reasonable, myself) are:

- Sticky emulation does not cause options to be saved and reset while
executing another function with the same sticky emulation.  This is to
provide consistent emulation environments --- something running in sh
emulation doesn't expect a complete set of options to be imposed and
later removed when it calls another function in the same emulation.

- Functions without sticky emulation are not specially handled, so are
entered with no option changes, and do not have options reset on
exit except as normal shell handling, e.g. LOCAL_OPTIONS.  Setting
LOCAL_OPTIONS is in any case the right thing for a native zsh function
to do to sanitise and protect its local environment, so I don't see any
point in limiting its behaviour in the new code.  You can of course
use "emulate zsh -c 'fn() { ... }'" if you so desire; that's not really
what this is intended for but it's supposed to work consistently.

Someone can probably tell me if I should be keeping the RESTRICTED
and PRIVILEGED options when restoring options after executing a sticky
function, as for LOCAL_OPTIONS handling but not as for "emulate"; my
brain hurts.  I think the answer is "no" because it looks more like the
latter case than the former, but it may not be that simple.

Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.219
diff -u -r1.219 builtin.c
--- Src/builtin.c	25 Jan 2009 18:19:29 -0000	1.219
+++ Src/builtin.c	10 Feb 2009 22:40:13 -0000
@@ -536,7 +536,7 @@
 
     /* Obsolescent sh compatibility: set - is the same as set +xv *
      * and set - args is the same as set +xv -- args              */
-    if (emulation != EMULATE_ZSH && *args && **args == '-' && !args[0][1]) {
+    if (!EMULATION(EMULATE_ZSH) && *args && **args == '-' && !args[0][1]) {
 	dosetopt(VERBOSE, 0, 0);
 	dosetopt(XTRACE, 0, 0);
 	if (!args[1])
@@ -2861,6 +2861,8 @@
 	    shf = (Shfunc) zshcalloc(sizeof *shf);
 	    shf->node.flags = on;
 	    shf->funcdef = mkautofn(shf);
+	    /* No sticky emulation for autoloaded functions */
+	    shf->emulation = 0;
 	    shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
 
 	    if (signum != -1) {
@@ -4834,21 +4836,38 @@
 {
     int opt_L = OPT_ISSET(ops, 'L');
     int opt_R = OPT_ISSET(ops, 'R');
-    int saveemulation ;
+    int saveemulation, savesticky_emulation;
     int ret;
     char saveopts[OPT_SIZE];
 
     /* without arguments just print current emulation */
     if (!*argv) {
+	const char *shname;
+
 	if (opt_L || opt_R) {
 	    zwarnnam("emulate", "not enough arguments");
 	    return 1;
 	}
 
-	printf("%s\n", emulation == EMULATE_CSH ? "csh" :
-		       emulation == EMULATE_KSH ? "ksh" :
-		       emulation == EMULATE_SH  ? "sh" :
-		       "zsh");
+	switch(SHELL_EMULATION()) {
+	case EMULATE_CSH:
+	    shname = "csh";
+	    break;
+
+	case EMULATE_KSH:
+	    shname = "ksh";
+	    break;
+
+	case EMULATE_SH:
+	    shname = "sh";
+	    break;
+
+	default:
+	    shname = "zsh";
+	    break;
+	}
+
+	printf("%s\n", shname);
 	return 0;
     }
 
@@ -4880,9 +4899,12 @@
 
     memcpy(saveopts, opts, sizeof(opts));
     saveemulation = emulation;
+    savesticky_emulation = sticky_emulation;
     emulate(*argv, OPT_ISSET(ops,'R'));
+    sticky_emulation = emulation;
     ret = eval(argv+2);
     memcpy(opts, saveopts, sizeof(opts));
+    sticky_emulation = savesticky_emulation;
     emulation = saveemulation;
     return ret;
 }
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.162
diff -u -r1.162 exec.c
--- Src/exec.c	17 Nov 2008 16:56:42 -0000	1.162
+++ Src/exec.c	10 Feb 2009 22:40:15 -0000
@@ -3999,6 +3999,7 @@
 	shf->node.flags = 0;
 	shf->filename = ztrdup(scriptfilename);
 	shf->lineno = lineno;
+	shf->emulation = sticky_emulation;
 
 	if (!names) {
 	    /*
@@ -4221,7 +4222,7 @@
     char *name = shfunc->node.nam;
     int flags = shfunc->node.flags;
     char *fname = dupstring(name);
-    int obreaks, saveemulation ;
+    int obreaks, saveemulation, savesticky_emulation, restore_sticky;
     Eprog prog;
     struct funcstack fstack;
 #ifdef MAX_FUNCTION_DEPTH
@@ -4261,6 +4262,26 @@
      * function we need to restore the original options on exit.   */
     memcpy(saveopts, opts, sizeof(opts));
     saveemulation = emulation;
+    savesticky_emulation = sticky_emulation;
+
+    if (shfunc->emulation && sticky_emulation != shfunc->emulation) {
+	/*
+	 * Function is marked for sticky emulation.
+	 * Enable it now.
+	 *
+	 * We deliberately do not do this if the sticky emulation
+	 * in effect is the same as that requested.  This enables
+	 * option setting naturally within emulation environments.
+	 * Note that a difference in EMULATE_FULLY (emulate with
+	 * or without -R) counts as a different environment.
+	 *
+	 * This propagates the sticky emulation to subfunctions.
+	 */
+	emulation = sticky_emulation = shfunc->emulation;
+	restore_sticky = 1;
+	installemulation();
+    } else
+	restore_sticky = 0;
 
     if (flags & PM_TAGGED)
 	opts[XTRACE] = 1;
@@ -4349,7 +4370,16 @@
     zoptind = oldzoptind;
     scriptname = oldscriptname;
 
-    if (isset(LOCALOPTIONS)) {
+    if (restore_sticky) {
+	/*
+	 * If we switched to an emulation environment just for
+	 * this function, we interpret the option and emulation
+	 * switch as being a firewall between environments.
+	 */
+	memcpy(opts, saveopts, sizeof(opts));
+	emulation = saveemulation;
+	sticky_emulation = savesticky_emulation;
+    } else if (isset(LOCALOPTIONS)) {
 	/* restore all shell options except PRIVILEGED and RESTRICTED */
 	saveopts[PRIVILEGED] = opts[PRIVILEGED];
 	saveopts[RESTRICTED] = opts[RESTRICTED];
Index: Src/hashtable.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/hashtable.c,v
retrieving revision 1.30
diff -u -r1.30 hashtable.c
--- Src/hashtable.c	1 Nov 2008 01:19:35 -0000	1.30
+++ Src/hashtable.c	10 Feb 2009 22:40:15 -0000
@@ -588,7 +588,7 @@
  
 /**/
 mod_export char **pathchecked;
- 
+
 /* Create a new command hash table */
  
 /**/
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.97
diff -u -r1.97 init.c
--- Src/init.c	16 Sep 2008 15:07:08 -0000	1.97
+++ Src/init.c	10 Feb 2009 22:40:15 -0000
@@ -775,7 +775,7 @@
     if(unset(INTERACTIVE)) {
 	prompt = ztrdup("");
 	prompt2 = ztrdup("");
-    } else if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
+    } else if (EMULATION(EMULATE_KSH|EMULATE_SH)) {
 	prompt  = ztrdup(privasserted() ? "# " : "$ ");
 	prompt2 = ztrdup("> ");
     } else {
@@ -783,7 +783,7 @@
 	prompt2 = ztrdup("%_> ");
     }
     prompt3 = ztrdup("?# ");
-    prompt4 = (emulation == EMULATE_KSH || emulation == EMULATE_SH)
+    prompt4 = EMULATION(EMULATE_KSH|EMULATE_SH)
 	? ztrdup("+ ") : ztrdup("+%N:%i> ");
     sprompt = ztrdup("zsh: correct '%R' to '%r' [nyae]? ");
 
@@ -811,14 +811,14 @@
     /* Get password entry and set info for `USERNAME' */
 #ifdef USE_GETPWUID
     if ((pswd = getpwuid(cached_uid))) {
-	if (emulation == EMULATE_ZSH)
+	if (EMULATION(EMULATE_ZSH))
 	    home = metafy(pswd->pw_dir, -1, META_DUP);
 	cached_username = ztrdup(pswd->pw_name);
     }
     else
 #endif /* USE_GETPWUID */
     {
-	if (emulation == EMULATE_ZSH)
+	if (EMULATION(EMULATE_ZSH))
 	    home = ztrdup("/");
 	cached_username = ztrdup("");
     }
@@ -828,7 +828,7 @@
      * In non-native emulations HOME must come from the environment;
      * we're not allowed to set it locally.
      */
-    if (emulation == EMULATE_ZSH)
+    if (EMULATION(EMULATE_ZSH))
 	ptr = home;
     else
 	ptr = zgetenv("HOME");
@@ -954,7 +954,7 @@
 {
     noerrexit = -1;
 
-    if (emulation == EMULATE_KSH || emulation == EMULATE_SH) {
+    if (EMULATION(EMULATE_KSH|EMULATE_SH)) {
 	if (islogin)
 	    source("/etc/profile");
 	if (unset(PRIVILEGED)) {
@@ -1160,8 +1160,7 @@
     char *h;
 
     queue_signals();
-    if (emulation == EMULATE_SH || emulation == EMULATE_KSH ||
-	!(h = getsparam("ZDOTDIR"))) {
+    if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam("ZDOTDIR"))) {
 	h = home;
 	if (!h)
 	    return;
Index: Src/mkbltnmlst.sh
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/mkbltnmlst.sh,v
retrieving revision 1.9
diff -u -r1.9 mkbltnmlst.sh
--- Src/mkbltnmlst.sh	6 Jul 2007 21:52:39 -0000	1.9
+++ Src/mkbltnmlst.sh	10 Feb 2009 22:40:15 -0000
@@ -40,7 +40,7 @@
     unset moddeps autofeatures
     . $srcdir/../$modfile
     if test "x$autofeatures" != x; then
-	echo "  if (emulation == EMULATE_ZSH) {"
+	echo "  if (EMULATION(EMULATE_ZSH)) {"
 	echo "    char *features[] = { "
 	for feature in $autofeatures; do
 	    echo "      \"$feature\","
Index: Src/options.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/options.c,v
retrieving revision 1.46
diff -u -r1.46 options.c
--- Src/options.c	11 Sep 2008 12:49:20 -0000	1.46
+++ Src/options.c	10 Feb 2009 22:40:16 -0000
@@ -35,6 +35,11 @@
 /**/
 mod_export int emulation;
  
+/* current sticky emulation:  0 means none */
+
+/**/
+mod_export int sticky_emulation;
+
 /* the options; e.g. if opts[SHGLOB] != 0, SH_GLOB is turned on */
  
 /**/
@@ -58,9 +63,12 @@
 #define OPT_NONBOURNE	(OPT_ALL & ~OPT_BOURNE)
 #define OPT_NONZSH	(OPT_ALL & ~OPT_ZSH)
 
-#define OPT_EMULATE	(1<<5)	/* option is relevant to emulation */
-#define OPT_SPECIAL	(1<<6)	/* option should never be set by emulate() */
-#define OPT_ALIAS	(1<<7)	/* option is an alias to an other option */
+/* option is relevant to emulation */
+#define OPT_EMULATE	(EMULATE_UNUSED)
+/* option should never be set by emulate() */
+#define OPT_SPECIAL	(EMULATE_UNUSED<<1)
+/* option is an alias to an other option */
+#define OPT_ALIAS	(EMULATE_UNUSED<<2)
 
 #define defset(X) (!!((X)->node.flags & emulation))
 
@@ -477,6 +485,14 @@
 
 /**/
 void
+installemulation(void)
+{
+    scanhashtable(optiontab, 0, 0, 0, setemulate,
+		  !!(emulation & EMULATE_FULLY));
+}
+
+/**/
+void
 emulate(const char *zsh_name, int fully)
 {
     char ch = *zsh_name;
@@ -494,7 +510,9 @@
     else
 	emulation = EMULATE_ZSH;
 
-    scanhashtable(optiontab, 0, 0, 0, setemulate, fully);
+    if (fully)
+	emulation |= EMULATE_FULLY;
+    installemulation();
 }
 
 /* setopt, unsetopt */
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.154
diff -u -r1.154 params.c
--- Src/params.c	15 Jan 2009 19:47:20 -0000	1.154
+++ Src/params.c	10 Feb 2009 22:40:17 -0000
@@ -642,7 +642,7 @@
     /* Add the special parameters to the hash table */
     for (ip = special_params; ip->node.nam; ip++)
 	paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
-    if (emulation != EMULATE_SH && emulation != EMULATE_KSH)
+    if (!EMULATION(EMULATE_SH|EMULATE_KSH))
 	while ((++ip)->node.nam)
 	    paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
 
@@ -720,7 +720,7 @@
 #endif
     opts[ALLEXPORT] = oae;
 
-    if (emulation == EMULATE_ZSH)
+    if (EMULATION(EMULATE_ZSH))
     {
 	/*
 	 * For native emulation we always set the variable home
@@ -1881,7 +1881,7 @@
     switch(PM_TYPE(v->pm->node.flags)) {
     case PM_HASHED:
 	/* (!v->isarr) should be impossible unless emulating ksh */
-	if (!v->isarr && emulation == EMULATE_KSH) {
+	if (!v->isarr && EMULATION(EMULATE_KSH)) {
 	    s = dupstring("[0]");
 	    if (getindex(&s, v, 0) == 0)
 		s = getstrvalue(v);
@@ -2164,7 +2164,7 @@
 
     if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
 #if 0	/* Requires changes elsewhere in params.c and builtin.c */
-	if (emulation == EMULATE_KSH /* isset(KSHARRAYS) */) {
+	if (EMULATION(EMULATE_KSH) /* isset(KSHARRAYS) */) {
 	    struct value v;
 	    v.isarr = 1;
 	    v.flags = 0;
Index: Src/parse.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/parse.c,v
retrieving revision 1.77
diff -u -r1.77 parse.c
--- Src/parse.c	18 Nov 2008 10:07:31 -0000	1.77
+++ Src/parse.c	10 Feb 2009 22:40:17 -0000
@@ -3415,6 +3415,7 @@
 	shf = (Shfunc) zshcalloc(sizeof *shf);
 	shf->node.flags = on;
 	shf->funcdef = mkautofn(shf);
+	shf->emulation = 0;
 	shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf);
 	if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->node.nam, ops, func))
 	    ret = 1;
Index: Src/signals.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
retrieving revision 1.53
diff -u -r1.53 signals.c
--- Src/signals.c	29 Sep 2008 21:46:58 -0000	1.53
+++ Src/signals.c	10 Feb 2009 22:40:18 -0000
@@ -706,6 +706,7 @@
 	    newshf->node.flags = shf->node.flags;
 	    newshf->funcdef = dupeprog(shf->funcdef, 0);
 	    newshf->filename = ztrdup(shf->filename);
+	    newshf->emulation = shf->emulation;
 	    if (shf->node.flags & PM_UNDEFINED)
 		newshf->funcdef->shf = newshf;
 	}
@@ -1201,7 +1202,7 @@
 	/* return triggered */
 	retflag = 1;
     } else {
-	if (traperr && emulation != EMULATE_SH)
+	if (traperr && !EMULATION(EMULATE_SH))
 	    lastval = 1;
 	if (try_tryflag)
 	    errflag = traperr;
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.93
diff -u -r1.93 subst.c
--- Src/subst.c	18 Nov 2008 10:07:31 -0000	1.93
+++ Src/subst.c	10 Feb 2009 22:40:18 -0000
@@ -1534,7 +1534,7 @@
 	 * doesn't have parameter flags it might be neater to
 	 * handle this with the ^, =, ~ stuff, below.
 	 */
-	if ((c = *s) == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) {
+	if ((c = *s) == '!' && s[1] != Outbrace && EMULATION(EMULATE_KSH)) {
 	    hkeys = SCANPM_WANTKEYS;
 	    s++;
 	} else if (c == '(' || c == Inpar) {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.151
diff -u -r1.151 zsh.h
--- Src/zsh.h	18 Nov 2008 10:07:31 -0000	1.151
+++ Src/zsh.h	10 Feb 2009 22:40:19 -0000
@@ -1067,6 +1067,7 @@
     char *filename;             /* Name of file located in */
     zlong lineno;		/* line number in above file */
     Eprog funcdef;		/* function definition    */
+    int emulation;		/* sticky emulation for function */
 };
 
 /* Shell function context types. */
@@ -1790,6 +1791,20 @@
 #define EMULATE_SH   (1<<3) /* Bourne shell */
 #define EMULATE_ZSH  (1<<4) /* `native' mode */
 
+/* Test for a shell emulation.  Use this rather than emulation directly. */
+#define EMULATION(X)	(emulation & (X))
+
+/* Return only base shell emulation field. */
+#define SHELL_EMULATION()	(emulation & ((1<<5)-1))
+
+/* Additional flags */
+
+#define EMULATE_FULLY (1<<5) /* "emulate -R" in effect */
+/*
+ * Higher bits are used in options.c, record lowest unused bit...
+ */
+#define EMULATE_UNUSED (1<<6)
+
 /* option indices */
 
 enum {
Index: Src/Modules/newuser.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/newuser.c,v
retrieving revision 1.6
diff -u -r1.6 newuser.c
--- Src/Modules/newuser.c	19 Jun 2007 20:37:40 -0000	1.6
+++ Src/Modules/newuser.c	10 Feb 2009 22:40:19 -0000
@@ -78,7 +78,7 @@
 	0 };
     const char **sp;
 
-    if (emulation != EMULATE_ZSH)
+    if (!EMULATION(EMULATE_ZSH))
 	return 0;
 
     if (!dotdir) {
Index: Src/Modules/parameter.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/parameter.c,v
retrieving revision 1.50
diff -u -r1.50 parameter.c
--- Src/Modules/parameter.c	29 Sep 2008 08:46:33 -0000	1.50
+++ Src/Modules/parameter.c	10 Feb 2009 22:40:19 -0000
@@ -289,6 +289,7 @@
     shf = (Shfunc) zshcalloc(sizeof(*shf));
     shf->funcdef = dupeprog(prog, 0);
     shf->node.flags = dis;
+    shf->emulation = sticky_emulation;
 
     if (!strncmp(name, "TRAP", 4) &&
 	(sn = getsignum(name + 4)) != -1) {
Index: Test/B07emulate.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/B07emulate.ztst,v
retrieving revision 1.1
diff -u -r1.1 B07emulate.ztst
--- Test/B07emulate.ztst	10 Feb 2009 20:30:11 -0000	1.1
+++ Test/B07emulate.ztst	10 Feb 2009 22:40:19 -0000
@@ -3,72 +3,176 @@
 %prep
 
   isset() { 
+    print -n "${1}: "
     if [[ -o $1 ]]; then print yes; else print no; fi
   }
   showopts() {
-      # Set for Bourne shell emulation
-      isset shwordsplit
-      # Set in native mode and unless "emulate -R" is in use
-      isset banghist
+    # Set for Bourne shell emulation
+    isset shwordsplit
+    # Set in native mode and unless "emulate -R" is in use
+    isset banghist
+  }
+  cshowopts() {
+    showopts
+    # Show a csh option, too
+    isset cshnullglob
   }
 
 %test
 
-  (showopts
+  (print Before
+  showopts
   fn() {
      emulate sh
   }
   fn
+   print After
   showopts)
 0:Basic use of emulate
->no
->yes
->yes
->yes
+>Before
+>shwordsplit: no
+>banghist: yes
+>After
+>shwordsplit: yes
+>banghist: yes
 
   fn() {
     emulate -L sh
+    print During
     showopts
   }
+  print Before
   showopts
   fn
+  print After
   showopts
 0:Use of emulate -L
->no
->yes
->yes
->yes
->no
->yes
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: yes
+>After
+>shwordsplit: no
+>banghist: yes
 
-  (showopts
+  (print Before
+  showopts
   emulate -R sh
+  print After
   showopts)
 0:Use of emulate -R
->no
->yes
->yes
->no
+>Before
+>shwordsplit: no
+>banghist: yes
+>After
+>shwordsplit: yes
+>banghist: no
 
+  print Before
   showopts
-  emulate sh -c 'showopts'
+  emulate sh -c 'print During; showopts'
+  print After
   showopts
 0:Use of emulate -c
->no
->yes
->yes
->yes
->no
->yes
-
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: yes
+>After
+>shwordsplit: no
+>banghist: yes
 
+  print Before
   showopts
-  emulate -R sh -c 'showopts'
+  emulate -R sh -c 'print During; showopts'
+  print After
   showopts
 0:Use of emulate -R -c
->no
->yes
->yes
->no
->no
->yes
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: no
+>After
+>shwordsplit: no
+>banghist: yes
+
+  print Before
+  showopts
+  emulate -R sh -c 'shshowopts() { showopts; }'
+  print After definition
+  showopts
+  print In sticky emulation
+  shshowopts
+  print After sticky emulation
+  showopts
+0:Basic sticky function emulation
+>Before
+>shwordsplit: no
+>banghist: yes
+>After definition
+>shwordsplit: no
+>banghist: yes
+>In sticky emulation
+>shwordsplit: yes
+>banghist: no
+>After sticky emulation
+>shwordsplit: no
+>banghist: yes
+
+  print Before
+  cshowopts
+  emulate -R sh -c 'shshowopts() { cshowopts; }'
+  emulate csh -c 'cshshowopts() {
+    cshowopts
+    print In nested sh emulation
+    shshowopts
+  }'
+  print After definition
+  cshowopts
+  print In sticky csh emulation
+  cshshowopts
+  print After sticky emulation
+  cshowopts
+0:Basic sticky function emulation
+>Before
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+>After definition
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+>In sticky csh emulation
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: yes
+>In nested sh emulation
+>shwordsplit: yes
+>banghist: no
+>cshnullglob: no
+>After sticky emulation
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+
+  isalp() { if [[ -o alwayslastprompt ]]; then print on; else print off; fi; }
+  emulate sh -c 'shfunc_inner() { setopt alwayslastprompt; }'
+  emulate csh -c 'cshfunc_inner() { setopt alwayslastprompt; }'
+  emulate sh -c 'shfunc_outer() {
+    unsetopt alwayslastprompt;
+    shfunc_inner;
+    isalp
+    unsetopt alwayslastprompt
+    cshfunc_inner
+    isalp
+  }'
+  shfunc_outer
+0:Sticky emulation not triggered if sticky emulation unchanged
+>on
+>off


-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-10 23:03 PATCH: sticky emulation Peter Stephenson
@ 2009-02-11  3:18 ` Bart Schaefer
  2009-02-11 20:28   ` Peter Stephenson
  0 siblings, 1 reply; 10+ messages in thread
From: Bart Schaefer @ 2009-02-11  3:18 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 10, 11:03pm, Peter Stephenson wrote:
} Subject: PATCH: sticky emulation
}
} This is how I envision (and have already described, at least briefly)
} sticky emulation for functions working.

This all seems quite reasonable to me, particularly because the
implementation appears to be a straightforward change to the code --
tends to imply that it fits naturally into the existing semantics.

Nit-pick:  The patch to Src/hashtable.c is a no-op.

} Note that sticky emulation is not propagated to autoloaded functions,
} neither when the autoload is set up nor when they are loaded

What about zcompiled functions?  Obviously there's no special case for
them, but their treatment may be worth explanation at doc time.

} - Sticky emulation does not cause options to be saved and reset while
} executing another function with the same sticky emulation.

I think this is fine.

} - Functions without sticky emulation are not specially handled, so are
} entered with no option changes, and do not have options reset on
} exit except as normal shell handling, e.g. LOCAL_OPTIONS.

I wouldn't expect this to behave any differently.

} Someone can probably tell me if I should be keeping the RESTRICTED
} and PRIVILEGED options when restoring options after executing a sticky
} function, as for LOCAL_OPTIONS handling but not as for "emulate"; my
} brain hurts.  I think the answer is "no" because it looks more like the
} latter case than the former, but it may not be that simple.

I think "no" is also the right answer; I've always been a little puzzled
about why those were made exceptions to LOCAL_OPTIONS.  I think the
answer to the latter is related to the fact that there's otherwise no
way to force *any* option to persist across LOCAL_OPTIONS.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-11  3:18 ` Bart Schaefer
@ 2009-02-11 20:28   ` Peter Stephenson
  2009-02-11 23:37     ` Bart Schaefer
  2009-02-12  2:23     ` Bart Schaefer
  0 siblings, 2 replies; 10+ messages in thread
From: Peter Stephenson @ 2009-02-11 20:28 UTC (permalink / raw)
  To: Zsh hackers list

On Tue, 10 Feb 2009 19:18:04 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Feb 10, 11:03pm, Peter Stephenson wrote:
> } Subject: PATCH: sticky emulation
> }
> } This is how I envision (and have already described, at least briefly)
> } sticky emulation for functions working.
> 
> This all seems quite reasonable to me, particularly because the
> implementation appears to be a straightforward change to the code --
> tends to imply that it fits naturally into the existing semantics.
> 
> Nit-pick:  The patch to Src/hashtable.c is a no-op.

Yes, that's been lying around for ages waiting for an excuse to commit
it.

> } Note that sticky emulation is not propagated to autoloaded functions,
> } neither when the autoload is set up nor when they are loaded
> 
> What about zcompiled functions?  Obviously there's no special case for
> them, but their treatment may be worth explanation at doc time.

I've done that.

Here's the documentation.  I'll submit the lot and it can be modified
later if necessary.

Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.118
diff -u -r1.118 builtins.yo
--- Doc/Zsh/builtins.yo	8 Feb 2009 08:09:19 -0000	1.118
+++ Doc/Zsh/builtins.yo	11 Feb 2009 20:28:11 -0000
@@ -356,10 +356,6 @@
 )\
 .
 
-If tt(-c) tt(arg) is given, evaluate tt(arg) after temporary setting
-requested emulation. Emulation and all options will be restored to their
-original values before tt(emulate) returns.
-
 If the tt(-R) option is given, all options
 are reset to their default value corresponding to the specified emulation
 mode, except for certain options describing the interactive
@@ -370,6 +366,62 @@
 tt(trap) commands to be local to the immediately surrounding shell
 function, if any; normally these options are turned off in all emulation
 modes except tt(ksh). The tt(-L) and tt(-c) are mutually exclusive.
+
+If tt(-c) tt(arg) is given, evaluate tt(arg) while the requested
+emulation is temporarily in effect.  The emulation and all options will
+be restored to their original values before tt(emulate) returns.  The
+tt(-R) flag may be used.
+
+Use of tt(-c) enables `sticky' emulation mode for functions defined
+within the evaluated expression:  the emulation mode is associated
+thereafter with the function so that whenever the function is executed
+the emulation (respecting the tt(-R) flag, if present) and all
+options are set before entry to the function, and restored after exit.
+If the function is called when the sticky emulation is already in
+effect, either within an `tt(emulate) var(shell) tt(-c)' expression or
+within another function with the same sticky emulation, entry and exit
+from the function do not cause options to be altered (except due to
+standard processing such as the tt(LOCAL_OPTIONS) option).
+
+For example:
+
+example(emulate sh -c 'fni+LPAR()RPAR() { setopt cshnullglob; }
+fno+LPAR()RPAR() { fni; }'
+fno
+)
+
+The two functions tt(fni) and tt(fno) are defined with sticky tt(sh)
+emulation.  tt(fno) is then executed, causing options associated
+with emulations to be set to their values in tt(sh).  tt(fni) then
+calls tt(fno); because tt(fno) is also marked for sticky tt(sh)
+emulation, no option changes take place on entry to or exit from it.
+Hence the option tt(cshnullglob), turned off by tt(sh) emulation, will
+be turned on within tt(fni) and remain on on return to tt(fno).  On exit
+from tt(fno), the emulation mode and all options will be restored to the
+state they were in before entry to the temporary emulation.
+
+The documentation above is typically sufficient for the intended
+purpose of executing code designed for other shells in a suitable
+environment.  More detailed rules follow.
+startsitem()
+sitem(1.)(The sticky emulation environment provided by `tt(emulate)
+var(shell) tt(-c)' is identical to that provided by entry to
+a function marked for sticky emulation as a consequence of being
+defined in such an environment.  Hence, for example, the sticky
+emulation is inherited by subfunctions defined within functions
+with sticky emulation.)
+sitem(2.)(No change of options takes place on entry to or exit from
+functions that are not marked for sticky emulation, other than those
+that would normally take place, even if those functions are called
+within sticky emulation.)
+sitem(3.)(No special handling is provided for functions marked for
+tt(autoload) nor for functions present in wordcode created by
+the tt(zcompile) command.)
+sitem(4.)(The presence or absence of the tt(-R) flag to tt(emulate)
+corresponds to different sticky emulation modes, so for example
+`tt(emulate sh -c)', `tt(emulate -R sh -c)' and `tt(emulate csh -c)'
+are treated as three distinct sticky emulations.)
+endsitem()
 )
 findex(enable)
 cindex(enabling commands)


-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-11 20:28   ` Peter Stephenson
@ 2009-02-11 23:37     ` Bart Schaefer
  2009-02-12  9:44       ` Peter Stephenson
  2009-02-12  2:23     ` Bart Schaefer
  1 sibling, 1 reply; 10+ messages in thread
From: Bart Schaefer @ 2009-02-11 23:37 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 11,  8:28pm, Peter Stephenson wrote:
}
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > What about zcompiled functions?  Obviously there's no special case for
} > them, but their treatment may be worth explanation at doc time.
} 
} I've done that.

I guess I'm specifically interested in what happens with "zcompile -c"
which takes a function already defined in the shell and writes it out
compiled.  Suppose this is used on a function with sticky emulation.
If the compiled form is then reloaded, is it still sticky?


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-11 20:28   ` Peter Stephenson
  2009-02-11 23:37     ` Bart Schaefer
@ 2009-02-12  2:23     ` Bart Schaefer
  1 sibling, 0 replies; 10+ messages in thread
From: Bart Schaefer @ 2009-02-12  2:23 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 11,  8:28pm, Peter Stephenson wrote:
}
} I'll submit the lot and it can be modified later if necessary.

Documentation nit:  My info-viewer and my emacs both display the list
of emulate rules like so:

     The documentation above is typically sufficient for the intended
     purpose of executing code designed for other shells in a suitable
     environment.  More detailed rules follow.
    1.
          The sticky emulation environment provided by `emulate SHELL
          -c' is identical to that provided by entry to a function
          marked for sticky emulation as a consequence of being defined
          in such an environment.  Hence, for example, the sticky
          emulation is inherited by subfunctions defined within
          functions with sticky emulation.

    2.
          No change of options takes place on entry to or exit from
          functions that are not marked for sticky emulation, other
          than those that would normally take place, even if those
          functions are called within sticky emulation.

(and so on with the floating numbers one line up and one character too
far "outdented").

I compiled this and started poking around and immediately encountered
an interesting side-effect.  Consider the function "allopt" which is
autoloaded and dumps out a list of the options and their states.

Starting from

% emulate sh -c "allopt"
(list of options appears as expected, with "sh" states)
zsh: allopt: function not defined by file

OK, clearly allopt should be getting "autoload -z" treatment.  (Aside:
Does the doc really not explain "autoload -z" anywhere?  Have I just
missed it?)

On reflection the rest of what follows is exactly as I should have
expected it to be, but having rambled on writing it all down I'm
going to send it anyway.

Exit and start a new shell, try this:

% emulate sh -c "ao() { allopt; }"
% ao
(list of options appears as expected, with "sh" states)
zsh: allopt: function not defined by file
% allopt
(list of options appears with zsh states)

Exit and start again:

% autoload -z allopt
% emulate sh -c "allopt"
(list of options appears as expected, with "sh" states)
% allopt
(list of options appears with zsh states)

Exit and start again:

% unfunction allopt
% emulate sh -c "autoload -z allopt; allopt"
(list of options appears as expected, with "sh" states)
% allopt
(list of options appears with zsh states)

So there's no way to cause an autoloaded function to acquire sticky
emulation, which is what's meant by "No special handling for ...
autoload."

-- 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-11 23:37     ` Bart Schaefer
@ 2009-02-12  9:44       ` Peter Stephenson
  2009-02-12 10:10         ` Oliver Kiddle
  2009-02-12 15:32         ` Bart Schaefer
  0 siblings, 2 replies; 10+ messages in thread
From: Peter Stephenson @ 2009-02-12  9:44 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 11 Feb 2009 15:37:58 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Feb 11,  8:28pm, Peter Stephenson wrote:
> }
> } Bart Schaefer <schaefer@brasslantern.com> wrote:
> } > What about zcompiled functions?  Obviously there's no special case for
> } > them, but their treatment may be worth explanation at doc time.
> } 
> } I've done that.
> 
> I guess I'm specifically interested in what happens with "zcompile -c"
> which takes a function already defined in the shell and writes it out
> compiled.  Suppose this is used on a function with sticky emulation.
> If the compiled form is then reloaded, is it still sticky?

I suspect the answer's no, but I don't understand the internals and I don't
know how to execute the file in such a way that the reloaded function isn't
marked for autoloading, and autoloading certainly isn't handled.

> Date: Wed, 11 Feb 2009 18:23:06 -0800
> Documentation nit:  My info-viewer and my emacs both display the list
> of emulate rules like so:
>...
> (and so on with the floating numbers one line up and one character too
> far "outdented").

Frankly, if I had time to look at things like what the back end of the
documentation tools is producing I'd be out of work.

> (Aside:
> Does the doc really not explain "autoload -z" anywhere?  Have I just
> missed it?)

A quick glance suggests it actually is missing: the flag appears in the
list at the top, but there's nothing in the description.

> % emulate sh -c "allopt"
> (list of options appears as expected, with "sh" states)
> zsh: allopt: function not defined by file
> 
> OK, clearly allopt should be getting "autoload -z" treatment.
>...
> So there's no way to cause an autoloaded function to acquire sticky
> emulation, which is what's meant by "No special handling for ...
> autoload."

Yes, that's right.  We may want to add this later; it should be no harder
than -k or -z.  However, saving a zcompile'd function in the appropriate
format may be harder (I've stayed sane by avoiding that code).

I've just gone through my initialisation files adding "-z"s everywhere as a
consequence.

Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.119
diff -u -r1.119 builtins.yo
--- Doc/Zsh/builtins.yo	11 Feb 2009 20:42:16 -0000	1.119
+++ Doc/Zsh/builtins.yo	12 Feb 2009 09:38:00 -0000
@@ -131,6 +131,11 @@
 With the tt(-w) flag, the var(name)s are taken as names of files compiled
 with the tt(zcompile) builtin, and all functions defined in them are
 marked for autoloading.
+
+The flags tt(-z) and tt(-k) mark the function to be autoloaded in
+native or ksh emulation, as if the option tt(KSH_AUTOLOAD) were
+unset or were set, respectively.  The flags override the setting of
+the option at the time the function is loaded.
 )
 findex(bg)
 cindex(jobs, backgrounding)

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-12  9:44       ` Peter Stephenson
@ 2009-02-12 10:10         ` Oliver Kiddle
  2009-02-12 15:30           ` Peter Stephenson
  2009-02-12 15:41           ` Bart Schaefer
  2009-02-12 15:32         ` Bart Schaefer
  1 sibling, 2 replies; 10+ messages in thread
From: Oliver Kiddle @ 2009-02-12 10:10 UTC (permalink / raw)
  To: Zsh hackers list

Is it somehow possible with this new feature to, from a function, revert
to the user's interactive option set. Could be useful for setopt
completion to correctly complete set and unset options.

Oliver


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-12 10:10         ` Oliver Kiddle
@ 2009-02-12 15:30           ` Peter Stephenson
  2009-02-12 15:41           ` Bart Schaefer
  1 sibling, 0 replies; 10+ messages in thread
From: Peter Stephenson @ 2009-02-12 15:30 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, 12 Feb 2009 11:10:40 +0100
Oliver Kiddle <okiddle@yahoo.co.uk> wrote:
> Is it somehow possible with this new feature to, from a function, revert
> to the user's interactive option set. Could be useful for setopt
> completion to correctly complete set and unset options.

The code doesn't make the original options available deeper in.  You'd have
to do what the completion code optionally does and save it yourself.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-12  9:44       ` Peter Stephenson
  2009-02-12 10:10         ` Oliver Kiddle
@ 2009-02-12 15:32         ` Bart Schaefer
  1 sibling, 0 replies; 10+ messages in thread
From: Bart Schaefer @ 2009-02-12 15:32 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 12,  9:44am, Peter Stephenson wrote:
}
} Frankly, if I had time to look at things like what the back end of the
} documentation tools is producing I'd be out of work.

Well, obviously, that's what the rest of us are here for. :-)

} On Wed, 11 Feb 2009 15:37:58 -0800
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > 
} > I guess I'm specifically interested in what happens with "zcompile -c"
} 
} I suspect the answer's no, but I don't understand the internals and
} I don't know how to execute the file in such a way that the reloaded
} function isn't marked for autoloading, and autoloading certainly isn't
} handled.

I think the only ways to execute a .zwc are with autoload and "." --
to run FILE.zwc with "." you have to use ". FILE" (omit extension).

The state of the autoload -U and -z flags are stored in the .zwc so I
thought that might mean some of the shfunc was packed there and thus
the sticky setting would get picked up as a side-effect, but that does
not appear to be the case.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: PATCH: sticky emulation
  2009-02-12 10:10         ` Oliver Kiddle
  2009-02-12 15:30           ` Peter Stephenson
@ 2009-02-12 15:41           ` Bart Schaefer
  1 sibling, 0 replies; 10+ messages in thread
From: Bart Schaefer @ 2009-02-12 15:41 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 12, 11:10am, Oliver Kiddle wrote:
}
} Is it somehow possible with this new feature to, from a function,
} revert to the user's interactive option set.

That'd require a bit more finagling; the saved option state is on the
C call stack, not somewhere that it can easily be grabbed, and we'd
need to figure out at exactly what point to save the options so as to
have the interactive set -- probably within ZLE, so it's orthogonal
to this feature.

Really all you need for option completion is to stash $options during
precmd and reference that in _options instead of the actual $options.


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-02-12 15:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-10 23:03 PATCH: sticky emulation Peter Stephenson
2009-02-11  3:18 ` Bart Schaefer
2009-02-11 20:28   ` Peter Stephenson
2009-02-11 23:37     ` Bart Schaefer
2009-02-12  9:44       ` Peter Stephenson
2009-02-12 10:10         ` Oliver Kiddle
2009-02-12 15:30           ` Peter Stephenson
2009-02-12 15:41           ` Bart Schaefer
2009-02-12 15:32         ` Bart Schaefer
2009-02-12  2:23     ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).