1 /* $OpenBSD: jump.c,v 1.2 2001/01/29 01:58:02 niklas Exp $ */ 2 3 /* 4 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice in the documentation and/or other materials provided with 14 * the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 /* 31 * Routines which jump to a new location in the file. 32 */ 33 34 #include "less.h" 35 #include "position.h" 36 37 extern int hit_eof; 38 extern int jump_sline; 39 extern int squished; 40 extern int screen_trashed; 41 extern int sc_width, sc_height; 42 43 /* 44 * Jump to the end of the file. 45 */ 46 public void 47 jump_forw() 48 { 49 POSITION pos; 50 51 if (ch_end_seek()) 52 { 53 error("Cannot seek to end of file", NULL_PARG); 54 return; 55 } 56 /* 57 * Position the last line in the file at the last screen line. 58 * Go back one line from the end of the file 59 * to get to the beginning of the last line. 60 */ 61 pos = back_line(ch_tell()); 62 if (pos == NULL_POSITION) 63 jump_loc((POSITION)0, sc_height-1); 64 else 65 jump_loc(pos, sc_height-1); 66 } 67 68 /* 69 * Jump to line n in the file. 70 */ 71 public void 72 jump_back(n) 73 int n; 74 { 75 POSITION pos; 76 PARG parg; 77 78 /* 79 * Find the position of the specified line. 80 * If we can seek there, just jump to it. 81 * If we can't seek, but we're trying to go to line number 1, 82 * use ch_beg_seek() to get as close as we can. 83 */ 84 pos = find_pos(n); 85 if (pos != NULL_POSITION && ch_seek(pos) == 0) 86 { 87 jump_loc(pos, jump_sline); 88 } else if (n <= 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_int = n; 95 error("Cannot seek to line number %d", &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) 120 int percent; 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 /* 139 * {{ This calculation may overflow! }} 140 */ 141 pos = (percent * len) / 100; 142 if (pos >= len) 143 pos = len-1; 144 145 jump_line_loc(pos, jump_sline); 146 } 147 148 /* 149 * Jump to a specified position in the file. 150 * Like jump_loc, but the position need not be 151 * the first character in a line. 152 */ 153 public void 154 jump_line_loc(pos, sline) 155 POSITION pos; 156 int sline; 157 { 158 int c; 159 160 if (ch_seek(pos) == 0) 161 { 162 /* 163 * Back up to the beginning of the line. 164 */ 165 while ((c = ch_back_get()) != '\n' && c != EOI) 166 ; 167 if (c == '\n') 168 (void) ch_forw_get(); 169 pos = ch_tell(); 170 } 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 return; 205 } 206 207 /* 208 * Line is not on screen. 209 * Seek to the desired location. 210 */ 211 if (ch_seek(pos)) 212 { 213 error("Cannot seek to that file position", NULL_PARG); 214 return; 215 } 216 217 /* 218 * See if the desired line is before or after 219 * the currently displayed screen. 220 */ 221 tpos = position(TOP); 222 bpos = position(BOTTOM_PLUS_ONE); 223 if (tpos == NULL_POSITION || pos >= tpos) 224 { 225 /* 226 * The desired line is after the current screen. 227 * Move back in the file far enough so that we can 228 * call forw() and put the desired line at the 229 * sline-th line on the screen. 230 */ 231 for (nline = 0; nline < sline; nline++) 232 { 233 if (bpos != NULL_POSITION && pos <= bpos) 234 { 235 /* 236 * Surprise! The desired line is 237 * close enough to the current screen 238 * that we can just scroll there after all. 239 */ 240 forw(sc_height-sline+nline-1, bpos, 1, 0, 0); 241 return; 242 } 243 pos = back_line(pos); 244 if (pos == NULL_POSITION) 245 { 246 /* 247 * Oops. Ran into the beginning of the file. 248 * Exit the loop here and rely on forw() 249 * below to draw the required number of 250 * blank lines at the top of the screen. 251 */ 252 break; 253 } 254 } 255 lastmark(); 256 hit_eof = 0; 257 squished = 0; 258 screen_trashed = 0; 259 forw(sc_height-1, pos, 1, 0, sline-nline); 260 } else 261 { 262 /* 263 * The desired line is before the current screen. 264 * Move forward in the file far enough so that we 265 * can call back() and put the desired line at the 266 * sline-th line on the screen. 267 */ 268 for (nline = sline; nline < sc_height - 1; nline++) 269 { 270 pos = forw_line(pos); 271 if (pos == NULL_POSITION) 272 { 273 /* 274 * Ran into end of file. 275 * This shouldn't normally happen, 276 * but may if there is some kind of read error. 277 */ 278 break; 279 } 280 if (pos >= tpos) 281 { 282 /* 283 * Surprise! The desired line is 284 * close enough to the current screen 285 * that we can just scroll there after all. 286 */ 287 back(nline+1, tpos, 1, 0); 288 return; 289 } 290 } 291 lastmark(); 292 clear(); 293 screen_trashed = 0; 294 add_back_pos(pos); 295 back(sc_height-1, pos, 1, 0); 296 } 297 } 298