version 1.4, 2003/04/06 23:38:07 |
version 1.5, 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" |
|
|
public char linebuf[1024]; /* Buffer which holds the current output line */ |
#define IS_CONT(c) (((c) & 0xC0) == 0x80) |
public int size_linebuf = sizeof(linebuf); |
|
|
|
static char attr[1024]; /* Extension of linebuf to hold attributes */ |
public char *linebuf = NULL; /* Buffer which holds the current output line */ |
|
static char *attr = NULL; /* Extension of linebuf to hold attributes */ |
|
public int size_linebuf = 0; /* Size of line buffer (and attr buffer) */ |
|
|
|
public int cshift; /* Current left-shift of output line buffer */ |
|
public int hshift; /* Desired left-shift of output line buffer */ |
|
public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */ |
|
public int ntabstops = 1; /* Number of tabstops */ |
|
public int tabdefault = 8; /* Default repeated tabstops */ |
|
|
static int curr; /* Index into linebuf */ |
static int curr; /* Index into linebuf */ |
static int column; /* Printable length, accounting for |
static int column; /* Printable length, accounting for |
backspaces, etc. */ |
backspaces, etc. */ |
static int lno_indent; /* Number of chars used for line number */ |
|
static int overstrike; /* Next char should overstrike previous char */ |
static int overstrike; /* Next char should overstrike previous char */ |
|
static int last_overstrike = AT_NORMAL; |
static int is_null_line; /* There is no current line */ |
static int is_null_line; /* There is no current line */ |
|
static int lmargin; /* Left margin */ |
|
static int hilites; /* Number of hilites in this line */ |
static char pendc; |
static char pendc; |
static POSITION pendpos; |
static POSITION pendpos; |
|
static char *end_ansi_chars; |
|
|
static int do_append(); |
static int do_append(); |
|
|
extern int bs_mode; |
extern int bs_mode; |
extern int tabstop; |
|
extern int linenums; |
extern int linenums; |
extern int ctldisp; |
extern int ctldisp; |
extern int twiddle; |
extern int twiddle; |
extern int binattr; |
extern int binattr; |
|
extern int status_col; |
extern int auto_wrap, ignaw; |
extern int auto_wrap, ignaw; |
extern int bo_s_width, bo_e_width; |
extern int bo_s_width, bo_e_width; |
extern int ul_s_width, ul_e_width; |
extern int ul_s_width, ul_e_width; |
extern int bl_s_width, bl_e_width; |
extern int bl_s_width, bl_e_width; |
extern int so_s_width, so_e_width; |
extern int so_s_width, so_e_width; |
extern int sc_width, sc_height; |
extern int sc_width, sc_height; |
|
extern int utf_mode; |
|
extern POSITION start_attnpos; |
|
extern POSITION end_attnpos; |
|
|
/* |
/* |
|
* Initialize from environment variables. |
|
*/ |
|
public void |
|
init_line() |
|
{ |
|
end_ansi_chars = lgetenv("LESSANSIENDCHARS"); |
|
if (end_ansi_chars == NULL || *end_ansi_chars == '\0') |
|
end_ansi_chars = "m"; |
|
linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); |
|
attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); |
|
size_linebuf = LINEBUF_SIZE; |
|
} |
|
|
|
/* |
|
* Expand the line buffer. |
|
*/ |
|
static int |
|
expand_linebuf() |
|
{ |
|
int new_size = size_linebuf + LINEBUF_SIZE; |
|
char *new_buf = (char *) calloc(new_size, sizeof(char)); |
|
char *new_attr = (char *) calloc(new_size, sizeof(char)); |
|
if (new_buf == NULL || new_attr == NULL) |
|
{ |
|
if (new_attr != NULL) |
|
free(new_attr); |
|
if (new_buf != NULL) |
|
free(new_buf); |
|
return 1; |
|
} |
|
memcpy(new_buf, linebuf, size_linebuf * sizeof(char)); |
|
memcpy(new_attr, attr, size_linebuf * sizeof(char)); |
|
free(attr); |
|
free(linebuf); |
|
linebuf = new_buf; |
|
attr = new_attr; |
|
size_linebuf = new_size; |
|
return 0; |
|
} |
|
|
|
/* |
* Rewind the line buffer. |
* Rewind the line buffer. |
*/ |
*/ |
public void |
public void |
|
|
column = 0; |
column = 0; |
overstrike = 0; |
overstrike = 0; |
is_null_line = 0; |
is_null_line = 0; |
lno_indent = 0; |
|
pendc = '\0'; |
pendc = '\0'; |
|
lmargin = 0; |
|
if (status_col) |
|
lmargin += 1; |
|
#if HILITE_SEARCH |
|
hilites = 0; |
|
#endif |
} |
} |
|
|
/* |
/* |
|
|
plinenum(pos) |
plinenum(pos) |
POSITION pos; |
POSITION pos; |
{ |
{ |
int lno; |
register LINENUM linenum = 0; |
int i; |
register int i; |
int n; |
|
|
|
|
if (linenums == OPT_ONPLUS) |
|
{ |
|
/* |
|
* Get the line number and put it in the current line. |
|
* {{ Note: since find_linenum calls forw_raw_line, |
|
* it may seek in the input file, requiring the caller |
|
* of plinenum to re-seek if necessary. }} |
|
* {{ Since forw_raw_line modifies linebuf, we must |
|
* do this first, before storing anything in linebuf. }} |
|
*/ |
|
linenum = find_linenum(pos); |
|
} |
|
|
/* |
/* |
* We display the line number at the start of each line |
* Display a status column if the -J option is set. |
* only if the -N option is set. |
|
*/ |
*/ |
if (linenums != OPT_ONPLUS) |
if (status_col) |
return; |
{ |
|
linebuf[curr] = ' '; |
|
if (start_attnpos != NULL_POSITION && |
|
pos >= start_attnpos && pos < end_attnpos) |
|
attr[curr] = AT_STANDOUT; |
|
else |
|
attr[curr] = 0; |
|
curr++; |
|
column++; |
|
} |
/* |
/* |
* Get the line number and put it in the current line. |
* Display the line number at the start of each line |
* {{ Note: since find_linenum calls forw_raw_line, |
* if the -N option is set. |
* it may seek in the input file, requiring the caller |
|
* of plinenum to re-seek if necessary. }} |
|
*/ |
*/ |
lno = find_linenum(pos); |
if (linenums == OPT_ONPLUS) |
|
{ |
|
char buf[INT_STRLEN_BOUND(pos) + 2]; |
|
int n; |
|
|
snprintf(&linebuf[curr], sizeof linebuf - curr, "%6d", lno); |
linenumtoa(linenum, buf, sizeof(buf)); |
n = strlen(&linebuf[curr]); |
n = strlen(buf); |
column += n; |
if (n < MIN_LINENUM_WIDTH) |
for (i = 0; i < n; i++) |
n = MIN_LINENUM_WIDTH; |
attr[curr++] = 0; |
snprintf(linebuf+curr, sizeof(linebuf)-curr, "%*s ", n, buf); |
|
n++; /* One space after the line number. */ |
|
for (i = 0; i < n; i++) |
|
attr[curr+i] = AT_NORMAL; |
|
curr += n; |
|
column += n; |
|
lmargin += n; |
|
} |
|
|
/* |
/* |
* Append enough spaces to bring us to the next tab stop. |
* Append enough spaces to bring us to the lmargin. |
* {{ We could avoid this at the cost of adding some |
|
* complication to the tab stop logic in pappend(). }} |
|
*/ |
*/ |
if (tabstop == 0) |
while (column < lmargin) |
tabstop = 1; |
|
do |
|
{ |
{ |
linebuf[curr] = ' '; |
linebuf[curr] = ' '; |
attr[curr++] = AT_NORMAL; |
attr[curr++] = AT_NORMAL; |
column++; |
column++; |
} while ((column % tabstop) != 0); |
} |
lno_indent = column; |
|
} |
} |
|
|
/* |
/* |
|
* Determine how many characters are required to shift N columns. |
|
*/ |
|
static int |
|
shift_chars(s, len) |
|
char *s; |
|
int len; |
|
{ |
|
char *p = s; |
|
|
|
/* |
|
* Each char counts for one column, except ANSI color escape |
|
* sequences use no columns since they don't move the cursor. |
|
*/ |
|
while (*p != '\0' && len > 0) |
|
{ |
|
if (*p++ != ESC) |
|
{ |
|
len--; |
|
} else |
|
{ |
|
while (*p != '\0') |
|
{ |
|
if (is_ansi_end(*p++)) |
|
break; |
|
} |
|
} |
|
} |
|
return (p - s); |
|
} |
|
|
|
/* |
|
* Determine how many characters are required to shift N columns (UTF version). |
|
* {{ FIXME: what about color escape sequences in UTF mode? }} |
|
*/ |
|
static int |
|
utf_shift_chars(s, len) |
|
char *s; |
|
int len; |
|
{ |
|
int ulen = 0; |
|
|
|
while (*s != '\0' && len > 0) |
|
{ |
|
if (!IS_CONT(*s)) |
|
len--; |
|
s++; |
|
ulen++; |
|
} |
|
while (IS_CONT(*s)) |
|
{ |
|
s++; |
|
ulen++; |
|
} |
|
return (ulen); |
|
} |
|
|
|
/* |
|
* Shift the input line left. |
|
* This means discarding N printable chars at the start of the buffer. |
|
*/ |
|
static void |
|
pshift(shift) |
|
int shift; |
|
{ |
|
int i; |
|
int nchars; |
|
|
|
if (shift > column - lmargin) |
|
shift = column - lmargin; |
|
if (shift > curr - lmargin) |
|
shift = curr - lmargin; |
|
|
|
if (utf_mode) |
|
nchars = utf_shift_chars(linebuf + lmargin, shift); |
|
else |
|
nchars = shift_chars(linebuf + lmargin, shift); |
|
if (nchars > curr) |
|
nchars = curr; |
|
for (i = 0; i < curr - nchars; i++) |
|
{ |
|
linebuf[lmargin + i] = linebuf[lmargin + i + nchars]; |
|
attr[lmargin + i] = attr[lmargin + i + nchars]; |
|
} |
|
curr -= nchars; |
|
column -= shift; |
|
cshift += shift; |
|
} |
|
|
|
/* |
* Return the printing width of the start (enter) sequence |
* Return the printing width of the start (enter) sequence |
* for a given character attribute. |
* for a given character attribute. |
*/ |
*/ |
int |
static int |
attr_swidth(a) |
attr_swidth(a) |
int a; |
int a; |
{ |
{ |
|
|
* Return the printing width of the end (exit) sequence |
* Return the printing width of the end (exit) sequence |
* for a given character attribute. |
* for a given character attribute. |
*/ |
*/ |
int |
static int |
attr_ewidth(a) |
attr_ewidth(a) |
int a; |
int a; |
{ |
{ |
|
|
int c; |
int c; |
int a; |
int a; |
{ |
{ |
int w; |
register int w; |
|
|
|
if (utf_mode && IS_CONT(c)) |
|
return (0); |
|
|
if (c == '\b') |
if (c == '\b') |
/* |
/* |
* Backspace moves backwards one position. |
* Backspace moves backwards one position. |
|
|
} |
} |
|
|
/* |
/* |
|
* Are we currently within a recognized ANSI escape sequence? |
|
*/ |
|
static int |
|
in_ansi_esc_seq() |
|
{ |
|
int i; |
|
|
|
/* |
|
* Search backwards for either an ESC (which means we ARE in a seq); |
|
* or an end char (which means we're NOT in a seq). |
|
*/ |
|
for (i = curr-1; i >= 0; i--) |
|
{ |
|
if (linebuf[i] == ESC) |
|
return (1); |
|
if (is_ansi_end(linebuf[i])) |
|
return (0); |
|
} |
|
return (0); |
|
} |
|
|
|
/* |
|
* Is a character the end of an ANSI escape sequence? |
|
*/ |
|
public int |
|
is_ansi_end(c) |
|
char c; |
|
{ |
|
return (strchr(end_ansi_chars, c) != NULL); |
|
} |
|
|
|
/* |
* Append a character and attribute to the line buffer. |
* Append a character and attribute to the line buffer. |
*/ |
*/ |
|
#define STORE_CHAR(c,a,pos) \ |
|
do { if (store_char((c),(a),(pos))) return (1); else curr++; } while (0) |
|
|
static int |
static int |
storec(c, a, pos) |
store_char(c, a, pos) |
int c; |
int c; |
int a; |
int a; |
POSITION pos; |
POSITION pos; |
{ |
{ |
int w; |
register int w; |
|
|
|
if (a != AT_NORMAL) |
|
last_overstrike = a; |
#if HILITE_SEARCH |
#if HILITE_SEARCH |
if (is_hilited(pos, pos+1, 0)) |
if (is_hilited(pos, pos+1, 0)) |
|
{ |
/* |
/* |
* This character should be highlighted. |
* This character should be highlighted. |
* Override the attribute passed in. |
* Override the attribute passed in. |
*/ |
*/ |
a = AT_STANDOUT; |
a = AT_STANDOUT; |
|
hilites++; |
|
} |
#endif |
#endif |
w = pwidth(c, a); |
if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) |
if (ctldisp > 0 && column + w + attr_ewidth(a) > sc_width) |
w = 0; |
|
else |
|
w = pwidth(c, a); |
|
if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) |
/* |
/* |
* Won't fit on screen. |
* Won't fit on screen. |
*/ |
*/ |
return (1); |
return (1); |
|
|
if (curr >= sizeof(linebuf)-2) |
if (curr >= size_linebuf-2) |
|
{ |
/* |
/* |
* Won't fit in line buffer. |
* Won't fit in line buffer. |
|
* Try to expand it. |
*/ |
*/ |
return (1); |
if (expand_linebuf()) |
|
return (1); |
|
} |
|
|
/* |
/* |
* Special handling for "magic cookie" terminals. |
* Special handling for "magic cookie" terminals. |
|
|
} |
} |
|
|
/* |
/* |
|
* Append a tab to the line buffer. |
|
* Store spaces to represent the tab. |
|
*/ |
|
#define STORE_TAB(a,pos) \ |
|
do { if (store_tab((a),(pos))) return (1); } while (0) |
|
|
|
static int |
|
store_tab(attr, pos) |
|
int attr; |
|
POSITION pos; |
|
{ |
|
int to_tab = column + cshift - lmargin; |
|
int i; |
|
|
|
if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1]) |
|
to_tab = tabdefault - |
|
((to_tab - tabstops[ntabstops-1]) % tabdefault); |
|
else |
|
{ |
|
for (i = ntabstops - 2; i >= 0; i--) |
|
if (to_tab >= tabstops[i]) |
|
break; |
|
to_tab = tabstops[i+1] - to_tab; |
|
} |
|
|
|
do { |
|
STORE_CHAR(' ', attr, pos); |
|
} while (--to_tab > 0); |
|
return 0; |
|
} |
|
|
|
/* |
* Append a character to the line buffer. |
* Append a character to the line buffer. |
* Expand tabs into spaces, handle underlining, boldfacing, etc. |
* Expand tabs into spaces, handle underlining, boldfacing, etc. |
* Returns 0 if ok, 1 if couldn't fit in buffer. |
* Returns 0 if ok, 1 if couldn't fit in buffer. |
*/ |
*/ |
public int |
public int |
pappend(c, pos) |
pappend(c, pos) |
int c; |
register int c; |
POSITION pos; |
POSITION pos; |
{ |
{ |
|
int r; |
|
|
if (pendc) |
if (pendc) |
{ |
{ |
if (do_append(pendc, pendpos)) |
if (do_append(pendc, pendpos)) |
|
|
return (0); |
return (0); |
} |
} |
|
|
return (do_append(c, pos)); |
r = do_append(c, pos); |
|
/* |
|
* If we need to shift the line, do it. |
|
* But wait until we get to at least the middle of the screen, |
|
* so shifting it doesn't affect the chars we're currently |
|
* pappending. (Bold & underline can get messed up otherwise.) |
|
*/ |
|
if (cshift < hshift && column > sc_width / 2) |
|
{ |
|
linebuf[curr] = '\0'; |
|
pshift(hshift - cshift); |
|
} |
|
return (r); |
} |
} |
|
|
|
#define IS_UTF8_4BYTE(c) ( ((c) & 0xf8) == 0xf0 ) |
|
#define IS_UTF8_3BYTE(c) ( ((c) & 0xf0) == 0xe0 ) |
|
#define IS_UTF8_2BYTE(c) ( ((c) & 0xe0) == 0xc0 ) |
|
#define IS_UTF8_TRAIL(c) ( ((c) & 0xc0) == 0x80 ) |
|
|
static int |
static int |
do_append(c, pos) |
do_append(c, pos) |
int c; |
int c; |
POSITION pos; |
POSITION pos; |
{ |
{ |
char *s; |
register char *s; |
int a; |
register int a; |
|
|
#define STOREC(c,a) \ |
#define STOREC(c,a) \ |
if (storec((c),(a),pos)) return (1); else curr++ |
if ((c) == '\t') STORE_TAB((a),pos); else STORE_CHAR((c),(a),pos) |
|
|
if (overstrike) |
if (c == '\b') |
{ |
{ |
|
switch (bs_mode) |
|
{ |
|
case BS_NORMAL: |
|
STORE_CHAR(c, AT_NORMAL, pos); |
|
break; |
|
case BS_CONTROL: |
|
goto do_control_char; |
|
case BS_SPECIAL: |
|
if (curr == 0) |
|
break; |
|
backc(); |
|
overstrike = 1; |
|
break; |
|
} |
|
} else if (overstrike) |
|
{ |
/* |
/* |
* Overstrike the character at the current position |
* Overstrike the character at the current position |
* in the line buffer. This will cause either |
* in the line buffer. This will cause either |
|
|
* bold (if an identical character is overstruck), |
* bold (if an identical character is overstruck), |
* or just deletion of the character in the buffer. |
* or just deletion of the character in the buffer. |
*/ |
*/ |
overstrike = 0; |
overstrike--; |
if ((char)c == linebuf[curr]) |
if (utf_mode && IS_UTF8_4BYTE(c) && curr > 2 && (char)c == linebuf[curr-3]) |
STOREC(linebuf[curr], AT_BOLD); |
{ |
else if (c == '_') |
backc(); |
|
backc(); |
|
backc(); |
|
STORE_CHAR(linebuf[curr], AT_BOLD, pos); |
|
overstrike = 3; |
|
} else if (utf_mode && (IS_UTF8_3BYTE(c) || (overstrike==2 && IS_UTF8_TRAIL(c))) && curr > 1 && (char)c == linebuf[curr-2]) |
|
{ |
|
backc(); |
|
backc(); |
|
STORE_CHAR(linebuf[curr], AT_BOLD, pos); |
|
overstrike = 2; |
|
} else if (utf_mode && curr > 0 && (IS_UTF8_2BYTE(c) || (overstrike==1 && IS_UTF8_TRAIL(c))) && (char)c == linebuf[curr-1]) |
|
{ |
|
backc(); |
|
STORE_CHAR(linebuf[curr], AT_BOLD, pos); |
|
overstrike = 1; |
|
} else if (utf_mode && curr > 0 && IS_UTF8_TRAIL(c) && attr[curr-1] == AT_UNDERLINE) |
|
{ |
|
STOREC(c, AT_UNDERLINE); |
|
} else if ((char)c == linebuf[curr]) |
|
{ |
|
/* |
|
* Overstriking a char with itself means make it bold. |
|
* But overstriking an underscore with itself is |
|
* ambiguous. It could mean make it bold, or |
|
* it could mean make it underlined. |
|
* Use the previous overstrike to resolve it. |
|
*/ |
|
if (c == '_' && last_overstrike != AT_NORMAL) |
|
STOREC(c, last_overstrike); |
|
else |
|
STOREC(c, AT_BOLD); |
|
} else if (c == '_') |
|
{ |
|
if (utf_mode) |
|
{ |
|
int i; |
|
for (i = 0; i < 5; i++) |
|
{ |
|
if (curr <= i || !IS_CONT(linebuf[curr-i])) |
|
break; |
|
attr[curr-i-1] = AT_UNDERLINE; |
|
} |
|
} |
STOREC(linebuf[curr], AT_UNDERLINE); |
STOREC(linebuf[curr], AT_UNDERLINE); |
else if (linebuf[curr] == '_') |
} else if (linebuf[curr] == '_') |
|
{ |
|
if (utf_mode) |
|
{ |
|
if (IS_UTF8_2BYTE(c)) |
|
overstrike = 1; |
|
else if (IS_UTF8_3BYTE(c)) |
|
overstrike = 2; |
|
else if (IS_UTF8_4BYTE(c)) |
|
overstrike = 3; |
|
} |
STOREC(c, AT_UNDERLINE); |
STOREC(c, AT_UNDERLINE); |
else if (control_char(c)) |
} else if (control_char(c)) |
goto do_control_char; |
goto do_control_char; |
else |
else |
STOREC(c, AT_NORMAL); |
STOREC(c, AT_NORMAL); |
} else if (c == '\b') |
} else if (c == '\t') |
{ |
{ |
|
/* |
|
* Expand a tab into spaces. |
|
*/ |
switch (bs_mode) |
switch (bs_mode) |
{ |
{ |
case BS_NORMAL: |
|
STOREC(c, AT_NORMAL); |
|
break; |
|
case BS_CONTROL: |
case BS_CONTROL: |
goto do_control_char; |
goto do_control_char; |
|
case BS_NORMAL: |
case BS_SPECIAL: |
case BS_SPECIAL: |
if (curr == 0) |
STORE_TAB(AT_NORMAL, pos); |
break; |
|
backc(); |
|
overstrike = 1; |
|
break; |
break; |
} |
} |
} else if (c == '\t') |
|
{ |
|
/* |
|
* Expand a tab into spaces. |
|
*/ |
|
if (tabstop == 0) |
|
tabstop = 1; |
|
do |
|
{ |
|
STOREC(' ', AT_NORMAL); |
|
} while ((column % tabstop) != 0); |
|
} else if (control_char(c)) |
} else if (control_char(c)) |
{ |
{ |
do_control_char: |
do_control_char: |
if (ctldisp == 0) |
if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && c == ESC)) |
{ |
{ |
/* |
/* |
* Output as a normal character. |
* Output as a normal character. |
*/ |
*/ |
STOREC(c, AT_NORMAL); |
STORE_CHAR(c, AT_NORMAL, pos); |
} else |
} else |
{ |
{ |
/* |
/* |
|
|
return (1); |
return (1); |
|
|
for ( ; *s != 0; s++) |
for ( ; *s != 0; s++) |
STOREC(*s, a); |
STORE_CHAR(*s, a, pos); |
} |
} |
} else |
} else |
{ |
{ |
|
|
(void) do_append(pendc, pendpos); |
(void) do_append(pendc, pendpos); |
|
|
/* |
/* |
|
* Make sure we've shifted the line, if we need to. |
|
*/ |
|
if (cshift < hshift) |
|
pshift(hshift - cshift); |
|
|
|
/* |
* Add a newline if necessary, |
* Add a newline if necessary, |
* and append a '\0' to the end of the line. |
* and append a '\0' to the end of the line. |
*/ |
*/ |
if (column < sc_width || !auto_wrap || ignaw || ctldisp == 0) |
if (column < sc_width || !auto_wrap || ignaw || ctldisp == OPT_ON) |
{ |
{ |
linebuf[curr] = '\n'; |
linebuf[curr] = '\n'; |
attr[curr] = AT_NORMAL; |
attr[curr] = AT_NORMAL; |
|
|
} |
} |
linebuf[curr] = '\0'; |
linebuf[curr] = '\0'; |
attr[curr] = AT_NORMAL; |
attr[curr] = AT_NORMAL; |
|
|
|
#if HILITE_SEARCH |
|
if (status_col && hilites > 0) |
|
{ |
|
linebuf[0] = '*'; |
|
attr[0] = AT_STANDOUT; |
|
} |
|
#endif |
|
/* |
|
* If we are done with this line, reset the current shift. |
|
*/ |
|
if (endline) |
|
cshift = 0; |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
public int |
public int |
gline(i, ap) |
gline(i, ap) |
int i; |
register int i; |
int *ap; |
register int *ap; |
{ |
{ |
char *s; |
char *s; |
|
|
|
|
* If there is no current line, we pretend the line is |
* If there is no current line, we pretend the line is |
* either "~" or "", depending on the "twiddle" flag. |
* either "~" or "", depending on the "twiddle" flag. |
*/ |
*/ |
*ap = AT_NORMAL; |
*ap = AT_BOLD; |
s = (twiddle) ? "~\n" : "\n"; |
s = (twiddle) ? "~\n" : "\n"; |
return (s[i]); |
return (s[i]); |
} |
} |
|
|
null_line() |
null_line() |
{ |
{ |
is_null_line = 1; |
is_null_line = 1; |
|
cshift = 0; |
} |
} |
|
|
#if 1 |
|
/* |
/* |
* Analogous to forw_line(), but deals with "raw lines": |
* Analogous to forw_line(), but deals with "raw lines": |
* lines which are not split for screen width. |
* lines which are not split for screen width. |
|
|
POSITION curr_pos; |
POSITION curr_pos; |
char **linep; |
char **linep; |
{ |
{ |
char *p; |
register int n; |
int c; |
register int c; |
POSITION new_pos; |
POSITION new_pos; |
|
|
if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || |
if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || |
(c = ch_forw_get()) == EOI) |
(c = ch_forw_get()) == EOI) |
return (NULL_POSITION); |
return (NULL_POSITION); |
|
|
p = linebuf; |
n = 0; |
|
|
for (;;) |
for (;;) |
{ |
{ |
if (c == '\n' || c == EOI) |
if (c == '\n' || c == EOI) |
|
|
new_pos = ch_tell(); |
new_pos = ch_tell(); |
break; |
break; |
} |
} |
if (p >= &linebuf[sizeof(linebuf)-1]) |
if (n >= size_linebuf-1) |
{ |
{ |
/* |
if (expand_linebuf()) |
* Overflowed the input buffer. |
{ |
* Pretend the line ended here. |
/* |
* {{ The line buffer is supposed to be big |
* Overflowed the input buffer. |
* enough that this never happens. }} |
* Pretend the line ended here. |
*/ |
*/ |
new_pos = ch_tell() - 1; |
new_pos = ch_tell() - 1; |
break; |
break; |
|
} |
} |
} |
*p++ = c; |
linebuf[n++] = c; |
c = ch_forw_get(); |
c = ch_forw_get(); |
} |
} |
*p = '\0'; |
linebuf[n] = '\0'; |
if (linep != NULL) |
if (linep != NULL) |
*linep = linebuf; |
*linep = linebuf; |
return (new_pos); |
return (new_pos); |
|
|
POSITION curr_pos; |
POSITION curr_pos; |
char **linep; |
char **linep; |
{ |
{ |
char *p; |
register int n; |
int c; |
register int c; |
POSITION new_pos; |
POSITION new_pos; |
|
|
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || |
if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || |
ch_seek(curr_pos-1)) |
ch_seek(curr_pos-1)) |
return (NULL_POSITION); |
return (NULL_POSITION); |
|
|
p = &linebuf[sizeof(linebuf)]; |
n = size_linebuf; |
*--p = '\0'; |
linebuf[--n] = '\0'; |
|
|
for (;;) |
for (;;) |
{ |
{ |
c = ch_back_get(); |
c = ch_back_get(); |
|
|
new_pos = ch_zero(); |
new_pos = ch_zero(); |
break; |
break; |
} |
} |
if (p <= linebuf) |
if (n <= 0) |
{ |
{ |
|
int old_size_linebuf = size_linebuf; |
|
char *fm; |
|
char *to; |
|
if (expand_linebuf()) |
|
{ |
|
/* |
|
* Overflowed the input buffer. |
|
* Pretend the line ended here. |
|
*/ |
|
new_pos = ch_tell() + 1; |
|
break; |
|
} |
/* |
/* |
* Overflowed the input buffer. |
* Shift the data to the end of the new linebuf. |
* Pretend the line ended here. |
|
*/ |
*/ |
new_pos = ch_tell() + 1; |
for (fm = linebuf + old_size_linebuf, |
break; |
to = linebuf + size_linebuf; |
|
fm >= linebuf; fm--, to--) |
|
*to = *fm; |
|
n = size_linebuf - old_size_linebuf; |
} |
} |
*--p = c; |
linebuf[--n] = c; |
} |
} |
if (linep != NULL) |
if (linep != NULL) |
*linep = p; |
*linep = &linebuf[n]; |
return (new_pos); |
return (new_pos); |
} |
} |
#endif |
|