//
// aegis - project change supervisor
// Copyright (C) 1992-1995, 1997, 1999, 2002-2008 Peter Miller
//
// 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 3 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, see
// .
//
#include
#include
#include
#include
#include
#include
#include // for umask prototype
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static quit_action_pager cleanup_action;
static int option_pager_flag = -1;
static output::pointer singleton;
void
option_pager_set(int n, void (*usage)(void))
{
if (option_pager_flag == 0 && n == 0)
duplicate_option_by_name(arglex_token_pager_not, usage);
if (option_pager_flag >= 1 && n != 0)
duplicate_option_by_name(arglex_token_pager, usage);
if (option_pager_flag >= 0)
{
mutually_exclusive_options
(
arglex_token_pager,
arglex_token_pager_not,
usage
);
}
option_pager_flag = (n != 0);
}
static int
option_pager_get(void)
{
if (option_pager_flag < 0)
{
user_ty::pointer up = user_ty::create();
option_pager_flag = up->pager_preference();
}
return option_pager_flag;
}
void
output_pager::pipe_open()
{
sub_context_ty *scp;
int uid;
int gid;
int um;
FILE *fp;
int fd[2];
const char *cmd[4];
int pid_;
int errno_old;
env_set_page();
fp = 0;
os_become_orig_query(&uid, &gid, &um);
if (pipe(fd))
nfatal("pipe()");
switch (pid_ = fork())
{
case 0:
undo_cancel();
while (os_become_active())
os_become_undo();
cmd[0] = "sh";
cmd[1] = "-c";
cmd[2] = pager.c_str();
cmd[3] = 0;
close(fd[1]);
close(0);
if (dup(fd[0]) != 0)
fatal_raw("dup was wrong");
close(fd[0]);
os_setgid(gid);
os_setuid(uid);
umask(um);
execvp(cmd[0], (char **)cmd);
errno_old = errno;
scp = sub_context_new();
sub_errno_setx(scp, errno_old);
sub_var_set_string(scp, "File_Name", pager);
fatal_intl(scp, i18n("exec \"$filename\": $errno"));
// NOTREACHED
case -1:
nfatal("fork()");
break;
default:
pid = pid_;
close(fd[0]);
fp = fdopen(fd[1], "w");
if (!fp)
nfatal("fdopen");
vdeeper = (void *)fp;
break;
}
}
void
output_pager::cleanup()
{
trace(("output_pager_cleanup()\n{\n"));
output::pointer temp;
temp.swap(singleton);
trace(("}\n"));
}
void
output_pager::pager_error()
{
int errno_old = errno;
sub_context_ty sc;
sc.errno_setx(errno_old);
sc.var_set_string("File_Name", pager);
sc.fatal_intl(i18n("write $filename: $errno"));
// NOTREACHED
}
output_pager::~output_pager()
{
trace(("output_pager::destructor(this = %08lX)\n{\n", (long)this));
assert(vdeeper);
//
// Make sure all buffered data has been passed to our write_inner
// method.
//
flush();
//
// write the last of the output
//
if (fflush((FILE *)vdeeper))
pager_error();
//
// close the paginator
//
fclose((FILE *)vdeeper);
vdeeper = 0;
int status = 0;
os_waitpid(pid, &status);
pid = 0;
trace(("}\n"));
}
output_pager::output_pager() :
vdeeper(0),
pid(0),
pager(user_ty::create()->pager_command()),
bol(true)
{
os_become_orig();
pipe_open();
os_become_undo();
assert(vdeeper);
}
nstring
output_pager::filename()
const
{
return pager;
}
long
output_pager::ftell_inner()
const
{
return -1;
}
void
output_pager::write_inner(const void *data, size_t len)
{
if (fwrite(data, 1, len, (FILE *)vdeeper) == 0)
pager_error();
if (len > 0)
bol = (((const char *)data)[len - 1] == '\n');
}
void
output_pager::flush_inner()
{
if (fflush((FILE *)vdeeper))
pager_error();
}
void
output_pager::end_of_line_inner()
{
if (!bol)
fputc('\n');
}
const char *
output_pager::type_name()
const
{
return "pager";
}
output::pointer
output_pager::open()
{
trace(("output_pager_open()\n{\n"));
if (singleton)
{
trace(("}\n"));
return singleton;
}
//
// If talking to a terminal,
// send the output through a paginator.
// If we're not, just use stdout.
//
if
(
!option_pager_get()
||
option_unformatted_get()
||
os_background()
||
!isatty(0)
||
!isatty(1)
)
{
output::pointer result = output_stdout::create();
singleton = result;
trace(("return %08lX;\n}\n", (long)result.get()));
return result;
}
//
// register the cleanup function in case of fatal errors
//
quit_register(cleanup_action);
//
// open the paginator
//
output::pointer result(new output_pager());
//
// We keep track of open paginators,
// so we can clean up after them if necessary.
//
singleton = result;
trace(("return %08lX;\n}\n", (long)result.get()));
return result;
}