Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!cmcl2!rutgers!sri-spam!ames!necntc!ncoast!allbery From: nwd@j.cc.purdue.edu (Daniel Lawrence) Newsgroups: comp.sources.misc Subject: MicroEmacs 3.9 (Part 7 of 16) Message-ID: <5654@ncoast.UUCP> Date: Sat, 14-Nov-87 16:10:12 EST Article-I.D.: ncoast.5654 Posted: Sat Nov 14 16:10:12 1987 Date-Received: Tue, 17-Nov-87 03:05:23 EST Sender: allbery@ncoast.UUCP Lines: 1037 Approved: allbery@ncoast.UUCP X-Archive: comp.sources.misc/microemacs-3.9/6 # This is a shar archive. # Remove everything above this line. # Run the file through sh, not csh. # (type `sh mes.7') # If you do not see the message # `mes.7 completed!' # then the file was incomplete. echo extracting - input.c sed 's/^X//' > input.c << 'FRIDAY_NIGHT' X/* INPUT: Various input routines for MicroEMACS X written by Daniel Lawrence X 5/9/86 */ X X#include X#include "estruct.h" X#include "edef.h" X X/* X * Ask a yes or no question in the message line. Return either TRUE, FALSE, or X * ABORT. The ABORT status is returned if the user bumps out of the question X * with a ^G. Used any time a confirmation is required. X */ X Xmlyesno(prompt) X Xchar *prompt; X X{ X char c; /* input character */ X char buf[NPAT]; /* prompt to user */ X X for (;;) { X /* build and prompt the user */ X strcpy(buf, prompt); X strcat(buf, " [y/n]? "); X mlwrite(buf); X X /* get the responce */ X c = tgetc(); X X if (c == ectoc(abortc)) /* Bail out! */ X return(ABORT); X X if (c=='y' || c=='Y') X return(TRUE); X X if (c=='n' || c=='N') X return(FALSE); X } X} X X/* X * Write a prompt into the message line, then read back a response. Keep X * track of the physical position of the cursor. If we are in a keyboard X * macro throw the prompt away, and return the remembered response. This X * lets macros run at full speed. The reply is always terminated by a carriage X * return. Handle erase, kill, and abort keys. X */ X Xmlreply(prompt, buf, nbuf) X char *prompt; X char *buf; X{ X return(nextarg(prompt, buf, nbuf, ctoec('\n'))); X} X Xmlreplyt(prompt, buf, nbuf, eolchar) X Xchar *prompt; Xchar *buf; Xint eolchar; X X{ X return(nextarg(prompt, buf, nbuf, eolchar)); X} X X/* ectoc: expanded character to character X colapse the CTRL and SPEC flags back into an ascii code */ X Xectoc(c) X Xint c; X X{ X if (c & CTRL) X c = c & ~(CTRL | 0x40); X if (c & SPEC) X c= c & 255; X return(c); X} X X/* ctoec: character to extended character X pull out the CTRL and SPEC prefixes (if possible) */ X Xctoec(c) X Xint c; X X{ X if (c>=0x00 && c<=0x1F) X c = CTRL | (c+'@'); X return (c); X} X X/* get a command name from the command line. Command completion means X that pressing a will attempt to complete an unfinished command X name if it is unique. X*/ X Xint (*getname())() X X{ X#if ST520 & LATTICE X#define register X#endif X register int cpos; /* current column on screen output */ X register int c; X register char *sp; /* pointer to string for output */ X register NBIND *ffp; /* first ptr to entry in name binding table */ X register NBIND *cffp; /* current ptr to entry in name binding table */ X register NBIND *lffp; /* last ptr to entry in name binding table */ X char buf[NSTRING]; /* buffer to hold tentative command name */ X int (*fncmatch())(); X X /* starting at the beginning of the string buffer */ X cpos = 0; X X /* if we are executing a command line get the next arg and match it */ X if (clexec) { X if (macarg(buf) != TRUE) X return(FALSE); X return(fncmatch(&buf[0])); X } X X /* build a name string from the keyboard */ X while (TRUE) { X c = tgetc(); X X /* if we are at the end, just match it */ X if (c == 0x0d) { X buf[cpos] = 0; X X /* and match it off */ X return(fncmatch(&buf[0])); X X } else if (c == ectoc(abortc)) { /* Bell, abort */ X ctrlg(FALSE, 0); X TTflush(); X return( (int (*)()) NULL); X X } else if (c == 0x7F || c == 0x08) { /* rubout/erase */ X if (cpos != 0) { X TTputc('\b'); X TTputc(' '); X TTputc('\b'); X --ttcol; X --cpos; X TTflush(); X } X X } else if (c == 0x15) { /* C-U, kill */ X while (cpos != 0) { X TTputc('\b'); X TTputc(' '); X TTputc('\b'); X --cpos; X --ttcol; X } X X TTflush(); X X } else if (c == ' ') { X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ X /* attempt a completion */ X buf[cpos] = 0; /* terminate it for us */ X ffp = &names[0]; /* scan for matches */ X while (ffp->n_func != NULL) { X if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) { X /* a possible match! More than one? */ X if ((ffp + 1)->n_func == NULL || X (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) { X /* no...we match, print it */ X sp = ffp->n_name + cpos; X while (*sp) X TTputc(*sp++); X TTflush(); X return(ffp->n_func); X } else { X/* << << << << << << << << << << << << << << << << << */ X /* try for a partial match against the list */ X X /* first scan down until we no longer match the current input */ X lffp = (ffp + 1); X while ((lffp+1)->n_func != NULL) { X if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0) X break; X ++lffp; X } X X /* and now, attempt to partial complete the string, char at a time */ X while (TRUE) { X /* add the next char in */ X buf[cpos] = ffp->n_name[cpos]; X X /* scan through the candidates */ X cffp = ffp + 1; X while (cffp <= lffp) { X if (cffp->n_name[cpos] != buf[cpos]) X goto onward; X ++cffp; X } X X /* add the character */ X TTputc(buf[cpos++]); X } X/* << << << << << << << << << << << << << << << << << */ X } X } X ++ffp; X } X X /* no match.....beep and onward */ X TTbeep(); Xonward:; X TTflush(); X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ X } else { X if (cpos < NSTRING-1 && c > ' ') { X buf[cpos++] = c; X TTputc(c); X } X X ++ttcol; X TTflush(); X } X } X} X X/* tgetc: Get a key from the terminal driver, resolve any keyboard X macro action */ X Xint tgetc() X X{ X int c; /* fetched character */ X X /* if we are playing a keyboard macro back, */ X if (kbdmode == PLAY) { X X /* if there is some left... */ X if (kbdptr < kbdend) X return((int)*kbdptr++); X X /* at the end of last repitition? */ X if (--kbdrep < 1) { X kbdmode = STOP; X#if VISMAC == 0 X /* force a screen update after all is done */ X update(FALSE); X#endif X } else { X X /* reset the macro to the begining for the next rep */ X kbdptr = &kbdm[0]; X return((int)*kbdptr++); X } X } X X /* fetch a character from the terminal driver */ X c = TTgetc(); X X /* record it for $lastkey */ X lastkey = c; X X /* save it if we need to */ X if (kbdmode == RECORD) { X *kbdptr++ = c; X kbdend = kbdptr; X X /* don't overrun the buffer */ X if (kbdptr == &kbdm[NKBDM - 1]) { X kbdmode = STOP; X TTbeep(); X } X } X X /* and finally give the char back */ X return(c); X} X X/* GET1KEY: Get one keystroke. The only prefixs legal here X are the SPEC and CTRL prefixes. X */ X Xget1key() X X{ X int c; X#if AMIGA X int d; X#endif X X /* get a keystroke */ X c = tgetc(); X X#if MSDOS | ST520 X if (c == 0) { /* Apply SPEC prefix */ X c = tgetc(); X if (c>=0x00 && c<=0x1F) /* control key? */ X c = CTRL | (c+'@'); X return(SPEC | c); X } X#endif X X#if AMIGA X /* apply SPEC prefix */ X if ((unsigned)c == 155) { X c = tgetc(); X X /* first try to see if it is a cursor key */ X if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T') X return(SPEC | c); X X /* next, a 2 char sequence */ X d = tgetc(); X if (d == '~') X return(SPEC | c); X X /* decode a 3 char sequence */ X c = d + 32; X /* if a shifted function key, eat the tilde */ X if (d >= '0' && d <= '9') X d = tgetc(); X return(SPEC | c); X } X#endif X X#if WANGPC X if (c == 0x1F) { /* Apply SPEC prefix */ X c = tgetc(); X return(SPEC | c); X } X#endif X X if (c>=0x00 && c<=0x1F) /* C0 control -> C- */ X c = CTRL | (c+'@'); X return (c); X} X X/* GETCMD: Get a command from the keyboard. Process all applicable X prefix keys X */ Xgetcmd() X X{ X int c; /* fetched keystroke */ X X /* get initial character */ X c = get1key(); X X /* process META prefix */ X#if VT100 X /* if ESC must be recognized.... change this to a 1 */ X if (c == metac || c == (CTRL | '[')) X#else X if (c == metac) { X#endif X c = get1key(); X if (islower(c)) /* Force to upper */ X c ^= DIFCASE; X if (c>=0x00 && c<=0x1F) /* control key */ X c = CTRL | (c+'@'); X#if VT100 X if (c == '[' || c == 'O') { X c = get1key(); X return(SPEC | c); X } X#endif X return(META | c); X } X X /* process CTLX prefix */ X if (c == ctlxc) { X c = get1key(); X if (c>='a' && c<='z') /* Force to upper */ X c -= 0x20; X if (c>=0x00 && c<=0x1F) /* control key */ X c = CTRL | (c+'@'); X return(CTLX | c); X } X X /* otherwise, just return it */ X return(c); X} X X/* A more generalized prompt/reply function allowing the caller X to specify the proper terminator. If the terminator is not X a return ('\n') it will echo as "" X */ Xgetstring(prompt, buf, nbuf, eolchar) X Xchar *prompt; Xchar *buf; Xint eolchar; X X{ X register int cpos; /* current character position in string */ X register int c; X register int quotef; /* are we quoting the next char? */ X X cpos = 0; X quotef = FALSE; X X /* prompt the user for the input string */ X mlwrite(prompt); X X for (;;) { X /* get a character from the user */ X c = get1key(); X X /* If it is a , change it to a */ X if (c == (CTRL | 0x4d)) X c = CTRL | 0x40 | '\n'; X X /* if they hit the line terminate, wrap it up */ X if (c == eolchar && quotef == FALSE) { X buf[cpos++] = 0; X X /* clear the message line */ X mlwrite(""); X TTflush(); X X /* if we default the buffer, return FALSE */ X if (buf[0] == 0) X return(FALSE); X X return(TRUE); X } X X /* change from command form back to character form */ X c = ectoc(c); X X if (c == ectoc(abortc) && quotef == FALSE) { X /* Abort the input? */ X ctrlg(FALSE, 0); X TTflush(); X return(ABORT); X } else if ((c==0x7F || c==0x08) && quotef==FALSE) { X /* rubout/erase */ X if (cpos != 0) { X outstring("\b \b"); X --ttcol; X X if (buf[--cpos] < 0x20) { X outstring("\b \b"); X --ttcol; X } X X if (buf[cpos] == '\n') { X outstring("\b\b \b\b"); X ttcol -= 2; X } X TTflush(); X } X X } else if (c == 0x15 && quotef == FALSE) { X /* C-U, kill */ X while (cpos != 0) { X outstring("\b \b"); X --ttcol; X X if (buf[--cpos] < 0x20) { X outstring("\b \b"); X --ttcol; X } X } X TTflush(); X X } else if (c == quotec && quotef == FALSE) { X quotef = TRUE; X } else { X quotef = FALSE; X if (cpos < nbuf-1) { X buf[cpos++] = c; X X if ((c < ' ') && (c != '\n')) { X outstring("^"); X ++ttcol; X c ^= 0x40; X } X X if (c != '\n') { X if (disinp) X TTputc(c); X } else { /* put out for */ X outstring(""); X ttcol += 3; X } X ++ttcol; X TTflush(); X } X } X } X} X Xoutstring(s) /* output a string of input characters */ X Xchar *s; /* string to output */ X X{ X if (disinp) X while (*s) X TTputc(*s++); X} X Xostring(s) /* output a string of output characters */ X Xchar *s; /* string to output */ X X{ X if (discmd) X while (*s) X TTputc(*s++); X} X FRIDAY_NIGHT echo extracting - isearch.c sed 's/^X//' > isearch.c << 'FRIDAY_NIGHT' X/* X * The functions in this file implement commands that perform incremental X * searches in the forward and backward directions. This "ISearch" command X * is intended to emulate the same command from the original EMACS X * implementation (ITS). Contains references to routines internal to X * SEARCH.C. X * X * REVISION HISTORY: X * X * D. R. Banks 9-May-86 X * - added ITS EMACSlike ISearch X * X * John M. Gamble 5-Oct-86 X * - Made iterative search use search.c's scanner() routine. X * This allowed the elimination of bakscan(). X * - Put isearch constants into estruct.h X * - Eliminated the passing of 'status' to scanmore() and X * checknext(), since there were no circumstances where X * it ever equalled FALSE. X */ X X#include X#include "estruct.h" X#include "edef.h" X X#if ISRCH X Xextern int scanner(); /* Handy search routine */ Xextern int eq(); /* Compare chars, match case */ X X/* A couple of "own" variables for re-eat */ X Xint (*saved_get_char)(); /* Get character routine */ Xint eaten_char = -1; /* Re-eaten char */ X X/* A couple more "own" variables for the command string */ X Xint cmd_buff[CMDBUFLEN]; /* Save the command args here */ Xint cmd_offset; /* Current offset into command buff */ Xint cmd_reexecute = -1; /* > 0 if re-executing command */ X X X/* X * Subroutine to do incremental reverse search. It actually uses the X * same code as the normal incremental search, as both can go both ways. X */ X Xint risearch(f, n) X{ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X X /* remember the initial . on entry: */ X X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X X /* Make sure the search doesn't match where we already are: */ X X backchar(TRUE, 1); /* Back up a character */ X X if (!(isearch(f, -n))) /* Call ISearch backwards */ X { /* If error in search: */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset to original value */ X curwp->w_flag |= WFMOVE; /* Say we've moved */ X update(FALSE); /* And force an update */ X mlwrite ("[search failed]"); /* Say we died */ X } else mlerase (); /* If happy, just erase the cmd line */ X} X X/* Again, but for the forward direction */ X Xint fisearch(f, n) X{ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X X /* remember the initial . on entry: */ X X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X X /* do the search */ X X if (!(isearch(f, n))) /* Call ISearch forwards */ X { /* If error in search: */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset to original value */ X curwp->w_flag |= WFMOVE; /* Say we've moved */ X update(FALSE); /* And force an update */ X mlwrite ("[search failed]"); /* Say we died */ X } else mlerase (); /* If happy, just erase the cmd line */ X} X X/* X * Subroutine to do an incremental search. In general, this works similarly X * to the older micro-emacs search function, except that the search happens X * as each character is typed, with the screen and cursor updated with each X * new search character. X * X * While searching forward, each successive character will leave the cursor X * at the end of the entire matched string. Typing a Control-S or Control-X X * will cause the next occurrence of the string to be searched for (where the X * next occurrence does NOT overlap the current occurrence). A Control-R will X * change to a backwards search, META will terminate the search and Control-G X * will abort the search. Rubout will back up to the previous match of the X * string, or if the starting point is reached first, it will delete the X * last character from the search string. X * X * While searching backward, each successive character will leave the cursor X * at the beginning of the matched string. Typing a Control-R will search X * backward for the next occurrence of the string. Control-S or Control-X X * will revert the search to the forward direction. In general, the reverse X * incremental search is just like the forward incremental search inverted. X * X * In all cases, if the search fails, the user will be feeped, and the search X * will stall until the pattern string is edited back into something that X * exists (or until the search is aborted). X */ X Xisearch(f, n) X{ X int status; /* Search status */ X int col; /* prompt column */ X register int cpos; /* character number in search string */ X register int c; /* current input character */ X register int expc; /* function expanded input char */ X char pat_save[NPAT]; /* Saved copy of the old pattern str */ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X int init_direction; /* The initial search direction */ X X /* Initialize starting conditions */ X X cmd_reexecute = -1; /* We're not re-executing (yet?) */ X cmd_offset = 0; /* Start at the beginning of the buff */ X cmd_buff[0] = '\0'; /* Init the command buffer */ X strncpy (pat_save, pat, NPAT); /* Save the old pattern string */ X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X init_direction = n; /* Save the initial search direction */ X X /* This is a good place to start a re-execution: */ X Xstart_over: X X /* ask the user for the text of a pattern */ X col = promptpattern("ISearch: "); /* Prompt, remember the col */ X X cpos = 0; /* Start afresh */ X status = TRUE; /* Assume everything's cool */ X X /* X Get the first character in the pattern. If we get an initial Control-S X or Control-R, re-use the old search string and find the first occurrence X */ X X c = ectoc(expc = get_char()); /* Get the first character */ X if ((c == IS_FORWARD) || X (c == IS_REVERSE) || X (c == IS_VMSFORW)) /* Reuse old search string? */ X { X for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */ X col = echochar(pat[cpos],col); /* and re-echo the string */ X if (c == IS_REVERSE) { /* forward search? */ X n = -1; /* No, search in reverse */ X backchar (TRUE, 1); /* Be defensive about EOB */ X } else X n = 1; /* Yes, search forward */ X status = scanmore(pat, n); /* Do the search */ X c = ectoc(expc = get_char()); /* Get another character */ X } X X /* Top of the per character loop */ X X for (;;) /* ISearch per character loop */ X { X /* Check for special characters first: */ X /* Most cases here change the search */ X X if (expc == metac) /* Want to quit searching? */ X return (TRUE); /* Quit searching now */ X X switch (c) /* dispatch on the input char */ X { X case IS_ABORT: /* If abort search request */ X return(FALSE); /* Quit searching again */ X X case IS_REVERSE: /* If backward search */ X case IS_FORWARD: /* If forward search */ X case IS_VMSFORW: /* of either flavor */ X if (c == IS_REVERSE) /* If reverse search */ X n = -1; /* Set the reverse direction */ X else /* Otherwise, */ X n = 1; /* go forward */ X status = scanmore(pat, n); /* Start the search again */ X c = ectoc(expc = get_char()); /* Get the next char */ X continue; /* Go continue with the search*/ X X case IS_NEWLINE: /* Carriage return */ X c = '\n'; /* Make it a new line */ X break; /* Make sure we use it */ X X case IS_QUOTE: /* Quote character */ X case IS_VMSQUOTE: /* of either variety */ X c = ectoc(expc = get_char()); /* Get the next char */ X X case IS_TAB: /* Generically allowed */ X case '\n': /* controlled characters */ X break; /* Make sure we use it */ X X case IS_BACKSP: /* If a backspace: */ X case IS_RUBOUT: /* or if a Rubout: */ X if (cmd_offset <= 1) /* Anything to delete? */ X return (TRUE); /* No, just exit */ X --cmd_offset; /* Back up over the Rubout */ X cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset */ X n = init_direction; /* Reset the search direction */ X strncpy (pat, pat_save, NPAT); /* Restore the old search str */ X cmd_reexecute = 0; /* Start the whole mess over */ X goto start_over; /* Let it take care of itself */ X X /* Presumably a quasi-normal character comes here */ X X default: /* All other chars */ X if (c < ' ') /* Is it printable? */ X { /* Nope. */ X reeat (c); /* Re-eat the char */ X return (TRUE); /* And return the last status */ X } X } /* Switch */ X X /* I guess we got something to search for, so search for it */ X X pat[cpos++] = c; /* put the char in the buffer */ X if (cpos >= NPAT) /* too many chars in string? */ X { /* Yup. Complain about it */ X mlwrite("? Search string too long"); X return(TRUE); /* Return an error */ X } X pat[cpos] = 0; /* null terminate the buffer */ X col = echochar(c,col); /* Echo the character */ X if (!status) { /* If we lost last time */ X TTputc(BELL); /* Feep again */ X TTflush(); /* see that the feep feeps */ X } else /* Otherwise, we must have won*/ X if (!(status = checknext(c, pat, n))) /* See if match */ X status = scanmore(pat, n); /* or find the next match */ X c = ectoc(expc = get_char()); /* Get the next char */ X } /* for {;;} */ X} X X/* X * Trivial routine to insure that the next character in the search string is X * still true to whatever we're pointing to in the buffer. This routine will X * not attempt to move the "point" if the match fails, although it will X * implicitly move the "point" if we're forward searching, and find a match, X * since that's the way forward isearch works. X * X * If the compare fails, we return FALSE and assume the caller will call X * scanmore or something. X */ X Xint checknext (chr, patrn, dir) /* Check next character in search string */ Xchar chr; /* Next char to look for */ Xchar *patrn; /* The entire search string (incl chr) */ Xint dir; /* Search direction */ X{ X register LINE *curline; /* current line during scan */ X register int curoff; /* position within current line */ X register int buffchar; /* character at current position */ X int status; /* how well things go */ X X X /* setup the local scan pointer to current "." */ X X curline = curwp->w_dotp; /* Get the current line structure */ X curoff = curwp->w_doto; /* Get the offset within that line */ X X if (dir > 0) /* If searching forward */ X { X if (curoff == llength(curline)) /* If at end of line */ X { X curline = lforw(curline); /* Skip to the next line */ X if (curline == curbp->b_linep) X return (FALSE); /* Abort if at end of buffer */ X curoff = 0; /* Start at the beginning of the line */ X buffchar = '\n'; /* And say the next char is NL */ X } else X buffchar = lgetc(curline, curoff++); /* Get the next char */ X if (status = eq(buffchar, chr)) /* Is it what we're looking for? */ X { X curwp->w_dotp = curline; /* Yes, set the buffer's point */ X curwp->w_doto = curoff; /* to the matched character */ X curwp->w_flag |= WFMOVE; /* Say that we've moved */ X } X return (status); /* And return the status */ X } else /* Else, if reverse search: */ X return (match_pat (patrn)); /* See if we're in the right place */ X} X X/* X * This hack will search for the next occurrence of in the buffer, either X * forward or backward. It is called with the status of the prior search X * attempt, so that it knows not to bother if it didn't work last time. If X * we can't find any more matches, "point" is left where it was before. If X * we do find a match, "point" will be at the end of the matched string for X * forward searches and at the beginning of the matched string for reverse X * searches. X */ X Xint scanmore(patrn, dir) /* search forward or back for a pattern */ Xchar *patrn; /* string to scan for */ Xint dir; /* direction to search */ X{ X int sts; /* search status */ X X if (dir < 0) /* reverse search? */ X { X rvstrcpy(tap, patrn); /* Put reversed string in tap */ X sts = scanner(tap, REVERSE, PTBEG); X } X else X sts = scanner(patrn, FORWARD, PTEND); /* Nope. Go forward */ X X if (!sts) X { X TTputc(BELL); /* Feep if search fails */ X TTflush(); /* see that the feep feeps */ X } X X return(sts); /* else, don't even try */ X} X X/* X * The following is a worker subroutine used by the reverse search. It X * compares the pattern string with the characters at "." for equality. If X * any characters mismatch, it will return FALSE. X * X * This isn't used for forward searches, because forward searches leave "." X * at the end of the search string (instead of in front), so all that needs to X * be done is match the last char input. X */ X Xint match_pat (patrn) /* See if the pattern string matches string at "." */ Xchar *patrn; /* String to match to buffer */ X{ X register int i; /* Generic loop index/offset */ X register int buffchar; /* character at current position */ X register LINE *curline; /* current line during scan */ X register int curoff; /* position within current line */ X X /* setup the local scan pointer to current "." */ X X curline = curwp->w_dotp; /* Get the current line structure */ X curoff = curwp->w_doto; /* Get the offset within that line */ X X /* top of per character compare loop: */ X X for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */ X { X if (curoff == llength(curline)) /* If at end of line */ X { X curline = lforw(curline); /* Skip to the next line */ X curoff = 0; /* Start at the beginning of the line */ X if (curline == curbp->b_linep) X return (FALSE); /* Abort if at end of buffer */ X buffchar = '\n'; /* And say the next char is NL */ X } else X buffchar = lgetc(curline, curoff++); /* Get the next char */ X if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */ X return (FALSE); /* Nope, just punt it then */ X } X return (TRUE); /* Everything matched? Let's celebrate*/ X} X X/* Routine to prompt for I-Search string. */ X Xint promptpattern(prompt) Xchar *prompt; X{ X char tpat[NPAT+20]; X X strcpy(tpat, prompt); /* copy prompt to output string */ X strcat(tpat, " ["); /* build new prompt string */ X expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */ X strcat(tpat, "]: "); X X /* check to see if we are executing a command line */ X if (!clexec) { X mlwrite(tpat); X } X return(strlen(tpat)); X} X X/* routine to echo i-search characters */ X Xint echochar(c,col) Xint c; /* character to be echoed */ Xint col; /* column to be echoed in */ X{ X movecursor(term.t_nrow,col); /* Position the cursor */ X if ((c < ' ') || (c == 0x7F)) /* Control character? */ X { X switch (c) /* Yes, dispatch special cases*/ X { X case '\n': /* Newline */ X TTputc('<'); X TTputc('N'); X TTputc('L'); X TTputc('>'); X col += 3; X break; X X case '\t': /* Tab */ X TTputc('<'); X TTputc('T'); X TTputc('A'); X TTputc('B'); X TTputc('>'); X col += 4; X break; X X case 0x7F: /* Rubout: */ X TTputc('^'); /* Output a funny looking */ X TTputc('?'); /* indication of Rubout */ X col++; /* Count the extra char */ X break; X X default: /* Vanilla control char */ X TTputc('^'); /* Yes, output prefix */ X TTputc(c+0x40); /* Make it "^X" */ X col++; /* Count this char */ X } X } else X TTputc(c); /* Otherwise, output raw char */ X TTflush(); /* Flush the output */ X return(++col); /* return the new column no */ X} X X/* X * Routine to get the next character from the input stream. If we're reading X * from the real terminal, force a screen update before we get the char. X * Otherwise, we must be re-executing the command string, so just return the X * next character. X */ X Xint get_char () X{ X int c; /* A place to get a character */ X X /* See if we're re-executing: */ X X if (cmd_reexecute >= 0) /* Is there an offset? */ X if ((c = cmd_buff[cmd_reexecute++]) != 0) X return (c); /* Yes, return any character */ X X /* We're not re-executing (or aren't any more). Try for a real char */ X X cmd_reexecute = -1; /* Say we're in real mode again */ X update(FALSE); /* Pretty up the screen */ X if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */ X { X mlwrite ("? command too long"); /* Complain loudly and bitterly */ X return (metac); /* And force a quit */ X } X c = get1key(); /* Get the next character */ X cmd_buff[cmd_offset++] = c; /* Save the char for next time */ X cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */ X return (c); /* Return the character */ X} X X/* X * Hacky routine to re-eat a character. This will save the character to be X * re-eaten by redirecting the input call to a routine here. Hack, etc. X */ X X/* Come here on the next term.t_getchar call: */ X Xint uneat() X{ X int c; X X term.t_getchar = saved_get_char; /* restore the routine address */ X c = eaten_char; /* Get the re-eaten char */ X eaten_char = -1; /* Clear the old char */ X return(c); /* and return the last char */ X} X Xint reeat(c) Xint c; X{ X if (eaten_char != -1) /* If we've already been here */ X return/*(NULL)*/; /* Don't do it again */ X eaten_char = c; /* Else, save the char for later */ X saved_get_char = term.t_getchar; /* Save the char get routine */ X term.t_getchar = uneat; /* Replace it with ours */ X} X#else Xisearch() X{ X} X#endif FRIDAY_NIGHT echo mes.7 completed! # That's all folks!