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

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2904 - (show annotations) (download) (as text)
Fri Sep 21 08:49:43 2007 UTC (11 years ago) by uberlord
File MIME type: text/x-csrc
File size: 12368 byte(s)
    Use a pty for prefixed output instead of pipes for stdout/stderr. This
    is so that programs can get information about the controlling terminal.
    This change was triggered by bug #188506 where it's possible that
    stdin, stdout and stderr didn't point to a terminal but ended up on one
    via our pipes. Using a pty means that stdout and stderr always point to
    a terminal, but we lose the ability to tell them apart.
    If there is not a pty available then we use un-prefixed output as normal.
    This change has also introduced the need for a signal pipe so that
    SIGCHLD can exit the loop cleanly.
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 "\033[32;01m"
68 #define ECOLOR_WARN "\033[33;01m"
69 #define ECOLOR_BAD "\033[31;01m"
70 #define ECOLOR_HILITE "\033[36;01m"
71 #define ECOLOR_BRACKET "\033[34;01m"
72 #define ECOLOR_NORMAL "\033[0m"
73 #define ECOLOR_FLUSH "\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 (void)
141 {
142 static int in_colour = -1;
143 int i = 0;
144
145 if (is_env ("RC_NOCOLOR", "yes"))
146 return (false);
147
148 if (in_colour == 0)
149 return (false);
150 if (in_colour == 1)
151 return (true);
152
153 if (! term) {
154 term = getenv ("TERM");
155 if (! term)
156 return (false);
157 }
158
159 if (strcmp (term, "cons25") == 0)
160 term_is_cons25 = true;
161 else
162 term_is_cons25 = false;
163
164 while (color_terms[i]) {
165 if (strcmp (color_terms[i], term) == 0) {
166 in_colour = 1;
167 return (true);
168 }
169 i++;
170 }
171
172 in_colour = 0;
173 return (false);
174 }
175
176 static int get_term_columns (FILE *stream)
177 {
178 struct winsize ws;
179
180 if (ioctl (fileno (stream), TIOCGWINSZ, &ws) == 0)
181 return (ws.ws_col);
182
183 return (DEFAULT_COLS);
184 }
185
186 void eprefix (const char *prefix) {
187 _eprefix = prefix;
188 }
189
190 static void elogv (int level, const char *fmt, va_list ap)
191 {
192 char *e = getenv ("RC_ELOG");
193 va_list apc;
194
195 if (fmt && e) {
196 closelog ();
197 openlog (e, LOG_PID, LOG_DAEMON);
198 va_copy (apc, ap);
199 vsyslog (level, fmt, apc);
200 va_end (apc);
201 closelog ();
202 }
203 }
204
205 void elog (int level, const char *fmt, ...)
206 {
207 va_list ap;
208
209 va_start (ap, fmt);
210 elogv (level, fmt, ap);
211 va_end (ap);
212 }
213 hidden_def(elog)
214
215 static int _eindent (FILE *stream)
216 {
217 char *env = getenv ("RC_EINDENT");
218 int amount = 0;
219 char indent[INDENT_MAX];
220
221 if (env) {
222 errno = 0;
223 amount = strtol (env, NULL, 0);
224 if (errno != 0 || amount < 0)
225 amount = 0;
226 else if (amount > INDENT_MAX)
227 amount = INDENT_MAX;
228
229 if (amount > 0)
230 memset (indent, ' ', amount);
231 }
232
233 /* Terminate it */
234 memset (indent + amount, 0, 1);
235 return (fprintf (stream, "%s", indent));
236 }
237
238 const char *ecolor (einfo_color_t color) {
239 const char *col = NULL;
240
241 if (! colour_terminal ())
242 return ("");
243
244 switch (color) {
245 case ecolor_good:
246 if (! (col = getenv ("ECOLOR_GOOD")))
247 col = ECOLOR_GOOD;
248 break;
249 case ecolor_warn:
250 if (! (col = getenv ("ECOLOR_WARN")))
251 col = ECOLOR_WARN;
252 break;
253 case ecolor_bad:
254 if (! (col = getenv ("ECOLOR_BAD")))
255 col = ECOLOR_BAD;
256 break;
257 case ecolor_hilite:
258 if (! (col = getenv ("ECOLOR_HILITE")))
259 col = ECOLOR_HILITE;
260 break;
261 case ecolor_bracket:
262 if (! (col = getenv ("ECOLOR_BRACKET")))
263 col = ECOLOR_BRACKET;
264 break;
265 case ecolor_normal:
266 col = ECOLOR_NORMAL;
267 break;
268 }
269
270 return (col);
271 }
272 hidden_def(ecolor)
273
274 #define EINFOVN(_file, _color) \
275 if (_eprefix) \
276 fprintf (_file, "%s%s%s|", ecolor (_color), _eprefix, ecolor (ecolor_normal)); \
277 fprintf (_file, " %s*%s ", ecolor (_color), ecolor (ecolor_normal)); \
278 retval += _eindent (_file); \
279 { \
280 va_list _ap; \
281 va_copy (_ap, ap); \
282 retval += vfprintf (_file, fmt, _ap) + 3; \
283 va_end (_ap); \
284 } \
285 if (colour_terminal ()) \
286 fprintf (_file, ECOLOR_FLUSH);
287
288 static int _einfovn (const char *fmt, va_list ap)
289 {
290 int retval = 0;
291
292 EINFOVN (stdout, ecolor_good);
293 return (retval);
294 }
295
296 static int _ewarnvn (const char *fmt, va_list ap)
297 {
298 int retval = 0;
299
300 EINFOVN (stdout, ecolor_warn);
301 return (retval);
302 }
303
304 static int _eerrorvn (const char *fmt, va_list ap)
305 {
306 int retval = 0;
307
308 EINFOVN (stderr, ecolor_bad);
309 return (retval);
310 }
311
312 int einfon (const char *fmt, ...)
313 {
314 int retval;
315 va_list ap;
316
317 if (! fmt || is_env ("RC_QUIET", "yes"))
318 return (0);
319
320 va_start (ap, fmt);
321 retval = _einfovn (fmt, ap);
322 va_end (ap);
323
324 return (retval);
325 }
326 hidden_def(einfon)
327
328 int ewarnn (const char *fmt, ...)
329 {
330 int retval;
331 va_list ap;
332
333 if (! fmt || is_env ("RC_QUIET", "yes"))
334 return (0);
335
336 va_start (ap, fmt);
337 retval = _ewarnvn (fmt, ap);
338 va_end (ap);
339
340 return (retval);
341 }
342 hidden_def(ewarnn)
343
344 int eerrorn (const char *fmt, ...)
345 {
346 int retval;
347 va_list ap;
348
349 va_start (ap, fmt);
350 retval = _eerrorvn (fmt, ap);
351 va_end (ap);
352
353 return (retval);
354 }
355 hidden_def(eerrorn)
356
357 int einfo (const char *fmt, ...)
358 {
359 int retval;
360 va_list ap;
361
362 if (! fmt || is_env ("RC_QUIET", "yes"))
363 return (0);
364
365 va_start (ap, fmt);
366 retval = _einfovn (fmt, ap);
367 retval += printf ("\n");
368 va_end (ap);
369
370 return (retval);
371 }
372 hidden_def(einfo)
373
374 int ewarn (const char *fmt, ...)
375 {
376 int retval;
377 va_list ap;
378
379 if (! fmt || is_env ("RC_QUIET", "yes"))
380 return (0);
381
382 va_start (ap, fmt);
383 elogv (LOG_WARNING, fmt, ap);
384 retval = _ewarnvn (fmt, ap);
385 retval += printf ("\n");
386 va_end (ap);
387
388 return (retval);
389 }
390 hidden_def(ewarn)
391
392 void ewarnx (const char *fmt, ...)
393 {
394 int retval;
395 va_list ap;
396
397 if (fmt && ! is_env ("RC_QUIET", "yes")) {
398 va_start (ap, fmt);
399 elogv (LOG_WARNING, fmt, ap);
400 retval = _ewarnvn (fmt, ap);
401 va_end (ap);
402 retval += printf ("\n");
403 }
404 exit (EXIT_FAILURE);
405 }
406 hidden_def(ewarnx)
407
408 int eerror (const char *fmt, ...)
409 {
410 int retval;
411 va_list ap;
412
413 if (! fmt)
414 return (0);
415
416 va_start (ap, fmt);
417 elogv (LOG_ERR, fmt, ap);
418 retval = _eerrorvn (fmt, ap);
419 va_end (ap);
420 retval += fprintf (stderr, "\n");
421
422 return (retval);
423 }
424 hidden_def(eerror)
425
426 void eerrorx (const char *fmt, ...)
427 {
428 va_list ap;
429
430 if (fmt) {
431 va_start (ap, fmt);
432 elogv (LOG_ERR, fmt, ap);
433 _eerrorvn (fmt, ap);
434 va_end (ap);
435 fprintf (stderr, "\n");
436 }
437
438 exit (EXIT_FAILURE);
439 }
440 hidden_def(eerrorx)
441
442 int ebegin (const char *fmt, ...)
443 {
444 int retval;
445 va_list ap;
446
447 if (! fmt || is_env ("RC_QUIET", "yes"))
448 return (0);
449
450 va_start (ap, fmt);
451 retval = _einfovn (fmt, ap);
452 va_end (ap);
453 retval += printf (" ...");
454 if (colour_terminal ())
455 retval += printf ("\n");
456
457 return (retval);
458 }
459 hidden_def(ebegin)
460
461 static void _eend (FILE *fp, int col, einfo_color_t color, const char *msg)
462 {
463 int i;
464 int cols;
465
466 if (! msg)
467 return;
468
469 cols = get_term_columns (fp) - (strlen (msg) + 5);
470
471 /* cons25 is special - we need to remove one char, otherwise things
472 * do not align properly at all. */
473 if (! term) {
474 term = getenv ("TERM");
475 if (term && strcmp (term, "cons25") == 0)
476 term_is_cons25 = true;
477 else
478 term_is_cons25 = false;
479 }
480 if (term_is_cons25)
481 cols--;
482
483 if (cols > 0 && colour_terminal ()) {
484 fprintf (fp, "\033[A\033[%dC %s[ %s%s %s]%s\n", cols,
485 ecolor (ecolor_bracket), ecolor (color), msg,
486 ecolor (ecolor_bracket), ecolor (ecolor_normal));
487 } else {
488 if (col > 0)
489 for (i = 0; i < cols - col; i++)
490 fprintf (fp, " ");
491 fprintf (fp, " [ %s ]\n", msg);
492 }
493 }
494
495 static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
496 {
497 int col = 0;
498 FILE *fp = stdout;
499 va_list apc;
500
501 if (fmt && retval != 0) {
502 va_copy (apc, ap);
503 if (strcmp (cmd, "ewend") == 0) {
504 col = _ewarnvn (fmt, apc);
505 fp = stdout;
506 } else {
507 col = _eerrorvn (fmt, apc);
508 fp = stderr;
509 }
510 col += fprintf (fp, "\n");
511 va_end (apc);
512 }
513
514 _eend (fp, col,
515 retval == 0 ? ecolor_good : ecolor_bad,
516 retval == 0 ? OK : NOT_OK);
517 return (retval);
518 }
519
520 int eend (int retval, const char *fmt, ...)
521 {
522 va_list ap;
523
524 if (is_env ("RC_QUIET", "yes"))
525 return (retval);
526
527 va_start (ap, fmt);
528 _do_eend ("eend", retval, fmt, ap);
529 va_end (ap);
530
531 return (retval);
532 }
533 hidden_def(eend)
534
535 int ewend (int retval, const char *fmt, ...)
536 {
537 va_list ap;
538
539 if (is_env ("RC_QUIET", "yes"))
540 return (retval);
541
542 va_start (ap, fmt);
543 _do_eend ("ewend", retval, fmt, ap);
544 va_end (ap);
545
546 return (retval);
547 }
548 hidden_def(ewend)
549
550 void ebracket (int col, einfo_color_t color, const char *msg)
551 {
552 _eend (stdout, col, color, msg);
553 }
554 hidden_def(ebracket)
555
556 void eindent (void)
557 {
558 char *env = getenv ("RC_EINDENT");
559 int amount = 0;
560 char num[10];
561
562 if (env) {
563 errno = 0;
564 amount = strtol (env, NULL, 0);
565 if (errno != 0)
566 amount = 0;
567 }
568
569 amount += INDENT_WIDTH;
570 if (amount > INDENT_MAX)
571 amount = INDENT_MAX;
572
573 snprintf (num, 10, "%08d", amount);
574 setenv ("RC_EINDENT", num, 1);
575 }
576 hidden_def(eindent)
577
578 void eoutdent (void)
579 {
580 char *env = getenv ("RC_EINDENT");
581 int amount = 0;
582 char num[10];
583
584 if (! env)
585 return;
586
587 errno = 0;
588 amount = strtol (env, NULL, 0);
589 if (errno != 0)
590 amount = 0;
591 else
592 amount -= INDENT_WIDTH;
593
594 if (amount <= 0)
595 unsetenv ("RC_EINDENT");
596 else {
597 snprintf (num, 10, "%08d", amount);
598 setenv ("RC_EINDENT", num, 1);
599 }
600 }
601 hidden_def(eoutdent)
602
603 int einfovn (const char *fmt, ...)
604 {
605 int retval;
606 va_list ap;
607
608 CHECK_VERBOSE;
609
610 if (! fmt)
611 return (0);
612
613 va_start (ap, fmt);
614 retval = _einfovn (fmt, ap);
615 va_end (ap);
616
617 return (retval);
618 }
619 hidden_def(einfovn)
620
621 int ewarnvn (const char *fmt, ...)
622 {
623 int retval;
624 va_list ap;
625
626 CHECK_VERBOSE;
627
628 if (! fmt)
629 return (0);
630
631 va_start (ap, fmt);
632 retval = _ewarnvn (fmt, ap);
633 va_end (ap);
634
635 return (retval);
636 }
637 hidden_def(ewarnvn)
638
639 int einfov (const char *fmt, ...)
640 {
641 int retval;
642 va_list ap;
643
644 CHECK_VERBOSE;
645
646 if (! fmt)
647 return (0);
648
649 va_start (ap, fmt);
650 retval = _einfovn (fmt, ap);
651 retval += printf ("\n");
652 va_end (ap);
653
654 return (retval);
655 }
656 hidden_def(einfov)
657
658 int ewarnv (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 = _ewarnvn (fmt, ap);
670 retval += printf ("\n");
671 va_end (ap);
672
673 return (retval);
674 }
675 hidden_def(ewarnv)
676
677 int ebeginv (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 = _einfovn (fmt, ap);
689 retval += printf (" ...");
690 if (colour_terminal ())
691 retval += printf ("\n");
692 va_end (ap);
693
694 return (retval);
695 }
696 hidden_def(ebeginv)
697
698 int eendv (int retval, const char *fmt, ...)
699 {
700 va_list ap;
701
702 CHECK_VERBOSE;
703
704 va_start (ap, fmt);
705 _do_eend ("eendv", retval, fmt, ap);
706 va_end (ap);
707
708 return (retval);
709 }
710 hidden_def(eendv)
711
712 int ewendv (int retval, const char *fmt, ...)
713 {
714 va_list ap;
715
716 CHECK_VERBOSE;
717
718 va_start (ap, fmt);
719 _do_eend ("ewendv", retval, fmt, ap);
720 va_end (ap);
721
722 return (retval);
723 }
724 hidden_def(ewendv)
725
726 void eindentv (void)
727 {
728 if (is_env ("RC_VERBOSE", "yes"))
729 eindent ();
730 }
731 hidden_def(eindentv)
732
733 void eoutdentv (void)
734 {
735 if (is_env ("RC_VERBOSE", "yes"))
736 eoutdent ();
737 }
738 hidden_def(eoutdentv)

  ViewVC Help
Powered by ViewVC 1.1.20