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