# HG changeset patch
# User Mike Miller <mtmiller@ieee.org>
# Date 1378858846 14400
#      Tue Sep 10 20:20:46 2013 -0400
# Node ID 9aa7ab5b2e242de9acc81a12fa863c7f30d16e2d
# Parent  0b644adf4f310ebaaa74a2ccbaba08dc6f4e8da5
Add hook function to handle missing Octave components

* __gripe_missing_component__.m: New internal function to handle errors due
to missing Octave components.
* scripts/help/module.mk (help_FCN_FILES): Add __gripe_missing_component__.m.
* variables.cc (Vmissing_component_hook): New internal variable.
* doc.m, mkoctfile.m, configure_make.m: Call __gripe_missing_component__
if required files are not found.

diff --git a/libinterp/corefcn/variables.cc b/libinterp/corefcn/variables.cc
--- a/libinterp/corefcn/variables.cc
+++ b/libinterp/corefcn/variables.cc
@@ -2606,3 +2606,33 @@
 
   return retval;
 }
+
+static std::string Vmissing_component_hook;
+
+DEFUN (missing_component_hook, args, nargout,
+    "-*- texinfo -*-\n\
+@deftypefn  {Built-in Function} {@var{val} =} missing_component_hook ()\n\
+@deftypefnx {Built-in Function} {@var{old_val} =} missing_component_hook (@var{new_val})\n\
+@deftypefnx {Built-in Function} {} missing_component_hook (@var{new_val}, \"local\")\n\
+Query or set the internal variable that specifies the function to call when\n\
+a component of Octave is missing.  This can be useful for packagers that\n\
+may split the Octave installation into multiple sub-packages, for example,\n\
+to provide a hint to users for how to install the missing components.\n\
+\n\
+When called from inside a function with the @qcode{\"local\"} option, the\n\
+variable is changed locally for the function and any subroutines it calls.  \n\
+The original variable value is restored when exiting the function.\n\
+\n\
+The hook function is expected to be of the form\n\
+\n\
+@example\n\
+@var{fcn} (@var{component})\n\
+@end example\n\
+\n\
+Octave will call @var{fcn} with the name of the function that requires the\n\
+component and a string describing the missing component.  The hook function\n\
+should return an error message to be displayed.\n\
+@end deftypefn")
+{
+  return SET_INTERNAL_VARIABLE (missing_component_hook);
+}
diff --git a/scripts/help/__gripe_missing_component__.m b/scripts/help/__gripe_missing_component__.m
new file mode 100644
--- /dev/null
+++ b/scripts/help/__gripe_missing_component__.m
@@ -0,0 +1,56 @@
+## Copyright (C) 2013 Mike Miller
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} __gripe_missing_component__ (@var{caller}, @var{component})
+## Undocumented internal function.
+## @end deftypefn
+
+function __gripe_missing_component__ (caller, component)
+
+  if (nargin != 2)
+    print_usage ();
+  endif
+
+  msg = "";
+  fcn = missing_component_hook ();
+
+  ftype = exist (fcn);
+  if (ftype == 2 || ftype == 3 || ftype == 5 || ftype == 103)
+    msg = feval (fcn, component);
+  endif
+
+  if (isempty (msg))
+    switch (component)
+      case "info-file"
+        msg = "unable to find the Octave info manual, Octave installation is incomplete";
+      case "mkoctfile"
+        msg = "unable to find the mkoctfile command, Octave installation is incomplete";
+      case "octave"
+        msg = "unable to find the octave executable, Octave installation is incomplete";
+      case "octave-config"
+        msg = "unable to find the octave-config command, Octave installation is incomplete";
+      otherwise
+        msg = ["unable to find required Octave component \"" component "\""];
+    endswitch
+  endif
+
+  error ("%s: %s\n", caller, msg);
+
+endfunction
+
diff --git a/scripts/help/doc.m b/scripts/help/doc.m
--- a/scripts/help/doc.m
+++ b/scripts/help/doc.m
@@ -79,6 +79,10 @@
 
       if (err < 0)
         info_file_name = info_file ();
+
+        if (! exist (info_file_name, "file"))
+          __gripe_missing_component__ ("doc", "info-file");
+        endif
       endif
 
       ## FIXME -- don't change the order of the arguments below because
diff --git a/scripts/help/module.mk b/scripts/help/module.mk
--- a/scripts/help/module.mk
+++ b/scripts/help/module.mk
@@ -5,6 +5,7 @@
   help/private/__strip_html_tags__.m
 
 help_FCN_FILES = \
+  help/__gripe_missing_component__.m \
   help/__makeinfo__.m \
   help/__unimplemented__.m \
   help/doc.m \
diff --git a/scripts/miscellaneous/mkoctfile.m b/scripts/miscellaneous/mkoctfile.m
--- a/scripts/miscellaneous/mkoctfile.m
+++ b/scripts/miscellaneous/mkoctfile.m
@@ -146,6 +146,10 @@
 
   shell_script = fullfile (bindir, sprintf ("mkoctfile-%s", OCTAVE_VERSION));
 
+  if (! exist (shell_script, "file"))
+    __gripe_missing_component__ ("mkoctfile", "mkoctfile");
+  endif
+
   cmd = ['"' shell_script '"'];
   for i = 1:nargin
     cmd = [cmd ' "' varargin{i} '"'];
@@ -159,10 +163,7 @@
     printf ("%s", out);
   endif
 
-  if (sys == 127)
-    warning ("unable to find mkoctfile in expected location: '%s'",
-             shell_script);
-
+  if (sys != 0)
     warning ("mkoctfile exited with failure status");
   endif
 
diff --git a/scripts/pkg/private/configure_make.m b/scripts/pkg/private/configure_make.m
--- a/scripts/pkg/private/configure_make.m
+++ b/scripts/pkg/private/configure_make.m
@@ -37,6 +37,16 @@
             "INSTALLDIR"; desc.dir};
     scenv = sprintf ("%s=\"%s\" ", cenv{:});
 
+    if (! exist (mkoctfile_program, "file"))
+      __gripe_missing_component__ ("pkg", "mkoctfile");
+    endif
+    if (! exist (octave_config_program, "file"))
+      __gripe_missing_component__ ("pkg", "octave-config");
+    endif
+    if (! exist (octave_binary, "file"))
+      __gripe_missing_component__ ("pkg", "octave");
+    endif
+
     ## Configure.
     if (exist (fullfile (src, "configure"), "file"))
       flags = "";
