Logo Search packages:      
Sourcecode: vile version File versions

isearch.c

/*
 * The functions in this file implement commands that perform incremental
 * searches in the forward and backward directions.  This "ISearch" command
 * is intended to emulate the same command from the original EMACS
 * implementation (ITS).  Contains references to routines internal to
 * SEARCH.C.
 *
 * original author: D. R. Banks 9-May-86
 *
 * $Header: /usr/build/vile/vile/RCS/isearch.c,v 1.58 2003/05/25 23:34:52 tom Exp $
 *
 */

#include    "estruct.h"
#include        "edef.h"

#if   OPT_ISRCH

#define IS_REVERSE      tocntrl('R')      /* Search backward */
#define IS_FORWARD      tocntrl('F')      /* Search forward */

/* A couple "own" variables for the command string */

static ITBUFF *cmd_buff;      /* Save the command args here */
static int cmd_reexecute = -1;      /* > 0 if re-executing command */

/*
 * This hack will search for the next occurrence of <searchpat> in the buffer,
 * either forward or backward.  It is called with the status of the prior
 * search attempt, so that it knows not to bother if it didn't work last
 * time.  If we can't find any more matches, "point" is left where it was
 * before.  If we do find a match, "point" will be at the end of the matched
 * string for forward searches and at the beginning of the matched string for
 * reverse searches.
 */
static int
scanmore(               /* search forward or back for a pattern */
          TBUFF * patrn,      /* string to scan for */
          int dir)            /* direction to search */
{
    int sts;                  /* current search status */

    FreeIfNeeded(gregexp);
    gregexp = regcomp(tb_values(patrn), tb_length(patrn), b_val(curbp, MDMAGIC));
    if (!gregexp)
      return FALSE;

    ignorecase = window_b_val(curwp, MDIGNCASE);

    sts = scanner(gregexp, (dir < 0) ? REVERSE : FORWARD, FALSE, (int *) 0);

    if (!sts)
      kbd_alarm();            /* beep the terminal if we fail */
    return (sts);       /* else, don't even try */
}

/* Routine to prompt for I-Search string. */

static void
promptpattern(const char *prompt)
{
    /* check to see if we are executing a command line */
    if (!clexec) {
      TBUFF *temp = tb_visbuf(tb_values(searchpat), tb_length(searchpat));

      mlforce("%s[%s]: ", prompt, temp ? tb_values(temp) : "");
      tb_free(&temp);
    }
}

/* routine to echo i-search characters */

static void
echochar(int c)               /* character to be echoed */
{
    kbd_putc(c);
    kbd_flush();
}

static void
unget_char(void)
{
    cmd_buff->itb_used -= 2;  /* remove Rubout and last char */
}

/*
 * Routine to get the next character from the input stream.  If we're reading
 * from the real terminal, force a screen update before we get the char.
 * Otherwise, we must be re-executing the command string, so just return the
 * next character.
 */
static int
get_char(void)
{
    int c;              /* A place to get a character */

    /* See if we're re-executing: */

    if (cmd_reexecute >= 0
      && (cmd_reexecute + 1) < (int) itb_length(cmd_buff)) {
      c = itb_values(cmd_buff)[cmd_reexecute++];
    } else {
      /* We're not re-executing (or aren't any more).  Try for a real char */

      cmd_reexecute = -1;     /* Say we're in real mode again */
      (void) update(FALSE);   /* Pretty up the screen */
      c = keystroke8(); /* Get the next character */
      itb_append(&cmd_buff, c);
    }
    return (c);               /* Return the character */
}

/*
 * Subroutine to do an incremental search.  In general, this works similarly
 * to the older micro-emacs search function, except that the search happens
 * as each character is typed, with the screen and cursor updated with each
 * new search character.
 *
 * While searching forward, each successive character will leave the cursor at
 * the end of the entire matched string.  Typing a Control-S or Control-X
 * will cause the next occurrence of the string to be searched for (where the
 * next occurrence does NOT overlap the current occurrence).  A Control-R
 * will change to a backwards search, META will terminate the search and
 * Control-G will abort the search.  Rubout will back up to the previous
 * match of the string, or if the starting point is reached first, it will
 * delete the last character from the search string.
 *
 * While searching backward, each successive character will leave the cursor at
 * the beginning of the matched string.  Typing a Control-R will search
 * backward for the next occurrence of the string.  Control-S or Control-X
 * will revert the search to the forward direction.  In general, the reverse
 * incremental search is just like the forward incremental search inverted.
 *
 * In all cases, if the search fails, the user will be feeped, and the search
 * will stall until the pattern string is edited back into something that
 * exists (or until the search is aborted).
 */

