home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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.
- *
- * REVISION HISTORY:
- *
- * D. R. Banks 9-May-86
- * - added ITS EMACSlike ISearch
- *
- * John M. Gamble 5-Oct-86
- * - Made iterative search use search.c's scanner() routine.
- * This allowed the elimination of bakscan().
- * - Put isearch constants into estruct.h
- * - Eliminated the passing of 'status' to scanmore() and
- * checknext(), since there were no circumstances where
- * it ever equalled FALSE.
- */
-
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
-
- #if ISRCH
-
- extern int scanner(); /* Handy search routine */
- extern int eq(); /* Compare chars, match case */
-
- /* A couple of "own" variables for re-eat */
-
- int (*saved_get_char)(); /* Get character routine */
- int eaten_char = -1; /* Re-eaten char */
-
- /* A couple more "own" variables for the command string */
-
- int cmd_buff[CMDBUFLEN]; /* Save the command args here */
- int cmd_offset; /* Current offset into command buff */
- 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(f, n)
- {
- LINE *curline; /* Current line on entry */
- int curoff; /* Current offset on entry */
-
- /* remember the initial . on entry: */
-
- curline = curwp->w_dotp; /* Save the current line pointer */
- curoff = curwp->w_doto; /* Save the current offset */
-
- /* 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: */
- curwp->w_dotp = curline; /* Reset the line pointer */
- curwp->w_doto = curoff; /* and the offset to original value */
- curwp->w_flag |= WFMOVE; /* Say we've moved */
- update(FALSE); /* And force an update */
- mlwrite ("[search failed]"); /* Say we died */
- } else mlerase (); /* If happy, just erase the cmd line */
- }
-
- /* Again, but for the forward direction */
-
- int fisearch(f, n)
- {
- LINE *curline; /* Current line on entry */
- int curoff; /* Current offset on entry */
-
- /* remember the initial . on entry: */
-
- curline = curwp->w_dotp; /* Save the current line pointer */
- curoff = curwp->w_doto; /* Save the current offset */
-
- /* do the search */
-
- if (!(isearch(f, n))) /* Call ISearch forwards */
- { /* If error in search: */
- curwp->w_dotp = curline; /* Reset the line pointer */
- curwp->w_doto = curoff; /* and the offset to original value */
- curwp->w_flag |= WFMOVE; /* Say we've moved */
- update(FALSE); /* And force an update */
- mlwrite ("[search failed]"); /* Say we died */
- } else mlerase (); /* If happy, just erase the cmd line */
- }
-
- /*
- * 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).
- */
-
- isearch(f, n)
- {
- int status; /* Search status */
- int col; /* prompt column */
- register int cpos; /* character number in search string */
- register int c; /* current input character */
- register int expc; /* function expanded input char */
- char pat_save[NPAT]; /* Saved copy of the old pattern str */
- LINE *curline; /* Current line on entry */
- int curoff; /* Current offset 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] = '\0'; /* Init the command buffer */
- strncpy (pat_save, pat, NPAT); /* Save the old pattern string */
- curline = curwp->w_dotp; /* Save the current line pointer */
- curoff = curwp->w_doto; /* Save the current offset */
- init_direction = n; /* Save the initial search direction */
-
- /* This is a good place to start a re-execution: */
-
- start_over:
-
- /* ask the user for the text of a pattern */
- col = promptpattern("ISearch: "); /* Prompt, remember the col */
-
- 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 = ectoc(expc = get_char()); /* Get the first character */
- if ((c == IS_FORWARD) ||
- (c == IS_REVERSE) ||
- (c == IS_VMSFORW)) /* Reuse old search string? */
- {
- for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */
- col = echochar(pat[cpos],col); /* and re-echo the string */
- if (c == IS_REVERSE) { /* forward search? */
- n = -1; /* No, search in reverse */
- backchar (TRUE, 1); /* Be defensive about EOB */
- } else
- n = 1; /* Yes, search forward */
- status = scanmore(pat, n); /* Do the search */
- c = ectoc(expc = get_char()); /* Get another character */
- }
-
- /* Top of the per character loop */
-
- for (;;) /* ISearch per character loop */
- {
- /* Check for special characters first: */
- /* Most cases here change the search */
-
- if (expc == metac) /* Want to quit searching? */
- return (TRUE); /* Quit searching now */
-
- switch (c) /* dispatch on the input char */
- {
- case IS_ABORT: /* If abort search request */
- return(FALSE); /* Quit searching again */
-
- case IS_REVERSE: /* If backward search */
- case IS_FORWARD: /* If forward search */
- case IS_VMSFORW: /* of either flavor */
- if (c == IS_REVERSE) /* If reverse search */
- n = -1; /* Set the reverse direction */
- else /* Otherwise, */
- n = 1; /* go forward */
- status = scanmore(pat, n); /* Start the search again */
- c = ectoc(expc = get_char()); /* Get the next char */
- continue; /* Go continue with the search*/
-
- case IS_NEWLINE: /* Carriage return */
- c = EOLCHAR; /* Make it a new line */
- break; /* Make sure we use it */
-
- case IS_QUOTE: /* Quote character */
- case IS_VMSQUOTE: /* of either variety */
- c = ectoc(expc = get_char()); /* Get the next char */
-
- case IS_TAB: /* Generically allowed */
- case LF: /* controlled characters */
- break; /* Make sure we use it */
-
- case IS_BACKSP: /* If a backspace: */
- case IS_RUBOUT: /* 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] = '\0'; /* Yes, delete last char */
- curwp->w_dotp = curline; /* Reset the line pointer */
- curwp->w_doto = curoff; /* and the offset */
- n = init_direction; /* Reset the search direction */
- strncpy (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? */
- { /* Nope. */
- reeat (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++] = c; /* put the char in the buffer */
- if (cpos >= NPAT) /* too many chars in string? */
- { /* Yup. Complain about it */
- mlwrite("? Search string too long");
- return(TRUE); /* Return an error */
- }
- pat[cpos] = 0; /* null terminate the buffer */
- col = echochar(c,col); /* Echo the character */
- if (!status) { /* If we lost last time */
- TTputc(BELL); /* Feep again */
- TTflush(); /* see that the feep feeps */
- } else /* Otherwise, we must have won*/
- if (!(status = checknext(c, pat, n))) /* See if match */
- status = scanmore(pat, n); /* or find the next match */
- c = ectoc(expc = get_char()); /* Get the next char */
- } /* for {;;} */
- }
-
- /*
- * Trivial routine to insure that the next character in the search string is
- * still true to whatever we're pointing to in the buffer. This routine will
- * not attempt to move the "point" if the match fails, although it will
- * implicitly move the "point" if we're forward searching, and find a match,
- * since that's the way forward isearch works.
- *
- * If the compare fails, we return FALSE and assume the caller will call
- * scanmore or something.
- */
-
- int checknext (chr, patrn, dir) /* Check next character in search string */
- char chr; /* Next char to look for */
- char *patrn; /* The entire search string (incl chr) */
- int dir; /* Search direction */
- {
- register LINE *curline; /* current line during scan */
- register int curoff; /* position within current line */
- register int buffchar; /* character at current position */
- int status; /* how well things go */
-
-
- /* setup the local scan pointer to current "." */
-
- curline = curwp->w_dotp; /* Get the current line structure */
- curoff = curwp->w_doto; /* Get the offset within that line */
-
- if (dir > 0) /* If searching forward */
- {
- if (curoff == llength(curline)) /* If at end of line */
- {
- curline = lforw(curline); /* Skip to the next line */
- if (curline == curbp->b_linep)
- return (FALSE); /* Abort if at end of buffer */
- curoff = 0; /* Start at the beginning of the line */
- buffchar = EOLCHAR; /* And say the next char is NL */
- } else
- buffchar = lgetc(curline, curoff++); /* Get the next char */
- if (status = eq(buffchar, chr)) /* Is it what we're looking for? */
- {
- curwp->w_dotp = curline; /* Yes, set the buffer's point */
- curwp->w_doto = curoff; /* to the matched character */
- curwp->w_flag |= WFMOVE; /* Say that we've moved */
- }
- return (status); /* And return the status */
- } else /* Else, if reverse search: */
- return (match_pat (patrn)); /* See if we're in the right place */
- }
-
- /*
- * 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.
- */
-
- int scanmore(patrn, dir) /* search forward or back for a pattern */
- char *patrn; /* string to scan for */
- int dir; /* direction to search */
- {
- int sts; /* search status */
-
- if (dir < 0) /* reverse search? */
- {
- rvstrcpy(tap, patrn); /* Put reversed string in tap */
- sts = scanner(tap, REVERSE, PTBEG);
- }
- else
- sts = scanner(patrn, FORWARD, PTEND); /* Nope. Go forward */
-
- if (!sts)
- {
- TTputc(BELL); /* Feep if search fails */
- TTflush(); /* see that the feep feeps */
- }
-
- return(sts); /* else, don't even try */
- }
-
- /*
- * The following is a worker subroutine used by the reverse search. It
- * compares the pattern string with the characters at "." for equality. If
- * any characters mismatch, it will return FALSE.
- *
- * This isn't used for forward searches, because forward searches leave "."
- * at the end of the search string (instead of in front), so all that needs to
- * be done is match the last char input.
- */
-
- int match_pat (patrn) /* See if the pattern string matches string at "." */
- char *patrn; /* String to match to buffer */
- {
- register int i; /* Generic loop index/offset */
- register int buffchar; /* character at current position */
- register LINE *curline; /* current line during scan */
- register int curoff; /* position within current line */
-
- /* setup the local scan pointer to current "." */
-
- curline = curwp->w_dotp; /* Get the current line structure */
- curoff = curwp->w_doto; /* Get the offset within that line */
-
- /* top of per character compare loop: */
-
- for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */
- {
- if (curoff == llength(curline)) /* If at end of line */
- {
- curline = lforw(curline); /* Skip to the next line */
- curoff = 0; /* Start at the beginning of the line */
- if (curline == curbp->b_linep)
- return (FALSE); /* Abort if at end of buffer */
- buffchar = EOLCHAR; /* And say the next char is NL */
- } else
- buffchar = lgetc(curline, curoff++); /* Get the next char */
- if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */
- return (FALSE); /* Nope, just punt it then */
- }
- return (TRUE); /* Everything matched? Let's celebrate*/
- }
-
- /* Routine to prompt for I-Search string. */
-
- int promptpattern(prompt)
- char *prompt;
- {
- char tpat[NPAT+20];
-
- strcpy(tpat, prompt); /* copy prompt to output string */
- strcat(tpat, " ["); /* build new prompt string */
- expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
- strcat(tpat, "]<META>: ");
-
- /* check to see if we are executing a command line */
- if (!clexec) {
- mlwrite(tpat);
- }
- return(strlen(tpat));
- }
-
- /* routine to echo i-search characters */
-
- int echochar(c,col)
- int c; /* character to be echoed */
- int col; /* column to be echoed in */
- {
- c &= 0xFF;
- movecursor(term.t_nrow,col); /* Position the cursor */
- if ((c < ' ') || (c == 0x7F)) /* Control character? */
- {
- switch (c) /* Yes, dispatch special cases*/
- {
- #ifdef FINDER
- case 13:
- #else
- case EOLCHAR: /* Newline */
- #endif
- TTputc('<');
- TTputc('N');
- TTputc('L');
- TTputc('>');
- col += 3;
- break;
-
- case '\t': /* Tab */
- TTputc('<');
- TTputc('T');
- TTputc('A');
- TTputc('B');
- TTputc('>');
- col += 4;
- break;
-
- case 0x7F: /* Rubout: */
- TTputc('^'); /* Output a funny looking */
- TTputc('?'); /* indication of Rubout */
- col++; /* Count the extra char */
- break;
-
- default: /* Vanilla control char */
- TTputc('^'); /* Yes, output prefix */
- TTputc(c+0x40); /* Make it "^X" */
- col++; /* Count this char */
- }
- } else
- TTputc(c); /* Otherwise, output raw char */
- TTflush(); /* Flush the output */
- return(++col); /* return the new column no */
- }
-
- /*
- * 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.
- */
-
- int get_char ()
- {
- 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 */
- update(FALSE); /* Pretty up the screen */
- if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */
- {
- mlwrite ("? command too long"); /* Complain loudly and bitterly */
- return (metac); /* And force a quit */
- }
- c = get1key(); /* Get the next character */
- cmd_buff[cmd_offset++] = c; /* Save the char for next time */
- cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */
- return (c); /* Return the character */
- }
-
- /*
- * Hacky routine to re-eat a character. This will save the character to be
- * re-eaten by redirecting the input call to a routine here. Hack, etc.
- */
-
- /* Come here on the next term.t_getchar call: */
-
- int uneat()
- {
- int c;
-
- term.t_getchar = saved_get_char; /* restore the routine address */
- c = eaten_char; /* Get the re-eaten char */
- eaten_char = -1; /* Clear the old char */
- return(c); /* and return the last char */
- }
-
- int reeat(c)
- int c;
- {
- if (eaten_char != -1) /* If we've already been here */
- return/*(NULL)*/; /* Don't do it again */
- eaten_char = c; /* Else, save the char for later */
- saved_get_char = term.t_getchar; /* Save the char get routine */
- term.t_getchar = uneat; /* Replace it with ours */
- }
- #else
- isearch()
- {
- }
- #endif
-