/*****************************************************************************\
 *                                                                           *
 * FINDFUNC.C                                                                *
 *   This macro will traverse the current buffer (assumed to contain a C     *
 * source file or even an ME macro file) and will look for all function      *
 * definitions. It will then display a menu with all of the function names   *
 * in it. You can move through the menu using the UP and DOWN arrow keys,    *
 * and when you get to a function that you want to go to, you press the      *
 * ENTER key. The menu will vanish and the cursor will move to that function *
 * definition.                                                               *
 *                                                                           *
 * This macro is invoked by pressing the ALT F key.                          *
 *                                                                           *
 * This macro was suggested by John Herbold of CompuCom Inc.                 *
 *                                                                           *
 * Written by Marc Adler of Magma Systems on 2/4/89                          *
 *                                                                           *
\*****************************************************************************/

#include mekeys.h

#define CFUNC_PATTERN   "^[a-zA-Z_]?*(?*)$"

#define HORIZ     1
#define VERT      2
#define TOP_LEFT  3
#define TOP_RIGHT 4
#define BOT_LEFT  5
#define BOT_RIGHT 6

string BoxChars[10];


init()
{
  assign_key("FindFunction", ALT_F);
}

FindFunction()
{
  nfuncs = 0;
  linenum = 0;

  /* Save the current position and go to the first line of the file */
  save_position();
  gobof();

  /* Create a temp buffer which will hold the function definitions */
  orig_buf = currbuf();
  temp_buf = create_buffer("FUNCTION LIST");

  /* Go thru the source code, looking for a function definition */
  while (fsearch(CFUNC_PATTERN))
  {
    /* record the line number where we found this function */
    cln = currlinenum();

    /* get rid of everything except the function name */
    funcdef = rtrim(substr(currline(), 1, index(currline(), "(") - 1));
    while ((i = index(funcdef, " ")) > 0)
      funcdef = substr(funcdef, i+1, 100);
    while ((i = index(funcdef, "*")) > 0)
      funcdef = substr(funcdef, i+1, 100);

    /* 
       Insert the function name into the temp buffer,
       followed by the line number in column 50
    */
    setcurrbuf(temp_buf);
    insert(funcdef);
    setcol(50);
    insert(sprintf("%d", cln));
    append_line();
    nfuncs++;
    setcurrbuf(orig_buf);
    if (!down())  break;
  }

  /* Move back to the original position in the buffer */
  restore_position();

  if (!nfuncs)
    get_tty_str("No functions were found");
  else
  {
    /* 
       Display the list of functions in a nice menu. The return value 
       is "" if the user pressed ESC, or the menu line if the user    
       pressed ENTER.
    */
    if ((line = show_file(temp_buf)) != "")
      linenum = atoi(substr(line, 50, 8));
  }

  /* Get rid of the temp buffer and move to the line which the user chose */
  delete_buffer(temp_buf);
  show_buffer(orig_buf);
  if (linenum > 0)
    goline(linenum);
}


show_file(buf_id)
{
  int  filecolor;

  /* Get rid of the trailing newline in the function list */
  setcurrbuf(buf_id);
  goeof();
  delline();
  gobof();

  filecolor = 0x07;

  /* Create the menu and attach the function listing to it */
  win_id = create_window(8, 20, 15, 60, filecolor);
  attach_window(win_id, buf_id);
  DrawBox(6, 19, 15, 61, filecolor);
  display(15, 25, 52, filecolor, " Press UP, DN, ENTER or ESC ");

  /* Let the user interact with the menu */
  return MenuProcess();
}


/* ------------------------- MENU PROCESSING ------------------------- */

MenuProcess()
{
  markline();

  while ((c = get_tty_char()) != '\r' && c != ESC)
  {
    switch (c)
    {
      case _UP  :
        MenuUp();
        break;
      case _DOWN :
        MenuDown();
        break;
      default   :
        bell();
        break;
    }
  }
  
  if (c == '\r')
    return currline();
  else
    return "";
}


MenuUp()
{
  if (currlinenum() > 1)
  {
    clear_mark();
    up();
    markline();
  }
}

MenuDown()
{
  if (currlinenum() < lastlinenum())
  {
    clear_mark();
    down();
    markline();
  }
}


DrawBox(row1, col1, row2, col2, color)
{
  BoxChars[HORIZ]     = "Í";
  BoxChars[VERT]      = "º";
  BoxChars[TOP_LEFT]  = "É";
  BoxChars[TOP_RIGHT] = "»";
  BoxChars[BOT_LEFT]  = "È";
  BoxChars[BOT_RIGHT] = "¼";
  
  start_row = row1;
  start_col = col1;
  end_row   = row2;
  end_col   = col2;

  width = col2 - col1 + 1;
  horiz_line = repstr(BoxChars[HORIZ], width - 2);
  blank_line = repstr(" ", width - 2);

  display(row1, col1 + 1, col1 + width - 1,  color, horiz_line);
  display(row2, col1 + 1, col1 + width - 1,  color, horiz_line);
  for (r = row1+1;  r < row2;  r++)
  {
    display(r, col1, col1, color, BoxChars[VERT]);
    display(r, col2, col2, color, BoxChars[VERT]);
  }
  display(row1, col1, col1,  color, BoxChars[TOP_LEFT]);
  display(row1, col2, col2,  color, BoxChars[TOP_RIGHT]);
  display(row2, col1, col1,  color, BoxChars[BOT_LEFT]);
  display(row2, col2, col2,  color, BoxChars[BOT_RIGHT]);
}

