
Wednesday October 13, 2004
Roses are red, and so should be warnings
I am always surprised that text-based user interfaces in computers have
not fully utilized the power of colour. Ever tried to scroll through
10,000 lines of history in an xterm trying to locate that particular
error message, or the command you typed ? So why don't shells emit user
input and program output in different colours ? Why don't programs emit
errors and warnings in colours that stand out amid a sea of text ? If
only K&R had provided a colour argument to printf...
Anyway, here's one sample implementation of a "warning printf". It
makes warnings stand out by printing them in red. It's pretty portable
and works on every unix terminal (that I use :-)
// include stdio and stdarg
void wfprintf(FILE *fp, char *format, ...)
{
int is_tty = isatty (fileno(fp));
va_list ap;
va_start(ap, format);
// ANSI escape for the colour
if (is_tty)
fprintf(fp, "%c[31m", 0x1B); // 31 is colour red
/* print out real message */
(void) vfprintf(fp, format, ap);
// reset terminal
if (is_tty)
fprintf (fp, "%c[m", 0x1B);
}
Unfortunately, though, I haven't discovered any way to check isatty() on the Java platform.
(2004-10-13 03:56:32.0)
Permalink
|
A more useful implementation of wprintf() would probably have to employ something like the theme-support modern text-based IRC clients support. This is important for two reasons:
a. The terminal might be incapable of supporting color output, or
b. The user might have explicitly set his TERM to avoid colour output.
Given a set of theme-dependent, in-band control sequences for coloring output strings, something like this would probably work like a charm:
#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static int tprintf(const char *_fmt, ...); static int use_color = 1; int main(void) { tprintf("hello color%s world\n", (use_color) ? "ful" : "-free"); return 0; } static int tprintf_aux_color(const char *_buf); static int tprintf_aux_mono(const char *_buf); int tprintf(const char *fmt, ...) { va_list ap, saved_ap; char *buf; size_t buflen; size_t maxlen; buflen = 512; if ((buf = malloc(buflen)) == NULL) { perror("malloc"); return (buflen); } /* * Try to save the data that printf would output to a string buffer. */ va_start(ap, fmt); while (1) { va_copy(saved_ap, ap); maxlen = vsnprintf(buf, buflen, fmt, ap); va_end(ap); if (maxlen <= buflen) { va_end(saved_ap); buflen = maxlen; break; } else { buflen = maxlen; if ((buf = realloc(buf, buflen)) == NULL) { va_end(saved_ap); goto err; } else { va_copy(ap, saved_ap); va_end(saved_ap); } } } if (use_color != 0) maxlen = tprintf_aux_color(buf); else maxlen = tprintf_aux_mono(buf); if (maxlen > buflen) buflen = maxlen; /* FALL THROUGH */ err: if (buf != NULL) free(buf); return buflen; } static int tprintf_aux_color(const char *buf) { /* * Add code here that substitutes color control sequences with ANSI * escape sequences and deletes/strips off monochrome control * sequences. */ printf("%s", buf); return strlen(buf); } static int tprintf_aux_mono(const char *buf) { /* * Add code here that substitutes monochrome output control sequences * with ANSI escape sequences and deletes/strips off color sequences. */ printf("%s", buf); return strlen(buf); }The implementation of tprintf_aux_xxx() functions is non-trivial and depends on the definition of "themable color control sequence", so I'll stop wasting blog space with my random C ramblings :-)
Does this sound any better than hard-coded color control codes? I think it does...
Posted by Giorgos Keramidas on October 13, 2004 at 09:52 AM PDT #