Logo Search packages:      
Sourcecode: fhist version File versions

pager.c

/*
 *    fhist - file history and comparison tools
 *    Copyright (C) 1992-1994, 1998-2000, 2002 Peter Miller;
 *    All rights reserved.
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 * MANIFEST: functions to pipe output through paginator
 */

#include <ac/stdio.h>
#include <ac/signal.h>
#include <ac/stdlib.h>
#include <ac/unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ac/libintl.h>

#include <error_intl.h>
#include <pager.h>


static      FILE  *out;
static      char  *pager;
static      int   pid;


/*
 * this stuff is to tell if we are in the background
 */

#ifdef SIGSTOP
#ifndef HAVE_TCGETPGRP

#include <sys/termio.h>

int
tcgetpgrp(int fd)
{
      int         result;

#ifdef TIOCGETPGRP
      if (ioctl(fd, TIOCGETPGRP, &result))
            result = -1;
#else
#ifdef TIOCGPGRP
        if (ioctl(fd, TIOCGPGRP, &result))
            result = -1;
#else
      result = -1;
#endif
#endif
      return result;
}

#endif /* !HAVE_TCGETPGRP */
#endif /* SIGSTOP */


/*
 *  NAME
 *      background - test for backgroundness
 *
 *  SYNOPSIS
 *      int background(void);
 *
 *  DESCRIPTION
 *      The background function is used to determin e if the curent process is
 *      in the background.
 *
 *  RETURNS
 *      int: zero if process is not in the background, nonzero if the process
 *      is in the background.
 *
 * CAVEAT:
 *    This function has a huge chance of being wrong for your system.
 *    If you need to modify this function, please let the author know.
 */

static int
background(void)
{
      RETSIGTYPE  (*x)(int);

      /*
       * C shell
       *    puts its children in a different process group.
       *    The process group the terminal in is the forground.
       *
       * Only available on systems with job control.
       */
#ifdef SIGSTOP
      if (getpgrp(CONF_getpgrp_arg) != tcgetpgrp(0))
            return 1;
#endif

      /*
       * Bourne shell
       *    sets its children to ignore SIGINT
       */
      x = signal(SIGINT, SIG_IGN);
      if (x == SIG_IGN)
            return 1;
      signal(SIGINT, x);

      /*
       * probably forground
       */
      return 0;
}


static FILE *
pipe_open(char *prog)
{
      FILE        *fp;
      int         fd[2];
      char        *cmd[4];
      sub_context_ty    *scp;

      fp = 0;
      if (pipe(fd))
      {
            scp = sub_context_new();
            sub_errno_set(scp);
            fatal_intl(scp, i18n("pipe(): $errno"));
            /* NOTREACHED */
            sub_context_delete(scp);
      }
      switch (pid = fork())
      {
      case 0:
            cmd[0] = "sh";
            cmd[1] = "-c";
            cmd[2] = prog;
            cmd[3] = 0;
            close(fd[1]);
            close(0);
            if (dup(fd[0]) != 0)
            {
                  fatal_intl(0, i18n("dup was wrong"));
            }
            close(fd[0]);
            execvp(cmd[0], cmd);
            scp = sub_context_new();
            sub_errno_set(scp);
            sub_var_set_charstar(scp, "File_Name", prog);
            fatal_intl(scp, i18n("exec \"$filename\": $errno"));
            /* NOTREACHED */
            sub_context_delete(scp);

      case -1:
            scp = sub_context_new();
            sub_errno_set(scp);
            error_intl(scp, i18n("fork(): $errno"));
            sub_context_delete(scp);
            fp = 0;
            break;

      default:
            close(fd[0]);
            fp = fdopen(fd[1], "w");
            if (!fp)
            {
                  scp = sub_context_new();
                  sub_errno_set(scp);
                  fatal_intl(scp, i18n("fdopen: $errno"));
                  /* NOTREACHED */
                  sub_context_delete(scp);
            }
            break;
      }
      return fp;
}


static void
pipe_close(FILE *fp)
{
      int         status;
      int         n;

      fclose(fp);
      for (;;)
      {
            n = wait(&status);
            if (n < 0 || n == pid)
                  break;
      }
      pid = 0;
}


#ifdef HAVE_ATEXIT

static void
cleanup(void)
{
      if (!out)
            return;

      /*
       * write the last of the output
       */
      fflush(out);

      /*
       * close the paginator
       */
      if (pager)
      {
            pipe_close(out);
            pager = 0;
      }
      out = 0;
}

#endif /* HAVE_ATEXIT */


FILE *
pager_open(void)
{
      /* assert(!out); */

      /*
       * if talking to a terminal,
       * send the output through a paginator
       */
      if (!background() && isatty(0) && isatty(1))
      {
            pager = getenv("PAGER");
            if (!pager || !*pager)
                  pager = "more";
      }
      else
            pager = 0;

#ifdef HAVE_ATEXIT
      /*
       * register the cleanup function in case of fatal errors
       */
      atexit(cleanup);
#endif

      /*
       * open the paginator
       */
      if (pager)
      {
            out = pipe_open(pager);
            if (!out)
            {
                  pager = 0;
                  out = stdout;
            }
      }
      else
            out = stdout;
      return out;
}


void
pager_close(FILE *fp)
{
      /* assert(out); */
      /* assert(fp == out); */

      /*
       * write the last of the output
       */
      fflush(out);
      if (ferror(out))
            pager_error(out);

      /*
       * close the paginator
       */
      if (pager)
      {
            pipe_close(out);
            pager = 0;
      }
      out = 0;
}


void
pager_error(FILE *fp)
{
      sub_context_ty    *scp;

      /* assert(out); */
      /* assert(fp == out); */

      scp = sub_context_new();
      sub_errno_set(scp);
      if (pager)
            sub_var_set_charstar(scp, "File_Name", pager);
      else
            sub_var_set_charstar(scp, "File_Name", gettext("standard input"));
      fatal_intl(scp, i18n("write \"$filename\": $errno"));
      /* NOTREACHED */
      sub_context_delete(scp);
}

Generated by  Doxygen 1.6.0   Back to index