Home | History | Annotate | Line # | Download | only in more
prim.c revision 1.3
      1 /*	$NetBSD: prim.c,v 1.3 1998/01/09 08:03:35 perry Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 Mark Nudleman
      5  * Copyright (c) 1988, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 static char sccsid[] = "@(#)prim.c	8.1 (Berkeley) 6/6/93";
     39 #endif /* not lint */
     40 
     41 /*
     42  * Primitives for displaying the file on the screen.
     43  */
     44 
     45 #include <sys/types.h>
     46 #include <stdio.h>
     47 #include <ctype.h>
     48 #include <less.h>
     49 
     50 int back_scroll = -1;
     51 int hit_eof;		/* keeps track of how many times we hit end of file */
     52 int screen_trashed;
     53 
     54 static int squished;
     55 
     56 extern int sigs;
     57 extern int top_scroll;
     58 extern int sc_width, sc_height;
     59 extern int caseless;
     60 extern int linenums;
     61 extern char *line;
     62 extern int retain_below;
     63 
     64 off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line();
     65 off_t ch_length(), ch_tell();
     66 
     67 static match(char *, char *);
     68 
     69 /*
     70  * Check to see if the end of file is currently "displayed".
     71  */
     72 eof_check()
     73 {
     74 	off_t pos;
     75 
     76 	if (sigs)
     77 		return;
     78 	/*
     79 	 * If the bottom line is empty, we are at EOF.
     80 	 * If the bottom line ends at the file length,
     81 	 * we must be just at EOF.
     82 	 */
     83 	pos = position(BOTTOM_PLUS_ONE);
     84 	if (pos == NULL_POSITION || pos == ch_length())
     85 		hit_eof++;
     86 }
     87 
     88 /*
     89  * If the screen is "squished", repaint it.
     90  * "Squished" means the first displayed line is not at the top
     91  * of the screen; this can happen when we display a short file
     92  * for the first time.
     93  */
     94 squish_check()
     95 {
     96 	if (squished) {
     97 		squished = 0;
     98 		repaint();
     99 	}
    100 }
    101 
    102 /*
    103  * Display n lines, scrolling forward, starting at position pos in the
    104  * input file.  "only_last" means display only the last screenful if
    105  * n > screen size.
    106  */
    107 forw(n, pos, only_last)
    108 	register int n;
    109 	off_t pos;
    110 	int only_last;
    111 {
    112 	extern int short_file;
    113 	static int first_time = 1;
    114 	int eof = 0, do_repaint;
    115 
    116 	squish_check();
    117 
    118 	/*
    119 	 * do_repaint tells us not to display anything till the end,
    120 	 * then just repaint the entire screen.
    121 	 */
    122 	do_repaint = (only_last && n > sc_height-1);
    123 
    124 	if (!do_repaint) {
    125 		if (top_scroll && n >= sc_height - 1) {
    126 			/*
    127 			 * Start a new screen.
    128 			 * {{ This is not really desirable if we happen
    129 			 *    to hit eof in the middle of this screen,
    130 			 *    but we don't yet know if that will happen. }}
    131 			 */
    132 			clear();
    133 			home();
    134 		} else {
    135 			lower_left();
    136 			clear_eol();
    137 		}
    138 
    139 		/*
    140 		 * This is not contiguous with what is currently displayed.
    141 		 * Clear the screen image (position table) and start a new
    142 		 * screen.
    143 		 */
    144 		if (pos != position(BOTTOM_PLUS_ONE)) {
    145 			pos_clear();
    146 			add_forw_pos(pos);
    147 			if (top_scroll) {
    148 				clear();
    149 				home();
    150 			} else if (!first_time)
    151 				putstr("...skipping...\n");
    152 		}
    153 	}
    154 
    155 	for (short_file = 0; --n >= 0;) {
    156 		/*
    157 		 * Read the next line of input.
    158 		 */
    159 		pos = forw_line(pos);
    160 		if (pos == NULL_POSITION) {
    161 			/*
    162 			 * end of file; copy the table if the file was
    163 			 * too small for an entire screen.
    164 			 */
    165 			eof = 1;
    166 			if (position(TOP) == NULL_POSITION) {
    167 				copytable();
    168 				if (!position(TOP))
    169 					short_file = 1;
    170 			}
    171 			break;
    172 		}
    173 		/*
    174 		 * Add the position of the next line to the position table.
    175 		 * Display the current line on the screen.
    176 		 */
    177 		add_forw_pos(pos);
    178 		if (do_repaint)
    179 			continue;
    180 		/*
    181 		 * If this is the first screen displayed and we hit an early
    182 		 * EOF (i.e. before the requested number of lines), we
    183 		 * "squish" the display down at the bottom of the screen.
    184 		 */
    185 		if (first_time && line == NULL && !top_scroll) {
    186 			squished = 1;
    187 			continue;
    188 		}
    189 		put_line();
    190 	}
    191 
    192 	if (eof && !sigs)
    193 		hit_eof++;
    194 	else
    195 		eof_check();
    196 	if (do_repaint)
    197 		repaint();
    198 	first_time = 0;
    199 	(void) currline(BOTTOM);
    200 }
    201 
    202 /*
    203  * Display n lines, scrolling backward.
    204  */
    205 back(n, pos, only_last)
    206 	register int n;
    207 	off_t pos;
    208 	int only_last;
    209 {
    210 	int do_repaint;
    211 
    212 	squish_check();
    213 	do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
    214 	hit_eof = 0;
    215 	while (--n >= 0)
    216 	{
    217 		/*
    218 		 * Get the previous line of input.
    219 		 */
    220 		pos = back_line(pos);
    221 		if (pos == NULL_POSITION)
    222 			break;
    223 		/*
    224 		 * Add the position of the previous line to the position table.
    225 		 * Display the line on the screen.
    226 		 */
    227 		add_back_pos(pos);
    228 		if (!do_repaint)
    229 		{
    230 			if (retain_below)
    231 			{
    232 				lower_left();
    233 				clear_eol();
    234 			}
    235 			home();
    236 			add_line();
    237 			put_line();
    238 		}
    239 	}
    240 
    241 	eof_check();
    242 	if (do_repaint)
    243 		repaint();
    244 	(void) currline(BOTTOM);
    245 }
    246 
    247 /*
    248  * Display n more lines, forward.
    249  * Start just after the line currently displayed at the bottom of the screen.
    250  */
    251 forward(n, only_last)
    252 	int n;
    253 	int only_last;
    254 {
    255 	off_t pos;
    256 
    257 	if (hit_eof) {
    258 		/*
    259 		 * If we're trying to go forward from end-of-file,
    260 		 * go on to the next file.
    261 		 */
    262 		next_file(1);
    263 		return;
    264 	}
    265 
    266 	pos = position(BOTTOM_PLUS_ONE);
    267 	if (pos == NULL_POSITION)
    268 	{
    269 		hit_eof++;
    270 		return;
    271 	}
    272 	forw(n, pos, only_last);
    273 }
    274 
    275 /*
    276  * Display n more lines, backward.
    277  * Start just before the line currently displayed at the top of the screen.
    278  */
    279 backward(n, only_last)
    280 	int n;
    281 	int only_last;
    282 {
    283 	off_t pos;
    284 
    285 	pos = position(TOP);
    286 	/*
    287 	 * This will almost never happen, because the top line is almost
    288 	 * never empty.
    289 	 */
    290 	if (pos == NULL_POSITION)
    291 		return;
    292 	back(n, pos, only_last);
    293 }
    294 
    295 /*
    296  * Repaint the screen, starting from a specified position.
    297  */
    298 prepaint(pos)
    299 	off_t pos;
    300 {
    301 	hit_eof = 0;
    302 	forw(sc_height-1, pos, 0);
    303 	screen_trashed = 0;
    304 }
    305 
    306 /*
    307  * Repaint the screen.
    308  */
    309 repaint()
    310 {
    311 	/*
    312 	 * Start at the line currently at the top of the screen
    313 	 * and redisplay the screen.
    314 	 */
    315 	prepaint(position(TOP));
    316 }
    317 
    318 /*
    319  * Jump to the end of the file.
    320  * It is more convenient to paint the screen backward,
    321  * from the end of the file toward the beginning.
    322  */
    323 jump_forw()
    324 {
    325 	off_t pos;
    326 
    327 	if (ch_end_seek())
    328 	{
    329 		error("Cannot seek to end of file");
    330 		return;
    331 	}
    332 	lastmark();
    333 	pos = ch_tell();
    334 	clear();
    335 	pos_clear();
    336 	add_back_pos(pos);
    337 	back(sc_height - 1, pos, 0);
    338 }
    339 
    340 /*
    341  * Jump to line n in the file.
    342  */
    343 jump_back(n)
    344 	register int n;
    345 {
    346 	register int c, nlines;
    347 
    348 	/*
    349 	 * This is done the slow way, by starting at the beginning
    350 	 * of the file and counting newlines.
    351 	 *
    352 	 * {{ Now that we have line numbering (in linenum.c),
    353 	 *    we could improve on this by starting at the
    354 	 *    nearest known line rather than at the beginning. }}
    355 	 */
    356 	if (ch_seek((off_t)0)) {
    357 		/*
    358 		 * Probably a pipe with beginning of file no longer buffered.
    359 		 * If he wants to go to line 1, we do the best we can,
    360 		 * by going to the first line which is still buffered.
    361 		 */
    362 		if (n <= 1 && ch_beg_seek() == 0)
    363 			jump_loc(ch_tell());
    364 		error("Cannot get to beginning of file");
    365 		return;
    366 	}
    367 
    368 	/*
    369 	 * Start counting lines.
    370 	 */
    371 	for (nlines = 1;  nlines < n;  nlines++)
    372 		while ((c = ch_forw_get()) != '\n')
    373 			if (c == EOI) {
    374 				char message[40];
    375 				(void)sprintf(message, "File has only %d lines",
    376 				    nlines - 1);
    377 				error(message);
    378 				return;
    379 			}
    380 	jump_loc(ch_tell());
    381 }
    382 
    383 /*
    384  * Jump to a specified percentage into the file.
    385  * This is a poor compensation for not being able to
    386  * quickly jump to a specific line number.
    387  */
    388 jump_percent(percent)
    389 	int percent;
    390 {
    391 	off_t pos, len, ch_length();
    392 	register int c;
    393 
    394 	/*
    395 	 * Determine the position in the file
    396 	 * (the specified percentage of the file's length).
    397 	 */
    398 	if ((len = ch_length()) == NULL_POSITION)
    399 	{
    400 		error("Don't know length of file");
    401 		return;
    402 	}
    403 	pos = (percent * len) / 100;
    404 
    405 	/*
    406 	 * Back up to the beginning of the line.
    407 	 */
    408 	if (ch_seek(pos) == 0)
    409 	{
    410 		while ((c = ch_back_get()) != '\n' && c != EOI)
    411 			;
    412 		if (c == '\n')
    413 			(void) ch_forw_get();
    414 		pos = ch_tell();
    415 	}
    416 	jump_loc(pos);
    417 }
    418 
    419 /*
    420  * Jump to a specified position in the file.
    421  */
    422 jump_loc(pos)
    423 	off_t pos;
    424 {
    425 	register int nline;
    426 	off_t tpos;
    427 
    428 	if ((nline = onscreen(pos)) >= 0) {
    429 		/*
    430 		 * The line is currently displayed.
    431 		 * Just scroll there.
    432 		 */
    433 		forw(nline, position(BOTTOM_PLUS_ONE), 0);
    434 		return;
    435 	}
    436 
    437 	/*
    438 	 * Line is not on screen.
    439 	 * Seek to the desired location.
    440 	 */
    441 	if (ch_seek(pos)) {
    442 		error("Cannot seek to that position");
    443 		return;
    444 	}
    445 
    446 	/*
    447 	 * See if the desired line is BEFORE the currently displayed screen.
    448 	 * If so, then move forward far enough so the line we're on will be
    449 	 * at the bottom of the screen, in order to be able to call back()
    450 	 * to make the screen scroll backwards & put the line at the top of
    451 	 * the screen.
    452 	 * {{ This seems inefficient, but it's not so bad,
    453 	 *    since we can never move forward more than a
    454 	 *    screenful before we stop to redraw the screen. }}
    455 	 */
    456 	tpos = position(TOP);
    457 	if (tpos != NULL_POSITION && pos < tpos) {
    458 		off_t npos = pos;
    459 		/*
    460 		 * Note that we can't forw_line() past tpos here,
    461 		 * so there should be no EOI at this stage.
    462 		 */
    463 		for (nline = 0;  npos < tpos && nline < sc_height - 1;  nline++)
    464 			npos = forw_line(npos);
    465 
    466 		if (npos < tpos) {
    467 			/*
    468 			 * More than a screenful back.
    469 			 */
    470 			lastmark();
    471 			clear();
    472 			pos_clear();
    473 			add_back_pos(npos);
    474 		}
    475 
    476 		/*
    477 		 * Note that back() will repaint() if nline > back_scroll.
    478 		 */
    479 		back(nline, npos, 0);
    480 		return;
    481 	}
    482 	/*
    483 	 * Remember where we were; clear and paint the screen.
    484 	 */
    485 	lastmark();
    486 	prepaint(pos);
    487 }
    488 
    489 /*
    490  * The table of marks.
    491  * A mark is simply a position in the file.
    492  */
    493 #define	NMARKS		(27)		/* 26 for a-z plus one for quote */
    494 #define	LASTMARK	(NMARKS-1)	/* For quote */
    495 static off_t marks[NMARKS];
    496 
    497 /*
    498  * Initialize the mark table to show no marks are set.
    499  */
    500 init_mark()
    501 {
    502 	int i;
    503 
    504 	for (i = 0;  i < NMARKS;  i++)
    505 		marks[i] = NULL_POSITION;
    506 }
    507 
    508 /*
    509  * See if a mark letter is valid (between a and z).
    510  */
    511 	static int
    512 badmark(c)
    513 	int c;
    514 {
    515 	if (c < 'a' || c > 'z')
    516 	{
    517 		error("Choose a letter between 'a' and 'z'");
    518 		return (1);
    519 	}
    520 	return (0);
    521 }
    522 
    523 /*
    524  * Set a mark.
    525  */
    526 setmark(c)
    527 	int c;
    528 {
    529 	if (badmark(c))
    530 		return;
    531 	marks[c-'a'] = position(TOP);
    532 }
    533 
    534 lastmark()
    535 {
    536 	marks[LASTMARK] = position(TOP);
    537 }
    538 
    539 /*
    540  * Go to a previously set mark.
    541  */
    542 gomark(c)
    543 	int c;
    544 {
    545 	off_t pos;
    546 
    547 	if (c == '\'') {
    548 		pos = marks[LASTMARK];
    549 		if (pos == NULL_POSITION)
    550 			pos = 0;
    551 	}
    552 	else {
    553 		if (badmark(c))
    554 			return;
    555 		pos = marks[c-'a'];
    556 		if (pos == NULL_POSITION) {
    557 			error("mark not set");
    558 			return;
    559 		}
    560 	}
    561 	jump_loc(pos);
    562 }
    563 
    564 /*
    565  * Get the backwards scroll limit.
    566  * Must call this function instead of just using the value of
    567  * back_scroll, because the default case depends on sc_height and
    568  * top_scroll, as well as back_scroll.
    569  */
    570 get_back_scroll()
    571 {
    572 	if (back_scroll >= 0)
    573 		return (back_scroll);
    574 	if (top_scroll)
    575 		return (sc_height - 2);
    576 	return (sc_height - 1);
    577 }
    578 
    579 /*
    580  * Search for the n-th occurence of a specified pattern,
    581  * either forward or backward.
    582  */
    583 search(search_forward, pattern, n, wantmatch)
    584 	register int search_forward;
    585 	register char *pattern;
    586 	register int n;
    587 	int wantmatch;
    588 {
    589 	off_t pos, linepos;
    590 	register char *p;
    591 	register char *q;
    592 	int linenum;
    593 	int linematch;
    594 #ifdef RECOMP
    595 	char *re_comp();
    596 	char *errmsg;
    597 #else
    598 #ifdef REGCMP
    599 	char *regcmp();
    600 	static char *cpattern = NULL;
    601 #else
    602 	static char lpbuf[100];
    603 	static char *last_pattern = NULL;
    604 	char *strcpy();
    605 #endif
    606 #endif
    607 
    608 	/*
    609 	 * For a caseless search, convert any uppercase in the pattern to
    610 	 * lowercase.
    611 	 */
    612 	if (caseless && pattern != NULL)
    613 		for (p = pattern;  *p;  p++)
    614 			if (isupper(*p))
    615 				*p = tolower(*p);
    616 #ifdef RECOMP
    617 
    618 	/*
    619 	 * (re_comp handles a null pattern internally,
    620 	 *  so there is no need to check for a null pattern here.)
    621 	 */
    622 	if ((errmsg = re_comp(pattern)) != NULL)
    623 	{
    624 		error(errmsg);
    625 		return(0);
    626 	}
    627 #else
    628 #ifdef REGCMP
    629 	if (pattern == NULL || *pattern == '\0')
    630 	{
    631 		/*
    632 		 * A null pattern means use the previous pattern.
    633 		 * The compiled previous pattern is in cpattern, so just use it.
    634 		 */
    635 		if (cpattern == NULL)
    636 		{
    637 			error("No previous regular expression");
    638 			return(0);
    639 		}
    640 	} else
    641 	{
    642 		/*
    643 		 * Otherwise compile the given pattern.
    644 		 */
    645 		char *s;
    646 		if ((s = regcmp(pattern, 0)) == NULL)
    647 		{
    648 			error("Invalid pattern");
    649 			return(0);
    650 		}
    651 		if (cpattern != NULL)
    652 			free(cpattern);
    653 		cpattern = s;
    654 	}
    655 #else
    656 	if (pattern == NULL || *pattern == '\0')
    657 	{
    658 		/*
    659 		 * Null pattern means use the previous pattern.
    660 		 */
    661 		if (last_pattern == NULL)
    662 		{
    663 			error("No previous regular expression");
    664 			return(0);
    665 		}
    666 		pattern = last_pattern;
    667 	} else
    668 	{
    669 		(void)strcpy(lpbuf, pattern);
    670 		last_pattern = lpbuf;
    671 	}
    672 #endif
    673 #endif
    674 
    675 	/*
    676 	 * Figure out where to start the search.
    677 	 */
    678 
    679 	if (position(TOP) == NULL_POSITION) {
    680 		/*
    681 		 * Nothing is currently displayed.  Start at the beginning
    682 		 * of the file.  (This case is mainly for searches from the
    683 		 * command line.
    684 		 */
    685 		pos = (off_t)0;
    686 	} else if (!search_forward) {
    687 		/*
    688 		 * Backward search: start just before the top line
    689 		 * displayed on the screen.
    690 		 */
    691 		pos = position(TOP);
    692 	} else {
    693 		/*
    694 		 * Start at the second screen line displayed on the screen.
    695 		 */
    696 		pos = position(TOP_PLUS_ONE);
    697 	}
    698 
    699 	if (pos == NULL_POSITION)
    700 	{
    701 		/*
    702 		 * Can't find anyplace to start searching from.
    703 		 */
    704 		error("Nothing to search");
    705 		return(0);
    706 	}
    707 
    708 	linenum = find_linenum(pos);
    709 	for (;;)
    710 	{
    711 		/*
    712 		 * Get lines until we find a matching one or
    713 		 * until we hit end-of-file (or beginning-of-file
    714 		 * if we're going backwards).
    715 		 */
    716 		if (sigs)
    717 			/*
    718 			 * A signal aborts the search.
    719 			 */
    720 			return(0);
    721 
    722 		if (search_forward)
    723 		{
    724 			/*
    725 			 * Read the next line, and save the
    726 			 * starting position of that line in linepos.
    727 			 */
    728 			linepos = pos;
    729 			pos = forw_raw_line(pos);
    730 			if (linenum != 0)
    731 				linenum++;
    732 		} else
    733 		{
    734 			/*
    735 			 * Read the previous line and save the
    736 			 * starting position of that line in linepos.
    737 			 */
    738 			pos = back_raw_line(pos);
    739 			linepos = pos;
    740 			if (linenum != 0)
    741 				linenum--;
    742 		}
    743 
    744 		if (pos == NULL_POSITION)
    745 		{
    746 			/*
    747 			 * We hit EOF/BOF without a match.
    748 			 */
    749 			error("Pattern not found");
    750 			return(0);
    751 		}
    752 
    753 		/*
    754 		 * If we're using line numbers, we might as well
    755 		 * remember the information we have now (the position
    756 		 * and line number of the current line).
    757 		 */
    758 		if (linenums)
    759 			add_lnum(linenum, pos);
    760 
    761 		/*
    762 		 * If this is a caseless search, convert uppercase in the
    763 		 * input line to lowercase.
    764 		 */
    765 		if (caseless)
    766 			for (p = q = line;  *p;  p++, q++)
    767 				*q = isupper(*p) ? tolower(*p) : *p;
    768 
    769 		/*
    770 		 * Remove any backspaces along with the preceeding char.
    771 		 * This allows us to match text which is underlined or
    772 		 * overstruck.
    773 		 */
    774 		for (p = q = line;  *p;  p++, q++)
    775 			if (q > line && *p == '\b')
    776 				/* Delete BS and preceeding char. */
    777 				q -= 2;
    778 			else
    779 				/* Otherwise, just copy. */
    780 				*q = *p;
    781 
    782 		/*
    783 		 * Test the next line to see if we have a match.
    784 		 * This is done in a variety of ways, depending
    785 		 * on what pattern matching functions are available.
    786 		 */
    787 #ifdef REGCMP
    788 		linematch = (regex(cpattern, line) != NULL);
    789 #else
    790 #ifdef RECOMP
    791 		linematch = (re_exec(line) == 1);
    792 #else
    793 		linematch = match(pattern, line);
    794 #endif
    795 #endif
    796 		/*
    797 		 * We are successful if wantmatch and linematch are
    798 		 * both true (want a match and got it),
    799 		 * or both false (want a non-match and got it).
    800 		 */
    801 		if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
    802 		      --n <= 0)
    803 			/*
    804 			 * Found the line.
    805 			 */
    806 			break;
    807 	}
    808 	jump_loc(linepos);
    809 	return(1);
    810 }
    811 
    812 #if !defined(REGCMP) && !defined(RECOMP)
    813 /*
    814  * We have neither regcmp() nor re_comp().
    815  * We use this function to do simple pattern matching.
    816  * It supports no metacharacters like *, etc.
    817  */
    818 static
    819 match(pattern, buf)
    820 	char *pattern, *buf;
    821 {
    822 	register char *pp, *lp;
    823 
    824 	for ( ;  *buf != '\0';  buf++)
    825 	{
    826 		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
    827 			if (*pp == '\0' || *lp == '\0')
    828 				break;
    829 		if (*pp == '\0')
    830 			return (1);
    831 	}
    832 	return (0);
    833 }
    834 #endif
    835