public
Last active

ZSH STDERR Colorizing

  • Download Gist
colorize.c
C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/* $Id: colorize.c 3816 2004-07-03 17:01:32Z lefevre $
*
* Colorize the standard input. Written for zsh stderr coloring.
* This was taken from a mail archive on the subject of colorizing
* the stderr stream in zsh. It was written by Vincent Lefèvre as far
* as I know. It is here so it can be used in a brew formula.
*
* The intended usage is to place a line like the following in your zshrc
* exec 2>>(colorize `tput bold; tput setaf 1` `tput sgr0` > /dev/tty &)
*
* I use the colors associative array generated by zsh to make friendly color names, e.g.
* exec 2>>(colorize $fg[yellow] $reset_color > /dev/tty &)
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/types.h>
 
#define BUFFSIZE 512
 
static volatile sig_atomic_t usr1;
 
static void sigusr1(int sig)
{
usr1 = 1;
}
 
static void writepid(char *tmpfile)
{
FILE *f;
 
f = fopen(tmpfile, "w");
if (f == NULL)
{
perror("colorize (fopen)");
exit(EXIT_FAILURE);
}
fprintf(f, "%ld\n", (long) getpid());
if (fclose(f) != 0)
{
perror("colorize (fclose)");
exit(EXIT_FAILURE);
}
}
 
int main(int argc, char **argv)
{
pid_t zshpid = 0;
char *begstr, *endstr;
fd_set rfds;
int ret;
 
if (argc != 3 && argc != 5)
{
fprintf(stderr,
"Usage: colorize <begstr> <endstr> [ <zshpid> <tmpfile> ]\n");
exit(EXIT_FAILURE);
}
 
/* Assume that the arguments are correct. Anyway, it is not possible
to check them entirely. */
begstr = argv[1];
endstr = argv[2];
if (argc == 5)
{
/* To do the synchronization with the zsh prompt output...
Seems to be useless in practice, hence the argc == 3 case. */
zshpid = atol(argv[3]);
signal(SIGUSR1, sigusr1);
writepid(argv[4]);
}
 
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
 
/* To watch stdin (fd 0). */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
 
for (;;)
{
ret = select(1, &rfds, NULL, NULL, NULL);
 
if (ret < 0 && errno != EINTR)
{
perror("colorize (pselect)");
exit(EXIT_FAILURE);
}
 
if (ret > 0)
{
static unsigned char buffer[BUFFSIZE];
static int dontcol = 0;
ssize_t n;
 
while ((n = read(0, buffer, BUFFSIZE)) >= 0)
{
ssize_t i;
 
if (n == 0)
return 0; /* stdin has been closed */
for (i = 0; i < n; i++)
{
if (buffer[i] == 27)
dontcol = 1;
if (buffer[i] == '\n')
dontcol = 0;
if (!dontcol)
fputs(begstr, stdout);
putchar(buffer[i]);
if (!dontcol)
fputs(endstr, stdout);
}
}
fflush(stdout);
}
 
if (usr1)
{
usr1 = 0;
if (kill(zshpid, SIGUSR1) != 0)
{
perror("colorize (kill)");
exit(EXIT_FAILURE);
}
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.