Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gettext-tools / gnulib-lib / term-ostream.c
1 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2
3 #line 1 "term-ostream.oo.c"
4 /* Output stream for attributed text, producing ANSI escape sequences.
5    Copyright (C) 2006-2008 Free Software Foundation, Inc.
6    Written by Bruno Haible <bruno@clisp.org>, 2006.
7
8    This program is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21 #include <config.h>
22
23 /* Specification.  */
24 #include "term-ostream.h"
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "error.h"
34 #include "fatal-signal.h"
35 #include "full-write.h"
36 #include "terminfo.h"
37 #include "xalloc.h"
38 #include "xsize.h"
39 #include "gettext.h"
40
41 #define _(str) gettext (str)
42
43 #if HAVE_TPARAM
44 /* GNU termcap's tparam() function requires a buffer argument.  Make it so
45    large that there is no risk that tparam() needs to call malloc().  */
46 static char tparambuf[100];
47 /* Define tparm in terms of tparam.  In the scope of this file, it is called
48    with at most one argument after the string.  */
49 # define tparm(str, arg1) \
50   tparam (str, tparambuf, sizeof (tparambuf), arg1)
51 #endif
52
53 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
54
55
56 /* =========================== Color primitives =========================== */
57
58 /* A color in RGB format.  */
59 typedef struct
60 {
61   unsigned int red   : 8; /* range 0..255 */
62   unsigned int green : 8; /* range 0..255 */
63   unsigned int blue  : 8; /* range 0..255 */
64 } rgb_t;
65
66 /* A color in HSV (a.k.a. HSB) format.  */
67 typedef struct
68 {
69   float hue;        /* normalized to interval [0,6) */
70   float saturation; /* normalized to interval [0,1] */
71   float brightness; /* a.k.a. value, normalized to interval [0,1] */
72 } hsv_t;
73
74 /* Conversion of a color in RGB to HSV format.  */
75 static void
76 rgb_to_hsv (rgb_t c, hsv_t *result)
77 {
78   unsigned int r = c.red;
79   unsigned int g = c.green;
80   unsigned int b = c.blue;
81
82   if (r > g)
83     {
84       if (b > r)
85         {
86           /* b > r > g, so max = b, min = g */
87           result->hue = 4.0f + (float) (r - g) / (float) (b - g);
88           result->saturation = 1.0f - (float) g / (float) b;
89           result->brightness = (float) b / 255.0f;
90         }
91       else if (b <= g)
92         {
93           /* r > g >= b, so max = r, min = b */
94           result->hue = 0.0f + (float) (g - b) / (float) (r - b);
95           result->saturation = 1.0f - (float) b / (float) r;
96           result->brightness = (float) r / 255.0f;
97         }
98       else
99         {
100           /* r >= b > g, so max = r, min = g */
101           result->hue = 6.0f - (float) (b - g) / (float) (r - g);
102           result->saturation = 1.0f - (float) g / (float) r;
103           result->brightness = (float) r / 255.0f;
104         }
105     }
106   else
107     {
108       if (b > g)
109         {
110           /* b > g >= r, so max = b, min = r */
111           result->hue = 4.0f - (float) (g - r) / (float) (b - r);
112           result->saturation = 1.0f - (float) r / (float) b;
113           result->brightness = (float) b / 255.0f;
114         }
115       else if (b < r)
116         {
117           /* g >= r > b, so max = g, min = b */
118           result->hue = 2.0f - (float) (r - b) / (float) (g - b);
119           result->saturation = 1.0f - (float) b / (float) g;
120           result->brightness = (float) g / 255.0f;
121         }
122       else if (g > r)
123         {
124           /* g >= b >= r, g > r, so max = g, min = r */
125           result->hue = 2.0f + (float) (b - r) / (float) (g - r);
126           result->saturation = 1.0f - (float) r / (float) g;
127           result->brightness = (float) g / 255.0f;
128         }
129       else
130         {
131           /* r = g = b.  A grey color.  */
132           result->hue = 0; /* arbitrary */
133           result->saturation = 0;
134           result->brightness = (float) r / 255.0f;
135         }
136     }
137 }
138
139 /* Square of distance of two colors.  */
140 static float
141 color_distance (const hsv_t *color1, const hsv_t *color2)
142 {
143 #if 0
144   /* Formula taken from "John Smith: Color Similarity",
145        http://www.ctr.columbia.edu/~jrsmith/html/pubs/acmmm96/node8.html.  */
146   float angle1 = color1->hue * 1.04719755f; /* normalize to [0,2π] */
147   float angle2 = color2->hue * 1.04719755f; /* normalize to [0,2π] */
148   float delta_x = color1->saturation * cosf (angle1)
149                   - color2->saturation * cosf (angle2);
150   float delta_y = color1->saturation * sinf (angle1)
151                   - color2->saturation * sinf (angle2);
152   float delta_v = color1->brightness
153                   - color2->brightness;
154
155   return delta_x * delta_x + delta_y * delta_y + delta_v * delta_v;
156 #else
157   /* Formula that considers hue differences with more weight than saturation
158      or brightness differences, like the human eye does.  */
159   float delta_hue =
160     (color1->hue >= color2->hue
161      ? (color1->hue - color2->hue >= 3.0f
162         ? 6.0f + color2->hue - color1->hue
163         : color1->hue - color2->hue)
164      : (color2->hue - color1->hue >= 3.0f
165         ? 6.0f + color1->hue - color2->hue
166         : color2->hue - color1->hue));
167   float min_saturation =
168     (color1->saturation < color2->saturation
169      ? color1->saturation
170      : color2->saturation);
171   float delta_saturation = color1->saturation - color2->saturation;
172   float delta_brightness = color1->brightness - color2->brightness;
173
174   return delta_hue * delta_hue * min_saturation
175          + delta_saturation * delta_saturation * 0.2f
176          + delta_brightness * delta_brightness * 0.8f;
177 #endif
178 }
179
180 /* Return the index of the color in a color table that is nearest to a given
181    color.  */
182 static unsigned int
183 nearest_color (rgb_t given, const rgb_t *table, unsigned int table_size)
184 {
185   hsv_t given_hsv;
186   unsigned int best_index;
187   float best_distance;
188   unsigned int i;
189
190   assert (table_size > 0);
191
192   rgb_to_hsv (given, &given_hsv);
193
194   best_index = 0;
195   best_distance = 1000000.0f;
196   for (i = 0; i < table_size; i++)
197     {
198       hsv_t i_hsv;
199
200       rgb_to_hsv (table[i], &i_hsv);
201
202       /* Avoid converting a color to grey, or fading out a color too much.  */
203       if (i_hsv.saturation > given_hsv.saturation * 0.5f)
204         {
205           float distance = color_distance (&given_hsv, &i_hsv);
206           if (distance < best_distance)
207             {
208               best_index = i;
209               best_distance = distance;
210             }
211         }
212     }
213
214 #if 0 /* Debugging code */
215   hsv_t best_hsv;
216   rgb_to_hsv (table[best_index], &best_hsv);
217   fprintf (stderr, "nearest: (%d,%d,%d) = (%f,%f,%f)\n    -> (%f,%f,%f) = (%d,%d,%d)\n",
218                    given.red, given.green, given.blue,
219                    (double)given_hsv.hue, (double)given_hsv.saturation, (double)given_hsv.brightness,
220                    (double)best_hsv.hue, (double)best_hsv.saturation, (double)best_hsv.brightness,
221                    table[best_index].red, table[best_index].green, table[best_index].blue);
222 #endif
223
224   return best_index;
225 }
226
227 /* The luminance of a color.  This is the brightness of the color, as it
228    appears to the human eye.  This must be used in color to grey conversion.  */
229 static float
230 color_luminance (int r, int g, int b)
231 {
232   /* Use the luminance model used by NTSC and JPEG.
233      Taken from http://www.fho-emden.de/~hoffmann/gray10012001.pdf .
234      No need to care about rounding errors leading to luminance > 1;
235      this cannot happen.  */
236   return (0.299f * r + 0.587f * g + 0.114f * b) / 255.0f;
237 }
238
239
240 /* ============================= Color models ============================= */
241
242 /* The color model used by the terminal.  */
243 typedef enum
244 {
245   cm_monochrome,        /* No colors.  */
246   cm_common8,           /* Usual terminal with at least 8 colors.  */
247   cm_xterm8,            /* TERM=xterm, with 8 colors.  */
248   cm_xterm16,           /* TERM=xterm-16color, with 16 colors.  */
249   cm_xterm88,           /* TERM=xterm-88color, with 88 colors.  */
250   cm_xterm256           /* TERM=xterm-256color, with 256 colors.  */
251 } colormodel_t;
252
253 /* ----------------------- cm_monochrome color model ----------------------- */
254
255 /* A non-default color index doesn't exist in this color model.  */
256 static inline term_color_t
257 rgb_to_color_monochrome ()
258 {
259   return COLOR_DEFAULT;
260 }
261
262 /* ------------------------ cm_common8 color model ------------------------ */
263
264 /* A non-default color index is in the range 0..7.
265                        RGB components
266    COLOR_BLACK         000
267    COLOR_BLUE          001
268    COLOR_GREEN         010
269    COLOR_CYAN          011
270    COLOR_RED           100
271    COLOR_MAGENTA       101
272    COLOR_YELLOW        110
273    COLOR_WHITE         111 */
274 static const rgb_t colors_of_common8[8] =
275 {
276   /* R    G    B        grey  index */
277   {   0,   0,   0 }, /* 0.000   0 */
278   {   0,   0, 255 },
279   {   0, 255,   0 },
280   {   0, 255, 255 },
281   { 255,   0,   0 },
282   { 255,   0, 255 },
283   { 255, 255,   0 },
284   { 255, 255, 255 }  /* 1.000   7 */
285 };
286
287 static inline term_color_t
288 rgb_to_color_common8 (int r, int g, int b)
289 {
290   rgb_t color;
291   hsv_t hsv;
292
293   color.red = r; color.green = g; color.blue = b;
294   rgb_to_hsv (color, &hsv);
295
296   if (hsv.saturation < 0.065f)
297     {
298       /* Greyscale approximation.  */
299       float luminance = color_luminance (r, g, b);
300       if (luminance < 0.500f)
301         return 0;
302       else
303         return 7;
304     }
305   else
306     /* Color approximation.  */
307     return nearest_color (color, colors_of_common8, 8);
308 }
309
310 /* Convert a cm_common8 color in RGB encoding to BGR encoding.
311    See the ncurses terminfo(5) manual page, section "Color Handling", for an
312    explanation why this is needed.  */
313 static inline int
314 color_bgr (term_color_t color)
315 {
316   return ((color & 4) >> 2) | (color & 2) | ((color & 1) << 2);
317 }
318
319 /* ------------------------- cm_xterm8 color model ------------------------- */
320
321 /* A non-default color index is in the range 0..7.
322                        BGR components
323    COLOR_BLACK         000
324    COLOR_RED           001
325    COLOR_GREEN         010
326    COLOR_YELLOW        011
327    COLOR_BLUE          100
328    COLOR_MAGENTA       101
329    COLOR_CYAN          110
330    COLOR_WHITE         111 */
331 static const rgb_t colors_of_xterm8[8] =
332 {
333   /* The real xterm's colors are dimmed; assume full-brightness instead.  */
334   /* R    G    B        grey  index */
335   {   0,   0,   0 }, /* 0.000   0 */
336   { 255,   0,   0 },
337   {   0, 255,   0 },
338   { 255, 255,   0 },
339   {   0,   0, 255 },
340   { 255,   0, 255 },
341   {   0, 255, 255 },
342   { 255, 255, 255 }  /* 1.000   7 */
343 };
344
345 static inline term_color_t
346 rgb_to_color_xterm8 (int r, int g, int b)
347 {
348   rgb_t color;
349   hsv_t hsv;
350
351   color.red = r; color.green = g; color.blue = b;
352   rgb_to_hsv (color, &hsv);
353
354   if (hsv.saturation < 0.065f)
355     {
356       /* Greyscale approximation.  */
357       float luminance = color_luminance (r, g, b);
358       if (luminance < 0.500f)
359         return 0;
360       else
361         return 7;
362     }
363   else
364     /* Color approximation.  */
365     return nearest_color (color, colors_of_xterm8, 8);
366 }
367
368 /* ------------------------ cm_xterm16 color model ------------------------ */
369
370 /* A non-default color index is in the range 0..15.
371    The RGB values come from xterm's XTerm-col.ad.  */
372 static const rgb_t colors_of_xterm16[16] =
373 {
374   /* R    G    B        grey  index */
375   {   0,   0,   0 }, /* 0.000   0 */
376   { 205,   0,   0 },
377   {   0, 205,   0 },
378   { 205, 205,   0 },
379   {   0,   0, 205 },
380   { 205,   0, 205 },
381   {   0, 205, 205 },
382   { 229, 229, 229 }, /* 0.898   7 */
383   {  77,  77,  77 }, /* 0.302   8 */
384   { 255,   0,   0 },
385   {   0, 255,   0 },
386   { 255, 255,   0 },
387   {   0,   0, 255 },
388   { 255,   0, 255 },
389   {   0, 255, 255 },
390   { 255, 255, 255 }  /* 1.000  15 */
391 };
392
393 static inline term_color_t
394 rgb_to_color_xterm16 (int r, int g, int b)
395 {
396   rgb_t color;
397   hsv_t hsv;
398
399   color.red = r; color.green = g; color.blue = b;
400   rgb_to_hsv (color, &hsv);
401
402   if (hsv.saturation < 0.065f)
403     {
404       /* Greyscale approximation.  */
405       float luminance = color_luminance (r, g, b);
406       if (luminance < 0.151f)
407         return 0;
408       else if (luminance < 0.600f)
409         return 8;
410       else if (luminance < 0.949f)
411         return 7;
412       else
413         return 15;
414     }
415   else
416     /* Color approximation.  */
417     return nearest_color (color, colors_of_xterm16, 16);
418 }
419
420 /* ------------------------ cm_xterm88 color model ------------------------ */
421
422 /* A non-default color index is in the range 0..87.
423    Colors 0..15 are the same as in the cm_xterm16 color model.
424    Colors 16..87 are defined in xterm's 88colres.h.  */
425
426 static const rgb_t colors_of_xterm88[88] =
427 {
428   /* R    G    B        grey  index */
429   {   0,   0,   0 }, /* 0.000   0 */
430   { 205,   0,   0 },
431   {   0, 205,   0 },
432   { 205, 205,   0 },
433   {   0,   0, 205 },
434   { 205,   0, 205 },
435   {   0, 205, 205 },
436   { 229, 229, 229 }, /* 0.898   7 */
437   {  77,  77,  77 }, /* 0.302   8 */
438   { 255,   0,   0 },
439   {   0, 255,   0 },
440   { 255, 255,   0 },
441   {   0,   0, 255 },
442   { 255,   0, 255 },
443   {   0, 255, 255 },
444   { 255, 255, 255 }, /* 1.000  15 */
445   {   0,   0,   0 }, /* 0.000  16 */
446   {   0,   0, 139 },
447   {   0,   0, 205 },
448   {   0,   0, 255 },
449   {   0, 139,   0 },
450   {   0, 139, 139 },
451   {   0, 139, 205 },
452   {   0, 139, 255 },
453   {   0, 205,   0 },
454   {   0, 205, 139 },
455   {   0, 205, 205 },
456   {   0, 205, 255 },
457   {   0, 255,   0 },
458   {   0, 255, 139 },
459   {   0, 255, 205 },
460   {   0, 255, 255 },
461   { 139,   0,   0 },
462   { 139,   0, 139 },
463   { 139,   0, 205 },
464   { 139,   0, 255 },
465   { 139, 139,   0 },
466   { 139, 139, 139 }, /* 0.545  37 */
467   { 139, 139, 205 },
468   { 139, 139, 255 },
469   { 139, 205,   0 },
470   { 139, 205, 139 },
471   { 139, 205, 205 },
472   { 139, 205, 255 },
473   { 139, 255,   0 },
474   { 139, 255, 139 },
475   { 139, 255, 205 },
476   { 139, 255, 255 },
477   { 205,   0,   0 },
478   { 205,   0, 139 },
479   { 205,   0, 205 },
480   { 205,   0, 255 },
481   { 205, 139,   0 },
482   { 205, 139, 139 },
483   { 205, 139, 205 },
484   { 205, 139, 255 },
485   { 205, 205,   0 },
486   { 205, 205, 139 },
487   { 205, 205, 205 }, /* 0.804  58 */
488   { 205, 205, 255 },
489   { 205, 255,   0 },
490   { 205, 255, 139 },
491   { 205, 255, 205 },
492   { 205, 255, 255 },
493   { 255,   0,   0 },
494   { 255,   0, 139 },
495   { 255,   0, 205 },
496   { 255,   0, 255 },
497   { 255, 139,   0 },
498   { 255, 139, 139 },
499   { 255, 139, 205 },
500   { 255, 139, 255 },
501   { 255, 205,   0 },
502   { 255, 205, 139 },
503   { 255, 205, 205 },
504   { 255, 205, 255 },
505   { 255, 255,   0 },
506   { 255, 255, 139 },
507   { 255, 255, 205 },
508   { 255, 255, 255 }, /* 1.000  79 */
509   {  46,  46,  46 }, /* 0.180  80 */
510   {  92,  92,  92 }, /* 0.361  81 */
511   { 115, 115, 115 }, /* 0.451  82 */
512   { 139, 139, 139 }, /* 0.545  83 */
513   { 162, 162, 162 }, /* 0.635  84 */
514   { 185, 185, 185 }, /* 0.725  85 */
515   { 208, 208, 208 }, /* 0.816  86 */
516   { 231, 231, 231 }  /* 0.906  87 */
517 };
518
519 static inline term_color_t
520 rgb_to_color_xterm88 (int r, int g, int b)
521 {
522   rgb_t color;
523   hsv_t hsv;
524
525   color.red = r; color.green = g; color.blue = b;
526   rgb_to_hsv (color, &hsv);
527
528   if (hsv.saturation < 0.065f)
529     {
530       /* Greyscale approximation.  */
531       float luminance = color_luminance (r, g, b);
532       if (luminance < 0.090f)
533         return 0;
534       else if (luminance < 0.241f)
535         return 80;
536       else if (luminance < 0.331f)
537         return 8;
538       else if (luminance < 0.406f)
539         return 81;
540       else if (luminance < 0.498f)
541         return 82;
542       else if (luminance < 0.585f)
543         return 37;
544       else if (luminance < 0.680f)
545         return 84;
546       else if (luminance < 0.764f)
547         return 85;
548       else if (luminance < 0.810f)
549         return 58;
550       else if (luminance < 0.857f)
551         return 86;
552       else if (luminance < 0.902f)
553         return 7;
554       else if (luminance < 0.953f)
555         return 87;
556       else
557         return 15;
558     }
559   else
560     /* Color approximation.  */
561     return nearest_color (color, colors_of_xterm88, 88);
562 }
563
564 /* ------------------------ cm_xterm256 color model ------------------------ */
565
566 /* A non-default color index is in the range 0..255.
567    Colors 0..15 are the same as in the cm_xterm16 color model.
568    Colors 16..255 are defined in xterm's 256colres.h.  */
569
570 static const rgb_t colors_of_xterm256[256] =
571 {
572   /* R    G    B        grey  index */
573   {   0,   0,   0 }, /* 0.000   0 */
574   { 205,   0,   0 },
575   {   0, 205,   0 },
576   { 205, 205,   0 },
577   {   0,   0, 205 },
578   { 205,   0, 205 },
579   {   0, 205, 205 },
580   { 229, 229, 229 }, /* 0.898   7 */
581   {  77,  77,  77 }, /* 0.302   8 */
582   { 255,   0,   0 },
583   {   0, 255,   0 },
584   { 255, 255,   0 },
585   {   0,   0, 255 },
586   { 255,   0, 255 },
587   {   0, 255, 255 },
588   { 255, 255, 255 }, /* 1.000  15 */
589   {   0,   0,   0 }, /* 0.000  16 */
590   {   0,   0,  42 },
591   {   0,   0,  85 },
592   {   0,   0, 127 },
593   {   0,   0, 170 },
594   {   0,   0, 212 },
595   {   0,  42,   0 },
596   {   0,  42,  42 },
597   {   0,  42,  85 },
598   {   0,  42, 127 },
599   {   0,  42, 170 },
600   {   0,  42, 212 },
601   {   0,  85,   0 },
602   {   0,  85,  42 },
603   {   0,  85,  85 },
604   {   0,  85, 127 },
605   {   0,  85, 170 },
606   {   0,  85, 212 },
607   {   0, 127,   0 },
608   {   0, 127,  42 },
609   {   0, 127,  85 },
610   {   0, 127, 127 },
611   {   0, 127, 170 },
612   {   0, 127, 212 },
613   {   0, 170,   0 },
614   {   0, 170,  42 },
615   {   0, 170,  85 },
616   {   0, 170, 127 },
617   {   0, 170, 170 },
618   {   0, 170, 212 },
619   {   0, 212,   0 },
620   {   0, 212,  42 },
621   {   0, 212,  85 },
622   {   0, 212, 127 },
623   {   0, 212, 170 },
624   {   0, 212, 212 },
625   {  42,   0,   0 },
626   {  42,   0,  42 },
627   {  42,   0,  85 },
628   {  42,   0, 127 },
629   {  42,   0, 170 },
630   {  42,   0, 212 },
631   {  42,  42,   0 },
632   {  42,  42,  42 }, /* 0.165  59 */
633   {  42,  42,  85 },
634   {  42,  42, 127 },
635   {  42,  42, 170 },
636   {  42,  42, 212 },
637   {  42,  85,   0 },
638   {  42,  85,  42 },
639   {  42,  85,  85 },
640   {  42,  85, 127 },
641   {  42,  85, 170 },
642   {  42,  85, 212 },
643   {  42, 127,   0 },
644   {  42, 127,  42 },
645   {  42, 127,  85 },
646   {  42, 127, 127 },
647   {  42, 127, 170 },
648   {  42, 127, 212 },
649   {  42, 170,   0 },
650   {  42, 170,  42 },
651   {  42, 170,  85 },
652   {  42, 170, 127 },
653   {  42, 170, 170 },
654   {  42, 170, 212 },
655   {  42, 212,   0 },
656   {  42, 212,  42 },
657   {  42, 212,  85 },
658   {  42, 212, 127 },
659   {  42, 212, 170 },
660   {  42, 212, 212 },
661   {  85,   0,   0 },
662   {  85,   0,  42 },
663   {  85,   0,  85 },
664   {  85,   0, 127 },
665   {  85,   0, 170 },
666   {  85,   0, 212 },
667   {  85,  42,   0 },
668   {  85,  42,  42 },
669   {  85,  42,  85 },
670   {  85,  42, 127 },
671   {  85,  42, 170 },
672   {  85,  42, 212 },
673   {  85,  85,   0 },
674   {  85,  85,  42 },
675   {  85,  85,  85 }, /* 0.333 102 */
676   {  85,  85, 127 },
677   {  85,  85, 170 },
678   {  85,  85, 212 },
679   {  85, 127,   0 },
680   {  85, 127,  42 },
681   {  85, 127,  85 },
682   {  85, 127, 127 },
683   {  85, 127, 170 },
684   {  85, 127, 212 },
685   {  85, 170,   0 },
686   {  85, 170,  42 },
687   {  85, 170,  85 },
688   {  85, 170, 127 },
689   {  85, 170, 170 },
690   {  85, 170, 212 },
691   {  85, 212,   0 },
692   {  85, 212,  42 },
693   {  85, 212,  85 },
694   {  85, 212, 127 },
695   {  85, 212, 170 },
696   {  85, 212, 212 },
697   { 127,   0,   0 },
698   { 127,   0,  42 },
699   { 127,   0,  85 },
700   { 127,   0, 127 },
701   { 127,   0, 170 },
702   { 127,   0, 212 },
703   { 127,  42,   0 },
704   { 127,  42,  42 },
705   { 127,  42,  85 },
706   { 127,  42, 127 },
707   { 127,  42, 170 },
708   { 127,  42, 212 },
709   { 127,  85,   0 },
710   { 127,  85,  42 },
711   { 127,  85,  85 },
712   { 127,  85, 127 },
713   { 127,  85, 170 },
714   { 127,  85, 212 },
715   { 127, 127,   0 },
716   { 127, 127,  42 },
717   { 127, 127,  85 },
718   { 127, 127, 127 }, /* 0.498 145 */
719   { 127, 127, 170 },
720   { 127, 127, 212 },
721   { 127, 170,   0 },
722   { 127, 170,  42 },
723   { 127, 170,  85 },
724   { 127, 170, 127 },
725   { 127, 170, 170 },
726   { 127, 170, 212 },
727   { 127, 212,   0 },
728   { 127, 212,  42 },
729   { 127, 212,  85 },
730   { 127, 212, 127 },
731   { 127, 212, 170 },
732   { 127, 212, 212 },
733   { 170,   0,   0 },
734   { 170,   0,  42 },
735   { 170,   0,  85 },
736   { 170,   0, 127 },
737   { 170,   0, 170 },
738   { 170,   0, 212 },
739   { 170,  42,   0 },
740   { 170,  42,  42 },
741   { 170,  42,  85 },
742   { 170,  42, 127 },
743   { 170,  42, 170 },
744   { 170,  42, 212 },
745   { 170,  85,   0 },
746   { 170,  85,  42 },
747   { 170,  85,  85 },
748   { 170,  85, 127 },
749   { 170,  85, 170 },
750   { 170,  85, 212 },
751   { 170, 127,   0 },
752   { 170, 127,  42 },
753   { 170, 127,  85 },
754   { 170, 127, 127 },
755   { 170, 127, 170 },
756   { 170, 127, 212 },
757   { 170, 170,   0 },
758   { 170, 170,  42 },
759   { 170, 170,  85 },
760   { 170, 170, 127 },
761   { 170, 170, 170 }, /* 0.667 188 */
762   { 170, 170, 212 },
763   { 170, 212,   0 },
764   { 170, 212,  42 },
765   { 170, 212,  85 },
766   { 170, 212, 127 },
767   { 170, 212, 170 },
768   { 170, 212, 212 },
769   { 212,   0,   0 },
770   { 212,   0,  42 },
771   { 212,   0,  85 },
772   { 212,   0, 127 },
773   { 212,   0, 170 },
774   { 212,   0, 212 },
775   { 212,  42,   0 },
776   { 212,  42,  42 },
777   { 212,  42,  85 },
778   { 212,  42, 127 },
779   { 212,  42, 170 },
780   { 212,  42, 212 },
781   { 212,  85,   0 },
782   { 212,  85,  42 },
783   { 212,  85,  85 },
784   { 212,  85, 127 },
785   { 212,  85, 170 },
786   { 212,  85, 212 },
787   { 212, 127,   0 },
788   { 212, 127,  42 },
789   { 212, 127,  85 },
790   { 212, 127, 127 },
791   { 212, 127, 170 },
792   { 212, 127, 212 },
793   { 212, 170,   0 },
794   { 212, 170,  42 },
795   { 212, 170,  85 },
796   { 212, 170, 127 },
797   { 212, 170, 170 },
798   { 212, 170, 212 },
799   { 212, 212,   0 },
800   { 212, 212,  42 },
801   { 212, 212,  85 },
802   { 212, 212, 127 },
803   { 212, 212, 170 },
804   { 212, 212, 212 }, /* 0.831 231 */
805   {   8,   8,   8 }, /* 0.031 232 */
806   {  18,  18,  18 }, /* 0.071 233 */
807   {  28,  28,  28 }, /* 0.110 234 */
808   {  38,  38,  38 }, /* 0.149 235 */
809   {  48,  48,  48 }, /* 0.188 236 */
810   {  58,  58,  58 }, /* 0.227 237 */
811   {  68,  68,  68 }, /* 0.267 238 */
812   {  78,  78,  78 }, /* 0.306 239 */
813   {  88,  88,  88 }, /* 0.345 240 */
814   {  98,  98,  98 }, /* 0.384 241 */
815   { 108, 108, 108 }, /* 0.424 242 */
816   { 118, 118, 118 }, /* 0.463 243 */
817   { 128, 128, 128 }, /* 0.502 244 */
818   { 138, 138, 138 }, /* 0.541 245 */
819   { 148, 148, 148 }, /* 0.580 246 */
820   { 158, 158, 158 }, /* 0.620 247 */
821   { 168, 168, 168 }, /* 0.659 248 */
822   { 178, 178, 178 }, /* 0.698 249 */
823   { 188, 188, 188 }, /* 0.737 250 */
824   { 198, 198, 198 }, /* 0.776 251 */
825   { 208, 208, 208 }, /* 0.816 252 */
826   { 218, 218, 218 }, /* 0.855 253 */
827   { 228, 228, 228 }, /* 0.894 254 */
828   { 238, 238, 238 }  /* 0.933 255 */
829 };
830
831 static inline term_color_t
832 rgb_to_color_xterm256 (int r, int g, int b)
833 {
834   rgb_t color;
835   hsv_t hsv;
836
837   color.red = r; color.green = g; color.blue = b;
838   rgb_to_hsv (color, &hsv);
839
840   if (hsv.saturation < 0.065f)
841     {
842       /* Greyscale approximation.  */
843       float luminance = color_luminance (r, g, b);
844       if (luminance < 0.015f)
845         return 0;
846       else if (luminance < 0.051f)
847         return 232;
848       else if (luminance < 0.090f)
849         return 233;
850       else if (luminance < 0.129f)
851         return 234;
852       else if (luminance < 0.157f)
853         return 235;
854       else if (luminance < 0.177f)
855         return 59;
856       else if (luminance < 0.207f)
857         return 236;
858       else if (luminance < 0.247f)
859         return 237;
860       else if (luminance < 0.284f)
861         return 238;
862       else if (luminance < 0.304f)
863         return 8;
864       else if (luminance < 0.319f)
865         return 239;
866       else if (luminance < 0.339f)
867         return 102;
868       else if (luminance < 0.364f)
869         return 240;
870       else if (luminance < 0.404f)
871         return 241;
872       else if (luminance < 0.443f)
873         return 242;
874       else if (luminance < 0.480f)
875         return 243;
876       else if (luminance < 0.500f)
877         return 145;
878       else if (luminance < 0.521f)
879         return 244;
880       else if (luminance < 0.560f)
881         return 245;
882       else if (luminance < 0.600f)
883         return 246;
884       else if (luminance < 0.639f)
885         return 247;
886       else if (luminance < 0.663f)
887         return 248;
888       else if (luminance < 0.682f)
889         return 188;
890       else if (luminance < 0.717f)
891         return 249;
892       else if (luminance < 0.756f)
893         return 250;
894       else if (luminance < 0.796f)
895         return 251;
896       else if (luminance < 0.823f)
897         return 252;
898       else if (luminance < 0.843f)
899         return 231;
900       else if (luminance < 0.874f)
901         return 253;
902       else if (luminance < 0.896f)
903         return 254;
904       else if (luminance < 0.915f)
905         return 7;
906       else if (luminance < 0.966f)
907         return 255;
908       else
909         return 15;
910     }
911   else
912     /* Color approximation.  */
913     return nearest_color (color, colors_of_xterm256, 256);
914 }
915
916
917 /* ============================= attributes_t ============================= */
918
919 /* ANSI C and ISO C99 6.7.2.1.(4) forbid use of bit fields for types other
920    than 'int' or 'unsigned int'.
921    On the other hand, C++ forbids conversion between enum types and integer
922    types without an explicit cast.  */
923 #ifdef __cplusplus
924 # define BITFIELD_TYPE(orig_type,integer_type) orig_type
925 #else
926 # define BITFIELD_TYPE(orig_type,integer_type) integer_type
927 #endif
928
929 /* Attributes that can be set on a character.  */
930 typedef struct
931 {
932   BITFIELD_TYPE(term_color_t,     signed int)   color     : 9;
933   BITFIELD_TYPE(term_color_t,     signed int)   bgcolor   : 9;
934   BITFIELD_TYPE(term_weight_t,    unsigned int) weight    : 1;
935   BITFIELD_TYPE(term_posture_t,   unsigned int) posture   : 1;
936   BITFIELD_TYPE(term_underline_t, unsigned int) underline : 1;
937 } attributes_t;
938
939
940 /* ============================ term_ostream_t ============================ */
941
942 #line 943 "term-ostream.c"
943 #if !IS_CPLUSPLUS
944 #define term_ostream_representation any_ostream_representation
945 #endif
946 #include "term_ostream.priv.h"
947
948 const typeinfo_t term_ostream_typeinfo = { "term_ostream" };
949
950 static const typeinfo_t * const term_ostream_superclasses[] =
951   { term_ostream_SUPERCLASSES };
952
953 #define super ostream_vtable
954
955 #line 979 "term-ostream.oo.c"
956
957 /* Simplify attributes, according to the terminal's capabilities.  */
958 static attributes_t
959 simplify_attributes (term_ostream_t stream, attributes_t attr)
960 {
961   if ((attr.color != COLOR_DEFAULT || attr.bgcolor != COLOR_DEFAULT)
962       && stream->no_color_video > 0)
963     {
964       /* When colors and attributes can not be represented simultaneously,
965          we give preference to the color.  */
966       if (stream->no_color_video & 2)
967         /* Colors conflict with underlining.  */
968         attr.underline = UNDERLINE_OFF;
969       if (stream->no_color_video & 32)
970         /* Colors conflict with bold weight.  */
971         attr.weight = WEIGHT_NORMAL;
972     }
973   if (!stream->supports_foreground)
974     attr.color = COLOR_DEFAULT;
975   if (!stream->supports_background)
976     attr.bgcolor = COLOR_DEFAULT;
977   if (!stream->supports_weight)
978     attr.weight = WEIGHT_DEFAULT;
979   if (!stream->supports_posture)
980     attr.posture = POSTURE_DEFAULT;
981   if (!stream->supports_underline)
982     attr.underline = UNDERLINE_DEFAULT;
983   return attr;
984 }
985
986 /* While a line is being output, we need to be careful to restore the
987    terminal's settings in case of a fatal signal or an exit() call.  */
988
989 /* File descriptor to which out_char shall output escape sequences.  */
990 static int out_fd = -1;
991
992 /* Filename of out_fd.  */
993 static const char *out_filename;
994
995 /* Output a single char to out_fd.  Ignore errors.  */
996 static int
997 out_char_unchecked (int c)
998 {
999   char bytes[1];
1000
1001   bytes[0] = (char)c;
1002   full_write (out_fd, bytes, 1);
1003   return 0;
1004 }
1005
1006 /* State that informs the exit handler what to do.  */
1007 static const char *restore_colors;
1008 static const char *restore_weight;
1009 static const char *restore_posture;
1010 static const char *restore_underline;
1011
1012 /* The exit handler.  */
1013 static void
1014 restore (void)
1015 {
1016   /* Only do something while some output was interrupted.  */
1017   if (out_fd >= 0)
1018     {
1019       if (restore_colors != NULL)
1020         tputs (restore_colors, 1, out_char_unchecked);
1021       if (restore_weight != NULL)
1022         tputs (restore_weight, 1, out_char_unchecked);
1023       if (restore_posture != NULL)
1024         tputs (restore_posture, 1, out_char_unchecked);
1025       if (restore_underline != NULL)
1026         tputs (restore_underline, 1, out_char_unchecked);
1027     }
1028 }
1029
1030 /* The list of signals whose default behaviour is to stop the program.  */
1031 static int stopping_signals[] =
1032   {
1033 #ifdef SIGTSTP
1034     SIGTSTP,
1035 #endif
1036 #ifdef SIGTTIN
1037     SIGTTIN,
1038 #endif
1039 #ifdef SIGTTOU
1040     SIGTTOU,
1041 #endif
1042     0
1043   };
1044
1045 #define num_stopping_signals (SIZEOF (stopping_signals) - 1)
1046
1047 static sigset_t stopping_signal_set;
1048
1049 static void
1050 init_stopping_signal_set ()
1051 {
1052   static bool stopping_signal_set_initialized = false;
1053   if (!stopping_signal_set_initialized)
1054     {
1055       size_t i;
1056
1057       sigemptyset (&stopping_signal_set);
1058       for (i = 0; i < num_stopping_signals; i++)
1059         sigaddset (&stopping_signal_set, stopping_signals[i]);
1060
1061       stopping_signal_set_initialized = true;
1062     }
1063 }
1064
1065 /* Temporarily delay the stopping signals.  */
1066 static inline void
1067 block_stopping_signals ()
1068 {
1069   init_stopping_signal_set ();
1070   sigprocmask (SIG_BLOCK, &stopping_signal_set, NULL);
1071 }
1072
1073 /* Stop delaying the stopping signals.  */
1074 static inline void
1075 unblock_stopping_signals ()
1076 {
1077   init_stopping_signal_set ();
1078   sigprocmask (SIG_UNBLOCK, &stopping_signal_set, NULL);
1079 }
1080
1081 /* Compare two sets of attributes for equality.  */
1082 static inline bool
1083 equal_attributes (attributes_t attr1, attributes_t attr2)
1084 {
1085   return (attr1.color == attr2.color
1086           && attr1.bgcolor == attr2.bgcolor
1087           && attr1.weight == attr2.weight
1088           && attr1.posture == attr2.posture
1089           && attr1.underline == attr2.underline);
1090 }
1091
1092 /* Signal error after full_write failed.  */
1093 static void
1094 out_error ()
1095 {
1096   error (EXIT_FAILURE, errno, _("error writing to %s"), out_filename);
1097 }
1098
1099 /* Output a single char to out_fd.  */
1100 static int
1101 out_char (int c)
1102 {
1103   char bytes[1];
1104
1105   bytes[0] = (char)c;
1106   /* We have to write directly to the file descriptor, not to a buffer with
1107      the same destination, because of the padding and sleeping that tputs()
1108      does.  */
1109   if (full_write (out_fd, bytes, 1) < 1)
1110     out_error ();
1111   return 0;
1112 }
1113
1114 /* Output escape sequences to switch from OLD_ATTR to NEW_ATTR.  */
1115 static void
1116 out_attr_change (term_ostream_t stream,
1117                  attributes_t old_attr, attributes_t new_attr)
1118 {
1119   bool cleared_attributes;
1120
1121   /* We don't know the default colors of the terminal.  The only way to switch
1122      back to a default color is to use stream->orig_pair.  */
1123   if ((new_attr.color == COLOR_DEFAULT && old_attr.color != COLOR_DEFAULT)
1124       || (new_attr.bgcolor == COLOR_DEFAULT && old_attr.bgcolor != COLOR_DEFAULT))
1125     {
1126       assert (stream->supports_foreground || stream->supports_background);
1127       tputs (stream->orig_pair, 1, out_char);
1128       old_attr.color = COLOR_DEFAULT;
1129       old_attr.bgcolor = COLOR_DEFAULT;
1130     }
1131
1132   /* To turn off WEIGHT_BOLD, the only way is to output the exit_attribute_mode
1133      sequence.  (With xterm, you can also do it with "Esc [ 0 m", but this
1134      escape sequence is not contained in the terminfo description.)  It may
1135      also clear the colors; this is the case e.g. when TERM="xterm" or
1136      TERM="ansi".
1137      To turn off UNDERLINE_ON, we can use the exit_underline_mode or the
1138      exit_attribute_mode sequence.  In the latter case, it will not only
1139      turn off UNDERLINE_ON, but also the other attributes, and possibly also
1140      the colors.
1141      To turn off POSTURE_ITALIC, we can use the exit_italics_mode or the
1142      exit_attribute_mode sequence.  Again, in the latter case, it will not
1143      only turn off POSTURE_ITALIC, but also the other attributes, and possibly
1144      also the colors.
1145      There is no point in setting an attribute just before emitting an
1146      escape sequence that may again turn off the attribute.  Therefore we
1147      proceed in two steps: First, clear the attributes that need to be
1148      cleared; then - taking into account that this may have cleared all
1149      attributes and all colors - set the colors and the attributes.
1150      The variable 'cleared_attributes' tells whether an escape sequence
1151      has been output that may have cleared all attributes and all color
1152      settings.  */
1153   cleared_attributes = false;
1154   if (old_attr.posture != POSTURE_NORMAL
1155       && new_attr.posture == POSTURE_NORMAL
1156       && stream->exit_italics_mode != NULL)
1157     {
1158       tputs (stream->exit_italics_mode, 1, out_char);
1159       old_attr.posture = POSTURE_NORMAL;
1160       cleared_attributes = true;
1161     }
1162   if (old_attr.underline != UNDERLINE_OFF
1163       && new_attr.underline == UNDERLINE_OFF
1164       && stream->exit_underline_mode != NULL)
1165     {
1166       tputs (stream->exit_underline_mode, 1, out_char);
1167       old_attr.underline = UNDERLINE_OFF;
1168       cleared_attributes = true;
1169     }
1170   if ((old_attr.weight != WEIGHT_NORMAL
1171        && new_attr.weight == WEIGHT_NORMAL)
1172       || (old_attr.posture != POSTURE_NORMAL
1173           && new_attr.posture == POSTURE_NORMAL
1174           /* implies stream->exit_italics_mode == NULL */)
1175       || (old_attr.underline != UNDERLINE_OFF
1176           && new_attr.underline == UNDERLINE_OFF
1177           /* implies stream->exit_underline_mode == NULL */))
1178     {
1179       tputs (stream->exit_attribute_mode, 1, out_char);
1180       /* We don't know exactly what effects exit_attribute_mode has, but
1181          this is the minimum effect:  */
1182       old_attr.weight = WEIGHT_NORMAL;
1183       if (stream->exit_italics_mode == NULL)
1184         old_attr.posture = POSTURE_NORMAL;
1185       if (stream->exit_underline_mode == NULL)
1186         old_attr.underline = UNDERLINE_OFF;
1187       cleared_attributes = true;
1188     }
1189
1190   /* Turn on the colors.  */
1191   if (new_attr.color != old_attr.color
1192       || (cleared_attributes && new_attr.color != COLOR_DEFAULT))
1193     {
1194       assert (stream->supports_foreground);
1195       assert (new_attr.color != COLOR_DEFAULT);
1196       switch (stream->colormodel)
1197         {
1198         case cm_common8:
1199           assert (new_attr.color >= 0 && new_attr.color < 8);
1200           if (stream->set_a_foreground != NULL)
1201             tputs (tparm (stream->set_a_foreground,
1202                           color_bgr (new_attr.color)),
1203                    1, out_char);
1204           else
1205             tputs (tparm (stream->set_foreground, new_attr.color),
1206                    1, out_char);
1207           break;
1208         /* When we are dealing with an xterm, there is no need to go through
1209            tputs() because we know there is no padding and sleeping.  */
1210         case cm_xterm8:
1211           assert (new_attr.color >= 0 && new_attr.color < 8);
1212           {
1213             char bytes[5];
1214             bytes[0] = 0x1B; bytes[1] = '[';
1215             bytes[2] = '3'; bytes[3] = '0' + new_attr.color;
1216             bytes[4] = 'm';
1217             if (full_write (out_fd, bytes, 5) < 5)
1218               out_error ();
1219           }
1220           break;
1221         case cm_xterm16:
1222           assert (new_attr.color >= 0 && new_attr.color < 16);
1223           {
1224             char bytes[5];
1225             bytes[0] = 0x1B; bytes[1] = '[';
1226             if (new_attr.color < 8)
1227               {
1228                 bytes[2] = '3'; bytes[3] = '0' + new_attr.color;
1229               }
1230             else
1231               {
1232                 bytes[2] = '9'; bytes[3] = '0' + (new_attr.color - 8);
1233               }
1234             bytes[4] = 'm';
1235             if (full_write (out_fd, bytes, 5) < 5)
1236               out_error ();
1237           }
1238           break;
1239         case cm_xterm88:
1240           assert (new_attr.color >= 0 && new_attr.color < 88);
1241           {
1242             char bytes[10];
1243             char *p;
1244             bytes[0] = 0x1B; bytes[1] = '[';
1245             bytes[2] = '3'; bytes[3] = '8'; bytes[4] = ';';
1246             bytes[5] = '5'; bytes[6] = ';';
1247             p = bytes + 7;
1248             if (new_attr.color >= 10)
1249               *p++ = '0' + (new_attr.color / 10);
1250             *p++ = '0' + (new_attr.color % 10);
1251             *p++ = 'm';
1252             if (full_write (out_fd, bytes, p - bytes) < p - bytes)
1253               out_error ();
1254           }
1255           break;
1256         case cm_xterm256:
1257           assert (new_attr.color >= 0 && new_attr.color < 256);
1258           {
1259             char bytes[11];
1260             char *p;
1261             bytes[0] = 0x1B; bytes[1] = '[';
1262             bytes[2] = '3'; bytes[3] = '8'; bytes[4] = ';';
1263             bytes[5] = '5'; bytes[6] = ';';
1264             p = bytes + 7;
1265             if (new_attr.color >= 100)
1266               *p++ = '0' + (new_attr.color / 100);
1267             if (new_attr.color >= 10)
1268               *p++ = '0' + ((new_attr.color % 100) / 10);
1269             *p++ = '0' + (new_attr.color % 10);
1270             *p++ = 'm';
1271             if (full_write (out_fd, bytes, p - bytes) < p - bytes)
1272               out_error ();
1273           }
1274           break;
1275         default:
1276           abort ();
1277         }
1278     }
1279   if (new_attr.bgcolor != old_attr.bgcolor
1280       || (cleared_attributes && new_attr.bgcolor != COLOR_DEFAULT))
1281     {
1282       assert (stream->supports_background);
1283       assert (new_attr.bgcolor != COLOR_DEFAULT);
1284       switch (stream->colormodel)
1285         {
1286         case cm_common8:
1287           assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 8);
1288           if (stream->set_a_background != NULL)
1289             tputs (tparm (stream->set_a_background,
1290                           color_bgr (new_attr.bgcolor)),
1291                    1, out_char);
1292           else
1293             tputs (tparm (stream->set_background, new_attr.bgcolor),
1294                    1, out_char);
1295           break;
1296         /* When we are dealing with an xterm, there is no need to go through
1297            tputs() because we know there is no padding and sleeping.  */
1298         case cm_xterm8:
1299           assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 8);
1300           {
1301             char bytes[5];
1302             bytes[0] = 0x1B; bytes[1] = '[';
1303             bytes[2] = '4'; bytes[3] = '0' + new_attr.bgcolor;
1304             bytes[4] = 'm';
1305             if (full_write (out_fd, bytes, 5) < 5)
1306               out_error ();
1307           }
1308           break;
1309         case cm_xterm16:
1310           assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 16);
1311           {
1312             char bytes[6];
1313             bytes[0] = 0x1B; bytes[1] = '[';
1314             if (new_attr.bgcolor < 8)
1315               {
1316                 bytes[2] = '4'; bytes[3] = '0' + new_attr.bgcolor;
1317                 bytes[4] = 'm';
1318                 if (full_write (out_fd, bytes, 5) < 5)
1319                   out_error ();
1320               }
1321             else
1322               {
1323                 bytes[2] = '1'; bytes[3] = '0';
1324                 bytes[4] = '0' + (new_attr.bgcolor - 8); bytes[5] = 'm';
1325                 if (full_write (out_fd, bytes, 6) < 6)
1326                   out_error ();
1327               }
1328           }
1329           break;
1330         case cm_xterm88:
1331           assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 88);
1332           {
1333             char bytes[10];
1334             char *p;
1335             bytes[0] = 0x1B; bytes[1] = '[';
1336             bytes[2] = '4'; bytes[3] = '8'; bytes[4] = ';';
1337             bytes[5] = '5'; bytes[6] = ';';
1338             p = bytes + 7;
1339             if (new_attr.bgcolor >= 10)
1340               *p++ = '0' + (new_attr.bgcolor / 10);
1341             *p++ = '0' + (new_attr.bgcolor % 10);
1342             *p++ = 'm';
1343             if (full_write (out_fd, bytes, p - bytes) < p - bytes)
1344               out_error ();
1345           }
1346           break;
1347         case cm_xterm256:
1348           assert (new_attr.bgcolor >= 0 && new_attr.bgcolor < 256);
1349           {
1350             char bytes[11];
1351             char *p;
1352             bytes[0] = 0x1B; bytes[1] = '[';
1353             bytes[2] = '4'; bytes[3] = '8'; bytes[4] = ';';
1354             bytes[5] = '5'; bytes[6] = ';';
1355             p = bytes + 7;
1356             if (new_attr.bgcolor >= 100)
1357               *p++ = '0' + (new_attr.bgcolor / 100);
1358             if (new_attr.bgcolor >= 10)
1359               *p++ = '0' + ((new_attr.bgcolor % 100) / 10);
1360             *p++ = '0' + (new_attr.bgcolor % 10);
1361             *p++ = 'm';
1362             if (full_write (out_fd, bytes, p - bytes) < p - bytes)
1363               out_error ();
1364           }
1365           break;
1366         default:
1367           abort ();
1368         }
1369     }
1370
1371   if (new_attr.weight != old_attr.weight
1372       || (cleared_attributes && new_attr.weight != WEIGHT_DEFAULT))
1373     {
1374       assert (stream->supports_weight);
1375       assert (new_attr.weight != WEIGHT_DEFAULT);
1376       /* This implies:  */
1377       assert (new_attr.weight == WEIGHT_BOLD);
1378       tputs (stream->enter_bold_mode, 1, out_char);
1379     }
1380   if (new_attr.posture != old_attr.posture
1381       || (cleared_attributes && new_attr.posture != POSTURE_DEFAULT))
1382     {
1383       assert (stream->supports_posture);
1384       assert (new_attr.posture != POSTURE_DEFAULT);
1385       /* This implies:  */
1386       assert (new_attr.posture == POSTURE_ITALIC);
1387       tputs (stream->enter_italics_mode, 1, out_char);
1388     }
1389   if (new_attr.underline != old_attr.underline
1390       || (cleared_attributes && new_attr.underline != UNDERLINE_DEFAULT))
1391     {
1392       assert (stream->supports_underline);
1393       assert (new_attr.underline != UNDERLINE_DEFAULT);
1394       /* This implies:  */
1395       assert (new_attr.underline == UNDERLINE_ON);
1396       tputs (stream->enter_underline_mode, 1, out_char);
1397     }
1398 }
1399
1400 /* Output the buffered line atomically.
1401    The terminal is assumed to have the default state (regarding colors and
1402    attributes) before this call.  It is left in default state after this
1403    call (regardless of stream->curr_attr).  */
1404 static void
1405 output_buffer (term_ostream_t stream)
1406 {
1407   attributes_t default_attr;
1408   attributes_t attr;
1409   const char *cp;
1410   const attributes_t *ap;
1411   size_t len;
1412   size_t n;
1413
1414   default_attr.color = COLOR_DEFAULT;
1415   default_attr.bgcolor = COLOR_DEFAULT;
1416   default_attr.weight = WEIGHT_DEFAULT;
1417   default_attr.posture = POSTURE_DEFAULT;
1418   default_attr.underline = UNDERLINE_DEFAULT;
1419
1420   attr = default_attr;
1421
1422   cp = stream->buffer;
1423   ap = stream->attrbuffer;
1424   len = stream->buflen;
1425
1426   /* See how much we can output without blocking signals.  */
1427   for (n = 0; n < len && equal_attributes (ap[n], attr); n++)
1428     ;
1429   if (n > 0)
1430     {
1431       if (full_write (stream->fd, cp, n) < n)
1432         error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename);
1433       cp += n;
1434       ap += n;
1435       len -= n;
1436     }
1437   if (len > 0)
1438     {
1439       /* Block fatal signals, so that a SIGINT or similar doesn't interrupt
1440          us without the possibility of restoring the terminal's state.  */
1441       block_fatal_signals ();
1442       /* Likewise for SIGTSTP etc.  */
1443       block_stopping_signals ();
1444
1445       /* Enable the exit handler for restoring the terminal's state.  */
1446       restore_colors =
1447         (stream->supports_foreground || stream->supports_background
1448          ? stream->orig_pair
1449          : NULL);
1450       restore_weight =
1451         (stream->supports_weight ? stream->exit_attribute_mode : NULL);
1452       restore_posture =
1453         (stream->supports_posture
1454          ? (stream->exit_italics_mode != NULL
1455             ? stream->exit_italics_mode
1456             : stream->exit_attribute_mode)
1457          : NULL);
1458       restore_underline =
1459         (stream->supports_underline
1460          ? (stream->exit_underline_mode != NULL
1461             ? stream->exit_underline_mode
1462             : stream->exit_attribute_mode)
1463          : NULL);
1464       out_fd = stream->fd;
1465       out_filename = stream->filename;
1466
1467       while (len > 0)
1468         {
1469           /* Activate the attributes in *ap.  */
1470           out_attr_change (stream, attr, *ap);
1471           attr = *ap;
1472           /* See how many characters we can output without further attribute
1473              changes.  */
1474           for (n = 1; n < len && equal_attributes (ap[n], attr); n++)
1475             ;
1476           if (full_write (stream->fd, cp, n) < n)
1477             error (EXIT_FAILURE, errno, _("error writing to %s"),
1478                    stream->filename);
1479           cp += n;
1480           ap += n;
1481           len -= n;
1482         }
1483
1484       /* Switch back to the default attributes.  */
1485       out_attr_change (stream, attr, default_attr);
1486
1487       /* Disable the exit handler.  */
1488       out_fd = -1;
1489       out_filename = NULL;
1490
1491       /* Unblock fatal and stopping signals.  */
1492       unblock_stopping_signals ();
1493       unblock_fatal_signals ();
1494     }
1495   stream->buflen = 0;
1496 }
1497
1498 /* Implementation of ostream_t methods.  */
1499
1500 static term_color_t
1501 term_ostream__rgb_to_color (term_ostream_t stream, int red, int green, int blue)
1502 {
1503   switch (stream->colormodel)
1504     {
1505     case cm_monochrome:
1506       return rgb_to_color_monochrome ();
1507     case cm_common8:
1508       return rgb_to_color_common8 (red, green, blue);
1509     case cm_xterm8:
1510       return rgb_to_color_xterm8 (red, green, blue);
1511     case cm_xterm16:
1512       return rgb_to_color_xterm16 (red, green, blue);
1513     case cm_xterm88:
1514       return rgb_to_color_xterm88 (red, green, blue);
1515     case cm_xterm256:
1516       return rgb_to_color_xterm256 (red, green, blue);
1517     default:
1518       abort ();
1519     }
1520 }
1521
1522 static void
1523 term_ostream__write_mem (term_ostream_t stream, const void *data, size_t len)
1524 {
1525   const char *cp = (const char *) data;
1526   while (len > 0)
1527     {
1528       /* Look for the next newline.  */
1529       const char *newline = (const char *) memchr (cp, '\n', len);
1530       size_t n = (newline != NULL ? newline - cp : len);
1531
1532       /* Copy n bytes into the buffer.  */
1533       if (n > stream->allocated - stream->buflen)
1534         {
1535           size_t new_allocated =
1536             xmax (xsum (stream->buflen, n),
1537                   xsum (stream->allocated, stream->allocated));
1538           if (size_overflow_p (new_allocated))
1539             error (EXIT_FAILURE, 0,
1540                    _("%s: too much output, buffer size overflow"),
1541                    "term_ostream");
1542           stream->buffer = (char *) xrealloc (stream->buffer, new_allocated);
1543           stream->attrbuffer =
1544             (attributes_t *)
1545             xrealloc (stream->attrbuffer,
1546                       new_allocated * sizeof (attributes_t));
1547           stream->allocated = new_allocated;
1548         }
1549       memcpy (stream->buffer + stream->buflen, cp, n);
1550       {
1551         attributes_t attr = stream->simp_attr;
1552         attributes_t *ap = stream->attrbuffer + stream->buflen;
1553         attributes_t *ap_end = ap + n;
1554         for (; ap < ap_end; ap++)
1555           *ap = attr;
1556       }
1557       stream->buflen += n;
1558
1559       if (newline != NULL)
1560         {
1561           output_buffer (stream);
1562           if (full_write (stream->fd, "\n", 1) < 1)
1563             error (EXIT_FAILURE, errno, _("error writing to %s"),
1564                    stream->filename);
1565           cp += n + 1; /* cp = newline + 1; */
1566           len -= n + 1;
1567         }
1568       else
1569         break;
1570     }
1571 }
1572
1573 static void
1574 term_ostream__flush (term_ostream_t stream)
1575 {
1576   output_buffer (stream);
1577 }
1578
1579 static void
1580 term_ostream__free (term_ostream_t stream)
1581 {
1582   term_ostream_flush (stream);
1583   free (stream->filename);
1584   if (stream->set_a_foreground != NULL)
1585     free (stream->set_a_foreground);
1586   if (stream->set_foreground != NULL)
1587     free (stream->set_foreground);
1588   if (stream->set_a_background != NULL)
1589     free (stream->set_a_background);
1590   if (stream->set_background != NULL)
1591     free (stream->set_background);
1592   if (stream->orig_pair != NULL)
1593     free (stream->orig_pair);
1594   if (stream->enter_bold_mode != NULL)
1595     free (stream->enter_bold_mode);
1596   if (stream->enter_italics_mode != NULL)
1597     free (stream->enter_italics_mode);
1598   if (stream->exit_italics_mode != NULL)
1599     free (stream->exit_italics_mode);
1600   if (stream->enter_underline_mode != NULL)
1601     free (stream->enter_underline_mode);
1602   if (stream->exit_underline_mode != NULL)
1603     free (stream->exit_underline_mode);
1604   if (stream->exit_attribute_mode != NULL)
1605     free (stream->exit_attribute_mode);
1606   free (stream->buffer);
1607   free (stream);
1608 }
1609
1610 /* Implementation of term_ostream_t methods.  */
1611
1612 static term_color_t
1613 term_ostream__get_color (term_ostream_t stream)
1614 {
1615   return stream->curr_attr.color;
1616 }
1617
1618 static void
1619 term_ostream__set_color (term_ostream_t stream, term_color_t color)
1620 {
1621   stream->curr_attr.color = color;
1622   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1623 }
1624
1625 static term_color_t
1626 term_ostream__get_bgcolor (term_ostream_t stream)
1627 {
1628   return stream->curr_attr.bgcolor;
1629 }
1630
1631 static void
1632 term_ostream__set_bgcolor (term_ostream_t stream, term_color_t color)
1633 {
1634   stream->curr_attr.bgcolor = color;
1635   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1636 }
1637
1638 static term_weight_t
1639 term_ostream__get_weight (term_ostream_t stream)
1640 {
1641   return stream->curr_attr.weight;
1642 }
1643
1644 static void
1645 term_ostream__set_weight (term_ostream_t stream, term_weight_t weight)
1646 {
1647   stream->curr_attr.weight = weight;
1648   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1649 }
1650
1651 static term_posture_t
1652 term_ostream__get_posture (term_ostream_t stream)
1653 {
1654   return stream->curr_attr.posture;
1655 }
1656
1657 static void
1658 term_ostream__set_posture (term_ostream_t stream, term_posture_t posture)
1659 {
1660   stream->curr_attr.posture = posture;
1661   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1662 }
1663
1664 static term_underline_t
1665 term_ostream__get_underline (term_ostream_t stream)
1666 {
1667   return stream->curr_attr.underline;
1668 }
1669
1670 static void
1671 term_ostream__set_underline (term_ostream_t stream, term_underline_t underline)
1672 {
1673   stream->curr_attr.underline = underline;
1674   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1675 }
1676
1677 /* Constructor.  */
1678
1679 static inline char *
1680 xstrdup0 (const char *str)
1681 {
1682   if (str == NULL)
1683     return NULL;
1684 #if HAVE_TERMINFO
1685   if (str == (const char *)(-1))
1686     return NULL;
1687 #endif
1688   return xstrdup (str);
1689 }
1690
1691 term_ostream_t
1692 term_ostream_create (int fd, const char *filename)
1693 {
1694   term_ostream_t stream = XMALLOC (struct term_ostream_representation);
1695   const char *term;
1696
1697   stream->base.vtable = &term_ostream_vtable;
1698   stream->fd = fd;
1699   stream->filename = xstrdup (filename);
1700
1701   /* Defaults.  */
1702   stream->max_colors = -1;
1703   stream->no_color_video = -1;
1704   stream->set_a_foreground = NULL;
1705   stream->set_foreground = NULL;
1706   stream->set_a_background = NULL;
1707   stream->set_background = NULL;
1708   stream->orig_pair = NULL;
1709   stream->enter_bold_mode = NULL;
1710   stream->enter_italics_mode = NULL;
1711   stream->exit_italics_mode = NULL;
1712   stream->enter_underline_mode = NULL;
1713   stream->exit_underline_mode = NULL;
1714   stream->exit_attribute_mode = NULL;
1715
1716   /* Retrieve the terminal type.  */
1717   term = getenv ("TERM");
1718   if (term != NULL && term[0] != '\0')
1719     {
1720       /* When the terminfo function are available, we prefer them over the
1721          termcap functions because
1722            1. they don't risk a buffer overflow,
1723            2. on OSF/1, for TERM=xterm, the tiget* functions provide access
1724               to the number of colors and the color escape sequences, whereas
1725               the tget* functions don't provide them.  */
1726 #if HAVE_TERMINFO
1727       int err = 1;
1728
1729       if (setupterm (term, fd, &err) || err == 1)
1730         {
1731           /* Retrieve particular values depending on the terminal type.  */
1732           stream->max_colors = tigetnum ("colors");
1733           stream->no_color_video = tigetnum ("ncv");
1734           stream->set_a_foreground = xstrdup0 (tigetstr ("setaf"));
1735           stream->set_foreground = xstrdup0 (tigetstr ("setf"));
1736           stream->set_a_background = xstrdup0 (tigetstr ("setab"));
1737           stream->set_background = xstrdup0 (tigetstr ("setb"));
1738           stream->orig_pair = xstrdup0 (tigetstr ("op"));
1739           stream->enter_bold_mode = xstrdup0 (tigetstr ("bold"));
1740           stream->enter_italics_mode = xstrdup0 (tigetstr ("sitm"));
1741           stream->exit_italics_mode = xstrdup0 (tigetstr ("ritm"));
1742           stream->enter_underline_mode = xstrdup0 (tigetstr ("smul"));
1743           stream->exit_underline_mode = xstrdup0 (tigetstr ("rmul"));
1744           stream->exit_attribute_mode = xstrdup0 (tigetstr ("sgr0"));
1745         }
1746 #elif HAVE_TERMCAP
1747       struct { char buf[1024]; char canary[4]; } termcapbuf;
1748       int retval;
1749
1750       /* Call tgetent, being defensive against buffer overflow.  */
1751       memcpy (termcapbuf.canary, "CnRy", 4);
1752       retval = tgetent (termcapbuf.buf, term);
1753       if (memcmp (termcapbuf.canary, "CnRy", 4) != 0)
1754         /* Buffer overflow!  */
1755         abort ();
1756
1757       if (retval > 0)
1758         {
1759           struct { char buf[1024]; char canary[4]; } termentrybuf;
1760           char *termentryptr;
1761
1762           /* Prepare for calling tgetstr, being defensive against buffer
1763              overflow.  ncurses' tgetstr() supports a second argument NULL,
1764              but NetBSD's tgetstr() doesn't.  */
1765           memcpy (termentrybuf.canary, "CnRz", 4);
1766           #define TEBP ((termentryptr = termentrybuf.buf), &termentryptr)
1767
1768           /* Retrieve particular values depending on the terminal type.  */
1769           stream->max_colors = tgetnum ("Co");
1770           stream->no_color_video = tgetnum ("NC");
1771           stream->set_a_foreground = xstrdup0 (tgetstr ("AF", TEBP));
1772           stream->set_foreground = xstrdup0 (tgetstr ("Sf", TEBP));
1773           stream->set_a_background = xstrdup0 (tgetstr ("AB", TEBP));
1774           stream->set_background = xstrdup0 (tgetstr ("Sb", TEBP));
1775           stream->orig_pair = xstrdup0 (tgetstr ("op", TEBP));
1776           stream->enter_bold_mode = xstrdup0 (tgetstr ("md", TEBP));
1777           stream->enter_italics_mode = xstrdup0 (tgetstr ("ZH", TEBP));
1778           stream->exit_italics_mode = xstrdup0 (tgetstr ("ZR", TEBP));
1779           stream->enter_underline_mode = xstrdup0 (tgetstr ("us", TEBP));
1780           stream->exit_underline_mode = xstrdup0 (tgetstr ("ue", TEBP));
1781           stream->exit_attribute_mode = xstrdup0 (tgetstr ("me", TEBP));
1782
1783 # ifdef __BEOS__
1784           /* The BeOS termcap entry for "beterm" is broken: For "AF" and "AB"
1785              it contains balues in terminfo syntax but the system's tparam()
1786              function understands only the termcap syntax.  */
1787           if (stream->set_a_foreground != NULL
1788               && strcmp (stream->set_a_foreground, "\033[3%p1%dm") == 0)
1789             {
1790               free (stream->set_a_foreground);
1791               stream->set_a_foreground = xstrdup ("\033[3%dm");
1792             }
1793           if (stream->set_a_background != NULL
1794               && strcmp (stream->set_a_background, "\033[4%p1%dm") == 0)
1795             {
1796               free (stream->set_a_background);
1797               stream->set_a_background = xstrdup ("\033[4%dm");
1798             }
1799 # endif
1800
1801           /* The termcap entry for cygwin is broken: It has no "ncv" value,
1802              but bold and underline are actually rendered through colors.  */
1803           if (strcmp (term, "cygwin") == 0)
1804             stream->no_color_video |= 2 | 32;
1805
1806           /* Done with tgetstr.  Detect possible buffer overflow.  */
1807           #undef TEBP
1808           if (memcmp (termentrybuf.canary, "CnRz", 4) != 0)
1809             /* Buffer overflow!  */
1810             abort ();
1811         }
1812 #else
1813     /* Fallback code for platforms with neither the terminfo nor the termcap
1814        functions, such as mingw.
1815        Assume the ANSI escape sequences.  Extracted through
1816        "TERM=ansi infocmp", replacing \E with \033.  */
1817       stream->max_colors = 8;
1818       stream->no_color_video = 3;
1819       stream->set_a_foreground = xstrdup ("\033[3%p1%dm");
1820       stream->set_a_background = xstrdup ("\033[4%p1%dm");
1821       stream->orig_pair = xstrdup ("\033[39;49m");
1822       stream->enter_bold_mode = xstrdup ("\033[1m");
1823       stream->enter_underline_mode = xstrdup ("\033[4m");
1824       stream->exit_underline_mode = xstrdup ("\033[m");
1825       stream->exit_attribute_mode = xstrdup ("\033[0;10m");
1826 #endif
1827
1828       /* AIX 4.3.2, IRIX 6.5, HP-UX 11, Solaris 7..10 all lack the
1829          description of color capabilities of "xterm" and "xterms"
1830          in their terminfo database.  But it is important to have
1831          color in xterm.  So we provide the color capabilities here.  */
1832       if (stream->max_colors <= 1
1833           && (strcmp (term, "xterm") == 0 || strcmp (term, "xterms") == 0))
1834         {
1835           stream->max_colors = 8;
1836           stream->set_a_foreground = xstrdup ("\033[3%p1%dm");
1837           stream->set_a_background = xstrdup ("\033[4%p1%dm");
1838           stream->orig_pair = xstrdup ("\033[39;49m");
1839         }
1840     }
1841
1842   /* Infer the capabilities.  */
1843   stream->supports_foreground =
1844     (stream->max_colors >= 8
1845      && (stream->set_a_foreground != NULL || stream->set_foreground != NULL)
1846      && stream->orig_pair != NULL);
1847   stream->supports_background =
1848     (stream->max_colors >= 8
1849      && (stream->set_a_background != NULL || stream->set_background != NULL)
1850      && stream->orig_pair != NULL);
1851   stream->colormodel =
1852     (stream->supports_foreground || stream->supports_background
1853      ? (term != NULL
1854         && (/* Recognize xterm-16color, xterm-88color, xterm-256color.  */
1855             (strlen (term) >= 5 && memcmp (term, "xterm", 5) == 0)
1856             || /* Recognize rxvt-16color.  */
1857                (strlen (term) >= 4 && memcmp (term, "rxvt", 7) == 0)
1858             || /* Recognize konsole-16color.  */
1859                (strlen (term) >= 7 && memcmp (term, "konsole", 7) == 0))
1860         ? (stream->max_colors == 256 ? cm_xterm256 :
1861            stream->max_colors == 88 ? cm_xterm88 :
1862            stream->max_colors == 16 ? cm_xterm16 :
1863            cm_xterm8)
1864         : cm_common8)
1865      : cm_monochrome);
1866   stream->supports_weight =
1867     (stream->enter_bold_mode != NULL && stream->exit_attribute_mode != NULL);
1868   stream->supports_posture =
1869     (stream->enter_italics_mode != NULL
1870      && (stream->exit_italics_mode != NULL
1871          || stream->exit_attribute_mode != NULL));
1872   stream->supports_underline =
1873     (stream->enter_underline_mode != NULL
1874      && (stream->exit_underline_mode != NULL
1875          || stream->exit_attribute_mode != NULL));
1876
1877   /* Initialize the buffer.  */
1878   stream->allocated = 120;
1879   stream->buffer = XNMALLOC (stream->allocated, char);
1880   stream->attrbuffer = XNMALLOC (stream->allocated, attributes_t);
1881   stream->buflen = 0;
1882
1883   /* Initialize the current attributes.  */
1884   stream->curr_attr.color = COLOR_DEFAULT;
1885   stream->curr_attr.bgcolor = COLOR_DEFAULT;
1886   stream->curr_attr.weight = WEIGHT_DEFAULT;
1887   stream->curr_attr.posture = POSTURE_DEFAULT;
1888   stream->curr_attr.underline = UNDERLINE_DEFAULT;
1889   stream->simp_attr = simplify_attributes (stream, stream->curr_attr);
1890
1891   /* Register an exit handler.  */
1892   {
1893     static bool registered = false;
1894     if (!registered)
1895       {
1896         atexit (restore);
1897         registered = true;
1898       }
1899   }
1900
1901   return stream;
1902 }
1903
1904 #line 1905 "term-ostream.c"
1905
1906 const struct term_ostream_implementation term_ostream_vtable =
1907 {
1908   term_ostream_superclasses,
1909   sizeof (term_ostream_superclasses) / sizeof (term_ostream_superclasses[0]),
1910   sizeof (struct term_ostream_representation),
1911   term_ostream__write_mem,
1912   term_ostream__flush,
1913   term_ostream__free,
1914   term_ostream__rgb_to_color,
1915   term_ostream__get_color,
1916   term_ostream__set_color,
1917   term_ostream__get_bgcolor,
1918   term_ostream__set_bgcolor,
1919   term_ostream__get_weight,
1920   term_ostream__set_weight,
1921   term_ostream__get_posture,
1922   term_ostream__set_posture,
1923   term_ostream__get_underline,
1924   term_ostream__set_underline,
1925 };
1926
1927 #if !HAVE_INLINE
1928
1929 /* Define the functions that invoke the methods.  */
1930
1931 void
1932 term_ostream_write_mem (term_ostream_t first_arg, const void *data, size_t len)
1933 {
1934   const struct term_ostream_implementation *vtable =
1935     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1936   vtable->write_mem (first_arg,data,len);
1937 }
1938
1939 void
1940 term_ostream_flush (term_ostream_t first_arg)
1941 {
1942   const struct term_ostream_implementation *vtable =
1943     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1944   vtable->flush (first_arg);
1945 }
1946
1947 void
1948 term_ostream_free (term_ostream_t first_arg)
1949 {
1950   const struct term_ostream_implementation *vtable =
1951     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1952   vtable->free (first_arg);
1953 }
1954
1955 term_color_t
1956 term_ostream_rgb_to_color (term_ostream_t first_arg,                              int red, int green, int blue)
1957 {
1958   const struct term_ostream_implementation *vtable =
1959     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1960   return vtable->rgb_to_color (first_arg,red,green,blue);
1961 }
1962
1963 term_color_t
1964 term_ostream_get_color (term_ostream_t first_arg)
1965 {
1966   const struct term_ostream_implementation *vtable =
1967     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1968   return vtable->get_color (first_arg);
1969 }
1970
1971 void
1972 term_ostream_set_color (term_ostream_t first_arg, term_color_t color)
1973 {
1974   const struct term_ostream_implementation *vtable =
1975     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1976   vtable->set_color (first_arg,color);
1977 }
1978
1979 term_color_t
1980 term_ostream_get_bgcolor (term_ostream_t first_arg)
1981 {
1982   const struct term_ostream_implementation *vtable =
1983     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1984   return vtable->get_bgcolor (first_arg);
1985 }
1986
1987 void
1988 term_ostream_set_bgcolor (term_ostream_t first_arg, term_color_t color)
1989 {
1990   const struct term_ostream_implementation *vtable =
1991     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
1992   vtable->set_bgcolor (first_arg,color);
1993 }
1994
1995 term_weight_t
1996 term_ostream_get_weight (term_ostream_t first_arg)
1997 {
1998   const struct term_ostream_implementation *vtable =
1999     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2000   return vtable->get_weight (first_arg);
2001 }
2002
2003 void
2004 term_ostream_set_weight (term_ostream_t first_arg, term_weight_t weight)
2005 {
2006   const struct term_ostream_implementation *vtable =
2007     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2008   vtable->set_weight (first_arg,weight);
2009 }
2010
2011 term_posture_t
2012 term_ostream_get_posture (term_ostream_t first_arg)
2013 {
2014   const struct term_ostream_implementation *vtable =
2015     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2016   return vtable->get_posture (first_arg);
2017 }
2018
2019 void
2020 term_ostream_set_posture (term_ostream_t first_arg, term_posture_t posture)
2021 {
2022   const struct term_ostream_implementation *vtable =
2023     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2024   vtable->set_posture (first_arg,posture);
2025 }
2026
2027 term_underline_t
2028 term_ostream_get_underline (term_ostream_t first_arg)
2029 {
2030   const struct term_ostream_implementation *vtable =
2031     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2032   return vtable->get_underline (first_arg);
2033 }
2034
2035 void
2036 term_ostream_set_underline (term_ostream_t first_arg,                                   term_underline_t underline)
2037 {
2038   const struct term_ostream_implementation *vtable =
2039     ((struct term_ostream_representation_header *) (struct term_ostream_representation *) first_arg)->vtable;
2040   vtable->set_underline (first_arg,underline);
2041 }
2042
2043 #endif