#!/usr/local/bin/perl -w

# check2tex.pl. Converts a VSOP Survey reduction checklist to LaTeX format
#
# Version 0.30, Jim Lovell  16-Apr-1999
# Version 0.40, Jim Lovell  27-Apr-1999
#               - Fixed a bug that caused an infinite loop
#               - "~" and "_" now interpreted correctly.
# Version 0.4.1, Jim Lovell 27-May-1999
#               - wasn't reporting a "modelfit" or "image made" correctly.
# Version 0.4.2, Jim Lovell 16-Jun-1999
#               - Fixed bug found by Bill Scott
# Version 0.5.0, Jim Lovell 12-Oct-1999
#               - now reads v0.4 of checklist.txt and does some error checking
#

my $progname = "check2tex.pl";
my $progver = "0.5.0";
#my ($day, $time, $tsys, $dummy);
#my @subs;

print "$progname version $progver\n\n";

my $nargs = @ARGV;

if ($nargs < 2){
    print "\nUsage: $progname [input file] [output file]\n";
    die;
}

my $infile = $ARGV[0];
my $outfile = $ARGV[1];

@line = ();
#my ($version, $i, $n);
#my ($exp, $fname, $gname, $dprep, $src, $cal, $oby, $obd, $grts,
#    $ts, $corel, $aipsv, $dmv, $vd, $abs, $pil, $dqa1, $pl5, $lcurv,
#    $indx, $ant, 
#    $uvf, $pacom, $pan,
#    $lis, $dt0, $dt1, $uv1, $uv2, $uv3, $vpl, $acc1, $acc2,
#    $apc1, $apc2, $nfr, $scp1, $scp2, $scd1, $scd2, $scr1,
#    $scr2, $scs1, $scs2, $vplap1, $vplap2, $pos1, $pos2, $tas, $fit, 
#    @file, @desc, @task,
#    @adverb, @incl, @insn, @outsn, @outcl, @comment,
#    $psc, $gscal, $asc, $mf, $image, $dmcom);


open(INLOG,"$infile") || die "cannot open $infile: $!\n";
open(OUT,">$outfile") || die "cannot open $outfile: $!\n";

$nlines = 0;
# first read in the entire file
while(<INLOG>) {
  $line[$nlines] = $_;
  $nlines++;
}
close INLOG;

$n = 0;
# read the version number. Should be inside the last 10 lines.
for ($i = $nlines - 10; $i < $nlines; $i++) {
  if ($line[$i] =~ /version/i) {
    $version = (split /\s+/, $line[$i])[7];
    print "version found : $version\n";
  }
}

if ($version <= 0.3) {
  process_v0p3();
} elsif ($version == 0.4) {
  process_v0p4();
} else {
  print "The version number of this checklist is unknown, and can't be processed.\n";
}

sub process_v0p3 {
  # strip comments out
  strip_comments();
  $n = $#line;
  # get the entries
  $i = 0;
  print "\nChecking input ...\n";
  # section 1
  print "\nSection 1\n---------\n";
  get_general_info_v0p3();
  # section 2
  print "\nSection 2\n---------\n";
  get_pre_aips_v0p3();
  # section 3
  print "\nSection 3\n---------\n";
  get_aips_out_v0p3();
  # section 4
  print "\nSection 4\n---------\n";
  get_supp_files_v0p3();
  # section 5
  print "\nSection 5\n---------\n";
  get_aips_notes_v0p3();
  # section 6
  print "\nSection 6\n---------\n";
  get_difmap_notes_v0p3();
  # write Latex header stuff
  print "\nWriting LaTeX file....\n";
  write_latex_header_v0p3();
  # latex table with experiment description and abstract
  write_latex_desc_abs_v0p3();
  # pre-aips checklist
  write_latex_pre_aips_v0p3();
  # aips output files
  write_latex_aips_output_v0p3();
  # aips reduction notes
  write_latex_aips_notes_v0p3();
  # difmap reduction notes
  write_latex_difmap_notes_v0p3();
  print "Program appears to have ended successfully\n";
}

sub process_v0p4 {
  # strip comments out
  strip_comments();
  $n = $#line;
  # get the entries
  $i = 0;
  print "Checking input\n";
  # section 1
  print "\nSection 1\n---------\n";
  get_general_info_v0p3();
  # section 2
  print "\nSection 2\n---------\n";
  get_pre_aips_v0p3();
  # section 3
  print "\nSection 3\n---------\n";
  get_aips_out_v0p3();
  # section 4
  print "\nSection 4\n---------\n";
  get_supp_files_v0p3();
  # section 5
  print "\nSection 5\n---------\n";
  get_aips_notes_v0p3();
  # section 6
  print "\nSection 6\n---------\n";
  get_amp_corrections_v0p4();
  # section 7
  print "\nSection 7\n---------\n";
  get_difmap_notes_v0p3();
  get_gscal_corrections_v0p4();
  # write Latex header stuff
  print "\nWriting LaTeX file....\n";
  write_latex_header_v0p3();
  # latex table with experiment description and abstract
  write_latex_desc_abs_v0p3();
  # pre-aips checklist
  write_latex_pre_aips_v0p3();
  # aips output files
  write_latex_aips_output_v0p3();
  # aips reduction notes
  write_latex_aips_notes_v0p3();
  write_latex_aips_ampcal_v0p4();
  # difmap reduction notes
  write_latex_difmap_notes_v0p4();
  print "Program appears to have ended successfully\n";
}

