diff options
Diffstat (limited to 'gettext-tools/gnulib-lib/term-ostream.c')
-rw-r--r-- | gettext-tools/gnulib-lib/term-ostream.c | 2043 |
1 files changed, 2043 insertions, 0 deletions
diff --git a/gettext-tools/gnulib-lib/term-ostream.c b/gettext-tools/gnulib-lib/term-ostream.c new file mode 100644 index 0000000..fbec783 --- /dev/null +++ b/gettext-tools/gnulib-lib/term-ostream.c @@ -0,0 +1,2043 @@ +/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ + +#line 1 "term-ostream.oo.c" +/* Output stream for attributed text, producing ANSI escape sequences. + Copyright (C) 2006-2008 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2006. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include "term-ostream.h" + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +#include "error.h" +#include "fatal-signal.h" +#include "full-write.h" +#include "terminfo.h" +#include "xalloc.h" +#include "xsize.h" +#include "gettext.h" + +#define _(str) gettext (str) + +#if HAVE_TPARAM +/* GNU termcap's tparam() function requires a buffer argument. Make it so + large that there is no risk that tparam() needs to call malloc(). */ +static char tparambuf[100]; +/* Define tparm in terms of tparam. In the scope of this file, it is called + with at most one argument after the string. */ +# define tparm(str, arg1) \ + tparam (str, tparambuf, sizeof (tparambuf), arg1) +#endif + +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + + +/* =========================== Color primitives =========================== */ + +/* A color in RGB format. */ +typedef struct +{ + unsigned int red : 8; /* range 0..255 */ + unsigned int green : 8; /* range 0..255 */ + unsigned int blue : 8; /* range 0..255 */ +} rgb_t; + +/* A color in HSV (a.k.a. HSB) format. */ +typedef struct +{ + float hue; /* normalized to interval [0,6) */ + float saturation; /* normalized to interval [0,1] */ + float brightness; /* a.k.a. value, normalized to interval [0,1] */ +} hsv_t; + +/* Conversion of a color in RGB to HSV format. */ +static void +rgb_to_hsv (rgb_t c, hsv_t *result) +{ + unsigned int r = c.red; + unsigned int g = c.green; + unsigned int b = c.blue; + + if (r > g) + { + if (b > r) + { + /* b > r > g, so max = b, min = g */ + result->hue = 4.0f + (float) (r - g) / (float) (b - g); + result->saturation = 1.0f - (float) g / (float) b; + result->brightness = (float) b / 255.0f; + } + else if (b <= g) + { + /* r > g >= b, so max = r, min = b */ + result->hue = 0.0f + (float) (g - b) / (float) (r - b); + result->saturation = 1.0f - (float) b / (float) r; + result->brightness = (float) r / 255.0f; + } + else + { + /* r >= b > g, so max = r, min = g */ + result->hue = 6.0f - (float) (b - g) / (float) (r - g); + result->saturation = 1.0f - (float) g / (float) r; + result->brightness = (float) r / 255.0f; + } + } + else + { + if (b > g) + { + /* b > g >= r, so max = b, min = r */ + result->hue = 4.0f - (float) (g - r) / (float) (b - r); + result->saturation = 1.0f - (float) r / (float) b; + result->brightness = (float) b / 255.0f; + } + else if (b < r) + { + /* g >= r > b, so max = g, min = b */ + result->hue = 2.0f - (float) (r - b) / (float) (g - b); + result->saturation = 1.0f - (float) b / (float) g; + result->brightness = (float) g / 255.0f; + } + else if (g > r) + { + /* g >= b >= r, g > r, so max = g, min = r */ + result->hue = 2.0f + (float) (b - r) / (float) (g - r); + result->saturation = 1.0f - (float) r / (float) g; + result->brightness = (float) g / 255.0f; + } + else + { + /* r = g = b. A grey color. */ + result->hue = 0; /* arbitrary */ + result->saturation = 0; + result->brightness = (float) r / 255.0f; + } + } +} + +/* Square of distance of two colors. */ +static float +color_distance (const hsv_t *color1, const hsv_t *color2) +{ +#if 0 + /* Formula taken from "John Smith: Color Similarity", + http://www.ctr.columbia.edu/~jrsmith/html/pubs/acmmm96/node8.html. */ + float angle1 = color1->hue * 1.04719755f; /* normalize to [0,2π] */ + float angle2 = color2->hue * 1.04719755f; /* normalize to [0,2π] */ + float delta_x = color1->saturation * cosf (angle1) + - color2->saturation * cosf (angle2); + float delta_y = color1->saturation * sinf (angle1) + - color2->saturation * sinf (angle2); + float delta_v = color1->brightness + - color2->brightness; + + return delta_x * delta_x + delta_y * delta_y + delta_v * delta_v; +#else + /* Formula that considers hue differences with more weight than saturation + or brightness differences, like the human eye does. */ + float delta_hue = + (color1->hue >= color2->hue + ? (color1->hue - color2->hue >= 3.0f + ? 6.0f + color2->hue - color1->hue + : color1->hue - color2->hue) + : (color2->hue - color1->hue >= 3.0f + ? 6.0f + color1->hue - color2->hue + : color2->hue - color1->hue)); + float min_saturation = + (color1->saturation < color2->saturation + ? color1->saturation + : color2->saturation); + float delta_saturation = color1->saturation - color2->saturation; + float delta_brightness = color1->brightness - color2->brightness; + + return delta_hue * delta_hue * min_saturation + + delta_saturation * delta_saturation * 0.2f + + delta_brightness * delta_brightness * 0.8f; +#endif +} + +/* Return the index of the color in a color table that is nearest to a given + color. */ +static unsigned int +nearest_color (rgb_t given, const rgb_t *table, unsigned int table_size) +{ + hsv_t given_hsv; + unsigned int best_index; + float best_distance; + unsigned int i; + + assert (table_size > 0); + + rgb_to_hsv (given, &given_hsv); + + best_index = 0; + best_distance = 1000000.0f; + for (i = 0; i < table_size; i++) + { + hsv_t i_hsv; + + rgb_to_hsv (table[i], &i_hsv); + + /* Avoid converting a color to grey, or fading out a color too much. */ + if (i_hsv.saturation > given_hsv.saturation * 0.5f) + { + float distance = color_distance (&given_hsv, &i_hsv); + if (distance < best_distance) + { + best_index = i; + best_distance = distance; + } + } + } + +#if 0 /* Debugging code */ + hsv_t best_hsv; + rgb_to_hsv (table[best_index], &best_hsv); + fprintf (stderr, "nearest: (%d,%d,%d) = (%f,%f,%f)\n -> (%f,%f,%f) = (%d,%d,%d)\n", + given.red, given.green, given.blue, + (double)given_hsv.hue, (double)given_hsv.saturation, (double)given_hsv.brightness, + (double)best_hsv.hue, (double)best_hsv.saturation, (double)best_hsv.brightness, + table[best_index].red, table[best_index].green, table[best_index].blue); +#endif + + return best_index; +} + +/* The luminance of a color. This is the brightness of the color, as it + appears to the human eye. This must be used in color to grey conversion. */ +static float +color_luminance (int r, int g, int b) +{ + /* Use the luminance model used by NTSC and JPEG. + Taken from http://www.fho-emden.de/~hoffmann/gray10012001.pdf . + No need to care about rounding errors leading to luminance > 1; + this cannot happen. */ + return (0.299f * r + 0.587f * g + 0.114f * b) / 255.0f; +} + + +/* ============================= Color models ============================= */ + +/* The color model used by the terminal. */ +typedef enum +{ + cm_monochrome, /* No colors. */ + cm_common8, /* Usual terminal with at least 8 colors. */ + cm_xterm8, /* TERM=xterm, with 8 colors. */ + cm_xterm16, /* TERM=xterm-16color, with 16 colors. */ + cm_xterm88, /* TERM=xterm-88color, with 88 colors. */ + cm_xterm256 /* TERM=xterm-256color, with 256 colors. */ +} colormodel_t; + +/* ----------------------- cm_monochrome color model ----------------------- */ + +/* A non-default color index doesn't exist in this color model. */ +static inline term_color_t +rgb_to_color_monochrome () +{ + return COLOR_DEFAULT; +} + +/* ------------------------ cm_common8 color model ------------------------ */ + +/* A non-default color index is in the range 0..7. + RGB components + COLOR_BLACK 000 + COLOR_BLUE 001 + COLOR_GREEN 010 + COLOR_CYAN 011 + COLOR_RED 100 + COLOR_MAGENTA 101 + COLOR_YELLOW 110 + COLOR_WHITE 111 */ +static const rgb_t colors_of_common8[8] = +{ + /* R G B grey index */ + { 0, 0, 0 }, /* 0.000 0 */ + { 0, 0, 255 }, + { 0, 255, 0 }, + { 0, 255, 255 }, + { 255, 0, 0 }, + { 255, 0, 255 }, + { 255, 255, 0 }, + { 255, 255, 255 } /* 1.000 7 */ +}; + +static inline term_color_t +rgb_to_color_common8 (int r, int g, int b) +{ + rgb_t color; + hsv_t hsv; + + color.red = r; color.green = g; color.blue = b; + rgb_to_hsv (color, &hsv); + + if (hsv.saturation < 0.065f) + { + /* Greyscale approximation. */ + float luminance = color_luminance (r, g, b); + if (luminance < 0.500f) + return 0; + else + return 7; + } + else + /* Color approximation. */ + return nearest_color (color, colors_of_common8, 8); +} + +/* Convert a cm_common8 color in RGB encoding to BGR encoding. + See the ncurses terminfo(5) manual page, section "Color Handling", for an + explanation why this is needed. */ +static inline int +color_bgr (term_color_t color) +{ + return ((color & 4) >> 2) | (color & 2) | ((color & 1) << 2); +} + +/* ------------------------- cm_xterm8 color model ------------------------- */ + +/* A non-default color index is in the range 0..7. + BGR components + COLOR_BLACK 000 + COLOR_RED 001 + COLOR_GREEN 010 + COLOR_YELLOW 011 + COLOR_BLUE 100 + COLOR_MAGENTA 101 + COLOR_CYAN 110 + COLOR_WHITE 111 */ +static const rgb_t colors_of_xterm8[8] = +{ + /* The real xterm's colors are dimmed; assume full-brightness instead. */ + /* R G B grey index */ + { 0, 0, 0 }, /* 0.000 0 */ + { 255, 0, 0 }, + { 0, 255, 0 }, + { 255, 255, 0 }, + { 0, 0, 255 }, + { 255, 0, 255 }, + { 0, 255, 255 }, + { 255, 255, 255 } /* 1.000 7 */ +}; + +static inline term_color_t +rgb_to_color_xterm8 (int r, int g, int b) +{ + rgb_t color; + hsv_t hsv; + + color.red = r; color.green = g; color.blue = b; + rgb_to_hsv (color, &hsv); + + if (hsv.saturation < 0.065f) + { + /* Greyscale approximation. */ + float luminance = color_luminance (r, g, b); + if (luminance < 0.500f) + return 0; + else + return 7; + } + else + /* Color approximation. */ + return nearest_color (color, colors_of_xterm8, 8); +} + +/* ------------------------ cm_xterm16 color model ------------------------ */ + +/* A non-default color index is in the range 0..15. + The RGB values come from xterm's XTerm-col.ad. */ +static const rgb_t colors_of_xterm16[16] = +{ + /* R G B grey index */ + { 0, 0, 0 }, /* 0.000 0 */ + { 205, 0, 0 }, + { 0, 205, 0 }, + { 205, 205, 0 }, + { 0, 0, 205 }, + { 205, 0, 205 }, + { 0, 205, 205 }, + { 229, 229, 229 }, /* 0.898 7 */ + { 77, 77, 77 }, /* 0.302 8 */ + { 255, 0, 0 }, + { 0, 255, 0 }, + { 255, 255, 0 }, + { 0, 0, 255 }, + { 255, 0, 255 }, + { 0, 255, 255 }, + { 255, 255, 255 } /* 1.000 15 */ +}; + +static inline term_color_t +rgb_to_color_xterm16 (int r, int g, int b) +{ + rgb_t color; + hsv_t hsv; + + color.red = r; color.green = g; color.blue = b; + rgb_to_hsv (color, &hsv); + + if (hsv.saturation < 0.065f) + { + /* Greyscale approximation. */ + float luminance = color_luminance (r, g, b); + if (luminance < 0.151f) + return 0; + else if (luminance < 0.600f) + return 8; + else if (luminance < 0.949f) + return 7; + else + return 15; + } + else + /* Color approximation. */ + return nearest_color (color, colors_of_xterm16, 16); +} + +/* ------------------------ cm_xterm88 color model ------------------------ */ + +/* A non-default color index is in the range 0..87. + Colors 0..15 are the same as in the cm_xterm16 color model. + Colors 16..87 are defined in xterm's 88colres.h. */ + +static const rgb_t colors_of_xterm88[88] = +{ + /* R G B grey index */ + { 0, 0, 0 }, /* 0.000 0 */ + { 205, 0, 0 }, + { 0, 205, 0 }, + { 205, 205, 0 }, + { 0, 0, 205 }, + { 205, 0, 205 }, + { 0, 205, 205 }, + { 229, 229, 229 }, /* 0.898 7 */ + { 77, 77, 77 }, /* 0.302 8 */ + { 255, 0, 0 }, + { 0, 255, 0 }, + { 255, 255, 0 }, + { 0, 0, 255 }, + { 255, 0, 255 }, + { 0, 255, 255 }, + { 255, 255, 255 }, /* 1.000 15 */ + { 0, 0, 0 }, /* 0.000 16 */ + { 0, 0, 139 }, + { 0, 0, 205 }, + { 0, 0, 255 }, + { 0, 139, 0 }, + { 0, 139, 139 }, + { 0, 139, 205 }, + { 0, 139, 255 }, + { 0, 205, 0 }, + { 0, 205, 139 }, + { 0, 205, 205 }, + { 0, 205, 255 }, + { 0, 255, 0 }, + { 0, 255, 139 }, + { 0, 255, 205 }, + { 0, 255, 255 }, + { 139, 0, 0 }, + { 139, 0, 139 }, + { 139, 0, 205 }, + { 139, 0, 255 }, + { 139, 139, 0 }, + { 139, 139, 139 }, /* 0.545 37 */ + { 139, 139, 205 }, + { 139, 139, 255 }, + { 139, 205, 0 }, + { 139, 205, 139 }, + { 139, 205, 205 }, + { 139, 205, 255 }, + { 139, 255, 0 }, + { 139, 255, 139 }, + { 139, 255, 205 }, + { 139, 255, 255 }, + { 205, 0, 0 }, + { 205, 0, 139 }, + { 205, 0, 205 }, + { 205, 0, 255 }, + { 205, 139, 0 }, + { 205, 139, 139 }, + { 205, 139, 205 }, + { 205, 139, 255 }, + { 205, 205, 0 }, + { 205, 205, 139 }, + { 205, 205, 205 }, /* 0.804 58 */ + { 205, 205, 255 }, + { 205, 255, 0 }, + { 205, 255, 139 }, + { 205, 255, 205 }, + { 205, 255, 255 }, + { 255, 0, 0 }, + { 255, 0, 139 }, + { 255, 0, 205 }, + { 255, 0, 255 }, + { 255, 139, 0 }, + { 255, 139, 139 }, + { 255, 139, 205 }, + { 255, 139, 255 }, + { 255, 205, 0 }, + { 255, 205, 139 }, + { 255, 205, 205 }, + { 255, 205, 255 }, + { 255, 255, 0 }, + { 255, 255, 139 }, + { 255, 255, 205 }, + { 255, 255, 255 }, /* 1.000 79 */ + { 46, 46, 46 }, /* 0.180 80 */ + { 92, 92, 92 }, /* 0.361 81 */ + { 115, 115, 115 }, /* 0.451 82 */ + { 139, 139, 139 }, /* 0.545 83 */ + { 162, 162, 162 }, /* 0.635 84 */ + { 185, 185, 185 }, /* 0.725 85 */ + { 208, 208, 208 }, /* 0.816 86 */ + { 231, 231, 231 } /* 0.906 87 */ +}; + +static inline term_color_t +rgb_to_color_xterm88 (int r, int g, int b) +{ + rgb_t color; + hsv_t hsv; + + color.red = r; color.green = g; color.blue = b; + rgb_to_hsv (color, &hsv); + + if (hsv.saturation < 0.065f) + { + /* Greyscale approximation. */ + float luminance = color_luminance (r, g, b); + if (luminance < 0.090f) + return 0; + else if (luminance < 0.241f) + return 80; + else if (luminance < 0.331f) + return 8; + else if (luminance < 0.406f) + return 81; + else if (luminance < 0.498f) + return 82; + else if (luminance < 0.585f) + return 37; + else if (luminance < 0.680f) + return 84; + else if (luminance < 0.764f) + return 85; + else if (luminance < 0.810f) + return 58; + else if (luminance < 0.857f) + return 86; + else if (luminance < 0.902f) + return 7; + else if (luminance < 0.953f) + return 87; + else + return 15; + } + else + /* Color approximation. */ + return nearest_color (color, colors_of_xterm88, 88); +} + +/* ------------------------ cm_xterm256 color model ------------------------ */ + +/* A non-default color index is in the range 0..255. + Colors 0..15 are the same as in the cm_xterm16 color model. + Colors 16..255 are defined in xterm's 256colres.h. */ + +static const rgb_t colors_of_xterm256[256] = +{ + /* R G B grey index */ + { 0, 0, 0 }, /* 0.000 0 */ + { 205, 0, 0 }, + { 0, 205, 0 }, + { 205, 205, 0 }, + { 0, 0, 205 }, + { 205, 0, 205 }, + { 0, 205, 205 }, + { 229, 229, 229 }, /* 0.898 7 */ + { 77, 77, 77 }, /* 0.302 8 */ + { 255, 0, 0 }, + { 0, 255, 0 }, + { 255, 255, 0 }, + { 0, 0, 255 }, + { 255, 0, 255 }, + { 0, 255, 255 }, + { 255, 255, 255 }, /* 1.000 15 */ + { 0, 0, 0 }, /* 0.000 16 */ + { 0, 0, 42 }, + { 0, 0, 85 }, + { 0, 0, 127 }, + { 0, 0, 170 }, + { 0, 0, 212 }, + { 0, 42, 0 }, + { 0, 42, 42 }, + { 0, 42, 85 }, + { 0, 42, 127 }, + { 0, 42, 170 }, + { 0, 42, 212 }, + { 0, 85, 0 }, + { 0, 85, 42 }, + { 0, 85, 85 }, + { 0, 85, 127 }, + { 0, 85, 170 }, + { 0, 85, 212 }, + { 0, 127, 0 }, + { 0, 127, 42 }, + { 0, 127, 85 }, + { 0, 127, 127 }, + { 0, 127, 170 }, + { 0, 127, 212 }, + { 0, 170, 0 }, + { 0, 170, 42 }, + { 0, 170, 85 }, + { 0, 170, 127 }, + { 0, 170, 170 }, + { 0, 170, 212 }, + { 0, 212, 0 }, + { 0, 212, 42 }, + { 0, 212, 85 }, + { 0, 212, 127 }, + { 0, 212, 170 }, + { 0, 212, 212 }, + { 42, 0, 0 }, + { 42, 0, 42 }, + { 42, 0, 85 }, + { 42, 0, 127 }, + { 42, 0, 170 }, + { 42, 0, 212 }, + { 42, 42, 0 }, + { 42, 42, 42 }, /* 0.165 59 */ + { 42, 42, 85 }, + { 42, 42, 127 }, + { 42, 42, 170 }, + { 42, 42, 212 }, + { 42, 85, 0 }, + { 42, 85, 42 }, + { 42, 85, 85 }, + { 42, 85, 127 }, + { 42, 85, 170 }, + { 42, 85, 212 }, + { 42, 127, 0 }, + { 42, 127, 42 }, + { 42, 127, 85 }, + { 42, 127, 127 }, + { 42, 127, 170 }, + { 42, 127, 212 }, + { 42, 170, 0 }, + { 42, 170, 42 }, + { 42, 170, 85 }, + { 42, 170, 127 }, + { 42, 170, 170 }, + { 42, 170, 212 }, + { 42, 212, 0 }, + { 42, 212, 42 }, + { 42, 212, 85 }, + { 42, 212, 127 }, + { 42, 212, 170 }, + { 42, 212, 212 }, + { 85, 0, 0 }, + { 85, 0, 42 }, + { 85, 0, 85 }, + { 85, 0, 127 }, + { 85, 0, 170 }, + { 85, 0, 212 }, + { 85, 42, 0 }, + { 85, 42, 42 }, + { 85, 42, 85 }, + { 85, 42, 127 }, + { 85, 42, 170 }, + { 85, 42, 212 }, + { 85, 85, 0 }, + { 85, 85, 42 }, + { 85, 85, 85 }, /* 0.333 102 */ + { 85, 85, 127 }, + { 85, 85, 170 }, + { 85, 85, 212 }, + { 85, 127, 0 }, + { 85, 127, 42 }, + { 85, 127, 85 }, + { 85, 127, 127 }, + { 85, 127, 170 }, + { 85, 127, 212 }, + { 85, 170, 0 }, + { 85, 170, 42 }, + { 85, 170, 85 }, + { 85, 170, 127 }, + { 85, 170, 170 }, + { 85, 170, 212 }, + { 85, 212, 0 }, + { 85, 212, 42 }, + { 85, 212, 85 }, + { 85, 212, 127 }, + { 85, 212, 170 }, + { 85, 212, 212 }, + { 127, 0, 0 }, + { 127, 0, 42 }, + { 127, 0, 85 }, + { 127, 0, 127 }, + { 127, 0, 170 }, + { 127, 0, 212 }, + { 127, 42, 0 }, + { 127, 42, 42 }, + { 127, 42, 85 }, + { 127, 42, 127 }, + { 127, 42, 170 }, + { 127, 42, 212 }, + { 127, 85, 0 }, + { 127, 85, 42 }, + { 127, 85, 85 }, + { 127, 85, 127 }, + { 127, 85, 170 }, + { 127, 85, 212 }, + { 127, 127, 0 }, + { 127, 127, 42 }, + { 127, 127, 85 }, + { 127, 127, 127 }, /* 0.498 145 */ + { 127, 127, 170 }, + { 127, 127, 212 }, + { 127, 170, 0 }, + { 127, 170, 42 }, + { 127, 170, 85 }, + { 127, 170, 127 }, + { 127, 170, 170 }, + { 127, 170, 212 }, + { 127, 212, 0 }, + { 127, 212, 42 }, + { 127, 212, 85 }, + { 127, 212, 127 }, + { 127, 212, 170 }, + { 127, 212, 212 }, + { 170, 0, 0 }, + { 170, 0, 42 }, + { 170, 0, 85 }, + { 170, 0, 127 }, + { 170, 0, 170 }, + { 170, 0, 212 }, + { 170, 42, 0 }, + { 170, 42, 42 }, + { 170, 42, 85 }, + { 170, 42, 127 }, + { 170, 42, 170 }, + { 170, 42, 212 }, + { 170, 85, 0 }, + { 170, 85, 42 }, + { 170, 85, 85 }, + { 170, 85, 127 }, + { 170, 85, 170 }, + { 170, 85, 212 }, + { 170, 127, 0 }, + { 170, 127, 42 }, + { 170, 127, 85 }, + { 170, 127, 127 }, + { 170, 127, 170 }, + { 170, 127, 212 }, + { 170, 170, 0 }, + { 170, 170, 42 }, + { 170, 170, 85 }, + { 170, 170, 127 }, + { 170, 170, 170 }, /* 0.667 188 */ + { 170, 170, 212 }, + { 170, 212, 0 }, + { 170, 212, 42 }, + { 170, 212, 85 }, + { 170, 212, 127 }, + { 170, 212, 170 }, + { 170, 212, 212 }, + { 212, 0, 0 }, + { 212, 0, 42 }, + { 212, 0, 85 }, + { 212, 0, 127 }, + { 212, 0, 170 }, + { 212, 0, 212 }, + { 212, 42, 0 }, + { 212, 42, 42 }, + { 212, 42, 85 }, + { 212, 42, 127 }, + { 212, 42, 170 }, + { 212, 42, 212 }, + { 212, 85, 0 }, + { 212, 85, 42 }, + { 212, 85, 85 }, + { 212, 85, 127 }, + { 212, 85, 170 }, + { 212, 85, 212 }, + { 212, 127, 0 }, + { 212, 127, 42 }, + { 212, 127, 85 }, + { 212, 127, 127 }, + { 212, 127, 170 }, + { 212, 127, 212 }, + { 212, 170, 0 }, + { 212, 170, 42 }, + { 212, 170, 85 }, + { 212, 170, 127 }, + { 212, 170, 170 }, + { 212, 170, 212 }, + { 212, 212, 0 }, + { 212, 212, 42 }, + { 212, 212, 85 }, + { 212, 212, 127 }, + { 212, 212, 170 }, + { 212, 212, 212 }, /* 0.831 231 */ + { 8, 8, 8 }, /* 0.031 232 */ + { 18, 18, 18 }, /* 0.071 233 */ + { 28, 28, 28 }, /* 0.110 234 */ + { 38, 38, 38 }, /* 0.149 235 */ + { 48, 48, 48 }, /* 0.188 236 */ + { 58, 58, 58 }, /* 0.227 237 */ + { 68, 68, 68 }, /* 0.267 238 */ + { 78, 78, 78 }, /* 0.306 239 */ + { 88, 88, 88 }, /* 0.345 240 */ + { 98, 98, 98 }, /* 0.384 241 */ + { 108, 108, 108 }, /* 0.424 242 */ + { 118, 118, 118 }, /* 0.463 243 */ + { 128, 128, 128 }, /* 0.502 244 */ + { 138, 138, 138 }, /* 0.541 245 */ + { 148, 148, 148 }, /* 0.580 246 */ + { 158, 158, 158 }, /* 0.620 247 */ + { 168, 168, 168 }, /* 0.659 248 */ + { 178, 178, 178 }, /* 0.698 249 */ + { 188, 188, 188 }, /* 0.737 250 */ + { 198, 198, 198 }, /* 0.776 251 */ + { 208, 208, 208 }, /* 0.816 252 */ + { 218, 218, 218 }, /* 0.855 253 */ + { 228, 228, 228 }, /* 0.894 254 */ + { 238, 238, 238 } /* 0.933 255 */ +}; + +static inline term_color_t +rgb_to_color_xterm256 (int r, int g, int b) +{ + rgb_t color; + hsv_t hsv; + + color.red = r; color.green = g; color.blue = b; + rgb_to_hsv (color, &hsv); + + if (hsv.saturation < 0.065f) + { + /* Greyscale approximation. */ + float luminance = color_luminance (r, g, b); + if (luminance < 0.015f) + return 0; + else if (luminance < 0.051f) + return 232; + else if (luminance < 0.090f) + return 233; + else if (luminance < 0.129f) + return 234; + else if (luminance < 0.157f) + return 235; + else if (luminance < 0.177f) + return 59; + else if (luminance < 0.207f) + return 236; + else if (luminance < 0.247f) + return 237; + else if (luminance < 0.284f) + return 238; + else if (luminance < 0.304f) + return 8; + else if (luminance < 0.319f) + return 239; + else if (luminance < 0.339f) + return 102; + else if (luminance < 0.364f) + return 240; + else if (luminance < 0.404f) + return 241; + else if (luminance < 0.443f) + return 242; + else if (luminance < 0.480f) + return 243; + else if (luminance < 0.500f) + return 145; + else if (luminance < 0.521f) + return 244; + else if (luminance < 0.560f) + return 245; + else if (luminance < 0.600f) + return 246; + else if (luminance < 0.639f) + return 247; + else if (luminance < 0.663f) + return 248; + else if (luminance < 0.682f) + return 188; + else if (luminance < 0.717f) + return 249; + else if (luminance < 0.756f) + return 250; + else if (luminance < 0.796f) + return 251; + else if (luminance < 0.823f) + return 252; + else if (luminance < 0.843f) + return 231; + else if (luminance < 0.874f) + return 253; + else if (luminance < 0.896f) + return 254; + else if (luminance < 0.915f) + return 7; + else if (luminance < 0.966f) + return 255; + else + return 15; + } + else + /* Color approximation. */ + return nearest_color (color, colors_of_xterm256, 256); +} + + +/* ============================= attributes_t ============================= */ + +/* ANSI C and ISO C99 6.7.2.1.(4) forbid use of bit fields for types other + than 'int' or 'unsigned int'. + On the other hand, C++ forbids conversion between enum types and integer + types without an explicit cast. */ +#ifdef __cplusplus +# define BITFIELD_TYPE(orig_type,integer_type) orig_type +#else +# define BITFIELD_TYPE(orig_type,integer_type) integer_type +#endif + +/* Attributes that can be set on a character. */ +typedef struct +{ + BITFIELD_TYPE(term_color_t, signed int) color : 9; + BITFIELD_TYPE(term_color_t, signed int) bgcolor : 9; + BITFIELD_TYPE(term_weight_t, unsigned int) weight : 1; + BITFIELD_TYPE(term_posture_t, unsigned int) posture : 1; + BITFIELD_TYPE(term_underline_t, unsigned int) underline : 1; +} attributes_t; + + +/* ============================ term_ostream_t ============================ */ + +#line 943 "term-ostream.c" +#if !IS_CPLUSPLUS +#define term_ostream_representation any_ostream_representation +#endif +#include "term_ostream.priv.h" + +const typeinfo_t term_ostream_typeinfo = { "term_ostream" }; + +static const typeinfo_t * const term_ostream_superclasses[] = + { term_ostream_SUPERCLASSES }; + +#define super ostream_vtable + +#line 979 "term-ostream.oo.c" + +/* Simplify attributes, according to the terminal's capabilities. */ +static attributes_t +simplify_attributes (term_ostream_t stream, attributes_t attr) +{ + if ((attr.color != COLOR_DEFAULT || attr.bgcolor != COLOR_DEFAULT) + && stream->no_color_video > 0) + { + /* When colors and attributes can not be represented simultaneously, + we give preference to the color. */ + if (stream->no_color_video & 2) + /* Colors conflict with underlining. */ + attr.underline = UNDERLINE_OFF; + if (stream->no_color_video & 32) + /* Colors conflict with bold weight. */ + attr.weight = WEIGHT_NORMAL; + } + if (!stream->supports_foreground) + attr.color = COLOR_DEFAULT; + if (!stream->supports_background) + attr.bgcolor = COLOR_DEFAULT; + if (!stream->supports_weight) + attr.weight = WEIGHT_DEFAULT; + if (!stream->supports_posture) + attr.posture = POSTURE_DEFAULT; + if (!stream->supports_underline) + attr.underline = UNDERLINE_DEFAULT; + return attr; +} + +/* While a line is being output, we need to be careful to restore the + terminal's settings in case of a fatal signal or an exit() call. */ + +/* File descriptor to which out_char shall output escape sequences. */ +static int out_fd = -1; + +/* Filename of out_fd. */ +static const char *out_filename; + +/* Output a single char to out_fd. Ignore errors. */ +static int +out_char_unchecked (int c) +{ + char bytes[1]; + + bytes[0] = (char)c; + full_write (out_fd, bytes, 1); + return 0; +} + +/* State that informs the exit handler what to do. */ +static const char *restore_colors; +static const char *restore_weight; +static const char *restore_posture; +static const char *restore_underline; + +/* The exit handler. */ +static void +restore (void) +{ + /* Only do something while some output was interrupted. */ + if (out_fd >= 0) + { + if (restore_colors != NULL) + tputs (restore_colors, 1, out_char_unchecked); + if (restore_weight != NULL) + tputs (restore_weight, 1, out_char_unchecked); + if (restore_posture != NULL) + tputs (restore_posture, 1, out_char_unchecked); + if (restore_underline != NULL) + tputs (restore_underline, 1, out_char_unchecked); + } +} + +/* The list of signals whose default behaviour is to stop the program. */ +static int stopping_signals[] = + { +#ifdef SIGTSTP + SIGTSTP, +#endif +#ifdef SIGTTIN + SIGTTIN, +#endif +#ifdef SIGTTOU + SIGTTOU, +#endif + 0 + }; + +#define num_stopping_signals (SIZEOF (stopping_signals) - 1) + +static sigset_t stopping_signal_set; + +static void +init_stopping_signal_set () +{ + static bool stopping_signal_set_initialized = false; + if (!stopping_signal_set_initialized) + { + size_t i; + + sigemptyset (&stopping_signal_set); + for (i = 0; i < num_stopping_signals; i++) + sigaddset (&stopping_signal_set, stopping_signals[i]); + + stopping_signal_set_initialized = true; + } +} + +/* Temporarily delay the stopping signals. */ +static inline void +block_stopping_signals () +{ + init_stopping_signal_set (); + sigprocmask (SIG_BLOCK, &stopping_signal_set, NULL); +} + +/* Stop delaying the stopping signals. */ +static inline void +unblock_stopping_signals () +{ + init_stopping_signal_set (); + sigprocmask (SIG_UNBLOCK, &stopping_signal_set, NULL); +} + +/* Compare two sets of attributes for equality. */ +static inline bool +equal_attributes (attributes_t attr1, attributes_t attr2) +{ + return (attr1.color == attr2.color + && attr1.bgcolor == attr2.bgcolor + && attr1.weight == attr2.weight + && attr1.posture == attr2.posture + && attr1.underline == attr2.underline); +} + +/* Signal error after full_write failed. */ +static void +out_error () +{ + error (EXIT_FAILURE, errno, _("error writing to %s"), out_filename); +} + +/* Output a single char to out_fd. */ +static int +out_char (int c) +{ + char bytes[1]; + + bytes[0] = (char)c; + /* We have to write directly to the file descriptor, not to a buffer with + the same destination, because of the padding and sleeping that tputs() + does. */ + if (full_write (out_fd, bytes, 1) < 1) + out_error (); + return 0; +} + +/* Output escape sequences to switch from OLD_ATTR to NEW_ATTR. */ +static void +out_attr_change (term_ostream_t stream, + attributes_t old_attr, attributes_t new_attr) +{ + bool cleared_attributes; + + /* We don't know the default colors of the terminal. The only way to switch + back to a default color is to use stream->orig_pair. */ + if ((new_attr.color == COLOR_DEFAULT && old_attr.color != COLOR_DEFAULT) + || (new_attr.bgcolor == COLOR_DEFAULT && old_attr.bgcolor != COLOR_DEFAULT)) + { + assert (stream->supports_foreground || stream->supports_background); + tputs (stream->orig_pair, 1, out_char); + old_attr.color = COLOR_DEFAULT; + old_attr.bgcolor = COLOR_DEFAULT; + } + + /* To turn off WEIGHT_BOLD, the only way is to output the exit_attribute_mode + sequence. (With xterm, you can also do it with "Esc [ 0 m", but this + escape sequence is not contained in the terminfo description.) It may + also clear the colors; this is the case e.g. when TERM="xterm" or + TERM="ansi". + To turn off UNDERLINE_ON, we can use the exit_underline_mode or the + exit_attribute_mode sequence. In the latter case, it will not only + turn off UNDERLINE_ON, but also the other attributes, and possibly also + the colors. + To turn off POSTURE_ITALIC, we can use the exit_italics_mode or the + exit_attribute_mode sequence. Again, in the latter case, it will not + only turn off POSTURE_ITALIC, but also the other attributes, and possibly + also the colors. + There is no point in setting an attribute just before emitting an + escape sequence that may again turn off the attribute. Therefore we + proceed in two steps: First, clear the attributes that need to be + cleared; then - taking into account that this may have cleared all + attributes and all colors - set the colors and the attributes. + The variable 'cleared_attributes' tells whether an escape sequence + has been output that may have cleared all attributes and all color + settings. */ + cleared_attributes = false; + if (old_attr.posture != POSTURE_NORMAL + && new_attr.posture == POSTURE_NORMAL + && stream->exit_italics_mode != NULL) + { + tputs (stream->exit_italics_mode, 1, out_char); + old_attr.posture = POSTURE_NORMAL; + cleared_attributes = true; + } + if (old_attr.underline != UNDERLINE_OFF + && new_attr.underline == UNDERLINE_OFF + && stream->exit_underline_mode != NULL) + { + tputs (stream->exit_underline_mode, 1, out_char); + old_attr.underline = UNDERLINE_OFF; + cleared_attributes = true; + } + if ((old_attr.weight != WEIGHT_NORMAL + && new_attr.weight == WEIGHT_NORMAL) + || (old_attr.posture != POSTURE_NORMAL + && new_attr.posture == POSTURE_NORMAL + /* implies stream->exit_italics_mode == NULL */) + || (old_attr.underline != UNDERLINE_OFF + && new_attr.underline == UNDERLINE_OFF + /* implies stream->exit_underline_mode == NULL */)) + { + tputs (stream->exit_attribute_mode, 1, out_char); + /* We don't know exactly what effects exit_attribute_mode has, but + this is the minimum effect: */ + old_attr.weight = WEIGHT_NORMAL; + if (stream->exit_italics_mode == NULL) + old_attr.posture = POSTURE_NORMAL; + if (stream->exit_underline_mode == NULL) + old_attr.underline = UNDERLINE_OFF; + cleared_attributes = true; + } + + /* Turn on the colors. */ + if (new_attr.color != old_attr.color + || (cleared_attributes && new_attr.color != COLOR_DEFAULT)) + { + assert (stream->supports_foreground); + assert (new_attr.color != COLOR_DEFAULT); + switch (stream->colormodel) + { + case cm_common8: + assert (new_attr.color >= 0 && new_attr.color < 8); + if (stream->set_a_foreground != NULL) + tputs (tparm (stream->set_a_foreground, + color_bgr (new_attr.color)), + 1, out_char); + else + tputs (tparm (stream->set_foreground, new_attr.color), + 1, out_char); + break; + /* When we are dealing with an xterm, there is no need to go through + tputs() because we know there is no padding and sleeping. */ + case cm_xterm8: + assert (new_attr.color >= 0 && new_attr.color < 8); + { + char bytes[5]; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '3'; bytes[3] = '0' + new_attr.color; + bytes[4] = 'm'; + if (full_write (out_fd, bytes, 5) < 5) + out_error (); + } + break; + case cm_xterm16: + assert (new_attr.color >= 0 && new_attr.color < 16); + { + char bytes[5]; + bytes[0] = 0x1B; bytes[1] = '['; + if (new_attr.color < 8) + { + bytes[2] = '3'; bytes[3] = '0' + new_attr.color; + } + else + { + bytes[2] = '9'; bytes[3] = '0' + (new_attr.color - 8); + } + bytes[4] = 'm'; + if (full_write (out_fd, bytes, 5) < 5) + out_error (); + } + break; + case cm_xterm88: + assert (new_attr.color >= 0 && new_attr.color < 88); + { + char bytes[10]; + char *p; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '3'; bytes[3] = '8'; bytes[4] = ';'; + bytes[5] = '5'; bytes[6] = ';'; + p = bytes + 7; + if (new_attr.color >= 10) + *p++ = '0' + (new_attr.color / 10); + *p++ = '0' + (new_attr.color % 10); + *p++ = 'm'; + if (full_write (out_fd, bytes, p - bytes) < p - bytes) + out_error (); + } + break; + case cm_xterm256: + assert (new_attr.color >= 0 && new_attr.color < 256); + { + char bytes[11]; + char *p; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '3'; bytes[3] = '8'; bytes[4] = ';'; + bytes[5] = '5'; bytes[6] = ';'; + p = bytes + 7; + if (new_attr.color >= 100) + *p++ = '0' + (new_attr.color / 100); + if (new_attr.color >= 10) + *p++ = '0' + ((new_attr.color % 100) / 10); + *p++ = '0' + (new_attr.color % 10); + *p++ = 'm'; + if (full_write (out_fd, bytes, p - bytes) < p - bytes) + out_error (); + } + break; + default: + abort (); + } + } + if (new_attr.bgcolor != old_attr.bgcolor + || (cleared_attributes && new_attr.bgcolor != COLOR_DEFAULT)) + { + assert (stream->supports_background); + assert (new_attr.bgcolor != COLOR_DEFAULT); + switch (stream->colormodel) + { + case cm_common8: + assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 8); + if (stream->set_a_background != NULL) + tputs (tparm (stream->set_a_background, + color_bgr (new_attr.bgcolor)), + 1, out_char); + else + tputs (tparm (stream->set_background, new_attr.bgcolor), + 1, out_char); + break; + /* When we are dealing with an xterm, there is no need to go through + tputs() because we know there is no padding and sleeping. */ + case cm_xterm8: + assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 8); + { + char bytes[5]; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '4'; bytes[3] = '0' + new_attr.bgcolor; + bytes[4] = 'm'; + if (full_write (out_fd, bytes, 5) < 5) + out_error (); + } + break; + case cm_xterm16: + assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 16); + { + char bytes[6]; + bytes[0] = 0x1B; bytes[1] = '['; + if (new_attr.bgcolor < 8) + { + bytes[2] = '4'; bytes[3] = '0' + new_attr.bgcolor; + bytes[4] = 'm'; + if (full_write (out_fd, bytes, 5) < 5) + out_error (); + } + else + { + bytes[2] = '1'; bytes[3] = '0'; + bytes[4] = '0' + (new_attr.bgcolor - 8); bytes[5] = 'm'; + if (full_write (out_fd, bytes, 6) < 6) + out_error (); + } + } + break; + case cm_xterm88: + assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 88); + { + char bytes[10]; + char *p; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '4'; bytes[3] = '8'; bytes[4] = ';'; + bytes[5] = '5'; bytes[6] = ';'; + p = bytes + 7; + if (new_attr.bgcolor >= 10) + *p++ = '0' + (new_attr.bgcolor / 10); + *p++ = '0' + (new_attr.bgcolor % 10); + *p++ = 'm'; + if (full_write (out_fd, bytes, p - bytes) < p - bytes) + out_error (); + } + break; + case cm_xterm256: + assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 256); + { + char bytes[11]; + char *p; + bytes[0] = 0x1B; bytes[1] = '['; + bytes[2] = '4'; bytes[3] = '8'; bytes[4] = ';'; + bytes[5] = '5'; bytes[6] = ';'; + p = bytes + 7; + if (new_attr.bgcolor >= 100) + *p++ = '0' + (new_attr.bgcolor / 100); + if (new_attr.bgcolor >= 10) + *p++ = '0' + ((new_attr.bgcolor % 100) / 10); + *p++ = '0' + (new_attr.bgcolor % 10); + *p++ = 'm'; + if (full_write (out_fd, bytes, p - bytes) < p - bytes) + out_error (); + } + break; + default: + abort (); + } + } + + if (new_attr.weight != old_attr.weight + || (cleared_attributes && new_attr.weight != WEIGHT_DEFAULT)) + { + assert (stream->supports_weight); + assert (new_attr.weight != WEIGHT_DEFAULT); + /* This implies: */ + assert (new_attr.weight == WEIGHT_BOLD); + tputs (stream->enter_bold_mode, 1, out_char); + } + if (new_attr.posture != old_attr.posture + || (cleared_attributes && new_attr.posture != POSTURE_DEFAULT)) + { + assert (stream->supports_posture); + assert (new_attr.posture != POSTURE_DEFAULT); + /* This implies: */ + assert (new_attr.posture == POSTURE_ITALIC); + tputs (stream->enter_italics_mode, 1, out_char); + } + if (new_attr.underline != old_attr.underline + || (cleared_attributes && new_attr.underline != UNDERLINE_DEFAULT)) + { + assert (stream->supports_underline); + assert (new_attr.underline != UNDERLINE_DEFAULT); + /* This implies: */ + assert (new_attr.underline == UNDERLINE_ON); + tputs (stream->enter_underline_mode, 1, out_char); + } +} + +/* Output the buffered line atomically. + The terminal is assumed to have the default state (regarding colors and + attributes) before this call. It is left in default state after this + call (regardless of stream->curr_attr). */ +static void +output_buffer (term_ostream_t stream) +{ + attributes_t default_attr; + attributes_t attr; + const char *cp; + const attributes_t *ap; + size_t len; + size_t n; + + default_attr.color = COLOR_DEFAULT; + default_attr.bgcolor = COLOR_DEFAULT; + default_attr.weight = WEIGHT_DEFAULT; + default_attr.posture = POSTURE_DEFAULT; + default_attr.underline = UNDERLINE_DEFAULT; + + attr = default_attr; + + cp = stream->buffer; + ap = stream->attrbuffer; + len = stream->buflen; + + /* See how much we can output without blocking signals. */ + for (n = 0; n < len && equal_attributes (ap[n], attr); n++) + ; + if (n > 0) + { + if (full_write (stream->fd, cp, n) < n) + error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename); + cp += n; + ap += n; + len -= n; + } + if (len > 0) + { + /* Block fatal signals, so that a SIGINT or similar doesn't interrupt + us without the possibility of restoring the terminal's state. */ + block_fatal_signals (); + /* Likewise for SIGTSTP etc. */ + block_stopping_signals (); + + /* Enable the exit handler for restoring the terminal's state. */ + restore_colors = + (stream->supports_foreground || stream->supports_background + ? stream->orig_pair + : NULL); + restore_weight = + (stream->supports_weight ? stream->exit_attribute_mode : NULL); + restore_posture = + (stream->supports_posture + ? (stream->exit_italics_mode != NULL + ? stream->exit_italics_mode + : stream->exit_attribute_mode) + : NULL); + restore_underline = + (stream->supports_underline + ? (stream->exit_underline_mode != NULL + ? stream->exit_underline_mode + : stream->exit_attribute_mode) + : NULL); + out_fd = stream->fd; + out_filename = stream->filename; + + while (len > 0) + { + /* Activate the attributes in *ap. */ + out_attr_change (stream, attr, *ap); + attr = *ap; + /* See how many characters we can output without further attribute + changes. */ + for (n = 1; n < len && equal_attributes (ap[n], attr); n++) + ; + if (full_write (stream->fd, cp, n) < n) + error (EXIT_FAILURE, errno, _("error writing to %s"), + stream->filename); + cp += n; + ap += n; + len -= n; + } + + /* Switch back to the default attributes. */ + out_attr_change (stream, attr, default_attr); + + /* Disable the exit handler. */ + out_fd = -1; + out_filename = NULL; + + /* Unblock fatal and stopping signals. */ + unblock_stopping_signals (); + unblock_fatal_signals (); + } + stream->buflen = 0; +} + +/* Implementation of ostream_t methods. */ + +static term_color_t +term_ostream__rgb_to_color (term_ostream_t stream, int red, int green, int blue) +{ + switch (stream->colormodel) + { + case cm_monochrome: + return rgb_to_color_monochrome (); + case cm_common8: + return rgb_to_color_common8 (red, green, blue); + case cm_xterm8: + return rgb_to_color_xterm8 (red, green, blue); + case cm_xterm16: + return rgb_to_color_xterm16 (red, green, blue); + case cm_xterm88: + return rgb_to_color_xterm88 (red, green, blue); + case cm_xterm256: + return rgb_to_color_xterm256 (red, green, blue); + default: + abort (); + } +} + +static void +term_ostream__write_mem (term_ostream_t stream, const void *data, size_t len) +{ + const char *cp = (const char *) data; + while (len > 0) + { + /* Look for the next newline. */ + const char *newline = (const char *) memchr (cp, '\n', len); + size_t n = (newline != NULL ? newline - cp : len); + + /* Copy n bytes into the buffer. */ + if (n > stream->allocated - stream->buflen) + { + size_t new_allocated = + xmax (xsum (stream->buflen, n), + xsum (stream->allocated, stream->allocated)); + if (size_overflow_p (new_allocated)) + error (EXIT_FAILURE, 0, + _("%s: too much output, buffer size overflow"), + "term_ostream"); + stream->buffer = (char *) xrealloc (stream->buffer, new_allocated); + stream->attrbuffer = + (attributes_t *) + xrealloc (stream->attrbuffer, + new_allocated * sizeof (attributes_t)); + stream->allocated = new_allocated; + } + memcpy (stream->buffer + stream->buflen, cp, n); + { + attributes_t attr = stream->simp_attr; + attributes_t *ap = stream->attrbuffer + stream->buflen; + attributes_t *ap_end = ap + n; + for (; ap < ap_end; ap++) + *ap = attr; + } + stream->buflen += n; + + if (newline != NULL) + { + output_buffer (stream); + if (full_write (stream->fd, "\n", 1) < 1) + error (EXIT_FAILURE, errno, _("error writing to %s"), + stream->filename); + cp += n + 1; /* cp = newline + 1; */ + len -= n + 1; + } + else + break; + } +} + +static void +term_ostream__flush (term_ostream_t stream) +{ + output_buffer (stream); +} + +static void +term_ostream__free (term_ostream_t stream) +{ + term_ostream_flush (stream); + free (stream->filename); + if (stream->set_a_foreground != NULL) + free (stream->set_a_foreground); + if (stream->set_foreground != NULL) + free (stream->set_foreground); + if (stream->set_a_background != NULL) + free (stream->set_a_background); + if (stream->set_background != NULL) + free (stream->set_background); + if (stream->orig_pair != NULL) + free (stream->orig_pair); + if (stream->enter_bold_mode != NULL) + free (stream->enter_bold_mode); + if (stream->enter_italics_mode != NULL) + free (stream->enter_italics_mode); + if (stream->exit_italics_mode != NULL) + free (stream->exit_italics_mode); + if (stream->enter_underline_mode != NULL) + free (stream->enter_underline_mode); + if (stream->exit_underline_mode != NULL) + free (stream->exit_underline_mode); + if (stream->exit_attribute_mode != NULL) + free (stream->exit_attribute_mode); + free (stream->buffer); + free (stream); +} + +/* Implementation of term_ostream_t methods. */ + +static term_color_t +term_ostream__get_color (term_ostream_t stream) +{ + return stream->curr_attr.color; +} + +static void +term_ostream__set_color (term_ostream_t stream, term_color_t color) +{ + stream->curr_attr.color = color; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); +} + +static term_color_t +term_ostream__get_bgcolor (term_ostream_t stream) +{ + return stream->curr_attr.bgcolor; +} + +static void +term_ostream__set_bgcolor (term_ostream_t stream, term_color_t color) +{ + stream->curr_attr.bgcolor = color; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); +} + +static term_weight_t +term_ostream__get_weight (term_ostream_t stream) +{ + return stream->curr_attr.weight; +} + +static void +term_ostream__set_weight (term_ostream_t stream, term_weight_t weight) +{ + stream->curr_attr.weight = weight; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); +} + +static term_posture_t +term_ostream__get_posture (term_ostream_t stream) +{ + return stream->curr_attr.posture; +} + +static void +term_ostream__set_posture (term_ostream_t stream, term_posture_t posture) +{ + stream->curr_attr.posture = posture; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); +} + +static term_underline_t +term_ostream__get_underline (term_ostream_t stream) +{ + return stream->curr_attr.underline; +} + +static void +term_ostream__set_underline (term_ostream_t stream, term_underline_t underline) +{ + stream->curr_attr.underline = underline; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); +} + +/* Constructor. */ + +static inline char * +xstrdup0 (const char *str) +{ + if (str == NULL) + return NULL; +#if HAVE_TERMINFO + if (str == (const char *)(-1)) + return NULL; +#endif + return xstrdup (str); +} + +term_ostream_t +term_ostream_create (int fd, const char *filename) +{ + term_ostream_t stream = XMALLOC (struct term_ostream_representation); + const char *term; + + stream->base.vtable = &term_ostream_vtable; + stream->fd = fd; + stream->filename = xstrdup (filename); + + /* Defaults. */ + stream->max_colors = -1; + stream->no_color_video = -1; + stream->set_a_foreground = NULL; + stream->set_foreground = NULL; + stream->set_a_background = NULL; + stream->set_background = NULL; + stream->orig_pair = NULL; + stream->enter_bold_mode = NULL; + stream->enter_italics_mode = NULL; + stream->exit_italics_mode = NULL; + stream->enter_underline_mode = NULL; + stream->exit_underline_mode = NULL; + stream->exit_attribute_mode = NULL; + + /* Retrieve the terminal type. */ + term = getenv ("TERM"); + if (term != NULL && term[0] != '\0') + { + /* When the terminfo function are available, we prefer them over the + termcap functions because + 1. they don't risk a buffer overflow, + 2. on OSF/1, for TERM=xterm, the tiget* functions provide access + to the number of colors and the color escape sequences, whereas + the tget* functions don't provide them. */ +#if HAVE_TERMINFO + int err = 1; + + if (setupterm (term, fd, &err) || err == 1) + { + /* Retrieve particular values depending on the terminal type. */ + stream->max_colors = tigetnum ("colors"); + stream->no_color_video = tigetnum ("ncv"); + stream->set_a_foreground = xstrdup0 (tigetstr ("setaf")); + stream->set_foreground = xstrdup0 (tigetstr ("setf")); + stream->set_a_background = xstrdup0 (tigetstr ("setab")); + stream->set_background = xstrdup0 (tigetstr ("setb")); + stream->orig_pair = xstrdup0 (tigetstr ("op")); + stream->enter_bold_mode = xstrdup0 (tigetstr ("bold")); + stream->enter_italics_mode = xstrdup0 (tigetstr ("sitm")); + stream->exit_italics_mode = xstrdup0 (tigetstr ("ritm")); + stream->enter_underline_mode = xstrdup0 (tigetstr ("smul")); + stream->exit_underline_mode = xstrdup0 (tigetstr ("rmul")); + stream->exit_attribute_mode = xstrdup0 (tigetstr ("sgr0")); + } +#elif HAVE_TERMCAP + struct { char buf[1024]; char canary[4]; } termcapbuf; + int retval; + + /* Call tgetent, being defensive against buffer overflow. */ + memcpy (termcapbuf.canary, "CnRy", 4); + retval = tgetent (termcapbuf.buf, term); + if (memcmp (termcapbuf.canary, "CnRy", 4) != 0) + /* Buffer overflow! */ + abort (); + + if (retval > 0) + { + struct { char buf[1024]; char canary[4]; } termentrybuf; + char *termentryptr; + + /* Prepare for calling tgetstr, being defensive against buffer + overflow. ncurses' tgetstr() supports a second argument NULL, + but NetBSD's tgetstr() doesn't. */ + memcpy (termentrybuf.canary, "CnRz", 4); + #define TEBP ((termentryptr = termentrybuf.buf), &termentryptr) + + /* Retrieve particular values depending on the terminal type. */ + stream->max_colors = tgetnum ("Co"); + stream->no_color_video = tgetnum ("NC"); + stream->set_a_foreground = xstrdup0 (tgetstr ("AF", TEBP)); + stream->set_foreground = xstrdup0 (tgetstr ("Sf", TEBP)); + stream->set_a_background = xstrdup0 (tgetstr ("AB", TEBP)); + stream->set_background = xstrdup0 (tgetstr ("Sb", TEBP)); + stream->orig_pair = xstrdup0 (tgetstr ("op", TEBP)); + stream->enter_bold_mode = xstrdup0 (tgetstr ("md", TEBP)); + stream->enter_italics_mode = xstrdup0 (tgetstr ("ZH", TEBP)); + stream->exit_italics_mode = xstrdup0 (tgetstr ("ZR", TEBP)); + stream->enter_underline_mode = xstrdup0 (tgetstr ("us", TEBP)); + stream->exit_underline_mode = xstrdup0 (tgetstr ("ue", TEBP)); + stream->exit_attribute_mode = xstrdup0 (tgetstr ("me", TEBP)); + +# ifdef __BEOS__ + /* The BeOS termcap entry for "beterm" is broken: For "AF" and "AB" + it contains balues in terminfo syntax but the system's tparam() + function understands only the termcap syntax. */ + if (stream->set_a_foreground != NULL + && strcmp (stream->set_a_foreground, "\033[3%p1%dm") == 0) + { + free (stream->set_a_foreground); + stream->set_a_foreground = xstrdup ("\033[3%dm"); + } + if (stream->set_a_background != NULL + && strcmp (stream->set_a_background, "\033[4%p1%dm") == 0) + { + free (stream->set_a_background); + stream->set_a_background = xstrdup ("\033[4%dm"); + } +# endif + + /* The termcap entry for cygwin is broken: It has no "ncv" value, + but bold and underline are actually rendered through colors. */ + if (strcmp (term, "cygwin") == 0) + stream->no_color_video |= 2 | 32; + + /* Done with tgetstr. Detect possible buffer overflow. */ + #undef TEBP + if (memcmp (termentrybuf.canary, "CnRz", 4) != 0) + /* Buffer overflow! */ + abort (); + } +#else + /* Fallback code for platforms with neither the terminfo nor the termcap + functions, such as mingw. + Assume the ANSI escape sequences. Extracted through + "TERM=ansi infocmp", replacing \E with \033. */ + stream->max_colors = 8; + stream->no_color_video = 3; + stream->set_a_foreground = xstrdup ("\033[3%p1%dm"); + stream->set_a_background = xstrdup ("\033[4%p1%dm"); + stream->orig_pair = xstrdup ("\033[39;49m"); + stream->enter_bold_mode = xstrdup ("\033[1m"); + stream->enter_underline_mode = xstrdup ("\033[4m"); + stream->exit_underline_mode = xstrdup ("\033[m"); + stream->exit_attribute_mode = xstrdup ("\033[0;10m"); +#endif + + /* AIX 4.3.2, IRIX 6.5, HP-UX 11, Solaris 7..10 all lack the + description of color capabilities of "xterm" and "xterms" + in their terminfo database. But it is important to have + color in xterm. So we provide the color capabilities here. */ + if (stream->max_colors <= 1 + && (strcmp (term, "xterm") == 0 || strcmp (term, "xterms") == 0)) + { + stream->max_colors = 8; + stream->set_a_foreground = xstrdup ("\033[3%p1%dm"); + stream->set_a_background = xstrdup ("\033[4%p1%dm"); + stream->orig_pair = xstrdup ("\033[39;49m"); + } + } + + /* Infer the capabilities. */ + stream->supports_foreground = + (stream->max_colors >= 8 + && (stream->set_a_foreground != NULL || stream->set_foreground != NULL) + && stream->orig_pair != NULL); + stream->supports_background = + (stream->max_colors >= 8 + && (stream->set_a_background != NULL || stream->set_background != NULL) + && stream->orig_pair != NULL); + stream->colormodel = + (stream->supports_foreground || stream->supports_background + ? (term != NULL + && (/* Recognize xterm-16color, xterm-88color, xterm-256color. */ + (strlen (term) >= 5 && memcmp (term, "xterm", 5) == 0) + || /* Recognize rxvt-16color. */ + (strlen (term) >= 4 && memcmp (term, "rxvt", 7) == 0) + || /* Recognize konsole-16color. */ + (strlen (term) >= 7 && memcmp (term, "konsole", 7) == 0)) + ? (stream->max_colors == 256 ? cm_xterm256 : + stream->max_colors == 88 ? cm_xterm88 : + stream->max_colors == 16 ? cm_xterm16 : + cm_xterm8) + : cm_common8) + : cm_monochrome); + stream->supports_weight = + (stream->enter_bold_mode != NULL && stream->exit_attribute_mode != NULL); + stream->supports_posture = + (stream->enter_italics_mode != NULL + && (stream->exit_italics_mode != NULL + || stream->exit_attribute_mode != NULL)); + stream->supports_underline = + (stream->enter_underline_mode != NULL + && (stream->exit_underline_mode != NULL + || stream->exit_attribute_mode != NULL)); + + /* Initialize the buffer. */ + stream->allocated = 120; + stream->buffer = XNMALLOC (stream->allocated, char); + stream->attrbuffer = XNMALLOC (stream->allocated, attributes_t); + stream->buflen = 0; + + /* Initialize the current attributes. */ + stream->curr_attr.color = COLOR_DEFAULT; + stream->curr_attr.bgcolor = COLOR_DEFAULT; + stream->curr_attr.weight = WEIGHT_DEFAULT; + stream->curr_attr.posture = POSTURE_DEFAULT; + stream->curr_attr.underline = UNDERLINE_DEFAULT; + stream->simp_attr = simplify_attributes (stream, stream->curr_attr); + + /* Register an exit handler. */ + { + static bool registered = false; + if (!registered) + { + atexit (restore); + registered = true; + } + } + + return stream; +} + +#line 1905 "term-ostream.c" + +const struct term_ostream_implementation term_ostream_vtable = +{ + term_ostream_superclasses, + sizeof (term_ostream_superclasses) / sizeof (term_ostream_superclasses[0]), + sizeof (struct term_ostream_representation), + term_ostream__write_mem, + term_ostream__flush, + term_ostream__free, + term_ostream__rgb_to_color, + term_ostream__get_color, + term_ostream__set_color, + term_ostream__get_bgcolor, + term_ostream__set_bgcolor, + term_ostream__get_weight, + term_ostream__set_weight, + term_ostream__get_posture, + term_ostream__set_posture, + term_ostream__get_underline, + term_ostream__set_underline, +}; + +#if !HAVE_INLINE + +/* Define the functions that invoke the methods. */ + +void +term_ostream_write_mem (term_ostream_t first_arg, const void *data, size_t len) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->write_mem (first_arg,data,len); +} + +void +term_ostream_flush (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->flush (first_arg); +} + +void +term_ostream_free (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->free (first_arg); +} + +term_color_t +term_ostream_rgb_to_color (term_ostream_t first_arg, int red, int green, int blue) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->rgb_to_color (first_arg,red,green,blue); +} + +term_color_t +term_ostream_get_color (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->get_color (first_arg); +} + +void +term_ostream_set_color (term_ostream_t first_arg, term_color_t color) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->set_color (first_arg,color); +} + +term_color_t +term_ostream_get_bgcolor (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->get_bgcolor (first_arg); +} + +void +term_ostream_set_bgcolor (term_ostream_t first_arg, term_color_t color) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->set_bgcolor (first_arg,color); +} + +term_weight_t +term_ostream_get_weight (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->get_weight (first_arg); +} + +void +term_ostream_set_weight (term_ostream_t first_arg, term_weight_t weight) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->set_weight (first_arg,weight); +} + +term_posture_t +term_ostream_get_posture (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->get_posture (first_arg); +} + +void +term_ostream_set_posture (term_ostream_t first_arg, term_posture_t posture) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->set_posture (first_arg,posture); +} + +term_underline_t +term_ostream_get_underline (term_ostream_t first_arg) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + return vtable->get_underline (first_arg); +} + +void +term_ostream_set_underline (term_ostream_t first_arg, term_underline_t underline) +{ + const struct term_ostream_implementation *vtable = + ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable; + vtable->set_underline (first_arg,underline); +} + +#endif |