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