home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vile-src.zip
/
vile-8.1
/
isearch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-31
|
12KB
|
404 lines
/*
* 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.49 1997/11/01 00:18:26 tom Exp $
*
*/
#include "estruct.h"
#include "edef.h"
#if OPT_ISRCH
static char * expandp(char *deststr, char *srcstr, int maxlength);
static int get_char (void);
static int isearch(int f, int n);
static int promptpattern(const char *prompt);
static int scanmore(char *patrn, int dir);
static void echochar(int c);
/* A couple "own" variables for the command string */
static int cmd_buff[CMDBUFLEN]; /* Save the command args here */
static int cmd_offset; /* Current offset into command buff */
static int cmd_reexecute = -1; /* > 0 if re-executing command */
/*
* 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;
}
/*
* 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)
{
int status; /* Search status */
register int cpos; /* character number in search string */
register int c; /* current input character */
char pat_save[NPAT]; /* Saved copy of the old pattern str */
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?) */
cmd_offset = 0; /* Start at the beginning of the buff */
cmd_buff[0] = EOS; /* Init the command buffer */
(void)strncpy0(pat_save, pat, NPAT); /* Save the old pattern string */
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: ");
cpos = 0; /* Start afresh */
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; pat[cpos] != 0; cpos++) /* Yup, find the length */
echochar(pat[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);
}
--cmd_offset; /* Back up over the Rubout */
cmd_buff[--cmd_offset] = EOS; /* Yes, delete last char */
status = scanmore(pat, 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 first: */
/* Most cases here change the search */
if (ABORTED(c) || c == '\r') /* Want to quit searching? */
return (TRUE); /* Quit searching now */
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(pat, n); /* Do the search */
if (status != TRUE)
DOT = curp;
c = kcod2key(get_char()); /* Get the next char */
--cmd_offset; /* Back up over the Rubout */
cmd_buff[--cmd_offset] = EOS; /* Yes, del last 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 (cmd_offset <= 1) /* Anything to delete? */
return (TRUE); /* No, just exit */
--cmd_offset; /* Back up over the Rubout */
cmd_buff[--cmd_offset] = EOS; /* Yes, del last char */
DOT = curpos; /* Reset the pointer */
n = init_direction; /* Reset the search direction */
(void)strncpy0(pat, pat_save, NPAT);
/* 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 */
pat[cpos++] = (char)c; /* put the char in the buffer */
if (cpos >= NPAT) { /* too many chars in string? *//* Yup
* . Complain about it */
mlforce("[Search string too long]");
return (TRUE); /* Return an error */
}
pat[cpos] = 0; /* null terminate 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(pat, n); /* or find the next
* match */
c = kcod2key(get_char()); /* Get the next char */
} /* for_ever */
}
/*
* This hack will search for the next occurrence of <pat> 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 */
char *patrn, /* string to scan for */
int dir) /* direction to search */
{
int sts; /* search status */
FreeIfNeeded(gregexp);
gregexp = regcomp(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(); /* Feep if search fails */
return (sts); /* else, don't even try */
}
/* Routine to prompt for I-Search string. */
static int
promptpattern(const char *prompt)
{
static const char fmt[] = "%s [%s]: ";
char tpat[NPAT],
temp[NPAT];
(void)lsprintf(tpat, fmt, prompt,
expandp(temp, pat, (int)(NPAT-sizeof(fmt)-strlen(prompt))));
/* check to see if we are executing a command line */
if (!clexec) {
mlforce("%s", tpat);
}
return (strlen(tpat));
}
/*
* expandp -- Expand control key sequences for output.
*/
static char *
expandp(
char *deststr, /* destination of expanded string */
char *srcstr, /* string to expand */
int maxlength) /* maximum chars in destination */
{
char *base = deststr;
UCHAR c; /* current char to translate */
/*
* Scan through the string.
*/
while ((c = *srcstr++) != 0) {
if (c == '\n') {/* it's a newline */
*deststr++ = '<';
*deststr++ = 'N';
*deststr++ = 'L';
*deststr++ = '>';
maxlength -= 4;
} else if (!isPrint(c)) { /* control character */
*deststr++ = '^';
*deststr++ = toalpha(c);
maxlength -= 2;
} else { /* any other character */
*deststr++ = c;
maxlength--;
}
/* check for maxlength */
if (maxlength < 4) {
*deststr++ = '$';
break;
}
}
*deststr = EOS;
return base;
}
/* routine to echo i-search characters */
static void
echochar(int c) /* character to be echoed */
{
kbd_putc(c);
kbd_flush();
}
/*
* 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) /* Is there an offset? */
if ((c = cmd_buff[cmd_reexecute++]) != 0)
return (c); /* Yes, return any character */
/* 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 */
if (cmd_offset >= CMDBUFLEN - 1) { /* If we're getting too big
* ... */
mlforce("[Command too long]"); /* Complain loudly and
* bitterly */
return (abortc);/* And force a quit */
}
c = keystroke8(); /* Get the next character */
cmd_buff[cmd_offset++] = c; /* Save the char for next time */
cmd_buff[cmd_offset] = EOS; /* And terminate the buffer */
return (c); /* Return the character */
}
#endif