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