1 /* 2 * Copyright (C) 1984-2007 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 * Routines which jump to a new location in the file. 14 */ 15 16 #include "less.h" 17 #include "position.h" 18 19 extern int hit_eof; 20 extern int jump_sline; 21 extern int squished; 22 extern int screen_trashed; 23 extern int sc_width, sc_height; 24 extern int show_attn; 25 extern int top_scroll; 26 27 /* 28 * Jump to the end of the file. 29 */ 30 public void 31 jump_forw() 32 { 33 POSITION pos; 34 POSITION end_pos; 35 36 if (ch_end_seek()) 37 { 38 error("Cannot seek to end of file", NULL_PARG); 39 return; 40 } 41 /* 42 * Position the last line in the file at the last screen line. 43 * Go back one line from the end of the file 44 * to get to the beginning of the last line. 45 */ 46 pos_clear(); 47 end_pos = ch_tell(); 48 pos = back_line(end_pos); 49 if (pos == NULL_POSITION) 50 jump_loc((POSITION)0, sc_height-1); 51 else 52 { 53 jump_loc(pos, sc_height-1); 54 if (position(sc_height-1) != end_pos) 55 repaint(); 56 } 57 } 58 59 /* 60 * Jump to line n in the file. 61 */ 62 public void 63 jump_back(linenum) 64 LINENUM linenum; 65 { 66 POSITION pos; 67 PARG parg; 68 69 /* 70 * Find the position of the specified line. 71 * If we can seek there, just jump to it. 72 * If we can't seek, but we're trying to go to line number 1, 73 * use ch_beg_seek() to get as close as we can. 74 */ 75 pos = find_pos(linenum); 76 if (pos != NULL_POSITION && ch_seek(pos) == 0) 77 { 78 if (show_attn) 79 set_attnpos(pos); 80 jump_loc(pos, jump_sline); 81 } else if (linenum <= 1 && ch_beg_seek() == 0) 82 { 83 jump_loc(ch_tell(), jump_sline); 84 error("Cannot seek to beginning of file", NULL_PARG); 85 } else 86 { 87 parg.p_linenum = linenum; 88 error("Cannot seek to line number %n", &parg); 89 } 90 } 91 92 /* 93 * Repaint the screen. 94 */ 95 public void 96 repaint() 97 { 98 struct scrpos scrpos; 99 /* 100 * Start at the line currently at the top of the screen 101 * and redisplay the screen. 102 */ 103 get_scrpos(&scrpos); 104 pos_clear(); 105 jump_loc(scrpos.pos, scrpos.ln); 106 } 107 108 /* 109 * Jump to a specified percentage into the file. 110 */ 111 public void 112 jump_percent(percent, fraction) 113 int percent; 114 long fraction; 115 { 116 POSITION pos, len; 117 118 /* 119 * Determine the position in the file 120 * (the specified percentage of the file's length). 121 */ 122 if ((len = ch_length()) == NULL_POSITION) 123 { 124 ierror("Determining length of file", NULL_PARG); 125 ch_end_seek(); 126 } 127 if ((len = ch_length()) == NULL_POSITION) 128 { 129 error("Don't know length of file", NULL_PARG); 130 return; 131 } 132 pos = percent_pos(len, percent, fraction); 133 if (pos >= len) 134 pos = len-1; 135 136 jump_line_loc(pos, jump_sline); 137 } 138 139 /* 140 * Jump to a specified position in the file. 141 * Like jump_loc, but the position need not be 142 * the first character in a line. 143 */ 144 public void 145 jump_line_loc(pos, sline) 146 POSITION pos; 147 int sline; 148 { 149 int c; 150 151 if (ch_seek(pos) == 0) 152 { 153 /* 154 * Back up to the beginning of the line. 155 */ 156 while ((c = ch_back_get()) != '\n' && c != EOI) 157 ; 158 if (c == '\n') 159 (void) ch_forw_get(); 160 pos = ch_tell(); 161 } 162 if (show_attn) 163 set_attnpos(pos); 164 jump_loc(pos, sline); 165 } 166 167 /* 168 * Jump to a specified position in the file. 169 * The position must be the first character in a line. 170 * Place the target line on a specified line on the screen. 171 */ 172 public void 173 jump_loc(pos, sline) 174 POSITION pos; 175 int sline; 176 { 177 register int nline; 178 POSITION tpos; 179 POSITION bpos; 180 181 /* 182 * Normalize sline. 183 */ 184 sline = adjsline(sline); 185 186 if ((nline = onscreen(pos)) >= 0) 187 { 188 /* 189 * The line is currently displayed. 190 * Just scroll there. 191 */ 192 nline -= sline; 193 if (nline > 0) 194 forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0); 195 else 196 back(-nline, position(TOP), 1, 0); 197 if (show_attn) 198 repaint_hilite(1); 199 return; 200 } 201 202 /* 203 * Line is not on screen. 204 * Seek to the desired location. 205 */ 206 if (ch_seek(pos)) 207 { 208 error("Cannot seek to that file position", NULL_PARG); 209 return; 210 } 211 212 /* 213 * See if the desired line is before or after 214 * the currently displayed screen. 215 */ 216 tpos = position(TOP); 217 bpos = position(BOTTOM_PLUS_ONE); 218 if (tpos == NULL_POSITION || pos >= tpos) 219 { 220 /* 221 * The desired line is after the current screen. 222 * Move back in the file far enough so that we can 223 * call forw() and put the desired line at the 224 * sline-th line on the screen. 225 */ 226 for (nline = 0; nline < sline; nline++) 227 { 228 if (bpos != NULL_POSITION && pos <= bpos) 229 { 230 /* 231 * Surprise! The desired line is 232 * close enough to the current screen 233 * that we can just scroll there after all. 234 */ 235 forw(sc_height-sline+nline-1, bpos, 1, 0, 0); 236 if (show_attn) 237 repaint_hilite(1); 238 return; 239 } 240 pos = back_line(pos); 241 if (pos == NULL_POSITION) 242 { 243 /* 244 * Oops. Ran into the beginning of the file. 245 * Exit the loop here and rely on forw() 246 * below to draw the required number of 247 * blank lines at the top of the screen. 248 */ 249 break; 250 } 251 } 252 lastmark(); 253 hit_eof = 0; 254 squished = 0; 255 screen_trashed = 0; 256 forw(sc_height-1, pos, 1, 0, sline-nline); 257 } else 258 { 259 /* 260 * The desired line is before the current screen. 261 * Move forward in the file far enough so that we 262 * can call back() and put the desired line at the 263 * sline-th line on the screen. 264 */ 265 for (nline = sline; nline < sc_height - 1; nline++) 266 { 267 pos = forw_line(pos); 268 if (pos == NULL_POSITION) 269 { 270 /* 271 * Ran into end of file. 272 * This shouldn't normally happen, 273 * but may if there is some kind of read error. 274 */ 275 break; 276 } 277 if (pos >= tpos) 278 { 279 /* 280 * Surprise! The desired line is 281 * close enough to the current screen 282 * that we can just scroll there after all. 283 */ 284 back(nline+1, tpos, 1, 0); 285 if (show_attn) 286 repaint_hilite(1); 287 return; 288 } 289 } 290 lastmark(); 291 if (!top_scroll) 292 clear(); 293 else 294 home(); 295 screen_trashed = 0; 296 add_back_pos(pos); 297 back(sc_height-1, pos, 1, 0); 298 } 299 } 300