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