Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: coloring stderr - was Re: piping stderr



On 2009-05-16 12:25:50 +1200, Atom Smasher wrote:
> this has me thinking about an old problem... coloring stderr. the two 
> problems i've found previously are (1) keeping stdout and stderr in sync, 
> and (2) stderr that doesn't end with a newline, such as messages from "rm 
> -i".
> 
> this [below] fixes the second problem,

I also solved the second problem a few years ago (see my solution in C,
attached). But I've checked again... the first problem is not solved by
my solution:

$ echo L1; echo L2 >&2; echo L3; echo L4 >&2
L1
L3
L2
L4

Also I disabled stderr coloring because some programs do not use stderr
consistently and I had various problems with them (perhaps because of
lack of synchronization).

> but it's still got some unintended consequences... the problem i'm
> having now with it is that if i start bash as a child of zsh, bash
> is a bit messed up.

I can notice that the bash prompt doesn't appear, because bash has
not been started in interactive mode ('i' is not in "$-"). If I force
interactive mode, I get:

prunille:~> bash -i
zsh: suspended (tty input)  bash -i

-- 
Vincent Lefèvre <vincent@xxxxxxxxxx> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)
/* $Id: colorize.c 29330 2009-05-18 00:27:09Z vinc17/prunille $
 *
 * Colorize the standard input. Written for zsh stderr coloring.
 *
 * Bug: stdout and stderr are not synchronized. For instance,
 *   $ echo L1; echo L2 >&2; echo L3; echo L4 >&2
 *   L1
 *   L3
 *   L2
 *   L4
 */

#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);
            }
        }
    }
}


Messages sorted by: Reverse Date, Date, Thread, Author