diff --git a/NEWS b/NEWS index 9da321fe..70e916f3 100644 --- a/NEWS +++ b/NEWS @@ -72,11 +72,29 @@ have already been considered. (mostly reverted) ////////////////////////////////////////////////////////////////////// +ELinks 0.12pre4.GIT now: +------------------------ + +To be released as 0.12pre5, 0.12rc1, or even 0.12.0. This branch also +includes the changes listed under ``ELinks 0.11.6.GIT now'' below. + +* bug 1080: Support ``--dump-color-mode'' with ``--dump-charset UTF-8''. +* minor bug 1017: To work around HTTP server bugs, disable + protocol.http.compression by default, until ELinks can report + decompression errors or automatically retry the connection. + +Bugs that should be removed from NEWS before the 0.12.0 release: + +* critical bug 1081: To fix crashes caused by different definitions of + regfree() in TRE and in the system libc, link with TRE before any + other libraries. ELinks 0.12pre4 was the first release that had + this bug. + ELinks 0.12pre4: ---------------- Released on 2009-05-31. This release also included the changes listed -under ``ELinks 0.11.6.GIT now'' below. +under ``ELinks 0.11.6'' below. Incompatibilities: @@ -87,6 +105,8 @@ Incompatibilities: Other changes: +* critical bug 1077: Fix crash opening a ``javascript:'' link in a new + tab. * Debian bug 528661: If using GNUTLS 2.1.7 or later, disable various TLS extensions (including CERT and SERVERNAME) to help handshaking with the SSLv3-only bugzilla.novell.com. diff --git a/configure.in b/configure.in index db916bdc..4a7143db 100644 --- a/configure.in +++ b/configure.in @@ -961,7 +961,7 @@ else AC_MSG_CHECKING([[for TRE header and library]]) EL_SAVE_FLAGS CFLAGS="$TRE_CFLAGS $CFLAGS" - LIBS="$TRE_LIBS $LIBS" + LIBS="$TRE_LIBS $LIBS" # must be first, because of regfree conflict AC_TRY_LINK([#include ], [regex_t re; regmatch_t match[1]; @@ -1452,6 +1452,9 @@ AC_ARG_ENABLE(weehoofooboomookerchoo, # This must be done after the CONFIG_UTF8 check above. # The first part of the TRE check is separate, to get # the configure --help output in a sensible order. +# +# After this section, nothing else must be added to the +# beginning of $LIBS. if test "$tre_log" = "available"; then if test "$CONFIG_UTF8" = "yes"; then @@ -1495,7 +1498,39 @@ if test "$tre_log" = "TRE"; then AC_DEFINE([CONFIG_TRE], [1], [Define as 1 to use the TRE library for regular expression searching. This requires the header file. If you define CONFIG_UTF8 too, then wchar_t must be exactly 32-bit so that it matches unicode_val_T.]) # TRE_CFLAGS will be used only where needed. - LIBS="$LIBS $TRE_LIBS" + # + # Bug 1081: If both TRE and libc define the regfree function, + # ELinks needs to use the version defined by TRE because + # that's the one compatible with regex_t initialized by the + # regwcomp function of TRE. Therefore put $TRE_LIBS at the + # very beginning of $LIBS so that the linker hopefully finds + # regfree there before it examines libc. In particular, + # $PERL_LIBS appears to often include "-lc". + # + # This scheme still risks a crash if ELinks is linked with + # some static library that uses GNU extensions that + # TRE does not implement. For example, the library might call + # re_compile_pattern, which is found in GNU libc, and then + # regfree, which is found in TRE and probably crashes with the + # GNU-initialized regex_t. Ways to avoid such crashes: + # + # - Change TRE so it defines only tre_... functions and does + # not attempt to override the POSIX names by default. + # + # - Change ELinks to access TRE only via dlopen and dlsym. + # The problem then is how to find the correct file name. + # There might be libtre.so.4 and libtre.so.5 with different + # ABI. How can this configure script detect which of them + # matches the in the include path? + # + # - Replace the static library with a shared library. At + # least on GNU/Linux, when the shared library is built, the + # linker should note that e.g. regfree is defined in libc + # and has the GLIBC_2.0 version there, and write that + # version string to the shared library as well; because TRE + # does not provide regfree with that version, any regfree + # calls at run time should then get resolved to libc. + LIBS="$TRE_LIBS $LIBS" else TRE_LIBS= TRE_CFLAGS= diff --git a/contrib/mkdist b/contrib/mkdist index 4d392c4a..34914035 100755 --- a/contrib/mkdist +++ b/contrib/mkdist @@ -106,7 +106,6 @@ tmpdir=$(mktemp -d -t elinks-dist-XXXXXXXX) || exit 1 git --git-dir="$GIT_DIR" archive --format=tar --prefix="elinks/" "$rev" | (cd -- "$tmpdir" && tar -xf -) -mkdir -- "$tmpdir/elinks/.git" printf "%s\n" "$commit" > "$tmpdir/elinks/git-commit-id" (set -e diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c index d9b8153c..db0cc0ee 100644 --- a/src/protocol/http/http.c +++ b/src/protocol/http/http.c @@ -159,10 +159,17 @@ static struct option_info http_options[] = { "risk because it tells web-masters and the FBI sniffers " "about your language preference.")), - /* After the compression support has been tested enough, - * we might wrap this option in #if CFG_DEBUG. */ + /* http://www.eweek.com/c/a/Desktops-and-Notebooks/Intel-Psion-End-Dispute-Concerning-Netbook-Trademark-288875/ + * responds with "Transfer-Encoding: chunked" and + * "Content-Encoding: gzip" but does not compress the first chunk + * and the last chunk, causing ELinks to display garbage. + * (If User-Agent includes "Gecko" (case sensitive), then + * that server correctly compresses the whole stream.) + * ELinks should instead report the decompression error (bug 1017) + * or perhaps even blacklist the server for compression and retry. + * Until that has been implemented, disable compression by default. */ INIT_OPT_BOOL("protocol.http", N_("Enable on-the-fly compression"), - "compression", 0, 1, + "compression", 0, 0, N_("If enabled, the capability to receive compressed content " "(gzip and/or bzip2) is announced to the server, which " "usually sends the reply compressed, thus saving some " diff --git a/src/viewer/dump/dump-color-mode.h b/src/viewer/dump/dump-color-mode.h new file mode 100644 index 00000000..3bd0e336 --- /dev/null +++ b/src/viewer/dump/dump-color-mode.h @@ -0,0 +1,46 @@ +/* Partially specialized functions for dumping to a file. + * + * This include file defines a function that dumps the document to a + * file. The function is specialized to one color mode. This is + * supposedly faster than runtime checks. The file that includes this + * file must define several macros to select the specialization. + * + * The following macros must be defined as names of functions that + * this file should define: + * + * - DUMP_FUNCTION_COLOR: The main function. It calls one of the others. + * - DUMP_FUNCTION_UNIBYTE: For dumping in unibyte charsets. + * - DUMP_FUNCTION_UTF8: For dumping in the UTF-8 charset. + * (The function names could be generated with the ## preprocessor + * operator, but that would make grepping more difficult.) + * + * At most one of the following macros may be defined: + * + * - DUMP_COLOR_MODE_16 + * - DUMP_COLOR_MODE_256 + * - DUMP_COLOR_MODE_TRUE + */ + +#define DUMP_FUNCTION_SPECIALIZED DUMP_FUNCTION_UNIBYTE +#include "dump-specialized.h" +#undef DUMP_FUNCTION_SPECIALIZED + +#ifdef CONFIG_UTF8 +# define DUMP_CHARSET_UTF8 +# define DUMP_FUNCTION_SPECIALIZED DUMP_FUNCTION_UTF8 +# include "dump-specialized.h" +# undef DUMP_FUNCTION_SPECIALIZED +# undef DUMP_CHARSET_UTF8 +#endif /* CONFIG_UTF8 */ + +static int +DUMP_FUNCTION_COLOR(struct document *document, int fd, + unsigned char buf[D_BUF]) +{ +#ifdef CONFIG_UTF8 + if (is_cp_utf8(document->options.cp)) + return DUMP_FUNCTION_UTF8(document, fd, buf); +#endif /* CONFIG_UTF8 */ + + return DUMP_FUNCTION_UNIBYTE(document, fd, buf); +} diff --git a/src/viewer/dump/dump-specialized.h b/src/viewer/dump/dump-specialized.h new file mode 100644 index 00000000..4a29777f --- /dev/null +++ b/src/viewer/dump/dump-specialized.h @@ -0,0 +1,163 @@ +/* Fully specialized functions for dumping to a file. + * + * This include file defines a function that dumps the document to a + * file. The function is specialized to one color mode and one kind + * of charset. This is supposedly faster than runtime checks. The + * file that includes this file must define several macros to select + * the specialization. + * + * The following macro must be defined: + * + * - DUMP_FUNCTION_SPECIALIZED: The name of the function that this + * file should define. + * + * At most one of the following macros may be defined: + * + * - DUMP_COLOR_MODE_16 + * - DUMP_COLOR_MODE_256 + * - DUMP_COLOR_MODE_TRUE + * + * The following macro may be defined: + * + * - DUMP_CHARSET_UTF8 + */ + +static int +DUMP_FUNCTION_SPECIALIZED(struct document *document, int fd, + unsigned char buf[D_BUF]) +{ + int y; + int bptr = 0; +#ifdef DUMP_COLOR_MODE_16 + unsigned char color = 0; + const int width = get_opt_int("document.dump.width", NULL); +#elif defined(DUMP_COLOR_MODE_256) + unsigned char foreground = 0; + unsigned char background = 0; + const int width = get_opt_int("document.dump.width", NULL); +#elif defined(DUMP_COLOR_MODE_TRUE) + static const unsigned char color[6] = {255, 255, 255, 0, 0, 0}; + const unsigned char *foreground = &color[0]; + const unsigned char *background = &color[3]; + const int width = get_opt_int("document.dump.width", NULL); +#endif /* DUMP_COLOR_MODE_TRUE */ + + for (y = 0; y < document->height; y++) { + int white = 0; + int x; + +#ifdef DUMP_COLOR_MODE_16 + write_color_16(color, fd, buf, &bptr); +#elif defined(DUMP_COLOR_MODE_256) + write_color_256("38", foreground, fd, buf, &bptr); + write_color_256("48", background, fd, buf, &bptr); +#elif defined(DUMP_COLOR_MODE_TRUE) + write_true_color("38", foreground, fd, buf, &bptr); + write_true_color("48", background, fd, buf, &bptr); +#endif /* DUMP_COLOR_MODE_TRUE */ + + for (x = 0; x < document->data[y].length; x++) { +#ifdef DUMP_CHARSET_UTF8 + unicode_val_T c; + const unsigned char *utf8_buf; +#else /* !DUMP_CHARSET_UTF8 */ + unsigned char c; +#endif /* !DUMP_CHARSET_UTF8 */ + const unsigned char attr + = document->data[y].chars[x].attr; +#ifdef DUMP_COLOR_MODE_16 + const unsigned char color1 + = document->data[y].chars[x].color[0]; + + if (color != color1) { + color = color1; + if (write_color_16(color, fd, buf, &bptr)) + return -1; + } +#elif defined(DUMP_COLOR_MODE_256) + const unsigned char color1 + = document->data[y].chars[x].color[0]; + const unsigned char color2 + = document->data[y].chars[x].color[1]; + + if (foreground != color1) { + foreground = color1; + if (write_color_256("38", foreground, fd, buf, &bptr)) + return -1; + } + + if (background != color2) { + background = color2; + if (write_color_256("48", background, fd, buf, &bptr)) + return -1; + } +#elif defined(DUMP_COLOR_MODE_TRUE) + const unsigned char *const new_foreground + = &document->data[y].chars[x].color[0]; + const unsigned char *const new_background + = &document->data[y].chars[x].color[3]; + + if (memcmp(foreground, new_foreground, 3)) { + foreground = new_foreground; + if (write_true_color("38", foreground, fd, buf, &bptr)) + return -1; + } + + if (memcmp(background, new_background, 3)) { + background = new_background; + if (write_true_color("48", background, fd, buf, &bptr)) + return -1; + } +#endif /* DUMP_COLOR_MODE_TRUE */ + + c = document->data[y].chars[x].data; + + if ((attr & SCREEN_ATTR_FRAME) + && c >= 176 && c < 224) + c = frame_dumb[c - 176]; + + if (c <= ' ') { + /* Count spaces. */ + white++; + continue; + } + + /* Print spaces if any. */ + while (white) { + if (write_char(' ', fd, buf, &bptr)) + return -1; + white--; + } + + /* Print normal char. */ +#ifdef DUMP_CHARSET_UTF8 + utf8_buf = encode_utf8(c); + while (*utf8_buf) { + if (write_char(*utf8_buf++, + fd, buf, &bptr)) return -1; + } + + x += unicode_to_cell(c) - 1; +#else /* !DUMP_CHARSET_UTF8 */ + if (write_char(c, fd, buf, &bptr)) + return -1; +#endif /* !DUMP_CHARSET_UTF8 */ + } + +#if defined(DUMP_COLOR_MODE_16) || defined(DUMP_COLOR_MODE_256) || defined(DUMP_COLOR_MODE_TRUE) + for (;x < width; x++) { + if (write_char(' ', fd, buf, &bptr)) + return -1; + } +#endif /* DUMP_COLOR_MODE_16 || DUMP_COLOR_MODE_256 || DUMP_COLOR_MODE_TRUE */ + + /* Print end of line. */ + if (write_char('\n', fd, buf, &bptr)) + return -1; + } + + if (hard_write(fd, buf, bptr) != bptr) + return -1; + + return 0; +} diff --git a/src/viewer/dump/dump.c b/src/viewer/dump/dump.c index d7ec7c00..c152a1c0 100644 --- a/src/viewer/dump/dump.c +++ b/src/viewer/dump/dump.c @@ -51,14 +51,254 @@ static int dump_pos; static struct download dump_download; static int dump_redir_count = 0; -static int dump_to_file_16(struct document *document, int fd); +#define D_BUF 65536 + +static int +write_char(unsigned char c, int fd, unsigned char *buf, int *bptr) +{ + buf[(*bptr)++] = c; + if ((*bptr) >= D_BUF) { + if (hard_write(fd, buf, (*bptr)) != (*bptr)) + return -1; + (*bptr) = 0; + } + + return 0; +} + +static int +write_color_16(unsigned char color, int fd, unsigned char *buf, int *bptr) +{ + unsigned char bufor[] = "\033[0;30;40m"; + unsigned char *data = bufor; + int background = (color >> 4) & 7; + int foreground = color & 7; + + bufor[5] += foreground; + if (background) bufor[8] += background; + else { + bufor[6] = 'm'; + bufor[7] = '\0'; + } + while(*data) { + if (write_char(*data++, fd, buf, bptr)) return -1; + } + return 0; +} + +#define DUMP_COLOR_MODE_16 +#define DUMP_FUNCTION_COLOR dump_16color +#define DUMP_FUNCTION_UTF8 dump_16color_utf8 +#define DUMP_FUNCTION_UNIBYTE dump_16color_unibyte +#include "dump-color-mode.h" +#undef DUMP_COLOR_MODE_16 +#undef DUMP_FUNCTION_COLOR +#undef DUMP_FUNCTION_UTF8 +#undef DUMP_FUNCTION_UNIBYTE + +/* configure --enable-debug uses gcc -Wall -Werror, and -Wall includes + * -Wunused-function, so declaring or defining any unused function + * would break the build. */ #if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) -static int dump_to_file_256(struct document *document, int fd); -#endif + +static int +write_color_256(const unsigned char *str, unsigned char color, + int fd, unsigned char *buf, int *bptr) +{ + unsigned char bufor[16]; + unsigned char *data = bufor; + + snprintf(bufor, 16, "\033[%s;5;%dm", str, color); + while(*data) { + if (write_char(*data++, fd, buf, bptr)) return -1; + } + return 0; +} + +#define DUMP_COLOR_MODE_256 +#define DUMP_FUNCTION_COLOR dump_256color +#define DUMP_FUNCTION_UTF8 dump_256color_utf8 +#define DUMP_FUNCTION_UNIBYTE dump_256color_unibyte +#include "dump-color-mode.h" +#undef DUMP_COLOR_MODE_256 +#undef DUMP_FUNCTION_COLOR +#undef DUMP_FUNCTION_UTF8 +#undef DUMP_FUNCTION_UNIBYTE + +#endif /* defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) */ + #ifdef CONFIG_TRUE_COLOR -static int dump_to_file_true_color(struct document *document, int fd); + +static int +write_true_color(const unsigned char *str, const unsigned char *color, + int fd, unsigned char *buf, int *bptr) +{ + unsigned char bufor[24]; + unsigned char *data = bufor; + + snprintf(bufor, 24, "\033[%s;2;%d;%d;%dm", str, color[0], color[1], color[2]); + while(*data) { + if (write_char(*data++, fd, buf, bptr)) return -1; + } + return 0; +} + +#define DUMP_COLOR_MODE_TRUE +#define DUMP_FUNCTION_COLOR dump_truecolor +#define DUMP_FUNCTION_UTF8 dump_truecolor_utf8 +#define DUMP_FUNCTION_UNIBYTE dump_truecolor_unibyte +#include "dump-color-mode.h" +#undef DUMP_COLOR_MODE_TRUE +#undef DUMP_FUNCTION_COLOR +#undef DUMP_FUNCTION_UTF8 +#undef DUMP_FUNCTION_UNIBYTE + +#endif /* CONFIG_TRUE_COLOR */ + +#define DUMP_FUNCTION_COLOR dump_nocolor +#define DUMP_FUNCTION_UTF8 dump_nocolor_utf8 +#define DUMP_FUNCTION_UNIBYTE dump_nocolor_unibyte +#include "dump-color-mode.h" +#undef DUMP_FUNCTION_COLOR +#undef DUMP_FUNCTION_UTF8 +#undef DUMP_FUNCTION_UNIBYTE + +/*! @return 0 on success, -1 on error */ +static int +dump_references(struct document *document, int fd, unsigned char buf[D_BUF]) +{ + if (document->nlinks + && get_opt_bool("document.dump.references", NULL)) { + int x; + unsigned char *header = "\nReferences\n\n Visible links\n"; + int headlen = strlen(header); + + if (hard_write(fd, header, headlen) != headlen) + return -1; + + for (x = 0; x < document->nlinks; x++) { + struct link *link = &document->links[x]; + unsigned char *where = link->where; + size_t reflen; + + if (!where) continue; + + if (document->options.links_numbering) { + if (link->title && *link->title) + snprintf(buf, D_BUF, "%4d. %s\n\t%s\n", + x + 1, link->title, where); + else + snprintf(buf, D_BUF, "%4d. %s\n", + x + 1, where); + } else { + if (link->title && *link->title) + snprintf(buf, D_BUF, " . %s\n\t%s\n", + link->title, where); + else + snprintf(buf, D_BUF, " . %s\n", where); + } + + reflen = strlen(buf); + if (hard_write(fd, buf, reflen) != reflen) + return -1; + } + } + + return 0; +} + +int +dump_to_file(struct document *document, int fd) +{ + unsigned char *buf = mem_alloc(D_BUF); + int result; + + if (!buf) return -1; + + result = dump_nocolor(document, fd, buf); + if (!result) + result = dump_references(document, fd, buf); + + mem_free(buf); + return result; +} + +/* This dumps the given @cached's formatted output onto @fd. */ +static void +dump_formatted(int fd, struct download *download, struct cache_entry *cached) +{ + struct document_options o; + struct document_view formatted; + struct view_state vs; + int width; + unsigned char *buf; + + if (!cached) return; + + memset(&formatted, 0, sizeof(formatted)); + + init_document_options(NULL, &o); + width = get_opt_int("document.dump.width", NULL); + set_box(&o.box, 0, 1, width, DEFAULT_TERMINAL_HEIGHT); + + o.cp = get_opt_codepage("document.dump.codepage", NULL); + o.color_mode = get_opt_int("document.dump.color_mode", NULL); + o.plain = 0; + o.frames = 0; + o.links_numbering = get_opt_bool("document.dump.numbering", NULL); + + init_vs(&vs, cached->uri, -1); + + render_document(&vs, &formatted, &o); + + buf = mem_alloc(D_BUF); + if (buf) { + int result; + + switch (o.color_mode) { + case COLOR_MODE_DUMP: + case COLOR_MODE_MONO: /* FIXME: inversion */ + result = dump_nocolor(formatted.document, fd, buf); + break; + + default: + /* If the desired color mode was not compiled in, + * use 16 colors. */ + case COLOR_MODE_16: + result = dump_16color(formatted.document, fd, buf); + break; + +#ifdef CONFIG_88_COLORS + case COLOR_MODE_88: + result = dump_256color(formatted.document, fd, buf); + break; #endif +#ifdef CONFIG_256_COLORS + case COLOR_MODE_256: + result = dump_256color(formatted.document, fd, buf); + break; +#endif + +#ifdef CONFIG_TRUE_COLOR + case COLOR_MODE_TRUE_COLOR: + result = dump_truecolor(formatted.document, fd, buf); + break; +#endif + } + + if (!result) + dump_references(formatted.document, fd, buf); + + mem_free(buf); + } /* if buf */ + + detach_formatted(&formatted); + destroy_vs(&vs, 1); +} + +#undef D_BUF + /* This dumps the given @cached's source onto @fd nothing more. It returns 0 if it * all went fine and 1 if something isn't quite right and we should terminate * ourselves ASAP. */ @@ -101,64 +341,6 @@ nextfrag: return 0; } -/* This dumps the given @cached's formatted output onto @fd. */ -static void -dump_formatted(int fd, struct download *download, struct cache_entry *cached) -{ - struct document_options o; - struct document_view formatted; - struct view_state vs; - int width; - - if (!cached) return; - - memset(&formatted, 0, sizeof(formatted)); - - init_document_options(NULL, &o); - width = get_opt_int("document.dump.width", NULL); - set_box(&o.box, 0, 1, width, DEFAULT_TERMINAL_HEIGHT); - - o.cp = get_opt_codepage("document.dump.codepage", NULL); - o.color_mode = get_opt_int("document.dump.color_mode", NULL); - o.plain = 0; - o.frames = 0; - o.links_numbering = get_opt_bool("document.dump.numbering", NULL); - - init_vs(&vs, cached->uri, -1); - - render_document(&vs, &formatted, &o); - switch(o.color_mode) { - case COLOR_MODE_DUMP: - case COLOR_MODE_MONO: /* FIXME: inversion */ - dump_to_file(formatted.document, fd); - break; - default: - /* If the desired color mode was not compiled in, - * use 16 colors. */ - case COLOR_MODE_16: - dump_to_file_16(formatted.document, fd); - break; -#ifdef CONFIG_88_COLORS - case COLOR_MODE_88: - dump_to_file_256(formatted.document, fd); - break; -#endif -#ifdef CONFIG_256_COLORS - case COLOR_MODE_256: - dump_to_file_256(formatted.document, fd); - break; -#endif -#ifdef CONFIG_TRUE_COLOR - case COLOR_MODE_TRUE_COLOR: - dump_to_file_true_color(formatted.document, fd); - break; -#endif - } - - detach_formatted(&formatted); - destroy_vs(&vs, 1); -} - static unsigned char * subst_url(unsigned char *str, struct string *url) { @@ -435,564 +617,3 @@ end: #endif /* CONFIG_UTF8 */ return string; } - -#define D_BUF 65536 - -static int -write_char(unsigned char c, int fd, unsigned char *buf, int *bptr) -{ - buf[(*bptr)++] = c; - if ((*bptr) >= D_BUF) { - if (hard_write(fd, buf, (*bptr)) != (*bptr)) - return -1; - (*bptr) = 0; - } - - return 0; -} - -static int -write_color_16(unsigned char color, int fd, unsigned char *buf, int *bptr) -{ - unsigned char bufor[] = "\033[0;30;40m"; - unsigned char *data = bufor; - int background = (color >> 4) & 7; - int foreground = color & 7; - - bufor[5] += foreground; - if (background) bufor[8] += background; - else { - bufor[6] = 'm'; - bufor[7] = '\0'; - } - while(*data) { - if (write_char(*data++, fd, buf, bptr)) return -1; - } - return 0; -} - - -static int -dump_to_file_16(struct document *document, int fd) -{ - int y; - int bptr = 0; - unsigned char *buf = mem_alloc(D_BUF); - unsigned char color = 0; - int width = get_opt_int("document.dump.width", NULL); - - if (!buf) return -1; - - for (y = 0; y < document->height; y++) { - int white = 0; - int x; - - write_color_16(color, fd, buf, &bptr); - for (x = 0; x < document->data[y].length; x++) { - unsigned char c; - unsigned char attr = document->data[y].chars[x].attr; - unsigned char color1 = document->data[y].chars[x].color[0]; - - if (color != color1) { - color = color1; - if (write_color_16(color, fd, buf, &bptr)) - goto fail; - } - - c = document->data[y].chars[x].data; - - if ((attr & SCREEN_ATTR_FRAME) - && c >= 176 && c < 224) - c = frame_dumb[c - 176]; - - if (c <= ' ') { - /* Count spaces. */ - white++; - continue; - } - - /* Print spaces if any. */ - while (white) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - white--; - } - - /* Print normal char. */ - if (write_char(c, fd, buf, &bptr)) - goto fail; - } - for (;x < width; x++) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - } - - /* Print end of line. */ - if (write_char('\n', fd, buf, &bptr)) - goto fail; - } - - if (hard_write(fd, buf, bptr) != bptr) { -fail: - mem_free(buf); - return -1; - } - - if (document->nlinks - && get_opt_bool("document.dump.references", NULL)) { - int x; - unsigned char *header = "\nReferences\n\n Visible links\n"; - int headlen = strlen(header); - - if (hard_write(fd, header, headlen) != headlen) - goto fail; - - for (x = 0; x < document->nlinks; x++) { - struct link *link = &document->links[x]; - unsigned char *where = link->where; - - if (!where) continue; - - if (document->options.links_numbering) { - if (link->title && *link->title) - snprintf(buf, D_BUF, "%4d. %s\n\t%s\n", - x + 1, link->title, where); - else - snprintf(buf, D_BUF, "%4d. %s\n", - x + 1, where); - } else { - if (link->title && *link->title) - snprintf(buf, D_BUF, " . %s\n\t%s\n", - link->title, where); - else - snprintf(buf, D_BUF, " . %s\n", where); - } - - bptr = strlen(buf); - if (hard_write(fd, buf, bptr) != bptr) - goto fail; - } - } - - mem_free(buf); - return 0; -} - -/* configure --enable-debug uses gcc -Wall -Werror, and -Wall includes - * -Wunused-function, so declaring or defining any unused function - * would break the build. */ -#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) - -static int -write_color_256(unsigned char *str, unsigned char color, int fd, unsigned char *buf, int *bptr) -{ - unsigned char bufor[16]; - unsigned char *data = bufor; - - snprintf(bufor, 16, "\033[%s;5;%dm", str, color); - while(*data) { - if (write_char(*data++, fd, buf, bptr)) return -1; - } - return 0; -} - -static int -dump_to_file_256(struct document *document, int fd) -{ - int y; - int bptr = 0; - unsigned char *buf = mem_alloc(D_BUF); - unsigned char foreground = 0; - unsigned char background = 0; - int width = get_opt_int("document.dump.width", NULL); - - if (!buf) return -1; - - for (y = 0; y < document->height; y++) { - int white = 0; - int x; - write_color_256("38", foreground, fd, buf, &bptr); - write_color_256("48", background, fd, buf, &bptr); - - for (x = 0; x < document->data[y].length; x++) { - unsigned char c; - unsigned char attr = document->data[y].chars[x].attr; - unsigned char color1 = document->data[y].chars[x].color[0]; - unsigned char color2 = document->data[y].chars[x].color[1]; - - if (foreground != color1) { - foreground = color1; - if (write_color_256("38", foreground, fd, buf, &bptr)) - goto fail; - } - - if (background != color2) { - background = color2; - if (write_color_256("48", background, fd, buf, &bptr)) - goto fail; - } - - c = document->data[y].chars[x].data; - - if ((attr & SCREEN_ATTR_FRAME) - && c >= 176 && c < 224) - c = frame_dumb[c - 176]; - - if (c <= ' ') { - /* Count spaces. */ - white++; - continue; - } - - /* Print spaces if any. */ - while (white) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - white--; - } - - /* Print normal char. */ - if (write_char(c, fd, buf, &bptr)) - goto fail; - } - for (;x < width; x++) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - } - - /* Print end of line. */ - if (write_char('\n', fd, buf, &bptr)) - goto fail; - } - - if (hard_write(fd, buf, bptr) != bptr) { -fail: - mem_free(buf); - return -1; - } - - if (document->nlinks - && get_opt_bool("document.dump.references", NULL)) { - int x; - unsigned char *header = "\nReferences\n\n Visible links\n"; - int headlen = strlen(header); - - if (hard_write(fd, header, headlen) != headlen) - goto fail; - - for (x = 0; x < document->nlinks; x++) { - struct link *link = &document->links[x]; - unsigned char *where = link->where; - - if (!where) continue; - - if (document->options.links_numbering) { - if (link->title && *link->title) - snprintf(buf, D_BUF, "%4d. %s\n\t%s\n", - x + 1, link->title, where); - else - snprintf(buf, D_BUF, "%4d. %s\n", - x + 1, where); - } else { - if (link->title && *link->title) - snprintf(buf, D_BUF, " . %s\n\t%s\n", - link->title, where); - else - snprintf(buf, D_BUF, " . %s\n", where); - } - - bptr = strlen(buf); - if (hard_write(fd, buf, bptr) != bptr) - goto fail; - } - } - - mem_free(buf); - return 0; -} - -#endif /* defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS) */ - -#ifdef CONFIG_TRUE_COLOR - -static int -write_true_color(unsigned char *str, unsigned char *color, int fd, unsigned char *buf, int *bptr) -{ - unsigned char bufor[24]; - unsigned char *data = bufor; - - snprintf(bufor, 24, "\033[%s;2;%d;%d;%dm", str, color[0], color[1], color[2]); - while(*data) { - if (write_char(*data++, fd, buf, bptr)) return -1; - } - return 0; -} - -static int -dump_to_file_true_color(struct document *document, int fd) -{ - static unsigned char color[6] = {255, 255, 255, 0, 0, 0}; - int y; - int bptr = 0; - unsigned char *buf = mem_alloc(D_BUF); - unsigned char *foreground = &color[0]; - unsigned char *background = &color[3]; - int width = get_opt_int("document.dump.width", NULL); - - if (!buf) return -1; - - for (y = 0; y < document->height; y++) { - int white = 0; - int x; - write_true_color("38", foreground, fd, buf, &bptr); - write_true_color("48", background, fd, buf, &bptr); - - for (x = 0; x < document->data[y].length; x++) { - unsigned char c; - unsigned char attr = document->data[y].chars[x].attr; - unsigned char *new_foreground = &document->data[y].chars[x].color[0]; - unsigned char *new_background = &document->data[y].chars[x].color[3]; - - if (memcmp(foreground, new_foreground, 3)) { - foreground = new_foreground; - if (write_true_color("38", foreground, fd, buf, &bptr)) - goto fail; - } - - if (memcmp(background, new_background, 3)) { - background = new_background; - if (write_true_color("48", background, fd, buf, &bptr)) - goto fail; - } - - c = document->data[y].chars[x].data; - - if ((attr & SCREEN_ATTR_FRAME) - && c >= 176 && c < 224) - c = frame_dumb[c - 176]; - - if (c <= ' ') { - /* Count spaces. */ - white++; - continue; - } - - /* Print spaces if any. */ - while (white) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - white--; - } - - /* Print normal char. */ - if (write_char(c, fd, buf, &bptr)) - goto fail; - } - for (;x < width; x++) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - } - - /* Print end of line. */ - if (write_char('\n', fd, buf, &bptr)) - goto fail; - } - - if (hard_write(fd, buf, bptr) != bptr) { -fail: - mem_free(buf); - return -1; - } - - if (document->nlinks - && get_opt_bool("document.dump.references", NULL)) { - int x; - unsigned char *header = "\nReferences\n\n Visible links\n"; - int headlen = strlen(header); - - if (hard_write(fd, header, headlen) != headlen) - goto fail; - - for (x = 0; x < document->nlinks; x++) { - struct link *link = &document->links[x]; - unsigned char *where = link->where; - - if (!where) continue; - - if (document->options.links_numbering) { - if (link->title && *link->title) - snprintf(buf, D_BUF, "%4d. %s\n\t%s\n", - x + 1, link->title, where); - else - snprintf(buf, D_BUF, "%4d. %s\n", - x + 1, where); - } else { - if (link->title && *link->title) - snprintf(buf, D_BUF, " . %s\n\t%s\n", - link->title, where); - else - snprintf(buf, D_BUF, " . %s\n", where); - } - - bptr = strlen(buf); - if (hard_write(fd, buf, bptr) != bptr) - goto fail; - } - } - - mem_free(buf); - return 0; -} - -#endif /* CONFIG_TRUE_COLOR */ -int -dump_to_file(struct document *document, int fd) -{ - int y; - int bptr = 0; - unsigned char *buf = mem_alloc(D_BUF); - - if (!buf) return -1; - -#ifdef CONFIG_UTF8 - if (is_cp_utf8(document->options.cp)) - goto utf8; -#endif /* CONFIG_UTF8 */ - - for (y = 0; y < document->height; y++) { - int white = 0; - int x; - - for (x = 0; x < document->data[y].length; x++) { - unsigned char c; - unsigned char attr = document->data[y].chars[x].attr; - - c = document->data[y].chars[x].data; - - if ((attr & SCREEN_ATTR_FRAME) - && c >= 176 && c < 224) - c = frame_dumb[c - 176]; - - if (c <= ' ') { - /* Count spaces. */ - white++; - continue; - } - - /* Print spaces if any. */ - while (white) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - white--; - } - - /* Print normal char. */ - if (write_char(c, fd, buf, &bptr)) - goto fail; - } - - /* Print end of line. */ - if (write_char('\n', fd, buf, &bptr)) - goto fail; - } -#ifdef CONFIG_UTF8 - goto ref; -utf8: - for (y = 0; y < document->height; y++) { - int white = 0; - int x; - - for (x = 0; x < document->data[y].length; x++) { - unicode_val_T c; - unsigned char attr = document->data[y].chars[x].attr; - - c = document->data[y].chars[x].data; - - if ((attr & SCREEN_ATTR_FRAME) - && c >= 176 && c < 224) - c = frame_dumb[c - 176]; - else { - unsigned char *utf8_buf = encode_utf8(c); - - while (*utf8_buf) { - if (write_char(*utf8_buf++, - fd, buf, &bptr)) goto fail; - } - - x += unicode_to_cell(c) - 1; - - continue; - } - - if (c <= ' ') { - /* Count spaces. */ - white++; - continue; - } - - /* Print spaces if any. */ - while (white) { - if (write_char(' ', fd, buf, &bptr)) - goto fail; - white--; - } - - /* Print normal char. */ - if (write_char(c, fd, buf, &bptr)) - goto fail; - } - - /* Print end of line. */ - if (write_char('\n', fd, buf, &bptr)) - goto fail; - } -ref: -#endif /* CONFIG_UTF8 */ - - if (hard_write(fd, buf, bptr) != bptr) { -fail: - mem_free(buf); - return -1; - } - - if (document->nlinks - && get_opt_bool("document.dump.references", NULL)) { - int x; - unsigned char *header = "\nReferences\n\n Visible links\n"; - int headlen = strlen(header); - - if (hard_write(fd, header, headlen) != headlen) - goto fail; - - for (x = 0; x < document->nlinks; x++) { - struct link *link = &document->links[x]; - unsigned char *where = link->where; - - if (!where) continue; - - if (document->options.links_numbering) { - if (link->title && *link->title) - snprintf(buf, D_BUF, "%4d. %s\n\t%s\n", - x + 1, link->title, where); - else - snprintf(buf, D_BUF, "%4d. %s\n", - x + 1, where); - } else { - if (link->title && *link->title) - snprintf(buf, D_BUF, " . %s\n\t%s\n", - link->title, where); - else - snprintf(buf, D_BUF, " . %s\n", where); - } - - bptr = strlen(buf); - if (hard_write(fd, buf, bptr) != bptr) - goto fail; - } - } - - mem_free(buf); - return 0; -} - -#undef D_BUF