/* ARGSUSED */
static int
isearch(int f GCC_UNUSED, int n)
{
    static TBUFF *pat_save = 0;     /* Saved copy of the old pattern str */

    int status;               /* Search status */
    register int cpos;        /* character number in search string */
    register int c;           /* current input character */
    MARK curpos, curp;        /* Current point on entry */
    int init_direction;       /* The initial search direction */

    /* Initialize starting conditions */

    cmd_reexecute = -1;       /* We're not re-executing (yet?) */
    itb_init(&cmd_buff, EOS); /* Init the command buffer */
    /* Save the old pattern string */
    (void) tb_copy(&pat_save, searchpat);
    curpos = DOT;       /* Save the current pointer */
    init_direction = n;       /* Save the initial search direction */

    ignorecase = window_b_val(curwp, MDIGNCASE);

    scanboundry(FALSE, DOT, FORWARD);     /* keep scanner() finite */

    /* This is a good place to start a re-execution: */

  start_over:

    /* ask the user for the text of a pattern */
    promptpattern("ISearch: ");

    status = TRUE;            /* Assume everything's cool */

    /*
     * Get the first character in the pattern.  If we get an initial
     * Control-S or Control-R, re-use the old search string and find the
     * first occurrence
     */

    c = kcod2key(get_char()); /* Get the first character */
    if ((c == IS_FORWARD) ||
      (c == IS_REVERSE)) {    /* Reuse old search string? */
      for (cpos = 0; cpos < (int) tb_length(searchpat); ++cpos)
          echochar(tb_values(searchpat)[cpos]); /* and re-echo the string */
      curp = DOT;
      if (c == IS_REVERSE) {  /* forward search? */
          n = -1;       /* No, search in reverse */
          last_srch_direc = REVERSE;
          backchar(TRUE, 1);  /* Be defensive about EOB */
      } else {
          n = 1;        /* Yes, search forward */
          last_srch_direc = FORWARD;
          forwchar(TRUE, 1);
      }
      unget_char();
      status = scanmore(searchpat, n);    /* Do the search */
      if (status != TRUE)
          DOT = curp;
      c = kcod2key(get_char());     /* Get another character */
    }
    /* Top of the per character loop */

    for_ever {                /* ISearch per character loop */
      /* Check for special characters, since they might change the
       * search to be done
       */

      if (ABORTED(c) || c == '\r')  /* search aborted? */
          return (TRUE);      /* end the search */

      if (isbackspace(c))
          c = '\b';

      if (c == quotec)  /* quote character? */
          c = kcod2key(get_char()); /* Get the next char */

      switch (c) {            /* dispatch on the input char */
      case IS_REVERSE:  /* If backward search */
      case IS_FORWARD:  /* If forward search */
          curp = DOT;
          if (c == IS_REVERSE) {    /* forward search? */
            last_srch_direc = REVERSE;
            n = -1;           /* No, search in reverse */
            backchar(TRUE, 1);      /* Be defensive about
                               * EOB */
          } else {
            n = 1;            /* Yes, search forward */
            last_srch_direc = FORWARD;
            forwchar(TRUE, 1);
          }
          status = scanmore(searchpat, n);      /* Do the search */
          if (status != TRUE)
            DOT = curp;
          c = kcod2key(get_char()); /* Get the next char */
          unget_char();
          continue;           /* Go continue with the search */

      case '\t':        /* Generically allowed */
      case '\n':        /* controlled characters */
          break;        /* Make sure we use it */

      case '\b':        /* or if a Rubout: */
          if (itb_length(cmd_buff) <= 1)  /* Anything to delete? */
            return (TRUE);    /* No, just exit */
          unget_char();
          DOT = curpos; /* Reset the pointer */
          n = init_direction; /* Reset the search direction */
          (void) tb_copy(&searchpat, pat_save);
          /* Restore the old search str */
          cmd_reexecute = 0;  /* Start the whole mess over */
          goto start_over;    /* Let it take care of itself */

          /* Presumably a quasi-normal character comes here */

      default:          /* All other chars */
          if (c < ' ') {      /* Is it printable? *//* Nop
                           * e. */
            unkeystroke(c);   /* Re-eat the char */
            return (TRUE);    /* And return the last status */
          }
      }                 /* Switch */

      /* I guess we got something to search for, so search for it */

      tb_append(&searchpat, c);     /* put the char in the buffer */
      echochar(c);            /* Echo the character */
      if (!status) {          /* If we lost last time */
          kbd_alarm();  /* Feep again */
      } else                  /* Otherwise, we must have won */
          status = scanmore(searchpat, n);      /* or find the next
                                       * match */
      c = kcod2key(get_char());     /* Get the next char */
    }                   /* for_ever */
}

/*
 * Subroutine to do incremental reverse search.  It actually uses the same
 * code as the normal incremental search, as both can go both ways.
 */
int
risearch(int f, int n)
{
    MARK curpos;        /* Current point on entry */

    /* remember the initial . on entry: */

    curpos = DOT;       /* Save the current point */

    /* Save direction */
    last_srch_direc = REVERSE;

    /* Make sure the search doesn't match where we already are: */

    backchar(TRUE, 1);        /* Back up a character */

    if (!(isearch(f, -n))) {  /* Call ISearch backwards */
      /* If error in search: */
      DOT = curpos;           /* Reset the pointer */
      curwp->w_flag |= WFMOVE;      /* Say we've moved */
      (void) update(FALSE);   /* And force an update */
      mlwarn("[I-Search failed]");  /* Say we died */
      return FALSE;
    } else
      mlerase();        /* If happy, just erase the cmd line */

    return TRUE;
}

/* Again, but for the forward direction */

int
fisearch(int f, int n)
{
    MARK curpos;        /* current line on entryl */

    /* remember the initial . on entry: */

    curpos = DOT;       /* save current point */

    /* Save direction */
    last_srch_direc = FORWARD;

    /* do the search */

    if (!(isearch(f, n))) {   /* Call ISearch forwards */
      /* If error in search: */
      DOT = curpos;           /* reset */
      curwp->w_flag |= WFMOVE;      /* Say we've moved */
      (void) update(FALSE);   /* And force an update */
      mlwarn("[I-Search failed]");  /* Say we died */
      return FALSE;
    } else
      mlerase();        /* If happy, just erase the cmd line */

    return TRUE;
}
#endif

Generated by  Doxygen 1.6.0   Back to index