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