135209Sbostic /*
235209Sbostic * Copyright (c) 1988 Mark Nudleman
3*62131Sbostic * Copyright (c) 1988, 1993
4*62131Sbostic * The Regents of the University of California. All rights reserved.
535209Sbostic *
642742Sbostic * %sccs.include.redist.c%
735209Sbostic */
835209Sbostic
935209Sbostic #ifndef lint
10*62131Sbostic static char sccsid[] = "@(#)prim.c 8.1 (Berkeley) 06/06/93";
1135209Sbostic #endif /* not lint */
1235209Sbostic
1335209Sbostic /*
1435209Sbostic * Primitives for displaying the file on the screen.
1535209Sbostic */
1635209Sbostic
1736253Sbostic #include <sys/types.h>
1836253Sbostic #include <stdio.h>
1936253Sbostic #include <ctype.h>
2036253Sbostic #include <less.h>
2135209Sbostic
2236253Sbostic int back_scroll = -1;
2336253Sbostic int hit_eof; /* keeps track of how many times we hit end of file */
2436253Sbostic int screen_trashed;
2535209Sbostic
2635209Sbostic static int squished;
2735209Sbostic
2835209Sbostic extern int sigs;
2935209Sbostic extern int top_scroll;
3035209Sbostic extern int sc_width, sc_height;
3135209Sbostic extern int caseless;
3235209Sbostic extern int linenums;
3336253Sbostic extern int tagoption;
3435209Sbostic extern char *line;
3557940Sedward extern int retain_below;
3635209Sbostic
3736253Sbostic off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line();
3836253Sbostic off_t ch_length(), ch_tell();
3935209Sbostic
4035209Sbostic /*
4135209Sbostic * Check to see if the end of file is currently "displayed".
4235209Sbostic */
eof_check()4335209Sbostic eof_check()
4435209Sbostic {
4536253Sbostic off_t pos;
4635209Sbostic
4735209Sbostic if (sigs)
4835209Sbostic return;
4935209Sbostic /*
5035209Sbostic * If the bottom line is empty, we are at EOF.
5135209Sbostic * If the bottom line ends at the file length,
5235209Sbostic * we must be just at EOF.
5335209Sbostic */
5435209Sbostic pos = position(BOTTOM_PLUS_ONE);
5535209Sbostic if (pos == NULL_POSITION || pos == ch_length())
5635209Sbostic hit_eof++;
5735209Sbostic }
5835209Sbostic
5935209Sbostic /*
6035209Sbostic * If the screen is "squished", repaint it.
6135209Sbostic * "Squished" means the first displayed line is not at the top
6235209Sbostic * of the screen; this can happen when we display a short file
6335209Sbostic * for the first time.
6435209Sbostic */
squish_check()6535209Sbostic squish_check()
6635209Sbostic {
6736253Sbostic if (squished) {
6836253Sbostic squished = 0;
6936253Sbostic repaint();
7036253Sbostic }
7135209Sbostic }
7235209Sbostic
7335209Sbostic /*
7436253Sbostic * Display n lines, scrolling forward, starting at position pos in the
7536358Sbostic * input file. "only_last" means display only the last screenful if
7636358Sbostic * n > screen size.
7735209Sbostic */
forw(n,pos,only_last)7836358Sbostic forw(n, pos, only_last)
7935209Sbostic register int n;
8036253Sbostic off_t pos;
8135209Sbostic int only_last;
8235209Sbostic {
8336358Sbostic extern int short_file;
8435209Sbostic static int first_time = 1;
8536253Sbostic int eof = 0, do_repaint;
8635209Sbostic
8735209Sbostic squish_check();
8835209Sbostic
8935209Sbostic /*
9035209Sbostic * do_repaint tells us not to display anything till the end,
9135209Sbostic * then just repaint the entire screen.
9235209Sbostic */
9335209Sbostic do_repaint = (only_last && n > sc_height-1);
9435209Sbostic
9536253Sbostic if (!do_repaint) {
9636253Sbostic if (top_scroll && n >= sc_height - 1) {
9735209Sbostic /*
9835209Sbostic * Start a new screen.
9935209Sbostic * {{ This is not really desirable if we happen
10035209Sbostic * to hit eof in the middle of this screen,
10135209Sbostic * but we don't yet know if that will happen. }}
10235209Sbostic */
10336253Sbostic clear();
10435209Sbostic home();
10536253Sbostic } else {
10635209Sbostic lower_left();
10735209Sbostic clear_eol();
10835209Sbostic }
10935209Sbostic
11036253Sbostic /*
11136253Sbostic * This is not contiguous with what is currently displayed.
11236253Sbostic * Clear the screen image (position table) and start a new
11336253Sbostic * screen.
11436253Sbostic */
11536253Sbostic if (pos != position(BOTTOM_PLUS_ONE)) {
11635209Sbostic pos_clear();
11735209Sbostic add_forw_pos(pos);
11836253Sbostic if (top_scroll) {
11936253Sbostic clear();
12035209Sbostic home();
12135209Sbostic } else if (!first_time)
12235209Sbostic putstr("...skipping...\n");
12335209Sbostic }
12435209Sbostic }
12535209Sbostic
12636358Sbostic for (short_file = 0; --n >= 0;) {
12735209Sbostic /*
12835209Sbostic * Read the next line of input.
12935209Sbostic */
13035209Sbostic pos = forw_line(pos);
13136253Sbostic if (pos == NULL_POSITION) {
13235209Sbostic /*
13336358Sbostic * end of file; copy the table if the file was
13436358Sbostic * too small for an entire screen.
13535209Sbostic */
13635209Sbostic eof = 1;
13736358Sbostic if (position(TOP) == NULL_POSITION) {
13836358Sbostic copytable();
13936358Sbostic if (!position(TOP))
14036358Sbostic short_file = 1;
14136358Sbostic }
14236358Sbostic break;
14335209Sbostic }
14435209Sbostic /*
14535209Sbostic * Add the position of the next line to the position table.
14635209Sbostic * Display the current line on the screen.
14735209Sbostic */
14835209Sbostic add_forw_pos(pos);
14935209Sbostic if (do_repaint)
15035209Sbostic continue;
15135209Sbostic /*
15236253Sbostic * If this is the first screen displayed and we hit an early
15336253Sbostic * EOF (i.e. before the requested number of lines), we
15436253Sbostic * "squish" the display down at the bottom of the screen.
15536253Sbostic * But don't do this if a -t option was given; it can cause
15636253Sbostic * us to start the display after the beginning of the file,
15735209Sbostic * and it is not appropriate to squish in that case.
15835209Sbostic */
15936253Sbostic if (first_time && line == NULL && !top_scroll && !tagoption) {
16035209Sbostic squished = 1;
16135209Sbostic continue;
16235209Sbostic }
16335209Sbostic put_line();
16435209Sbostic }
16535209Sbostic
16635209Sbostic if (eof && !sigs)
16735209Sbostic hit_eof++;
16835209Sbostic else
16935209Sbostic eof_check();
17036253Sbostic if (do_repaint)
17135209Sbostic repaint();
17235209Sbostic first_time = 0;
17335209Sbostic (void) currline(BOTTOM);
17435209Sbostic }
17535209Sbostic
17635209Sbostic /*
17735209Sbostic * Display n lines, scrolling backward.
17835209Sbostic */
back(n,pos,only_last)17936358Sbostic back(n, pos, only_last)
18035209Sbostic register int n;
18136253Sbostic off_t pos;
18235209Sbostic int only_last;
18335209Sbostic {
18435209Sbostic int do_repaint;
18535209Sbostic
18635209Sbostic squish_check();
18735209Sbostic do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
18835209Sbostic hit_eof = 0;
18935209Sbostic while (--n >= 0)
19035209Sbostic {
19135209Sbostic /*
19235209Sbostic * Get the previous line of input.
19335209Sbostic */
19435209Sbostic pos = back_line(pos);
19535209Sbostic if (pos == NULL_POSITION)
19636358Sbostic break;
19735209Sbostic /*
19835209Sbostic * Add the position of the previous line to the position table.
19935209Sbostic * Display the line on the screen.
20035209Sbostic */
20135209Sbostic add_back_pos(pos);
20235209Sbostic if (!do_repaint)
20335209Sbostic {
20457940Sedward if (retain_below)
20557940Sedward {
20657940Sedward lower_left();
20757940Sedward clear_eol();
20857940Sedward }
20935209Sbostic home();
21035209Sbostic add_line();
21135209Sbostic put_line();
21235209Sbostic }
21335209Sbostic }
21435209Sbostic
21535209Sbostic eof_check();
21636253Sbostic if (do_repaint)
21735209Sbostic repaint();
21835209Sbostic (void) currline(BOTTOM);
21935209Sbostic }
22035209Sbostic
22135209Sbostic /*
22235209Sbostic * Display n more lines, forward.
22335209Sbostic * Start just after the line currently displayed at the bottom of the screen.
22435209Sbostic */
forward(n,only_last)22535209Sbostic forward(n, only_last)
22635209Sbostic int n;
22735209Sbostic int only_last;
22835209Sbostic {
22936253Sbostic off_t pos;
23035209Sbostic
23136253Sbostic if (hit_eof) {
23235209Sbostic /*
23336253Sbostic * If we're trying to go forward from end-of-file,
23436253Sbostic * go on to the next file.
23535209Sbostic */
23635209Sbostic next_file(1);
23735209Sbostic return;
23835209Sbostic }
23935209Sbostic
24035209Sbostic pos = position(BOTTOM_PLUS_ONE);
24135209Sbostic if (pos == NULL_POSITION)
24235209Sbostic {
24335209Sbostic hit_eof++;
24435209Sbostic return;
24535209Sbostic }
24636358Sbostic forw(n, pos, only_last);
24735209Sbostic }
24835209Sbostic
24935209Sbostic /*
25035209Sbostic * Display n more lines, backward.
25135209Sbostic * Start just before the line currently displayed at the top of the screen.
25235209Sbostic */
backward(n,only_last)25335209Sbostic backward(n, only_last)
25435209Sbostic int n;
25535209Sbostic int only_last;
25635209Sbostic {
25736253Sbostic off_t pos;
25835209Sbostic
25935209Sbostic pos = position(TOP);
26036253Sbostic /*
26136253Sbostic * This will almost never happen, because the top line is almost
26236253Sbostic * never empty.
26336253Sbostic */
26435209Sbostic if (pos == NULL_POSITION)
26535209Sbostic return;
26636358Sbostic back(n, pos, only_last);
26735209Sbostic }
26835209Sbostic
26935209Sbostic /*
27035209Sbostic * Repaint the screen, starting from a specified position.
27135209Sbostic */
prepaint(pos)27236253Sbostic prepaint(pos)
27336253Sbostic off_t pos;
27435209Sbostic {
27535209Sbostic hit_eof = 0;
27636358Sbostic forw(sc_height-1, pos, 0);
27735209Sbostic screen_trashed = 0;
27835209Sbostic }
27935209Sbostic
28035209Sbostic /*
28135209Sbostic * Repaint the screen.
28235209Sbostic */
repaint()28335209Sbostic repaint()
28435209Sbostic {
28535209Sbostic /*
28635209Sbostic * Start at the line currently at the top of the screen
28735209Sbostic * and redisplay the screen.
28835209Sbostic */
28935209Sbostic prepaint(position(TOP));
29035209Sbostic }
29135209Sbostic
29235209Sbostic /*
29335209Sbostic * Jump to the end of the file.
29435209Sbostic * It is more convenient to paint the screen backward,
29535209Sbostic * from the end of the file toward the beginning.
29635209Sbostic */
jump_forw()29735209Sbostic jump_forw()
29835209Sbostic {
29936253Sbostic off_t pos;
30035209Sbostic
30135209Sbostic if (ch_end_seek())
30235209Sbostic {
30335209Sbostic error("Cannot seek to end of file");
30435209Sbostic return;
30535209Sbostic }
30635209Sbostic lastmark();
30735209Sbostic pos = ch_tell();
30835209Sbostic clear();
30935209Sbostic pos_clear();
31035209Sbostic add_back_pos(pos);
31136358Sbostic back(sc_height - 1, pos, 0);
31235209Sbostic }
31335209Sbostic
31435209Sbostic /*
31535209Sbostic * Jump to line n in the file.
31635209Sbostic */
jump_back(n)31735209Sbostic jump_back(n)
31835209Sbostic register int n;
31935209Sbostic {
32036253Sbostic register int c, nlines;
32135209Sbostic
32235209Sbostic /*
32335209Sbostic * This is done the slow way, by starting at the beginning
32435209Sbostic * of the file and counting newlines.
32535209Sbostic *
32635209Sbostic * {{ Now that we have line numbering (in linenum.c),
32735209Sbostic * we could improve on this by starting at the
32835209Sbostic * nearest known line rather than at the beginning. }}
32935209Sbostic */
33036253Sbostic if (ch_seek((off_t)0)) {
33135209Sbostic /*
33235209Sbostic * Probably a pipe with beginning of file no longer buffered.
33335209Sbostic * If he wants to go to line 1, we do the best we can,
33435209Sbostic * by going to the first line which is still buffered.
33535209Sbostic */
33635209Sbostic if (n <= 1 && ch_beg_seek() == 0)
33735209Sbostic jump_loc(ch_tell());
33835209Sbostic error("Cannot get to beginning of file");
33935209Sbostic return;
34035209Sbostic }
34135209Sbostic
34235209Sbostic /*
34335209Sbostic * Start counting lines.
34435209Sbostic */
34535209Sbostic for (nlines = 1; nlines < n; nlines++)
34635209Sbostic while ((c = ch_forw_get()) != '\n')
34736253Sbostic if (c == EOI) {
34835209Sbostic char message[40];
34935242Sbostic (void)sprintf(message, "File has only %d lines",
35036253Sbostic nlines - 1);
35135209Sbostic error(message);
35235209Sbostic return;
35335209Sbostic }
35435209Sbostic jump_loc(ch_tell());
35535209Sbostic }
35635209Sbostic
35735209Sbostic /*
35835209Sbostic * Jump to a specified percentage into the file.
35935209Sbostic * This is a poor compensation for not being able to
36035209Sbostic * quickly jump to a specific line number.
36135209Sbostic */
jump_percent(percent)36235209Sbostic jump_percent(percent)
36335209Sbostic int percent;
36435209Sbostic {
36536253Sbostic off_t pos, len, ch_length();
36635209Sbostic register int c;
36735209Sbostic
36835209Sbostic /*
36935209Sbostic * Determine the position in the file
37035209Sbostic * (the specified percentage of the file's length).
37135209Sbostic */
37235209Sbostic if ((len = ch_length()) == NULL_POSITION)
37335209Sbostic {
37435209Sbostic error("Don't know length of file");
37535209Sbostic return;
37635209Sbostic }
37735209Sbostic pos = (percent * len) / 100;
37835209Sbostic
37935209Sbostic /*
38035209Sbostic * Back up to the beginning of the line.
38135209Sbostic */
38235209Sbostic if (ch_seek(pos) == 0)
38335209Sbostic {
38435209Sbostic while ((c = ch_back_get()) != '\n' && c != EOI)
38535209Sbostic ;
38635209Sbostic if (c == '\n')
38735209Sbostic (void) ch_forw_get();
38835209Sbostic pos = ch_tell();
38935209Sbostic }
39035209Sbostic jump_loc(pos);
39135209Sbostic }
39235209Sbostic
39335209Sbostic /*
39435209Sbostic * Jump to a specified position in the file.
39535209Sbostic */
jump_loc(pos)39635209Sbostic jump_loc(pos)
39736253Sbostic off_t pos;
39835209Sbostic {
39935209Sbostic register int nline;
40036253Sbostic off_t tpos;
40135209Sbostic
40236253Sbostic if ((nline = onscreen(pos)) >= 0) {
40335209Sbostic /*
40435209Sbostic * The line is currently displayed.
40535209Sbostic * Just scroll there.
40635209Sbostic */
40736358Sbostic forw(nline, position(BOTTOM_PLUS_ONE), 0);
40835209Sbostic return;
40935209Sbostic }
41035209Sbostic
41135209Sbostic /*
41235209Sbostic * Line is not on screen.
41335209Sbostic * Seek to the desired location.
41435209Sbostic */
41536253Sbostic if (ch_seek(pos)) {
41635209Sbostic error("Cannot seek to that position");
41735209Sbostic return;
41835209Sbostic }
41935209Sbostic
42035209Sbostic /*
42136253Sbostic * See if the desired line is BEFORE the currently displayed screen.
42236253Sbostic * If so, then move forward far enough so the line we're on will be
42336253Sbostic * at the bottom of the screen, in order to be able to call back()
42436253Sbostic * to make the screen scroll backwards & put the line at the top of
42536253Sbostic * the screen.
42635209Sbostic * {{ This seems inefficient, but it's not so bad,
42735209Sbostic * since we can never move forward more than a
42835209Sbostic * screenful before we stop to redraw the screen. }}
42935209Sbostic */
43035209Sbostic tpos = position(TOP);
43136253Sbostic if (tpos != NULL_POSITION && pos < tpos) {
43236253Sbostic off_t npos = pos;
43335209Sbostic /*
43435209Sbostic * Note that we can't forw_line() past tpos here,
43535209Sbostic * so there should be no EOI at this stage.
43635209Sbostic */
43735209Sbostic for (nline = 0; npos < tpos && nline < sc_height - 1; nline++)
43835209Sbostic npos = forw_line(npos);
43935209Sbostic
44036253Sbostic if (npos < tpos) {
44135209Sbostic /*
44235209Sbostic * More than a screenful back.
44335209Sbostic */
44435209Sbostic lastmark();
44535209Sbostic clear();
44635209Sbostic pos_clear();
44735209Sbostic add_back_pos(npos);
44835209Sbostic }
44935209Sbostic
45035209Sbostic /*
45135209Sbostic * Note that back() will repaint() if nline > back_scroll.
45235209Sbostic */
45336358Sbostic back(nline, npos, 0);
45435209Sbostic return;
45535209Sbostic }
45635209Sbostic /*
45735209Sbostic * Remember where we were; clear and paint the screen.
45835209Sbostic */
45936253Sbostic lastmark();
46036253Sbostic prepaint(pos);
46135209Sbostic }
46235209Sbostic
46335209Sbostic /*
46435209Sbostic * The table of marks.
46535209Sbostic * A mark is simply a position in the file.
46635209Sbostic */
46735209Sbostic #define NMARKS (27) /* 26 for a-z plus one for quote */
46835209Sbostic #define LASTMARK (NMARKS-1) /* For quote */
46936253Sbostic static off_t marks[NMARKS];
47035209Sbostic
47135209Sbostic /*
47235209Sbostic * Initialize the mark table to show no marks are set.
47335209Sbostic */
init_mark()47435209Sbostic init_mark()
47535209Sbostic {
47635209Sbostic int i;
47735209Sbostic
47835209Sbostic for (i = 0; i < NMARKS; i++)
47935209Sbostic marks[i] = NULL_POSITION;
48035209Sbostic }
48135209Sbostic
48235209Sbostic /*
48335209Sbostic * See if a mark letter is valid (between a and z).
48435209Sbostic */
48535209Sbostic static int
badmark(c)48635209Sbostic badmark(c)
48735209Sbostic int c;
48835209Sbostic {
48935209Sbostic if (c < 'a' || c > 'z')
49035209Sbostic {
49135209Sbostic error("Choose a letter between 'a' and 'z'");
49235209Sbostic return (1);
49335209Sbostic }
49435209Sbostic return (0);
49535209Sbostic }
49635209Sbostic
49735209Sbostic /*
49835209Sbostic * Set a mark.
49935209Sbostic */
setmark(c)50035209Sbostic setmark(c)
50135209Sbostic int c;
50235209Sbostic {
50335209Sbostic if (badmark(c))
50435209Sbostic return;
50535209Sbostic marks[c-'a'] = position(TOP);
50635209Sbostic }
50735209Sbostic
lastmark()50835209Sbostic lastmark()
50935209Sbostic {
51035209Sbostic marks[LASTMARK] = position(TOP);
51135209Sbostic }
51235209Sbostic
51335209Sbostic /*
51435209Sbostic * Go to a previously set mark.
51535209Sbostic */
gomark(c)51635209Sbostic gomark(c)
51735209Sbostic int c;
51835209Sbostic {
51936253Sbostic off_t pos;
52035209Sbostic
52136300Sbostic if (c == '\'') {
52235209Sbostic pos = marks[LASTMARK];
52336300Sbostic if (pos == NULL_POSITION)
52436300Sbostic pos = 0;
52536300Sbostic }
52636300Sbostic else {
52736300Sbostic if (badmark(c))
52836300Sbostic return;
52935209Sbostic pos = marks[c-'a'];
53036300Sbostic if (pos == NULL_POSITION) {
53136300Sbostic error("mark not set");
53236300Sbostic return;
53336300Sbostic }
53436300Sbostic }
53536300Sbostic jump_loc(pos);
53635209Sbostic }
53735209Sbostic
53835209Sbostic /*
53935209Sbostic * Get the backwards scroll limit.
54035209Sbostic * Must call this function instead of just using the value of
54135209Sbostic * back_scroll, because the default case depends on sc_height and
54235209Sbostic * top_scroll, as well as back_scroll.
54335209Sbostic */
get_back_scroll()54435209Sbostic get_back_scroll()
54535209Sbostic {
54635209Sbostic if (back_scroll >= 0)
54735209Sbostic return (back_scroll);
54835209Sbostic if (top_scroll)
54935209Sbostic return (sc_height - 2);
55035209Sbostic return (sc_height - 1);
55135209Sbostic }
55235209Sbostic
55335209Sbostic /*
55435209Sbostic * Search for the n-th occurence of a specified pattern,
55535209Sbostic * either forward or backward.
55635209Sbostic */
search(search_forward,pattern,n,wantmatch)55735209Sbostic search(search_forward, pattern, n, wantmatch)
55835209Sbostic register int search_forward;
55935209Sbostic register char *pattern;
56035209Sbostic register int n;
56135209Sbostic int wantmatch;
56235209Sbostic {
56336253Sbostic off_t pos, linepos;
56435209Sbostic register char *p;
56535209Sbostic register char *q;
56635209Sbostic int linenum;
56735209Sbostic int linematch;
56836253Sbostic #ifdef RECOMP
56935209Sbostic char *re_comp();
57035209Sbostic char *errmsg;
57135209Sbostic #else
57236253Sbostic #ifdef REGCMP
57335209Sbostic char *regcmp();
57435209Sbostic static char *cpattern = NULL;
57535209Sbostic #else
57635209Sbostic static char lpbuf[100];
57735209Sbostic static char *last_pattern = NULL;
57835242Sbostic char *strcpy();
57935209Sbostic #endif
58035209Sbostic #endif
58135209Sbostic
58236253Sbostic /*
58336253Sbostic * For a caseless search, convert any uppercase in the pattern to
58436253Sbostic * lowercase.
58536253Sbostic */
58635209Sbostic if (caseless && pattern != NULL)
58736253Sbostic for (p = pattern; *p; p++)
58836253Sbostic if (isupper(*p))
58936253Sbostic *p = tolower(*p);
59036253Sbostic #ifdef RECOMP
59135209Sbostic
59235209Sbostic /*
59335209Sbostic * (re_comp handles a null pattern internally,
59435209Sbostic * so there is no need to check for a null pattern here.)
59535209Sbostic */
59635209Sbostic if ((errmsg = re_comp(pattern)) != NULL)
59735209Sbostic {
59835209Sbostic error(errmsg);
59936253Sbostic return(0);
60035209Sbostic }
60135209Sbostic #else
60236253Sbostic #ifdef REGCMP
60335209Sbostic if (pattern == NULL || *pattern == '\0')
60435209Sbostic {
60535209Sbostic /*
60635209Sbostic * A null pattern means use the previous pattern.
60735209Sbostic * The compiled previous pattern is in cpattern, so just use it.
60835209Sbostic */
60935209Sbostic if (cpattern == NULL)
61035209Sbostic {
61135209Sbostic error("No previous regular expression");
61236253Sbostic return(0);
61335209Sbostic }
61435209Sbostic } else
61535209Sbostic {
61635209Sbostic /*
61735209Sbostic * Otherwise compile the given pattern.
61835209Sbostic */
61935209Sbostic char *s;
62035209Sbostic if ((s = regcmp(pattern, 0)) == NULL)
62135209Sbostic {
62235209Sbostic error("Invalid pattern");
62336253Sbostic return(0);
62435209Sbostic }
62535209Sbostic if (cpattern != NULL)
62635209Sbostic free(cpattern);
62735209Sbostic cpattern = s;
62835209Sbostic }
62935209Sbostic #else
63035209Sbostic if (pattern == NULL || *pattern == '\0')
63135209Sbostic {
63235209Sbostic /*
63335209Sbostic * Null pattern means use the previous pattern.
63435209Sbostic */
63535209Sbostic if (last_pattern == NULL)
63635209Sbostic {
63735209Sbostic error("No previous regular expression");
63836253Sbostic return(0);
63935209Sbostic }
64035209Sbostic pattern = last_pattern;
64135209Sbostic } else
64235209Sbostic {
64335242Sbostic (void)strcpy(lpbuf, pattern);
64435209Sbostic last_pattern = lpbuf;
64535209Sbostic }
64635209Sbostic #endif
64735209Sbostic #endif
64835209Sbostic
64935209Sbostic /*
65035209Sbostic * Figure out where to start the search.
65135209Sbostic */
65235209Sbostic
65336253Sbostic if (position(TOP) == NULL_POSITION) {
65435209Sbostic /*
65536253Sbostic * Nothing is currently displayed. Start at the beginning
65636253Sbostic * of the file. (This case is mainly for searches from the
65736253Sbostic * command line.
65835209Sbostic */
65936253Sbostic pos = (off_t)0;
66036253Sbostic } else if (!search_forward) {
66135209Sbostic /*
66235209Sbostic * Backward search: start just before the top line
66335209Sbostic * displayed on the screen.
66435209Sbostic */
66535209Sbostic pos = position(TOP);
66636253Sbostic } else {
66735209Sbostic /*
66835209Sbostic * Start at the second screen line displayed on the screen.
66935209Sbostic */
67035209Sbostic pos = position(TOP_PLUS_ONE);
67135209Sbostic }
67235209Sbostic
67335209Sbostic if (pos == NULL_POSITION)
67435209Sbostic {
67535209Sbostic /*
67635209Sbostic * Can't find anyplace to start searching from.
67735209Sbostic */
67835209Sbostic error("Nothing to search");
67936253Sbostic return(0);
68035209Sbostic }
68135209Sbostic
68235209Sbostic linenum = find_linenum(pos);
68335209Sbostic for (;;)
68435209Sbostic {
68535209Sbostic /*
68635209Sbostic * Get lines until we find a matching one or
68735209Sbostic * until we hit end-of-file (or beginning-of-file
68835209Sbostic * if we're going backwards).
68935209Sbostic */
69035209Sbostic if (sigs)
69135209Sbostic /*
69235209Sbostic * A signal aborts the search.
69335209Sbostic */
69436253Sbostic return(0);
69535209Sbostic
69635209Sbostic if (search_forward)
69735209Sbostic {
69835209Sbostic /*
69935209Sbostic * Read the next line, and save the
70035209Sbostic * starting position of that line in linepos.
70135209Sbostic */
70235209Sbostic linepos = pos;
70335209Sbostic pos = forw_raw_line(pos);
70435209Sbostic if (linenum != 0)
70535209Sbostic linenum++;
70635209Sbostic } else
70735209Sbostic {
70835209Sbostic /*
70935209Sbostic * Read the previous line and save the
71035209Sbostic * starting position of that line in linepos.
71135209Sbostic */
71235209Sbostic pos = back_raw_line(pos);
71335209Sbostic linepos = pos;
71435209Sbostic if (linenum != 0)
71535209Sbostic linenum--;
71635209Sbostic }
71735209Sbostic
71835209Sbostic if (pos == NULL_POSITION)
71935209Sbostic {
72035209Sbostic /*
72135209Sbostic * We hit EOF/BOF without a match.
72235209Sbostic */
72335209Sbostic error("Pattern not found");
72436253Sbostic return(0);
72535209Sbostic }
72635209Sbostic
72735209Sbostic /*
72835209Sbostic * If we're using line numbers, we might as well
72935209Sbostic * remember the information we have now (the position
73035209Sbostic * and line number of the current line).
73135209Sbostic */
73235209Sbostic if (linenums)
73335209Sbostic add_lnum(linenum, pos);
73435209Sbostic
73536253Sbostic /*
73636253Sbostic * If this is a caseless search, convert uppercase in the
73736253Sbostic * input line to lowercase.
73836253Sbostic */
73935209Sbostic if (caseless)
74036253Sbostic for (p = q = line; *p; p++, q++)
74136253Sbostic *q = isupper(*p) ? tolower(*p) : *p;
74235209Sbostic
74335209Sbostic /*
74436253Sbostic * Remove any backspaces along with the preceeding char.
74536253Sbostic * This allows us to match text which is underlined or
74636253Sbostic * overstruck.
74736253Sbostic */
74836253Sbostic for (p = q = line; *p; p++, q++)
74936253Sbostic if (q > line && *p == '\b')
75036253Sbostic /* Delete BS and preceeding char. */
75136253Sbostic q -= 2;
75236253Sbostic else
75336253Sbostic /* Otherwise, just copy. */
75436253Sbostic *q = *p;
75536253Sbostic
75636253Sbostic /*
75735209Sbostic * Test the next line to see if we have a match.
75835209Sbostic * This is done in a variety of ways, depending
75935209Sbostic * on what pattern matching functions are available.
76035209Sbostic */
76136253Sbostic #ifdef REGCMP
76235209Sbostic linematch = (regex(cpattern, line) != NULL);
76335209Sbostic #else
76436253Sbostic #ifdef RECOMP
76535209Sbostic linematch = (re_exec(line) == 1);
76635209Sbostic #else
76735209Sbostic linematch = match(pattern, line);
76835209Sbostic #endif
76935209Sbostic #endif
77035209Sbostic /*
77135209Sbostic * We are successful if wantmatch and linematch are
77235209Sbostic * both true (want a match and got it),
77335209Sbostic * or both false (want a non-match and got it).
77435209Sbostic */
77535209Sbostic if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
77635209Sbostic --n <= 0)
77735209Sbostic /*
77835209Sbostic * Found the line.
77935209Sbostic */
78035209Sbostic break;
78135209Sbostic }
78235209Sbostic jump_loc(linepos);
78336253Sbostic return(1);
78435209Sbostic }
78535209Sbostic
78636253Sbostic #if !defined(REGCMP) && !defined(RECOMP)
78735209Sbostic /*
78835209Sbostic * We have neither regcmp() nor re_comp().
78935209Sbostic * We use this function to do simple pattern matching.
79035209Sbostic * It supports no metacharacters like *, etc.
79135209Sbostic */
79236253Sbostic static
match(pattern,buf)79335209Sbostic match(pattern, buf)
79435209Sbostic char *pattern, *buf;
79535209Sbostic {
79635209Sbostic register char *pp, *lp;
79735209Sbostic
79835209Sbostic for ( ; *buf != '\0'; buf++)
79935209Sbostic {
80035209Sbostic for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
80135209Sbostic if (*pp == '\0' || *lp == '\0')
80235209Sbostic break;
80335209Sbostic if (*pp == '\0')
80435209Sbostic return (1);
80535209Sbostic }
80635209Sbostic return (0);
80735209Sbostic }
80835209Sbostic #endif
809