Channels ▼



Source Code Accompanies This Article. Download It Now.


Marvin Hymowech works as a programmer for Symplex Communications Corp. Previously he taught mathematics at the University of Michigan in Ann Arbor He can be reached at 4906 Cole Blvd., Ypsilanti, MI 48197.

For those readers who appreciated the convenience of my function finder ("Find That Function!" DDJ August 1988), this article presents a useful refinement: A Brief macro that prompts the user for the name of a C function to be located, then presents the source file containing the function definition in the current editing window. With this macro, successive function calls can be traced without exiting Brief and without ever having to remember which source file contains which function.

getf Becomes a Macro

Recall my previous function finder, and you'll remember that it consists of the two programs, bldfuncs and getf The first program, bldfuncs, reads C source files, extracts the names of functions defined therein, and constructs an index file (named funcs./xt) of source files and functions, in the form:



The second program, getf then searches funcs.txt for a specified function name, extracts the relevant C source file name, and replaces itself in memory with a text editor using this source file as the file to be edited.

Although getf works well, it can only be invoked from the DOS level. A valuable addition to this mechanism would be a way to use something like getf after you are already in Brief, without having to exit to DOS first. There is an obvious way for the user to continue finding functions from inside Brief, via the following steps:

    1. Open a new window containing funcs.txt

    2. Search for a function name

    3. Search backwards for a : (colon)

    4. Read the name of the relevant source file, now on the current line

    5. Edit this source file in a new window

    6. Search for the function name in this source file until you find it

The Brief macro language contains all of the capabilities required to automate this process. (I use Brief, Version 2.01.) Listing One, page 72, contains the Brief macro getf (it is the macro analog of the program getf) as well as a slightly improved version of the macro funcsrch (which was presented in my original article). To maximize ease of use, getf should be bound to the Ctrl-F key by placing the following lines

(autoload "" "getf" "funcsrch") (assign_to_key "<Ctrl-f>" "getf")

in the keyboard.h file. (This file is included in the macro startup, which runs automatically when Brief is first invoked.) Of course, you must first use Brief to compile both getf m and startup.m, which produces .cm files (see the Brief documentation for the details).

How getf Works from Within Brief

Let's look at the macro getf in detail. First, let's get a function name from the user using the Brief function getparm:

     (get_parm NULL fn_name "Enter function name:" NULL fn_name))

Here, the first NULL parameter instructs getparm to prompt the user (get-parm is also used to get parameters passed by other macros) by displaying "Enter function name:" on the bottom message line of Brief. The string the user types is then placed in the variable fn_name, which is declared as a global string variable so that it will retain its value between calls to getf this allows us to present its last value as the default, and display it after the prompt string.

Next, check that the file funcs.txt exists in the current directory; if not, the message "file funcs.txt not found" is printed on the message line and the macro returns. Assuming funcs.txt is found, create a buffer for it using create_buffer, then make it the current buffer using set_buffer. Note that the user will not see any change on the screen as yet, because this buffer has not been attached to a window.

Now funcs.txt can be searched for the function name. Care must be exercised, however, because simply finding a string matching the function name is not enough: This might be a part of a larger function name or might occur as the name of a source file. After finding an occurrence of the string, the line is read into the string variable line and is examined as follows: the line must have a tab (\t) as its first character in order to be a line containing a function name (source file names are not indented in the standard format of funcs.txt), and the line must consist exactly of a tab, the string contained in fn_name, and a newline (\n). Note that a semicolon is allowed before the newline --this would occur if the function were the last entry for a source file. If the line matches these specifications, a search backwards from this point for the first : (colon) is performed to get the name of the source file; otherwise we'll advance to the next line and search for the next occurrence of the function name. If at any point the function name is not found, "function not found" is displayed on the message line and the macro returns.

Having obtained the line containing the source file name, this name is extracted and placed in the string variable file_name. After first verifying that this file exists in the current directory, it is read into a buffer and attached to a window using the single Brief function editfile. Control is now transferred to the macro funcsrch (explained in my previous article) in an attempt to position the cursor on the exact line of the function definition.

After getf is executed, the file funcs.txt remains in a buffer during the editing session, which speeds up subsequent calls to getf since funcs.txt need not be reloaded each time.

Using Wildcards?

The program getf (in my previous article) has a capability that this Brief macro version of getf lacks: the program version was able to search for function names based on a mask containing wildcard characters, and then present the user with a menu of matching names. It should be possible to add this feature to the macro getf by using Briefs Dialog Manager to construct a system buffer of available choices and to present this menu to the user. I would be interested in hearing from any reader who pursues this.



