#!/usr/bin/perl -w
use strict;
require 5.002;

# ************************************************************ #
# NAME: psmulti
# PURPOSE: Script for combining multiple postscript images
#    in an n-up fashion.
#
# NOTES: 
# SCCS: @(#)psmulti.pl	2.6 5/26/92
# HISTORY:
#       murray - Feb 19, 1992: Created.
#       murray - Mar 23, 1992: Tidied up the overall structure
#           of the program.
# ************************************************************ #

#
# port to perl5 by Denis N. Antonioli <antonio@ifi.unizh.ch>
#  1.0    27 Apr 1997
#  1.0.1  12 Aug 1997  -help thanks to przemek klosowski <przemek@nist.gov>
#  1.1    19 Feb 1998  reordered the check for option: -r was hiding -reverse!
#  1.1.1  28 May 1998  warning also gives $! and $@ if possible.
#

# ##################################################################### #
# (C) 1992 D Murray Laing, D.M.Laing@uk.ac.edinburgh
#          c/o Department of Chemical Engineering,
#              University of Edinburgh,
#              Edinburgh,
#              Scotland
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License version 2 as
#    published by the Free Software Foundation.
# 
#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
# ###################################################################### #

# ============================================================ #
# Set Up PSMulti Search Paths
# ============================================================ #

my @DefaultPSMultiLibPath = ( '/usr/share/psmulti' );

if ( defined $ENV{'PSMULTILIBPATH'} ) {
	unshift(@INC, split(/:/, $ENV{'PSMULTILIBPATH'}));
    @::PSPPIncludePath = split(/:/, $ENV{'PSMULTILIBPATH'});
} else {
	unshift(@INC, @DefaultPSMultiLibPath);
    @::PSPPIncludePath = @DefaultPSMultiLibPath;
}

%::StandardBBox=( 'page', '/Default',
				 'a5',     '20 20 401 574'   ,
				 'a4',     '20 20 574 822'   ,
				 'a3',     '20 20 822 1168'  ,
				 'a2',     '20 20 1168 1664' ,
				 'letter', '18 3 594 789'  ,
				 'note',   '29 30 583 761' ,
				 'legal',  '64 36 548 972'
				 );
# ============================================================ #
#             Variables
# ============================================================ #
my($verbose, $StdinTmpFile, $OutFile);

# ============================================================ #
#             Error Handling Routine
# ============================================================ #

my $ProgName = $0;
$ProgName = $1 if ( $0 =~ m|.*/([^/]*)|o );

sub error {
  die "$ProgName: @_\n";
}

sub warning {
  print STDERR "$ProgName: @_\n";
  print STDERR "+ $ProgName: $@\n" if $@ ne '';
  print STDERR "+ $ProgName: $!\n" if $! ne '';
}

sub info {
  print STDERR "$ProgName: @_\n" if defined $verbose;
}


# ============================================================ #
#                    Argument Processing
# ============================================================ #
  

# Global Multi Options #
my $File = 'Default';

