1 /* 2 * Copyright (C) 1984-2000 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * High level routines dealing with getting lines of input 14 * from the file being viewed. 15 * 16 * When we speak of "lines" here, we mean PRINTABLE lines; 17 * lines processed with respect to the screen width. 18 * We use the term "raw line" to refer to lines simply 19 * delimited by newlines; not processed with respect to screen width. 20 */ 21 22 #include "less.h" 23 24 extern int squeeze; 25 extern int chopline; 26 extern int hshift; 27 extern int quit_if_one_screen; 28 extern int sigs; 29 extern int ignore_eoi; 30 extern POSITION start_attnpos; 31 extern POSITION end_attnpos; 32 #if HILITE_SEARCH 33 extern int hilite_search; 34 extern int size_linebuf; 35 #endif 36 37 /* 38 * Get the next line. 39 * A "current" position is passed and a "new" position is returned. 40 * The current position is the position of the first character of 41 * a line. The new position is the position of the first character 42 * of the NEXT line. The line obtained is the line starting at curr_pos. 43 */ 44 public POSITION 45 forw_line(curr_pos) 46 POSITION curr_pos; 47 { 48 POSITION new_pos; 49 register int c; 50 int blankline; 51 int endline; 52 53 if (curr_pos == NULL_POSITION) 54 { 55 null_line(); 56 return (NULL_POSITION); 57 } 58 #if HILITE_SEARCH 59 if (hilite_search == OPT_ONPLUS) 60 /* 61 * If we are ignoring EOI (command F), only prepare 62 * one line ahead, to avoid getting stuck waiting for 63 * slow data without displaying the data we already have. 64 * If we're not ignoring EOI, we *could* do the same, but 65 * for efficiency we prepare several lines ahead at once. 66 */ 67 prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 68 ignore_eoi ? 1 : -1); 69 #endif 70 if (ch_seek(curr_pos)) 71 { 72 null_line(); 73 return (NULL_POSITION); 74 } 75 76 prewind(); 77 plinenum(curr_pos); 78 (void) ch_seek(curr_pos); 79 80 c = ch_forw_get(); 81 if (c == EOI) 82 { 83 null_line(); 84 return (NULL_POSITION); 85 } 86 blankline = (c == '\n' || c == '\r'); 87 88 for (;;) 89 { 90 if (ABORT_SIGS()) 91 { 92 null_line(); 93 return (NULL_POSITION); 94 } 95 if (c == '\n' || c == EOI) 96 { 97 /* 98 * End of the line. 99 */ 100 new_pos = ch_tell(); 101 endline = TRUE; 102 break; 103 } 104 105 /* 106 * Append the char to the line and get the next char. 107 */ 108 if (pappend(c, ch_tell()-1)) 109 { 110 /* 111 * The char won't fit in the line; the line 112 * is too long to print in the screen width. 113 * End the line here. 114 */ 115 if (chopline || hshift > 0) 116 { 117 do 118 { 119 c = ch_forw_get(); 120 } while (c != '\n' && c != EOI); 121 new_pos = ch_tell(); 122 endline = TRUE; 123 quit_if_one_screen = FALSE; 124 } else 125 { 126 new_pos = ch_tell() - 1; 127 endline = FALSE; 128 } 129 break; 130 } 131 c = ch_forw_get(); 132 } 133 pdone(endline); 134 135 if (squeeze && blankline) 136 { 137 /* 138 * This line is blank. 139 * Skip down to the last contiguous blank line 140 * and pretend it is the one which we are returning. 141 */ 142 while ((c = ch_forw_get()) == '\n' || c == '\r') 143 if (ABORT_SIGS()) 144 { 145 null_line(); 146 return (NULL_POSITION); 147 } 148 if (c != EOI) 149 (void) ch_back_get(); 150 new_pos = ch_tell(); 151 } 152 153 return (new_pos); 154 } 155 156 /* 157 * Get the previous line. 158 * A "current" position is passed and a "new" position is returned. 159 * The current position is the position of the first character of 160 * a line. The new position is the position of the first character 161 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 162 */ 163 public POSITION 164 back_line(curr_pos) 165 POSITION curr_pos; 166 { 167 POSITION new_pos, begin_new_pos; 168 int c; 169 int endline; 170 171 if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 172 { 173 null_line(); 174 return (NULL_POSITION); 175 } 176 #if HILITE_SEARCH 177 if (hilite_search == OPT_ONPLUS) 178 prep_hilite((curr_pos < 3*size_linebuf) ? 179 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 180 #endif 181 if (ch_seek(curr_pos-1)) 182 { 183 null_line(); 184 return (NULL_POSITION); 185 } 186 187 if (squeeze) 188 { 189 /* 190 * Find out if the "current" line was blank. 191 */ 192 (void) ch_forw_get(); /* Skip the newline */ 193 c = ch_forw_get(); /* First char of "current" line */ 194 (void) ch_back_get(); /* Restore our position */ 195 (void) ch_back_get(); 196 197 if (c == '\n' || c == '\r') 198 { 199 /* 200 * The "current" line was blank. 201 * Skip over any preceding blank lines, 202 * since we skipped them in forw_line(). 203 */ 204 while ((c = ch_back_get()) == '\n' || c == '\r') 205 if (ABORT_SIGS()) 206 { 207 null_line(); 208 return (NULL_POSITION); 209 } 210 if (c == EOI) 211 { 212 null_line(); 213 return (NULL_POSITION); 214 } 215 (void) ch_forw_get(); 216 } 217 } 218 219 /* 220 * Scan backwards until we hit the beginning of the line. 221 */ 222 for (;;) 223 { 224 if (ABORT_SIGS()) 225 { 226 null_line(); 227 return (NULL_POSITION); 228 } 229 c = ch_back_get(); 230 if (c == '\n') 231 { 232 /* 233 * This is the newline ending the previous line. 234 * We have hit the beginning of the line. 235 */ 236 new_pos = ch_tell() + 1; 237 break; 238 } 239 if (c == EOI) 240 { 241 /* 242 * We have hit the beginning of the file. 243 * This must be the first line in the file. 244 * This must, of course, be the beginning of the line. 245 */ 246 new_pos = ch_tell(); 247 break; 248 } 249 } 250 251 /* 252 * Now scan forwards from the beginning of this line. 253 * We keep discarding "printable lines" (based on screen width) 254 * until we reach the curr_pos. 255 * 256 * {{ This algorithm is pretty inefficient if the lines 257 * are much longer than the screen width, 258 * but I don't know of any better way. }} 259 */ 260 if (ch_seek(new_pos)) 261 { 262 null_line(); 263 return (NULL_POSITION); 264 } 265 endline = FALSE; 266 loop: 267 begin_new_pos = new_pos; 268 prewind(); 269 plinenum(new_pos); 270 (void) ch_seek(new_pos); 271 272 do 273 { 274 c = ch_forw_get(); 275 if (c == EOI || ABORT_SIGS()) 276 { 277 null_line(); 278 return (NULL_POSITION); 279 } 280 new_pos++; 281 if (c == '\n') 282 { 283 endline = TRUE; 284 break; 285 } 286 if (pappend(c, ch_tell()-1)) 287 { 288 /* 289 * Got a full printable line, but we haven't 290 * reached our curr_pos yet. Discard the line 291 * and start a new one. 292 */ 293 if (chopline || hshift > 0) 294 { 295 endline = TRUE; 296 quit_if_one_screen = FALSE; 297 break; 298 } 299 pdone(0); 300 (void) ch_back_get(); 301 new_pos--; 302 goto loop; 303 } 304 } while (new_pos < curr_pos); 305 306 pdone(endline); 307 308 return (begin_new_pos); 309 } 310 311 /* 312 * Set attnpos. 313 */ 314 public void 315 set_attnpos(pos) 316 POSITION pos; 317 { 318 int c; 319 320 if (pos != NULL_POSITION) 321 { 322 if (ch_seek(pos)) 323 return; 324 for (;;) 325 { 326 c = ch_forw_get(); 327 if (c == EOI) 328 return; 329 if (c != '\n' && c != '\r') 330 break; 331 pos++; 332 } 333 } 334 start_attnpos = pos; 335 for (;;) 336 { 337 c = ch_forw_get(); 338 pos++; 339 if (c == EOI || c == '\n' || c == '\r') 340 break; 341 } 342 end_attnpos = pos; 343 } 344