#!/usr/bin/perl

####==========================================================================
# The program will start an xterm and run vim with the specified roff file.
# Then it will start gv. When the roff file is changed, it will run the groff
# command to generate the PS file and send HUP signal to gv to refresh the
# PS file immediately. 
#
# usage: ge.pl roff_file
#
# Note: the name of the PostScript file will be roff_file.ps. If gv exits, the
# script will exit as well.
#
# Modify the following variables:
#   $groff  - The groff command
#   $xterm  - The xterm command
#   $gv     - The gv command
#
# Functions:
#   run_prog($prog) - fork and exec an exernnal program
#   watch_roff_file_for_change($roff_file) - watches roff file if it is changed
#
# Inspired by the ge shell script posted in groff mailing list by
# Ted Harding) <Ted.Harding@nessie.mcc.ac.uk. 
#
#  muquit@lucent.com Mar-25-2003 
####==========================================================================

use strict;

my $me=$0;
$me =~ s(.*/)();

my $argc=$#ARGV+1;
if ($argc != 1)
{
    print STDERR "usage: $me <roff file>\n";
    exit;
}

##--------------------------globals----------------- start----
my $roff_file=$ARGV[0];
my $ps_file="${roff_file}.ps";

# modify the next 3 lines
my $groff="groff -Tps -tpe -mm $roff_file > $ps_file";
my $gv="gv -scale 2 -scalebase 1 -antialias -spartan $ps_file";
# mansi_xterm is available in my homepage: http://muquit.com/
# I just hate the scrollbar in xterm
my $xterm="/home/mmuquit/bin/mansi_xterm -ls -sl 2000 -fn -adobe-courier-medium-r-normal--14-140-75-75-m-90-iso8859-1 -geo 80x60 -name \"groff $roff_file\" -e vim $roff_file";

my %old=();
my $xterm_pid;
my $gv_pid;
##--------------------------globals----------------- ends----

# if the gv file doesn't exist, just create one with one line 
if (! -f $ps_file)
{
    local *FD;
    open(FD,">$ps_file") or die "Could not create ps file: $ps_file ($!)";
    print FD "%!PS-Adobe-3.0\n";
    close(FD);
}

# in most unices ignoring SIGCHLD should stop accumulating zombies
$SIG{CHLD}='IGNORE';

# store the modification time of the roff file
$old{$roff_file}=(stat($roff_file))[9];

# start xterm with document in vim
$xterm_pid=&run_prog("$xterm");
print "xterm pid: $xterm_pid\n";

# start gv with the PS file
$gv_pid=&run_prog("$gv");
print "gv pid: $gv_pid\n";


# now watch the roff file. If it changes, run groff and generate the PS file
# and send HUP signal to gv to refresh immediately
&watch_roff_file_for_change($roff_file);

###----
# watch_roff_file_for_change
# Watch the roff file. If the modification time is changed, generate the PS
# file by running groff and send a HUP signal to gv to refresh the PS file
# immediately.
# arg1: the roff file
# if gv exits, the routine will call exit
###----
sub watch_roff_file_for_change
{
    my $file=shift;
    my $new=(stat($file))[9];

    for (;;)
    {
        $new=(stat($file))[9];

        # check if gv is alive
        my $rc=kill(0,$gv_pid);
        if ($rc == 0)
        {
            print "gv exited\n";
            exit(0);
        }
        if ($old{$file} == $new)
        {
            # roff file didn't change
            sleep(1);
            next;
        }

        $old{$file}=$new;
        if ($old{$file} == $new)
        {
            # roff file has changed.
            print "Running $groff\n";
            system("$groff");
            # send HUP signal to gv
            print "sending HUP signal to gv pid $gv_pid\n";
            kill('HUP',$gv_pid);
        }
    }
}

##-----
# fork and exec a process. 
# arg1: the program to run
# returns the pid of the process on success. exits on failure 
##-----
sub run_prog
{
    my $prog=shift;
    my $pid;
    $pid=fork();
    if (! defined($pid))
    {
        die "Could not fork() ($!)";
    }

    if ($pid == 0)
    {
        # child
        exec($prog);
        die "could not exec: $prog ($!)";
    }

    return($pid);
}
