Re: Kind of a lookfor function (moved from help list)

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 5/30/05, David Bateman <[hidden email]> wrote:
> See the attached for a proof-of-concept of what I think is the right way
> of doing this. This is much better than treating the issue at compile
> time. There are several issues with this current implementation

Very nice. And very useful.

Would it be a big change to allow searchs without quotation marks?

lookfor inverse

instead of

lookfor "inverse"

I hit an error (memory exhausted). (Sorry that the examples below
don't keep your nice formatting.)

octave:1> lookfor "inverse"
acos                 Compute the inverse cosine of each element of X
acosh                Compute the inverse hyperbolic cosine of each element of X
asin                 Compute the inverse sine of each element of X
asinh                Compute the inverse hyperbolic sine of each element of X
atan                 Compute the inverse tangent of each element of X
atanh                Compute the inverse hyperbolic tangent of each element of X
ipermute             The inverse of the `permute' function
sinh                 Compute the inverse hyperbolic sine of each element of X
octave:2> lookfor "inv"
error: memory exhausted -- trying to return to prompt
PS4                  If Octave is invoked with the `--echo-commands'
option, the value
acos                 Compute the inverse cosine of each element of X
acosh                Compute the inverse hyperbolic cosine of each element of X
argv                 The command line arguments passed to Octave are
available in this
asin                 Compute the inverse sine of each element of X
asinh                Compute the inverse hyperbolic sine of each element of X
atan                 Compute the inverse tangent of each element of X
atanh                Compute the inverse hyperbolic tangent of each element of X
cell                 Create a new cell array object
echo                 Control whether commands are displayed as they are executed
edit_history         If invoked with no arguments, `edit_history'
allows you to edit the
erf                  Computes the error function,
erfc                 Computes the complementary error function, `1 - erf (Z)'
eye                  Return an identity matrix
format               Control the format of the output produced by
`disp' and Octave's
help                 Octave's `help' command can be used to print
brief usage-style
history              If invoked with no arguments, `history' displays
a list of commands
ipermute             The inverse of the `permute' function
keyboard             This function is normally used for simple debugging
load                 Load the named variables from the file FILE
pause                Suspend the execution of the program


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
OK. I now remember what "proof-of-concept" means. Sorry for the bug report.

On 5/31/05, Keith Goodman <[hidden email]> wrote:

> On 5/30/05, David Bateman <[hidden email]> wrote:
> > See the attached for a proof-of-concept of what I think is the right way
> > of doing this. This is much better than treating the issue at compile
> > time. There are several issues with this current implementation
>
> Very nice. And very useful.
>
> Would it be a big change to allow searchs without quotation marks?
>
> lookfor inverse
>
> instead of
>
> lookfor "inverse"
>
> I hit an error (memory exhausted). (Sorry that the examples below
> don't keep your nice formatting.)
>
> octave:1> lookfor "inverse"
> acos                 Compute the inverse cosine of each element of X
> acosh                Compute the inverse hyperbolic cosine of each element of X
> asin                 Compute the inverse sine of each element of X
> asinh                Compute the inverse hyperbolic sine of each element of X
> atan                 Compute the inverse tangent of each element of X
> atanh                Compute the inverse hyperbolic tangent of each element of X
> ipermute             The inverse of the `permute' function
> sinh                 Compute the inverse hyperbolic sine of each element of X
> octave:2> lookfor "inv"
> error: memory exhausted -- trying to return to prompt
> PS4                  If Octave is invoked with the `--echo-commands'
> option, the value
> acos                 Compute the inverse cosine of each element of X
> acosh                Compute the inverse hyperbolic cosine of each element of X
> argv                 The command line arguments passed to Octave are
> available in this
> asin                 Compute the inverse sine of each element of X
> asinh                Compute the inverse hyperbolic sine of each element of X
> atan                 Compute the inverse tangent of each element of X
> atanh                Compute the inverse hyperbolic tangent of each element of X
> cell                 Create a new cell array object
> echo                 Control whether commands are displayed as they are executed
> edit_history         If invoked with no arguments, `edit_history'
> allows you to edit the
> erf                  Computes the error function,
> erfc                 Computes the complementary error function, `1 - erf (Z)'
> eye                  Return an identity matrix
> format               Control the format of the output produced by
> `disp' and Octave's
> help                 Octave's `help' command can be used to print
> brief usage-style
> history              If invoked with no arguments, `history' displays
> a list of commands
> ipermute             The inverse of the `permute' function
> keyboard             This function is normally used for simple debugging
> load                 Load the named variables from the file FILE
> pause                Suspend the execution of the program
>


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
Keith Goodman wrote:

>OK. I now remember what "proof-of-concept" means. Sorry for the bug report.
>  
>

Still a bug, even in a proof-of-concept, though I was aware of one of
them. There are also issues with the upper/lower case of the input
argument. In any case the reason for a proof-of-concept was to allow
discussion, and see if and how this feature might be integrated.. Do you
want it John?

>On 5/31/05, Keith Goodman <[hidden email]> wrote:
>  
>
>>On 5/30/05, David Bateman <[hidden email]> wrote:
>>    
>>
>>>See the attached for a proof-of-concept of what I think is the right way
>>>of doing this. This is much better than treating the issue at compile
>>>time. There are several issues with this current implementation
>>>      
>>>
>>Very nice. And very useful.
>>
>>Would it be a big change to allow searchs without quotation marks?
>>
>>lookfor inverse
>>
>>instead of
>>
>>lookfor "inverse"
>>    
>>
Huh? It does if you use mark_as_command....

>>I hit an error (memory exhausted). (Sorry that the examples below
>>don't keep your nice formatting.)
>>
>>octave:1> lookfor "inverse"
>>acos                 Compute the inverse cosine of each element of X
>>acosh                Compute the inverse hyperbolic cosine of each element of X
>>asin                 Compute the inverse sine of each element of X
>>asinh                Compute the inverse hyperbolic sine of each element of X
>>atan                 Compute the inverse tangent of each element of X
>>atanh                Compute the inverse hyperbolic tangent of each element of X
>>ipermute             The inverse of the `permute' function
>>sinh                 Compute the inverse hyperbolic sine of each element of X
>>    
>>

That is where are the "inverse" and "inv" functions here..

>>octave:2> lookfor "inv"
>>error: memory exhausted -- trying to return to prompt
>>    
>>

Ok, this is one I didn't know about.


Cheers
D.

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 5/30/05, David Bateman <[hidden email]> wrote:
> In any case the reason for a proof-of-concept was to allow
> discussion, and see if and how this feature might be integrated.. Do you
> want it John?

What's the status on adding a lookfor command? Do you want a doc string?


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
Keith Goodman wrote:

>On 5/30/05, David Bateman <[hidden email]> wrote:
>  
>
>>In any case the reason for a proof-of-concept was to allow
>>discussion, and see if and how this feature might be integrated.. Do you
>>want it John?
>>    
>>
>
>What's the status on adding a lookfor command? Do you want a doc string?
>
>  
>
The status is that I don't want to write a function that won't be
incorporated into octave so I'm waiting for John to bless the idea of a
lookfor function, with the understanding that non texinfo help strings
might cause problems in getting the first sentence for the lookfor function.

Yes write the doc string, one less thing that I'll have to do if John
accepts the code...

Cheers
David

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
Sorry. Poorly worded question. I too was asking John. I didn't want to
work on the doc string unless...

On 6/3/05, David Bateman <[hidden email]> wrote:

> Keith Goodman wrote:
>
> >On 5/30/05, David Bateman <[hidden email]> wrote:
> >
> >
> >>In any case the reason for a proof-of-concept was to allow
> >>discussion, and see if and how this feature might be integrated.. Do you
> >>want it John?
> >>
> >>
> >
> >What's the status on adding a lookfor command? Do you want a doc string?
> >
> >
> >
> The status is that I don't want to write a function that won't be
> incorporated into octave so I'm waiting for John to bless the idea of a
> lookfor function, with the understanding that non texinfo help strings
> might cause problems in getting the first sentence for the lookfor function.
>
> Yes write the doc string, one less thing that I'll have to do if John
> accepts the code...
>
> Cheers
> David
>
> --
> David Bateman                                [hidden email]
> Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
> Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
> 91193 Gif-Sur-Yvette FRANCE
>
> The information contained in this communication has been classified as:
>
> [x] General Business Information
> [ ] Motorola Internal Use Only
> [ ] Motorola Confidential Proprietary
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

John W. Eaton-6
In reply to this post by David Bateman-3
On  3-Jun-2005, David Bateman wrote:

| The status is that I don't want to write a function that won't be
| incorporated into octave so I'm waiting for John to bless the idea of a
| lookfor function, with the understanding that non texinfo help strings
| might cause problems in getting the first sentence for the lookfor function.

I don't see how a compatible lookfor function could be a bad thing,
but I'm traveling now and don't have time to comment on the
implementation (I've not even had time to look at it).

jwe

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
In reply to this post by Keith Goodman
> I don't see how a compatible lookfor function could be a bad thing,
> but I'm traveling now and don't have time to comment on the
> implementation (I've not even had time to look at it).


Ok, then what about the attached function. It should go in help.cc so it
can have access to the operators and keywords, however It is still
written as a separate function. It copies the code from
octave-forge/admin/make_index for the idea of how to recognize the first
sentence, but still gets it wrong in some cases, though not for any
functions within octave itself, due to the use of texinfo and all octave
function start with a sentence.

Regards
David

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


/*

Copyright (C) 2005 David Bateman

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 2, 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, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

*/

#include <config.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include "oct.h"
#include "oct-strstrm.h"
#include "defaults.h"
#include "fn-cache.h"
#include "cmd-edit.h"

extern std::string get_help_from_file (const std::string& f);

static std::string
pad (const std::string &s, const size_t len)
{
  std::string ret = s;
  for (size_t i = 0; i < len - s.length(); i++)
    ret.append(" ");

  return ret;
}

static bool
looks_like_texinfo (const std::string& msg, size_t& p1)
{
  p1 = msg.find ('\n');

  std::string t = msg.substr (0, p1);

  if (p1 == NPOS)
    p1 = 0;

  size_t p2 = t.find ("-*- texinfo -*-");

  return (p2 != NPOS);
}

// XXX FIXME XXX This function might be simplified using regex
std::string
first_help_sentence (const std::string &h, const bool short_sentence = true)
{
  size_t pos = 0;

  if (looks_like_texinfo (h, pos))
    {
      // Get the parsed help string.
      pos = 0;
      OSSTREAM os;
      display_help_text (os, h);
      std::string h2 = os.str ();

      while (1)
        {
          // Skip leading whitespace and get new line
          pos = h2.find_first_not_of ("\n\t ", pos);

          if (pos == NPOS)
            break;

          size_t new_pos = h2.find_first_of ('\n', pos);
          std::string line = h2.substr (pos, new_pos-pos);

          // Skip lines starting in "-"
          if (line.find_first_of ('-') == 0)
            {
              pos = new_pos + 1;
              continue;
            }

          break;
        }


      if (pos == NPOS)
        return std::string ();

      // At start of real text. Get first line with the sentence
      size_t new_pos = h2.find_first_of ('\n', pos);
      std::string line = h2.substr (pos, new_pos-pos);
      size_t dot_pos;

      while ((dot_pos = line.find_first_of ('.')) == NPOS)
        {
          // Trim trailing blanks on line
          line.substr (0, line.find_last_not_of ("\n\t ") + 1);

          // Append next line
          size_t tmp_pos = h2.find_first_not_of ("\n\t ", new_pos + 1);
          if (tmp_pos == NPOS || h2.substr (tmp_pos, 1) == "\n")
            break;

          new_pos = h2.find_first_of ('\n', tmp_pos);
          std::string next = h2.substr (tmp_pos, new_pos-tmp_pos);

          if (short_sentence)
            {
              size_t tmp_pos;
              if ((tmp_pos = next.find_first_of ('.')) != NPOS)
                {
                  line = line + " " + next;
                  tmp_pos = line.find_first_of ('.');
                }
              break;
            }
          else
            line = line + " " + next;
        }

      if (dot_pos == NPOS)
        return line;
      else
        return line.substr (0, dot_pos + 1);
    }
  else
    {
      std::string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      std::string lower = "abcdefghijklmnopqrstuvwxyz";
      std::string alpha = upper + lower + "_";
      std::string alphanum = alpha + "1234567890";
      pos = 0;

      while (1)
        {
          // Skip leading whitespace and get new line
          pos = h.find_first_not_of ("\n\t ", pos);

          if (pos == NPOS)
            break;

          size_t new_pos = h.find_first_of ('\n', pos);
          std::string line = h.substr (pos, new_pos-pos);

          // Make a lower case copy to simplify some tests
          std::string lower = line;
          transform (lower.begin (), lower.end (), lower.begin (), tolower);

          // Skip lines starting in "-" or "Usage"
          if (lower.find_first_of ('-') == 0 ||
              lower.substr (0, 5) == "usage")
            {
              pos = new_pos + 1;
              continue;
            }

          size_t line_pos = 0;
          size_t tmp_pos = 0;

          // chop " blah : "
          tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                             (alphanum, line_pos));
          if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == ":")
            line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " function "
          if (lower.substr (line_pos, 8) == "function")
            line_pos =  line.find_first_not_of ("\t ", line_pos + 8);
         
          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " [a,b] = "
          if (line.substr (line_pos, 1) == "[")
            {
              tmp_pos = line.find_first_not_of
                ("\t ", line.find_first_of ("]", line_pos) + 1);

              if (line.substr (tmp_pos, 1) == "=")
                line_pos = line.find_first_not_of ("\t ",tmp_pos + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " a = "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (line.substr (tmp_pos, 1) == "=")
                line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " f(x) "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (line.substr (tmp_pos, 1) == "(")
                line_pos = line.find_first_not_of ("\t ", line.find_first_of
                                                   (")", tmp_pos) + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " ; "
          if (line.substr (line_pos, 1) == ":" ||
              line.substr (line_pos, 1) == ";")
            line_pos = line.find_first_not_of ("\t ", line_pos + 1);

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " BLAH "
          if (line.length ()  > line_pos + 2 &&
              line.find_first_of (upper, line_pos) == line_pos &&
              line.find_first_of (upper, line_pos+1) == line_pos + 1)
            line_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                        (upper + "0123456789_", line_pos));

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah --- "
          tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                             (alphanum, line_pos));
          if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "-")
            {
              tmp_pos = line.find_first_not_of ("-", tmp_pos);
              if (line.substr (tmp_pos, 1) == " " ||
                  line.substr (tmp_pos, 1) == "\t")
                line_pos = line.find_first_not_of ("\t ", tmp_pos);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah <TAB> "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of (" ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (line.substr (tmp_pos, 1) == "\t")
                line_pos = line.find_first_not_of ("\t ", line.find_first_of
                                                   (")", tmp_pos) + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah  "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of (alphanum, line_pos);

              if (line.substr (tmp_pos, 2) == "\t\t" ||
                  line.substr (tmp_pos, 2) == "\t " ||
                  line.substr (tmp_pos, 2) == " \t" ||
                  line.substr (tmp_pos, 2) == " ")
                line_pos = line.find_first_not_of ("\t ", tmp_pos);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // skip blah \n or \n blah
          // skip blank line
          // skip "# !/usr/bin/octave"
          if ((line.substr (line_pos , 2) == "or" &&
               line.find_first_not_of ("\n\t ", line_pos + 2) == NPOS) ||
              line.find_first_not_of ("\n\t ", line_pos) == NPOS ||
              line.substr (line_pos, 2) == "!/")
            {
              pos = new_pos + 1;
              continue;
            }

          // Got the start of first sentence, break.
          pos = pos + line_pos;
          break;
        }

      if (pos == NPOS)
        return std::string ();

      // At start of real text. Get first line with the sentence
      size_t new_pos = h.find_first_of ('\n', pos);
      std::string line = h.substr (pos, new_pos-pos);
      size_t dot_pos;

      while ((dot_pos = line.find_first_of ('.')) == NPOS)
        {
          // Trim trailing blanks on line
          line = line.substr (0, line.find_last_not_of ("\n\t ") + 1);

          // Append next line
          size_t tmp_pos = h.find_first_not_of ("\t ", new_pos + 1);
          if (tmp_pos == NPOS || h.substr (tmp_pos, 1) == "\n")
            break;

          new_pos = h.find_first_of ('\n', tmp_pos);
          std::string next = h.substr (tmp_pos, new_pos-tmp_pos);

          if (short_sentence)
            {
              // Only add the next line if it terminates the sentence, then break
              if ((tmp_pos = next.find_first_of ('.')) != NPOS)
                {
                  line = line + " " + next;
                  tmp_pos = line.find_first_of ('.');
                }
              break;
            }
          else
            line = line + " " + next;
        }

      if (dot_pos == NPOS)
        return line;
      else
        return line.substr (0, dot_pos + 1);
    }
}

// XXX FIXME DEFUN_DLD should be replaced with DEFCMD when included in help.cc
DEFUN_DLD (lookfor, args, nargout,
  "-*- texinfo -*-\n\
@deffn {Command} lookfor @var{str}\n\
@deffnx {Command} lookfor -all @var{str}\n\
@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor (@var{str})\n\
@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor ('-all', @var{str})\n\
Search for the string @var{str} in all of the functions found in\n\
@var{LOADPATH}. By default @code{lookfor} searchs for @var{str} in the\n\
first sentence of the help string of each function found. The entire\n\
help string of each function found of @var{LOADPATH} can be search if\n\
the '-all' argument is supplied. All searches are case insensitive.\n\
\n\
Called with no output arguments, @code{lookfor} prints the list of matching\n\
functions to the terminal. Otherwise the output arguments @var{fun} and\n\
@var{helpstring} define the matching functions and the first sentence of\n\
each of their help strings.\n\
\n\
Note that the ability of @code{lookfor} to correctly identify the first\n\
sentence of the help of the functions is dependent on the format of the\n\
functions help. All of the functions in octave itself will correctly\n\
find the first sentence, but the same can not be guaranteed for other\n\
functions. Therefore the use of the '-all' argument might be necessary\n\
to find related functions that are not part of octave.\n\
@end deffn\n\
@seealso{which, help}")
{
  octave_value_list retval;
  int nargin = args.length ();
  bool first_sentence_only = true;

  if (nargin != 1 && nargin != 2)
    {
      usage ("lookfor");
      return retval;
    }

  string_vector ret[2];

  std::string txt;

  if (args(0).is_string ())
    {
      txt = args(0).string_value ();

      if (nargin == 2)
        {
          if (args(1).is_string ())
            {
              std::string tmp = args(1).string_value ();

              if (txt.substr(0,1) == "-")
                {
                  txt = tmp;
                  tmp = args(0).string_value ();
                }

              if (tmp == "-all")
                first_sentence_only = false;
              else
                error ("lookfor: unrecognized option argument");
            }
          else
            error ("lookfor: arguments must be a string");
        }
    }
  else
    error ("lookfor: argument must be a string");

  if (!error_state)
    {
      // All tests in lower case
      transform (txt.begin (), txt.end (), txt.begin (), tolower);

      // XXX FIXME XXX Add test for keywords and operators here
     

      // Check the symbol record table
      string_vector names
        = fbi_sym_tab->name_list (string_vector (), true);

      for (octave_idx_type i = 0; i < names.length (); i++)
        {
          std::string name = names (i);

          symbol_record *sr = lookup_by_name (name, 0);
          if (sr && sr->is_defined ())
            {
              std::string h = sr->help ();
              std::string s;
              if (first_sentence_only)
                s = first_help_sentence (h);
              else
                s = h;
             
              transform (s.begin (), s.end (), s.begin (), tolower);

              if (s.length () > 0 && s.find (txt) != NPOS)
                {
                  ret[0].append (name);
                  ret[1].append (first_help_sentence (h));
                }
            }
        }

      string_vector dirs = Vload_path_dir_path.all_directories ();

      int len = dirs.length ();

      for (int i = 0; i < len; i++)
        {
          names = octave_fcn_file_name_cache::list (dirs[i]);

          if (! names.empty ())
            {
              for (int j = 0; j < names.length (); j++)
                {
                  std::string name = names (j);

                  // Strip extension
                  size_t len = name.length ();
                  if (name.substr (len-4) == ".oct")
                    name = name.substr (0, len - 4);
                  else if (name.substr (len-2) == ".m")
                    name = name.substr (0, len - 2);
                  else
                    continue;

                  // Check if already in symbol table
                  symbol_record *sr = fbi_sym_tab->lookup (name);

                  if (!sr)
                    {
                      // Check if this version is first in the path
                      string_vector tmp (2);
                      tmp(0) = name + ".oct";
                      tmp(1) = name + ".m";
                      std::string file_name =
                        Vload_path_dir_path.find_first_of (tmp);

                      if (file_name == dirs[i] + tmp(0) ||
                          file_name == dirs[i] + tmp(1))
                        {
                          std::string h = get_help_from_file (file_name);

                          std::string s;
                          if (first_sentence_only)
                            s = first_help_sentence (h);
                          else
                            s = h;

                          transform (s.begin (), s.end (), s.begin (), tolower);

                          if (s.length () > 0 && s.find (txt) != NPOS)
                            {
                              ret[0].append (name);
                              ret[1].append (first_help_sentence (h));
                            }
                        }
                    }
                }
            }
        }


      if (nargout != 0)
        {
          retval (1) = ret[1];
          retval (0) = ret[0];
        }
      else
        {
#define DEFLEN 20

          octave_idx_type max_width = command_editor::terminal_cols () - DEFLEN;
          if (max_width < 20)
            max_width = 20;


          for (octave_idx_type i = 0; i < ret[0].length (); i++)
            {
              octave_stdout << pad (ret[0](i), DEFLEN);
              std::string line = ret[1](i);
              size_t pos = 0;

              while (1)
                {
                  size_t new_pos = line.find_first_of ("\n\t ", pos);
                  size_t end_pos = new_pos;

                  if ((line.length () - pos) < max_width)
                    new_pos = end_pos = NPOS;
                  else
                    while (new_pos != NPOS && (new_pos - pos) < max_width)
                      {
                        end_pos = new_pos;
                        new_pos = line.find_first_of ("\n\t ", new_pos + 1);
                      }

                  octave_stdout << line.substr (pos, end_pos-pos) << std::endl;
                 
                  if (new_pos == NPOS)
                    break;

                  pos = end_pos +1;
                  octave_stdout << pad ("", DEFLEN);
                }
            }
        }
    }
  else
    {
      error ("lookfor: argument must be a string");
    }

  return retval;
}

// XXX FIXME XXX helpstring is only here to allow me to test the code on a
// single help string, and in particular the code to obtain the first sentence.
// Delete when included in octave.
DEFUN_DLD (helpstring, args, , "help text")
{
  octave_value retval;
  int nargin = args.length ();

  if (nargin != 1)
    {
      usage ("helpstring");
      return retval;
    }

  // Open the string stream
  octave_ostrstream *o_ostr = new octave_ostrstream ();
  std::ostream *os = o_ostr->output_stream ();

  if (os)
    {
      if (args(0).is_string ())
        {
          std::string nm = args(0).string_value ();
          bool got_help = false;

          // Check the symbol record table first
          symbol_record *sym_rec = lookup_by_name (nm, 0);
          if (sym_rec && sym_rec->is_defined ())
            {
              std::string h = sym_rec->help ();
             
              if (h.length () > 0)
                {
                  display_help_text (*os, h);
                  got_help = true;
                }
            }
         
          // Get help from file if we haven't already gotten the help
          if (! got_help)
            {
              std::string path = fcn_file_in_path (nm);
             
              std::string h = get_help_from_file (path);

              if (! h.empty ())
                {
                  display_help_text (*os, h);
                  got_help = true;
                }
            }
         
          if (! got_help)
            error ("helpstring: sorry %s is not documented", nm.c_str());
          else
            retval = first_help_sentence (o_ostr->str ());
        }
      else
        {
          error ("helpstring: argument must be a string");
        }
    }
  else
    {
      error ("helpstring: could not open output stream");
    }

  return retval;
}

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 6/4/05, David Bateman <[hidden email]> wrote:
> Ok, then what about the attached function. It should go in help.cc so it
> can have access to the operators and keywords, however It is still
> written as a separate function. It copies the code from
> octave-forge/admin/make_index for the idea of how to recognize the first
> sentence, but still gets it wrong in some cases, though not for any
> functions within octave itself, due to the use of texinfo and all octave
> function start with a sentence.

It panics and aborts Octave. What am I doing wrong?

$ mkoctfile lookfor.cc
$ octave
Octave 2.9.3 Forge 20041116
>> lookfor inverse
panic: Aborted -- stopping myself...
Aborted
$ octave
Octave 2.9.3 Forge 20041116
>> lookfor "inverse"
panic: Aborted -- stopping myself...
Aborted
$ octave
Octave 2.9.3 Forge 20041116
>> which lookfor
lookfor is the dynamically-linked function from the file
/home/me/test/octave/lookfor/lookfor.oct
>> lookfor("inverse")
panic: Aborted -- stopping myself...
Aborted

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
In reply to this post by Keith Goodman
>It panics and aborts Octave. What am I doing wrong?


I had lots of those, but thought I'd fixed them all.. Its almost
certainly that I'm trying to take a substr in a range that is larger
than the string itself in the function first_help_sentence... There are
two ways of calling lookfor, with or without the -all argument. With the
-all argument lookfor search in the entire help string of all functions
and only calls first_help_sentence on the matching functions, without
the -all argument first_help_sentence is called on all help strings...

I made some changes, and only called with the "-all" flag and so got
caught out.. Try the new version attached...

Regards
D.


--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


/*

Copyright (C) 2005 David Bateman

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 2, 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, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

*/

#include <config.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include "oct.h"
#include "oct-strstrm.h"
#include "defaults.h"
#include "fn-cache.h"
#include "cmd-edit.h"

extern std::string get_help_from_file (const std::string& f);

static std::string
pad (const std::string &s, const size_t len)
{
  std::string ret = s;
  for (size_t i = 0; i < len - s.length(); i++)
    ret.append(" ");

  return ret;
}

static bool
looks_like_texinfo (const std::string& msg, size_t& p1)
{
  p1 = msg.find ('\n');

  std::string t = msg.substr (0, p1);

  if (p1 == NPOS)
    p1 = 0;

  size_t p2 = t.find ("-*- texinfo -*-");

  return (p2 != NPOS);
}

// XXX FIXME XXX This function might be simplified using regex
std::string
first_help_sentence (const std::string &h, const bool short_sentence = true)
{
  size_t pos = 0;

  if (looks_like_texinfo (h, pos))
    {
      // Get the parsed help string.
      pos = 0;
      OSSTREAM os;
      display_help_text (os, h);
      std::string h2 = os.str ();

      while (1)
        {
          // Skip leading whitespace and get new line
          pos = h2.find_first_not_of ("\n\t ", pos);

          if (pos == NPOS)
            break;

          size_t new_pos = h2.find_first_of ('\n', pos);
          std::string line = h2.substr (pos, new_pos-pos);

          // Skip lines starting in "-"
          if (line.find_first_of ('-') == 0)
            {
              pos = new_pos + 1;
              continue;
            }

          break;
        }


      if (pos == NPOS)
        return std::string ();

      // At start of real text. Get first line with the sentence
      size_t new_pos = h2.find_first_of ('\n', pos);
      std::string line = h2.substr (pos, new_pos-pos);
      size_t dot_pos;

      while ((dot_pos = line.find_first_of ('.')) == NPOS)
        {
          // Trim trailing blanks on line
          line.substr (0, line.find_last_not_of ("\n\t ") + 1);

          // Append next line
          size_t tmp_pos = h2.find_first_not_of ("\n\t ", new_pos + 1);
          if (tmp_pos == NPOS || h2.substr (tmp_pos, 1) == "\n")
            break;

          new_pos = h2.find_first_of ('\n', tmp_pos);
          std::string next = h2.substr (tmp_pos, new_pos-tmp_pos);

          if (short_sentence)
            {
              size_t tmp_pos;
              if ((tmp_pos = next.find_first_of ('.')) != NPOS)
                {
                  line = line + " " + next;
                  tmp_pos = line.find_first_of ('.');
                }
              break;
            }
          else
            line = line + " " + next;
        }

      if (dot_pos == NPOS)
        return line;
      else
        return line.substr (0, dot_pos + 1);
    }
  else
    {
      std::string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      std::string lower = "abcdefghijklmnopqrstuvwxyz";
      std::string alpha = upper + lower + "_";
      std::string alphanum = alpha + "1234567890";
      pos = 0;

      while (1)
        {
          // Skip leading whitespace and get new line
          pos = h.find_first_not_of ("\n\t ", pos);

          if (pos == NPOS)
            break;

          size_t new_pos = h.find_first_of ('\n', pos);
          std::string line = h.substr (pos, new_pos-pos);

          // Make a lower case copy to simplify some tests
          std::string lower = line;
          transform (lower.begin (), lower.end (), lower.begin (), tolower);

          // Skip lines starting in "-" or "Usage"
          if (lower.find_first_of ('-') == 0 ||
              lower.substr (0, 5) == "usage")
            {
              pos = new_pos + 1;
              continue;
            }

          size_t line_pos = 0;
          size_t tmp_pos = 0;

          // chop " blah : "
          tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                             (alphanum, line_pos));
          if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == ":")
            line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " function "
          if (lower.substr (line_pos, 8) == "function")
            line_pos =  line.find_first_not_of ("\t ", line_pos + 8);
         
          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " [a,b] = "
          if (line.substr (line_pos, 1) == "[")
            {
              tmp_pos = line.find_first_not_of
                ("\t ", line.find_first_of ("]", line_pos) + 1);

              if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "=")
                line_pos = line.find_first_not_of ("\t ",tmp_pos + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " a = "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "=")
                line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " f(x) "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "(")
                line_pos = line.find_first_not_of ("\t ", line.find_first_of
                                                   (")", tmp_pos) + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " ; "
          if (line.substr (line_pos, 1) == ":" ||
              line.substr (line_pos, 1) == ";")
            line_pos = line.find_first_not_of ("\t ", line_pos + 1);

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " BLAH "
          if (line.length ()  > line_pos + 2 &&
              line.find_first_of (upper, line_pos) == line_pos &&
              line.find_first_of (upper, line_pos+1) == line_pos + 1)
            line_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                        (upper + "0123456789_", line_pos));

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah --- "
          tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
                                             (alphanum, line_pos));
          if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "-")
            {
              tmp_pos = line.find_first_not_of ("-", tmp_pos);
              if (line.substr (tmp_pos, 1) == " " ||
                  line.substr (tmp_pos, 1) == "\t")
                line_pos = line.find_first_not_of ("\t ", tmp_pos);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah <TAB> "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of (" ", line.find_first_not_of
                                                (alphanum, line_pos));
              if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "\t")
                line_pos = line.find_first_not_of ("\t ", line.find_first_of
                                                   (")", tmp_pos) + 1);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // chop " blah  "
          if (line.find_first_not_of (alpha, line_pos) != line_pos)
            {
              tmp_pos = line.find_first_not_of (alphanum, line_pos);

              if (tmp_pos != NPOS && (line.substr (tmp_pos, 2) == "\t\t" ||
                  line.substr (tmp_pos, 2) == "\t " ||
                  line.substr (tmp_pos, 2) == " \t" ||
                  line.substr (tmp_pos, 2) == " "))
                line_pos = line.find_first_not_of ("\t ", tmp_pos);
            }

          if (line_pos == NPOS)
            {
              pos = new_pos + 1;
              continue;
            }

          // skip blah \n or \n blah
          // skip blank line
          // skip "# !/usr/bin/octave"
          if ((line.substr (line_pos , 2) == "or" &&
               line.find_first_not_of ("\n\t ", line_pos + 2) == NPOS) ||
              line.find_first_not_of ("\n\t ", line_pos) == NPOS ||
              line.substr (line_pos, 2) == "!/")
            {
              pos = new_pos + 1;
              continue;
            }

          // Got the start of first sentence, break.
          pos = pos + line_pos;
          break;
        }

      if (pos == NPOS)
        return std::string ();

      // At start of real text. Get first line with the sentence
      size_t new_pos = h.find_first_of ('\n', pos);
      std::string line = h.substr (pos, new_pos-pos);
      size_t dot_pos;

      while ((dot_pos = line.find_first_of ('.')) == NPOS)
        {
          // Trim trailing blanks on line
          line = line.substr (0, line.find_last_not_of ("\n\t ") + 1);

          // Append next line
          size_t tmp_pos = h.find_first_not_of ("\t ", new_pos + 1);
          if (tmp_pos == NPOS || h.substr (tmp_pos, 1) == "\n")
            break;

          new_pos = h.find_first_of ('\n', tmp_pos);
          std::string next = h.substr (tmp_pos, new_pos-tmp_pos);

          if (short_sentence)
            {
              // Only add the next line if it terminates the sentence, then break
              if ((tmp_pos = next.find_first_of ('.')) != NPOS)
                {
                  line = line + " " + next;
                  tmp_pos = line.find_first_of ('.');
                }
              break;
            }
          else
            line = line + " " + next;
        }

      if (dot_pos == NPOS)
        return line;
      else
        return line.substr (0, dot_pos + 1);
    }
}

// XXX FIXME DEFUN_DLD should be replaced with DEFCMD when included in help.cc
DEFUN_DLD (lookfor, args, nargout,
  "-*- texinfo -*-\n\
@deffn {Command} lookfor @var{str}\n\
@deffnx {Command} lookfor -all @var{str}\n\
@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor (@var{str})\n\
@deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor ('-all', @var{str})\n\
Search for the string @var{str} in all of the functions found in\n\
@var{LOADPATH}. By default @code{lookfor} searchs for @var{str} in the\n\
first sentence of the help string of each function found. The entire\n\
help string of each function found of @var{LOADPATH} can be search if\n\
the '-all' argument is supplied. All searches are case insensitive.\n\
\n\
Called with no output arguments, @code{lookfor} prints the list of matching\n\
functions to the terminal. Otherwise the output arguments @var{fun} and\n\
@var{helpstring} define the matching functions and the first sentence of\n\
each of their help strings.\n\
\n\
Note that the ability of @code{lookfor} to correctly identify the first\n\
sentence of the help of the functions is dependent on the format of the\n\
functions help. All of the functions in octave itself will correctly\n\
find the first sentence, but the same can not be guaranteed for other\n\
functions. Therefore the use of the '-all' argument might be necessary\n\
to find related functions that are not part of octave.\n\
@end deffn\n\
@seealso{which, help}")
{
  octave_value_list retval;
  int nargin = args.length ();
  bool first_sentence_only = true;

  if (nargin != 1 && nargin != 2)
    {
      usage ("lookfor");
      return retval;
    }

  string_vector ret[2];

  std::string txt;

  if (args(0).is_string ())
    {
      txt = args(0).string_value ();

      if (nargin == 2)
        {
          if (args(1).is_string ())
            {
              std::string tmp = args(1).string_value ();

              if (txt.substr(0,1) == "-")
                {
                  txt = tmp;
                  tmp = args(0).string_value ();
                }

              if (tmp == "-all")
                first_sentence_only = false;
              else
                error ("lookfor: unrecognized option argument");
            }
          else
            error ("lookfor: arguments must be a string");
        }
    }
  else
    error ("lookfor: argument must be a string");

  if (!error_state)
    {
      // All tests in lower case
      transform (txt.begin (), txt.end (), txt.begin (), tolower);

      // XXX FIXME XXX Add test for keywords and operators here
     

      // Check the symbol record table
      string_vector names
        = fbi_sym_tab->name_list (string_vector (), true);

      for (octave_idx_type i = 0; i < names.length (); i++)
        {
          std::string name = names (i);

          symbol_record *sr = lookup_by_name (name, 0);
          if (sr && sr->is_defined ())
            {
              std::string h = sr->help ();
              std::string s;
              if (first_sentence_only)
                s = first_help_sentence (h);
              else
                s = h;
             
              transform (s.begin (), s.end (), s.begin (), tolower);

              if (s.length () > 0 && s.find (txt) != NPOS)
                {
                  ret[0].append (name);
                  ret[1].append (first_help_sentence (h));
                }
            }
        }

      string_vector dirs = Vload_path_dir_path.all_directories ();

      int len = dirs.length ();

      for (int i = 0; i < len; i++)
        {
          names = octave_fcn_file_name_cache::list (dirs[i]);

          if (! names.empty ())
            {
              for (int j = 0; j < names.length (); j++)
                {
                  std::string name = names (j);

                  // Strip extension
                  size_t len = name.length ();
                  if (name.substr (len-4) == ".oct")
                    name = name.substr (0, len - 4);
                  else if (name.substr (len-2) == ".m")
                    name = name.substr (0, len - 2);
                  else
                    continue;

                  // Check if already in symbol table
                  symbol_record *sr = fbi_sym_tab->lookup (name);

                  if (!sr)
                    {
                      // Check if this version is first in the path
                      string_vector tmp (2);
                      tmp(0) = name + ".oct";
                      tmp(1) = name + ".m";
                      std::string file_name =
                        Vload_path_dir_path.find_first_of (tmp);

                      if (file_name == dirs[i] + tmp(0) ||
                          file_name == dirs[i] + tmp(1))
                        {
                          std::string h = get_help_from_file (file_name);

                          std::string s;
                          if (first_sentence_only)
                            s = first_help_sentence (h);
                          else
                            s = h;

                          transform (s.begin (), s.end (), s.begin (), tolower);

                          if (s.length () > 0 && s.find (txt) != NPOS)
                            {
                              ret[0].append (name);
                              ret[1].append (first_help_sentence (h));
                            }
                        }
                    }
                }
            }
        }


      if (nargout != 0)
        {
          retval (1) = ret[1];
          retval (0) = ret[0];
        }
      else
        {
#define DEFLEN 20

          octave_idx_type max_width = command_editor::terminal_cols () - DEFLEN;
          if (max_width < 20)
            max_width = 20;


          for (octave_idx_type i = 0; i < ret[0].length (); i++)
            {
              octave_stdout << pad (ret[0](i), DEFLEN);
              std::string line = ret[1](i);
              size_t pos = 0;

              while (1)
                {
                  size_t new_pos = line.find_first_of ("\n\t ", pos);
                  size_t end_pos = new_pos;

                  if ((line.length () - pos) < max_width)
                    new_pos = end_pos = NPOS;
                  else
                    while (new_pos != NPOS && (new_pos - pos) < max_width)
                      {
                        end_pos = new_pos;
                        new_pos = line.find_first_of ("\n\t ", new_pos + 1);
                      }

                  octave_stdout << line.substr (pos, end_pos-pos) << std::endl;
                 
                  if (new_pos == NPOS)
                    break;

                  pos = end_pos +1;
                  octave_stdout << pad ("", DEFLEN);
                }
            }
        }
    }
  else
    {
      error ("lookfor: argument must be a string");
    }

  return retval;
}

// XXX FIXME XXX helpstring is only here to allow me to test the code on a
// single help string, and in particular the code to obtain the first sentence.
// Delete when included in octave.
DEFUN_DLD (helpstring, args, , "help text")
{
  octave_value retval;
  int nargin = args.length ();

  if (nargin != 1)
    {
      usage ("helpstring");
      return retval;
    }

  // Open the string stream
  octave_ostrstream *o_ostr = new octave_ostrstream ();
  std::ostream *os = o_ostr->output_stream ();

  if (os)
    {
      if (args(0).is_string ())
        {
          std::string nm = args(0).string_value ();
          bool got_help = false;

          // Check the symbol record table first
          symbol_record *sym_rec = lookup_by_name (nm, 0);
          if (sym_rec && sym_rec->is_defined ())
            {
              std::string h = sym_rec->help ();
             
              if (h.length () > 0)
                {
                  display_help_text (*os, h);
                  got_help = true;
                }
            }
         
          // Get help from file if we haven't already gotten the help
          if (! got_help)
            {
              std::string path = fcn_file_in_path (nm);
             
              std::string h = get_help_from_file (path);

              if (! h.empty ())
                {
                  display_help_text (*os, h);
                  got_help = true;
                }
            }
         
          if (! got_help)
            error ("helpstring: sorry %s is not documented", nm.c_str());
          else
            retval = first_help_sentence (o_ostr->str ());
        }
      else
        {
          error ("helpstring: argument must be a string");
        }
    }
  else
    {
      error ("helpstring: could not open output stream");
    }

  return retval;
}

/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/
Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 6/5/05, David Bateman <[hidden email]> wrote:
> I made some changes, and only called with the "-all" flag and so got
> caught out.. Try the new version attached...

It breaks if you try to abort a search with Control-C, which someone
might want to do if the search is long:

>> lookfor inverse
[I pressed Control-C]
warning: help: Texinfo formatting filter exited abnormally
warning: help: raw Texinfo source of help text follows...
Press Control-C again to abort.
warning: help: Texinfo formatting filter exited abnormally
warning: help: raw Texinfo source of help text follows...
panic: Interrupt -- stopping myself...

$

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
In reply to this post by Keith Goodman
> It breaks if you try to abort a search with Control-C, which someone
> might want to do if the search is long:


You're a good bug hunter. Yeah I forgot that little detail, you just
need to add OCTAVE_QUIT in the loops to allow the C++ exception handling
to deal with the ctrl-c... Try the attached version, this time gzipped
as I seem to be sending this file rather a lot recently...

D.

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


lookfor.cc.gz (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 6/5/05, David Bateman <[hidden email]> wrote:
> Try the attached version, this time gzipped
> as I seem to be sending this file rather a lot recently...

It works most of the time. But I did manage to get an out of memory error.

$ octave
Octave 2.9.3 Forge 20041116
>> lookfor inverse
[I hit Control-C. It works. But is there any way to prevent it from
spitting out the warnings below?]
warning: help: Texinfo formatting filter exited abnormally
warning: help: raw Texinfo source of help text follows...
warning: broken pipe -- some output may be lost

>> lookfor matlab
casesen             Provided for compatibility with Matlab, but does nothing.
error: memory exhausted -- trying to return to prompt
>>

I noticed that the -all flag can come before or after the search
string. Matlab documents it by putting the -all flag after the search
string, so

Command: lookfor STR -all

instead of

Command: lookfor -all STR

But that doesn't make sense (to me), unless you're into that whole
compatibility thing.

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
Keith Goodman wrote:

>On 6/5/05, David Bateman <[hidden email]> wrote:
>  
>
>>Try the attached version, this time gzipped
>>as I seem to be sending this file rather a lot recently...
>>    
>>
>
>It works most of the time. But I did manage to get an out of memory error.
>
>$ octave
>Octave 2.9.3 Forge 20041116
>  
>
>>>lookfor inverse
>>>      
>>>
>[I hit Control-C. It works. But is there any way to prevent it from
>spitting out the warnings below?]
>warning: help: Texinfo formatting filter exited abnormally
>warning: help: raw Texinfo source of help text follows...
>warning: broken pipe -- some output may be lost
>  
>

I don't know why that happens. At the moment I store all of the data and
print it at the end, to allow return args. I suppose I can partially fix
the problem wen then is not return args by printing the matchs as they
happen and not storing them. To think about..

>  
>
>>>lookfor matlab
>>>      
>>>
>casesen             Provided for compatibility with Matlab, but does nothing.
>error: memory exhausted -- trying to return to prompt
>  
>
>
>I noticed that the -all flag can come before or after the search
>string. Matlab documents it by putting the -all flag after the search
>string, so
>
>Command: lookfor STR -all
>
>instead of
>
>Command: lookfor -all STR
>
>But that doesn't make sense (to me), unless you're into that whole
>compatibility thing.
>
>  
>
This is why I changed the order in the documentation but allowed the
matlab compatiable ordering... So we get compatiability and something a
bit more sensible...

Regards
David

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

Keith Goodman
On 6/6/05, David Bateman <[hidden email]> wrote:
> I don't know why that happens. At the moment I store all of the data and
> print it at the end, to allow return args. I suppose I can partially fix
> the problem wen then is not return args by printing the matchs as they
> happen and not storing them. To think about..

I'm not going to ask for more features---I've already gotten ten times
more than I asked for. But I think it is a good trade to get the
matches printed as you find them in exchange for the ability to
capture the output as string matrices. A lookfor search can be long,
so in 98.7 out of 100 cases (by my ab initio calculations) the user
would prefer to see the results as they are found over capturing the
output.

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
Keith Goodman wrote:

>On 6/6/05, David Bateman <[hidden email]> wrote:
>  
>
>>I don't know why that happens. At the moment I store all of the data and
>>print it at the end, to allow return args. I suppose I can partially fix
>>the problem wen then is not return args by printing the matchs as they
>>happen and not storing them. To think about..
>>    
>>
>
>I'm not going to ask for more features---I've already gotten ten times
>more than I asked for. But I think it is a good trade to get the
>matches printed as you find them in exchange for the ability to
>capture the output as string matrices. A lookfor search can be long,
>so in 98.7 out of 100 cases (by my ab initio calculations) the user
>would prefer to see the results as they are found over capturing the
>output.
>
>  
>
Won't get that anyway if they don't have page_screen_output set to
zero... In any case I implemented this, but won't both sending it to the
list, but send it off-line to you and John... At this point its pretty
much ready for integration into octave...

D.

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

David Bateman-3
In reply to this post by Keith Goodman
Ok, I worked my last version of this code up as a patch against the CVS,
attached. John do you want this, with the understanding that finding the
first sentence in an arbitrary help string is not guarenteed, though the
code I have works 100% on the core octave functions and almost 100% on
the octave-forge stuff. The same algorithm is used in make_index to
build the category index on octave-forge.

Cheers
David

2005-06-20  David Bateman  <[hidden email]>

    * help.cc (std::string first_help_sentence): New function to find
    first sentence in help string.
    (std::string pad (const std:string &, const size_t): New
    function to pad string to a certain length.
    (void print_lookfor (const std::string &, const std::strig &):
    Nnew function to print help string in a formatted manner.
    (Flookfor): Lookfor function.


--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary


Index: src/help.cc
===================================================================
RCS file: /usr/local/cvsroot/octave/src/help.cc,v
retrieving revision 1.137
diff -c -r1.137 help.cc
*** src/help.cc 17 Jun 2005 21:16:22 -0000 1.137
--- src/help.cc 20 Jun 2005 19:55:34 -0000
***************
*** 66,71 ****
--- 66,72 ----
  #include "utils.h"
  #include "variables.h"
  #include "version.h"
+ #include "quit.h"
 
  // Name of the info file specified on command line.
  // (--info-file file)
***************
*** 1196,1201 ****
--- 1197,1827 ----
    return 0;
  }
 
+ // XXX FIXME XXX
+ // This function attempts to find the first sentence of a help string, though
+ // given that the user can create the help in an arbitrary format, your
+ // success might vary.. it works much better with help string formated in
+ // texinfo. Using regex might make this function much simpler.
+
+ std::string
+ first_help_sentence (const std::string &h, const bool short_sentence = true)
+ {
+   size_t pos = 0;
+
+   if (looks_like_texinfo (h, pos))
+     {
+       // Get the parsed help string.
+       pos = 0;
+       OSSTREAM os;
+       display_help_text (os, h);
+       std::string h2 = os.str ();
+
+       while (1)
+ {
+  // Skip leading whitespace and get new line
+  pos = h2.find_first_not_of ("\n\t ", pos);
+
+  if (pos == NPOS)
+    break;
+
+  size_t new_pos = h2.find_first_of ('\n', pos);
+  std::string line = h2.substr (pos, new_pos-pos);
+
+  // Skip lines starting in "-"
+  if (line.find_first_of ('-') == 0)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  break;
+ }
+
+
+       if (pos == NPOS)
+ return std::string ();
+
+       // At start of real text. Get first line with the sentence
+       size_t new_pos = h2.find_first_of ('\n', pos);
+       std::string line = h2.substr (pos, new_pos-pos);
+       size_t dot_pos;
+
+       while ((dot_pos = line.find_first_of ('.')) == NPOS)
+ {
+  // Trim trailing blanks on line
+  line.substr (0, line.find_last_not_of ("\n\t ") + 1);
+
+  // Append next line
+  size_t tmp_pos = h2.find_first_not_of ("\n\t ", new_pos + 1);
+  if (tmp_pos == NPOS || h2.substr (tmp_pos, 1) == "\n")
+    break;
+
+  new_pos = h2.find_first_of ('\n', tmp_pos);
+  std::string next = h2.substr (tmp_pos, new_pos-tmp_pos);
+
+  if (short_sentence)
+    {
+      if ((tmp_pos = next.find_first_of ('.')) != NPOS)
+ {
+  line = line + " " + next;
+  dot_pos = line.find_first_of ('.');
+ }
+      break;
+    }
+  else
+    line = line + " " + next;
+ }
+
+       if (dot_pos == NPOS)
+ return line;
+       else
+ return line.substr (0, dot_pos + 1);
+     }
+   else
+     {
+       std::string _upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       std::string _lower = "abcdefghijklmnopqrstuvwxyz";
+       std::string _alpha = _upper + _lower + "_";
+       std::string _alphanum = _alpha + "1234567890";
+       pos = 0;
+
+       while (1)
+ {
+  // Skip leading whitespace and get new line
+  pos = h.find_first_not_of ("\n\t ", pos);
+
+  if (pos == NPOS)
+    break;
+
+  size_t new_pos = h.find_first_of ('\n', pos);
+  std::string line = h.substr (pos, new_pos-pos);
+
+  // Make a lower case copy to simplify some tests
+  std::string lower = line;
+  transform (lower.begin (), lower.end (), lower.begin (), tolower);
+
+  // Skip lines starting in "-" or "Usage"
+  if (lower.find_first_of ('-') == 0 ||
+      lower.substr (0, 5) == "usage")
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  size_t line_pos = 0;
+  size_t tmp_pos = 0;
+
+  // chop " blah : "
+  tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
+     (_alphanum, line_pos));
+  if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == ":")
+    line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " function "
+  if (lower.substr (line_pos, 8) == "function")
+    line_pos =  line.find_first_not_of ("\t ", line_pos + 8);
+  
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " [a,b] = "
+  if (line.substr (line_pos, 1) == "[")
+    {
+      tmp_pos = line.find_first_not_of
+ ("\t ", line.find_first_of ("]", line_pos) + 1);
+
+      if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "=")
+ line_pos = line.find_first_not_of ("\t ",tmp_pos + 1);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " a = "
+  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
+    {
+      tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
+ (_alphanum, line_pos));
+      if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "=")
+ line_pos = line.find_first_not_of ("\t ", tmp_pos + 1);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " f(x) "
+  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
+    {
+      tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
+ (_alphanum, line_pos));
+      if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "(")
+ line_pos = line.find_first_not_of ("\t ", line.find_first_of
+   (")", tmp_pos) + 1);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " ; "
+  if (line.substr (line_pos, 1) == ":" ||
+      line.substr (line_pos, 1) == ";")
+    line_pos = line.find_first_not_of ("\t ", line_pos + 1);
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " BLAH "
+  if (line.length ()  > line_pos + 2 &&
+      line.find_first_of (_upper, line_pos) == line_pos &&
+      line.find_first_of (_upper, line_pos+1) == line_pos + 1)
+    line_pos = line.find_first_not_of ("\t ", line.find_first_not_of
+ (_upper + "0123456789_", line_pos));
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " blah --- "
+  tmp_pos = line.find_first_not_of ("\t ", line.find_first_not_of
+     (_alphanum, line_pos));
+  if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "-")
+    {
+      tmp_pos = line.find_first_not_of ("-", tmp_pos);
+      if (line.substr (tmp_pos, 1) == " " ||
+  line.substr (tmp_pos, 1) == "\t")
+ line_pos = line.find_first_not_of ("\t ", tmp_pos);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " blah <TAB> "
+  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
+    {
+      tmp_pos = line.find_first_not_of (" ", line.find_first_not_of
+ (_alphanum, line_pos));
+      if (tmp_pos != NPOS && line.substr (tmp_pos, 1) == "\t")
+ line_pos = line.find_first_not_of ("\t ", line.find_first_of
+   (")", tmp_pos) + 1);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // chop " blah  "
+  if (line.find_first_not_of (_alpha, line_pos) != line_pos)
+    {
+      tmp_pos = line.find_first_not_of (_alphanum, line_pos);
+
+      if (tmp_pos != NPOS && (line.substr (tmp_pos, 2) == "\t\t" ||
+  line.substr (tmp_pos, 2) == "\t " ||
+  line.substr (tmp_pos, 2) == " \t" ||
+  line.substr (tmp_pos, 2) == " "))
+ line_pos = line.find_first_not_of ("\t ", tmp_pos);
+    }
+
+  if (line_pos == NPOS)
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // skip blah \n or \n blah
+  // skip blank line
+  // skip "# !/usr/bin/octave"
+  if ((line.substr (line_pos , 2) == "or" &&
+       line.find_first_not_of ("\n\t ", line_pos + 2) == NPOS) ||
+      line.find_first_not_of ("\n\t ", line_pos) == NPOS ||
+      line.substr (line_pos, 2) == "!/")
+    {
+      pos = new_pos + 1;
+      continue;
+    }
+
+  // Got the start of first sentence, break.
+  pos = pos + line_pos;
+  break;
+ }
+
+       if (pos == NPOS)
+ return std::string ();
+
+       // At start of real text. Get first line with the sentence
+       size_t new_pos = h.find_first_of ('\n', pos);
+       std::string line = h.substr (pos, new_pos-pos);
+       size_t dot_pos;
+
+       while ((dot_pos = line.find_first_of ('.')) == NPOS)
+ {
+  // Trim trailing blanks on line
+  line = line.substr (0, line.find_last_not_of ("\n\t ") + 1);
+
+  // Append next line
+  size_t tmp_pos = h.find_first_not_of ("\t ", new_pos + 1);
+  if (tmp_pos == NPOS || h.substr (tmp_pos, 1) == "\n")
+    break;
+
+  new_pos = h.find_first_of ('\n', tmp_pos);
+  std::string next = h.substr (tmp_pos, new_pos-tmp_pos);
+
+  if (short_sentence)
+    {
+      // Only add the next line if it terminates the sentence, then break
+      if ((tmp_pos = next.find_first_of ('.')) != NPOS)
+ {
+  line = line + " " + next;
+  dot_pos = line.find_first_of ('.');
+ }
+      break;
+    }
+  else
+    line = line + " " + next;
+ }
+
+       if (dot_pos == NPOS)
+ return line;
+       else
+ return line.substr (0, dot_pos + 1);
+     }
+ }
+
+ static std::string
+ pad (const std::string &s, const size_t len)
+ {
+   std::string ret = s + " ";
+   if (s.length() < len)
+     for (size_t i = 0; i < len - s.length(); i++)
+       ret.append(" ");
+  
+   return ret;
+ }
+
+ static void
+ print_lookfor (const std::string &name, const std::string &line)
+ {
+ #define DEFLEN 20
+
+   octave_idx_type max_width = command_editor::terminal_cols () - DEFLEN;
+   if (max_width < 20)
+     max_width = 20;
+
+   octave_idx_type width = max_width;
+   if (name.length () > DEFLEN)
+     {
+       width = command_editor::terminal_cols () - name.length();
+       if (width < 20)
+ width = 20;
+     }
+
+   octave_stdout << pad (name, DEFLEN);
+   size_t pos = 0;
+
+   while (1)
+     {
+       size_t new_pos = line.find_first_of ("\n\t ", pos);
+       size_t end_pos = new_pos;
+
+       if (static_cast<octave_idx_type>(line.length () - pos) < width)
+ new_pos = end_pos = NPOS;
+       else
+ while (new_pos != NPOS &&
+       static_cast<octave_idx_type>(new_pos - pos) < width)
+  {
+    end_pos = new_pos;
+    new_pos = line.find_first_of ("\n\t ", new_pos + 1);
+  }
+
+       octave_stdout << line.substr (pos, end_pos-pos) << std::endl;
+  
+       if (end_pos == NPOS)
+ break;
+
+       pos = end_pos + 1;
+       width = max_width;
+       octave_stdout << pad ("", DEFLEN);
+     }
+ }
+
+ DEFCMD (lookfor, args, nargout,
+   "-*- texinfo -*-\n\
+ @deffn {Command} lookfor @var{str}\n\
+ @deffnx {Command} lookfor -all @var{str}\n\
+ @deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor (@var{str})\n\
+ @deffnx {Function} {[@var{fun}, @var{helpstring}] = } lookfor ('-all', @var{str})\n\
+ Search for the string @var{str} in all of the functions found in\n\
+ @var{LOADPATH}. By default @code{lookfor} searchs for @var{str} in the\n\
+ first sentence of the help string of each function found. The entire\n\
+ help string of each function found of @var{LOADPATH} can be search if\n\
+ the '-all' argument is supplied. All searches are case insensitive.\n\
+ \n\
+ Called with no output arguments, @code{lookfor} prints the list of matching\n\
+ functions to the terminal. Otherwise the output arguments @var{fun} and\n\
+ @var{helpstring} define the matching functions and the first sentence of\n\
+ each of their help strings.\n\
+ \n\
+ Note that the ability of @code{lookfor} to correctly identify the first\n\
+ sentence of the help of the functions is dependent on the format of the\n\
+ functions help. All of the functions in octave itself will correctly\n\
+ find the first sentence, but the same can not be guaranteed for other\n\
+ functions. Therefore the use of the '-all' argument might be necessary\n\
+ to find related functions that are not part of octave.\n\
+ @end deffn\n\
+ @seealso{which, help}")
+ {
+   octave_value_list retval;
+   int nargin = args.length ();
+   bool first_sentence_only = true;
+
+   if (nargin != 1 && nargin != 2)
+     {
+       usage ("lookfor");
+       return retval;
+     }
+
+   string_vector ret[2];
+
+   std::string txt;
+
+   if (args(0).is_string ())
+     {
+       txt = args(0).string_value ();
+
+       if (nargin == 2)
+ {
+  if (args(1).is_string ())
+    {
+      std::string tmp = args(1).string_value ();
+
+      if (txt.substr(0,1) == "-")
+ {
+  txt = tmp;
+  tmp = args(0).string_value ();
+ }
+
+      if (tmp == "-all")
+ first_sentence_only = false;
+      else
+ error ("lookfor: unrecognized option argument");
+    }
+  else
+    error ("lookfor: arguments must be a string");
+ }
+     }
+   else
+     error ("lookfor: argument must be a string");
+
+   if (!error_state)
+     {
+       // All tests in lower case
+       transform (txt.begin (), txt.end (), txt.begin (), tolower);
+
+       help_list *ptr = keyword_help ();
+       while (ptr->name)
+ {
+  std::string name = ptr->name;
+  std::string h = ptr->help;
+
+  std::string s;
+  if (first_sentence_only)
+    s = first_help_sentence (h);
+  else
+    s = h;
+      
+  transform (s.begin (), s.end (), s.begin (), tolower);
+
+  if (s.length () > 0 && s.find (txt) != NPOS)
+    {
+      if (nargout)
+ {
+  ret[0].append (name);
+  ret[1].append (first_help_sentence (h));
+ }
+      else
+ print_lookfor (name, first_help_sentence (h));
+    }
+
+  OCTAVE_QUIT;
+
+  ptr++;
+ }
+
+       ptr = operator_help ();
+       while (ptr->name)
+ {
+  std::string name = ptr->name;
+  std::string h = ptr->help;
+
+  std::string s;
+  if (first_sentence_only)
+    s = first_help_sentence (h);
+  else
+    s = h;
+      
+  transform (s.begin (), s.end (), s.begin (), tolower);
+
+  if (s.length () > 0 && s.find (txt) != NPOS)
+    {
+      if (nargout)
+ {
+  ret[0].append (name);
+  ret[1].append (first_help_sentence (h));
+ }
+      else
+ print_lookfor (name, first_help_sentence (h));
+    }
+
+  OCTAVE_QUIT;
+
+  ptr++;
+ }
+
+       // Check the symbol record table
+       string_vector names
+ = fbi_sym_tab->name_list (string_vector (), true);
+
+       for (octave_idx_type i = 0; i < names.length (); i++)
+ {
+  std::string name = names (i);
+
+  OCTAVE_QUIT;
+
+  symbol_record *sr = lookup_by_name (name, 0);
+  if (sr && sr->is_defined ())
+    {
+      std::string h = sr->help ();
+      std::string s;
+      if (first_sentence_only)
+ s = first_help_sentence (h);
+      else
+ s = h;
+      
+      transform (s.begin (), s.end (), s.begin (), tolower);
+
+      if (s.length () > 0 && s.find (txt) != NPOS)
+ {
+  if (nargout)
+    {
+      ret[0].append (name);
+      ret[1].append (first_help_sentence (h));
+    }
+  else
+    print_lookfor (name, first_help_sentence (h));
+ }
+    }
+ }
+
+       string_vector dirs = Vload_path_dir_path.all_directories ();
+
+       int len = dirs.length ();
+
+       for (int i = 0; i < len; i++)
+ {
+  names = octave_fcn_file_name_cache::list (dirs[i]);
+
+  if (! names.empty ())
+    {
+      for (int j = 0; j < names.length (); j++)
+ {
+  std::string name = names (j);
+
+  OCTAVE_QUIT;
+
+  // Strip extension
+  size_t l = name.length ();
+  if (name.substr (l-4) == ".oct")
+    name = name.substr (0, l - 4);
+  else if (name.substr (l-2) == ".m")
+    name = name.substr (0, l - 2);
+  else
+    continue;
+
+
+  // Check if already in symbol table
+  symbol_record *sr = fbi_sym_tab->lookup (name);
+
+  if (!sr)
+    {
+      // Check if this version is first in the path
+      string_vector tmp (2);
+      tmp(0) = name + ".oct";
+      tmp(1) = name + ".m";
+      std::string file_name =
+ Vload_path_dir_path.find_first_of (tmp);
+
+
+      if (file_name == dirs[i] + tmp(0) ||
+  file_name == dirs[i] + tmp(1))
+ {
+  std::string h = get_help_from_file (file_name);
+
+  std::string s;
+  if (first_sentence_only)
+    s = first_help_sentence (h);
+  else
+    s = h;
+
+  transform (s.begin (), s.end (), s.begin (), tolower);
+
+  if (s.length () > 0 && s.find (txt) != NPOS)
+    {
+      if (nargout)
+ {
+  ret[0].append (name);
+  ret[1].append (first_help_sentence (h));
+ }
+      else
+ print_lookfor (name, first_help_sentence (h));
+    }
+ }
+    }
+ }
+    }
+ }
+
+
+       if (nargout != 0)
+ {
+  retval (1) = ret[1];
+  retval (0) = ret[0];
+ }
+     }
+   else
+     {
+       error ("lookfor: argument must be a string");
+     }
+
+   return retval;
+ }
+
  void
  symbols_of_help (void)
  {
Reply | Threaded
Open this post in threaded view
|

Re: {Spam?} Re: Kind of a lookfor function (moved from help list)

Przemek Klosowski

Could we please find another string flagging code requiring
further attention? the current convention:

         // XXX FIXME XXX

invariably triggers spam filters on emails with patches. How about

           ZZZ further work required but we're tired now ZZZ

:)

Reply | Threaded
Open this post in threaded view
|

Re: {Spam?} Re: Kind of a lookfor function (moved from help list)

David Bateman-3
Przemek Klosowski wrote:

>Could we please find another string flagging code requiring
>further attention? the current convention:
>
> // XXX FIXME XXX
>
>invariably triggers spam filters on emails with patches. How about
>
>  
>
Hey, another "hot and dirty" patch :-) ....

>   ZZZ further work required but we're tired now ZZZ
>
>  
>
Seriously, I have no problems with the spam filtering issue and mail
from octave.org, I think your spam filters are perhaps a bit niave and
you might be loosing other mails as well... If you don't want to change
your filters, why not just white-list things with a CC or To of
*@octave.org or *@bevo.che.wisc.edu, I haven't seen any spam on these
lists, so I don't think that would cause you a problem...

Cheers
David

--
David Bateman                                [hidden email]
Motorola Labs - Paris                        +33 1 69 35 48 04 (Ph)
Parc Les Algorithmes, Commune de St Aubin    +33 1 69 35 77 01 (Fax)
91193 Gif-Sur-Yvette FRANCE

The information contained in this communication has been classified as:

[x] General Business Information
[ ] Motorola Internal Use Only
[ ] Motorola Confidential Proprietary

Reply | Threaded
Open this post in threaded view
|

Re: Kind of a lookfor function (moved from help list)

John W. Eaton-6
In reply to this post by David Bateman-3
On 20-Jun-2005, David Bateman wrote:

| Ok, I worked my last version of this code up as a patch against the CVS,
| attached. John do you want this, with the understanding that finding the
| first sentence in an arbitrary help string is not guarenteed, though the
| code I have works 100% on the core octave functions and almost 100% on
| the octave-forge stuff. The same algorithm is used in make_index to
| build the category index on octave-forge.
|
| Cheers
| David
|
| 2005-06-20  David Bateman  <[hidden email]>
|
|     * help.cc (std::string first_help_sentence): New function to find
|     first sentence in help string.
|     (std::string pad (const std:string &, const size_t): New
|     function to pad string to a certain length.
|     (void print_lookfor (const std::string &, const std::strig &):
|     Nnew function to print help string in a formatted manner.
|     (Flookfor): Lookfor function.

Just to let people on the list know, I merged a version of this
patch.

It seems a little slow, probably because it has to open every .m file
in the LOADPATH, then parse the help.  This will happen each time the
function is evaluated as there is no caching.  Maybe we should
consider (at some future time) installing the DOCSTRINGS file(s) and
searching there instead?

jwe