while( $#ARGV >= 0 ) {
    $_ = splice(@ARGV, 0, 1);

    # Help #
    if ( /^-help/o )  {
        print <<HELP;
Usage: psmulti -v -o <file> -style -border -format -[no]decor pages -geom
               -{r,c}major -ttob -btot -ltor -rtol -pbbox -m<margin> -s<scaling>
               -max{pect,xy,x,y} -j -center{x,y} -left -right -top -bottom
               -[n]eps -ibbox -l -pr<deg> -[no]reverse
               -select{ordinal,label}
HELP
        exit 1;
    }

    # Debugging #
    if ( /^-v/o )  { $verbose = 1; }

    # Output File #
    elsif ( /^-o/o ) { $OutFile = splice(@ARGV, 0, 1); }

    # ---------------------------------------- #
    #        Global Multi Options
    # ---------------------------------------- #

    elsif ( /^-style$/o || /^-border$/o )
      { $::Global{'Style'} = splice(@ARGV, 0, 1); }
    
    elsif ( /^-format$/o )   { $::Global{'Format'} = splice(@ARGV, 0, 1); }

    elsif ( /^-nodecor/o ) { $::FileSettings{$File}{'NoDecor'} = 'true'; }
    elsif ( /^-decor/o )   { $::FileSettings{$File}{'NoDecor'} = 'false'; }


    elsif ( /^-pages/o ) {
		if ( $ARGV[0] =~ /^\d+$/o ) {
			$::Global{'Pages'} = splice(@ARGV, 0, 1);
		} else {
			&error('Incorrect Pages Specification');
		}
	}

    elsif ( /^-geom/o ) {
		if ( $ARGV[0] =~ /^(\d+)x(\d+)$/o ) {
			$::Global{'Columns'} = $1; $::Global{'Rows'} = $2;
		} else {
			&error('Incorrect Geometry Specification');
		}
        shift @ARGV;
	}

    elsif ( /^-rmajor/o ) { $::Global{'RowMajor'} = 'true'; }
    elsif ( /^-cmajor/o ) { $::Global{'RowMajor'} = 'false'; }
    elsif ( /^-ttob/o )   { $::Global{'TtoB'}     = 'true'; }
    elsif ( /^-btot/o )   { $::Global{'TtoB'}     = 'false'; }
    elsif ( /^-ltor/o )   { $::Global{'LtoR'}     = 'true'; }
    elsif ( /^-rtol/o )   { $::Global{'LtoR'}     = 'false'; }
  
    elsif ( /^-pbbox/o ) {
        if ( defined $::StandardBBox{$ARGV[0]} ) {
			$::Global{'FPageBBox'} = $::StandardBBox{$ARGV[0]};
            shift @ARGV;
		} elsif ( $ARGV[0] =~ /^-?\d+$/o && $ARGV[1] =~ /^-?\d+$/o &&
				 $ARGV[2] =~ /^-?\d+$/o && $ARGV[3] =~ /^-?\d+$/o
				 ) {
			$::Global{'PageBBox'} = join(' ', splice(@ARGV, 0, 4));
		} else {
			&error('Incorrect Page BBox Specification');
		}
	}

    # ---------------------------------------- #
    #       Document Specific Options
    # ---------------------------------------- #

    # Scaling #
    elsif ( /^-s(-?[\d\.]+)$/o ) {
		$::FileSettings{$File}{'ScaleX'} = $1;
		$::FileSettings{$File}{'ScaleY'} = $1;
	} elsif ( /^-s$/o ) {
		($::FileSettings{$File}{'ScaleX'}, $::FileSettings{$File}{'ScaleY'}) = splice(@ARGV, 0, 2);
	}

    elsif ( /^-maxpect/o )  { $::FileSettings{$File}{'ScaleX'}='/Ratio';
							  $::FileSettings{$File}{'ScaleY'}='/Ratio';
                           }
    elsif ( /^-maxxy/o )    { $::FileSettings{$File}{'ScaleX'}='/Max';
							  $::FileSettings{$File}{'ScaleY'}='/Max';
                           }
    elsif ( /^-maxx$/o )    { $::FileSettings{$File}{'ScaleX'}='/Max'; }
    elsif ( /^-maxy$/o )    { $::FileSettings{$File}{'ScaleY'}='/Max'; }

    # Margin #
    elsif ( /^-m(-?[\d\.]+)/o ) {
		$::FileSettings{$File}{'MarginX'} = $1; $::FileSettings{$File}{'MarginY'} = $1;
	} elsif ( /^-m$/o ) {
		if ( $ARGV[0] =~ /^-?[\d\.]+$/o && $ARGV[1] =~ /^-?[\d\.]+$/o ) {
			($::FileSettings{$File}{'MarginX'}, $::FileSettings{$File}{'MarginY'}) = splice(@ARGV, 0, 2);
		} else {
			&error('Incorrect Margin Specification');
		}
	}

    # Arguments Related to Page Selection and Ordering #
    elsif ( /^-reverse/o ) {
		$::FileSettings{$File}{'ReversePages'} = 1;
	} elsif ( /^-noreverse/o ) {
		$::FileSettings{$File}{'ReversePages'} = 0;
	} elsif (/^-select/o ) {
		$_=splice(@ARGV, 0, 1);
        if ( /^ordinal/o ) {
			$::FileSettings{$File}{'SelectBy'} = 'PageOrdinal'; 
            $::FileSettings{$File}{'SelectPages'} = splice(@ARGV, 0, 1);
		} elsif (  /^label/o ) {
			$::FileSettings{$File}{'SelectBy'}='PageLabel';
            $::FileSettings{$File}{'SelectPages'}=splice(@ARGV,0,1);
		} else {
			$::FileSettings{$File}{'SelectBy'}='PageOrdinal';
            $::FileSettings{$File}{'SelectPages'}=$_;
		}
	}

    # Justification #
    elsif( /^-j/o ) {
		($::FileSettings{$File}{'JustX'}, $::FileSettings{$File}{'JustY'}) = splice(@ARGV, 0, 2);
	}

    elsif( /^-centerx/o )  { $::FileSettings{$File}{'JustX'}='/Center'; }
    elsif( /^-centery/o )  { $::FileSettings{$File}{'JustY'}='/Center'; }
    elsif( /^-left/o )     { $::FileSettings{$File}{'JustX'}='/Left'; }
    elsif( /^-right/o )    { $::FileSettings{$File}{'JustX'}='/Right'; }
    elsif( /^-top/o )      { $::FileSettings{$File}{'JustX'}='/Top'; }
    elsif( /^-bottom/o )   { $::FileSettings{$File}{'JustX'}='/Bottom'; }

    
    elsif ( /^-maxxy/o )   { $::FileSettings{$File}{'MaxXY'} = 'true'; }
    elsif ( /^-maxpect/o ) { $::FileSettings{$File}{'MaxXY'} = 'false'; }

    elsif ( /^-eps/o )     { $::FileSettings{$File}{'EPSDoc'} = 'true'; }
    elsif ( /^-neps/o )    { $::FileSettings{$File}{'EPSDoc'} = 'false'; }
    
    elsif ( /^-ibbox/o ) {
		if ( defined $::StandardBBox{$ARGV[0]} ) {
			$::FileSettings{$File}{'ImageBBox'} = $::StandardBBox{$ARGV[0]};
            shift @ARGV;
		} elsif ( $ARGV[0] eq 'dsc' ) {
			$::FileSettings{$File}{'ImageBBox'} = 'dsc';
            shift @ARGV;
		} elsif ( $ARGV[0] =~ /^-?\d+$/o && $ARGV[1] =~ /^-?\d+$/o &&
				 $ARGV[2] =~ /^-?\d+$/o && $ARGV[3] =~ /^-?\d+$/o
				 ) {
			$::FileSettings{$File}{'ImageBBox'}=join(' ',splice(@ARGV,0,4));
		} else {
			&error('Incorrect Image BBox Specification' );
		}
	}
    
    elsif ( /^-l$/o ) {
        $::FileSettings{$File}{'Rotate'}= -90 unless defined $::FileSettings{$File}{'Rotate'};
        $::Global{'LtoR'}     = 'false' unless defined $::Global{'LtoR'};
        $::Global{'RowMajor'} = 'false' unless defined $::Global{'RowMajor'};
	}
    
    elsif ( /^-p$/o ) {
        $::FileSettings{$File}{'Rotate'} = 0 unless defined $::FileSettings{$File}{'Rotate'};
        $::Global{'LtoR'}     = 'true' unless defined $::Global{'LtoR'};
        $::Global{'RowMajor'} = 'true' unless defined $::Global{'RowMajor'};
	}

    elsif ( /^-r(-?[\d\.]+)/o ) { $::FileSettings{$File}{'Rotate'} = $1; }
    elsif ( /^-r/o ) {
		if ( $ARGV[0] =~ /^-?[\d\.]+$/o ) {
			$::FileSettings{$File}{'Rotate'} = $ARGV[0];
		} else {
			&error('Incorrect Rotation Specification');
		}
	}

    # Deal with a file #
    elsif ( /^-$/o ) {
		if ( defined $StdinTmpFile ) {
			$File = $StdinTmpFile;
		} else {
			require "file-util.pl";
            if ( ($File = &stdin_to_tmp("/tmp/$ProgName")) ) {
				$StdinTmpFile = $File;
			} else {
				&error($@);
			}
		}
        push(@::FileList, $File);
	}

    elsif ( -f ) {
		if ( -r ) {
			$File = $_;
            push(@::FileList, $File);
		} else {
			&error("Cannot read file $File");
		}
	}
    
    # Unknown Argument #
    else {
		&error("Unknown file/argument: $_");
	}
}

if( $#::FileList < 0 ) {
	require "file-util.pl";
    if ( ($StdinTmpFile = &stdin_to_tmp("/tmp/$ProgName")) ) {
		push(@::FileList, $StdinTmpFile);
	} else {
		&error($@);
	}
}

if ( defined $OutFile ) {
	open(OUTPUT,">$OutFile") || &error("Could not open $OutFile for writing");
    select OUTPUT;
} else {
	*OUTPUT = *STDOUT;
}

$::Global{'Format'}='standard' unless defined $::Global{'Format'};

eval "require \"format-$::Global{'Format'}.pl\"" || &error($@);

# ============================================================ #
#                  Clean Up
# ============================================================ #

close(OUTPUT);

# Clean Up Any Temporary Files #

unlink $StdinTmpFile if ( defined $StdinTmpFile && -f $StdinTmpFile );

1;
