1a5f0fb15SPaul Saab /* 27374caaaSXin LI * Copyright (C) 1984-2008 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 7a5f0fb15SPaul Saab * For more information about less, or for information on how to 8a5f0fb15SPaul Saab * contact the author, see the README file. 9a5f0fb15SPaul Saab */ 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab 12a5f0fb15SPaul Saab /* 13a5f0fb15SPaul Saab * Code to handle displaying line numbers. 14a5f0fb15SPaul Saab * 15a5f0fb15SPaul Saab * Finding the line number of a given file position is rather tricky. 16a5f0fb15SPaul Saab * We don't want to just start at the beginning of the file and 17a5f0fb15SPaul Saab * count newlines, because that is slow for large files (and also 18a5f0fb15SPaul Saab * wouldn't work if we couldn't get to the start of the file; e.g. 19a5f0fb15SPaul Saab * if input is a long pipe). 20a5f0fb15SPaul Saab * 21a5f0fb15SPaul Saab * So we use the function add_lnum to cache line numbers. 22a5f0fb15SPaul Saab * We try to be very clever and keep only the more interesting 23a5f0fb15SPaul Saab * line numbers when we run out of space in our table. A line 24a5f0fb15SPaul Saab * number is more interesting than another when it is far from 25a5f0fb15SPaul Saab * other line numbers. For example, we'd rather keep lines 26a5f0fb15SPaul Saab * 100,200,300 than 100,101,300. 200 is more interesting than 27a5f0fb15SPaul Saab * 101 because 101 can be derived very cheaply from 100, while 28a5f0fb15SPaul Saab * 200 is more expensive to derive from 100. 29a5f0fb15SPaul Saab * 30a5f0fb15SPaul Saab * The function currline() returns the line number of a given 31a5f0fb15SPaul Saab * position in the file. As a side effect, it calls add_lnum 32a5f0fb15SPaul Saab * to cache the line number. Therefore currline is occasionally 33a5f0fb15SPaul Saab * called to make sure we cache line numbers often enough. 34a5f0fb15SPaul Saab */ 35a5f0fb15SPaul Saab 36a5f0fb15SPaul Saab #include "less.h" 37a5f0fb15SPaul Saab 38a5f0fb15SPaul Saab /* 39a5f0fb15SPaul Saab * Structure to keep track of a line number and the associated file position. 40a5f0fb15SPaul Saab * A doubly-linked circular list of line numbers is kept ordered by line number. 41a5f0fb15SPaul Saab */ 42000ba3e8STim J. Robbins struct linenum_info 43a5f0fb15SPaul Saab { 44000ba3e8STim J. Robbins struct linenum_info *next; /* Link to next in the list */ 45000ba3e8STim J. Robbins struct linenum_info *prev; /* Line to previous in the list */ 46a5f0fb15SPaul Saab POSITION pos; /* File position */ 47a5f0fb15SPaul Saab POSITION gap; /* Gap between prev and next */ 48000ba3e8STim J. Robbins LINENUM line; /* Line number */ 49a5f0fb15SPaul Saab }; 50a5f0fb15SPaul Saab /* 51a5f0fb15SPaul Saab * "gap" needs some explanation: the gap of any particular line number 52a5f0fb15SPaul Saab * is the distance between the previous one and the next one in the list. 53a5f0fb15SPaul Saab * ("Distance" means difference in file position.) In other words, the 54a5f0fb15SPaul Saab * gap of a line number is the gap which would be introduced if this 55a5f0fb15SPaul Saab * line number were deleted. It is used to decide which one to replace 56a5f0fb15SPaul Saab * when we have a new one to insert and the table is full. 57a5f0fb15SPaul Saab */ 58a5f0fb15SPaul Saab 597374caaaSXin LI #define NPOOL 200 /* Size of line number pool */ 60a5f0fb15SPaul Saab 61a5f0fb15SPaul Saab #define LONGTIME (2) /* In seconds */ 62a5f0fb15SPaul Saab 63000ba3e8STim J. Robbins static struct linenum_info anchor; /* Anchor of the list */ 64000ba3e8STim J. Robbins static struct linenum_info *freelist; /* Anchor of the unused entries */ 65000ba3e8STim J. Robbins static struct linenum_info pool[NPOOL]; /* The pool itself */ 66000ba3e8STim J. Robbins static struct linenum_info *spare; /* We always keep one spare entry */ 67a5f0fb15SPaul Saab 68a5f0fb15SPaul Saab extern int linenums; 69a5f0fb15SPaul Saab extern int sigs; 70a5f0fb15SPaul Saab extern int sc_height; 717374caaaSXin LI extern int screen_trashed; 72a5f0fb15SPaul Saab 73a5f0fb15SPaul Saab /* 74a5f0fb15SPaul Saab * Initialize the line number structures. 75a5f0fb15SPaul Saab */ 76a5f0fb15SPaul Saab public void 77a5f0fb15SPaul Saab clr_linenum() 78a5f0fb15SPaul Saab { 79000ba3e8STim J. Robbins register struct linenum_info *p; 80a5f0fb15SPaul Saab 81a5f0fb15SPaul Saab /* 82a5f0fb15SPaul Saab * Put all the entries on the free list. 83a5f0fb15SPaul Saab * Leave one for the "spare". 84a5f0fb15SPaul Saab */ 85a5f0fb15SPaul Saab for (p = pool; p < &pool[NPOOL-2]; p++) 86a5f0fb15SPaul Saab p->next = p+1; 87a5f0fb15SPaul Saab pool[NPOOL-2].next = NULL; 88a5f0fb15SPaul Saab freelist = pool; 89a5f0fb15SPaul Saab 90a5f0fb15SPaul Saab spare = &pool[NPOOL-1]; 91a5f0fb15SPaul Saab 92a5f0fb15SPaul Saab /* 93a5f0fb15SPaul Saab * Initialize the anchor. 94a5f0fb15SPaul Saab */ 95a5f0fb15SPaul Saab anchor.next = anchor.prev = &anchor; 96a5f0fb15SPaul Saab anchor.gap = 0; 97a5f0fb15SPaul Saab anchor.pos = (POSITION)0; 98a5f0fb15SPaul Saab anchor.line = 1; 99a5f0fb15SPaul Saab } 100a5f0fb15SPaul Saab 101a5f0fb15SPaul Saab /* 102a5f0fb15SPaul Saab * Calculate the gap for an entry. 103a5f0fb15SPaul Saab */ 104a5f0fb15SPaul Saab static void 105a5f0fb15SPaul Saab calcgap(p) 106000ba3e8STim J. Robbins register struct linenum_info *p; 107a5f0fb15SPaul Saab { 108a5f0fb15SPaul Saab /* 109a5f0fb15SPaul Saab * Don't bother to compute a gap for the anchor. 110a5f0fb15SPaul Saab * Also don't compute a gap for the last one in the list. 111a5f0fb15SPaul Saab * The gap for that last one should be considered infinite, 112a5f0fb15SPaul Saab * but we never look at it anyway. 113a5f0fb15SPaul Saab */ 114a5f0fb15SPaul Saab if (p == &anchor || p->next == &anchor) 115a5f0fb15SPaul Saab return; 116a5f0fb15SPaul Saab p->gap = p->next->pos - p->prev->pos; 117a5f0fb15SPaul Saab } 118a5f0fb15SPaul Saab 119a5f0fb15SPaul Saab /* 120a5f0fb15SPaul Saab * Add a new line number to the cache. 121a5f0fb15SPaul Saab * The specified position (pos) should be the file position of the 122a5f0fb15SPaul Saab * FIRST character in the specified line. 123a5f0fb15SPaul Saab */ 124a5f0fb15SPaul Saab public void 125000ba3e8STim J. Robbins add_lnum(linenum, pos) 126000ba3e8STim J. Robbins LINENUM linenum; 127a5f0fb15SPaul Saab POSITION pos; 128a5f0fb15SPaul Saab { 129000ba3e8STim J. Robbins register struct linenum_info *p; 130000ba3e8STim J. Robbins register struct linenum_info *new; 131000ba3e8STim J. Robbins register struct linenum_info *nextp; 132000ba3e8STim J. Robbins register struct linenum_info *prevp; 133a5f0fb15SPaul Saab register POSITION mingap; 134a5f0fb15SPaul Saab 135a5f0fb15SPaul Saab /* 136a5f0fb15SPaul Saab * Find the proper place in the list for the new one. 137a5f0fb15SPaul Saab * The entries are sorted by position. 138a5f0fb15SPaul Saab */ 139a5f0fb15SPaul Saab for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) 140000ba3e8STim J. Robbins if (p->line == linenum) 141a5f0fb15SPaul Saab /* We already have this one. */ 142a5f0fb15SPaul Saab return; 143a5f0fb15SPaul Saab nextp = p; 144a5f0fb15SPaul Saab prevp = p->prev; 145a5f0fb15SPaul Saab 146a5f0fb15SPaul Saab if (freelist != NULL) 147a5f0fb15SPaul Saab { 148a5f0fb15SPaul Saab /* 149a5f0fb15SPaul Saab * We still have free (unused) entries. 150a5f0fb15SPaul Saab * Use one of them. 151a5f0fb15SPaul Saab */ 152a5f0fb15SPaul Saab new = freelist; 153a5f0fb15SPaul Saab freelist = freelist->next; 154a5f0fb15SPaul Saab } else 155a5f0fb15SPaul Saab { 156a5f0fb15SPaul Saab /* 157a5f0fb15SPaul Saab * No free entries. 158a5f0fb15SPaul Saab * Use the "spare" entry. 159a5f0fb15SPaul Saab */ 160a5f0fb15SPaul Saab new = spare; 161a5f0fb15SPaul Saab spare = NULL; 162a5f0fb15SPaul Saab } 163a5f0fb15SPaul Saab 164a5f0fb15SPaul Saab /* 165a5f0fb15SPaul Saab * Fill in the fields of the new entry, 166a5f0fb15SPaul Saab * and insert it into the proper place in the list. 167a5f0fb15SPaul Saab */ 168a5f0fb15SPaul Saab new->next = nextp; 169a5f0fb15SPaul Saab new->prev = prevp; 170a5f0fb15SPaul Saab new->pos = pos; 171000ba3e8STim J. Robbins new->line = linenum; 172a5f0fb15SPaul Saab 173a5f0fb15SPaul Saab nextp->prev = new; 174a5f0fb15SPaul Saab prevp->next = new; 175a5f0fb15SPaul Saab 176a5f0fb15SPaul Saab /* 177a5f0fb15SPaul Saab * Recalculate gaps for the new entry and the neighboring entries. 178a5f0fb15SPaul Saab */ 179a5f0fb15SPaul Saab calcgap(new); 180a5f0fb15SPaul Saab calcgap(nextp); 181a5f0fb15SPaul Saab calcgap(prevp); 182a5f0fb15SPaul Saab 183a5f0fb15SPaul Saab if (spare == NULL) 184a5f0fb15SPaul Saab { 185a5f0fb15SPaul Saab /* 186a5f0fb15SPaul Saab * We have used the spare entry. 187a5f0fb15SPaul Saab * Scan the list to find the one with the smallest 188a5f0fb15SPaul Saab * gap, take it out and make it the spare. 189a5f0fb15SPaul Saab * We should never remove the last one, so stop when 190a5f0fb15SPaul Saab * we get to p->next == &anchor. This also avoids 191a5f0fb15SPaul Saab * looking at the gap of the last one, which is 192a5f0fb15SPaul Saab * not computed by calcgap. 193a5f0fb15SPaul Saab */ 194a5f0fb15SPaul Saab mingap = anchor.next->gap; 195a5f0fb15SPaul Saab for (p = anchor.next; p->next != &anchor; p = p->next) 196a5f0fb15SPaul Saab { 197a5f0fb15SPaul Saab if (p->gap <= mingap) 198a5f0fb15SPaul Saab { 199a5f0fb15SPaul Saab spare = p; 200a5f0fb15SPaul Saab mingap = p->gap; 201a5f0fb15SPaul Saab } 202a5f0fb15SPaul Saab } 203a5f0fb15SPaul Saab spare->next->prev = spare->prev; 204a5f0fb15SPaul Saab spare->prev->next = spare->next; 205a5f0fb15SPaul Saab } 206a5f0fb15SPaul Saab } 207a5f0fb15SPaul Saab 208a5f0fb15SPaul Saab /* 209a5f0fb15SPaul Saab * If we get stuck in a long loop trying to figure out the 210a5f0fb15SPaul Saab * line number, print a message to tell the user what we're doing. 211a5f0fb15SPaul Saab */ 212a5f0fb15SPaul Saab static void 213a5f0fb15SPaul Saab longloopmessage() 214a5f0fb15SPaul Saab { 215a5f0fb15SPaul Saab ierror("Calculating line numbers", NULL_PARG); 216a5f0fb15SPaul Saab } 217a5f0fb15SPaul Saab 218a5f0fb15SPaul Saab static int loopcount; 219a5f0fb15SPaul Saab #if HAVE_TIME 220a5f0fb15SPaul Saab static long startime; 221a5f0fb15SPaul Saab #endif 222a5f0fb15SPaul Saab 223a5f0fb15SPaul Saab static void 224a5f0fb15SPaul Saab longish() 225a5f0fb15SPaul Saab { 226a5f0fb15SPaul Saab #if HAVE_TIME 227a5f0fb15SPaul Saab if (loopcount >= 0 && ++loopcount > 100) 228a5f0fb15SPaul Saab { 229a5f0fb15SPaul Saab loopcount = 0; 230a5f0fb15SPaul Saab if (get_time() >= startime + LONGTIME) 231a5f0fb15SPaul Saab { 232a5f0fb15SPaul Saab longloopmessage(); 233a5f0fb15SPaul Saab loopcount = -1; 234a5f0fb15SPaul Saab } 235a5f0fb15SPaul Saab } 236a5f0fb15SPaul Saab #else 237a5f0fb15SPaul Saab if (loopcount >= 0 && ++loopcount > LONGLOOP) 238a5f0fb15SPaul Saab { 239a5f0fb15SPaul Saab longloopmessage(); 240a5f0fb15SPaul Saab loopcount = -1; 241a5f0fb15SPaul Saab } 242a5f0fb15SPaul Saab #endif 243a5f0fb15SPaul Saab } 244a5f0fb15SPaul Saab 245a5f0fb15SPaul Saab /* 2467374caaaSXin LI * Turn off line numbers because the user has interrupted 2477374caaaSXin LI * a lengthy line number calculation. 2487374caaaSXin LI */ 2497374caaaSXin LI static void 2507374caaaSXin LI abort_long() 2517374caaaSXin LI { 2527374caaaSXin LI if (linenums == OPT_ONPLUS) 2537374caaaSXin LI /* 2547374caaaSXin LI * We were displaying line numbers, so need to repaint. 2557374caaaSXin LI */ 2567374caaaSXin LI screen_trashed = 1; 2577374caaaSXin LI linenums = 0; 2587374caaaSXin LI error("Line numbers turned off", NULL_PARG); 2597374caaaSXin LI } 2607374caaaSXin LI 2617374caaaSXin LI /* 262a5f0fb15SPaul Saab * Find the line number associated with a given position. 263a5f0fb15SPaul Saab * Return 0 if we can't figure it out. 264a5f0fb15SPaul Saab */ 265000ba3e8STim J. Robbins public LINENUM 266a5f0fb15SPaul Saab find_linenum(pos) 267a5f0fb15SPaul Saab POSITION pos; 268a5f0fb15SPaul Saab { 269000ba3e8STim J. Robbins register struct linenum_info *p; 270000ba3e8STim J. Robbins register LINENUM linenum; 271a5f0fb15SPaul Saab POSITION cpos; 272a5f0fb15SPaul Saab 273a5f0fb15SPaul Saab if (!linenums) 274a5f0fb15SPaul Saab /* 275a5f0fb15SPaul Saab * We're not using line numbers. 276a5f0fb15SPaul Saab */ 277a5f0fb15SPaul Saab return (0); 278a5f0fb15SPaul Saab if (pos == NULL_POSITION) 279a5f0fb15SPaul Saab /* 280a5f0fb15SPaul Saab * Caller doesn't know what he's talking about. 281a5f0fb15SPaul Saab */ 282a5f0fb15SPaul Saab return (0); 283a5f0fb15SPaul Saab if (pos <= ch_zero()) 284a5f0fb15SPaul Saab /* 285a5f0fb15SPaul Saab * Beginning of file is always line number 1. 286a5f0fb15SPaul Saab */ 287a5f0fb15SPaul Saab return (1); 288a5f0fb15SPaul Saab 289a5f0fb15SPaul Saab /* 290a5f0fb15SPaul Saab * Find the entry nearest to the position we want. 291a5f0fb15SPaul Saab */ 292a5f0fb15SPaul Saab for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) 293a5f0fb15SPaul Saab continue; 294a5f0fb15SPaul Saab if (p->pos == pos) 295a5f0fb15SPaul Saab /* Found it exactly. */ 296a5f0fb15SPaul Saab return (p->line); 297a5f0fb15SPaul Saab 298a5f0fb15SPaul Saab /* 299a5f0fb15SPaul Saab * This is the (possibly) time-consuming part. 300a5f0fb15SPaul Saab * We start at the line we just found and start 301a5f0fb15SPaul Saab * reading the file forward or backward till we 302a5f0fb15SPaul Saab * get to the place we want. 303a5f0fb15SPaul Saab * 304a5f0fb15SPaul Saab * First decide whether we should go forward from the 305a5f0fb15SPaul Saab * previous one or backwards from the next one. 306a5f0fb15SPaul Saab * The decision is based on which way involves 307a5f0fb15SPaul Saab * traversing fewer bytes in the file. 308a5f0fb15SPaul Saab */ 309a5f0fb15SPaul Saab #if HAVE_TIME 310a5f0fb15SPaul Saab startime = get_time(); 311a5f0fb15SPaul Saab #endif 312a5f0fb15SPaul Saab if (p == &anchor || pos - p->prev->pos < p->pos - pos) 313a5f0fb15SPaul Saab { 314a5f0fb15SPaul Saab /* 315a5f0fb15SPaul Saab * Go forward. 316a5f0fb15SPaul Saab */ 317a5f0fb15SPaul Saab p = p->prev; 318a5f0fb15SPaul Saab if (ch_seek(p->pos)) 319a5f0fb15SPaul Saab return (0); 320a5f0fb15SPaul Saab loopcount = 0; 321000ba3e8STim J. Robbins for (linenum = p->line, cpos = p->pos; cpos < pos; linenum++) 322a5f0fb15SPaul Saab { 323a5f0fb15SPaul Saab /* 324a5f0fb15SPaul Saab * Allow a signal to abort this loop. 325a5f0fb15SPaul Saab */ 3267f074f9cSXin LI cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); 3277374caaaSXin LI if (ABORT_SIGS()) { 3287374caaaSXin LI abort_long(); 3297374caaaSXin LI return (0); 3307374caaaSXin LI } 3317374caaaSXin LI if (cpos == NULL_POSITION) 332a5f0fb15SPaul Saab return (0); 333a5f0fb15SPaul Saab longish(); 334a5f0fb15SPaul Saab } 335a5f0fb15SPaul Saab /* 336a5f0fb15SPaul Saab * We might as well cache it. 337a5f0fb15SPaul Saab */ 338000ba3e8STim J. Robbins add_lnum(linenum, cpos); 339a5f0fb15SPaul Saab /* 340a5f0fb15SPaul Saab * If the given position is not at the start of a line, 341a5f0fb15SPaul Saab * make sure we return the correct line number. 342a5f0fb15SPaul Saab */ 343a5f0fb15SPaul Saab if (cpos > pos) 344000ba3e8STim J. Robbins linenum--; 345a5f0fb15SPaul Saab } else 346a5f0fb15SPaul Saab { 347a5f0fb15SPaul Saab /* 348a5f0fb15SPaul Saab * Go backward. 349a5f0fb15SPaul Saab */ 350a5f0fb15SPaul Saab if (ch_seek(p->pos)) 351a5f0fb15SPaul Saab return (0); 352a5f0fb15SPaul Saab loopcount = 0; 353000ba3e8STim J. Robbins for (linenum = p->line, cpos = p->pos; cpos > pos; linenum--) 354a5f0fb15SPaul Saab { 355a5f0fb15SPaul Saab /* 356a5f0fb15SPaul Saab * Allow a signal to abort this loop. 357a5f0fb15SPaul Saab */ 3587f074f9cSXin LI cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); 3597374caaaSXin LI if (ABORT_SIGS()) { 3607374caaaSXin LI abort_long(); 3617374caaaSXin LI return (0); 3627374caaaSXin LI } 3637374caaaSXin LI if (cpos == NULL_POSITION) 364a5f0fb15SPaul Saab return (0); 365a5f0fb15SPaul Saab longish(); 366a5f0fb15SPaul Saab } 367a5f0fb15SPaul Saab /* 368a5f0fb15SPaul Saab * We might as well cache it. 369a5f0fb15SPaul Saab */ 370000ba3e8STim J. Robbins add_lnum(linenum, cpos); 371a5f0fb15SPaul Saab } 372a5f0fb15SPaul Saab 373000ba3e8STim J. Robbins return (linenum); 374a5f0fb15SPaul Saab } 375a5f0fb15SPaul Saab 376a5f0fb15SPaul Saab /* 377a5f0fb15SPaul Saab * Find the position of a given line number. 378a5f0fb15SPaul Saab * Return NULL_POSITION if we can't figure it out. 379a5f0fb15SPaul Saab */ 380a5f0fb15SPaul Saab public POSITION 381000ba3e8STim J. Robbins find_pos(linenum) 382000ba3e8STim J. Robbins LINENUM linenum; 383a5f0fb15SPaul Saab { 384000ba3e8STim J. Robbins register struct linenum_info *p; 385a5f0fb15SPaul Saab POSITION cpos; 386000ba3e8STim J. Robbins LINENUM clinenum; 387a5f0fb15SPaul Saab 388000ba3e8STim J. Robbins if (linenum <= 1) 389a5f0fb15SPaul Saab /* 390a5f0fb15SPaul Saab * Line number 1 is beginning of file. 391a5f0fb15SPaul Saab */ 392a5f0fb15SPaul Saab return (ch_zero()); 393a5f0fb15SPaul Saab 394a5f0fb15SPaul Saab /* 395a5f0fb15SPaul Saab * Find the entry nearest to the line number we want. 396a5f0fb15SPaul Saab */ 397000ba3e8STim J. Robbins for (p = anchor.next; p != &anchor && p->line < linenum; p = p->next) 398a5f0fb15SPaul Saab continue; 399000ba3e8STim J. Robbins if (p->line == linenum) 400a5f0fb15SPaul Saab /* Found it exactly. */ 401a5f0fb15SPaul Saab return (p->pos); 402a5f0fb15SPaul Saab 403000ba3e8STim J. Robbins if (p == &anchor || linenum - p->prev->line < p->line - linenum) 404a5f0fb15SPaul Saab { 405a5f0fb15SPaul Saab /* 406a5f0fb15SPaul Saab * Go forward. 407a5f0fb15SPaul Saab */ 408a5f0fb15SPaul Saab p = p->prev; 409a5f0fb15SPaul Saab if (ch_seek(p->pos)) 410a5f0fb15SPaul Saab return (NULL_POSITION); 411000ba3e8STim J. Robbins for (clinenum = p->line, cpos = p->pos; clinenum < linenum; clinenum++) 412a5f0fb15SPaul Saab { 413a5f0fb15SPaul Saab /* 414a5f0fb15SPaul Saab * Allow a signal to abort this loop. 415a5f0fb15SPaul Saab */ 4167f074f9cSXin LI cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); 4177374caaaSXin LI if (ABORT_SIGS()) 4187374caaaSXin LI return (NULL_POSITION); 4197374caaaSXin LI if (cpos == NULL_POSITION) 420a5f0fb15SPaul Saab return (NULL_POSITION); 421a5f0fb15SPaul Saab } 422a5f0fb15SPaul Saab } else 423a5f0fb15SPaul Saab { 424a5f0fb15SPaul Saab /* 425a5f0fb15SPaul Saab * Go backward. 426a5f0fb15SPaul Saab */ 427a5f0fb15SPaul Saab if (ch_seek(p->pos)) 428a5f0fb15SPaul Saab return (NULL_POSITION); 429000ba3e8STim J. Robbins for (clinenum = p->line, cpos = p->pos; clinenum > linenum; clinenum--) 430a5f0fb15SPaul Saab { 431a5f0fb15SPaul Saab /* 432a5f0fb15SPaul Saab * Allow a signal to abort this loop. 433a5f0fb15SPaul Saab */ 4347f074f9cSXin LI cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); 4357374caaaSXin LI if (ABORT_SIGS()) 4367374caaaSXin LI return (NULL_POSITION); 4377374caaaSXin LI if (cpos == NULL_POSITION) 438a5f0fb15SPaul Saab return (NULL_POSITION); 439a5f0fb15SPaul Saab } 440a5f0fb15SPaul Saab } 441a5f0fb15SPaul Saab /* 442a5f0fb15SPaul Saab * We might as well cache it. 443a5f0fb15SPaul Saab */ 444000ba3e8STim J. Robbins add_lnum(clinenum, cpos); 445a5f0fb15SPaul Saab return (cpos); 446a5f0fb15SPaul Saab } 447a5f0fb15SPaul Saab 448a5f0fb15SPaul Saab /* 449a5f0fb15SPaul Saab * Return the line number of the "current" line. 450a5f0fb15SPaul Saab * The argument "where" tells which line is to be considered 451a5f0fb15SPaul Saab * the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc). 452a5f0fb15SPaul Saab */ 453000ba3e8STim J. Robbins public LINENUM 454a5f0fb15SPaul Saab currline(where) 455a5f0fb15SPaul Saab int where; 456a5f0fb15SPaul Saab { 457a5f0fb15SPaul Saab POSITION pos; 458a5f0fb15SPaul Saab POSITION len; 459000ba3e8STim J. Robbins LINENUM linenum; 460a5f0fb15SPaul Saab 461a5f0fb15SPaul Saab pos = position(where); 462a5f0fb15SPaul Saab len = ch_length(); 463a5f0fb15SPaul Saab while (pos == NULL_POSITION && where >= 0 && where < sc_height) 464a5f0fb15SPaul Saab pos = position(++where); 465a5f0fb15SPaul Saab if (pos == NULL_POSITION) 466a5f0fb15SPaul Saab pos = len; 467000ba3e8STim J. Robbins linenum = find_linenum(pos); 468a5f0fb15SPaul Saab if (pos == len) 469000ba3e8STim J. Robbins linenum--; 470000ba3e8STim J. Robbins return (linenum); 471a5f0fb15SPaul Saab } 472