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