summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2016-10-05 12:14:43 +0100
committerPeter Stephenson <pws@zsh.org>2016-10-05 12:14:43 +0100
commitdc517212caf3a8263cea9587bc6e96f7ff129b59 (patch)
treeab199c0936a8de2bc3c3e81661f7cee6b0e0c2d8
parent429f8ae71dc7f84b799a6d0a1f96716a7cde8806 (diff)
downloadzsh-dc517212caf3a8263cea9587bc6e96f7ff129b59.tar.gz
zsh-dc517212caf3a8263cea9587bc6e96f7ff129b59.tar.xz
zsh-dc517212caf3a8263cea9587bc6e96f7ff129b59.zip
39566: Improve usefulness of command_not_found_handler.
Don't behave as if command not found if return status is non-zero

as this may simply be the return status of the replacement command.
Let the function report a command not found instead.
-rw-r--r--Doc/Zsh/exec.yo15
-rw-r--r--README9
-rw-r--r--Src/exec.c13
-rw-r--r--Test/C04funcdef.ztst5
4 files changed, 27 insertions, 15 deletions
diff --git a/Doc/Zsh/exec.yo b/Doc/Zsh/exec.yo
index 30e4a61a2..5f79967de 100644
--- a/Doc/Zsh/exec.yo
+++ b/Doc/Zsh/exec.yo
@@ -28,10 +28,11 @@ not handle this executable format in the kernel.
 
 If no external command is found but a function tt(command_not_found_handler)
 exists the shell executes this function with all
-command line arguments.  The function should return status zero if it
-successfully handled the command, or non-zero status if it failed.
-In the latter case the standard handling is applied: `command not
-found' is printed to standard error and the shell exits with status 127.
-Note that the handler is executed in a subshell forked to execute
-an external command, hence changes to directories, shell parameters,
-etc. have no effect on the main shell.
+command line arguments.  The return status of the function becomes the
+status of the command.  If the function wishes to mimic the
+behaviour of the shell when the command is not found, it should
+print the message `tt(command not found:) var(cmd)' to standard error
+and return status 127.  Note that the handler is executed in a
+subshell forked to execute an external command, hence changes to
+directories, shell parameters, etc. have no effect on the main shell.
+
diff --git a/README b/README
index d146d4b16..ed2183d8d 100644
--- a/README
+++ b/README
@@ -101,6 +101,15 @@ For the more common case of non-repeatable options that take a single
 argument, completion functions now have to unescape not only colons but
 also backslashes when obtaining the option's argument from $opt_args.
 
+6) Previously, if the function command_not_found_handler was run
+in place of a command-not-found error, and the function returned
+non-zero status, zsh set the status to 127 and printed an error message
+anyway.  Now, the status from the handler is retained and no additional
+message is printed.  The main reasons for this change are that it was not
+possible to return a non-zero status to the parent shell from a command
+executed as a replacement, and the new implementation is more consistent
+with other shells.
+
 Incompatibilities between 5.0.8 and 5.2
 ---------------------------------------
 
diff --git a/Src/exec.c b/Src/exec.c
index 9890286b2..f248ca288 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -568,11 +568,14 @@ commandnotfound(char *arg0, LinkList args)
     Shfunc shf = (Shfunc)
 	shfunctab->getnode(shfunctab, "command_not_found_handler");
 
-    if (!shf)
-	return 127;
+    if (!shf) {
+	lastval = 127;
+	return 1;
+    }
 
     pushnode(args, arg0);
-    return doshfunc(shf, args, 1);
+    lastval = doshfunc(shf, args, 1);
+    return 0;
 }
 
 /*
@@ -703,7 +706,7 @@ execute(LinkList args, int flags, int defpath)
 
 	if (!search_defpath(arg0, pbuf, PATH_MAX)) {
 	    if (commandnotfound(arg0, args) == 0)
-		_exit(0);
+		_exit(lastval);
 	    zerr("command not found: %s", arg0);
 	    _exit(127);
 	}
@@ -767,7 +770,7 @@ execute(LinkList args, int flags, int defpath)
     if (eno)
 	zerr("%e: %s", eno, arg0);
     else if (commandnotfound(arg0, args) == 0)
-	_exit(0);
+	_exit(lastval);
     else
 	zerr("command not found: %s", arg0);
     _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127);
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
index 9f15e04ff..ab7b42928 100644
--- a/Test/C04funcdef.ztst
+++ b/Test/C04funcdef.ztst
@@ -120,14 +120,13 @@
      print "Your command:" >&2
      print "$1" >&2
      print "has gone down the tubes.  Sorry." >&2
-     return 1
+     return 42
   }
   ThisCommandDoesNotExistEither
-127:Command not found handler, failure
+42:Command not found handler, failure
 ?Your command:
 ?ThisCommandDoesNotExistEither
 ?has gone down the tubes.  Sorry.
-?(eval):7: command not found: ThisCommandDoesNotExistEither
 
   local variable=outside
   print "I am $variable"