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-2007 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(). */ 46static 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. */ 59typedef 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. */ 67typedef 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. */ 75static void 76rgb_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. */ 140static float 141color_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. */ 182static unsigned int 183nearest_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. */ 229static float 230color_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. */ 243typedef 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. */ 256static inline term_color_t 257rgb_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 */ 274static 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 287static inline term_color_t 288rgb_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. */ 313static inline int 314color_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 */ 331static 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 345static inline term_color_t 346rgb_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. */ 372static 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 393static inline term_color_t 394rgb_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 426static 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 519static inline term_color_t 520rgb_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 570static 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 831static inline term_color_t 832rgb_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. */ 930typedef 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 948const typeinfo_t term_ostream_typeinfo = { "term_ostream" }; 949 950static 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. */ 958static attributes_t 959simplify_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. */ 990static int out_fd = -1; 991 992/* Filename of out_fd. */ 993static const char *out_filename; 994 995/* Output a single char to out_fd. Ignore errors. */ 996static int 997out_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. */ 1007static const char *restore_colors; 1008static const char *restore_weight; 1009static const char *restore_posture; 1010static const char *restore_underline; 1011 1012/* The exit handler. */ 1013static void 1014restore (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. */ 1031static 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 1047static sigset_t stopping_signal_set; 1048 1049static void 1050init_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. */ 1066static inline void 1067block_stopping_signals () 1068{ 1069 init_stopping_signal_set (); 1070 sigprocmask (SIG_BLOCK, &stopping_signal_set, NULL); 1071} 1072 1073/* Stop delaying the stopping signals. */ 1074static inline void 1075unblock_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. */ 1082static inline bool 1083equal_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. */ 1093static void 1094out_error () 1095{ 1096 error (EXIT_FAILURE, errno, _("error writing to %s"), out_filename); 1097} 1098 1099/* Output a single char to out_fd. */ 1100static int 1101out_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. */ 1115static void 1116out_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). */ 1404static void 1405output_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 1500static term_color_t 1501term_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 1522static void 1523term_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 1573static void 1574term_ostream__flush (term_ostream_t stream) 1575{ 1576 output_buffer (stream); 1577} 1578 1579static void 1580term_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 1612term_color_t 1613term_ostream__get_color (term_ostream_t stream) 1614{ 1615 return stream->curr_attr.color; 1616} 1617 1618void 1619term_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 1625term_color_t 1626term_ostream__get_bgcolor (term_ostream_t stream) 1627{ 1628 return stream->curr_attr.bgcolor; 1629} 1630 1631void 1632term_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 1638term_weight_t 1639term_ostream__get_weight (term_ostream_t stream) 1640{ 1641 return stream->curr_attr.weight; 1642} 1643 1644void 1645term_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 1651term_posture_t 1652term_ostream__get_posture (term_ostream_t stream) 1653{ 1654 return stream->curr_attr.posture; 1655} 1656 1657void 1658term_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 1664term_underline_t 1665term_ostream__get_underline (term_ostream_t stream) 1666{ 1667 return stream->curr_attr.underline; 1668} 1669 1670void 1671term_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 1679static inline char * 1680xstrdup0 (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 1691term_ostream_t 1692term_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 1906const 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 1931void 1932term_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 1939void 1940term_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 1947void 1948term_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 1955term_color_t 1956term_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 1963term_color_t 1964term_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 1971void 1972term_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 1979term_color_t 1980term_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 1987void 1988term_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 1995term_weight_t 1996term_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 2003void 2004term_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 2011term_posture_t 2012term_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 2019void 2020term_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 2027term_underline_t 2028term_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 2035void 2036term_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 2044