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

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20