symtab.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2009 VZLU Prague, a.s.
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include "file-ops.h"
00029 #include "file-stat.h"
00030 #include "oct-env.h"
00031 #include "oct-time.h"
00032 #include "singleton-cleanup.h"
00033 
00034 #include "debug.h"
00035 #include "defun.h"
00036 #include "dirfns.h"
00037 #include "input.h"
00038 #include "load-path.h"
00039 #include "ov-fcn.h"
00040 #include "ov-usr-fcn.h"
00041 #include "pager.h"
00042 #include "parse.h"
00043 #include "pt-arg-list.h"
00044 #include "symtab.h"
00045 #include "unwind-prot.h"
00046 #include "utils.h"
00047 
00048 symbol_table *symbol_table::instance = 0;
00049 
00050 symbol_table::scope_id_cache *symbol_table::scope_id_cache::instance = 0;
00051 
00052 std::map<symbol_table::scope_id, symbol_table*> symbol_table::all_instances;
00053 
00054 std::map<std::string, octave_value> symbol_table::global_table;
00055 
00056 std::map<std::string, symbol_table::fcn_info> symbol_table::fcn_table;
00057 
00058 std::map<std::string, std::set<std::string> > symbol_table::class_precedence_table;
00059 
00060 std::map<std::string, std::list<std::string> > symbol_table::parent_map;
00061 
00062 const symbol_table::scope_id symbol_table::xglobal_scope = 0;
00063 const symbol_table::scope_id symbol_table::xtop_scope = 1;
00064 
00065 symbol_table::scope_id symbol_table::xcurrent_scope = 1;
00066 
00067 symbol_table::context_id symbol_table::xcurrent_context = 0;
00068 
00069 // Should Octave always check to see if function files have changed
00070 // since they were last compiled?
00071 static int Vignore_function_time_stamp = 1;
00072 
00073 void
00074 symbol_table::scope_id_cache::create_instance (void)
00075 {
00076   instance = new scope_id_cache ();
00077 
00078   singleton_cleanup_list::add (cleanup_instance);
00079 }
00080 
00081 void
00082 symbol_table::symbol_record::symbol_record_rep::dump
00083   (std::ostream& os, const std::string& prefix) const
00084 {
00085   octave_value val = varval (xcurrent_context);
00086 
00087   os << prefix << name;
00088 
00089   if (val.is_defined ())
00090     {
00091       os << " ["
00092          << (is_local () ? "l" : "")
00093          << (is_automatic () ? "a" : "")
00094          << (is_formal () ? "f" : "")
00095          << (is_hidden () ? "h" : "")
00096          << (is_inherited () ? "i" : "")
00097          << (is_global () ? "g" : "")
00098          << (is_persistent () ? "p" : "")
00099          << "] ";
00100       val.dump (os);
00101     }
00102 
00103   os << "\n";
00104 }
00105 
00106 octave_value
00107 symbol_table::symbol_record::find (const octave_value_list& args) const
00108 {
00109   octave_value retval;
00110 
00111   if (is_global ())
00112     retval = symbol_table::global_varref (name ());
00113   else
00114     {
00115       retval = varval ();
00116 
00117       if (retval.is_undefined ())
00118         {
00119           // Use cached fcn_info pointer if possible.
00120           if (rep->finfo)
00121             retval = rep->finfo->find (args);
00122           else
00123             {
00124               retval = symbol_table::find_function (name (), args);
00125 
00126               if (retval.is_defined ())
00127                 rep->finfo = get_fcn_info (name ());
00128             }
00129         }
00130     }
00131 
00132   return retval;
00133 }
00134 
00135 // Check the load path to see if file that defined this is still
00136 // visible.  If the file is no longer visible, then erase the
00137 // definition and move on.  If the file is visible, then we also
00138 // need to check to see whether the file has changed since the the
00139 // function was loaded/parsed.  However, this check should only
00140 // happen once per prompt (for files found from relative path
00141 // elements, we also check if the working directory has changed
00142 // since the last time the function was loaded/parsed).
00143 //
00144 // FIXME -- perhaps this should be done for all loaded functions when
00145 // the prompt is printed or the directory has changed, and then we
00146 // would not check for it when finding symbol definitions.
00147 
00148 static inline bool
00149 load_out_of_date_fcn (const std::string& ff, const std::string& dir_name,
00150                       octave_value& function,
00151                       const std::string& dispatch_type = std::string ())
00152 {
00153   bool retval = false;
00154 
00155   octave_function *fcn = load_fcn_from_file (ff, dir_name, dispatch_type);
00156 
00157   if (fcn)
00158     {
00159       retval = true;
00160 
00161       function = octave_value (fcn);
00162     }
00163   else
00164     function = octave_value ();
00165 
00166   return retval;
00167 }
00168 
00169 bool
00170 out_of_date_check (octave_value& function,
00171                    const std::string& dispatch_type,
00172                    bool check_relative)
00173 {
00174   bool retval = false;
00175 
00176   octave_function *fcn = function.function_value (true);
00177 
00178   if (fcn)
00179     {
00180       // FIXME -- we need to handle subfunctions properly here.
00181 
00182       if (! fcn->is_subfunction ())
00183         {
00184           std::string ff = fcn->fcn_file_name ();
00185 
00186           if (! ff.empty ())
00187             {
00188               octave_time tc = fcn->time_checked ();
00189 
00190               bool relative = check_relative && fcn->is_relative ();
00191 
00192               if (tc < Vlast_prompt_time
00193                   || (relative && tc < Vlast_chdir_time))
00194                 {
00195                   bool clear_breakpoints = false;
00196                   std::string nm = fcn->name ();
00197 
00198                   bool is_same_file = false;
00199 
00200                   std::string file;
00201                   std::string dir_name;
00202 
00203                   if (check_relative)
00204                     {
00205                       int nm_len = nm.length ();
00206 
00207                       if (octave_env::absolute_pathname (nm)
00208                           && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
00209                                               || nm.substr (nm_len-4) == ".mex"))
00210                               || (nm_len > 2 && nm.substr (nm_len-2) == ".m")))
00211                         file = nm;
00212                       else
00213                         {
00214                           // We don't want to make this an absolute name,
00215                           // because load_fcn_file looks at the name to
00216                           // decide whether it came from a relative lookup.
00217 
00218                           if (! dispatch_type.empty ())
00219                             {
00220                               file = load_path::find_method (dispatch_type, nm,
00221                                                              dir_name);
00222 
00223                               if (file.empty ())
00224                                 {
00225                                   const std::list<std::string>& plist
00226                                     = symbol_table::parent_classes (dispatch_type);
00227                                   std::list<std::string>::const_iterator it
00228                                     = plist.begin ();
00229 
00230                                   while (it != plist.end ())
00231                                     {
00232                                       file = load_path::find_method (*it, nm, dir_name);
00233                                       if (! file.empty ())
00234                                         break;
00235 
00236                                       it++;
00237                                     }
00238                                 }
00239                             }
00240 
00241                           // Maybe it's an autoload?
00242                           if (file.empty ())
00243                             file = lookup_autoload (nm);
00244 
00245                           if (file.empty ())
00246                             file = load_path::find_fcn (nm, dir_name);
00247                         }
00248 
00249                       if (! file.empty ())
00250                         is_same_file = same_file (file, ff);
00251                     }
00252                   else
00253                     {
00254                       is_same_file = true;
00255                       file = ff;
00256                     }
00257 
00258                   if (file.empty ())
00259                     {
00260                       // Can't see this function from current
00261                       // directory, so we should clear it.
00262 
00263                       function = octave_value ();
00264 
00265                       clear_breakpoints = true;
00266                     }
00267                   else if (is_same_file)
00268                     {
00269                       // Same file.  If it is out of date, then reload it.
00270 
00271                       octave_time ottp = fcn->time_parsed ();
00272                       time_t tp = ottp.unix_time ();
00273 
00274                       fcn->mark_fcn_file_up_to_date (octave_time ());
00275 
00276                       if (! (Vignore_function_time_stamp == 2
00277                              || (Vignore_function_time_stamp
00278                                  && fcn->is_system_fcn_file ())))
00279                         {
00280                           file_stat fs (ff);
00281 
00282                           if (fs)
00283                             {
00284                               if (fs.is_newer (tp))
00285                                 {
00286                                   retval = load_out_of_date_fcn (ff, dir_name,
00287                                                                  function,
00288                                                                  dispatch_type);
00289 
00290                                   clear_breakpoints = true;
00291                                 }
00292                             }
00293                           else
00294                             {
00295                               function = octave_value ();
00296 
00297                               clear_breakpoints = true;
00298                             }
00299                         }
00300                     }
00301                   else
00302                     {
00303                       // Not the same file, so load the new file in
00304                       // place of the old.
00305 
00306                       retval = load_out_of_date_fcn (file, dir_name, function,
00307                                                      dispatch_type);
00308 
00309                       clear_breakpoints = true;
00310                     }
00311 
00312                   // If the function has been replaced then clear any
00313                   // breakpoints associated with it
00314                   if (clear_breakpoints)
00315                     bp_table::remove_all_breakpoints_in_file (nm, true);
00316                 }
00317             }
00318         }
00319     }
00320 
00321   return retval;
00322 }
00323 
00324 octave_value
00325 symbol_table::fcn_info::fcn_info_rep::load_private_function
00326   (const std::string& dir_name)
00327 {
00328   octave_value retval;
00329 
00330   std::string file_name = load_path::find_private_fcn (dir_name, name);
00331 
00332   if (! file_name.empty ())
00333     {
00334       octave_function *fcn = load_fcn_from_file (file_name, dir_name);
00335 
00336       if (fcn)
00337         {
00338           std::string class_name;
00339 
00340           size_t pos = dir_name.find_last_of (file_ops::dir_sep_chars ());
00341 
00342           if (pos != std::string::npos)
00343             {
00344               std::string tmp = dir_name.substr (pos+1);
00345 
00346               if (tmp[0] == '@')
00347                 class_name = tmp.substr (1);
00348             }
00349 
00350           fcn->mark_as_private_function (class_name);
00351 
00352           retval = octave_value (fcn);
00353 
00354           private_functions[dir_name] = retval;
00355         }
00356     }
00357 
00358   return retval;
00359 }
00360 
00361 octave_value
00362 symbol_table::fcn_info::fcn_info_rep::load_class_constructor (void)
00363 {
00364   octave_value retval;
00365 
00366   std::string dir_name;
00367 
00368   std::string file_name = load_path::find_method (name, name, dir_name);
00369 
00370   if (! file_name.empty ())
00371     {
00372       octave_function *fcn = load_fcn_from_file (file_name, dir_name, name);
00373 
00374       if (fcn)
00375         {
00376           retval = octave_value (fcn);
00377 
00378           class_constructors[name] = retval;
00379         }
00380     }
00381 
00382   return retval;
00383 }
00384 
00385 octave_value
00386 symbol_table::fcn_info::fcn_info_rep::load_class_method
00387   (const std::string& dispatch_type)
00388 {
00389   octave_value retval;
00390 
00391   if (name == dispatch_type)
00392     retval = load_class_constructor ();
00393   else
00394     {
00395       std::string dir_name;
00396 
00397       std::string file_name = load_path::find_method (dispatch_type, name,
00398                                                       dir_name);
00399 
00400       if (! file_name.empty ())
00401         {
00402           octave_function *fcn = load_fcn_from_file (file_name, dir_name,
00403                                                      dispatch_type);
00404 
00405           if (fcn)
00406             {
00407               retval = octave_value (fcn);
00408 
00409               class_methods[dispatch_type] = retval;
00410             }
00411         }
00412 
00413       if (retval.is_undefined ())
00414         {
00415           // Search parent classes
00416 
00417           const std::list<std::string>& plist = parent_classes (dispatch_type);
00418 
00419           std::list<std::string>::const_iterator it = plist.begin ();
00420 
00421           while (it != plist.end ())
00422             {
00423               retval = find_method (*it);
00424 
00425               if (retval.is_defined ())
00426                 {
00427                   class_methods[dispatch_type] = retval;
00428                   break;
00429                 }
00430 
00431               it++;
00432             }
00433         }
00434     }
00435 
00436   return retval;
00437 }
00438 
00439 void
00440 symbol_table::fcn_info::fcn_info_rep:: mark_subfunction_in_scope_as_private
00441   (scope_id scope, const std::string& class_name)
00442 {
00443   scope_val_iterator p = subfunctions.find (scope);
00444 
00445   if (p != subfunctions.end ())
00446     {
00447       octave_function *fcn = p->second.function_value ();
00448 
00449       if (fcn)
00450         fcn->mark_as_private_function (class_name);
00451     }
00452 }
00453 
00454 void
00455 symbol_table::fcn_info::fcn_info_rep::print_dispatch (std::ostream& os) const
00456 {
00457   if (dispatch_map.empty ())
00458     os << "dispatch: " << name << " is not overloaded" << std::endl;
00459   else
00460     {
00461       os << "Overloaded function " << name << ":\n\n";
00462 
00463       for (dispatch_map_const_iterator p = dispatch_map.begin ();
00464            p != dispatch_map.end (); p++)
00465         os << "  " << name << " (" << p->first << ", ...) -> "
00466            << p->second << " (" << p->first << ", ...)\n";
00467 
00468       os << std::endl;
00469     }
00470 }
00471 
00472 std::string
00473 symbol_table::fcn_info::fcn_info_rep::help_for_dispatch (void) const
00474 {
00475   std::string retval;
00476 
00477   if (! dispatch_map.empty ())
00478     {
00479       retval = "Overloaded function:\n\n";
00480 
00481       for (dispatch_map_const_iterator p = dispatch_map.begin ();
00482            p != dispatch_map.end (); p++)
00483         retval += "  " + p->second + " (" + p->first + ", ...)\n\n";
00484     }
00485 
00486   return retval;
00487 }
00488 
00489 // :-) JWE, can you parse this? Returns a 2D array with second dimension equal
00490 // to btyp_num_types (static constant). Only the leftmost dimension can be
00491 // variable in C/C++. Typedefs are boring.
00492 
00493 static builtin_type_t (*build_sup_table (void))[btyp_num_types]
00494 {
00495   static builtin_type_t sup_table[btyp_num_types][btyp_num_types];
00496   for (int i = 0; i < btyp_num_types; i++)
00497     for (int j = 0; j < btyp_num_types; j++)
00498       {
00499         builtin_type_t ityp = static_cast<builtin_type_t> (i);
00500         builtin_type_t jtyp = static_cast<builtin_type_t> (j);
00501         // FIXME: Is this really right?
00502         bool use_j =
00503           (jtyp == btyp_func_handle || ityp == btyp_bool
00504            || (btyp_isarray (ityp)
00505                && (! btyp_isarray (jtyp)
00506                    || (btyp_isinteger (jtyp) && ! btyp_isinteger (ityp))
00507                    || ((ityp == btyp_double || ityp == btyp_complex || ityp == btyp_char)
00508                        && (jtyp == btyp_float || jtyp == btyp_float_complex)))));
00509 
00510         sup_table[i][j] = use_j ? jtyp : ityp;
00511       }
00512 
00513   return sup_table;
00514 }
00515 
00516 std::string
00517 get_dispatch_type (const octave_value_list& args,
00518                    builtin_type_t& builtin_type)
00519 {
00520   static builtin_type_t (*sup_table)[btyp_num_types] = build_sup_table ();
00521   std::string dispatch_type;
00522 
00523   int n = args.length ();
00524 
00525   if (n > 0)
00526     {
00527       int i = 0;
00528       builtin_type = args(0).builtin_type ();
00529       if (builtin_type != btyp_unknown)
00530         {
00531           for (i = 1; i < n; i++)
00532             {
00533               builtin_type_t bti = args(i).builtin_type ();
00534               if (bti != btyp_unknown)
00535                 builtin_type = sup_table[builtin_type][bti];
00536               else
00537                 {
00538                   builtin_type = btyp_unknown;
00539                   break;
00540                 }
00541             }
00542         }
00543 
00544       if (builtin_type == btyp_unknown)
00545         {
00546           // There's a non-builtin class in the argument list.
00547           dispatch_type = args(i).class_name ();
00548 
00549           for (int j = i+1; j < n; j++)
00550             {
00551               octave_value arg = args(j);
00552 
00553               if (arg.builtin_type () == btyp_unknown)
00554                 {
00555                   std::string cname = arg.class_name ();
00556 
00557                   // Only switch to type of ARG if it is marked superior
00558                   // to the current DISPATCH_TYPE.
00559                   if (! symbol_table::is_superiorto (dispatch_type, cname)
00560                       && symbol_table::is_superiorto (cname, dispatch_type))
00561                     dispatch_type = cname;
00562                 }
00563             }
00564         }
00565       else
00566         dispatch_type = btyp_class_name[builtin_type];
00567     }
00568   else
00569     builtin_type = btyp_unknown;
00570 
00571   return dispatch_type;
00572 }
00573 
00574 std::string
00575 get_dispatch_type (const octave_value_list& args)
00576 {
00577   builtin_type_t builtin_type;
00578   return get_dispatch_type (args, builtin_type);
00579 }
00580 
00581 // Find the definition of NAME according to the following precedence
00582 // list:
00583 //
00584 //   variable
00585 //   subfunction
00586 //   private function
00587 //   class method
00588 //   class constructor
00589 //   legacy dispatch
00590 //   command-line function
00591 //   autoload function
00592 //   function on the path
00593 //   built-in function
00594 //
00595 // Matlab documentation states that constructors have higher precedence
00596 // than methods, but that does not seem to be the case.
00597 
00598 octave_value
00599 symbol_table::fcn_info::fcn_info_rep::find (const octave_value_list& args,
00600                                             bool local_funcs)
00601 {
00602   octave_value retval = xfind (args, local_funcs);
00603 
00604   if (! (error_state || retval.is_defined ()))
00605     {
00606       // It is possible that the user created a file on the fly since
00607       // the last prompt or chdir, so try updating the load path and
00608       // searching again.
00609 
00610       load_path::update ();
00611 
00612       retval = xfind (args, local_funcs);
00613     }
00614 
00615   return retval;
00616 }
00617 
00618 octave_value
00619 symbol_table::fcn_info::fcn_info_rep::xfind (const octave_value_list& args,
00620                                              bool local_funcs)
00621 {
00622   if (local_funcs)
00623     {
00624       // Subfunction.  I think it only makes sense to check for
00625       // subfunctions if we are currently executing a function defined
00626       // from a .m file.
00627 
00628       scope_val_iterator r = subfunctions.find (xcurrent_scope);
00629 
00630       octave_user_function *curr_fcn = symbol_table::get_curr_fcn ();
00631 
00632       if (r != subfunctions.end ())
00633         {
00634           // FIXME -- out-of-date check here.
00635 
00636           return r->second;
00637         }
00638       else
00639         {
00640           if (curr_fcn)
00641             {
00642               // FIXME -- maybe it would be better if we could just get
00643               // a pointer to the parent function so we would have
00644               // access to all info about it instead of only being able
00645               // to query the current function for specific bits of info
00646               // about its parent function?
00647 
00648               scope_id pscope = curr_fcn->parent_fcn_scope ();
00649 
00650               if (pscope > 0)
00651                 {
00652                   r = subfunctions.find (pscope);
00653 
00654                   if (r != subfunctions.end ())
00655                     {
00656                       // FIXME -- out-of-date check here.
00657 
00658                       return r->second;
00659                     }
00660                 }
00661             }
00662         }
00663 
00664       // Private function.
00665 
00666       if (curr_fcn)
00667         {
00668           std::string dir_name = curr_fcn->dir_name ();
00669 
00670           if (! dir_name.empty ())
00671             {
00672               str_val_iterator q = private_functions.find (dir_name);
00673 
00674               if (q == private_functions.end ())
00675                 {
00676                   octave_value val = load_private_function (dir_name);
00677 
00678                   if (val.is_defined ())
00679                     return val;
00680                 }
00681               else
00682                 {
00683                   octave_value& fval = q->second;
00684 
00685                   if (fval.is_defined ())
00686                     out_of_date_check (fval, "", false);
00687 
00688                   if (fval.is_defined ())
00689                     return fval;
00690                   else
00691                     {
00692                       octave_value val = load_private_function (dir_name);
00693 
00694                       if (val.is_defined ())
00695                         return val;
00696                     }
00697                 }
00698             }
00699         }
00700     }
00701 
00702   // Class methods.
00703 
00704   if (! args.empty ())
00705     {
00706       std::string dispatch_type = get_dispatch_type (args);
00707 
00708       octave_value fcn = find_method (dispatch_type);
00709 
00710       if (fcn.is_defined ())
00711         return fcn;
00712     }
00713 
00714   // Class constructors.  The class name and function name are the same.
00715 
00716   str_val_iterator q = class_constructors.find (name);
00717 
00718   if (q == class_constructors.end ())
00719     {
00720       octave_value val = load_class_constructor ();
00721 
00722       if (val.is_defined ())
00723         return val;
00724     }
00725   else
00726     {
00727       octave_value& fval = q->second;
00728 
00729       if (fval.is_defined ())
00730         out_of_date_check (fval, name);
00731 
00732       if (fval.is_defined ())
00733         return fval;
00734       else
00735         {
00736           octave_value val = load_class_constructor ();
00737 
00738           if (val.is_defined ())
00739             return val;
00740         }
00741     }
00742 
00743   // Legacy dispatch.
00744 
00745   if (! args.empty () && ! dispatch_map.empty ())
00746     {
00747       std::string dispatch_type = args(0).type_name ();
00748 
00749       std::string fname;
00750 
00751       dispatch_map_iterator p = dispatch_map.find (dispatch_type);
00752 
00753       if (p == dispatch_map.end ())
00754         p = dispatch_map.find ("any");
00755 
00756       if (p != dispatch_map.end ())
00757         {
00758           fname = p->second;
00759 
00760           octave_value fcn
00761             = symbol_table::find_function (fname, args);
00762 
00763           if (fcn.is_defined ())
00764             return fcn;
00765         }
00766     }
00767 
00768   // Command-line function.
00769 
00770   if (cmdline_function.is_defined ())
00771     return cmdline_function;
00772 
00773   // Autoload?
00774 
00775   octave_value fcn = find_autoload ();
00776 
00777   if (fcn.is_defined ())
00778     return fcn;
00779 
00780   // Function on the path.
00781 
00782   fcn = find_user_function ();
00783 
00784   if (fcn.is_defined ())
00785     return fcn;
00786 
00787   // Built-in function (might be undefined).
00788 
00789   return built_in_function;
00790 }
00791 
00792 // Find the definition of NAME according to the following precedence
00793 // list:
00794 //
00795 //   built-in function
00796 //   function on the path
00797 //   autoload function
00798 //   command-line function
00799 //   private function
00800 //   subfunction
00801 
00802 // This function is used to implement the "builtin" function, which
00803 // searches for "built-in" functions.  In Matlab, "builtin" only
00804 // returns functions that are actually built-in to the interpreter.
00805 // But since the list of built-in functions is different in Octave and
00806 // Matlab, we also search up the precedence list until we find
00807 // something that matches.  Note that we are only searching by name,
00808 // so class methods, constructors, and legacy dispatch functions are
00809 // skipped.
00810 
00811 octave_value
00812 symbol_table::fcn_info::fcn_info_rep::builtin_find (void)
00813 {
00814   octave_value retval = x_builtin_find ();
00815 
00816   if (! retval.is_defined ())
00817     {
00818       // It is possible that the user created a file on the fly since
00819       // the last prompt or chdir, so try updating the load path and
00820       // searching again.
00821 
00822       load_path::update ();
00823 
00824       retval = x_builtin_find ();
00825     }
00826 
00827   return retval;
00828 }
00829 
00830 octave_value
00831 symbol_table::fcn_info::fcn_info_rep::x_builtin_find (void)
00832 {
00833   // Built-in function.
00834   if (built_in_function.is_defined ())
00835     return built_in_function;
00836 
00837   // Function on the path.
00838 
00839   octave_value fcn = find_user_function ();
00840 
00841   if (fcn.is_defined ())
00842     return fcn;
00843 
00844   // Autoload?
00845 
00846   fcn = find_autoload ();
00847 
00848   if (fcn.is_defined ())
00849     return fcn;
00850 
00851   // Command-line function.
00852 
00853   if (cmdline_function.is_defined ())
00854     return cmdline_function;
00855 
00856   // Private function.
00857 
00858   octave_user_function *curr_fcn = symbol_table::get_curr_fcn ();
00859 
00860   if (curr_fcn)
00861     {
00862       std::string dir_name = curr_fcn->dir_name ();
00863 
00864       if (! dir_name.empty ())
00865         {
00866           str_val_iterator q = private_functions.find (dir_name);
00867 
00868           if (q == private_functions.end ())
00869             {
00870               octave_value val = load_private_function (dir_name);
00871 
00872               if (val.is_defined ())
00873                 return val;
00874             }
00875           else
00876             {
00877               octave_value& fval = q->second;
00878 
00879               if (fval.is_defined ())
00880                 out_of_date_check (fval);
00881 
00882               if (fval.is_defined ())
00883                 return fval;
00884               else
00885                 {
00886                   octave_value val = load_private_function (dir_name);
00887 
00888                   if (val.is_defined ())
00889                     return val;
00890                 }
00891             }
00892         }
00893     }
00894 
00895   // Subfunction.  I think it only makes sense to check for
00896   // subfunctions if we are currently executing a function defined
00897   // from a .m file.
00898 
00899   scope_val_iterator r = subfunctions.find (xcurrent_scope);
00900 
00901   if (r != subfunctions.end ())
00902     {
00903       // FIXME -- out-of-date check here.
00904 
00905       return r->second;
00906     }
00907   else if (curr_fcn)
00908     {
00909       scope_id pscope = curr_fcn->parent_fcn_scope ();
00910 
00911       if (pscope > 0)
00912         {
00913           r = subfunctions.find (pscope);
00914 
00915           if (r != subfunctions.end ())
00916             {
00917               // FIXME -- out-of-date check here.
00918 
00919               return r->second;
00920             }
00921         }
00922     }
00923 
00924   return octave_value ();
00925 }
00926 
00927 octave_value
00928 symbol_table::fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type)
00929 {
00930   octave_value retval;
00931 
00932   str_val_iterator q = class_methods.find (dispatch_type);
00933 
00934   if (q == class_methods.end ())
00935     {
00936       octave_value val = load_class_method (dispatch_type);
00937 
00938       if (val.is_defined ())
00939         return val;
00940     }
00941   else
00942     {
00943       octave_value& fval = q->second;
00944 
00945       if (fval.is_defined ())
00946         out_of_date_check (fval, dispatch_type);
00947 
00948       if (fval.is_defined ())
00949         return fval;
00950       else
00951         {
00952           octave_value val = load_class_method (dispatch_type);
00953 
00954           if (val.is_defined ())
00955             return val;
00956         }
00957     }
00958 
00959   return retval;
00960 }
00961 
00962 octave_value
00963 symbol_table::fcn_info::fcn_info_rep::find_autoload (void)
00964 {
00965   octave_value retval;
00966 
00967   // Autoloaded function.
00968 
00969   if (autoload_function.is_defined ())
00970     out_of_date_check (autoload_function);
00971 
00972   if (! autoload_function.is_defined ())
00973     {
00974       std::string file_name = lookup_autoload (name);
00975 
00976       if (! file_name.empty ())
00977         {
00978           size_t pos = file_name.find_last_of (file_ops::dir_sep_chars ());
00979 
00980           std::string dir_name = file_name.substr (0, pos);
00981 
00982           octave_function *fcn = load_fcn_from_file (file_name, dir_name,
00983                                                      "", name, true);
00984 
00985           if (fcn)
00986             autoload_function = octave_value (fcn);
00987         }
00988     }
00989 
00990   return autoload_function;
00991 }
00992 
00993 octave_value
00994 symbol_table::fcn_info::fcn_info_rep::find_user_function (void)
00995 {
00996   // Function on the path.
00997 
00998   if (function_on_path.is_defined ())
00999     out_of_date_check (function_on_path);
01000 
01001   if (! (error_state || function_on_path.is_defined ()))
01002     {
01003       std::string dir_name;
01004 
01005       std::string file_name = load_path::find_fcn (name, dir_name);
01006 
01007       if (! file_name.empty ())
01008         {
01009           octave_function *fcn = load_fcn_from_file (file_name, dir_name);
01010 
01011           if (fcn)
01012             function_on_path = octave_value (fcn);
01013         }
01014     }
01015 
01016   return function_on_path;
01017 }
01018 
01019 // Insert INF_CLASS in the set of class names that are considered
01020 // inferior to SUP_CLASS.  Return FALSE if INF_CLASS is currently
01021 // marked as superior to  SUP_CLASS.
01022 
01023 bool
01024 symbol_table::set_class_relationship (const std::string& sup_class,
01025                                       const std::string& inf_class)
01026 {
01027   class_precedence_table_const_iterator p
01028     = class_precedence_table.find (inf_class);
01029 
01030   if (p != class_precedence_table.end ())
01031     {
01032       const std::set<std::string>& inferior_classes = p->second;
01033 
01034       std::set<std::string>::const_iterator q
01035         = inferior_classes.find (sup_class);
01036 
01037       if (q != inferior_classes.end ())
01038         return false;
01039     }
01040 
01041   class_precedence_table[sup_class].insert (inf_class);
01042 
01043   return true;
01044 }
01045 
01046 // Has class A been marked as superior to class B?  Also returns
01047 // TRUE if B has been marked as inferior to A, since we only keep
01048 // one table, and convert inferiort information to a superiorto
01049 // relationship.  Two calls are required to determine whether there
01050 // is no relationship between two classes:
01051 //
01052 //  if (symbol_table::is_superiorto (a, b))
01053 //    // A is superior to B, or B has been marked inferior to A.
01054 //  else if (symbol_table::is_superiorto (b, a))
01055 //    // B is superior to A, or A has been marked inferior to B.
01056 //  else
01057 //    // No relation.
01058 
01059 bool
01060 symbol_table::is_superiorto (const std::string& a, const std::string& b)
01061 {
01062   bool retval = false;
01063 
01064   class_precedence_table_const_iterator p = class_precedence_table.find (a);
01065 
01066   if (p != class_precedence_table.end ())
01067     {
01068       const std::set<std::string>& inferior_classes = p->second;
01069       std::set<std::string>::const_iterator q = inferior_classes.find (b);
01070 
01071       if (q != inferior_classes.end ())
01072         retval = true;
01073     }
01074 
01075   return retval;
01076 }
01077 
01078 static std::string
01079 fcn_file_name (const octave_value& fcn)
01080 {
01081   const octave_function *f = fcn.function_value ();
01082 
01083   return f ? f->fcn_file_name () : std::string ();
01084 }
01085 
01086 void
01087 symbol_table::fcn_info::fcn_info_rep::dump
01088   (std::ostream& os, const std::string& prefix) const
01089 {
01090   os << prefix << name
01091      << " ["
01092      << (cmdline_function.is_defined () ? "c" : "")
01093      << (built_in_function.is_defined () ? "b" : "")
01094      << "]\n";
01095 
01096   std::string tprefix = prefix + "  ";
01097 
01098   if (autoload_function.is_defined ())
01099     os << tprefix << "autoload: "
01100        << fcn_file_name (autoload_function) << "\n";
01101 
01102   if (function_on_path.is_defined ())
01103     os << tprefix << "function from path: "
01104        << fcn_file_name (function_on_path) << "\n";
01105 
01106   if (! subfunctions.empty ())
01107     {
01108       for (scope_val_const_iterator p = subfunctions.begin ();
01109            p != subfunctions.end (); p++)
01110         os << tprefix << "subfunction: " << fcn_file_name (p->second)
01111            << " [" << p->first << "]\n";
01112     }
01113 
01114   if (! private_functions.empty ())
01115     {
01116       for (str_val_const_iterator p = private_functions.begin ();
01117            p != private_functions.end (); p++)
01118         os << tprefix << "private: " << fcn_file_name (p->second)
01119            << " [" << p->first << "]\n";
01120     }
01121 
01122   if (! class_constructors.empty ())
01123     {
01124       for (str_val_const_iterator p = class_constructors.begin ();
01125            p != class_constructors.end (); p++)
01126         os << tprefix << "constructor: " << fcn_file_name (p->second)
01127            << " [" << p->first << "]\n";
01128     }
01129 
01130   if (! class_methods.empty ())
01131     {
01132       for (str_val_const_iterator p = class_methods.begin ();
01133            p != class_methods.end (); p++)
01134         os << tprefix << "method: " << fcn_file_name (p->second)
01135            << " [" << p->first << "]\n";
01136     }
01137 
01138   if (! dispatch_map.empty ())
01139     {
01140       for (dispatch_map_const_iterator p = dispatch_map.begin ();
01141            p != dispatch_map.end (); p++)
01142         os << tprefix << "dispatch: " << fcn_file_name (p->second)
01143            << " [" << p->first << "]\n";
01144     }
01145 }
01146 
01147 octave_value
01148 symbol_table::find (const std::string& name,
01149                     const octave_value_list& args,
01150                     bool skip_variables,
01151                     bool local_funcs)
01152 {
01153   symbol_table *inst = get_instance (xcurrent_scope);
01154 
01155   return inst
01156     ? inst->do_find (name, args, skip_variables, local_funcs)
01157     : octave_value ();
01158 }
01159 
01160 octave_value
01161 symbol_table::builtin_find (const std::string& name)
01162 {
01163   symbol_table *inst = get_instance (xcurrent_scope);
01164 
01165   return inst ? inst->do_builtin_find (name) : octave_value ();
01166 }
01167 
01168 octave_value
01169 symbol_table::find_function (const std::string& name,
01170                              const octave_value_list& args,
01171                              bool local_funcs)
01172 {
01173   octave_value retval;
01174 
01175   if (! name.empty () && name[0] == '@')
01176     {
01177       // Look for a class specific function.
01178       std::string dispatch_type =
01179         name.substr (1, name.find_first_of (file_ops::dir_sep_str ()) - 1);
01180 
01181       std::string method =
01182         name.substr (name.find_last_of (file_ops::dir_sep_str ()) + 1,
01183                      std::string::npos);
01184 
01185       retval = find_method (method, dispatch_type);
01186     }
01187   else
01188     {
01189       size_t pos = name.find_first_of (Vfilemarker);
01190 
01191       if (pos == std::string::npos)
01192         retval = find (name, args, true, local_funcs);
01193       else
01194         {
01195           std::string fcn_scope = name.substr (0, pos);
01196           scope_id stored_scope = xcurrent_scope;
01197           xcurrent_scope = xtop_scope;
01198           octave_value parent = find_function (name.substr(0, pos),
01199                                                octave_value_list (), false);
01200 
01201           if (parent.is_defined ())
01202             {
01203               octave_function *parent_fcn = parent.function_value ();
01204 
01205               if (parent_fcn)
01206                 {
01207                   xcurrent_scope = parent_fcn->scope ();
01208 
01209                   if (xcurrent_scope > 1)
01210                     retval = find_function (name.substr (pos + 1), args);
01211                 }
01212             }
01213 
01214           xcurrent_scope = stored_scope;
01215         }
01216     }
01217 
01218   return retval;
01219 }
01220 
01221 void
01222 symbol_table::dump (std::ostream& os, scope_id scope)
01223 {
01224   if (scope == xglobal_scope)
01225     dump_global (os);
01226   else
01227     {
01228       symbol_table *inst = get_instance (scope, false);
01229 
01230       if (inst)
01231         {
01232           os << "*** dumping symbol table scope " << scope
01233              << " (" << inst->table_name << ")\n\n";
01234 
01235           std::map<std::string, octave_value> sfuns
01236             = symbol_table::subfunctions_defined_in_scope (scope);
01237 
01238           if (! sfuns.empty ())
01239             {
01240               os << "  subfunctions defined in this scope:\n";
01241 
01242               for (std::map<std::string, octave_value>::const_iterator p = sfuns.begin ();
01243                    p != sfuns.end (); p++)
01244                 os << "    " << p->first << "\n";
01245 
01246               os << "\n";
01247             }
01248 
01249           inst->do_dump (os);
01250         }
01251     }
01252 }
01253 
01254 void
01255 symbol_table::dump_global (std::ostream& os)
01256 {
01257   if (! global_table.empty ())
01258     {
01259       os << "*** dumping global symbol table\n\n";
01260 
01261       for (global_table_const_iterator p = global_table.begin ();
01262            p != global_table.end (); p++)
01263         {
01264           std::string nm = p->first;
01265           octave_value val = p->second;
01266 
01267           os << "  " << nm << " ";
01268           val.dump (os);
01269           os << "\n";
01270         }
01271     }
01272 }
01273 
01274 void
01275 symbol_table::dump_functions (std::ostream& os)
01276 {
01277   if (! fcn_table.empty ())
01278     {
01279       os << "*** dumping globally visible functions from symbol table\n"
01280          << "    (c=commandline, b=built-in)\n\n";
01281 
01282       for (fcn_table_const_iterator p = fcn_table.begin ();
01283            p != fcn_table.end (); p++)
01284         p->second.dump (os, "  ");
01285 
01286       os << "\n";
01287     }
01288 }
01289 
01290 void
01291 symbol_table::stash_dir_name_for_subfunctions (scope_id scope,
01292                                                const std::string& dir_name)
01293 {
01294   // FIXME -- is this the best way to do this?  Maybe it would be
01295   // better if we had a map from scope to list of subfunctions
01296   // stored with the function.  Do we?
01297 
01298   for (fcn_table_const_iterator p = fcn_table.begin ();
01299        p != fcn_table.end (); p++)
01300     {
01301       std::pair<std::string, octave_value> tmp
01302         = p->second.subfunction_defined_in_scope (scope);
01303 
01304       std::string nm = tmp.first;
01305 
01306       if (! nm.empty ())
01307         {
01308           octave_value& fcn = tmp.second;
01309 
01310           octave_user_function *f = fcn.user_function_value ();
01311 
01312           if (f)
01313             f->stash_dir_name (dir_name);
01314         }
01315     }
01316 }
01317 
01318 octave_value
01319 symbol_table::do_find (const std::string& name,
01320                        const octave_value_list& args,
01321                        bool skip_variables,
01322                        bool local_funcs)
01323 {
01324   octave_value retval;
01325 
01326   // Variable.
01327 
01328   if (! skip_variables)
01329     {
01330       table_iterator p = table.find (name);
01331 
01332       if (p != table.end ())
01333         {
01334           symbol_record sr = p->second;
01335 
01336           // FIXME -- should we be using something other than varref here?
01337 
01338           if (sr.is_global ())
01339             return symbol_table::global_varref (name);
01340           else
01341             {
01342               octave_value& val = sr.varref ();
01343 
01344               if (val.is_defined ())
01345                 return val;
01346             }
01347         }
01348     }
01349 
01350   fcn_table_iterator p = fcn_table.find (name);
01351 
01352   if (p != fcn_table.end ())
01353     return p->second.find (args, local_funcs);
01354   else
01355     {
01356       fcn_info finfo (name);
01357 
01358       octave_value fcn = finfo.find (args, local_funcs);
01359 
01360       if (fcn.is_defined ())
01361         fcn_table[name] = finfo;
01362 
01363       return fcn;
01364     }
01365 
01366   return retval;
01367 }
01368 
01369 octave_value
01370 symbol_table::do_builtin_find (const std::string& name)
01371 {
01372   octave_value retval;
01373 
01374   fcn_table_iterator p = fcn_table.find (name);
01375 
01376   if (p != fcn_table.end ())
01377     return p->second.builtin_find ();
01378   else
01379     {
01380       fcn_info finfo (name);
01381 
01382       octave_value fcn = finfo.builtin_find ();
01383 
01384       if (fcn.is_defined ())
01385         fcn_table[name] = finfo;
01386 
01387       return fcn;
01388     }
01389 
01390   return retval;
01391 }
01392 
01393 void
01394 symbol_table::do_dump (std::ostream& os)
01395 {
01396   if (! persistent_table.empty ())
01397     {
01398       os << "  persistent variables in this scope:\n\n";
01399 
01400       for (persistent_table_const_iterator p = persistent_table.begin ();
01401            p != persistent_table.end (); p++)
01402         {
01403           std::string nm = p->first;
01404           octave_value val = p->second;
01405 
01406           os << "    " << nm << " ";
01407           val.dump (os);
01408           os << "\n";
01409         }
01410 
01411       os << "\n";
01412     }
01413 
01414   if (! table.empty ())
01415     {
01416       os << "  other symbols in this scope (l=local; a=auto; f=formal\n"
01417          << "    h=hidden; i=inherited; g=global; p=persistent)\n\n";
01418 
01419       for (table_const_iterator p = table.begin (); p != table.end (); p++)
01420         p->second.dump (os, "    ");
01421 
01422       os << "\n";
01423     }
01424 }
01425 
01426 void symbol_table::cleanup (void)
01427 {
01428   // Clear variables in top scope.
01429   all_instances[xtop_scope]->clear_variables ();
01430 
01431   // Clear function table. This is a hard clear, ignoring mlocked functions.
01432   fcn_table.clear ();
01433 
01434   // Clear variables in global scope.
01435   // FIXME: are there any?
01436   all_instances[xglobal_scope]->clear_variables ();
01437 
01438   // Clear global variables.
01439   global_table.clear ();
01440 
01441   // Delete all possibly remaining scopes.
01442   for (all_instances_iterator iter = all_instances.begin ();
01443        iter != all_instances.end (); iter++)
01444     {
01445       scope_id scope = iter->first;
01446       if (scope != xglobal_scope && scope != xtop_scope)
01447         scope_id_cache::free (scope);
01448 
01449       // First zero the table entry to avoid possible duplicate delete.
01450       symbol_table *inst = iter->second;
01451       iter->second = 0;
01452 
01453       // Now delete the scope. Note that there may be side effects, such as
01454       // deleting other scopes.
01455       delete inst;
01456     }
01457 }
01458 
01459 DEFUN (ignore_function_time_stamp, args, nargout,
01460     "-*- texinfo -*-\n\
01461 @deftypefn  {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
01462 @deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\
01463 Query or set the internal variable that controls whether Octave checks\n\
01464 the time stamp on files each time it looks up functions defined in\n\
01465 function files.  If the internal variable is set to @code{\"system\"},\n\
01466 Octave will not automatically recompile function files in subdirectories of\n\
01467 @file{@var{octave-home}/lib/@var{version}} if they have changed since\n\
01468 they were last compiled, but will recompile other function files in the\n\
01469 search path if they change.  If set to @code{\"all\"}, Octave will not\n\
01470 recompile any function files unless their definitions are removed with\n\
01471 @code{clear}.  If set to \"none\", Octave will always check time stamps\n\
01472 on files to determine whether functions defined in function files\n\
01473 need to recompiled.\n\
01474 @end deftypefn")
01475 {
01476   octave_value retval;
01477 
01478   int nargin = args.length ();
01479 
01480   if (nargout > 0 || nargin == 0)
01481     {
01482       switch (Vignore_function_time_stamp)
01483         {
01484         case 1:
01485           retval = "system";
01486           break;
01487 
01488         case 2:
01489           retval = "all";
01490           break;
01491 
01492         default:
01493           retval = "none";
01494           break;
01495         }
01496     }
01497 
01498   if (nargin == 1)
01499     {
01500       std::string sval = args(0).string_value ();
01501 
01502       if (! error_state)
01503         {
01504           if (sval == "all")
01505             Vignore_function_time_stamp = 2;
01506           else if (sval == "system")
01507             Vignore_function_time_stamp = 1;
01508           else if (sval == "none")
01509             Vignore_function_time_stamp = 0;
01510           else
01511             error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\"");
01512         }
01513       else
01514         error ("ignore_function_time_stamp: expecting argument to be character string");
01515     }
01516   else if (nargin > 1)
01517     print_usage ();
01518 
01519   return retval;
01520 }
01521 
01522 /*
01523 %!shared old_state
01524 %! old_state = ignore_function_time_stamp ();
01525 %!test
01526 %! state = ignore_function_time_stamp ("all");
01527 %! assert (state, old_state);
01528 %! assert (ignore_function_time_stamp (), "all");
01529 %! state = ignore_function_time_stamp ("system");
01530 %! assert (state, "all");
01531 %! assert (ignore_function_time_stamp (), "system");
01532 %! ignore_function_time_stamp (old_state);
01533 
01534 %% Test input validation
01535 %!error (ignore_function_time_stamp ("all", "all"))
01536 %!error (ignore_function_time_stamp ("UNKNOWN_VALUE"))
01537 %!error (ignore_function_time_stamp (42))
01538 
01539 */
01540 
01541 DEFUN (__current_scope__, , ,
01542   "-*- texinfo -*-\n\
01543 @deftypefn {Built-in Function} {[@var{scope}, @var{context}]} __dump_symtab_info__ ()\n\
01544 Undocumented internal function.\n\
01545 @end deftypefn")
01546 {
01547   octave_value_list retval;
01548 
01549   retval(1) = symbol_table::current_context ();
01550   retval(0) = symbol_table::current_scope ();
01551 
01552   return retval;
01553 }
01554 
01555 DEFUN (__dump_symtab_info__, args, ,
01556   "-*- texinfo -*-\n\
01557 @deftypefn  {Built-in Function} {} __dump_symtab_info__ ()\n\
01558 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (@var{scope})\n\
01559 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"scopes\")\n\
01560 @deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"functions\")\n\
01561 Undocumented internal function.\n\
01562 @end deftypefn")
01563 {
01564   octave_value retval;
01565 
01566   int nargin = args.length ();
01567 
01568   if (nargin == 0)
01569     {
01570       symbol_table::dump_functions (octave_stdout);
01571 
01572       symbol_table::dump_global (octave_stdout);
01573 
01574       std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
01575 
01576       for (std::list<symbol_table::scope_id>::const_iterator p = lst.begin ();
01577            p != lst.end (); p++)
01578         symbol_table::dump (octave_stdout, *p);
01579     }
01580   else if (nargin == 1)
01581     {
01582       octave_value arg = args(0);
01583 
01584       if (arg.is_string ())
01585         {
01586           std::string s_arg = arg.string_value ();
01587 
01588           if (s_arg == "scopes")
01589             {
01590               std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
01591 
01592               RowVector v (lst.size ());
01593 
01594               octave_idx_type k = 0;
01595 
01596               for (std::list<symbol_table::scope_id>::const_iterator p = lst.begin ();
01597                    p != lst.end (); p++)
01598                 v.xelem (k++) = *p;
01599 
01600               retval = v;
01601             }
01602           else if (s_arg == "functions")
01603             {
01604               symbol_table::dump_functions (octave_stdout);
01605             }
01606           else
01607             error ("__dump_symtab_info__: expecting \"functions\" or \"scopes\"");
01608         }
01609       else
01610         {
01611           int s = arg.int_value ();
01612 
01613           if (! error_state)
01614             symbol_table::dump (octave_stdout, s);
01615           else
01616             error ("__dump_symtab_info__: expecting string or scope id");
01617         }
01618     }
01619   else
01620     print_usage ();
01621 
01622   return retval;
01623 }
01624 
01625 #if 0
01626 
01627 // FIXME -- should we have functions like this in Octave?
01628 
01629 DEFUN (set_variable, args, , "set_variable (NAME, VALUE)")
01630 {
01631   octave_value retval;
01632 
01633   if (args.length () == 2)
01634     {
01635       std::string name = args(0).string_value ();
01636 
01637       if (! error_state)
01638         symbol_table::varref (name) = args(1);
01639       else
01640         error ("set_variable: expecting variable name as first argument");
01641     }
01642   else
01643     print_usage ();
01644 
01645   return retval;
01646 }
01647 
01648 DEFUN (variable_value, args, , "VALUE = variable_value (NAME)")
01649 {
01650   octave_value retval;
01651 
01652   if (args.length () == 1)
01653     {
01654       std::string name = args(0).string_value ();
01655 
01656       if (! error_state)
01657         {
01658           retval = symbol_table::varval (name);
01659 
01660           if (retval.is_undefined ())
01661             error ("variable_value: '%s' is not a variable in the current scope",
01662                    name.c_str ());
01663         }
01664       else
01665         error ("variable_value: expecting variable name as first argument");
01666     }
01667   else
01668     print_usage ();
01669 
01670   return retval;
01671 }
01672 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines