about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/exec.yo12
-rw-r--r--Src/exec.c23
3 files changed, 41 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 889468f9a..01b9dd7e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2007-07-13  Peter Stephenson  <pws@csr.com>
+
+	* 23671: Doc/Zsh/exec.yo, Src/exec.c: Function
+	command_not_found_handler can be defined to handle command
+	not found.
+
 2007-07-12  Clint Adams  <clint@zsh.org>
 
 	* 23674: Completion/Unix/Command/_git: merge in git clone
diff --git a/Doc/Zsh/exec.yo b/Doc/Zsh/exec.yo
index 0d53b14b8..30e4a61a2 100644
--- a/Doc/Zsh/exec.yo
+++ b/Doc/Zsh/exec.yo
@@ -5,6 +5,8 @@ sect(Command Execution)
 )\
 cindex(command execution)
 cindex(execution, of commands)
+cindex(command not found, handling of)
+findex(command_not_found_handler)
 If a command name contains no slashes, the shell attempts to locate
 it.  If there exists a shell function by that name, the function
 is invoked as described in noderef(Functions).  If there exists
@@ -23,3 +25,13 @@ is a file beginning with `tt(#!)', the remainder of the first line
 specifies an interpreter for the program.  The shell will
 execute the specified interpreter on operating systems that do
 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.
diff --git a/Src/exec.c b/Src/exec.c
index 015753a83..ad088001e 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -468,6 +468,25 @@ isgooderr(int e, char *dir)
 	    e != ENOENT && e != ENOTDIR); 
 }
 
+/*
+ * Attempt to handle command not found.
+ * Return 0 if the condition was handled, non-zero otherwise.
+ */
+
+/**/
+static int
+commandnotfound(char *arg0, LinkList args)
+{
+    Shfunc shf = (Shfunc)
+	shfunctab->getnode(shfunctab, "command_not_found_handler");
+
+    if (!shf)
+	return 127;
+
+    pushnode(args, arg0);
+    return doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 1);
+}
+
 /* execute an external command */
 
 /**/
@@ -562,6 +581,8 @@ execute(LinkList args, int flags, int defpath)
 	}
 
 	if (!ps) {
+	    if (commandnotfound(arg0, args) == 0)
+		_exit(0);
 	    zerr("command not found: %s", arg0);
 	    _exit(127);
 	}
@@ -624,6 +645,8 @@ execute(LinkList args, int flags, int defpath)
 
     if (eno)
 	zerr("%e: %s", eno, arg0);
+    else if (commandnotfound(arg0, args) == 0)
+	_exit(0);
     else
 	zerr("command not found: %s", arg0);
     _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127);