xref: /csrg-svn/usr.bin/more/input.c (revision 62131)
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[] = "@(#)input.c	8.1 (Berkeley) 06/06/93";
1135209Sbostic #endif /* not lint */
1235209Sbostic 
1335209Sbostic /*
1435209Sbostic  * High level routines dealing with getting lines of input
1535209Sbostic  * from the file being viewed.
1635209Sbostic  *
1735209Sbostic  * When we speak of "lines" here, we mean PRINTABLE lines;
1835209Sbostic  * lines processed with respect to the screen width.
1935209Sbostic  * We use the term "raw line" to refer to lines simply
2035209Sbostic  * delimited by newlines; not processed with respect to screen width.
2135209Sbostic  */
2235209Sbostic 
2336251Sbostic #include <sys/types.h>
2436251Sbostic #include <less.h>
2535209Sbostic 
2635209Sbostic extern int squeeze;
2735209Sbostic extern int sigs;
2835209Sbostic extern char *line;
2935209Sbostic 
3036251Sbostic off_t ch_tell();
3136251Sbostic 
3235209Sbostic /*
3335209Sbostic  * Get the next line.
3435209Sbostic  * A "current" position is passed and a "new" position is returned.
3535209Sbostic  * The current position is the position of the first character of
3635209Sbostic  * a line.  The new position is the position of the first character
3735209Sbostic  * of the NEXT line.  The line obtained is the line starting at curr_pos.
3835209Sbostic  */
3936251Sbostic off_t
forw_line(curr_pos)4035209Sbostic forw_line(curr_pos)
4136251Sbostic 	off_t curr_pos;
4235209Sbostic {
4336251Sbostic 	off_t new_pos;
4435209Sbostic 	register int c;
4535209Sbostic 
4635209Sbostic 	if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
4735209Sbostic 		return (NULL_POSITION);
4835209Sbostic 
4935209Sbostic 	c = ch_forw_get();
5035209Sbostic 	if (c == EOI)
5135209Sbostic 		return (NULL_POSITION);
5235209Sbostic 
5335209Sbostic 	prewind();
5435209Sbostic 	for (;;)
5535209Sbostic 	{
5635209Sbostic 		if (sigs)
5735209Sbostic 			return (NULL_POSITION);
5835209Sbostic 		if (c == '\n' || c == EOI)
5935209Sbostic 		{
6035209Sbostic 			/*
6135209Sbostic 			 * End of the line.
6235209Sbostic 			 */
6335209Sbostic 			new_pos = ch_tell();
6435209Sbostic 			break;
6535209Sbostic 		}
6635209Sbostic 
6735209Sbostic 		/*
6835209Sbostic 		 * Append the char to the line and get the next char.
6935209Sbostic 		 */
7035209Sbostic 		if (pappend(c))
7135209Sbostic 		{
7235209Sbostic 			/*
7335209Sbostic 			 * The char won't fit in the line; the line
7435209Sbostic 			 * is too long to print in the screen width.
7535209Sbostic 			 * End the line here.
7635209Sbostic 			 */
7735209Sbostic 			new_pos = ch_tell() - 1;
7835209Sbostic 			break;
7935209Sbostic 		}
8035209Sbostic 		c = ch_forw_get();
8135209Sbostic 	}
8235209Sbostic 	(void) pappend('\0');
8335209Sbostic 
8435209Sbostic 	if (squeeze && *line == '\0')
8535209Sbostic 	{
8635209Sbostic 		/*
8735209Sbostic 		 * This line is blank.
8835209Sbostic 		 * Skip down to the last contiguous blank line
8935209Sbostic 		 * and pretend it is the one which we are returning.
9035209Sbostic 		 */
9135209Sbostic 		while ((c = ch_forw_get()) == '\n')
9235209Sbostic 			if (sigs)
9335209Sbostic 				return (NULL_POSITION);
9435209Sbostic 		if (c != EOI)
9535209Sbostic 			(void) ch_back_get();
9635209Sbostic 		new_pos = ch_tell();
9735209Sbostic 	}
9835209Sbostic 
9935209Sbostic 	return (new_pos);
10035209Sbostic }
10135209Sbostic 
10235209Sbostic /*
10335209Sbostic  * Get the previous line.
10435209Sbostic  * A "current" position is passed and a "new" position is returned.
10535209Sbostic  * The current position is the position of the first character of
10635209Sbostic  * a line.  The new position is the position of the first character
10735209Sbostic  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
10835209Sbostic  */
10936251Sbostic off_t
back_line(curr_pos)11035209Sbostic back_line(curr_pos)
11136251Sbostic 	off_t curr_pos;
11235209Sbostic {
11336251Sbostic 	off_t new_pos, begin_new_pos;
11435209Sbostic 	int c;
11535209Sbostic 
11636251Sbostic 	if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
11735209Sbostic 		ch_seek(curr_pos-1))
11835209Sbostic 		return (NULL_POSITION);
11935209Sbostic 
12035209Sbostic 	if (squeeze)
12135209Sbostic 	{
12235209Sbostic 		/*
12335209Sbostic 		 * Find out if the "current" line was blank.
12435209Sbostic 		 */
12535209Sbostic 		(void) ch_forw_get();	/* Skip the newline */
12635209Sbostic 		c = ch_forw_get();	/* First char of "current" line */
12735209Sbostic 		(void) ch_back_get();	/* Restore our position */
12835209Sbostic 		(void) ch_back_get();
12935209Sbostic 
13035209Sbostic 		if (c == '\n')
13135209Sbostic 		{
13235209Sbostic 			/*
13335209Sbostic 			 * The "current" line was blank.
13435209Sbostic 			 * Skip over any preceeding blank lines,
13535209Sbostic 			 * since we skipped them in forw_line().
13635209Sbostic 			 */
13735209Sbostic 			while ((c = ch_back_get()) == '\n')
13835209Sbostic 				if (sigs)
13935209Sbostic 					return (NULL_POSITION);
14035209Sbostic 			if (c == EOI)
14135209Sbostic 				return (NULL_POSITION);
14235209Sbostic 			(void) ch_forw_get();
14335209Sbostic 		}
14435209Sbostic 	}
14535209Sbostic 
14635209Sbostic 	/*
14735209Sbostic 	 * Scan backwards until we hit the beginning of the line.
14835209Sbostic 	 */
14935209Sbostic 	for (;;)
15035209Sbostic 	{
15135209Sbostic 		if (sigs)
15235209Sbostic 			return (NULL_POSITION);
15335209Sbostic 		c = ch_back_get();
15435209Sbostic 		if (c == '\n')
15535209Sbostic 		{
15635209Sbostic 			/*
15735209Sbostic 			 * This is the newline ending the previous line.
15835209Sbostic 			 * We have hit the beginning of the line.
15935209Sbostic 			 */
16035209Sbostic 			new_pos = ch_tell() + 1;
16135209Sbostic 			break;
16235209Sbostic 		}
16335209Sbostic 		if (c == EOI)
16435209Sbostic 		{
16535209Sbostic 			/*
16635209Sbostic 			 * We have hit the beginning of the file.
16735209Sbostic 			 * This must be the first line in the file.
16835209Sbostic 			 * This must, of course, be the beginning of the line.
16935209Sbostic 			 */
17035209Sbostic 			new_pos = ch_tell();
17135209Sbostic 			break;
17235209Sbostic 		}
17335209Sbostic 	}
17435209Sbostic 
17535209Sbostic 	/*
17635209Sbostic 	 * Now scan forwards from the beginning of this line.
17735209Sbostic 	 * We keep discarding "printable lines" (based on screen width)
17835209Sbostic 	 * until we reach the curr_pos.
17935209Sbostic 	 *
18035209Sbostic 	 * {{ This algorithm is pretty inefficient if the lines
18135209Sbostic 	 *    are much longer than the screen width,
18235209Sbostic 	 *    but I don't know of any better way. }}
18335209Sbostic 	 */
18435209Sbostic 	if (ch_seek(new_pos))
18535209Sbostic 		return (NULL_POSITION);
18635209Sbostic     loop:
18735209Sbostic 	begin_new_pos = new_pos;
18835209Sbostic 	prewind();
18935209Sbostic 
19035209Sbostic 	do
19135209Sbostic 	{
19235209Sbostic 		c = ch_forw_get();
19335209Sbostic 		if (c == EOI || sigs)
19435209Sbostic 			return (NULL_POSITION);
19535209Sbostic 		new_pos++;
19635209Sbostic 		if (c == '\n')
19735209Sbostic 			break;
19835209Sbostic 		if (pappend(c))
19935209Sbostic 		{
20035209Sbostic 			/*
20135209Sbostic 			 * Got a full printable line, but we haven't
20235209Sbostic 			 * reached our curr_pos yet.  Discard the line
20335209Sbostic 			 * and start a new one.
20435209Sbostic 			 */
20535209Sbostic 			(void) pappend('\0');
20635209Sbostic 			(void) ch_back_get();
20735209Sbostic 			new_pos--;
20835209Sbostic 			goto loop;
20935209Sbostic 		}
21035209Sbostic 	} while (new_pos < curr_pos);
21135209Sbostic 
21235209Sbostic 	(void) pappend('\0');
21335209Sbostic 
21435209Sbostic 	return (begin_new_pos);
21535209Sbostic }
216