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