#-------------------------------------------------------------------------
sub yesno {
  #interprets "Y*" to 1 and "N*" to 0
  my ($answ) = @_;
  $answ = uc2lc($answ);
  if ($answ =~ /^y/) {
    return (1);
  } else {
    return (0);
  }
}

#-------------------------------------------------------------------------
sub yn {
  my ($answ) = @_;

  if ($answ > 0) {
    return ("\\yes");
  } else {
    return ("\\no");
  }
}

#-------------------------------------------------------------------------
sub strip_comments {
  # removes all comment lines
  my $n = $#line;
  my (@out, $j);
  my $k = 0;

  for ($j = 0; $j <= $n; $j++) {
    # remove leading and trailing spaces
    $line[$j] =~ s/\s*(.*?)\s*$/$1/;

    if ($line[$j] !~ /^\#/) {
      # not a comment, so put it into the output array
      $out[$k] = $line[$j];

      $k++;
    }
  }
  @line = @out;
}

#-------------------------------------------------------------------------
sub new_entry {
  # skips comments and blank lines to return the next field and it's value

  my ($ln, $expected);
  $expected = "";
  my ($ln, $expected) = @_;
  my @entry = ();
  my $en = 0;
#  print "ln = $ln, line[$ln] = $line[$ln]\n";
  while ($line[$ln] !~ /^\{/) {
    $ln++;
  } 
  if (defined $expected) {
    if ($line[$ln] !~ /$expected/) {
      print "Expected to see the text \"$expected\" but it was not found.\n";
      printf "Previous lines were:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", $line[$ln-7], $line[$ln-6], $line[$ln-5], $line[$ln-4], $line[$ln-3], $line[$ln-2];
      error ("");
    }
  }
  # field found. Find line marking start of next field, or end of array
  $entry[$en] = $line[$ln];
  $ln++;
  while (($line[$ln] !~ /^\{/) && ($ln <= $#line)) {
    $en++;
    $entry[$en] = $line[$ln];
    $ln++;
  } 
  # @entry now contains the field and it's value, possibly on multiple lines.
  # split 
  my $full = join 'NeWlInE', @entry;
  my $val = "";
  $val = (split ':',((split '\}',$full,2)[1]),2)[1];
  if (defined $val) {
    $val =~ s/\s*(.*?)\s*$/$1/;
    # remove leading or trailing \n's
    $val =~ s/(\\n)+$//;
    $val =~ s/^(\\n)+//;
    # remove leading or trailing \\\\'s
    $val =~ s/\s*(.*?)\s*$/$1/;
    $val =~ s/(NeWlInE)+$/ /;
    $val =~ s/^(NeWlInE)+//;
    $val =~ s/(\\\\)+$//;
    $val =~ s/^(\\\\)+//;
    $val =~ s/\s*(.*?)\s*$/$1/;
  } else {
    $val = "";
  }

  return ($val, $ln);
}

#-------------------------------------------------------------------------
sub uc2lc {
# converts upper case to lower case
# call $lc_string = uc2lc($string);
    local($lc_string);
    $lc_string = "\L$_[0]\E";
}
#-------------------------------------------------------------------------
sub lc2uc {
# converts lower case to upper case
# call $lc_string = lc2uc($string);
    local($uc_string);
    $uc_string = "\U$_[0]\E";
}

sub sentence {
  my ($nchar, $text) = @_;
  my $subset = "";
  my $newword;
  my @words;
  if (length($text) <= $nchar) {
    $subset = $text;
    $text = "";
  } else {
    @words = split(/\s/, $text);
    # if the length of the first word is more than nchar, return with that word
    # straight away
    if (length($words[0]) > $nchar) {
      $text = "";
      $subset = $words[0];
    } else {
      while ((length($subset) < $nchar) && ($#words > 0)) {
	$newword = shift(@words);
	$subset = join ' ', $subset, $newword;
      }
      $text = join ' ', @words;
    }
  }
  return($subset, $text);
    
}

#--------------------------------------------------

sub get_general_info_v0p3 {
  # read entries
  ($exp, $i) = new_entry($i);
  ($fname, $i) = new_entry($i);
  ($gname, $i) = new_entry($i);
  ($dprep, $i) = new_entry($i);
  ($src, $i) = new_entry($i);
  ($cal, $i) = new_entry($i);
  ($oby, $i) = new_entry($i);
  ($obd, $i) = new_entry($i);
  ($grts, $i) = new_entry($i);
  ($ts, $i) = new_entry($i);
  ($corel, $i) = new_entry($i);
  ($aipsv, $i) = new_entry($i);
  ($dmv, $i) = new_entry($i);
  ($vd, $i) = new_entry($i);
  ($abs, $i) = new_entry($i);

  # warn if possible errors
  if (!single_word($exp)) {warning("Experiment code may be in error");} else {OK();}
  if (!single_word($fname)) {error("Your family name should be one word.");} else {OK();}
  if (!single_word($gname)) {error("Your given name should be one word.");} else {OK();}
  if (!date_format($dprep)) {error("The date you prepared this document is in the wrong format.");} else {OK();}
  if (!source_name($src)) {warning("The name of the survey source may be in an incorrect format.");} else {OK();}
  if (!source_list($cal)) {warning("The name of the calibration source(s) observed: Format may be incorrect.");} else {OK();}
  if (!yr_format($oby)) {error("The year the experiment took place should be an integer >= 1997.");} else {OK();}
  if (!dayno_format($obd)) {error("The starting day number of the experiment should be an integer >= 1, <=366.");} else {OK();}
  if (!word_list($grts)) {warning("List of GRTs that observed may be in the wrong format.");} else {OK();}
  if (!word_list($ts)) {warning("List the tracking stations that took part may be in the wrong format.");} else {OK();}
  if (!correl_format($corel)) {error("Name of correlator was used is not recognised");} else {OK();}
  if (!single_word($aipsv)) {error("AIPS Version should be one 'word' with a format like 15APR98.");} else {OK();}
#  if (!single_word($dmv)) {error("Difmap version used should be one 'word'.");} else {OK();}
  if (!yesORno($vd)) {error("Was vsop_difmap used: Must answer 'yes' or 'no'.");} else {OK();}
  if (suspect_entry($abs)) {warning("Abstract may contain illegal text.");} else {OK();}

  # LaTeX-ify the text
  $src =~ s/\-/\$\-\$/g;
  $src =~ s/\+/\$\+\$/g;
  $cal =~ s/\-/\$\-\$/g;
  $cal =~ s/\+/\$\+\$/g;
  $abs =~ s/NeWlInE/\n/g;
  $abs =~ s/\_/\\_/g; 
  $abs =~ s/\~/\$\\sim\$/g;
}

sub get_pre_aips_v0p3 {
  ($pil, $i) = new_entry($i);
  ($dqa1, $i) = new_entry($i);
  ($pl5, $i) = new_entry($i);
  ($lcurv, $i) = new_entry($i);
  ($indx, $i) = new_entry($i);
  ($ant, $i) = new_entry($i);
  ($uvf, $i) = new_entry($i);
  ($pacom, $i) = new_entry($i);

  if (!yesORno($pil)) {error("PI letter retrieved?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($dqa1)) {error("Data quality reports and plots retrieved?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($pl5)) {error("Pre-launch 5GHz survey data retrieved?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($lcurv)) {error("Light-curve data retrieved?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($indx)) {error("Has a INDXR input file (INDXR.TXT) been created?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($ant)) {error("Has a ANTAB input file (ANTAB.TXT) been created?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($uvf)) {error("Has a UVFLG input file (UVFLG.TXT) been created?: Must answer 'yes' or 'no'.");} else {OK();}
  if (suspect_entry($pacom)) {warning("Any comments on Pre-AIPS file preparation?: Possibly contains illegal text.");} else {OK();}

  # convert yes/no answers to 0 or 1
  $pil = yesno($pil);
  $dqa1 = yesno($dqa1);
  $pl5 = yesno($pl5);
  $lcurv = yesno($lcurv);
  $indx = yesno($indx);
  $ant = yesno($ant);
  $uvf = yesno($uvf);
  $pacom =~ s/NeWlInE/\n/g;
  $pacom =~ s/\_/\\_/g;
  $pacom =~ s/\~/\$\\sim\$/g;
}

sub get_aips_out_v0p3 {
  ($pan, $i) = new_entry($i);
  ($lis, $i) = new_entry($i);
  ($dt0, $i) = new_entry($i);
  ($dt1, $i) = new_entry($i);
  ($uv1, $i) = new_entry($i);
  ($uv2, $i) = new_entry($i);
  ($uv3, $i) = new_entry($i);
  ($vpl, $i) = new_entry($i);
  ($acc1, $i) = new_entry($i);
  ($acc2, $i) = new_entry($i);
  ($apc1, $i) = new_entry($i);
  ($apc2, $i) = new_entry($i);
  ($nfr, $i) = new_entry($i);
  if ($nfr =~ /\D/) {
    $nfr = 1;
  }
  ($scp1, $i) = new_entry($i);
  ($scp2, $i) = new_entry($i);
  ($scd1, $i) = new_entry($i);
  ($scd2, $i) = new_entry($i);
  ($scr1, $i) = new_entry($i);
  ($scr2, $i) = new_entry($i);
  ($scs1, $i) = new_entry($i);
  ($scs2, $i) = new_entry($i);

  ($vplap1, $i) = new_entry($i);
  ($vplap2, $i) = new_entry($i);


  ($pos1, $i) = new_entry($i);
  ($pos2, $i) = new_entry($i);
  ($tas, $i) = new_entry($i);
  ($fit, $i) = new_entry($i);

  if (!yesORno($pan)) {error("PRTAN [PRTAN.LIS]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($lis)) {error("LISTR (optyp = 'SCAN') [LISTR.LIS]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($dt0)) {error("DTSUM (aparm = 0) [DTSUM_0.LIS]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($dt1)) {error("DTSUM (aparm = 1) [DTSUM_1.LIS]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($uv1)) {error("UVPLT (u vs v) [UVPLT_UV.PS]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($uv2)) {error("UVPLT ((u,v) distance vs time) [UVPLT_UVD.PS]:\n\tMust answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($uv3)) {error("UVPLT ((u,v) position angle vs time).  [UVPLT_UVPA.PS]:\n\tMust answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($vpl)) {error("VPLOT antenna weights vs time (after adjustment) [WEIGHTS.PS]:\n\tMust answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($acc1)) {error("ACCOR SNPLT (amplitude), IF 1: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($acc2)) {error("ACCOR SNPLT (amplitude), IF 2: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($apc1)) {error("APCAL SNPLT (amplitude), IF 1: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($apc2)) {error("APCAL SNPLT (amplitude), IF 2: Must answer 'yes' or 'no'.");} else {OK();}
  if (!an_integer($nfr)) {error("Number of times preliminary FRING solutions were plotted:\n \tMust be an integer >= 1");} else {OK();}
  if (!yesORno($scp1)) {error("Post-FRING CALIB SNPLT: IF 1 [SN_CALIB_PHA_1]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scp2)) {error("Post-FRING CALIB SNPLT: IF 2 [SN_CALIB_PHA_2]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scd1)) {error("Post-FRING CALIB SNPLT: IF 1 [SN_CALIB_DEL_1]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scd2)) {error("Post-FRING CALIB SNPLT: IF 2 [SN_CALIB_DEL_2]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scr1)) {error("Post-FRING CALIB SNPLT: IF 1 [SN_CALIB_RAT_1]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scr2)) {error("Post-FRING CALIB SNPLT: IF 2 [SN_CALIB_RAT_2]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scs1)) {error("Post-FRING CALIB SNPLT: IF 1 [SN_CALIB_SNR_1]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($scs2)) {error("Post-FRING CALIB SNPLT: IF 2 [SN_CALIB_SNR_2]: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($vplap1)) {error("Post-calibration VPLOT, IF 1: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($vplap2)) {error("Post-calibration VPLOT, IF 2: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($pos1)) {error("Post-calibration POSSM, IF 1: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($pos2)) {error("Post-calibration POSSM, IF 2: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($tas)) {error("Output TASAV FITS file: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($fit)) {error("Calibrated and averaged FITS data files: Must answer 'yes' or 'no'.");} else {OK();}

  $pan = yesno($pan);
  $lis = yesno($lis);
  $dt0 = yesno($dt0);
  $dt1 = yesno($dt1);
  $uv1 = yesno($uv1);
  $uv2 = yesno($uv2);
  $uv3 = yesno($uv3);
  $vpl = yesno($vpl);
  $acc1 = yesno($acc1);
  $acc2 = yesno($acc2);
  $apc1 = yesno($apc1);
  $apc2 = yesno($apc2);
  $scp1 = yesno($scp1);
  $scp2 = yesno($scp2);
  $scd1 = yesno($scd1);
  $scd2 = yesno($scd2);
  $scr1 = yesno($scr1);
  $scr2 = yesno($scr2);
  $scs1 = yesno($scs1);
  $scs2 = yesno($scs2);
  $vplap1 = yesno($vplap1);
  $vplap2 = yesno($vplap2);
  $pos1 = yesno($pos1);
  $pos2 = yesno($pos2);
  $tas = yesno($tas);
  $fit = yesno($fit);
}

sub get_supp_files_v0p3 {
  $nfile = 0;
  while ($line[$i] =~ /{File}/) {
    ($file[$nfile], $i) =  new_entry($i);
    if ($file[$nfile] ne "") {
      if (!single_file($file[$nfile])) {warning("File = $file[$nfile]:\n\tFile name may be in error, should be a single file name.");} else {OK();}
      $file[$nfile] =~ s/\_/\\_/g;
      $file[$nfile] =~ s/\~/\$\\sim\$/g;
      ($desc[$nfile], $i) =  new_entry($i);
      if (suspect_entry($desc[$nfile])) {warning("File = $file[$nfile]:\n\tFile description possibly contains illegal text.");} else {OK();}
      $desc[$nfile] =~ s/NeWlInE/\n/g;
      $desc[$nfile] =~ s/\_/\\_/g;
      $desc[$nfile] =~ s/\~/\$\\sim\$/g;
      $nfile++;
    } else {
      # just read the description to keep up, but ignore the contents
      ($desc[$nfile], $i) =  new_entry($i);
    }
  }
}

sub get_aips_notes_v0p3 {
  $ntask = 0;
  my $tmpn;
  while ($line[$i] =~ /\{Task\}/) {
    $tmpn = $ntask + 1;
    ($task[$ntask], $i) =  new_entry($i, "Task");
    ($adverb[$ntask], $i) =  new_entry($i, "ADVERBs");
    ($incl[$ntask], $i) =  new_entry($i, "Input CL");
    ($insn[$ntask], $i) =  new_entry($i, "Input SN");
    ($outsn[$ntask], $i) =  new_entry($i, "Output SN");
    ($outcl[$ntask], $i) =  new_entry($i, "Output CL");
    ($comment[$ntask], $i) =  new_entry($i, "Comments");

    if (!single_word($task[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tTask name must be a single word.");} else {OK();}
    if (suspect_entry($adverb[$ntask])) {warning("Task number $tmpn = \"$task[$ntask]\":\n\tADVERBs possibly contains illegal text.");} else {OK();}
    if (!an_integer_list($incl[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tInput CL must be an integer or list of integers.");} else {OK();}
    if (!an_integer_list($insn[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tInput SN must be an integer or list of integers.");} else {OK();}
    if (!an_integer_list($insn[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tOutput SN must be an integer or list of integers.");} else {OK();}
    if (!an_integer_list($outcl[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tOutput CL must be an integer or list of integers.");} else {OK();}
    if (suspect_entry($comment[$ntask])) {error("Task number $tmpn = \"$task[$ntask]\":\n\tComments possibly contains illegal text.");} else {OK();}
    $comment[$ntask] =~ s/NeWlInE/\n/g;
    $comment[$ntask] =~ s/\_/\\_/g;
    $comment[$ntask] =~ s/\~/\$\\sim\$/g;
    $ntask++;
  }
}

sub get_difmap_notes_v0p3 {
  ($psc, $i) = new_entry($i);
  ($gscal, $i) = new_entry($i);
  ($asc, $i) = new_entry($i);
  ($mf, $i) = new_entry($i);
  ($image, $i) = new_entry($i);
  ($dmcom, $i) = new_entry($i);

  if (!yesORno($psc)) {error("Phase Selfcal applied?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($gscal)) {error("Global Amplitude Selfcal applied?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($asc)) {error("Amplitude Selfcal applied on non-global timescales?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($mf)) {error("Modelfit made and saved using the vs_final_mod macro?: Must answer 'yes' or 'no'.");} else {OK();}
  if (!yesORno($image)) {error("Image made and saved using the vs_final_img macro?: Must answer 'yes' or 'no'.");} else {OK();}
  if (suspect_entry($dmcom)) {error("Comments on Difmap processing possibly contains illegal text.");} else {OK();}
  $dmcom =~ s/NeWlInE/\n/g;
  $dmcom =~ s/\_/\\_/g;
  $dmcom =~ s/\~/\$\\sim\$/g;

  $psc = yesno($psc);
  $gscal = yesno($gscal);
  $asc = yesno($asc);
  $mf = yesno($mf);
  $image = yesno($image);
}

sub  write_latex_header_v0p3 {
  print OUT <<'EOF';
\documentclass[]{article}

\usepackage{supertabular}


\textwidth=17.3cm
\textheight=26cm
\topmargin=-2.5cm
\oddsidemargin=-1.0cm
\evensidemargin=-1.0cm
\parindent 0pt
\def\yes{\small 
  \framebox[3.8mm]{\rule[0mm]{0mm}{1.5mm} }\hspace*{-4.7mm}
\raisebox{0.1mm}{$\surd$}\makebox[1mm]{} }
\def\no {\small \framebox[3.8mm]{\rule[0mm]{0mm}{1.5mm}}\makebox[1mm]{}}

\begin{document}
\begin{tabular*}{\textwidth}[t]{@{}l@{\extracolsep{\fill}}cr@{\extracolsep{0pt}}|c|}
\cline{4-4}
  &                                                  & &                   \\
EOF

print OUT "& {\\LARGE \\sf VSOP Survey Data Reduction Checklist and Worksheet}    & & {\\LARGE \\sf $exp} \\\\ \n";
print OUT "& {\\it Prepared by} $gname $fname {\\it on} $dprep & & $oby/$obd   \\\\ \n";
print OUT "&                       & &                   \\\\ \\cline{4-4} \n";
print OUT " \\end{tabular*} \n";
print OUT " \\vspace{0.2cm} \n";

}

sub  write_latex_desc_abs_v0p3 {
print OUT <<'EOF';

\begin{tabular*}{\textwidth}[t]{@{}l@{ : }ll@{ : }l}\hline
EOF

if (yesno($vd)) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{\\bf \\sf Observation code}      & $exp       & {\\bf \\sf AIPS version} & $aipsv \\\\ \n";
print OUT "{\\bf \\sf Date of observation}   & $oby/$obd  & {\\bf \\sf Difmap version} & $dmv \\\\ \n";
print OUT "{\\bf \\sf Source name}           & $src       & {\\bf \\sf vsop\\_difmap used} & $tmptxt \\\\ \n";
print OUT "{\\bf \\sf Calibration source(s)} & $cal       & \\multicolumn{2}{c}{} \\\\ \n";
if ($mf) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{\\bf \\sf Ground telescopes}     & $grts      & {\\bf \\sf Model fitted to data}  & $tmptxt \\\\ \n";
if ($image) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{\\bf \\sf Tracking station(s)}   & $ts        & {\\bf \\sf Image made}            & $tmptxt  \\\\ \n";
print OUT "{\\bf \\sf Correlator}            & $corel     & \\multicolumn{2}{c}{} \\\\ \n";

print OUT <<'EOF';
 \hline
\end{tabular*}
 \vspace{0.2cm}

\underline{\large \sf Abstract.}\\
EOF

print OUT "$abs \\\\ \n";
print OUT <<'EOF';
\rule[0mm]{\textwidth}{0.1mm}

 \vspace{0.5cm}
EOF
}


sub write_latex_pre_aips_v0p3 {

print OUT <<'EOF';
\underline{\large \sf Pre-AIPS Checklist}\\
\begin{tabular}[t]{|ll|} \hline
EOF
print OUT "PI Letter     & ".yn($pil)." \\\\ \n";
print OUT "Data quality reports and plots  & ".yn($dqa1)." \\\\ \n";
print OUT "Pre-launch 5 GHz survey data obtained & ".yn($pl5)." \\\\ \n";
print OUT "Light curve data obtained     & ".yn($lcurv)." \\\\ \n";
print OUT "INDXR.TXT input file    & ".yn($indx)." \\\\ \n";
print OUT "ANTAB.TXT input file    & ".yn($ant)."  \\\\ \n";
print OUT "UVFLG.TXT input file    & ".yn($uvf)."  \\\\ \\hline \n";

print OUT <<'EOF';
\end{tabular}
\begin{tabular}[t]{p{9cm}}
	 {\bf Comments:} \\
EOF
print OUT "$pacom \\\\ \n";

print OUT <<'EOF';
\end{tabular}

 \vspace{0.5cm}
EOF
}

sub  write_latex_aips_output_v0p3 {

print OUT <<'EOF';

\underline{\large \sf AIPS Output Files}\\
\begin{tabular}[t]{|ll@{~~~~~~}ll|} \hline
EOF

print OUT "PRTAN.LIS     & ".yn($pan)." &  SN\\_FRINGnn\\_RAT\\_1.PS & ".yn($nfr)." \\\\ \n";
print OUT "LISTR.LIS     & ".yn($lis)." &  SN\\_FRINGnn\\_RAT\\_2.PS & ".yn($nfr)." \\\\ \n";
print OUT "        &  &         &  \\\\ \n";
print OUT "DTSUM\\_0.LIS    & ".yn($dt0)." &  SN\\_CALIB\\_SNR\\_1.PS   & ".yn($scs1)." \\\\ \n";
print OUT "DTSUM\\_1.LIS    & ".yn($dt1)." &  SN\\_CALIB\\_SNR\\_2.PS   & ".yn($scs2)." \\\\ \n";
print OUT "                         &  &  SN\\_CALIB\\_DEL\\_1.PS   & ".yn($scd1)." \\\\ \n";
print OUT "UVPLT\\_UV.PS    & ".yn($uv1)." &  SN\\_CALIB\\_DEL\\_2.PS   & ".yn($scd2)." \\\\ \n";
print OUT "UVPLT\\_UVD.PS     & ".yn($uv2)." &  SN\\_CALIB\\_RAT\\_1.PS   & ".yn($scr1)." \\\\ \n";
print OUT "UVPLT\\_UVPA.PS    & ".yn($uv3)." &  SN\\_CALIB\\_RAT\\_2.PS   & ".yn($scr2)." \\\\ \n";
print OUT "                           &  &  SN\\_CALIB\\_PHA\\_1.PS   & ".yn($scp1)." \\\\ \n";
print OUT "VPLOT\\_WEIGHTS.PS   & ".yn($vpl)." &  SN\\_CALIB\\_PHA\\_2.PS   & ".yn($scp2)." \\\\ \n";
print OUT "        &  &         &  \\\\ \n";
print OUT "SN\\_ACCOR\\_AMP\\_1.PS  & ".yn($acc1)." &  VPLOT\\_AP\\_1.PS    & ".yn($vplap1)." \\\\ \n";
print OUT "SN\\_ACCOR\\_AMP\\_2.PS  & ".yn($acc2)." &  VPLOT\\_AP\\_2.PS    & ".yn($vplap2)." \\\\ \n";
print OUT "SN\\_APCAL\\_AMP\\_1.PS  & ".yn($apc1)." &         &  \\\\ \n";
print OUT "SN\\_APCAL\\_AMP\\_2.PS  & ".yn($apc2)." &  POSSMnn\\_AP\\_1.PS    & ".yn($pos1)." \\\\ \n";
print OUT "         &  &  POSSMnn\\_AP\\_2.PS    & ".yn($pos2)." \\\\ \n";
print OUT "SN\\_FRINGnn\\_SNR\\_1.PS & ".yn($nfr)." & & \\\\ \n";
print OUT "SN\\_FRINGnn\\_SNR\\_2.PS & ".yn($nfr)." & & \\\\ \n";
print OUT "SN\\_FRINGnn\\_DEL\\_1.PS & ".yn($nfr)." & & \\\\ \n";
print OUT "SN\\_FRINGnn\\_DEL\\_2.PS & ".yn($nfr)." & & \\\\ \n";

print OUT "\\multicolumn{4}{|l|}{} \\\\ \n";
print OUT "\\multicolumn{4}{|l|}{VSxxx\\_surname\\_TASAV.FITS \\hfill ".yn($tas)."} \\\\ \n";
print OUT "\\multicolumn{4}{|l|}{sourcename\\_surname\\_AIPS.FITS \\hfill ".yn($fit)."} \\\\\\hline \n";
print OUT "\\end{tabular} \n";
	 if ($nfile > 0) {
	   print OUT "\\begin{tabular}[t]{|p{6.5cm}|} \\hline \n";
	   for ($i = 0; $i < $nfile; $i++) {
	     print OUT "$file[$i] \\\\ \n";
	     print OUT "$desc[$i] \\\\ \\hline \n";
	   }
	   print OUT "\\end{tabular} \n";
	 }


}

sub write_latex_aips_notes_v0p3 {

print OUT <<'EOF';

\newpage
\tablefirsthead{
  \multicolumn{7}{c}{\LARGE \sf AIPS Data Reduction Notes} \\
  \multicolumn{7}{c}{} \\ \hline
    &  & CL & SN & CL & SN &  \\ 
Task& \multicolumn{1}{c}{Adverb(s)} & in & in & out & out & \multicolumn{1}{c}{Comments} \\ \hline}

\tablehead{\hline
    &  & CL & SN & CL & SN &  \\ 
Task& \multicolumn{1}{c}{Adverb(s)} & in & in & out & out & \multicolumn{1}{c}{Comments} \\ }

\tablelasttail{\hline} \tabletail{\hline \multicolumn{7}{l}{\small \slshape continued on next page}\\}

\begin{supertabular}{cp{3cm}ccccp{8cm}}
EOF

for ($i = 0; $i < $ntask; $i++) {
  @advl = split "NeWlInE", $adverb[$i];
  print OUT "$task[$i] & \\begin{verbatim}";
  for ($j = 0; $j <= $#advl; $j++) {
    $advl[$j] =~ s/\s*(.*?)\s*$/$1/;
    if (length($advl[$j]) >= 16) {
      $tmptxt = $advl[$j];
      @broken = ();
      $nb = 0;
      while (length($tmptxt) > 0) {
	($broken[$nb], $tmptxt) = sentence(10, $tmptxt);
	if ($nb > 0) {
	  $broken[$nb] = "  $broken[$nb]";
	} else {
	  $broken[$nb] =~ s/\s*(.*?)\s*$/$1/;
	}
	$nb++;
      }
    } else {
      @broken = ($advl[$j]);
    }
    for ($k = 0; $k <= $#broken; $k++) {
      print OUT "$broken[$k]\n";
    }
  }
  print OUT "\\end{verbatim} & $incl[$i] & $insn[$i] & $outcl[$i] & $outsn[$i] & $comment[$i] \\\\ \\hline \n";

}
print OUT "\\end{supertabular} \n";
}

sub  write_latex_difmap_notes_v0p3 {
print OUT <<'EOF';
\newpage
\begin{center}
{\LARGE \sf Difmap Data Reduction Notes}
\end{center}

\begin{tabular*}{\textwidth}[t]{@{}l@{~~}l}\hline
\multicolumn{2}{c}{} \\
EOF

if ($psc) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Phase selfcal applied?} & $tmptxt \\\\ \n";
if ($gscal) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Global amplitude selfcal (gscal) applied?}             & $tmptxt \\\\ \n";
if ($asc) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Amplitude selfcal on non-global timescales?} & $tmptxt \\\\ \n";
if ($mf) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Modelfit made and saved using the vs\\_final\\_mod macro?} & $tmptxt \\\\ \n";
if ($image) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Image made and saved using the vs\\_final\\_img macro?} & $tmptxt \\\\ \n";

print OUT <<'EOF';
\multicolumn{2}{c}{} \\
\end{tabular*}
\begin{tabular}[t]{@{}p{0.99\textwidth}} 
\\
\underline{\large \sf Comments on Difmap processing.}\\
EOF

print OUT "$dmcom \n";
print OUT <<'EOF';
\end{tabular}

\end{document}
EOF
}

#-------
sub suspect_entry{
  # looks for substrings containing "} [spaces] :" or "{"
  # returns 1 if bad text, 0 otherwise
  my ($text) = @_;
  if ($text =~ /\}\s*:/) {
    return (1);
  } elsif ($text =~ /\{/) {
    return (1);
  } else {
    return (0);
  }
}
#-------
sub OK {
  # prints "OK\n";
#  print "OK\n";
}
#-------
sub warning {
  # prints a warning message using supplied text to STDOUT
  my ($text) = @_;
  $text =~ s/NeWlInE/\n/g;
  print "\nWARNING: $text\n";
}
#-------
sub error {
  # prints an error message using supplied text to STDOUT
  my ($text) = @_;
  $text =~ s/NeWlInE/\n/g;
  print "\nERROR: $text\n"; die;
}
#-------
sub single_word {
  # returns 1 if the text is a single word, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }

  if ($text =~ /^\w+$/) {
    return (1);
  } else {
    return (0);
  }
}
#-------
sub date_format {
  # checks to see if input text complies to the date format day-month-year, e.g 23-04-1999
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  my (@data) = split "-", $text;
  if ($#data != 2) {
    return(0);
  }
  my ($d, $m, $y) = @data;

  if (an_integer($d) + an_integer($m) + an_integer($y) != 3) {
    return(0);
  }
  if ( ($d >= 1) && ($d <=32) && 
       ($m >= 1) && ($m <=12) &&
       yr_format($y) ) {
    return (1);
  } else {
    return (0);
  } 
  die;
}
#-------
sub source_name {
  # checks if input text is a source name
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }

  if ($text =~ /^\w*\d+(\+|\-)\d+$/) {
    return (1);
  } else {
    return (0);
  }

}
#-------
sub word_list {
  # checks if input text contains one or more words separated by spaces or commas
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text =~ /,/) {
    # split on commas
    @words = split ",", $text;
  } else {
    # split on spaces
    @words = split /\s+/, $text;
  }
  my $mult = 1;
  foreach $w (@words) {
    $mult = $mult * single_word($w);
  }
  return ($mult);
}
#-------
sub source_list {
  # checks if input text contains one or more sources separated by spaces or commas
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  my @sources;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text =~ /,/) {
    # split on commas
    @sources = split ",", $text;
  } else {
    # split on spaces
    @sources = split /\s+/, $text;
  }
  my $mult = 1;
  foreach $w (@sources) {
    $mult = $mult * source_name($w);
  }
  return ($mult);
}
#-------
sub yr_format{
  # checks for an integer >= 1997, < 2010
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text >= 1997 && $text <= 2010) {
    return(1);
  } else {
    return(0);
  }
}
#-------
sub dayno_format {
  # checks for an integer between 1 and 366
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text >= 1 && $text <= 366) {
    return(1);
  } else {
    return(0);
  }
}
#-------
sub correl_format {
  # checks that the text is a word equal to "Mitaka" "Penticton" or "Socorro"
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  $text = uc2lc ($text);
  if ($text eq "mitaka" || $text eq "penticton" || $text eq "socorro") {
    return (1);
  } else {
    return (0);
  }
}
#-------
sub yesORno{
  # checks that the input text is one of the following:  "yes", "no", "Y", "N", "y" or "n"
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  my $safetext = $text;
  $text = uc2lc ($text);
#  print "text text = $text\n";
  if ($text eq "yes" || $text eq "y" || $text eq "no" || $text eq "n") {
    return (1);
  } else {
    $safetext =~ s/NeWlInE/\n/g;
    $safetext =~ s/^(NeWlInE)+//;

    print "\n-----------------\nResponse to Yes/No question was:\n\t \"$safetext\"\n-----------------\n";
    return (0);
  }
}
#-------
sub an_integer{
  # checks if the input text is an integer
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }

  if ($text =~ /\d+/) {
    return (1);
  } else {
    return (0);
  }
}
#-------
sub an_integer_list {
  # checks if input text is a list of integers separated by spaces or commas
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text =~ /,/) {
    # split on commas
    @nums = split ",", $text;
  } else {
    # split on spaces
    @nums = split /\s+/, $text;
  }
  my $mult = 1;
  foreach $n (@nums) {
    $mult = $mult * an_integer($n);
  }
  return ($mult);

}

#-------
sub real_list {
  # checks if input text is a list of reals separated by spaces or commas
  # returns 1 of OK, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }
  if ($text =~ /,/) {
    # split on commas
    @nums = split ",", $text;
  } else {
    # split on spaces
    @nums = split /\s+/, $text;
  }
  my $mult = 1;
  foreach $n (@nums) {
    @subs = split ".", $n;
    if ($#subs > 1) {
      $mult = 0; error("$n is not a number.");
    } else {
      foreach $n1 (@subs) {
	$mult = $mult * an_integer($n1);
      }
    }
  }
  return ($mult);

}
#-------


sub get_amp_corrections_v0p4 {
  # read entries
  ($clcor_ants, $i) = new_entry($i);
  ($clcor_fact, $i) = new_entry($i);

  # warn if possible errors
  if (!word_list($clcor_ants)) {error("Antenna name list not in a recognised format.");} else {OK();}
  if (!real_list($clcor_fact)) {error("Amplitude correction factors not in a recognised format.");} else {OK();}

  # LaTeX-ify the text
  $clcor_ants =~ s/\_/\\_/g; 
  $clcor_fact =~ s/\~/\$\\sim\$/g;
}

sub get_gscal_corrections_v0p4 {
  # read entries
  ($gscal_ants, $i) = new_entry($i);
  ($gscal_fact, $i) = new_entry($i);

  # warn if possible errors
  if (!word_list($gscal_ants)) {error("Antenna name list not in a recognised format.");} else {OK();}
  if (!real_list($gscal_fact)) {error("Amplitude correction factors not in a recognised format.");} else {OK();}

  # LaTeX-ify the text
  $gscal_ants =~ s/\_/\\_/g; 
  $gscal_fact =~ s/\~/\$\\sim\$/g;
}

sub  write_latex_aips_ampcal_v0p4 {
  print OUT <<'EOF';

\vspace{0.5cm}
\underline{\large \sf Antenna gain corrections applied in CLCOR.}\\
\begin{tabular}[t]{|ll|} \hline
Antenna     & Factor \\ \hline 
EOF

  if ($clcor_ants =~ /,/) {
    # split on commas
    @ants = split ",", $clcor_ants;
  } else {
    # split on spaces
    @ants = split /\s+/, $clcor_ants;
  }
  if ($clcor_fact =~ /,/) {
    # split on commas
    @facts = split ",", $clcor_fact;
  } else {
    # split on spaces
    @facts = split /\s+/, $clcor_fact;
  }
for ($antenna = 0; $antenna < $#ants; $antenna++) {
  print OUT "$ants[$antenna] & $facts[$antenna] \\\\ \n";
}
print OUT "\\hline \n";
print OUT "\\end{tabular}\n\n";
}

sub write_latex_difmap_notes_v0p4 {
  print OUT <<'EOF';
\newpage
\begin{center}
{\LARGE \sf Difmap Data Reduction Notes}
\end{center}

\begin{tabular*}{\textwidth}[t]{@{}l@{~~}l}\hline
\multicolumn{2}{c}{} \\
EOF

  if ($psc) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Phase selfcal applied?} & $tmptxt \\\\ \n";
if ($gscal) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Global amplitude selfcal (gscal) applied?}             & $tmptxt \\\\ \n";
if ($asc) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Amplitude selfcal on non-global timescales?} & $tmptxt \\\\ \n";
if ($mf) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Modelfit made and saved using the vs\\_final\\_mod macro?} & $tmptxt \\\\ \n";
if ($image) {$tmptxt = "Yes";} else {$tmptxt = "No";}
print OUT "{ \\sf Image made and saved using the vs\\_final\\_img macro?} & $tmptxt \\\\ \n";

print OUT <<'EOF';
\multicolumn{2}{c}{} \\
\end{tabular*}

\underline{\large \sf Gscal correction factors applied.}\\
\begin{tabular}[t]{|ll|} \hline
Antenna     & Factor \\ \hline 
EOF

  if ($gscal_ants =~ /,/) {
    # split on commas
    @ants = split ",", $gscal_ants;
  } else {
    # split on spaces
    @ants = split /\s+/, $gscal_ants;
  }
  if ($gscal_fact =~ /,/) {
    # split on commas
    @facts = split ",", $gscal_fact;
  } else {
    # split on spaces
    @facts = split /\s+/, $gscal_fact;
  }
for ($antenna = 0; $antenna < $#ants; $antenna++) {
  print OUT "$ants[$antenna] & $facts[$antenna] \\\\ \n";
}
print OUT "\\hline \n";

print OUT <<'EOF';
\end{tabular}

\begin{tabular}[t]{@{}p{0.99\textwidth}} 
\\
\underline{\large \sf Comments on Difmap processing.}\\
EOF

print OUT "$dmcom \n";
print OUT <<'EOF';
\end{tabular}

\end{document}
EOF
}

#-------
sub single_file {
  # returns 1 if the text is a single filename, 0 otherwise
  my ($text) = @_;
  # remove leading and trailing space
  $text =~ s/\s*(.*?)\s*$/$1/;
  # check for suspect text
  if (suspect_entry($text)) {
    warning("Text possibly contains illegal characters.");
  }

  if ($text =~ /^[\w\-\.]+$/) {
    return (1);
  } else {
    return (0);
  }
}
