home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / src / help.cc < prev    next >
C/C++ Source or Header  |  1996-09-27  |  18KB  |  876 lines

  1. // help.cc                                             -*- C++ -*-
  2. /*
  3.  
  4. Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
  5.  
  6. This file is part of Octave.
  7.  
  8. Octave is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. Octave is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with Octave; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. */
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27.  
  28. #include <signal.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <iostream.h>
  32. #include <strstream.h>
  33.  
  34. #include "tree-expr.h"
  35. #include "tree-const.h"
  36. #include "sighandlers.h"
  37. #include "user-prefs.h"
  38. #include "tree-expr.h"
  39. #include "variables.h"
  40. #include "oct-obj.h"
  41. #include "symtab.h"
  42. #include "octave.h"
  43. #include "dirfns.h"
  44. #include "pager.h"
  45. #include "error.h"
  46. #include "utils.h"
  47. #include "help.h"
  48. #include "defun.h"
  49.  
  50. extern "C"
  51. {
  52. #include "info/info.h"
  53. #include "info/dribble.h"
  54. #include "info/terminal.h"
  55.  
  56. extern int initialize_info_session ();
  57. extern int index_entry_exists ();
  58. extern int do_info_index_search ();
  59. extern void finish_info_session ();
  60. extern char *replace_in_documentation ();
  61.  
  62. // XXX FIXME XXX
  63. #undef __FUNCTION_DEF
  64. #include <readline/tilde.h>
  65.  
  66. #define boolean kpathsea_boolean
  67. #define false kpathsea_false
  68. #define true kpathsea_true
  69. #include <kpathsea/pathsearch.h>
  70. }
  71.  
  72. static help_list operators[] =
  73. {
  74.   { "!",
  75.     "Logical not operator.  See also `~'.\n", },
  76.  
  77.   { "!=",
  78.     "Logical not equals operator.  See also `~' and `<>'.\n", },
  79.  
  80.   { "\"",
  81.     "String delimiter.\n", },
  82.  
  83.   { "#",
  84.     "Begin comment character.  See also `%'.", },
  85.  
  86.   { "%",
  87.     "Begin comment charcter.  See also `#'.", },
  88.  
  89.   { "&",
  90.     "Logical and operator.  See also `&&'.", },
  91.  
  92.   { "&&",
  93.     "Logical and operator.  See also `&'.", },
  94.  
  95.   { "'",
  96.     "Matrix transpose operator.  For complex matrices, computes the\n\
  97. complex conjugate (Hermitian) transpose.  See also `.''\n\
  98. \n\
  99. The single quote character may also be used to delimit strings, but\n\
  100. it is better to use the double quote character, since that is never\n\
  101. ambiguous", },
  102.  
  103.   { "(",
  104.     "Array index or function argument delimiter.", },
  105.  
  106.   { ")",
  107.     "Array index or function argument delimiter.", },
  108.  
  109.   { "*",
  110.     "Multiplication operator.  See also `.*'", },
  111.  
  112.   { "**",
  113.     "Power operator.  See also `^', `.**', and `.^'", },
  114.  
  115.   { "+",
  116.     "Addition operator.", },
  117.  
  118.   { "++",
  119.     "Increment operator.  As in C, may be applied as a prefix or postfix operator.", },
  120.  
  121.   { ",",
  122.     "Array index, function argument, or command separator.", },
  123.  
  124.   { "-",
  125.     "Subtraction or unary negation operator.", },
  126.  
  127.   { "--",
  128.     "Decrement operator.  As in C, may be applied as a prefix or postfix operator.", },
  129.  
  130.   { ".'",
  131.     "Matrix transpose operator.  For complex matrices, computes the\n\
  132. transpose, *not* the complex conjugate transpose.  See also `''.", },
  133.  
  134.   { ".*",
  135.     "Element by element multiplication operator.  See also `*'.", },
  136.  
  137.   { ".**",
  138.     "Element by element power operator.  See also `**', `^', and `.^'.", },
  139.  
  140.   { "./",
  141.     "Element by element division operator.  See also `/' and `\\'.", },
  142.  
  143.   { ".^",
  144.     "Element by element power operator.  See also `**', `^', and `.^'.", },
  145.  
  146.   { "/",
  147.     "Right division.  See also `\\' and `./'.", },
  148.  
  149.   { ":",
  150.     "Select entire rows or columns of matrices.", },
  151.  
  152.   { ";",
  153.     "Array row or command separator.  See also `,'.", },
  154.  
  155.   { "<",
  156.     "Less than operator.", },
  157.  
  158.   { "<=",
  159.     "Less than or equals operator.", },
  160.  
  161.   { "<>",
  162.     "Logical not equals operator.  See also `!=' and `~='.", },
  163.  
  164.   { "=",
  165.     "Assignment operator.", },
  166.  
  167.   { "==",
  168.     "Equality test operator.", },
  169.  
  170.   { ">",
  171.     "Greater than operator.", },
  172.  
  173.   { ">=",
  174.     "Greater than or equals operator.", },
  175.  
  176.   { "[",
  177.     "Return list delimiter.  See also `]'.", },
  178.  
  179.   { "\\",
  180.     "Left division operator.  See also `/' and `./'.", },
  181.  
  182.   { "]",
  183.     "Return list delimiter.  See also `['.", },
  184.  
  185.   { "^",
  186.     "Power operator.  See also `**', `.^', and `.**.'", },
  187.  
  188.   { "|",
  189.     "Logical or operator.  See also `||'.", },
  190.  
  191.   { "||",
  192.     "Logical or operator.  See also `|'.", },
  193.  
  194.   { "~",
  195.     "Logical not operator.  See also `!' and `~'.", },
  196.  
  197.   { "~=",
  198.     "Logical not equals operator.  See also `<>' and `!='.", },
  199.  
  200.   { 0, 0, },
  201. };
  202.  
  203. static help_list keywords[] =
  204. {
  205.   { "all_va_args",
  206.     "Pass all unnamed arguments to another function call.", },
  207.  
  208.   { "break",
  209.     "Exit the innermost enclosing while or for loop.", },
  210.  
  211.   { "continue",
  212.     "Jump to the end of the innermost enclosing while or for loop.", },
  213.  
  214.   { "else",
  215.     "Alternate action for an if block.", },
  216.  
  217.   { "elseif",
  218.     "Alternate conditional test for an if block.", },
  219.  
  220.   { "end",
  221.     "Mark the end of any for, if, while, or function block.", },
  222.  
  223.   { "end_unwind_protect",
  224.     "Mark the end of an unwind_protect block.", }, 
  225.  
  226.   { "endfor",
  227.     "Mark the end of a for loop.", },
  228.  
  229.   { "endfunction",
  230.     "Mark the end of a function.", },
  231.  
  232.   { "endif",
  233.     "Mark the end of an if block.", },
  234.  
  235.   { "endwhile",
  236.     "Mark the end of a while loop.", },
  237.  
  238.   { "for",
  239.     "Begin a for loop.", },
  240.  
  241.   { "function",
  242.     "Begin a function body.", },
  243.  
  244.   { "global",
  245.     "Declare variables to have global scope.", },
  246.  
  247.   { "gplot",
  248.     "Produce 2-D plots using gnuplot-like command syntax.", },
  249.  
  250.   { "gsplot",
  251.     "Produce 3-D plots using gnuplot-like command syntax.", },
  252.  
  253.   { "if",
  254.     "Begin an if block.", },
  255.  
  256.   { "return",
  257.     "Return from a function.", },
  258.  
  259.   { "unwind_protect",
  260.     "Begin an unwind_protect block.", }, 
  261.  
  262.   { "unwind_protect_cleanup",
  263.     "Begin the cleanup section of an unwind_protect block.", }, 
  264.  
  265.   { "while",
  266.     "Begin a while loop.", },
  267.  
  268.   { 0, 0, },
  269. };
  270.  
  271. // Return a copy of the operator or keyword names.
  272.  
  273. char **
  274. names (help_list *lst, int& count)
  275. {
  276.   count = 0;
  277.   help_list *ptr = lst;
  278.   while (ptr->name)
  279.     {
  280.       count++;
  281.       ptr++;
  282.     }
  283.  
  284.   if (count == 0)
  285.     return 0;
  286.     
  287.   char **name_list = new char * [count+1];
  288.  
  289.   ptr = lst;
  290.   int i = 0;
  291.   while (ptr->name)
  292.     {
  293.       name_list[i++] = strsave (ptr->name);
  294.       ptr++;
  295.     }
  296.  
  297.   name_list[i] = 0;
  298.   return name_list;
  299. }
  300.  
  301. help_list *
  302. operator_help (void)
  303. {
  304.   return operators;
  305. }
  306.  
  307. help_list *
  308. keyword_help (void)
  309. {
  310.   return keywords;
  311. }
  312.  
  313. #define VERBOSE_HELP_MESSAGE \
  314.   "\n\
  315. Additional help for builtin functions, operators, and variables\n\
  316. is available in the on-line version of the manual.\n\
  317. \n\
  318. Use the command `help -i <topic>' to search the manual index.\n"
  319.  
  320. static void
  321. additional_help_message (ostrstream& output_buf)
  322. {
  323.   if (! user_pref.suppress_verbose_help_message)
  324.     output_buf << VERBOSE_HELP_MESSAGE;
  325. }
  326.  
  327. void
  328. print_usage (const char *string, int just_usage)
  329. {
  330.   ostrstream output_buf;
  331.  
  332.   symbol_record *sym_rec = global_sym_tab->lookup (string, 0, 0);
  333.   if (sym_rec)
  334.     {
  335.       char *h = sym_rec->help ();
  336.       if (h && *h)
  337.     {
  338.       output_buf << "\n*** " << string << ":\n\n"
  339.         << h << "\n";
  340.  
  341.       if (! just_usage)
  342.         additional_help_message (output_buf);
  343.       output_buf << ends;
  344.       maybe_page_output (output_buf);
  345.     }
  346.     }
  347.   else
  348.     warning ("no usage message found for `%s'", string);
  349. }
  350.  
  351. static void
  352. display_names_from_help_list (ostrstream& output_buf, help_list *list,
  353.                   const char *desc)
  354. {
  355.   int count = 0;
  356.   char **symbols = names (list, count);
  357.   output_buf << "\n*** " << desc << ":\n\n";
  358.   if (symbols && count > 0)
  359.     list_in_columns (output_buf, symbols);
  360.   delete [] symbols;
  361. }
  362.  
  363. static char *
  364. print_symbol_type (ostrstream& output_buf, symbol_record *sym_rec,
  365.            char *name, int print)
  366. {
  367.   char *retval = 0;
  368.  
  369.   if (sym_rec->is_user_function ())
  370.     {
  371.       tree_fvc *defn = sym_rec->def ();
  372.       char *fn = defn->fcn_file_name ();
  373.       if (fn)
  374.     {
  375.       char *ff = fcn_file_in_path (fn);
  376.       ff = ff ? ff : fn;
  377.  
  378.       if (print)
  379.         output_buf << name
  380.           << " is the function defined from:\n"
  381.         << ff << "\n";
  382.       else
  383.         retval = ff;
  384.     }
  385.       else
  386.     {
  387.       if (print)
  388.         output_buf << name << " is a user-defined function\n";
  389.       else
  390.         retval = "user-defined function";
  391.     }
  392.     }
  393.   else if (sym_rec->is_text_function ())
  394.     {
  395.       if (print)
  396.     output_buf << name << " is a builtin text-function\n";
  397.       else
  398.     retval = "builtin text-function";
  399.     }
  400.   else if (sym_rec->is_builtin_function ())
  401.     {
  402.       if (print)
  403.     output_buf << name << " is a builtin function\n";
  404.       else
  405.     retval = "builtin function";
  406.     }
  407.   else if (sym_rec->is_user_variable ())
  408.     {
  409.       if (print)
  410.     output_buf << name << " is a user-defined variable\n";
  411.       else
  412.     retval = "user-defined variable";
  413.     }
  414.   else if (sym_rec->is_builtin_variable ())
  415.     {
  416.       if (print)
  417.     output_buf << name << " is a builtin variable\n";
  418.       else
  419.     retval = "builtin variable";
  420.     }
  421.   else
  422.     {
  423.       if (print)
  424.     output_buf << "which: `" << name
  425.       << "' has unknown type\n";
  426.       else
  427.     retval = "unknown type";
  428.     }
  429.  
  430.   return retval;
  431. }
  432.  
  433. static void
  434. display_symtab_names (ostrstream& output_buf, char **names,
  435.               int count, const char *desc)
  436. {
  437.   output_buf << "\n*** " << desc << ":\n\n";
  438.   if (names && count > 0)
  439.     list_in_columns (output_buf, names);
  440. }
  441.  
  442. static void
  443. simple_help (void)
  444. {
  445.   ostrstream output_buf;
  446.  
  447.   display_names_from_help_list (output_buf, operator_help (),
  448.                 "operators");
  449.  
  450.   display_names_from_help_list (output_buf, keyword_help (),
  451.                 "reserved words");
  452.  
  453. #ifdef LIST_SYMBOLS
  454. #undef LIST_SYMBOLS
  455. #endif
  456. #define LIST_SYMBOLS(type, msg) \
  457.   do \
  458.     { \
  459.       int count; \
  460.       char **names = global_sym_tab->list (count, 0, 0, 1, type); \
  461.       display_symtab_names (output_buf, names, count, msg); \
  462.       char **ptr = names; \
  463.       while (*ptr) \
  464.         delete [] *ptr++; \
  465.       delete [] names; \
  466.     } \
  467.   while (0)
  468.  
  469. // XXX FIXME XXX -- is this distinction needed?
  470.   LIST_SYMBOLS (symbol_def::TEXT_FUNCTION,
  471.         "text functions (these names are also reserved)");
  472.  
  473.   LIST_SYMBOLS (symbol_def::MAPPER_FUNCTION, "mapper functions");
  474.  
  475.   LIST_SYMBOLS (symbol_def::BUILTIN_FUNCTION, "general functions");
  476.  
  477.   LIST_SYMBOLS (symbol_def::BUILTIN_VARIABLE, "builtin variables");
  478.  
  479. // Also need to list variables and currently compiled functions from
  480. // the symbol table, if there are any.
  481.  
  482. // Also need to search octave_path for script files.
  483.  
  484.   char *path_elt = kpse_path_element (user_pref.loadpath);
  485.  
  486.   while (path_elt)
  487.     {
  488.       str_llist_type *elt_dirs = kpse_element_dirs (path_elt);
  489.  
  490.       str_llist_elt_type *dir;
  491.       for (dir = *elt_dirs; dir; dir = STR_LLIST_NEXT (*dir))
  492.     {
  493.       char *elt_dir = STR_LLIST (*dir);
  494.  
  495.       if (elt_dir)
  496.         {
  497.           int count;
  498.           char **names = get_fcn_file_names (count, elt_dir, 0);
  499.  
  500.           output_buf << "\n*** function files in "
  501.         << make_absolute (elt_dir, the_current_working_directory)
  502.           << ":\n\n";
  503.  
  504.           if (names && count > 0)
  505.         list_in_columns (output_buf, names);
  506.  
  507.           delete [] names;
  508.         }
  509.     }
  510.       path_elt = kpse_path_element (0);
  511.     }
  512.  
  513.   additional_help_message (output_buf);
  514.   output_buf << ends;
  515.   maybe_page_output (output_buf);
  516. }
  517.  
  518. static int
  519. try_info (const char *string, int force = 0)
  520. {
  521.   int status = 0;
  522.  
  523.   char *directory_name = strsave (user_pref.info_file);
  524.   char *temp = filename_non_directory (directory_name);
  525.  
  526.   if (temp != directory_name)
  527.     {
  528.       *temp = 0;
  529.       info_add_path (directory_name, INFOPATH_PREPEND);
  530.     }
  531.  
  532.   delete [] directory_name;
  533.  
  534.   NODE *initial_node = info_get_node (user_pref.info_file, 0);
  535.  
  536.   if (! initial_node)
  537.     {
  538.       warning ("can't find info file!\n");
  539.       status = -1;
  540.     }
  541.   else
  542.     {
  543.       status = initialize_info_session (initial_node, 0);
  544.  
  545.       if (status == 0 && (force || index_entry_exists (windows, string)))
  546.     {
  547.       terminal_clear_screen ();
  548.  
  549.       terminal_prep_terminal ();
  550.  
  551.       display_update_display (windows);
  552.  
  553.       info_last_executed_command = 0;
  554.  
  555.       if (! force)
  556.         do_info_index_search (windows, 0, string);
  557.  
  558.       char *format = replace_in_documentation
  559.         ("Type \"\\[quit]\" to quit, \"\\[get-help-window]\" for help.");
  560.  
  561.       window_message_in_echo_area (format);
  562.  
  563.       info_read_and_dispatch ();
  564.  
  565.       terminal_goto_xy (0, screenheight - 1);
  566.  
  567.       terminal_clear_to_eol ();
  568.  
  569.       terminal_unprep_terminal ();
  570.  
  571.       status = 1;
  572.     }
  573.  
  574.       finish_info_session (initial_node, 0);
  575.     }
  576.  
  577.   return status;
  578. }
  579.  
  580. int
  581. help_from_list (ostrstream& output_buf, const help_list *list,
  582.         const char *string, int usage)
  583. {
  584.   char *name;
  585.   while ((name = list->name) != 0)
  586.     {
  587.       if (strcmp (name, string) == 0)
  588.     {
  589.       if (usage)
  590.         output_buf << "\nusage: ";
  591.       else
  592.         {
  593.           output_buf << "\n*** " << string << ":\n\n";
  594.         }
  595.  
  596.       output_buf << list->help << "\n";
  597.  
  598.       return 1;
  599.     }
  600.       list++;
  601.     }
  602.   return 0;
  603. }
  604.  
  605. DEFUN_TEXT ("help", Fhelp, Shelp, -1, 1,
  606.   "help [-i] [topic ...]\n\
  607. \n\
  608. print cryptic yet witty messages")
  609. {
  610.   Octave_object retval;
  611.  
  612.   DEFINE_ARGV("help");
  613.  
  614.   if (argc == 1)
  615.     {
  616.       simple_help ();
  617.     }
  618.   else
  619.     {
  620.       if (argv[1] && strcmp (argv[1], "-i") == 0)
  621.     {
  622.       argc--;
  623.       argv++;
  624.  
  625.       if (argc == 1)
  626.         {
  627.           volatile sig_handler *old_sigint_handler;
  628.           old_sigint_handler = signal (SIGINT, SIG_IGN);
  629.  
  630.           try_info (0, 1);
  631.  
  632.           signal (SIGINT, old_sigint_handler);
  633.         }
  634.       else
  635.         {
  636.           while (--argc > 0)
  637.         {
  638.           argv++;
  639.  
  640.           if (! *argv || ! **argv)
  641.             continue;
  642.  
  643.           volatile sig_handler *old_sigint_handler;
  644.           old_sigint_handler = signal (SIGINT, SIG_IGN);
  645.  
  646.           if (! try_info (*argv))
  647.             {
  648.               message ("help",
  649.                    "sorry, `%s' is not indexed in the manual",
  650.                    *argv); 
  651.               sleep (2);
  652.             }
  653.  
  654.           signal (SIGINT, old_sigint_handler);
  655.         }
  656.         }
  657.     }
  658.       else
  659.     {
  660.       ostrstream output_buf;
  661.  
  662.       help_list *op_help_list = operator_help ();
  663.       help_list *kw_help_list = keyword_help ();
  664.  
  665.       while (--argc > 0)
  666.         {
  667.           argv++;
  668.  
  669.           if (! *argv || ! **argv)
  670.         continue;
  671.  
  672.           if (help_from_list (output_buf, op_help_list, *argv, 0))
  673.         continue;
  674.  
  675.           if (help_from_list (output_buf, kw_help_list, *argv, 0))
  676.         continue;
  677.  
  678.           symbol_record *sym_rec = lookup_by_name (*argv, 0);
  679.  
  680.           if (sym_rec && sym_rec->is_defined ())
  681.         {
  682.           char *h = sym_rec->help ();
  683.           if (h && *h)
  684.             {
  685.               print_symbol_type (output_buf, sym_rec, *argv, 1);
  686.               output_buf << "\n" << h << "\n";
  687.               continue;
  688.             }
  689.         }
  690.  
  691.           char *path = fcn_file_in_path (*argv);
  692.           char *h = get_help_from_file (path);
  693.           if (h && *h)
  694.         {
  695.           output_buf << *argv << " is the file:\n"
  696.             << path << "\n\n" << h << "\n";
  697.           delete [] h;
  698.           delete [] path;
  699.           continue;
  700.         }
  701.           delete [] path;
  702.  
  703.           output_buf << "\nhelp: sorry, `" << *argv
  704.         << "' is not documented\n"; 
  705.         }
  706.  
  707.       additional_help_message (output_buf);
  708.       output_buf << ends;
  709.       maybe_page_output (output_buf);
  710.     }
  711.     }
  712.  
  713.   DELETE_ARGV;
  714.  
  715.   return retval;
  716. }
  717.  
  718. DEFUN_TEXT ("type", Ftype, Stype, -1, 1,
  719.   "type NAME ...]\n\
  720. \n\
  721. display the definition of each NAME that refers to a function")
  722. {
  723.   Octave_object retval;
  724.  
  725.   DEFINE_ARGV("type");
  726.  
  727.   if (argc > 1)
  728.     {
  729. // XXX FIXME XXX -- we should really use getopt ()
  730.       int quiet = 0;
  731.       if (argv[1] && strcmp (argv[1], "-q") == 0)
  732.     {
  733.       quiet = 1;
  734.       argc--;
  735.       argv++;
  736.     }
  737.  
  738.       ostrstream output_buf;
  739.  
  740.       while (--argc > 0)
  741.     {
  742.       argv++;
  743.  
  744.       if (! *argv || ! **argv)
  745.         continue;
  746.  
  747.       symbol_record *sym_rec = lookup_by_name (*argv, 0);
  748.  
  749.       if (sym_rec)
  750.         {
  751.           if (sym_rec->is_user_function ())
  752.         {
  753.           tree_fvc *defn = sym_rec->def ();
  754.  
  755.           if (nargout == 0 && ! quiet)
  756.             output_buf << *argv << " is a user-defined function\n";
  757.  
  758.           defn->print_code (output_buf);
  759.         }
  760.  
  761. // XXX FIXME XXX -- this code should be shared with Fwhich
  762.  
  763.           else if (sym_rec->is_text_function ())
  764.         output_buf << *argv << " is a builtin text-function\n";
  765.           else if (sym_rec->is_builtin_function ())
  766.         output_buf << *argv << " is a builtin function\n";
  767.           else if (sym_rec->is_user_variable ())
  768.         {
  769.           tree_fvc *defn = sym_rec->def ();
  770.  
  771.           if (nargout == 0 && ! quiet)
  772.             output_buf << *argv << " is a user-defined variable\n";
  773.  
  774.           defn->print_code (output_buf);
  775.  
  776.           if (nargout == 0)
  777.             output_buf << "\n";
  778.         }
  779.           else if (sym_rec->is_builtin_variable ())
  780.         {
  781.           tree_fvc *defn = sym_rec->def ();
  782.  
  783.           if (nargout == 0 && ! quiet)
  784.             output_buf << *argv << " is a builtin variable\n";
  785.  
  786.           defn->print_code (output_buf);
  787.  
  788.           if (nargout == 0)
  789.             output_buf << "\n";
  790.         }
  791.           else
  792.         output_buf << "type: `" << *argv << "' has unknown type!\n";
  793.         }
  794.       else
  795.         output_buf << "type: `" << *argv << "' undefined\n";
  796.     }
  797.  
  798.       output_buf << ends;
  799.  
  800.       if (nargout == 0)
  801.     maybe_page_output (output_buf);
  802.       else
  803.     {
  804.       char *s = output_buf.str ();
  805.       retval = s;
  806.       delete s;
  807.     }
  808.     }
  809.   else
  810.     print_usage ("type");
  811.  
  812.   DELETE_ARGV;
  813.  
  814.   return retval;
  815. }
  816.  
  817. DEFUN_TEXT ("which", Fwhich, Swhich, -1, 1,
  818.   "which NAME ...]\n\
  819. \n\
  820. display the type of each NAME.  If NAME is defined from an function\n\
  821. file, print the full name of the file.")
  822. {
  823.   Octave_object retval;
  824.  
  825.   DEFINE_ARGV("which");
  826.  
  827.   if (argc > 1)
  828.     {
  829.       if (nargout > 0)
  830.     retval.resize (argc-1, Matrix ());
  831.  
  832.       ostrstream output_buf;
  833.  
  834.       for (int i = 0; i < argc-1; i++)
  835.     {
  836.       argv++;
  837.  
  838.       if (! *argv || ! **argv)
  839.         continue;
  840.  
  841.       symbol_record *sym_rec = lookup_by_name (*argv, 0);
  842.  
  843.       if (sym_rec)
  844.         {
  845.           int print = (nargout == 0);
  846.           char *tmp = print_symbol_type (output_buf, sym_rec,
  847.                          *argv, print);
  848.           if (! print)
  849.         retval(i) = tmp;
  850.         }
  851.       else
  852.         {
  853.           if (nargout == 0)
  854.         output_buf << "which: `" << *argv << "' is undefined\n";
  855.           else
  856.         retval(i) = "undefined";
  857.         }
  858.     }
  859.       output_buf << ends;
  860.       maybe_page_output (output_buf);
  861.     }
  862.   else
  863.     print_usage ("which");
  864.  
  865.   DELETE_ARGV;
  866.  
  867.   return retval;
  868. }
  869.  
  870. /*
  871. ;;; Local Variables: ***
  872. ;;; mode: C++ ***
  873. ;;; page-delimiter: "^/\\*" ***
  874. ;;; End: ***
  875. */
  876.