Home | History | Annotate | Line # | Download | only in more
input.c revision 1.5
      1 /*	$NetBSD: input.c,v 1.5 2003/08/07 09:27:59 agc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1988 Mark Nudleman
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  * 3. All advertising materials mentioning features or use of this software
     44  *    must display the following acknowledgement:
     45  *	This product includes software developed by the University of
     46  *	California, Berkeley and its contributors.
     47  * 4. Neither the name of the University nor the names of its contributors
     48  *    may be used to endorse or promote products derived from this software
     49  *    without specific prior written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61  * SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 #if 0
     67 static char sccsid[] = "@(#)input.c	8.1 (Berkeley) 6/6/93";
     68 #else
     69 __RCSID("$NetBSD: input.c,v 1.5 2003/08/07 09:27:59 agc Exp $");
     70 #endif
     71 #endif /* not lint */
     72 
     73 /*
     74  * High level routines dealing with getting lines of input
     75  * from the file being viewed.
     76  *
     77  * When we speak of "lines" here, we mean PRINTABLE lines;
     78  * lines processed with respect to the screen width.
     79  * We use the term "raw line" to refer to lines simply
     80  * delimited by newlines; not processed with respect to screen width.
     81  */
     82 
     83 #include <sys/types.h>
     84 
     85 #include "less.h"
     86 #include "extern.h"
     87 
     88 /*
     89  * Get the next line.
     90  * A "current" position is passed and a "new" position is returned.
     91  * The current position is the position of the first character of
     92  * a line.  The new position is the position of the first character
     93  * of the NEXT line.  The line obtained is the line starting at curr_pos.
     94  */
     95 off_t
     96 forw_line(curr_pos)
     97 	off_t curr_pos;
     98 {
     99 	off_t new_pos;
    100 	int c;
    101 
    102 	if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
    103 		return (NULL_POSITION);
    104 
    105 	c = ch_forw_get();
    106 	if (c == EOI)
    107 		return (NULL_POSITION);
    108 
    109 	prewind();
    110 	for (;;)
    111 	{
    112 		if (sigs)
    113 			return (NULL_POSITION);
    114 		if (c == '\n' || c == EOI)
    115 		{
    116 			/*
    117 			 * End of the line.
    118 			 */
    119 			new_pos = ch_tell();
    120 			break;
    121 		}
    122 
    123 		/*
    124 		 * Append the char to the line and get the next char.
    125 		 */
    126 		if (pappend(c))
    127 		{
    128 			/*
    129 			 * The char won't fit in the line; the line
    130 			 * is too long to print in the screen width.
    131 			 * End the line here.
    132 			 */
    133 			new_pos = ch_tell() - 1;
    134 			break;
    135 		}
    136 		c = ch_forw_get();
    137 	}
    138 	(void) pappend('\0');
    139 
    140 	if (squeeze && *line == '\0')
    141 	{
    142 		/*
    143 		 * This line is blank.
    144 		 * Skip down to the last contiguous blank line
    145 		 * and pretend it is the one which we are returning.
    146 		 */
    147 		while ((c = ch_forw_get()) == '\n')
    148 			if (sigs)
    149 				return (NULL_POSITION);
    150 		if (c != EOI)
    151 			(void) ch_back_get();
    152 		new_pos = ch_tell();
    153 	}
    154 
    155 	return (new_pos);
    156 }
    157 
    158 /*
    159  * Get the previous line.
    160  * A "current" position is passed and a "new" position is returned.
    161  * The current position is the position of the first character of
    162  * a line.  The new position is the position of the first character
    163  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
    164  */
    165 off_t
    166 back_line(curr_pos)
    167 	off_t curr_pos;
    168 {
    169 	off_t new_pos, begin_new_pos;
    170 	int c;
    171 
    172 	if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
    173 		ch_seek(curr_pos-1))
    174 		return (NULL_POSITION);
    175 
    176 	if (squeeze)
    177 	{
    178 		/*
    179 		 * Find out if the "current" line was blank.
    180 		 */
    181 		(void) ch_forw_get();	/* Skip the newline */
    182 		c = ch_forw_get();	/* First char of "current" line */
    183 		(void) ch_back_get();	/* Restore our position */
    184 		(void) ch_back_get();
    185 
    186 		if (c == '\n')
    187 		{
    188 			/*
    189 			 * The "current" line was blank.
    190 			 * Skip over any preceding blank lines,
    191 			 * since we skipped them in forw_line().
    192 			 */
    193 			while ((c = ch_back_get()) == '\n')
    194 				if (sigs)
    195 					return (NULL_POSITION);
    196 			if (c == EOI)
    197 				return (NULL_POSITION);
    198 			(void) ch_forw_get();
    199 		}
    200 	}
    201 
    202 	/*
    203 	 * Scan backwards until we hit the beginning of the line.
    204 	 */
    205 	for (;;)
    206 	{
    207 		if (sigs)
    208 			return (NULL_POSITION);
    209 		c = ch_back_get();
    210 		if (c == '\n')
    211 		{
    212 			/*
    213 			 * This is the newline ending the previous line.
    214 			 * We have hit the beginning of the line.
    215 			 */
    216 			new_pos = ch_tell() + 1;
    217 			break;
    218 		}
    219 		if (c == EOI)
    220 		{
    221 			/*
    222 			 * We have hit the beginning of the file.
    223 			 * This must be the first line in the file.
    224 			 * This must, of course, be the beginning of the line.
    225 			 */
    226 			new_pos = ch_tell();
    227 			break;
    228 		}
    229 	}
    230 
    231 	/*
    232 	 * Now scan forwards from the beginning of this line.
    233 	 * We keep discarding "printable lines" (based on screen width)
    234 	 * until we reach the curr_pos.
    235 	 *
    236 	 * {{ This algorithm is pretty inefficient if the lines
    237 	 *    are much longer than the screen width,
    238 	 *    but I don't know of any better way. }}
    239 	 */
    240 	if (ch_seek(new_pos))
    241 		return (NULL_POSITION);
    242     loop:
    243 	begin_new_pos = new_pos;
    244 	prewind();
    245 
    246 	do
    247 	{
    248 		c = ch_forw_get();
    249 		if (c == EOI || sigs)
    250 			return (NULL_POSITION);
    251 		new_pos++;
    252 		if (c == '\n')
    253 			break;
    254 		if (pappend(c))
    255 		{
    256 			/*
    257 			 * Got a full printable line, but we haven't
    258 			 * reached our curr_pos yet.  Discard the line
    259 			 * and start a new one.
    260 			 */
    261 			(void) pappend('\0');
    262 			(void) ch_back_get();
    263 			new_pos--;
    264 			goto loop;
    265 		}
    266 	} while (new_pos < curr_pos);
    267 
    268 	(void) pappend('\0');
    269 
    270 	return (begin_new_pos);
    271 }
    272