version 1.3, 2001/11/19 19:02:14 |
version 1.4, 2003/04/13 18:26:26 |
|
|
/* $OpenBSD$ */ |
|
|
|
/* |
/* |
* Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman |
* Copyright (C) 1984-2002 Mark Nudelman |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* You may distribute under the terms of either the GNU General Public |
* modification, are permitted provided that the following conditions |
* License or the Less License, as specified in the README file. |
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice in the documentation and/or other materials provided with |
|
* the distribution. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
* For more information about less, or for information on how to |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* contact the author, see the README file. |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
|
|
|
|
*/ |
*/ |
|
|
#include "less.h" |
#include "less.h" |
#include "position.h" |
|
|
|
/* |
/* |
* Structure to keep track of a line number and the associated file position. |
* Structure to keep track of a line number and the associated file position. |
* A doubly-linked circular list of line numbers is kept ordered by line number. |
* A doubly-linked circular list of line numbers is kept ordered by line number. |
*/ |
*/ |
struct linenum |
struct linenum_info |
{ |
{ |
struct linenum *next; /* Link to next in the list */ |
struct linenum_info *next; /* Link to next in the list */ |
struct linenum *prev; /* Line to previous in the list */ |
struct linenum_info *prev; /* Line to previous in the list */ |
POSITION pos; /* File position */ |
POSITION pos; /* File position */ |
POSITION gap; /* Gap between prev and next */ |
POSITION gap; /* Gap between prev and next */ |
int line; /* Line number */ |
LINENUM line; /* Line number */ |
}; |
}; |
/* |
/* |
* "gap" needs some explanation: the gap of any particular line number |
* "gap" needs some explanation: the gap of any particular line number |
|
|
|
|
public int lnloop = 0; /* Are we in the line num loop? */ |
public int lnloop = 0; /* Are we in the line num loop? */ |
|
|
static struct linenum anchor; /* Anchor of the list */ |
static struct linenum_info anchor; /* Anchor of the list */ |
static struct linenum *freelist; /* Anchor of the unused entries */ |
static struct linenum_info *freelist; /* Anchor of the unused entries */ |
static struct linenum pool[NPOOL]; /* The pool itself */ |
static struct linenum_info pool[NPOOL]; /* The pool itself */ |
static struct linenum *spare; /* We always keep one spare entry */ |
static struct linenum_info *spare; /* We always keep one spare entry */ |
|
|
extern int linenums; |
extern int linenums; |
extern int sigs; |
extern int sigs; |
|
|
public void |
public void |
clr_linenum() |
clr_linenum() |
{ |
{ |
struct linenum *p; |
register struct linenum_info *p; |
|
|
/* |
/* |
* Put all the entries on the free list. |
* Put all the entries on the free list. |
|
|
*/ |
*/ |
static void |
static void |
calcgap(p) |
calcgap(p) |
struct linenum *p; |
register struct linenum_info *p; |
{ |
{ |
/* |
/* |
* Don't bother to compute a gap for the anchor. |
* Don't bother to compute a gap for the anchor. |
|
|
* FIRST character in the specified line. |
* FIRST character in the specified line. |
*/ |
*/ |
public void |
public void |
add_lnum(lno, pos) |
add_lnum(linenum, pos) |
int lno; |
LINENUM linenum; |
POSITION pos; |
POSITION pos; |
{ |
{ |
struct linenum *p; |
register struct linenum_info *p; |
struct linenum *new; |
register struct linenum_info *new; |
struct linenum *nextp; |
register struct linenum_info *nextp; |
struct linenum *prevp; |
register struct linenum_info *prevp; |
POSITION mingap; |
register POSITION mingap; |
|
|
/* |
/* |
* Find the proper place in the list for the new one. |
* Find the proper place in the list for the new one. |
* The entries are sorted by position. |
* The entries are sorted by position. |
*/ |
*/ |
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) |
for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) |
if (p->line == lno) |
if (p->line == linenum) |
/* We already have this one. */ |
/* We already have this one. */ |
return; |
return; |
nextp = p; |
nextp = p; |
|
|
new->next = nextp; |
new->next = nextp; |
new->prev = prevp; |
new->prev = prevp; |
new->pos = pos; |
new->pos = pos; |
new->line = lno; |
new->line = linenum; |
|
|
nextp->prev = new; |
nextp->prev = new; |
prevp->next = new; |
prevp->next = new; |
|
|
* Find the line number associated with a given position. |
* Find the line number associated with a given position. |
* Return 0 if we can't figure it out. |
* Return 0 if we can't figure it out. |
*/ |
*/ |
public int |
public LINENUM |
find_linenum(pos) |
find_linenum(pos) |
POSITION pos; |
POSITION pos; |
{ |
{ |
struct linenum *p; |
register struct linenum_info *p; |
int lno; |
register LINENUM linenum; |
POSITION cpos; |
POSITION cpos; |
|
|
if (!linenums) |
if (!linenums) |
|
|
* The decision is based on which way involves |
* The decision is based on which way involves |
* traversing fewer bytes in the file. |
* traversing fewer bytes in the file. |
*/ |
*/ |
flush(); |
|
#if HAVE_TIME |
#if HAVE_TIME |
startime = get_time(); |
startime = get_time(); |
#endif |
#endif |
|
|
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (0); |
return (0); |
loopcount = 0; |
loopcount = 0; |
for (lno = p->line, cpos = p->pos; cpos < pos; lno++) |
for (linenum = p->line, cpos = p->pos; cpos < pos; linenum++) |
{ |
{ |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
|
|
/* |
/* |
* We might as well cache it. |
* We might as well cache it. |
*/ |
*/ |
add_lnum(lno, cpos); |
add_lnum(linenum, cpos); |
/* |
/* |
* If the given position is not at the start of a line, |
* If the given position is not at the start of a line, |
* make sure we return the correct line number. |
* make sure we return the correct line number. |
*/ |
*/ |
if (cpos > pos) |
if (cpos > pos) |
lno--; |
linenum--; |
} else |
} else |
{ |
{ |
/* |
/* |
|
|
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (0); |
return (0); |
loopcount = 0; |
loopcount = 0; |
for (lno = p->line, cpos = p->pos; cpos > pos; lno--) |
for (linenum = p->line, cpos = p->pos; cpos > pos; linenum--) |
{ |
{ |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
|
|
/* |
/* |
* We might as well cache it. |
* We might as well cache it. |
*/ |
*/ |
add_lnum(lno, cpos); |
add_lnum(linenum, cpos); |
} |
} |
|
|
return (lno); |
return (linenum); |
} |
} |
|
|
/* |
/* |
|
|
* Return NULL_POSITION if we can't figure it out. |
* Return NULL_POSITION if we can't figure it out. |
*/ |
*/ |
public POSITION |
public POSITION |
find_pos(lno) |
find_pos(linenum) |
int lno; |
LINENUM linenum; |
{ |
{ |
struct linenum *p; |
register struct linenum_info *p; |
POSITION cpos; |
POSITION cpos; |
int clno; |
LINENUM clinenum; |
|
|
if (lno <= 1) |
if (linenum <= 1) |
/* |
/* |
* Line number 1 is beginning of file. |
* Line number 1 is beginning of file. |
*/ |
*/ |
|
|
/* |
/* |
* Find the entry nearest to the line number we want. |
* Find the entry nearest to the line number we want. |
*/ |
*/ |
for (p = anchor.next; p != &anchor && p->line < lno; p = p->next) |
for (p = anchor.next; p != &anchor && p->line < linenum; p = p->next) |
continue; |
continue; |
if (p->line == lno) |
if (p->line == linenum) |
/* Found it exactly. */ |
/* Found it exactly. */ |
return (p->pos); |
return (p->pos); |
|
|
flush(); |
if (p == &anchor || linenum - p->prev->line < p->line - linenum) |
if (p == &anchor || lno - p->prev->line < p->line - lno) |
|
{ |
{ |
/* |
/* |
* Go forward. |
* Go forward. |
|
|
p = p->prev; |
p = p->prev; |
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (NULL_POSITION); |
return (NULL_POSITION); |
for (clno = p->line, cpos = p->pos; clno < lno; clno++) |
for (clinenum = p->line, cpos = p->pos; clinenum < linenum; clinenum++) |
{ |
{ |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
|
|
*/ |
*/ |
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (NULL_POSITION); |
return (NULL_POSITION); |
for (clno = p->line, cpos = p->pos; clno > lno; clno--) |
for (clinenum = p->line, cpos = p->pos; clinenum > linenum; clinenum--) |
{ |
{ |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
|
|
/* |
/* |
* We might as well cache it. |
* We might as well cache it. |
*/ |
*/ |
add_lnum(clno, cpos); |
add_lnum(clinenum, cpos); |
return (cpos); |
return (cpos); |
} |
} |
|
|
|
|
* The argument "where" tells which line is to be considered |
* The argument "where" tells which line is to be considered |
* the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc). |
* the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc). |
*/ |
*/ |
public int |
public LINENUM |
currline(where) |
currline(where) |
int where; |
int where; |
{ |
{ |
POSITION pos; |
POSITION pos; |
POSITION len; |
POSITION len; |
int lnum; |
LINENUM linenum; |
|
|
pos = position(where); |
pos = position(where); |
len = ch_length(); |
len = ch_length(); |
|
|
pos = position(++where); |
pos = position(++where); |
if (pos == NULL_POSITION) |
if (pos == NULL_POSITION) |
pos = len; |
pos = len; |
lnum = find_linenum(pos); |
linenum = find_linenum(pos); |
if (pos == len) |
if (pos == len) |
lnum--; |
linenum--; |
return (lnum); |
return (linenum); |
} |
} |