mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Build option to disable scrollback compression.
This was requested by a downstream of the code, who wanted to change
the time/space tradeoff in the terminal. I currently have no plans to
change this setting for upstream PuTTY, although there is a cmake
option for it just to make testing it easy.
To avoid sprinkling ifdefs over the whole terminal code, the strategy
is to keep the separate type 'compressed_scrollback_line', and turn it
into a typedef for a 'termline *'. So compressline() becomes almost
trivial, and decompressline() even more so.
Memory management is the fiddly part. To make this work sensibly on
both sides, I've broken up each of compressline() and decompressline()
into two versions, one of which takes ownership of (and logically
speaking frees) its input, and the other doesn't. So at call sites
where a function was followed by a free, it's now calling the
'and_free' version of the function, and where the input object was
reused afterwards, it's calling the 'no_free' version. This means that
in different branches of the #if, I can make one function call the
other or vice versa, and no call site is stuck with having to do
things in a more roundabout way than necessary.
The freeing of the _return_ value from decompressline() is handled for
us, because termlines already have a 'temporary' flag which is set
when they're returned from the decompressor, and anyone receiving a
termline from lineptr() calls unlineptr() when they're finished with
it, which will _conditionally_ free it, depending on that 'temporary'
flag. So in the new mode, 'temporary' is never set at all, and all
those unlineptr() calls do nothing.
However, we also still need to free compressed lines properly when
they're actually being thrown away (scrolled off the top of the
scrollback, or cleaned up in term_free), and for that, I've made a new
special-purpose free_compressed_line() function.
(cherry picked from commit 5f2eff2fea
)
This commit is contained in:
parent
65639fbbe7
commit
cfda9585ac
@ -1,6 +1,7 @@
|
|||||||
#cmakedefine NO_IPV6
|
#cmakedefine NO_IPV6
|
||||||
#cmakedefine NO_GSSAPI
|
#cmakedefine NO_GSSAPI
|
||||||
#cmakedefine STATIC_GSSAPI
|
#cmakedefine STATIC_GSSAPI
|
||||||
|
#cmakedefine NO_SCROLLBACK_COMPRESSION
|
||||||
|
|
||||||
#cmakedefine NO_MULTIMON
|
#cmakedefine NO_MULTIMON
|
||||||
|
|
||||||
|
@ -15,6 +15,12 @@ set(PUTTY_FUZZING OFF
|
|||||||
CACHE BOOL "Build PuTTY binaries suitable for fuzzing, NOT FOR REAL USE")
|
CACHE BOOL "Build PuTTY binaries suitable for fuzzing, NOT FOR REAL USE")
|
||||||
set(PUTTY_COVERAGE OFF
|
set(PUTTY_COVERAGE OFF
|
||||||
CACHE BOOL "Build PuTTY binaries suitable for code coverage analysis")
|
CACHE BOOL "Build PuTTY binaries suitable for code coverage analysis")
|
||||||
|
set(PUTTY_COMPRESS_SCROLLBACK ON
|
||||||
|
# This is always on in production versions of PuTTY, but downstreams
|
||||||
|
# of the code have been known to find it a better tradeoff to
|
||||||
|
# disable it. So there's a #ifdef in terminal.c, and a cmake option
|
||||||
|
# to enable that ifdef just in case it needs testing or debugging.
|
||||||
|
CACHE BOOL "Store terminal scrollback in compressed form")
|
||||||
|
|
||||||
set(STRICT OFF
|
set(STRICT OFF
|
||||||
CACHE BOOL "Enable extra compiler warnings and make them errors")
|
CACHE BOOL "Enable extra compiler warnings and make them errors")
|
||||||
@ -108,6 +114,9 @@ endif()
|
|||||||
if(PUTTY_FUZZING)
|
if(PUTTY_FUZZING)
|
||||||
add_compile_definitions(FUZZING)
|
add_compile_definitions(FUZZING)
|
||||||
endif()
|
endif()
|
||||||
|
if(NOT PUTTY_COMPRESS_SCROLLBACK)
|
||||||
|
set(NO_SCROLLBACK_COMPRESSION ON)
|
||||||
|
endif()
|
||||||
if(PUTTY_COVERAGE)
|
if(PUTTY_COVERAGE)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -g ")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -g ")
|
||||||
endif()
|
endif()
|
||||||
|
@ -398,6 +398,8 @@ static void move_termchar(termline *line, termchar *dest, termchar *src)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_SCROLLBACK_COMPRESSION
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compress and decompress a termline into an RLE-based format for
|
* Compress and decompress a termline into an RLE-based format for
|
||||||
* storing in scrollback. (Since scrollback almost never needs to
|
* storing in scrollback. (Since scrollback almost never needs to
|
||||||
@ -688,11 +690,12 @@ static void makeliteral_cc(strbuf *b, termchar *c, unsigned long *state)
|
|||||||
|
|
||||||
typedef struct compressed_scrollback_line {
|
typedef struct compressed_scrollback_line {
|
||||||
size_t len;
|
size_t len;
|
||||||
|
/* compressed data follows after this */
|
||||||
} compressed_scrollback_line;
|
} compressed_scrollback_line;
|
||||||
|
|
||||||
static termline *decompressline(compressed_scrollback_line *line);
|
static termline *decompressline_no_free(compressed_scrollback_line *line);
|
||||||
|
|
||||||
static compressed_scrollback_line *compressline(termline *ldata)
|
static compressed_scrollback_line *compressline_no_free(termline *ldata)
|
||||||
{
|
{
|
||||||
strbuf *b = strbuf_new();
|
strbuf *b = strbuf_new();
|
||||||
|
|
||||||
@ -768,7 +771,7 @@ static compressed_scrollback_line *compressline(termline *ldata)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dcl = decompressline(line);
|
dcl = decompressline_no_free(line);
|
||||||
assert(ldata->cols == dcl->cols);
|
assert(ldata->cols == dcl->cols);
|
||||||
assert(ldata->lattr == dcl->lattr);
|
assert(ldata->lattr == dcl->lattr);
|
||||||
for (i = 0; i < ldata->cols; i++)
|
for (i = 0; i < ldata->cols; i++)
|
||||||
@ -788,6 +791,13 @@ static compressed_scrollback_line *compressline(termline *ldata)
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static compressed_scrollback_line *compressline_and_free(termline *ldata)
|
||||||
|
{
|
||||||
|
compressed_scrollback_line *cline = compressline_no_free(ldata);
|
||||||
|
freetermline(ldata);
|
||||||
|
return cline;
|
||||||
|
}
|
||||||
|
|
||||||
static void readrle(BinarySource *bs, termline *ldata,
|
static void readrle(BinarySource *bs, termline *ldata,
|
||||||
void (*readliteral)(BinarySource *bs, termchar *c,
|
void (*readliteral)(BinarySource *bs, termchar *c,
|
||||||
termline *ldata, unsigned long *state))
|
termline *ldata, unsigned long *state))
|
||||||
@ -921,7 +931,7 @@ static void readliteral_cc(BinarySource *bs, termchar *c, termline *ldata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static termline *decompressline(compressed_scrollback_line *line)
|
static termline *decompressline_no_free(compressed_scrollback_line *line)
|
||||||
{
|
{
|
||||||
int ncols, byte, shift;
|
int ncols, byte, shift;
|
||||||
BinarySource bs[1];
|
BinarySource bs[1];
|
||||||
@ -988,6 +998,66 @@ static termline *decompressline(compressed_scrollback_line *line)
|
|||||||
return ldata;
|
return ldata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void free_compressed_line(compressed_scrollback_line *cline)
|
||||||
|
{
|
||||||
|
sfree(cline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static termline *decompressline_and_free(compressed_scrollback_line *cline)
|
||||||
|
{
|
||||||
|
termline *ldata = decompressline_no_free(cline);
|
||||||
|
free_compressed_line(cline);
|
||||||
|
return ldata;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* NO_SCROLLBACK_COMPRESSION */
|
||||||
|
|
||||||
|
static termline *duptermline(termline *oldline)
|
||||||
|
{
|
||||||
|
termline *newline = snew(termline);
|
||||||
|
*newline = *oldline; /* copy the POD structure fields */
|
||||||
|
newline->chars = snewn(newline->size, termchar);
|
||||||
|
for (int j = 0; j < newline->size; j++)
|
||||||
|
newline->chars[j] = oldline->chars[j];
|
||||||
|
return newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef termline compressed_scrollback_line;
|
||||||
|
|
||||||
|
static inline compressed_scrollback_line *compressline_and_free(
|
||||||
|
termline *ldata)
|
||||||
|
{
|
||||||
|
return ldata;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline compressed_scrollback_line *compressline_no_free(termline *ldata)
|
||||||
|
{
|
||||||
|
return duptermline(ldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline termline *decompressline_no_free(
|
||||||
|
compressed_scrollback_line *line)
|
||||||
|
{
|
||||||
|
/* This will return a line without the 'temporary' flag, which
|
||||||
|
* means that unlineptr() is already set up to avoid freeing it */
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline termline *decompressline_and_free(
|
||||||
|
compressed_scrollback_line *line)
|
||||||
|
{
|
||||||
|
/* Same as decompressline_no_free, because the caller will free
|
||||||
|
* our returned termline, and that does all the freeing necessary */
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void free_compressed_line(compressed_scrollback_line *line)
|
||||||
|
{
|
||||||
|
freetermline(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* NO_SCROLLBACK_COMPRESSION */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resize a line to make it `cols' columns wide.
|
* Resize a line to make it `cols' columns wide.
|
||||||
*/
|
*/
|
||||||
@ -1134,7 +1204,7 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen)
|
|||||||
compressed_scrollback_line *cline = index234(whichtree, treeindex);
|
compressed_scrollback_line *cline = index234(whichtree, treeindex);
|
||||||
if (!cline)
|
if (!cline)
|
||||||
null_line_error(term, y, lineno, whichtree, treeindex, "cline");
|
null_line_error(term, y, lineno, whichtree, treeindex, "cline");
|
||||||
line = decompressline(cline);
|
line = decompressline_no_free(cline);
|
||||||
} else {
|
} else {
|
||||||
line = index234(whichtree, treeindex);
|
line = index234(whichtree, treeindex);
|
||||||
}
|
}
|
||||||
@ -2066,12 +2136,13 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win)
|
|||||||
|
|
||||||
void term_free(Terminal *term)
|
void term_free(Terminal *term)
|
||||||
{
|
{
|
||||||
|
compressed_scrollback_line *cline;
|
||||||
termline *line;
|
termline *line;
|
||||||
struct beeptime *beep;
|
struct beeptime *beep;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while ((line = delpos234(term->scrollback, 0)) != NULL)
|
while ((cline = delpos234(term->scrollback, 0)) != NULL)
|
||||||
sfree(line); /* compressed data, not a termline */
|
free_compressed_line(cline);
|
||||||
freetree234(term->scrollback);
|
freetree234(term->scrollback);
|
||||||
while ((line = delpos234(term->screen, 0)) != NULL)
|
while ((line = delpos234(term->screen, 0)) != NULL)
|
||||||
freetermline(line);
|
freetermline(line);
|
||||||
@ -2195,8 +2266,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
|
|||||||
/* Insert a line from the scrollback at the top of the screen. */
|
/* Insert a line from the scrollback at the top of the screen. */
|
||||||
assert(sblen >= term->tempsblines);
|
assert(sblen >= term->tempsblines);
|
||||||
cline = delpos234(term->scrollback, --sblen);
|
cline = delpos234(term->scrollback, --sblen);
|
||||||
line = decompressline(cline);
|
line = decompressline_and_free(cline);
|
||||||
sfree(cline);
|
|
||||||
line->temporary = false; /* reconstituted line is now real */
|
line->temporary = false; /* reconstituted line is now real */
|
||||||
term->tempsblines -= 1;
|
term->tempsblines -= 1;
|
||||||
addpos234(term->screen, line, 0);
|
addpos234(term->screen, line, 0);
|
||||||
@ -2220,8 +2290,7 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
|
|||||||
} else {
|
} else {
|
||||||
/* push top row to scrollback */
|
/* push top row to scrollback */
|
||||||
line = delpos234(term->screen, 0);
|
line = delpos234(term->screen, 0);
|
||||||
addpos234(term->scrollback, compressline(line), sblen++);
|
addpos234(term->scrollback, compressline_and_free(line), sblen++);
|
||||||
freetermline(line);
|
|
||||||
term->tempsblines += 1;
|
term->tempsblines += 1;
|
||||||
term->curs.y -= 1;
|
term->curs.y -= 1;
|
||||||
term->savecurs.y -= 1;
|
term->savecurs.y -= 1;
|
||||||
@ -2597,15 +2666,15 @@ static void scroll(Terminal *term, int topline, int botline,
|
|||||||
* the scrollback is full.
|
* the scrollback is full.
|
||||||
*/
|
*/
|
||||||
if (sblen == term->savelines) {
|
if (sblen == term->savelines) {
|
||||||
unsigned char *cline;
|
compressed_scrollback_line *cline;
|
||||||
|
|
||||||
sblen--;
|
sblen--;
|
||||||
cline = delpos234(term->scrollback, 0);
|
cline = delpos234(term->scrollback, 0);
|
||||||
sfree(cline);
|
free_compressed_line(cline);
|
||||||
} else
|
} else
|
||||||
term->tempsblines += 1;
|
term->tempsblines += 1;
|
||||||
|
|
||||||
addpos234(term->scrollback, compressline(line), sblen);
|
addpos234(term->scrollback, compressline_no_free(line), sblen);
|
||||||
|
|
||||||
/* now `line' itself can be reused as the bottom line */
|
/* now `line' itself can be reused as the bottom line */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user