1 /* $OpenBSD: input.c,v 1.2 2001/01/29 01:58:02 niklas Exp $ */ 2 3 /* 4 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 5 * 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 in the documentation and/or other materials provided with 14 * the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 /* 31 * High level routines dealing with getting lines of input 32 * from the file being viewed. 33 * 34 * When we speak of "lines" here, we mean PRINTABLE lines; 35 * lines processed with respect to the screen width. 36 * We use the term "raw line" to refer to lines simply 37 * delimited by newlines; not processed with respect to screen width. 38 */ 39 40 #include "less.h" 41 42 extern int squeeze; 43 extern int chopline; 44 extern int sigs; 45 #if HILITE_SEARCH 46 extern int hilite_search; 47 extern int size_linebuf; 48 #endif 49 50 /* 51 * Get the next line. 52 * A "current" position is passed and a "new" position is returned. 53 * The current position is the position of the first character of 54 * a line. The new position is the position of the first character 55 * of the NEXT line. The line obtained is the line starting at curr_pos. 56 */ 57 public POSITION 58 forw_line(curr_pos) 59 POSITION curr_pos; 60 { 61 POSITION new_pos; 62 register int c; 63 int blankline; 64 int endline; 65 66 if (curr_pos == NULL_POSITION) 67 { 68 null_line(); 69 return (NULL_POSITION); 70 } 71 #if HILITE_SEARCH 72 if (hilite_search == OPT_ONPLUS) 73 prep_hilite(curr_pos, curr_pos + 3*size_linebuf); 74 #endif 75 if (ch_seek(curr_pos)) 76 { 77 null_line(); 78 return (NULL_POSITION); 79 } 80 81 prewind(); 82 plinenum(curr_pos); 83 (void) ch_seek(curr_pos); 84 85 c = ch_forw_get(); 86 if (c == EOI) 87 { 88 null_line(); 89 return (NULL_POSITION); 90 } 91 blankline = (c == '\n' || c == '\r'); 92 93 for (;;) 94 { 95 if (ABORT_SIGS()) 96 { 97 null_line(); 98 return (NULL_POSITION); 99 } 100 if (c == '\n' || c == EOI) 101 { 102 /* 103 * End of the line. 104 */ 105 new_pos = ch_tell(); 106 endline = 1; 107 break; 108 } 109 110 /* 111 * Append the char to the line and get the next char. 112 */ 113 if (pappend(c, ch_tell()-1)) 114 { 115 /* 116 * The char won't fit in the line; the line 117 * is too long to print in the screen width. 118 * End the line here. 119 */ 120 if (chopline) 121 { 122 do 123 { 124 c = ch_forw_get(); 125 } while (c != '\n' && c != EOI); 126 new_pos = ch_tell(); 127 endline = 1; 128 } else 129 { 130 new_pos = ch_tell() - 1; 131 endline = 0; 132 } 133 break; 134 } 135 c = ch_forw_get(); 136 } 137 pdone(endline); 138 139 if (squeeze && blankline) 140 { 141 /* 142 * This line is blank. 143 * Skip down to the last contiguous blank line 144 * and pretend it is the one which we are returning. 145 */ 146 while ((c = ch_forw_get()) == '\n' || c == '\r') 147 if (ABORT_SIGS()) 148 { 149 null_line(); 150 return (NULL_POSITION); 151 } 152 if (c != EOI) 153 (void) ch_back_get(); 154 new_pos = ch_tell(); 155 } 156 157 return (new_pos); 158 } 159 160 /* 161 * Get the previous line. 162 * A "current" position is passed and a "new" position is returned. 163 * The current position is the position of the first character of 164 * a line. The new position is the position of the first character 165 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 166 */ 167 public POSITION 168 back_line(curr_pos) 169 POSITION curr_pos; 170 { 171 POSITION new_pos, begin_new_pos; 172 int c; 173 int endline; 174 175 if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 176 { 177 null_line(); 178 return (NULL_POSITION); 179 } 180 #if HILITE_SEARCH 181 if (hilite_search == OPT_ONPLUS) 182 prep_hilite((curr_pos < 3*size_linebuf) ? 183 0 : curr_pos - 3*size_linebuf, curr_pos); 184 #endif 185 if (ch_seek(curr_pos-1)) 186 { 187 null_line(); 188 return (NULL_POSITION); 189 } 190 191 if (squeeze) 192 { 193 /* 194 * Find out if the "current" line was blank. 195 */ 196 (void) ch_forw_get(); /* Skip the newline */ 197 c = ch_forw_get(); /* First char of "current" line */ 198 (void) ch_back_get(); /* Restore our position */ 199 (void) ch_back_get(); 200 201 if (c == '\n' || c == '\r') 202 { 203 /* 204 * The "current" line was blank. 205 * Skip over any preceding blank lines, 206 * since we skipped them in forw_line(). 207 */ 208 while ((c = ch_back_get()) == '\n' || c == '\r') 209 if (ABORT_SIGS()) 210 { 211 null_line(); 212 return (NULL_POSITION); 213 } 214 if (c == EOI) 215 { 216 null_line(); 217 return (NULL_POSITION); 218 } 219 (void) ch_forw_get(); 220 } 221 } 222 223 /* 224 * Scan backwards until we hit the beginning of the line. 225 */ 226 for (;;) 227 { 228 if (ABORT_SIGS()) 229 { 230 null_line(); 231 return (NULL_POSITION); 232 } 233 c = ch_back_get(); 234 if (c == '\n') 235 { 236 /* 237 * This is the newline ending the previous line. 238 * We have hit the beginning of the line. 239 */ 240 new_pos = ch_tell() + 1; 241 break; 242 } 243 if (c == EOI) 244 { 245 /* 246 * We have hit the beginning of the file. 247 * This must be the first line in the file. 248 * This must, of course, be the beginning of the line. 249 */ 250 new_pos = ch_tell(); 251 break; 252 } 253 } 254 255 /* 256 * Now scan forwards from the beginning of this line. 257 * We keep discarding "printable lines" (based on screen width) 258 * until we reach the curr_pos. 259 * 260 * {{ This algorithm is pretty inefficient if the lines 261 * are much longer than the screen width, 262 * but I don't know of any better way. }} 263 */ 264 if (ch_seek(new_pos)) 265 { 266 null_line(); 267 return (NULL_POSITION); 268 } 269 endline = 0; 270 loop: 271 begin_new_pos = new_pos; 272 prewind(); 273 plinenum(new_pos); 274 (void) ch_seek(new_pos); 275 276 do 277 { 278 c = ch_forw_get(); 279 if (c == EOI || ABORT_SIGS()) 280 { 281 null_line(); 282 return (NULL_POSITION); 283 } 284 new_pos++; 285 if (c == '\n') 286 { 287 endline = 1; 288 break; 289 } 290 if (pappend(c, ch_tell()-1)) 291 { 292 /* 293 * Got a full printable line, but we haven't 294 * reached our curr_pos yet. Discard the line 295 * and start a new one. 296 */ 297 if (chopline) 298 { 299 endline = 1; 300 break; 301 } 302 pdone(0); 303 (void) ch_back_get(); 304 new_pos--; 305 goto loop; 306 } 307 } while (new_pos < curr_pos); 308 309 pdone(endline); 310 311 return (begin_new_pos); 312 } 313