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