Home | History | Annotate | Line # | Download | only in common
      1  1.5  gutterid /*	$NetBSD: search.c,v 1.5 2023/02/13 23:08:43 gutteridge Exp $ */
      2  1.1  christos /*-
      3  1.1  christos  * Copyright (c) 1992, 1993, 1994
      4  1.1  christos  *	The Regents of the University of California.  All rights reserved.
      5  1.1  christos  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  1.1  christos  *	Keith Bostic.  All rights reserved.
      7  1.1  christos  *
      8  1.1  christos  * See the LICENSE file for redistribution information.
      9  1.1  christos  */
     10  1.1  christos 
     11  1.1  christos #include "config.h"
     12  1.1  christos 
     13  1.3  christos #include <sys/cdefs.h>
     14  1.3  christos #if 0
     15  1.1  christos #ifndef lint
     16  1.1  christos static const char sccsid[] = "Id: search.c,v 10.31 2001/06/25 15:19:12 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:12 ";
     17  1.1  christos #endif /* not lint */
     18  1.3  christos #else
     19  1.5  gutterid __RCSID("$NetBSD: search.c,v 1.5 2023/02/13 23:08:43 gutteridge Exp $");
     20  1.3  christos #endif
     21  1.1  christos 
     22  1.1  christos #include <sys/types.h>
     23  1.1  christos #include <sys/queue.h>
     24  1.1  christos 
     25  1.1  christos #include <bitstring.h>
     26  1.1  christos #include <ctype.h>
     27  1.1  christos #include <errno.h>
     28  1.1  christos #include <limits.h>
     29  1.1  christos #include <stdio.h>
     30  1.1  christos #include <stdlib.h>
     31  1.1  christos #include <string.h>
     32  1.1  christos #include <unistd.h>
     33  1.1  christos 
     34  1.1  christos #include "common.h"
     35  1.1  christos 
     36  1.1  christos typedef enum { S_EMPTY, S_EOF, S_NOPREV, S_NOTFOUND, S_SOF, S_WRAP } smsg_t;
     37  1.1  christos 
     38  1.1  christos static void	search_msg __P((SCR *, smsg_t));
     39  1.1  christos static int	search_init __P((SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int));
     40  1.1  christos 
     41  1.1  christos /*
     42  1.1  christos  * search_init --
     43  1.1  christos  *	Set up a search.
     44  1.1  christos  */
     45  1.1  christos static int
     46  1.1  christos search_init(SCR *sp, dir_t dir, CHAR_T *ptrn, size_t plen, CHAR_T **epp, u_int flags)
     47  1.1  christos {
     48  1.1  christos 	db_recno_t lno;
     49  1.1  christos 	int delim;
     50  1.1  christos 	CHAR_T *p, *t;
     51  1.1  christos 
     52  1.1  christos 	/* If the file is empty, it's a fast search. */
     53  1.1  christos 	if (sp->lno <= 1) {
     54  1.1  christos 		if (db_last(sp, &lno))
     55  1.1  christos 			return (1);
     56  1.1  christos 		if (lno == 0) {
     57  1.1  christos 			if (LF_ISSET(SEARCH_MSG))
     58  1.1  christos 				search_msg(sp, S_EMPTY);
     59  1.1  christos 			return (1);
     60  1.1  christos 		}
     61  1.1  christos 	}
     62  1.1  christos 
     63  1.1  christos 	if (LF_ISSET(SEARCH_PARSE)) {		/* Parse the string. */
     64  1.1  christos 		/*
     65  1.1  christos 		 * Use the saved pattern if no pattern specified, or if only
     66  1.1  christos 		 * one or two delimiter characters specified.
     67  1.1  christos 		 *
     68  1.1  christos 		 * !!!
     69  1.1  christos 		 * Historically, only the pattern itself was saved, vi didn't
     70  1.1  christos 		 * preserve addressing or delta information.
     71  1.1  christos 		 */
     72  1.1  christos 		if (ptrn == NULL)
     73  1.1  christos 			goto prev;
     74  1.1  christos 		if (plen == 1) {
     75  1.1  christos 			if (epp != NULL)
     76  1.1  christos 				*epp = ptrn + 1;
     77  1.1  christos 			goto prev;
     78  1.1  christos 		}
     79  1.1  christos 		if (ptrn[0] == ptrn[1]) {
     80  1.1  christos 			if (epp != NULL)
     81  1.1  christos 				*epp = ptrn + 2;
     82  1.1  christos 
     83  1.1  christos 			/* Complain if we don't have a previous pattern. */
     84  1.1  christos prev:			if (sp->re == NULL) {
     85  1.1  christos 				search_msg(sp, S_NOPREV);
     86  1.1  christos 				return (1);
     87  1.1  christos 			}
     88  1.1  christos 			/* Re-compile the search pattern if necessary. */
     89  1.1  christos 			if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp,
     90  1.1  christos 			    sp->re, sp->re_len, NULL, NULL, &sp->re_c,
     91  1.1  christos 			    SEARCH_CSEARCH | SEARCH_MSG))
     92  1.1  christos 				return (1);
     93  1.1  christos 
     94  1.1  christos 			/* Set the search direction. */
     95  1.1  christos 			if (LF_ISSET(SEARCH_SET))
     96  1.1  christos 				sp->searchdir = dir;
     97  1.1  christos 			return (0);
     98  1.1  christos 		}
     99  1.1  christos 
    100  1.1  christos 		/*
    101  1.1  christos 		 * Set the delimiter, and move forward to the terminating
    102  1.1  christos 		 * delimiter, handling escaped delimiters.
    103  1.1  christos 		 *
    104  1.1  christos 		 * QUOTING NOTE:
    105  1.1  christos 		 * Only discard an escape character if it escapes a delimiter.
    106  1.1  christos 		 */
    107  1.1  christos 		for (delim = *ptrn, p = t = ++ptrn;; *t++ = *p++) {
    108  1.1  christos 			if (--plen == 0 || p[0] == delim) {
    109  1.1  christos 				if (plen != 0)
    110  1.1  christos 					++p;
    111  1.1  christos 				break;
    112  1.1  christos 			}
    113  1.5  gutterid 			if (plen > 1 && p[0] == '\\') {
    114  1.5  gutterid 				if(p[1] == delim) {
    115  1.5  gutterid 					++p;
    116  1.5  gutterid 					--plen;
    117  1.5  gutterid 				} else if(p[1] == '\\') {
    118  1.5  gutterid 					*t++ = *p++;
    119  1.5  gutterid 					--plen;
    120  1.5  gutterid 				}
    121  1.1  christos 			}
    122  1.1  christos 		}
    123  1.1  christos 		if (epp != NULL)
    124  1.1  christos 			*epp = p;
    125  1.1  christos 
    126  1.1  christos 		plen = t - ptrn;
    127  1.1  christos 	}
    128  1.1  christos 
    129  1.1  christos 	/* Compile the RE. */
    130  1.1  christos 	if (re_compile(sp, ptrn, plen, &sp->re, &sp->re_len, &sp->re_c,
    131  1.1  christos 	    SEARCH_CSEARCH | LF_ISSET(SEARCH_CSCOPE | SEARCH_EXTEND |
    132  1.1  christos 	    SEARCH_IC | SEARCH_LITERAL | SEARCH_MSG | SEARCH_TAG)))
    133  1.1  christos 		return (1);
    134  1.1  christos 
    135  1.1  christos 	/* Set the search direction. */
    136  1.1  christos 	if (LF_ISSET(SEARCH_SET))
    137  1.1  christos 		sp->searchdir = dir;
    138  1.1  christos 
    139  1.1  christos 	return (0);
    140  1.1  christos }
    141  1.1  christos 
    142  1.1  christos /*
    143  1.1  christos  * f_search --
    144  1.1  christos  *	Do a forward search.
    145  1.1  christos  *
    146  1.1  christos  * PUBLIC: int f_search __P((SCR *,
    147  1.1  christos  * PUBLIC:    MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
    148  1.1  christos  */
    149  1.1  christos int
    150  1.1  christos f_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, CHAR_T **eptrn, u_int flags)
    151  1.1  christos {
    152  1.1  christos 	busy_t btype;
    153  1.1  christos 	db_recno_t lno;
    154  1.1  christos 	regmatch_t match[1];
    155  1.1  christos 	size_t coff, len;
    156  1.4       rin 	int cnt, eval, rval, wrapped = 0;
    157  1.1  christos 	CHAR_T *l;
    158  1.1  christos 
    159  1.1  christos 	if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags))
    160  1.1  christos 		return (1);
    161  1.1  christos 
    162  1.1  christos 	/* Figure out if we're going to wrap. */
    163  1.1  christos 	if (!LF_ISSET(SEARCH_NOOPT) && O_ISSET(sp, O_WRAPSCAN))
    164  1.1  christos 		LF_SET(SEARCH_WRAP);
    165  1.1  christos 
    166  1.1  christos 	if (LF_ISSET(SEARCH_FIRST)) {
    167  1.1  christos 		lno = 1;
    168  1.1  christos 		coff = 0;
    169  1.1  christos 	} else {
    170  1.1  christos 		if (db_get(sp, fm->lno, DBG_FATAL, &l, &len))
    171  1.1  christos 			return (1);
    172  1.1  christos 		lno = fm->lno;
    173  1.1  christos 
    174  1.1  christos 		/*
    175  1.1  christos 		 * If doing incremental search, start searching at the previous
    176  1.1  christos 		 * column, so that we search a minimal distance and still match
    177  1.1  christos 		 * special patterns, e.g., \< for beginning of a word.
    178  1.1  christos 		 *
    179  1.1  christos 		 * Otherwise, start searching immediately after the cursor.  If
    180  1.1  christos 		 * at the end of the line, start searching on the next line.
    181  1.1  christos 		 * This is incompatible (read bug fix) with the historic vi --
    182  1.1  christos 		 * searches for the '$' pattern never moved forward, and the
    183  1.1  christos 		 * "-t foo" didn't work if the 'f' was the first character in
    184  1.1  christos 		 * the file.
    185  1.1  christos 		 */
    186  1.1  christos 		if (LF_ISSET(SEARCH_INCR)) {
    187  1.1  christos 			if ((coff = fm->cno) != 0)
    188  1.1  christos 				--coff;
    189  1.1  christos 		} else if (fm->cno + 1 >= len) {
    190  1.1  christos 			coff = 0;
    191  1.1  christos 			lno = fm->lno + 1;
    192  1.1  christos 			if (db_get(sp, lno, 0, &l, &len)) {
    193  1.1  christos 				if (!LF_ISSET(SEARCH_WRAP)) {
    194  1.1  christos 					if (LF_ISSET(SEARCH_MSG))
    195  1.1  christos 						search_msg(sp, S_EOF);
    196  1.1  christos 					return (1);
    197  1.1  christos 				}
    198  1.1  christos 				lno = 1;
    199  1.4       rin 				wrapped = 1;
    200  1.1  christos 			}
    201  1.1  christos 		} else
    202  1.1  christos 			coff = fm->cno + 1;
    203  1.1  christos 	}
    204  1.1  christos 
    205  1.1  christos 	btype = BUSY_ON;
    206  1.4       rin 	for (cnt = INTERRUPT_CHECK, rval = 1;; ++lno, coff = 0) {
    207  1.1  christos 		if (cnt-- == 0) {
    208  1.1  christos 			if (INTERRUPTED(sp))
    209  1.1  christos 				break;
    210  1.1  christos 			if (LF_ISSET(SEARCH_MSG)) {
    211  1.1  christos 				search_busy(sp, btype);
    212  1.1  christos 				btype = BUSY_UPDATE;
    213  1.1  christos 			}
    214  1.1  christos 			cnt = INTERRUPT_CHECK;
    215  1.1  christos 		}
    216  1.2  christos 		if ((wrapped && lno > fm->lno) ||
    217  1.2  christos 		    db_get(sp, lno, 0, &l, &len)) {
    218  1.1  christos 			if (wrapped) {
    219  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    220  1.1  christos 					search_msg(sp, S_NOTFOUND);
    221  1.1  christos 				break;
    222  1.1  christos 			}
    223  1.1  christos 			if (!LF_ISSET(SEARCH_WRAP)) {
    224  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    225  1.1  christos 					search_msg(sp, S_EOF);
    226  1.1  christos 				break;
    227  1.1  christos 			}
    228  1.1  christos 			lno = 0;
    229  1.1  christos 			wrapped = 1;
    230  1.1  christos 			continue;
    231  1.1  christos 		}
    232  1.1  christos 
    233  1.1  christos 		/* If already at EOL, just keep going. */
    234  1.1  christos 		if (len != 0 && coff == len)
    235  1.1  christos 			continue;
    236  1.1  christos 
    237  1.1  christos 		/* Set the termination. */
    238  1.1  christos 		match[0].rm_so = coff;
    239  1.1  christos 		match[0].rm_eo = len;
    240  1.1  christos 
    241  1.1  christos #if defined(DEBUG) && 0
    242  1.1  christos 		vtrace(sp, "F search: %lu from %u to %u\n",
    243  1.1  christos 		    lno, coff, len != 0 ? len - 1 : len);
    244  1.1  christos #endif
    245  1.1  christos 		/* Search the line. */
    246  1.1  christos 		eval = regexec(&sp->re_c, l, 1, match,
    247  1.1  christos 		    (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND);
    248  1.1  christos 		if (eval == REG_NOMATCH)
    249  1.1  christos 			continue;
    250  1.1  christos 		if (eval != 0) {
    251  1.1  christos 			if (LF_ISSET(SEARCH_MSG))
    252  1.1  christos 				re_error(sp, eval, &sp->re_c);
    253  1.1  christos 			else
    254  1.1  christos 				(void)sp->gp->scr_bell(sp);
    255  1.1  christos 			break;
    256  1.1  christos 		}
    257  1.1  christos 
    258  1.1  christos 		/* Warn if the search wrapped. */
    259  1.1  christos 		if (wrapped && LF_ISSET(SEARCH_WMSG))
    260  1.1  christos 			search_msg(sp, S_WRAP);
    261  1.1  christos 
    262  1.1  christos #if defined(DEBUG) && 0
    263  1.1  christos 		vtrace(sp, "F search: %qu to %qu\n",
    264  1.1  christos 		    match[0].rm_so, match[0].rm_eo);
    265  1.1  christos #endif
    266  1.1  christos 		rm->lno = lno;
    267  1.1  christos 		rm->cno = match[0].rm_so;
    268  1.1  christos 
    269  1.1  christos 		/*
    270  1.1  christos 		 * If a change command, it's possible to move beyond the end
    271  1.1  christos 		 * of a line.  Historic vi generally got this wrong (e.g. try
    272  1.1  christos 		 * "c?$<cr>").  Not all that sure this gets it right, there
    273  1.1  christos 		 * are lots of strange cases.
    274  1.1  christos 		 */
    275  1.1  christos 		if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len)
    276  1.1  christos 			rm->cno = len != 0 ? len - 1 : 0;
    277  1.1  christos 
    278  1.1  christos 		rval = 0;
    279  1.1  christos 		break;
    280  1.1  christos 	}
    281  1.1  christos 
    282  1.1  christos 	if (LF_ISSET(SEARCH_MSG))
    283  1.1  christos 		search_busy(sp, BUSY_OFF);
    284  1.1  christos 	return (rval);
    285  1.1  christos }
    286  1.1  christos 
    287  1.1  christos /*
    288  1.1  christos  * b_search --
    289  1.1  christos  *	Do a backward search.
    290  1.1  christos  *
    291  1.1  christos  * PUBLIC: int b_search __P((SCR *,
    292  1.1  christos  * PUBLIC:    MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int));
    293  1.1  christos  */
    294  1.1  christos int
    295  1.1  christos b_search(SCR *sp, MARK *fm, MARK *rm, CHAR_T *ptrn, size_t plen, CHAR_T **eptrn, u_int flags)
    296  1.1  christos {
    297  1.1  christos 	busy_t btype;
    298  1.1  christos 	db_recno_t lno;
    299  1.1  christos 	regmatch_t match[1];
    300  1.1  christos 	size_t coff, last, len;
    301  1.1  christos 	int cnt, eval, rval, wrapped;
    302  1.1  christos 	CHAR_T *l;
    303  1.1  christos 
    304  1.1  christos 	if (search_init(sp, BACKWARD, ptrn, plen, eptrn, flags))
    305  1.1  christos 		return (1);
    306  1.1  christos 
    307  1.1  christos 	/* Figure out if we're going to wrap. */
    308  1.1  christos 	if (!LF_ISSET(SEARCH_NOOPT) && O_ISSET(sp, O_WRAPSCAN))
    309  1.1  christos 		LF_SET(SEARCH_WRAP);
    310  1.1  christos 
    311  1.1  christos 	/*
    312  1.1  christos 	 * If doing incremental search, set the "starting" position past the
    313  1.1  christos 	 * current column, so that we search a minimal distance and still
    314  1.1  christos 	 * match special patterns, e.g., \> for the end of a word.  This is
    315  1.1  christos 	 * safe when the cursor is at the end of a line because we only use
    316  1.1  christos 	 * it for comparison with the location of the match.
    317  1.1  christos 	 *
    318  1.1  christos 	 * Otherwise, start searching immediately before the cursor.  If in
    319  1.1  christos 	 * the first column, start search on the previous line.
    320  1.1  christos 	 */
    321  1.1  christos 	if (LF_ISSET(SEARCH_INCR)) {
    322  1.1  christos 		lno = fm->lno;
    323  1.1  christos 		coff = fm->cno + 1;
    324  1.1  christos 	} else {
    325  1.1  christos 		if (fm->cno == 0) {
    326  1.1  christos 			if (fm->lno == 1 && !LF_ISSET(SEARCH_WRAP)) {
    327  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    328  1.1  christos 					search_msg(sp, S_SOF);
    329  1.1  christos 				return (1);
    330  1.1  christos 			}
    331  1.1  christos 			lno = fm->lno - 1;
    332  1.1  christos 		} else
    333  1.1  christos 			lno = fm->lno;
    334  1.1  christos 		coff = fm->cno;
    335  1.1  christos 	}
    336  1.1  christos 
    337  1.1  christos 	btype = BUSY_ON;
    338  1.1  christos 	for (cnt = INTERRUPT_CHECK, rval = 1, wrapped = 0;; --lno, coff = 0) {
    339  1.1  christos 		if (cnt-- == 0) {
    340  1.1  christos 			if (INTERRUPTED(sp))
    341  1.1  christos 				break;
    342  1.1  christos 			if (LF_ISSET(SEARCH_MSG)) {
    343  1.1  christos 				search_busy(sp, btype);
    344  1.1  christos 				btype = BUSY_UPDATE;
    345  1.1  christos 			}
    346  1.1  christos 			cnt = INTERRUPT_CHECK;
    347  1.1  christos 		}
    348  1.2  christos 		if ((wrapped && lno < fm->lno) || lno == 0) {
    349  1.1  christos 			if (wrapped) {
    350  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    351  1.1  christos 					search_msg(sp, S_NOTFOUND);
    352  1.1  christos 				break;
    353  1.1  christos 			}
    354  1.1  christos 			if (!LF_ISSET(SEARCH_WRAP)) {
    355  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    356  1.1  christos 					search_msg(sp, S_SOF);
    357  1.1  christos 				break;
    358  1.1  christos 			}
    359  1.1  christos 			if (db_last(sp, &lno))
    360  1.1  christos 				break;
    361  1.1  christos 			if (lno == 0) {
    362  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    363  1.1  christos 					search_msg(sp, S_EMPTY);
    364  1.1  christos 				break;
    365  1.1  christos 			}
    366  1.1  christos 			++lno;
    367  1.1  christos 			wrapped = 1;
    368  1.1  christos 			continue;
    369  1.1  christos 		}
    370  1.1  christos 
    371  1.1  christos 		if (db_get(sp, lno, 0, &l, &len))
    372  1.1  christos 			break;
    373  1.1  christos 
    374  1.1  christos 		/* Set the termination. */
    375  1.1  christos 		match[0].rm_so = 0;
    376  1.1  christos 		match[0].rm_eo = len;
    377  1.1  christos 
    378  1.1  christos #if defined(DEBUG) && 0
    379  1.1  christos 		vtrace(sp,
    380  1.1  christos 		    "B search: %lu from 0 to %qu\n", lno, match[0].rm_eo);
    381  1.1  christos #endif
    382  1.1  christos 		/* Search the line. */
    383  1.1  christos 		eval = regexec(&sp->re_c, l, 1, match,
    384  1.2  christos 		    ((size_t)match[0].rm_eo == len ? 0 : REG_NOTEOL) | REG_STARTEND);
    385  1.1  christos 		if (eval == REG_NOMATCH)
    386  1.1  christos 			continue;
    387  1.1  christos 		if (eval != 0) {
    388  1.1  christos 			if (LF_ISSET(SEARCH_MSG))
    389  1.1  christos 				re_error(sp, eval, &sp->re_c);
    390  1.1  christos 			else
    391  1.1  christos 				(void)sp->gp->scr_bell(sp);
    392  1.1  christos 			break;
    393  1.1  christos 		}
    394  1.1  christos 
    395  1.1  christos 		/* Check for a match starting past the cursor. */
    396  1.2  christos 		if (coff != 0 && (size_t)match[0].rm_so >= coff)
    397  1.1  christos 			continue;
    398  1.1  christos 
    399  1.1  christos 		/* Warn if the search wrapped. */
    400  1.1  christos 		if (wrapped && LF_ISSET(SEARCH_WMSG))
    401  1.1  christos 			search_msg(sp, S_WRAP);
    402  1.1  christos 
    403  1.1  christos #if defined(DEBUG) && 0
    404  1.1  christos 		vtrace(sp, "B found: %qu to %qu\n",
    405  1.1  christos 		    match[0].rm_so, match[0].rm_eo);
    406  1.1  christos #endif
    407  1.1  christos 		/*
    408  1.1  christos 		 * We now have the first match on the line.  Step through the
    409  1.1  christos 		 * line character by character until find the last acceptable
    410  1.1  christos 		 * match.  This is painful, we need a better interface to regex
    411  1.1  christos 		 * to make this work.
    412  1.1  christos 		 */
    413  1.1  christos 		for (;;) {
    414  1.1  christos 			last = match[0].rm_so++;
    415  1.2  christos 			if ((size_t)match[0].rm_so >= len)
    416  1.1  christos 				break;
    417  1.1  christos 			match[0].rm_eo = len;
    418  1.1  christos 			eval = regexec(&sp->re_c, l, 1, match,
    419  1.1  christos 			    (match[0].rm_so == 0 ? 0 : REG_NOTBOL) |
    420  1.1  christos 			    REG_STARTEND);
    421  1.1  christos 			if (eval == REG_NOMATCH)
    422  1.1  christos 				break;
    423  1.1  christos 			if (eval != 0) {
    424  1.1  christos 				if (LF_ISSET(SEARCH_MSG))
    425  1.1  christos 					re_error(sp, eval, &sp->re_c);
    426  1.1  christos 				else
    427  1.1  christos 					(void)sp->gp->scr_bell(sp);
    428  1.1  christos 				goto err;
    429  1.1  christos 			}
    430  1.2  christos 			if (coff && (size_t)match[0].rm_so >= coff)
    431  1.1  christos 				break;
    432  1.1  christos 		}
    433  1.1  christos 		rm->lno = lno;
    434  1.1  christos 
    435  1.1  christos 		/* See comment in f_search(). */
    436  1.1  christos 		if (!LF_ISSET(SEARCH_EOL) && last >= len)
    437  1.1  christos 			rm->cno = len != 0 ? len - 1 : 0;
    438  1.1  christos 		else
    439  1.1  christos 			rm->cno = last;
    440  1.1  christos 		rval = 0;
    441  1.1  christos 		break;
    442  1.1  christos 	}
    443  1.1  christos 
    444  1.1  christos err:	if (LF_ISSET(SEARCH_MSG))
    445  1.1  christos 		search_busy(sp, BUSY_OFF);
    446  1.1  christos 	return (rval);
    447  1.1  christos }
    448  1.1  christos 
    449  1.1  christos /*
    450  1.1  christos  * search_msg --
    451  1.1  christos  *	Display one of the search messages.
    452  1.1  christos  */
    453  1.1  christos static void
    454  1.1  christos search_msg(SCR *sp, smsg_t msg)
    455  1.1  christos {
    456  1.1  christos 	switch (msg) {
    457  1.1  christos 	case S_EMPTY:
    458  1.1  christos 		msgq(sp, M_ERR, "072|File empty; nothing to search");
    459  1.1  christos 		break;
    460  1.1  christos 	case S_EOF:
    461  1.1  christos 		msgq(sp, M_ERR,
    462  1.1  christos 		    "073|Reached end-of-file without finding the pattern");
    463  1.1  christos 		break;
    464  1.1  christos 	case S_NOPREV:
    465  1.1  christos 		msgq(sp, M_ERR, "074|No previous search pattern");
    466  1.1  christos 		break;
    467  1.1  christos 	case S_NOTFOUND:
    468  1.1  christos 		msgq(sp, M_ERR, "075|Pattern not found");
    469  1.1  christos 		break;
    470  1.1  christos 	case S_SOF:
    471  1.1  christos 		msgq(sp, M_ERR,
    472  1.1  christos 		    "076|Reached top-of-file without finding the pattern");
    473  1.1  christos 		break;
    474  1.1  christos 	case S_WRAP:
    475  1.1  christos 		msgq(sp, M_ERR, "077|Search wrapped");
    476  1.1  christos 		break;
    477  1.1  christos 	default:
    478  1.1  christos 		abort();
    479  1.1  christos 	}
    480  1.1  christos }
    481  1.1  christos 
    482  1.1  christos /*
    483  1.1  christos  * search_busy --
    484  1.1  christos  *	Put up the busy searching message.
    485  1.1  christos  *
    486  1.1  christos  * PUBLIC: void search_busy __P((SCR *, busy_t));
    487  1.1  christos  */
    488  1.1  christos void
    489  1.1  christos search_busy(SCR *sp, busy_t btype)
    490  1.1  christos {
    491  1.1  christos 	sp->gp->scr_busy(sp, "078|Searching...", btype);
    492  1.1  christos }
    493