<a name="022f_0008">

;**   getf - Copyright 1988 by Marvin Hymowech.
;**        - Prompts for a function name, extracts the name of the file
;**        - in which it is defined from "funcs.txt" (see bldfuncs.c)
;**        - and presents the file in the current window.
;**        - Returns: 0 if error, else 1.

#define NON_SYSTEM 0

( macro getf
      ( int start_buf_id func_buf_id )
      ( string fn_name line file_name )

         ;** make fn_name a global so that it will retain its prior
         ;** value for the default display in the get_parm below
      ( global fn_name )

         ;** get desired function name from user
      ( if
         ( ( !
            ( get_parm NULL fn_name "Enter function name: " NULL fn_name ) )
         (return 0)

         ;** verify that funcs.txt exists on disk in the current directory
      ( if ( ! ( exist "funcs.txt" ) )
            ( beep )
            ( error "file funcs.txt not found" )
            ( return 0 )

         ;** save current buf id, so we can restore it if an error occurs
      ( = start_buf_id ( inq_buffer ) )

         ;** create a buffer for funcs.txt without attaching it to a window
      ( if
         ( ! ( = func_buf_id
               ( create_buffer "functions" "funcs.txt" NON_SYSTEM )
            ( beep )
            ( error "Can't load funcs.txt file." )
            ( return 0 )

         ;** make it the current buffer
      ( set_buffer func_buf_id )

         ;** Brief back-end buffer functions won't set tabs for us
         ;** like edit_file, so we do it explicitly
      ( tabs 9 17 )

      ( top_of_buffer )

         ;** search for the function name
      ( while 1
               ;** break if function name not found
            ( if ( <= ( search_fwd fn_name ) 0 )
                  ( beep )
                  ( error "function %s not found" fn_name )
                     ;** restore the original buffer
                  ( set_buffer start_buf_id )
                  ( return 0 )
               ;** get the current line into variable "line"
            ( beginning_of_line )
            ( sprintf line "%s" ( read ) )

               ;** if fn line, not file line
            ( if ( == ( index line "\t" ) 1 )
                     ;** read the line into "line" starting after the tab
                  ( next_char )
                  ( sprintf line "%s" ( read ) )

                     ;** make sure we have the exact function name, not
                     ;** part of a larger function name

                     ;** if the line consists of \t,fn_name, and \n,
                     ;**    then break
                  ( if ( == ( index line "\n" ) ( + 1 ( strlen fn_name) ) )
                     ( break )

                     ;** if the line consists of \t,fn_name, ;, and \n
                     ;**    then break
                  ( if ( == ( index line ";" ) ( + 1 ( strlen fn_name ) ) )
                     ( break )
            ( end_of_line )               ;** else try next line

      ( if ( <= ( search_back ":" ) 0 )   ;** done, get the file name
            ( beep )
            ( error "funcs.txt corrupted" )
            ( set_buffer start_buf_id )
            ( return 0 )

      ( beginning_of_line )
      ( sprintf line "%s" ( read ) )
      ( sprintf file_name "%s"            ;** get rid of trailing ":"
         ( substr line 1 ( - (index line ":" ) 1 ) ) )

          ;** verify that the file exists on disk
      ( if ( ! ( exist file_name ) )
            ( beep )
            ( error "file %s not found" file_name )
            ( set_buffer start_buf_id )
            ( return 0 )

         ;** and edit it
      ( edit_file file_name )
         ;** try to place cursor on the function defn
      ( return ( funcsrch fn_name ) )

;** funcsrch - Copyright 1988 by Marvin Hymowech.
;**          - Searches the current buffer for a string (function name)
;**          - by starting from the end of the buffer.
;**          - This is designed to position the cursor on
;**          - a function definition since most functions tend to be
;**          - used before they are defined.
;**          - Returns: 0 if function not found, 1 if found.
(macro funcsrch
      ( string s )
      ( extern _s_pat _dir center_line )

      ( get_parm 0 s )
      ( message "locating function %s..." s )
      ( end_of_buffer )
      ( if ( > (search_back s) 0 )
            ( message "function %s found" s )
            ( center_line )
            ( sprintf _s_pat "%s" s )
            ( = _dir 0 )
            ( return 1 )
            ( top_of_buffer )
            ( beep )
            ( error "function %s not found" s )
            ( return 0 )

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.