1 /* $NetBSD: input.c,v 1.4 2001/08/20 12:00:47 wiz 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 #include <sys/cdefs.h> 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93"; 41 #else 42 __RCSID("$NetBSD: input.c,v 1.4 2001/08/20 12:00:47 wiz Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * High level routines dealing with getting lines of input 48 * from the file being viewed. 49 * 50 * When we speak of "lines" here, we mean PRINTABLE lines; 51 * lines processed with respect to the screen width. 52 * We use the term "raw line" to refer to lines simply 53 * delimited by newlines; not processed with respect to screen width. 54 */ 55 56 #include <sys/types.h> 57 58 #include "less.h" 59 #include "extern.h" 60 61 /* 62 * Get the next line. 63 * A "current" position is passed and a "new" position is returned. 64 * The current position is the position of the first character of 65 * a line. The new position is the position of the first character 66 * of the NEXT line. The line obtained is the line starting at curr_pos. 67 */ 68 off_t 69 forw_line(curr_pos) 70 off_t curr_pos; 71 { 72 off_t new_pos; 73 int c; 74 75 if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) 76 return (NULL_POSITION); 77 78 c = ch_forw_get(); 79 if (c == EOI) 80 return (NULL_POSITION); 81 82 prewind(); 83 for (;;) 84 { 85 if (sigs) 86 return (NULL_POSITION); 87 if (c == '\n' || c == EOI) 88 { 89 /* 90 * End of the line. 91 */ 92 new_pos = ch_tell(); 93 break; 94 } 95 96 /* 97 * Append the char to the line and get the next char. 98 */ 99 if (pappend(c)) 100 { 101 /* 102 * The char won't fit in the line; the line 103 * is too long to print in the screen width. 104 * End the line here. 105 */ 106 new_pos = ch_tell() - 1; 107 break; 108 } 109 c = ch_forw_get(); 110 } 111 (void) pappend('\0'); 112 113 if (squeeze && *line == '\0') 114 { 115 /* 116 * This line is blank. 117 * Skip down to the last contiguous blank line 118 * and pretend it is the one which we are returning. 119 */ 120 while ((c = ch_forw_get()) == '\n') 121 if (sigs) 122 return (NULL_POSITION); 123 if (c != EOI) 124 (void) ch_back_get(); 125 new_pos = ch_tell(); 126 } 127 128 return (new_pos); 129 } 130 131 /* 132 * Get the previous line. 133 * A "current" position is passed and a "new" position is returned. 134 * The current position is the position of the first character of 135 * a line. The new position is the position of the first character 136 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 137 */ 138 off_t 139 back_line(curr_pos) 140 off_t curr_pos; 141 { 142 off_t new_pos, begin_new_pos; 143 int c; 144 145 if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || 146 ch_seek(curr_pos-1)) 147 return (NULL_POSITION); 148 149 if (squeeze) 150 { 151 /* 152 * Find out if the "current" line was blank. 153 */ 154 (void) ch_forw_get(); /* Skip the newline */ 155 c = ch_forw_get(); /* First char of "current" line */ 156 (void) ch_back_get(); /* Restore our position */ 157 (void) ch_back_get(); 158 159 if (c == '\n') 160 { 161 /* 162 * The "current" line was blank. 163 * Skip over any preceding blank lines, 164 * since we skipped them in forw_line(). 165 */ 166 while ((c = ch_back_get()) == '\n') 167 if (sigs) 168 return (NULL_POSITION); 169 if (c == EOI) 170 return (NULL_POSITION); 171 (void) ch_forw_get(); 172 } 173 } 174 175 /* 176 * Scan backwards until we hit the beginning of the line. 177 */ 178 for (;;) 179 { 180 if (sigs) 181 return (NULL_POSITION); 182 c = ch_back_get(); 183 if (c == '\n') 184 { 185 /* 186 * This is the newline ending the previous line. 187 * We have hit the beginning of the line. 188 */ 189 new_pos = ch_tell() + 1; 190 break; 191 } 192 if (c == EOI) 193 { 194 /* 195 * We have hit the beginning of the file. 196 * This must be the first line in the file. 197 * This must, of course, be the beginning of the line. 198 */ 199 new_pos = ch_tell(); 200 break; 201 } 202 } 203 204 /* 205 * Now scan forwards from the beginning of this line. 206 * We keep discarding "printable lines" (based on screen width) 207 * until we reach the curr_pos. 208 * 209 * {{ This algorithm is pretty inefficient if the lines 210 * are much longer than the screen width, 211 * but I don't know of any better way. }} 212 */ 213 if (ch_seek(new_pos)) 214 return (NULL_POSITION); 215 loop: 216 begin_new_pos = new_pos; 217 prewind(); 218 219 do 220 { 221 c = ch_forw_get(); 222 if (c == EOI || sigs) 223 return (NULL_POSITION); 224 new_pos++; 225 if (c == '\n') 226 break; 227 if (pappend(c)) 228 { 229 /* 230 * Got a full printable line, but we haven't 231 * reached our curr_pos yet. Discard the line 232 * and start a new one. 233 */ 234 (void) pappend('\0'); 235 (void) ch_back_get(); 236 new_pos--; 237 goto loop; 238 } 239 } while (new_pos < curr_pos); 240 241 (void) pappend('\0'); 242 243 return (begin_new_pos); 244 } 245