/*
* fhist - file history and comparison tools
* Copyright (C) 1992-1994, 1998-2000, 2002, 2004 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 <ac/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);
}
syntax highlighted by Code2HTML, v. 0.9.1