/[baselayout]/trunk/src/libeinfo.c
Gentoo

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2971 - (show annotations) (download) (as text)
Wed Oct 3 12:43:50 2007 UTC (6 years, 6 months ago) by uberlord
File MIME type: text/x-csrc
File size: 12721 byte(s)
Don't use colour when not a tty - like say when we're redirected to a file.
1 /*
2 einfo.c
3 Gentoo informational functions
4 Copyright 2007 Gentoo Foundation
5 */
6
7 #include <sys/types.h>
8 #include <sys/ioctl.h>
9 #include <sys/stat.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <syslog.h>
19 #include <unistd.h>
20
21 #include "einfo.h"
22 #include "rc.h"
23 #include "rc-misc.h"
24
25 #include "hidden-visibility.h"
26 hidden_proto(ecolor)
27 hidden_proto(ebegin)
28 hidden_proto(ebeginv)
29 hidden_proto(ebracket)
30 hidden_proto(eend)
31 hidden_proto(eendv)
32 hidden_proto(eerror)
33 hidden_proto(eerrorn)
34 hidden_proto(eerrorx)
35 hidden_proto(eindent)
36 hidden_proto(eindentv)
37 hidden_proto(einfo)
38 hidden_proto(einfon)
39 hidden_proto(einfov)
40 hidden_proto(einfovn)
41 hidden_proto(elog)
42 hidden_proto(eoutdent)
43 hidden_proto(eoutdentv)
44 hidden_proto(ewarn)
45 hidden_proto(ewarnn)
46 hidden_proto(ewarnv)
47 hidden_proto(ewarnvn)
48 hidden_proto(ewarnx)
49 hidden_proto(ewend)
50 hidden_proto(ewendv)
51
52 /* Incase we cannot work out how many columns from ioctl, supply a default */
53 #define DEFAULT_COLS 80
54
55 #define OK "ok"
56 #define NOT_OK "!!"
57
58 #define CHECK_VERBOSE if (! is_env ("RC_VERBOSE", "yes")) return 0
59
60 /* Number of spaces for an indent */
61 #define INDENT_WIDTH 2
62
63 /* How wide can the indent go? */
64 #define INDENT_MAX 40
65
66 /* Default colours */
67 #define ECOLOR_GOOD_A "\033[32;01m"
68 #define ECOLOR_WARN_A "\033[33;01m"
69 #define ECOLOR_BAD_A "\033[31;01m"
70 #define ECOLOR_HILITE_A "\033[36;01m"
71 #define ECOLOR_BRACKET_A "\033[34;01m"
72 #define ECOLOR_NORMAL_A "\033[0m"
73 #define ECOLOR_FLUSH_A "\033[K"
74
75 /* A cheat sheet of colour capable terminals
76 This is taken from DIR_COLORS from GNU coreutils
77 We embed it here as we shouldn't depend on coreutils */
78 static const char *color_terms[] = {
79 "Eterm",
80 "ansi",
81 "color-xterm",
82 "con132x25",
83 "con132x30",
84 "con132x43",
85 "con132x60",
86 "con80x25",
87 "con80x28",
88 "con80x30",
89 "con80x43",
90 "con80x50",
91 "con80x60",
92 "cons25",
93 "console",
94 "cygwin",
95 "dtterm",
96 "gnome",
97 "konsole",
98 "kterm",
99 "linux",
100 "linux-c",
101 "mach-color",
102 "mlterm",
103 "putty",
104 "rxvt",
105 "rxvt-cygwin",
106 "rxvt-cygwin-native",
107 "rxvt-unicode",
108 "screen",
109 "screen-bce",
110 "screen-w",
111 "screen.linux",
112 "vt100",
113 "xterm",
114 "xterm-256color",
115 "xterm-color",
116 "xterm-debian",
117 NULL
118 };
119
120 static const char *term = NULL;
121 static bool term_is_cons25 = false;
122
123 /* A pointer to a string to prefix to einfo/ewarn/eerror messages */
124 static const char *_eprefix = NULL;
125
126 static bool is_env (const char *var, const char *val)
127 {
128 char *v;
129
130 if (! var)
131 return (false);
132
133 v = getenv (var);
134 if (! v)
135 return (val ? false : true);
136
137 return (strcasecmp (v, val) ? false : true);
138 }
139
140 static bool colour_terminal (FILE *f)
141 {
142 static int in_colour = -1;
143 int i = 0;
144
145 if (f && ! isatty (fileno (f)))
146 return (false);
147
148 if (is_env ("RC_NOCOLOR", "yes"))
149 return (false);
150
151 if (in_colour == 0)
152 return (false);
153 if (in_colour == 1)
154 return (true);
155
156 if (! term) {
157 term = getenv ("TERM");
158 if (! term)
159 return (false);
160 }
161
162 if (strcmp (term, "cons25") == 0)
163 term_is_cons25 = true;
164 else
165 term_is_cons25 = false;
166
167 while (color_terms[i]) {
168 if (strcmp (color_terms[i], term) == 0) {
169 in_colour = 1;
170 return (true);
171 }
172 i++;
173 }
174
175 in_colour = 0;
176 return (false);
177 }
178
179 static int get_term_columns (FILE *stream)
180 {
181 struct winsize ws;
182 char *env = getenv ("COLUMNS");
183 char *p;
184 int i;
185
186 if (env) {
187 i = strtol (env, &p, 10);
188 if (! *p)
189 return (i);
190 }
191
192 if (ioctl (fileno (stream), TIOCGWINSZ, &ws) == 0)
193 return (ws.ws_col);
194
195 return (DEFAULT_COLS);
196 }
197
198 void eprefix (const char *prefix)
199 {
200 _eprefix = prefix;
201 }
202
203 static void elogv (int level, const char *fmt, va_list ap)
204 {
205 char *e = getenv ("RC_ELOG");
206 va_list apc;
207
208 if (fmt && e) {
209 closelog ();
210 openlog (e, LOG_PID, LOG_DAEMON);
211 va_copy (apc, ap);
212 vsyslog (level, fmt, apc);
213 va_end (apc);
214 closelog ();
215 }
216 }
217
218 void elog (int level, const char *fmt, ...)
219 {
220 va_list ap;
221
222 va_start (ap, fmt);
223 elogv (level, fmt, ap);
224 va_end (ap);
225 }
226 hidden_def(elog)
227
228 static int _eindent (FILE *stream)
229 {
230 char *env = getenv ("RC_EINDENT");
231 int amount = 0;
232 char indent[INDENT_MAX];
233
234 if (env) {
235 errno = 0;
236 amount = strtol (env, NULL, 0);
237 if (errno != 0 || amount < 0)
238 amount = 0;
239 else if (amount > INDENT_MAX)
240 amount = INDENT_MAX;
241
242 if (amount > 0)
243 memset (indent, ' ', amount);
244 }
245
246 /* Terminate it */
247 memset (indent + amount, 0, 1);
248 return (fprintf (stream, "%s", indent));
249 }
250
251 static const char *_ecolor (FILE *f, einfo_color_t color)
252 {
253 const char *col = NULL;
254
255 if (! colour_terminal (f))
256 return ("");
257
258 switch (color) {
259 case ECOLOR_GOOD:
260 if (! (col = getenv ("ECOLOR_GOOD")))
261 col = ECOLOR_GOOD_A;
262 break;
263 case ECOLOR_WARN:
264 if (! (col = getenv ("ECOLOR_WARN")))
265 col = ECOLOR_WARN_A;
266 break;
267 case ECOLOR_BAD:
268 if (! (col = getenv ("ECOLOR_BAD")))
269 col = ECOLOR_BAD_A;
270 break;
271 case ECOLOR_HILITE:
272 if (! (col = getenv ("ECOLOR_HILITE")))
273 col = ECOLOR_HILITE_A;
274 break;
275 case ECOLOR_BRACKET:
276 if (! (col = getenv ("ECOLOR_BRACKET")))
277 col = ECOLOR_BRACKET_A;
278 break;
279 case ECOLOR_NORMAL:
280 col = ECOLOR_NORMAL_A;
281 break;
282 }
283
284 return (col);
285 }
286 hidden_def(ecolor)
287
288 const char *ecolor (einfo_color_t color)
289 {
290 return (_ecolor (NULL, color));
291 }
292
293 #define EINFOVN(_file, _color) \
294 if (_eprefix) \
295 fprintf (_file, "%s%s%s|", _ecolor (_file, _color), _eprefix, _ecolor (_file, ECOLOR_NORMAL)); \
296 fprintf (_file, " %s*%s ", _ecolor (_file, _color), _ecolor (_file, ECOLOR_NORMAL)); \
297 retval += _eindent (_file); \
298 { \
299 va_list _ap; \
300 va_copy (_ap, ap); \
301 retval += vfprintf (_file, fmt, _ap) + 3; \
302 va_end (_ap); \
303 } \
304 if (colour_terminal (_file)) \
305 fprintf (_file, ECOLOR_FLUSH_A);
306
307 static int _einfovn (const char *fmt, va_list ap)
308 {
309 int retval = 0;
310
311 EINFOVN (stdout, ECOLOR_GOOD);
312 return (retval);
313 }
314
315 static int _ewarnvn (const char *fmt, va_list ap)
316 {
317 int retval = 0;
318
319 EINFOVN (stdout, ECOLOR_WARN);
320 return (retval);
321 }
322
323 static int _eerrorvn (const char *fmt, va_list ap)
324 {
325 int retval = 0;
326
327 EINFOVN (stderr, ECOLOR_BAD);
328 return (retval);
329 }
330
331 int einfon (const char *fmt, ...)
332 {
333 int retval;
334 va_list ap;
335
336 if (! fmt || is_env ("RC_QUIET", "yes"))
337 return (0);
338
339 va_start (ap, fmt);
340 retval = _einfovn (fmt, ap);
341 va_end (ap);
342
343 return (retval);
344 }
345 hidden_def(einfon)
346
347 int ewarnn (const char *fmt, ...)
348 {
349 int retval;
350 va_list ap;
351
352 if (! fmt || is_env ("RC_QUIET", "yes"))
353 return (0);
354
355 va_start (ap, fmt);
356 retval = _ewarnvn (fmt, ap);
357 va_end (ap);
358
359 return (retval);
360 }
361 hidden_def(ewarnn)
362
363 int eerrorn (const char *fmt, ...)
364 {
365 int retval;
366 va_list ap;
367
368 va_start (ap, fmt);
369 retval = _eerrorvn (fmt, ap);
370 va_end (ap);
371
372 return (retval);
373 }
374 hidden_def(eerrorn)
375
376 int einfo (const char *fmt, ...)
377 {
378 int retval;
379 va_list ap;
380
381 if (! fmt || is_env ("RC_QUIET", "yes"))
382 return (0);
383
384 va_start (ap, fmt);
385 retval = _einfovn (fmt, ap);
386 retval += printf ("\n");
387 va_end (ap);
388
389 return (retval);
390 }
391 hidden_def(einfo)
392
393 int ewarn (const char *fmt, ...)
394 {
395 int retval;
396 va_list ap;
397
398 if (! fmt || is_env ("RC_QUIET", "yes"))
399 return (0);
400
401 va_start (ap, fmt);
402 elogv (LOG_WARNING, fmt, ap);
403 retval = _ewarnvn (fmt, ap);
404 retval += printf ("\n");
405 va_end (ap);
406
407 return (retval);
408 }
409 hidden_def(ewarn)
410
411 void ewarnx (const char *fmt, ...)
412 {
413 int retval;
414 va_list ap;
415
416 if (fmt && ! is_env ("RC_QUIET", "yes")) {
417 va_start (ap, fmt);
418 elogv (LOG_WARNING, fmt, ap);
419 retval = _ewarnvn (fmt, ap);
420 va_end (ap);
421 retval += printf ("\n");
422 }
423 exit (EXIT_FAILURE);
424 }
425 hidden_def(ewarnx)
426
427 int eerror (const char *fmt, ...)
428 {
429 int retval;
430 va_list ap;
431
432 if (! fmt)
433 return (0);
434
435 va_start (ap, fmt);
436 elogv (LOG_ERR, fmt, ap);
437 retval = _eerrorvn (fmt, ap);
438 va_end (ap);
439 retval += fprintf (stderr, "\n");
440
441 return (retval);
442 }
443 hidden_def(eerror)
444
445 void eerrorx (const char *fmt, ...)
446 {
447 va_list ap;
448
449 if (fmt) {
450 va_start (ap, fmt);
451 elogv (LOG_ERR, fmt, ap);
452 _eerrorvn (fmt, ap);
453 va_end (ap);
454 fprintf (stderr, "\n");
455 }
456
457 exit (EXIT_FAILURE);
458 }
459 hidden_def(eerrorx)
460
461 int ebegin (const char *fmt, ...)
462 {
463 int retval;
464 va_list ap;
465
466 if (! fmt || is_env ("RC_QUIET", "yes"))
467 return (0);
468
469 va_start (ap, fmt);
470 retval = _einfovn (fmt, ap);
471 va_end (ap);
472 retval += printf (" ...");
473 if (colour_terminal (stdout))
474 retval += printf ("\n");
475
476 return (retval);
477 }
478 hidden_def(ebegin)
479
480 static void _eend (FILE *fp, int col, einfo_color_t color, const char *msg)
481 {
482 int i;
483 int cols;
484
485 if (! msg)
486 return;
487
488 cols = get_term_columns (fp) - (strlen (msg) + 5);
489
490 /* cons25 is special - we need to remove one char, otherwise things
491 * do not align properly at all. */
492 if (! term) {
493 term = getenv ("TERM");
494 if (term && strcmp (term, "cons25") == 0)
495 term_is_cons25 = true;
496 else
497 term_is_cons25 = false;
498 }
499 if (term_is_cons25)
500 cols--;
501
502 if (cols > 0 && colour_terminal (fp)) {
503 fprintf (fp, "\033[A\033[%dC %s[ %s%s %s]%s\n", cols,
504 ecolor (ECOLOR_BRACKET), ecolor (color), msg,
505 ecolor (ECOLOR_BRACKET), ecolor (ECOLOR_NORMAL));
506 } else {
507 if (col > 0)
508 for (i = 0; i < cols - col; i++)
509 fprintf (fp, " ");
510 fprintf (fp, " [ %s ]\n", msg);
511 }
512 }
513
514 static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
515 {
516 int col = 0;
517 FILE *fp = stdout;
518 va_list apc;
519
520 if (fmt && retval != 0) {
521 va_copy (apc, ap);
522 if (strcmp (cmd, "ewend") == 0) {
523 col = _ewarnvn (fmt, apc);
524 fp = stdout;
525 } else {
526 col = _eerrorvn (fmt, apc);
527 fp = stderr;
528 }
529 col += fprintf (fp, "\n");
530 va_end (apc);
531 }
532
533 _eend (fp, col,
534 retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD,
535 retval == 0 ? OK : NOT_OK);
536 return (retval);
537 }
538
539 int eend (int retval, const char *fmt, ...)
540 {
541 va_list ap;
542
543 if (is_env ("RC_QUIET", "yes"))
544 return (retval);
545
546 va_start (ap, fmt);
547 _do_eend ("eend", retval, fmt, ap);
548 va_end (ap);
549
550 return (retval);
551 }
552 hidden_def(eend)
553
554 int ewend (int retval, const char *fmt, ...)
555 {
556 va_list ap;
557
558 if (is_env ("RC_QUIET", "yes"))
559 return (retval);
560
561 va_start (ap, fmt);
562 _do_eend ("ewend", retval, fmt, ap);
563 va_end (ap);
564
565 return (retval);
566 }
567 hidden_def(ewend)
568
569 void ebracket (int col, einfo_color_t color, const char *msg)
570 {
571 _eend (stdout, col, color, msg);
572 }
573 hidden_def(ebracket)
574
575 void eindent (void)
576 {
577 char *env = getenv ("RC_EINDENT");
578 int amount = 0;
579 char num[10];
580
581 if (env) {
582 errno = 0;
583 amount = strtol (env, NULL, 0);
584 if (errno != 0)
585 amount = 0;
586 }
587
588 amount += INDENT_WIDTH;
589 if (amount > INDENT_MAX)
590 amount = INDENT_MAX;
591
592 snprintf (num, 10, "%08d", amount);
593 setenv ("RC_EINDENT", num, 1);
594 }
595 hidden_def(eindent)
596
597 void eoutdent (void)
598 {
599 char *env = getenv ("RC_EINDENT");
600 int amount = 0;
601 char num[10];
602
603 if (! env)
604 return;
605
606 errno = 0;
607 amount = strtol (env, NULL, 0);
608 if (errno != 0)
609 amount = 0;
610 else
611 amount -= INDENT_WIDTH;
612
613 if (amount <= 0)
614 unsetenv ("RC_EINDENT");
615 else {
616 snprintf (num, 10, "%08d", amount);
617 setenv ("RC_EINDENT", num, 1);
618 }
619 }
620 hidden_def(eoutdent)
621
622 int einfovn (const char *fmt, ...)
623 {
624 int retval;
625 va_list ap;
626
627 CHECK_VERBOSE;
628
629 if (! fmt)
630 return (0);
631
632 va_start (ap, fmt);
633 retval = _einfovn (fmt, ap);
634 va_end (ap);
635
636 return (retval);
637 }
638 hidden_def(einfovn)
639
640 int ewarnvn (const char *fmt, ...)
641 {
642 int retval;
643 va_list ap;
644
645 CHECK_VERBOSE;
646
647 if (! fmt)
648 return (0);
649
650 va_start (ap, fmt);
651 retval = _ewarnvn (fmt, ap);
652 va_end (ap);
653
654 return (retval);
655 }
656 hidden_def(ewarnvn)
657
658 int einfov (const char *fmt, ...)
659 {
660 int retval;
661 va_list ap;
662
663 CHECK_VERBOSE;
664
665 if (! fmt)
666 return (0);
667
668 va_start (ap, fmt);
669 retval = _einfovn (fmt, ap);
670 retval += printf ("\n");
671 va_end (ap);
672
673 return (retval);
674 }
675 hidden_def(einfov)
676
677 int ewarnv (const char *fmt, ...)
678 {
679 int retval;
680 va_list ap;
681
682 CHECK_VERBOSE;
683
684 if (! fmt)
685 return (0);
686
687 va_start (ap, fmt);
688 retval = _ewarnvn (fmt, ap);
689 retval += printf ("\n");
690 va_end (ap);
691
692 return (retval);
693 }
694 hidden_def(ewarnv)
695
696 int ebeginv (const char *fmt, ...)
697 {
698 int retval;
699 va_list ap;
700
701 CHECK_VERBOSE;
702
703 if (! fmt)
704 return (0);
705
706 va_start (ap, fmt);
707 retval = _einfovn (fmt, ap);
708 retval += printf (" ...");
709 if (colour_terminal (stdout))
710 retval += printf ("\n");
711 va_end (ap);
712
713 return (retval);
714 }
715 hidden_def(ebeginv)
716
717 int eendv (int retval, const char *fmt, ...)
718 {
719 va_list ap;
720
721 CHECK_VERBOSE;
722
723 va_start (ap, fmt);
724 _do_eend ("eendv", retval, fmt, ap);
725 va_end (ap);
726
727 return (retval);
728 }
729 hidden_def(eendv)
730
731 int ewendv (int retval, const char *fmt, ...)
732 {
733 va_list ap;
734
735 CHECK_VERBOSE;
736
737 va_start (ap, fmt);
738 _do_eend ("ewendv", retval, fmt, ap);
739 va_end (ap);
740
741 return (retval);
742 }
743 hidden_def(ewendv)
744
745 void eindentv (void)
746 {
747 if (is_env ("RC_VERBOSE", "yes"))
748 eindent ();
749 }
750 hidden_def(eindentv)
751
752 void eoutdentv (void)
753 {
754 if (is_env ("RC_VERBOSE", "yes"))
755 eoutdent ();
756 }
757 hidden_def(eoutdentv)

  ViewVC Help
Powered by ViewVC 1.1.20