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