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

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2734 - (show annotations) (download) (as text)
Thu Jun 28 15:44:14 2007 UTC (7 years, 6 months ago) by uberlord
File MIME type: text/x-csrc
File size: 15170 byte(s)
Add --nocolor to more programs
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(eflush)
36 hidden_proto(eclose)
37 hidden_proto(eindent)
38 hidden_proto(eindentv)
39 hidden_proto(einfo)
40 hidden_proto(einfon)
41 hidden_proto(einfov)
42 hidden_proto(einfovn)
43 hidden_proto(eoutdent)
44 hidden_proto(eoutdentv)
45 hidden_proto(ewarn)
46 hidden_proto(ewarnn)
47 hidden_proto(ewarnv)
48 hidden_proto(ewarnvn)
49 hidden_proto(ewarnx)
50 hidden_proto(ewend)
51 hidden_proto(ewendv)
52
53 /* Incase we cannot work out how many columns from ioctl, supply a default */
54 #define DEFAULT_COLS 80
55
56 #define OK "ok"
57 #define NOT_OK "!!"
58
59 #define CHECK_VERBOSE if (! is_env ("RC_VERBOSE", "yes")) return 0
60
61 /* Number of spaces for an indent */
62 #define INDENT_WIDTH 2
63
64 /* How wide can the indent go? */
65 #define INDENT_MAX 40
66
67 #define EBUFFER_LOCK RC_SVCDIR "ebuffer/.lock"
68
69 /* Default colours */
70 #define ECOLOR_GOOD "\033[32;01m"
71 #define ECOLOR_WARN "\033[33;01m"
72 #define ECOLOR_BAD "\033[31;01m"
73 #define ECOLOR_HILITE "\033[36;01m"
74 #define ECOLOR_BRACKET "\033[34;01m"
75 #define ECOLOR_NORMAL "\033[0m"
76 #define ECOLOR_FLUSH "\033[K"
77
78 /* A cheat sheet of colour capable terminals
79 This is taken from DIR_COLORS from GNU coreutils
80 We embed it here as we shouldn't depend on coreutils */
81 static const char *color_terms[] = {
82 "Eterm",
83 "ansi",
84 "color-xterm",
85 "con132x25",
86 "con132x30",
87 "con132x43",
88 "con132x60",
89 "con80x25",
90 "con80x28",
91 "con80x30",
92 "con80x43",
93 "con80x50",
94 "con80x60",
95 "cons25",
96 "console",
97 "cygwin",
98 "dtterm",
99 "gnome",
100 "konsole",
101 "kterm",
102 "linux",
103 "linux-c",
104 "mach-color",
105 "mlterm",
106 "putty",
107 "rxvt",
108 "rxvt-cygwin",
109 "rxvt-cygwin-native",
110 "rxvt-unicode",
111 "screen",
112 "screen-bce",
113 "screen-w",
114 "screen.linux",
115 "vt100",
116 "xterm",
117 "xterm-256color",
118 "xterm-color",
119 "xterm-debian",
120 NULL
121 };
122
123 /* We use this array to save the stdout/stderr fd's for buffering */
124 static int stdfd[2] = {-1, -1};
125 static FILE *ebfp = NULL;
126 static char ebfile[PATH_MAX] = { '\0' };
127 static const char *term = NULL;
128 static bool term_is_cons25 = false;
129
130 /* A pointer to a string to prefix to einfo/ewarn/eerror messages */
131 static const char *_eprefix = NULL;
132
133 static bool is_env (const char *var, const char *val)
134 {
135 char *v;
136
137 if (! var)
138 return (false);
139
140 v = getenv (var);
141 if (! v)
142 return (val ? false : true);
143
144 return (strcasecmp (v, val) ? false : true);
145 }
146
147 static bool colour_terminal (void)
148 {
149 static int in_colour = -1;
150 int i = 0;
151
152 if (is_env ("RC_NOCOLOR", "yes"))
153 return (false);
154
155 if (in_colour == 0)
156 return (false);
157 if (in_colour == 1)
158 return (true);
159
160 if (! term) {
161 term = getenv ("TERM");
162 if (! term)
163 return (false);
164 }
165
166 if (strcmp (term, "cons25") == 0)
167 term_is_cons25 = true;
168 else
169 term_is_cons25 = false;
170
171 while (color_terms[i]) {
172 if (strcmp (color_terms[i], term) == 0) {
173 in_colour = 1;
174 return (true);
175 }
176 i++;
177 }
178
179 in_colour = 0;
180 return (false);
181 }
182
183 static int get_term_columns (void)
184 {
185 #if defined(TIOCGSIZE) /* BSD */
186 struct ttysize ts;
187
188 if (ioctl(0, TIOCGSIZE, &ts) == 0)
189 return (ts.ts_cols);
190 #elif defined(TIOCGWINSZ) /* Linux */
191 struct winsize ws;
192
193 if (ioctl(0, TIOCGWINSZ, &ws) == 0)
194 return (ws.ws_col);
195 #endif
196
197 return (DEFAULT_COLS);
198 }
199
200 void eprefix (const char *prefix) {
201 _eprefix = prefix;
202 }
203
204 void ebuffer (const char *file)
205 {
206 /* Don't ebuffer if we don't have a file or we already are */
207 if (! file || stdfd[0] >= 0 || ! isatty (fileno (stdout)))
208 return;
209
210 /* Save the current fd's */
211 stdfd[0] = dup (fileno (stdout));
212 stdfd[1] = dup (fileno (stderr));
213
214 if (! (ebfp = fopen (file, "w+"))) {
215 fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno));
216 return;
217 }
218
219 snprintf (ebfile, sizeof (ebfile), "%s", file);
220
221 fflush (stdout);
222 fflush (stderr);
223
224 /* Now redirect stdout and stderr */
225 if ((dup2 (fileno (ebfp), fileno (stdout))) < 0)
226 fprintf (stderr, "dup2: %s", strerror (errno));
227 if ((dup2 (fileno (ebfp), fileno (stderr))) < 0)
228 fprintf (stderr, "dup2: %s", strerror (errno));
229
230 /* Store the filename in our environment so scripts can tell if we're
231 * buffering or not */
232 unsetenv ("RC_EBUFFER");
233 setenv ("RC_EBUFFER", file, 1);
234
235 return;
236 }
237
238 static void _eflush (bool reopen)
239 {
240 char buffer[RC_LINEBUFFER];
241 int serrno = errno;
242
243 /* eflush called from an init script? */
244 if (! ebfp) {
245 char *file = getenv ("RC_EBUFFER");
246 if (file)
247 ebfp = fopen (file, "a+");
248 }
249
250 if (! ebfp)
251 return;
252
253 fflush (stdout);
254 fflush (stderr);
255
256 /* Restore stdout and stderr now */
257 if (stdfd[0] >= 0) {
258 dup2 (stdfd[0], fileno (stdout));
259 dup2 (stdfd[1], fileno (stderr));
260 } else {
261 char *tty = getenv ("RC_TTY");
262 if (tty) {
263 freopen (tty, "w+", stdout);
264 dup2 (fileno (stdout), fileno (stderr));
265 }
266 }
267
268 /* Spin until we can lock the ebuffer */
269 while (true) {
270 struct timeval tv;
271 errno = 0;
272 if (mkfifo (EBUFFER_LOCK, 0700) == 0)
273 break;
274 if (errno != EEXIST)
275 eerror ("mkfifo `%s': %s\n", EBUFFER_LOCK, strerror (errno));
276 tv.tv_sec = 0;
277 tv.tv_usec = 20000;
278 select (0, NULL, NULL, NULL, &tv);
279 }
280 errno = serrno;
281
282 /* Dump the file to stdout */
283 memset (buffer, 0, RC_LINEBUFFER);
284 if (fseek (ebfp, (off_t) 0, SEEK_SET) < 0)
285 eerror ("fseek: %s", strerror (errno));
286 else {
287 while (fgets (buffer, RC_LINEBUFFER, ebfp))
288 printf ("%s", buffer);
289 }
290 fflush (stdout);
291 fflush (stderr);
292
293 if (unlink (EBUFFER_LOCK))
294 eerror ("unlink `%s': %s", EBUFFER_LOCK, strerror (errno));
295
296 if (reopen) {
297 ftruncate (fileno (ebfp), (off_t) 0);
298 fseek (ebfp, (off_t) 0, SEEK_SET);
299 dup2 (fileno (ebfp), fileno (stdout));
300 dup2 (fileno (ebfp), fileno (stderr));
301 } else {
302 stdfd[0] = -1;
303 stdfd[1] = -1;
304 fclose (ebfp);
305 ebfp = NULL;
306 unlink (ebfile);
307 ebfile[0] = '\0';
308 unsetenv ("RC_EBUFFER");
309 }
310
311 return;
312 }
313
314 void eflush () {
315 _eflush (true);
316 }
317 hidden_def(eflush)
318
319 void eclose () {
320 _eflush (false);
321 }
322 hidden_def(eclose)
323
324 static void elog (int level, const char *fmt, va_list ap)
325 {
326 char *e = getenv ("RC_ELOG");
327 va_list apc;
328
329 if (fmt && e) {
330 closelog ();
331 openlog (e, LOG_PID, LOG_DAEMON);
332 va_copy (apc, ap);
333 vsyslog (level, fmt, apc);
334 va_end (apc);
335 closelog ();
336 }
337 }
338
339 static int _eindent (FILE *stream)
340 {
341 char *env = getenv ("RC_EINDENT");
342 int amount = 0;
343 char indent[INDENT_MAX];
344
345 if (env) {
346 errno = 0;
347 amount = strtol (env, NULL, 0);
348 if (errno != 0 || amount < 0)
349 amount = 0;
350 else if (amount > INDENT_MAX)
351 amount = INDENT_MAX;
352
353 if (amount > 0)
354 memset (indent, ' ', amount);
355 }
356
357 /* Terminate it */
358 memset (indent + amount, 0, 1);
359 return (fprintf (stream, "%s", indent));
360 }
361
362 const char *ecolor (einfo_color_t color) {
363 const char *col = NULL;
364
365 if (! colour_terminal ())
366 return ("");
367
368 switch (color) {
369 case ecolor_good:
370 if (! (col = getenv ("ECOLOR_GOOD")))
371 col = ECOLOR_GOOD;
372 break;
373 case ecolor_warn:
374 if (! (col = getenv ("ECOLOR_WARN")))
375 col = ECOLOR_WARN;
376 break;
377 case ecolor_bad:
378 if (! (col = getenv ("ECOLOR_BAD")))
379 col = ECOLOR_BAD;
380 break;
381 case ecolor_hilite:
382 if (! (col = getenv ("ECOLOR_HILITE")))
383 col = ECOLOR_HILITE;
384 break;
385 case ecolor_bracket:
386 if (! (col = getenv ("ECOLOR_BRACKET")))
387 col = ECOLOR_BRACKET;
388 break;
389 case ecolor_normal:
390 col = ECOLOR_NORMAL;
391 break;
392 }
393
394 return (col);
395 }
396 hidden_def(ecolor)
397
398 #define EINFOVN(_file, _color) \
399 if (_eprefix) \
400 fprintf (_file, "%s%s%s|", ecolor (_color), _eprefix, ecolor (ecolor_normal)); \
401 fprintf (_file, " %s*%s ", ecolor (_color), ecolor (ecolor_normal)); \
402 retval += _eindent (_file); \
403 { \
404 va_list _ap; \
405 va_copy (_ap, ap); \
406 retval += vfprintf (_file, fmt, _ap) + 3; \
407 va_end (_ap); \
408 } \
409 if (colour_terminal ()) \
410 fprintf (_file, ECOLOR_FLUSH);
411
412 static int _einfovn (const char *fmt, va_list ap)
413 {
414 int retval = 0;
415
416 EINFOVN (stdout, ecolor_good);
417 return (retval);
418 }
419
420 static int _ewarnvn (const char *fmt, va_list ap)
421 {
422 int retval = 0;
423
424 EINFOVN (stdout, ecolor_warn);
425 return (retval);
426 }
427
428 static int _eerrorvn (const char *fmt, va_list ap)
429 {
430 int retval = 0;
431
432 EINFOVN (stderr, ecolor_bad);
433 return (retval);
434 }
435
436 int einfon (const char *fmt, ...)
437 {
438 int retval;
439 va_list ap;
440
441 if (! fmt || is_env ("RC_QUIET", "yes"))
442 return (0);
443
444 va_start (ap, fmt);
445 retval = _einfovn (fmt, ap);
446 va_end (ap);
447
448 return (retval);
449 }
450 hidden_def(einfon)
451
452 int ewarnn (const char *fmt, ...)
453 {
454 int retval;
455 va_list ap;
456
457 if (! fmt || is_env ("RC_QUIET", "yes"))
458 return (0);
459
460 va_start (ap, fmt);
461 retval = _ewarnvn (fmt, ap);
462 va_end (ap);
463
464 return (retval);
465 }
466 hidden_def(ewarnn)
467
468 int eerrorn (const char *fmt, ...)
469 {
470 int retval;
471 va_list ap;
472
473 va_start (ap, fmt);
474 retval = _eerrorvn (fmt, ap);
475 va_end (ap);
476
477 return (retval);
478 }
479 hidden_def(eerrorn)
480
481 int einfo (const char *fmt, ...)
482 {
483 int retval;
484 va_list ap;
485
486 if (! fmt || is_env ("RC_QUIET", "yes"))
487 return (0);
488
489 va_start (ap, fmt);
490 retval = _einfovn (fmt, ap);
491 retval += printf ("\n");
492 va_end (ap);
493
494 return (retval);
495 }
496 hidden_def(einfo)
497
498 int ewarn (const char *fmt, ...)
499 {
500 int retval;
501 va_list ap;
502
503 if (! fmt || is_env ("RC_QUIET", "yes"))
504 return (0);
505
506 va_start (ap, fmt);
507 elog (LOG_WARNING, fmt, ap);
508 retval = _ewarnvn (fmt, ap);
509 retval += printf ("\n");
510 va_end (ap);
511
512 return (retval);
513 }
514 hidden_def(ewarn)
515
516 void ewarnx (const char *fmt, ...)
517 {
518 int retval;
519 va_list ap;
520
521 eclose ();
522 if (fmt && ! is_env ("RC_QUIET", "yes")) {
523 va_start (ap, fmt);
524 elog (LOG_WARNING, fmt, ap);
525 retval = _ewarnvn (fmt, ap);
526 va_end (ap);
527 retval += printf ("\n");
528 }
529 exit (EXIT_FAILURE);
530 }
531 hidden_def(ewarnx)
532
533 int eerror (const char *fmt, ...)
534 {
535 int retval;
536 va_list ap;
537
538 if (! fmt)
539 return (0);
540
541 va_start (ap, fmt);
542 elog (LOG_ERR, fmt, ap);
543 retval = _eerrorvn (fmt, ap);
544 va_end (ap);
545 retval += fprintf (stderr, "\n");
546
547 eflush ();
548 return (retval);
549 }
550 hidden_def(eerror)
551
552 void eerrorx (const char *fmt, ...)
553 {
554 va_list ap;
555
556 eclose ();
557 if (fmt) {
558 va_start (ap, fmt);
559 elog (LOG_ERR, fmt, ap);
560 _eerrorvn (fmt, ap);
561 va_end (ap);
562 printf ("\n");
563 }
564
565 exit (EXIT_FAILURE);
566 }
567 hidden_def(eerrorx)
568
569 int ebegin (const char *fmt, ...)
570 {
571 int retval;
572 va_list ap;
573
574 if (! fmt || is_env ("RC_QUIET", "yes"))
575 return (0);
576
577 va_start (ap, fmt);
578 retval = _einfovn (fmt, ap);
579 va_end (ap);
580 retval += printf (" ...");
581 if (colour_terminal ())
582 retval += printf ("\n");
583
584 return (retval);
585 }
586 hidden_def(ebegin)
587
588 static void _eend (FILE *fp, int col, einfo_color_t color, const char *msg)
589 {
590 int i;
591 int cols;
592
593 if (! msg)
594 return;
595
596 cols = get_term_columns () - (strlen (msg) + 5);
597
598 /* cons25 is special - we need to remove one char, otherwise things
599 * do not align properly at all. */
600 if (! term) {
601 term = getenv ("TERM");
602 if (term && strcmp (term, "cons25") == 0)
603 term_is_cons25 = true;
604 else
605 term_is_cons25 = false;
606 }
607 if (term_is_cons25)
608 cols--;
609
610 if (cols > 0 && colour_terminal ()) {
611 fprintf (fp, "\033[A\033[%dC %s[ %s%s %s]%s\n", cols,
612 ecolor (ecolor_bracket), ecolor (color), msg,
613 ecolor (ecolor_bracket), ecolor (ecolor_normal));
614 } else {
615 if (col > 0)
616 for (i = 0; i < cols - col; i++)
617 fprintf (fp, " ");
618 fprintf (fp, " [ %s ]\n", msg);
619 }
620 }
621
622 static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
623 {
624 int col = 0;
625 FILE *fp = stdout;
626 va_list apc;
627
628 if (fmt && retval != 0) {
629 va_copy (apc, ap);
630 if (strcmp (cmd, "ewend") == 0) {
631 col = _ewarnvn (fmt, apc);
632 fp = stdout;
633 } else {
634 col = _eerrorvn (fmt, apc);
635 fp = stderr;
636 }
637 va_end (apc);
638 }
639
640 _eend (fp, col,
641 retval == 0 ? ecolor_good : ecolor_bad,
642 retval == 0 ? OK : NOT_OK);
643 return (retval);
644 }
645
646 int eend (int retval, const char *fmt, ...)
647 {
648 va_list ap;
649
650 if (is_env ("RC_QUIET", "yes"))
651 return (retval);
652
653 va_start (ap, fmt);
654 _do_eend ("eend", retval, fmt, ap);
655 va_end (ap);
656
657 return (retval);
658 }
659 hidden_def(eend)
660
661 int ewend (int retval, const char *fmt, ...)
662 {
663 va_list ap;
664
665 if (is_env ("RC_QUIET", "yes"))
666 return (retval);
667
668 va_start (ap, fmt);
669 _do_eend ("ewend", retval, fmt, ap);
670 va_end (ap);
671
672 return (retval);
673 }
674 hidden_def(ewend)
675
676 void ebracket (int col, einfo_color_t color, const char *msg)
677 {
678 _eend (stdout, col, color, msg);
679 }
680 hidden_def(ebracket)
681
682 void eindent (void)
683 {
684 char *env = getenv ("RC_EINDENT");
685 int amount = 0;
686 char num[10];
687
688 if (env) {
689 errno = 0;
690 amount = strtol (env, NULL, 0);
691 if (errno != 0)
692 amount = 0;
693 }
694
695 amount += INDENT_WIDTH;
696 if (amount > INDENT_MAX)
697 amount = INDENT_MAX;
698
699 snprintf (num, 10, "%08d", amount);
700 setenv ("RC_EINDENT", num, 1);
701 }
702 hidden_def(eindent)
703
704 void eoutdent (void)
705 {
706 char *env = getenv ("RC_EINDENT");
707 int amount = 0;
708 char num[10];
709
710 if (! env)
711 return;
712
713 errno = 0;
714 amount = strtol (env, NULL, 0);
715 if (errno != 0)
716 amount = 0;
717 else
718 amount -= INDENT_WIDTH;
719
720 if (amount <= 0)
721 unsetenv ("RC_EINDENT");
722 else {
723 snprintf (num, 10, "%08d", amount);
724 setenv ("RC_EINDENT", num, 1);
725 }
726 }
727 hidden_def(eoutdent)
728
729 int einfovn (const char *fmt, ...)
730 {
731 int retval;
732 va_list ap;
733
734 CHECK_VERBOSE;
735
736 if (! fmt)
737 return (0);
738
739 va_start (ap, fmt);
740 retval = _einfovn (fmt, ap);
741 va_end (ap);
742
743 return (retval);
744 }
745 hidden_def(einfovn)
746
747 int ewarnvn (const char *fmt, ...)
748 {
749 int retval;
750 va_list ap;
751
752 CHECK_VERBOSE;
753
754 if (! fmt)
755 return (0);
756
757 va_start (ap, fmt);
758 retval = _ewarnvn (fmt, ap);
759 va_end (ap);
760
761 return (retval);
762 }
763 hidden_def(ewarnvn)
764
765 int einfov (const char *fmt, ...)
766 {
767 int retval;
768 va_list ap;
769
770 CHECK_VERBOSE;
771
772 if (! fmt)
773 return (0);
774
775 va_start (ap, fmt);
776 retval = _einfovn (fmt, ap);
777 retval += printf ("\n");
778 va_end (ap);
779
780 return (retval);
781 }
782 hidden_def(einfov)
783
784 int ewarnv (const char *fmt, ...)
785 {
786 int retval;
787 va_list ap;
788
789 CHECK_VERBOSE;
790
791 if (! fmt)
792 return (0);
793
794 va_start (ap, fmt);
795 retval = _ewarnvn (fmt, ap);
796 retval += printf ("\n");
797 va_end (ap);
798
799 return (retval);
800 }
801 hidden_def(ewarnv)
802
803 int ebeginv (const char *fmt, ...)
804 {
805 int retval;
806 va_list ap;
807
808 CHECK_VERBOSE;
809
810 if (! fmt)
811 return (0);
812
813 va_start (ap, fmt);
814 retval = _einfovn (fmt, ap);
815 retval += printf (" ...");
816 if (colour_terminal ())
817 retval += printf ("\n");
818 va_end (ap);
819
820 return (retval);
821 }
822 hidden_def(ebeginv)
823
824 int eendv (int retval, const char *fmt, ...)
825 {
826 va_list ap;
827
828 CHECK_VERBOSE;
829
830 va_start (ap, fmt);
831 _do_eend ("eendv", retval, fmt, ap);
832 va_end (ap);
833
834 return (retval);
835 }
836 hidden_def(eendv)
837
838 int ewendv (int retval, const char *fmt, ...)
839 {
840 va_list ap;
841
842 CHECK_VERBOSE;
843
844 va_start (ap, fmt);
845 _do_eend ("ewendv", retval, fmt, ap);
846 va_end (ap);
847
848 return (retval);
849 }
850 hidden_def(ewendv)
851
852 void eindentv (void)
853 {
854 if (is_env ("RC_VERBOSE", "yes"))
855 eindent ();
856 }
857 hidden_def(eindentv)
858
859 void eoutdentv (void)
860 {
861 if (is_env ("RC_VERBOSE", "yes"))
862 eoutdent ();
863 }
864 hidden_def(eoutdentv)

  ViewVC Help
Powered by ViewVC 1.1.20