version 1.7, 2014/04/25 13:38:21 |
version 1.8, 2015/11/05 22:08:44 |
|
|
* |
* |
* For more information, see the README file. |
* For more information, see the README file. |
*/ |
*/ |
|
/* |
|
* Modified for use with illumos. |
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
|
*/ |
|
|
|
|
/* |
/* |
* Code to handle displaying line numbers. |
* Code to handle displaying line numbers. |
* |
* |
|
|
{ |
{ |
struct linenum_info *next; /* Link to next in the list */ |
struct linenum_info *next; /* Link to next in the list */ |
struct linenum_info *prev; /* Line to previous in the list */ |
struct linenum_info *prev; /* Line to previous in the list */ |
POSITION pos; /* File position */ |
off_t pos; /* File position */ |
POSITION gap; /* Gap between prev and next */ |
off_t gap; /* Gap between prev and next */ |
LINENUM line; /* Line number */ |
LINENUM line; /* Line number */ |
}; |
}; |
/* |
/* |
|
|
static struct linenum_info anchor; /* Anchor of the list */ |
static struct linenum_info anchor; /* Anchor of the list */ |
static struct linenum_info *freelist; /* Anchor of the unused entries */ |
static struct linenum_info *freelist; /* Anchor of the unused entries */ |
static struct linenum_info pool[NPOOL]; /* The pool itself */ |
static struct linenum_info pool[NPOOL]; /* The pool itself */ |
static struct linenum_info *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 volatile sig_atomic_t sigs; |
extern volatile sig_atomic_t sigs; |
|
|
/* |
/* |
* Initialize the line number structures. |
* Initialize the line number structures. |
*/ |
*/ |
public void |
void |
clr_linenum() |
clr_linenum(void) |
{ |
{ |
register struct linenum_info *p; |
struct linenum_info *p; |
|
|
/* |
/* |
* Put all the entries on the free list. |
* Put all the entries on the free list. |
|
|
*/ |
*/ |
anchor.next = anchor.prev = &anchor; |
anchor.next = anchor.prev = &anchor; |
anchor.gap = 0; |
anchor.gap = 0; |
anchor.pos = (POSITION)0; |
anchor.pos = 0; |
anchor.line = 1; |
anchor.line = 1; |
} |
} |
|
|
/* |
/* |
* Calculate the gap for an entry. |
* Calculate the gap for an entry. |
*/ |
*/ |
static void |
static void |
calcgap(p) |
calcgap(struct linenum_info *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. |
|
|
* The specified position (pos) should be the file position of the |
* The specified position (pos) should be the file position of the |
* FIRST character in the specified line. |
* FIRST character in the specified line. |
*/ |
*/ |
public void |
void |
add_lnum(linenum, pos) |
add_lnum(LINENUM linenum, off_t pos) |
LINENUM linenum; |
|
POSITION pos; |
|
{ |
{ |
register struct linenum_info *p; |
struct linenum_info *p; |
register struct linenum_info *new; |
struct linenum_info *new; |
register struct linenum_info *nextp; |
struct linenum_info *nextp; |
register struct linenum_info *prevp; |
struct linenum_info *prevp; |
register POSITION mingap; |
off_t mingap; |
|
|
/* |
/* |
* Find the proper place in the list for the new one. |
* Find the proper place in the list for the new one. |
|
|
nextp = p; |
nextp = p; |
prevp = p->prev; |
prevp = p->prev; |
|
|
if (freelist != NULL) |
if (freelist != NULL) { |
{ |
|
/* |
/* |
* We still have free (unused) entries. |
* We still have free (unused) entries. |
* Use one of them. |
* Use one of them. |
*/ |
*/ |
new = freelist; |
new = freelist; |
freelist = freelist->next; |
freelist = freelist->next; |
} else |
} else { |
{ |
|
/* |
/* |
* No free entries. |
* No free entries. |
* Use the "spare" entry. |
* Use the "spare" entry. |
|
|
calcgap(nextp); |
calcgap(nextp); |
calcgap(prevp); |
calcgap(prevp); |
|
|
if (spare == NULL) |
if (spare == NULL) { |
{ |
|
/* |
/* |
* We have used the spare entry. |
* We have used the spare entry. |
* Scan the list to find the one with the smallest |
* Scan the list to find the one with the smallest |
|
|
* not computed by calcgap. |
* not computed by calcgap. |
*/ |
*/ |
mingap = anchor.next->gap; |
mingap = anchor.next->gap; |
for (p = anchor.next; p->next != &anchor; p = p->next) |
for (p = anchor.next; p->next != &anchor; p = p->next) { |
{ |
if (p->gap <= mingap) { |
if (p->gap <= mingap) |
|
{ |
|
spare = p; |
spare = p; |
mingap = p->gap; |
mingap = p->gap; |
} |
} |
|
|
* If we get stuck in a long loop trying to figure out the |
* If we get stuck in a long loop trying to figure out the |
* line number, print a message to tell the user what we're doing. |
* line number, print a message to tell the user what we're doing. |
*/ |
*/ |
static void |
static void |
longloopmessage() |
longloopmessage(void) |
{ |
{ |
ierror("Calculating line numbers", NULL_PARG); |
ierror("Calculating line numbers", NULL_PARG); |
} |
} |
|
|
static int loopcount; |
static int loopcount; |
#if HAVE_TIME |
|
static long startime; |
static long startime; |
#endif |
|
|
|
static void |
static void |
longish() |
longish(void) |
{ |
{ |
#if HAVE_TIME |
if (loopcount >= 0 && ++loopcount > 100) { |
if (loopcount >= 0 && ++loopcount > 100) |
|
{ |
|
loopcount = 0; |
loopcount = 0; |
if (get_time() >= startime + LONGTIME) |
if (get_time() >= startime + LONGTIME) { |
{ |
|
longloopmessage(); |
longloopmessage(); |
loopcount = -1; |
loopcount = -1; |
} |
} |
} |
} |
#else |
|
if (loopcount >= 0 && ++loopcount > LONGLOOP) |
|
{ |
|
longloopmessage(); |
|
loopcount = -1; |
|
} |
|
#endif |
|
} |
} |
|
|
/* |
/* |
* Turn off line numbers because the user has interrupted |
* Turn off line numbers because the user has interrupted |
* a lengthy line number calculation. |
* a lengthy line number calculation. |
*/ |
*/ |
static void |
static void |
abort_long() |
abort_long(void) |
{ |
{ |
if (linenums == OPT_ONPLUS) |
if (linenums == OPT_ONPLUS) |
/* |
/* |
|
|
* 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 LINENUM |
LINENUM |
find_linenum(pos) |
find_linenum(off_t pos) |
POSITION pos; |
|
{ |
{ |
register struct linenum_info *p; |
struct linenum_info *p; |
register LINENUM linenum; |
LINENUM linenum; |
POSITION cpos; |
off_t cpos; |
|
|
if (!linenums) |
if (!linenums) |
/* |
/* |
* We're not using line numbers. |
* We're not using line numbers. |
*/ |
*/ |
return (0); |
return (0); |
if (pos == NULL_POSITION) |
if (pos == -1) |
/* |
/* |
* Caller doesn't know what he's talking about. |
* Caller doesn't know what he's talking about. |
*/ |
*/ |
|
|
* reading the file forward or backward till we |
* reading the file forward or backward till we |
* get to the place we want. |
* get to the place we want. |
* |
* |
* First decide whether we should go forward from the |
* First decide whether we should go forward from the |
* previous one or backwards from the next one. |
* previous one or backwards from the next one. |
* 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. |
*/ |
*/ |
#if HAVE_TIME |
|
startime = get_time(); |
startime = get_time(); |
#endif |
if (p == &anchor || pos - p->prev->pos < p->pos - pos) { |
if (p == &anchor || pos - p->prev->pos < p->pos - pos) |
|
{ |
|
/* |
/* |
* Go forward. |
* Go forward. |
*/ |
*/ |
|
|
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (0); |
return (0); |
loopcount = 0; |
loopcount = 0; |
for (linenum = p->line, cpos = p->pos; cpos < pos; linenum++) |
for (linenum = p->line, cpos = p->pos; cpos < pos; linenum++) { |
{ |
|
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
*/ |
*/ |
cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); |
cpos = forw_raw_line(cpos, NULL, NULL); |
if (ABORT_SIGS()) { |
if (ABORT_SIGS()) { |
abort_long(); |
abort_long(); |
return (0); |
return (0); |
} |
} |
if (cpos == NULL_POSITION) |
if (cpos == -1) |
return (0); |
return (0); |
longish(); |
longish(); |
} |
} |
|
|
*/ |
*/ |
if (cpos > pos) |
if (cpos > pos) |
linenum--; |
linenum--; |
} else |
} else { |
{ |
|
/* |
/* |
* Go backward. |
* Go backward. |
*/ |
*/ |
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (0); |
return (0); |
loopcount = 0; |
loopcount = 0; |
for (linenum = p->line, cpos = p->pos; cpos > pos; linenum--) |
for (linenum = p->line, cpos = p->pos; cpos > pos; linenum--) { |
{ |
|
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
*/ |
*/ |
cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); |
cpos = back_raw_line(cpos, NULL, NULL); |
if (ABORT_SIGS()) { |
if (ABORT_SIGS()) { |
abort_long(); |
abort_long(); |
return (0); |
return (0); |
} |
} |
if (cpos == NULL_POSITION) |
if (cpos == -1) |
return (0); |
return (0); |
longish(); |
longish(); |
} |
} |
|
|
|
|
/* |
/* |
* Find the position of a given line number. |
* Find the position of a given line number. |
* Return NULL_POSITION if we can't figure it out. |
* Return -1 if we can't figure it out. |
*/ |
*/ |
public POSITION |
off_t |
find_pos(linenum) |
find_pos(LINENUM linenum) |
LINENUM linenum; |
|
{ |
{ |
register struct linenum_info *p; |
struct linenum_info *p; |
POSITION cpos; |
off_t cpos; |
LINENUM clinenum; |
LINENUM clinenum; |
|
|
if (linenum <= 1) |
if (linenum <= 1) |
|
|
/* Found it exactly. */ |
/* Found it exactly. */ |
return (p->pos); |
return (p->pos); |
|
|
if (p == &anchor || linenum - p->prev->line < p->line - linenum) |
if (p == &anchor || linenum - p->prev->line < p->line - linenum) { |
{ |
|
/* |
/* |
* Go forward. |
* Go forward. |
*/ |
*/ |
p = p->prev; |
p = p->prev; |
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (NULL_POSITION); |
return (-1); |
for (clinenum = p->line, cpos = p->pos; clinenum < linenum; clinenum++) |
for (clinenum = p->line, cpos = p->pos; |
{ |
clinenum < linenum; |
|
clinenum++) { |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
*/ |
*/ |
cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); |
cpos = forw_raw_line(cpos, NULL, NULL); |
if (ABORT_SIGS()) |
if (ABORT_SIGS()) |
return (NULL_POSITION); |
return (-1); |
if (cpos == NULL_POSITION) |
if (cpos == -1) |
return (NULL_POSITION); |
return (-1); |
} |
} |
} else |
} else { |
{ |
|
/* |
/* |
* Go backward. |
* Go backward. |
*/ |
*/ |
if (ch_seek(p->pos)) |
if (ch_seek(p->pos)) |
return (NULL_POSITION); |
return (-1); |
for (clinenum = p->line, cpos = p->pos; clinenum > linenum; clinenum--) |
for (clinenum = p->line, cpos = p->pos; |
{ |
clinenum > linenum; |
|
clinenum--) { |
/* |
/* |
* Allow a signal to abort this loop. |
* Allow a signal to abort this loop. |
*/ |
*/ |
cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); |
cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); |
if (ABORT_SIGS()) |
if (ABORT_SIGS()) |
return (NULL_POSITION); |
return (-1); |
if (cpos == NULL_POSITION) |
if (cpos == -1) |
return (NULL_POSITION); |
return (-1); |
} |
} |
} |
} |
/* |
/* |
|
|
* 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 LINENUM |
LINENUM |
currline(where) |
currline(int where) |
int where; |
|
{ |
{ |
POSITION pos; |
off_t pos; |
POSITION len; |
off_t len; |
LINENUM linenum; |
LINENUM linenum; |
|
|
pos = position(where); |
pos = position(where); |
len = ch_length(); |
len = ch_length(); |
while (pos == NULL_POSITION && where >= 0 && where < sc_height) |
while (pos == -1 && where >= 0 && where < sc_height) |
pos = position(++where); |
pos = position(++where); |
if (pos == NULL_POSITION) |
if (pos == -1) |
pos = len; |
pos = len; |
linenum = find_linenum(pos); |
linenum = find_linenum(pos); |
if (pos == len) |
if (pos == len) |