1/* Color and styling handling. 2 Copyright (C) 2006-2007 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2006. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18#ifdef HAVE_CONFIG_H 19# include <config.h> 20#endif 21 22/* Specification. */ 23#include "color.h" 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30 31#include "term-ostream.h" 32#include "xalloc.h" 33#include "relocatable.h" 34#include "filename.h" 35 36 37/* Whether to output a test page. */ 38bool color_test_mode; 39 40/* Color option. */ 41enum color_option color_mode = color_tty; 42 43/* Style to use when coloring. */ 44const char *style_file_name; 45 46/* --color argument handling. Return an error indicator. */ 47bool 48handle_color_option (const char *option) 49{ 50 if (option != NULL) 51 { 52 if (strcmp (option, "never") == 0 || strcmp (option, "no") == 0) 53 color_mode = color_no; 54 else if (strcmp (option, "auto") == 0 || strcmp (option, "tty") == 0) 55 color_mode = color_tty; 56 else if (strcmp (option, "always") == 0 || strcmp (option, "yes") == 0) 57 color_mode = color_yes; 58 else if (strcmp (option, "html") == 0) 59 color_mode = color_html; 60 else if (strcmp (option, "test") == 0) 61 color_test_mode = true; 62 else 63 { 64 fprintf (stderr, "invalid --color argument: %s\n", option); 65 return true; 66 } 67 } 68 else 69 /* --color is equivalent to --color=yes. */ 70 color_mode = color_yes; 71 return false; 72} 73 74/* --style argument handling. */ 75void 76handle_style_option (const char *option) 77{ 78 style_file_name = option; 79} 80 81/* Print a color test page. */ 82void 83print_color_test () 84{ 85 /* Code copied from test-term-ostream.c. */ 86 static struct { const char *name; term_color_t c; int r; int g; int b; } 87 colors[] = 88 { 89 { "black", -2, 0, 0, 0 }, 90 { "blue", -2, 0, 0, 255 }, 91 { "green", -2, 0, 255, 0 }, 92 { "cyan", -2, 0, 255, 255 }, 93 { "red", -2, 255, 0, 0 }, 94 { "magenta", -2, 255, 0, 255 }, 95 { "yellow", -2, 255, 255, 0 }, 96 { "white", -2, 255, 255, 255 }, 97 { "default", COLOR_DEFAULT } 98 }; 99 term_ostream_t stream; 100 int i, row, col; 101 102 stream = term_ostream_create (1, "stdout"); 103 104 for (i = 0; i < 8; i++) 105 colors[i].c = 106 term_ostream_rgb_to_color (stream, colors[i].r, colors[i].g, colors[i].b); 107 108 ostream_write_str (stream, "Colors (foreground/background):\n"); 109 ostream_write_str (stream, " "); 110 for (col = 0; col <= 8; col++) 111 { 112 const char *name = colors[col].name; 113 ostream_write_str (stream, "|"); 114 ostream_write_str (stream, name); 115 ostream_write_mem (stream, " ", 7 - strlen (name)); 116 } 117 ostream_write_str (stream, "\n"); 118 for (row = 0; row <= 8; row++) 119 { 120 const char *name = colors[row].name; 121 ostream_write_str (stream, name); 122 ostream_write_mem (stream, " ", 7 - strlen (name)); 123 for (col = 0; col <= 8; col++) 124 { 125 term_color_t row_color = colors[row].c; 126 term_color_t col_color = colors[col].c; 127 128 ostream_write_str (stream, "|"); 129 term_ostream_set_color (stream, row_color); 130 term_ostream_set_bgcolor (stream, col_color); 131 if (!(term_ostream_get_color (stream) == row_color 132 && term_ostream_get_bgcolor (stream) == col_color)) 133 abort (); 134 ostream_write_str (stream, " Words "); 135 term_ostream_set_color (stream, COLOR_DEFAULT); 136 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 137 if (!(term_ostream_get_color (stream) == COLOR_DEFAULT 138 && term_ostream_get_bgcolor (stream) == COLOR_DEFAULT)) 139 abort (); 140 } 141 ostream_write_str (stream, "\n"); 142 } 143 ostream_write_str (stream, "\n"); 144 145 ostream_write_str (stream, "Colors (hue/saturation):\n"); 146 /* Hue from 0 to 1. */ 147 for (row = 0; row <= 17; row++) 148 { 149 ostream_write_str (stream, row == 0 ? "red: " : " "); 150 for (col = 0; col <= 64; col++) 151 { 152 int r = 255; 153 int b = (int) (255.0f / 64.0f * col + 0.5f); 154 int g = b + (int) (row / 17.0f * (r - b) + 0.5f); 155 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 156 term_ostream_set_bgcolor (stream, c); 157 ostream_write_str (stream, " "); 158 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 159 } 160 ostream_write_str (stream, "\n"); 161 } 162 /* Hue from 1 to 2. */ 163 for (row = 17; row >= 0; row--) 164 { 165 ostream_write_str (stream, row == 17 ? "yellow: " : " "); 166 for (col = 0; col <= 64; col++) 167 { 168 int g = 255; 169 int b = (int) (255.0f / 64.0f * col + 0.5f); 170 int r = b + (int) (row / 17.0f * (g - b) + 0.5f); 171 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 172 term_ostream_set_bgcolor (stream, c); 173 ostream_write_str (stream, " "); 174 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 175 } 176 ostream_write_str (stream, "\n"); 177 } 178 /* Hue from 2 to 3. */ 179 for (row = 0; row <= 17; row++) 180 { 181 ostream_write_str (stream, row == 0 ? "green: " : " "); 182 for (col = 0; col <= 64; col++) 183 { 184 int g = 255; 185 int r = (int) (255.0f / 64.0f * col + 0.5f); 186 int b = r + (int) (row / 17.0f * (g - r) + 0.5f); 187 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 188 term_ostream_set_bgcolor (stream, c); 189 ostream_write_str (stream, " "); 190 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 191 } 192 ostream_write_str (stream, "\n"); 193 } 194 /* Hue from 3 to 4. */ 195 for (row = 17; row >= 0; row--) 196 { 197 ostream_write_str (stream, row == 17 ? "cyan: " : " "); 198 for (col = 0; col <= 64; col++) 199 { 200 int b = 255; 201 int r = (int) (255.0f / 64.0f * col + 0.5f); 202 int g = r + (int) (row / 17.0f * (b - r) + 0.5f); 203 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 204 term_ostream_set_bgcolor (stream, c); 205 ostream_write_str (stream, " "); 206 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 207 } 208 ostream_write_str (stream, "\n"); 209 } 210 /* Hue from 4 to 5. */ 211 for (row = 0; row <= 17; row++) 212 { 213 ostream_write_str (stream, row == 0 ? "blue: " : " "); 214 for (col = 0; col <= 64; col++) 215 { 216 int b = 255; 217 int g = (int) (255.0f / 64.0f * col + 0.5f); 218 int r = g + (int) (row / 17.0f * (b - g) + 0.5f); 219 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 220 term_ostream_set_bgcolor (stream, c); 221 ostream_write_str (stream, " "); 222 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 223 } 224 ostream_write_str (stream, "\n"); 225 } 226 /* Hue from 5 to 6. */ 227 for (row = 17; row >= 0; row--) 228 { 229 ostream_write_str (stream, row == 17 ? "magenta: " : 230 row == 0 ? "red: " : " "); 231 for (col = 0; col <= 64; col++) 232 { 233 int r = 255; 234 int g = (int) (255.0f / 64.0f * col + 0.5f); 235 int b = g + (int) (row / 17.0f * (r - g) + 0.5f); 236 term_color_t c = term_ostream_rgb_to_color (stream, r, g, b); 237 term_ostream_set_bgcolor (stream, c); 238 ostream_write_str (stream, " "); 239 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 240 } 241 ostream_write_str (stream, "\n"); 242 } 243 ostream_write_str (stream, "\n"); 244 245 ostream_write_str (stream, "Weights:\n"); 246 term_ostream_set_weight (stream, WEIGHT_NORMAL); 247 if (term_ostream_get_weight (stream) != WEIGHT_NORMAL) 248 abort (); 249 ostream_write_str (stream, "normal, "); 250 term_ostream_set_weight (stream, WEIGHT_BOLD); 251 if (term_ostream_get_weight (stream) != WEIGHT_BOLD) 252 abort (); 253 ostream_write_str (stream, "bold, "); 254 term_ostream_set_weight (stream, WEIGHT_DEFAULT); 255 if (term_ostream_get_weight (stream) != WEIGHT_DEFAULT) 256 abort (); 257 ostream_write_str (stream, "default \n"); 258 ostream_write_str (stream, "\n"); 259 260 ostream_write_str (stream, "Postures:\n"); 261 term_ostream_set_posture (stream, POSTURE_NORMAL); 262 if (term_ostream_get_posture (stream) != POSTURE_NORMAL) 263 abort (); 264 ostream_write_str (stream, "normal, "); 265 term_ostream_set_posture (stream, POSTURE_ITALIC); 266 if (term_ostream_get_posture (stream) != POSTURE_ITALIC) 267 abort (); 268 ostream_write_str (stream, "italic, "); 269 term_ostream_set_posture (stream, POSTURE_DEFAULT); 270 if (term_ostream_get_posture (stream) != POSTURE_DEFAULT) 271 abort (); 272 ostream_write_str (stream, "default \n"); 273 ostream_write_str (stream, "\n"); 274 275 ostream_write_str (stream, "Text decorations:\n"); 276 term_ostream_set_underline (stream, UNDERLINE_OFF); 277 if (term_ostream_get_underline (stream) != UNDERLINE_OFF) 278 abort (); 279 ostream_write_str (stream, "normal, "); 280 term_ostream_set_underline (stream, UNDERLINE_ON); 281 if (term_ostream_get_underline (stream) != UNDERLINE_ON) 282 abort (); 283 ostream_write_str (stream, "underlined, "); 284 term_ostream_set_underline (stream, UNDERLINE_DEFAULT); 285 if (term_ostream_get_underline (stream) != UNDERLINE_DEFAULT) 286 abort (); 287 ostream_write_str (stream, "default \n"); 288 ostream_write_str (stream, "\n"); 289 290 ostream_write_str (stream, "Colors (foreground) mixed with attributes:\n"); 291 for (row = 0; row <= 8; row++) 292 { 293 const char *name = colors[row].name; 294 ostream_write_str (stream, name); 295 ostream_write_mem (stream, " ", 7 - strlen (name)); 296 term_ostream_set_color (stream, colors[row].c); 297 ostream_write_str (stream, "|normal|"); 298 term_ostream_set_weight (stream, WEIGHT_BOLD); 299 ostream_write_str (stream, "bold"); 300 term_ostream_set_weight (stream, WEIGHT_NORMAL); 301 ostream_write_str (stream, "|normal|"); 302 term_ostream_set_posture (stream, POSTURE_ITALIC); 303 ostream_write_str (stream, "italic"); 304 term_ostream_set_posture (stream, POSTURE_NORMAL); 305 ostream_write_str (stream, "|normal|"); 306 term_ostream_set_underline (stream, UNDERLINE_ON); 307 ostream_write_str (stream, "underlined"); 308 term_ostream_set_underline (stream, UNDERLINE_OFF); 309 ostream_write_str (stream, "|normal|"); 310 term_ostream_set_color (stream, COLOR_DEFAULT); 311 ostream_write_str (stream, "\n "); 312 term_ostream_set_color (stream, colors[row].c); 313 ostream_write_str (stream, "|normal|"); 314 term_ostream_set_weight (stream, WEIGHT_BOLD); 315 term_ostream_set_posture (stream, POSTURE_ITALIC); 316 ostream_write_str (stream, "bold+italic"); 317 term_ostream_set_weight (stream, WEIGHT_NORMAL); 318 term_ostream_set_posture (stream, POSTURE_NORMAL); 319 ostream_write_str (stream, "|normal|"); 320 term_ostream_set_weight (stream, WEIGHT_BOLD); 321 term_ostream_set_underline (stream, UNDERLINE_ON); 322 ostream_write_str (stream, "bold+underl"); 323 term_ostream_set_weight (stream, WEIGHT_NORMAL); 324 term_ostream_set_underline (stream, UNDERLINE_OFF); 325 ostream_write_str (stream, "|normal|"); 326 term_ostream_set_posture (stream, POSTURE_ITALIC); 327 term_ostream_set_underline (stream, UNDERLINE_ON); 328 ostream_write_str (stream, "italic+underl"); 329 term_ostream_set_posture (stream, POSTURE_NORMAL); 330 term_ostream_set_underline (stream, UNDERLINE_OFF); 331 ostream_write_str (stream, "|normal|"); 332 term_ostream_set_color (stream, COLOR_DEFAULT); 333 ostream_write_str (stream, "\n"); 334 } 335 ostream_write_str (stream, "\n"); 336 337 ostream_write_str (stream, "Colors (background) mixed with attributes:\n"); 338 for (row = 0; row <= 8; row++) 339 { 340 const char *name = colors[row].name; 341 ostream_write_str (stream, name); 342 ostream_write_mem (stream, " ", 7 - strlen (name)); 343 term_ostream_set_bgcolor (stream, colors[row].c); 344 ostream_write_str (stream, "|normal|"); 345 term_ostream_set_weight (stream, WEIGHT_BOLD); 346 ostream_write_str (stream, "bold"); 347 term_ostream_set_weight (stream, WEIGHT_NORMAL); 348 ostream_write_str (stream, "|normal|"); 349 term_ostream_set_posture (stream, POSTURE_ITALIC); 350 ostream_write_str (stream, "italic"); 351 term_ostream_set_posture (stream, POSTURE_NORMAL); 352 ostream_write_str (stream, "|normal|"); 353 term_ostream_set_underline (stream, UNDERLINE_ON); 354 ostream_write_str (stream, "underlined"); 355 term_ostream_set_underline (stream, UNDERLINE_OFF); 356 ostream_write_str (stream, "|normal|"); 357 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 358 ostream_write_str (stream, "\n "); 359 term_ostream_set_bgcolor (stream, colors[row].c); 360 ostream_write_str (stream, "|normal|"); 361 term_ostream_set_weight (stream, WEIGHT_BOLD); 362 term_ostream_set_posture (stream, POSTURE_ITALIC); 363 ostream_write_str (stream, "bold+italic"); 364 term_ostream_set_weight (stream, WEIGHT_NORMAL); 365 term_ostream_set_posture (stream, POSTURE_NORMAL); 366 ostream_write_str (stream, "|normal|"); 367 term_ostream_set_weight (stream, WEIGHT_BOLD); 368 term_ostream_set_underline (stream, UNDERLINE_ON); 369 ostream_write_str (stream, "bold+underl"); 370 term_ostream_set_weight (stream, WEIGHT_NORMAL); 371 term_ostream_set_underline (stream, UNDERLINE_OFF); 372 ostream_write_str (stream, "|normal|"); 373 term_ostream_set_posture (stream, POSTURE_ITALIC); 374 term_ostream_set_underline (stream, UNDERLINE_ON); 375 ostream_write_str (stream, "italic+underl"); 376 term_ostream_set_posture (stream, POSTURE_NORMAL); 377 term_ostream_set_underline (stream, UNDERLINE_OFF); 378 ostream_write_str (stream, "|normal|"); 379 term_ostream_set_bgcolor (stream, COLOR_DEFAULT); 380 ostream_write_str (stream, "\n"); 381 } 382 ostream_write_str (stream, "\n"); 383 384 ostream_free (stream); 385} 386 387/* Lookup the location of the style file. */ 388static const char * 389style_file_lookup (const char *file_name) 390{ 391 if (!IS_PATH_WITH_DIR (file_name)) 392 { 393 /* It's a file name without a directory specification. 394 If it does not exist in the current directory... */ 395 struct stat statbuf; 396 397 if (stat (file_name, &statbuf) < 0) 398 { 399 /* ... but it exists in the styles installation location... */ 400 const char *gettextstylesdir = relocate (GETTEXTDATADIR "/styles"); 401 char *possible_file_name = 402 concatenated_filename (gettextstylesdir, file_name, NULL); 403 404 if (stat (possible_file_name, &statbuf) >= 0) 405 { 406 /* ... then use the file in the styles installation directory. */ 407 return possible_file_name; 408 } 409 free (possible_file_name); 410 } 411 412 /* Let the CSS library show a warning. */ 413 } 414 return file_name; 415} 416 417/* Assign a default value to style_file_name if necessary. */ 418void 419style_file_prepare () 420{ 421 if (style_file_name == NULL) 422 { 423 const char *user_preference = getenv ("PO_STYLE"); 424 425 if (user_preference != NULL && user_preference[0] != '\0') 426 style_file_name = style_file_lookup (xstrdup (user_preference)); 427 else 428 { 429 const char *gettextdatadir; 430 431 /* Make it possible to override the po-default.css location. This is 432 necessary for running the testsuite before "make install". */ 433 gettextdatadir = getenv ("GETTEXTDATADIR"); 434 if (gettextdatadir == NULL || gettextdatadir[0] == '\0') 435 gettextdatadir = relocate (GETTEXTDATADIR); 436 437 style_file_name = 438 concatenated_filename (gettextdatadir, "styles/po-default.css", 439 NULL); 440 } 441 } 442 else 443 style_file_name = style_file_lookup (style_file_name); 444} 445