#!/bin/sh
#
#   Usage: qdump -T [options] file_name_template [sfx=val] [start=val] [stop=val] [months=val]
#          qdump [options] file1 [file2 ...] [sfx=val]
#          qdump [options] list=fname [file|patt ...]
#          qdump [options] patt [patt ...]
#
# Purpose: Create and optionally submit a job to dump files to cfs.
#
#          If invoked with the "-T" option, file names are determined using
#          a file_name_template supplied on the command line together with information
#          in the optional variable definitions found on the commmand line.
#
#          If invoked with the "-L" option (the default), file names are determined
#          from an explicit list of file names supplied on the command line.
#          If sfx=suffix_list is supplied on the commmand line then each file name
#          in this list will be appended with every suffix found in suffix_list.
#
#          If invoked with list=fname on the command line, fname is the name of a
#          file containing a list of file names, one file name per line, that will
#          be dumped to cfs. Blank lines and comment lines (lines beginning with "#")
#          are ignored in "fname". Any three digit numeric file name extension
#          (such as ".001") found on a file name in flist is removed.
#
#          File names or file name patterns (containing wild cards) supplied
#          on the command line will also be dumped, in addition to those
#          found in the file "fname".
#
#          If invoked with at least 1 file name pattern (containing wild cards)
#          on the command line the pattern or patterns will be expanded when
#          the job created here is actually run on the front end machine in
#          Dorval. These patterns will match file names found on the front end
#          or back end DATAPATH in Dorval, depending on whether or not the -f
#          command line option was used.
#
#          All file name patterns found on the command line should be quoted with
#          single quotes to protect them from premature expansion by the shell.
#
#          file_name template is of the form ${uxxx}_${runid}_${year}_m${month}
#          where the month field may be missing and if the month is missing
#          then the year field may also be missing.
#
# Variable definitions:
#    sfx=suffix_list  ...A white space separated list of file name suffixes
#                        default: sfx='cm gz gs ss os+12 cs+12 rs+12 ab+12 ob+12 an+12'
#    start=year:month ...The first year/month to be dumped
#                        ":month" is optional and it defaults to 1
#    stop=year:month  ...The last year/month to be dumped
#                        ":month" is optional and it defaults to 12
#    months=Integer   ...The number of months per job in the submission string
#                        default: all files will be dumped by a single job
#    maxsize=Size     ...The maximum size of any group of file that will be dumped
#                        to a single arc file. Size defaults to 8GB if not specified.
#                        This variable is meaninful only in list mode (-L in effect).
#    maxfiles=Integer ...The maximum number of file that will be dumped to a
#                        single arc file.
#                        This variable is meaninful only in list mode (-L in effect).
#    uxxx=String      ...Setting uxxx when using a template will override the value
#                        of uxxx found in the template
#    runid=String     ...Setting runid when using a template will override the value
#                        of runid found in the template
#
# Options:
# All options begin with a dash (-) and must appear before any other command line arg
# Single letter options may be combined, as in "qdump -Bsf ..."
#   -L      ...provide an explicit list of file names on the command line (default)
#   -T      ...provide a file name template on the command line
#   -B      ...batch mode, automatically submit the job and clean up
#   -D      ...delete files from DATAPATH after they are dumped (only valid with list option)
#   -o file ...user supplied file name for the output submission job
#   -d mach ...the name of the machine from which the files will be dumped
#   -f      ...dump files from front end      (otherwise dump from back end)
#   -v      ...dump files from Victoria       (otherwise dump from back end)
#   -s      ...dump files to short term cfs   (otherwise dump to long term cfs)
#   -m      ...dump files to master dir       (otherwise dump to long term cfs)
#   -u user ...cfs files belong to this user  (otherwise files belong to invoking user)
#   -h      ...show this usage info
#
# Examples:
# To dump history files for year 1850 to long term cfs from the back end type
#   qdump -T mc_xyz_1850
#
# To dump these same history files but do it in 3 month chunks type
#   qdump -T mc_xyz_1850 months=3
#
# To dump a set of 1849_m12 coupled restarts and binaries to long term cfs type
#   qdump -T mc_xyz_1849_m12 sfx='rs os cs ab ob an'
#
# To dump 5 years of diagnostic files to short term cfs from the front end type
#   qdump -T -sf da_xyz start=2 stop=6 sfx='gp xp'
#
# To dump 2 files which are named explicitly by the user type
#   qdump this_is_one_file this_is_another
#
# To dump a list of files whose names are found in a user supplied file named FLIST
#   qdump list=FLIST
#
# To dump a list of files whose names match the pattern sc_xyz_1991_2000_gp_*
# WARNING: Be very careful when using file name patterns.
#   qdump 'sc_xyz_1991_2000_gp_*'
########################################################################
#
# Larry Solheim Dec,2009
#
# $Id: qdump 659 2012-03-21 21:56:58Z acrnrls $

FULLPATH=`type $0|awk '{print $3}'` # pathname of this script
Runame=`basename $FULLPATH`
usage() {
  err_exit=0
  while getopts e opt; do
    case $opt in
      e) err_exit=1 ;;
    esac
  done
  shift `expr $OPTIND - 1`

  [ -n "$1" ] && echo >&2 "${Runame}:" "$@"
  echo >&2 " "
  sed >&2 -n '/^###/q; s/^#$/# /; s/^ *$/# /; 3,$s/^# //p;' "$FULLPATH"
  if [ $err_exit -eq 0 ]; then
    exit
  else
    exit 1
  fi
}

bail(){
echo "${Runame}: *** ERROR *** $1"
exit 1
}

# echo without return (ie: emulate -n if not recognized by echo)
if [ "X`echo -n`" = "X-n" ]; then
  echo_n() { echo ${1+"$@"}'\c'; }
else
  echo_n() { echo -n ${1+"$@"}; }
fi

# Set defaults

# The name of the file containing the batch script to be submitted
outfile=qdump$$_job

# batch_mode = 1 means do not query the user for anything and automatically
# submit the job string once it is created, then delete it from disk
batch_mode=0

# The alias for the remote machine to which the tape job will be submitted
sub_mach=af

# The name of the machine from which the cfs files will be dumped
dest_mach=hadar

# uxxx is the first underscore spearated field in the file name
uxxx=''

# runid is the string from the second underscore spearated field
# in the file name up to the year field
runid=''

# year is the field following runid (if any)
year=''

# month id defined by the field following year (if any)
month=''

# The number of months per submission. This may be set by the user to
# break the the submission job into a sequence of tdumper jobs. Each
# job in this sequence will dump "$months" months of data.
months=0

# If sv is set to "off" then dump files from the back end
# If sv is set to "on"  then dump files from the front end
sv_opt='sv=off'

# If vic is set to "off" then do not copy files from Victoria
# If vic is set to "on"  then copy files from Victoria
vic_opt='vic=off'

# If besc is set to "off" then run he tdumper job on the front end
# If besc is set to "on"  then run he tdumper job on the back end
besc_opt='besc=off'

# CCRNTMP is the temporary directory used during transfers/saves
CCRNTMP_opt=''
CCRNTMP_cl=''

# RUNPATH is the directory in which files are saved
RUNPATH_opt=''
RUNPATH_cl=''

# BERUNPATH is the RUNPATH used to save files on the back end
BERUNPATH_opt=''
BERUNPATH_cl=''

# RMTRUNPATH is the RUNPATH used to save files in Victoria
# RMTRUNPATH is only used when vic = on is specified
RMTRUNPATH_opt=''
RMTRUNPATH_cl=''

# If shortermdir is set to "off" then dump files to the long term cfs dir
# If shortermdir is set to "on"  then dump files to the short term cfs dir
shortermdir_opt='shortermdir=off'

# cfsuser identifies the owner of the files on cfs
# If cfsuser is unset then the invoking user is assumed to be the owner
cfsuser_opt=''

# If masterdir is set to "off" then dump files to the user cfs dir
# If masterdir is set to "on"  then dump files to the master cfs dir
masterdir_opt='masterdir=off'

# Options that will be passed to dump_sublist when defined
# dump_sublist_maxarcsize is an upper limit on the total size
# of all files in any single list created in dump_sublist
dump_sublist_maxarcsize_opt=''

# dump_sublist_max_files_per_arc is an upper limit on the number
# of files in any single list created in dump_sublist
dump_sublist_max_files_per_arc_opt=''

# dump_sublist_pattern is a colon ":" separated list of file name patterns that
# will be matched against files on cfs to create file lists in dump_sublist
dump_sublist_pattern_opt=''

# patterns will accumulate all file names containing shell wild cards and
# is used as the definition of dump_sublist_pattern
patterns=''

# keep = 0 means delete the batch script from local disk after submission
keep=0

# The template for all files to be dumped (read from the command line)
tmplt=''

# A white space separated list of file name suffixes to be used
# The default for sfx is set below
sfx=''

# start is the starting year/month in the form year:month
start=''

# stop is the stopping year/month in the form year:month
stop=''

# nfile indicates the number of file names specified on the command line
nfile=0

# del_nfile indicates the number of file names to be deleted specified on the command line
del_nfile=0

# dump_list=0 means use cccjob/mdump to create the submission job
# dump_list=1 means use cccjob/dump_list to create the submission job
dump_list=1

# usr_list, if defined, is the name of a file containing a list of files to be dumped
# This will be in addition to any supplied on the command line with the -L option
usr_list=''

# del_after_dump = 1 means add a job to the the submission string that will
# delete all files that were dumped to cfs
del_after_dump=0

# QUIET is passed to cccjob
QUIET="--quiet"
verbose=0

# process command line options
while getopts LTBDo:u:d:fskmhvV opt
do
  case $opt in
    L) dump_list=1 ;;
    T) dump_list=0 ;;
    B) batch_mode=1 ;;
    D) del_after_dump=1 ;;
    o) outfile="$OPTARG" ;;
    d) dest_mach=$OPTARG ;;
    f) sv_opt='sv=on'; dest_mach=pollux ;;
    v) vic_opt='vic=on'; sv_opt='sv=on'; dest_mach=pollux ;;
    s) shortermdir_opt='shortermdir=on' ;;
    u) cfsuser_opt="cfsuser=$OPTARG" ;;
    m) masterdir_opt='masterdir=on' ;;
    V) verbose=`expr $verbose + 1` ;;
    k) keep=1 ;;
    h) usage ;;
    -) shift; break ;; # end of options
    ?) usage -e $USAGE   ;;
  esac
done
shift `expr $OPTIND - 1`

[ $# -eq 0 ] && usage -e "A file name template is required"
[ -z "$outfile" ] && bail "The output file name is missing"

if [ $verbose -gt 0 ]; then
  QUIET=''
fi

# Set the default for sfx
sfx='cm gz gs ss os+12 cs+12 rs+12 ab+12 ob+12 an+12'
[ $dump_list -eq 1 ] && sfx=''

# Process the remaining command line args
for arg in "$@"; do
  case $arg in
    *=*) var=`echo $arg|awk -F\= '{printf "%s",$1}' -`
         val=`echo "$arg"|awk '{i=index($0,"=")+1;printf "%s",substr($0,i)}' -`
         [ -n "$var" ] && eval ${var}=\"\$val\" # preserve quoted assignments
         case $var in
           CCRNTMP) CCRNTMP_cl="$CCRNTMP" ;;
           RUNPATH) RUNPATH_cl="$RUNPATH" ;;
           BERUNPATH) BERUNPATH_cl="$BERUNPATH" ;;
           RMTRUNPATH) RMTRUNPATH_cl="$RMTRUNPATH" ;;
           list) dump_list=1; sfx=''; usr_list=$val; tmplt=USR_LIST
                 [ ! -s $usr_list ] && bail "The user supplied list $usr_list is missing or empty."
                 # Remove comments and blank lines from usr_list
                 # Use only the first word found on each line

                 # Strip comments, leading whitespace and everthing but the first whitespace
                 # or semicolon separated word from each line of the input file list
                 USR_LIST=`sed -n '/^ *#/d; s/#.*$//g; s/^ *//g;
                                   s/ .*$//g; s/;.*$//g; p' $usr_list`
                 for FNAME in $USR_LIST; do
                   # Strip any fileN= from the beginning of the string
                   FNAME=`echo $FNAME|sed 's/^file[0-9][0-9]*=//g'`
                   # Strip single quotes
                   FNAME=`echo $FNAME|sed "s/'//g"`
                   # Strip double quotes
                   FNAME=`echo $FNAME|sed 's/"//g'`
                   if [ -n "$FNAME" ]; then
                     # Strip any numeric extension
                     FNAME=`echo $FNAME|sed 's/\.[0-9][0-9][0-9]$//'`
                   fi
                   [ -z "$FNAME" ] && continue
                   has_wild=`echo $FNAME|sed -n '/[][?*]/p'`
                   if [ -z "$has_wild" ]; then
                     # FNAME does not contain shell wild cards so it must be a valid
                     # file name containg only alphanumeric or underscore characters
                     FNAME=`echo $FNAME|sed -n '/^[A-Za-z0-9_.-][A-Za-z0-9_.-]*$/p'`
                   fi
                   [ -z "$FNAME" ] && continue
                   
                   # Add fileN to the current env
                   nfile=`expr $nfile + 1`
                   eval file${nfile}="$FNAME"
                 done
                 ;;
       del_list) usr_del_list=$val; del_after_dump=1
                 [ -s $usr_del_list ] || bail "The user supplied del_list $usr_del_list is missing or empty."
                 # Remove comments and blank lines from usr_del_list
                 # Use only the first word found on each line

                 # Strip comments, leading whitespace and everthing but the first whitespace
                 # or semicolon separated word from each line of the input file list
                 USR_DEL_LIST=`sed -n '/^ *#/d; s/#.*$//g; s/^ *//g;
                                   s/ .*$//g; s/;.*$//g; p' $usr_del_list`
                 del_nfile=0
                 for FNAME in $USR_DEL_LIST; do
                   # Strip any fileN= from the beginning of the string
                   FNAME=`echo $FNAME|sed 's/^file[0-9][0-9]*=//g'`
                   # Strip single quotes
                   FNAME=`echo $FNAME|sed "s/'//g"`
                   # Strip double quotes
                   FNAME=`echo $FNAME|sed 's/"//g'`
                   if [ -n "$FNAME" ]; then
                     # Strip any numeric extension
                     FNAME=`echo $FNAME|sed 's/\.[0-9][0-9][0-9]$//'`
                   fi
                   [ -z "$FNAME" ] && continue
                   has_wild=`echo $FNAME|sed -n '/[][?*]/p'`
                   if [ -z "$has_wild" ]; then
                     # FNAME does not contain shell wild cards so it must be a valid
                     # file name containg only alphanumeric or underscore characters
                     FNAME=`echo $FNAME|sed -n '/^[A-Za-z0-9_.-][A-Za-z0-9_.-]*$/p'`
                   fi
                   [ -z "$FNAME" ] && continue
                   
                   # Add del_fileN to the current env
                   del_nfile=`expr $del_nfile + 1`
                   eval del_file${del_nfile}="$FNAME"
                 done
                 ;;
           patt) dump_list=1; sfx=''; tmplt=PATTERN
                 if [ -z "$patterns" ]; then
                   patterns="$val"
                 else
                   patterns="${patterns}:$val"
                 fi
                 ;;
           maxsize)  dump_sublist_maxarcsize_opt="dump_sublist_maxarcsize=$val" ;;
           maxfiles) dump_sublist_max_files_per_arc_opt="dump_sublist_max_files_per_arc=$val" ;;
         esac
         ;;
      *) has_wild=`echo $arg|sed -n '/[][?*]/p'`
         if [ -n "$has_wild" ]; then
           # This argument contains shell wild cards
           # Assume list input
           dump_list=1; sfx=''; tmplt=CMDLINE_LIST
         else
           if [ -z "$tmplt" ]; then
             tmplt="$arg"
           else
             [ $dump_list -eq 0 ] && \
               usage -e Only 1 file_name_template is allowed on the command line
           fi
         fi
         # Add fileN to the current env
         nfile=`expr $nfile + 1`
         eval file${nfile}="$arg"
         ;;
  esac
done

[ -z "$tmplt" ] &&
  usage -e A file name template or file name is required on the command line
[ -z "$sfx" -a $dump_list -eq 0 ] && bail "The suffix list is empty"

# Define pathnames, if set on commnad line
[ -n "$CCRNTMP_cl"    ] && CCRNTMP_opt="CCRNTMP=$CCRNTMP_cl"
[ -n "$RUNPATH_cl"    ] && RUNPATH_opt="RUNPATH=$RUNPATH_cl"
[ -n "$BERUNPATH_cl"  ] && BERUNPATH_opt="BERUNPATH=$BERUNPATH_cl"
[ -n "$RMTRUNPATH_cl" ] && RMTRUNPATH_opt="RMTRUNPATH=$RMTRUNPATH_cl"

if [ -n "$usr_list" ]; then
  [ ! -s $usr_list ] && bail "The user supplied list $usr_list is missing or empty."
fi

# Set parameters to be consistent with the destination machine
berunpath=''
case $dest_mach in
  sp|spica) dest_mach=spica
            sub_mach=spica
            sv_opt='sv=off'
            besc_opt='besc=on'
      # Determine the run path for P7 back end machines
      berunpath=`ssh spica echo '$RUNPATH'` 2>/dev/null
      [ -z "$berunpath" ] &&
        bail "Unable to determine RUNPATH on destination $dest_mach\n The machine could be down."
      ;;
  ha|hadar) dest_mach=hadar
            sub_mach=hadar
            sv_opt='sv=off'
            besc_opt='besc=on'
      # Determine the run path for P7 back end machines
      berunpath=`ssh hadar echo '$RUNPATH'` 2>/dev/null
      [ -z "$berunpath" ] &&
        bail "Unable to determine RUNPATH on destination $dest_mach\n The machine could be down."
      ;;
  za|zeta)   dest_mach=zeta
             sub_mach=pollux
             sv_opt='sv=off'
             besc_opt='besc=on'
             ;;
  sa|saiph)  dest_mach=saiph
             sub_mach=pollux
             sv_opt='sv=off'
             besc_opt='besc=on'
             ;;
  po|pollux) dest_mach=pollux
             sub_mach=pollux
             sv_opt='sv=on'
             besc_opt='besc=off'
             ;;
  af|alef)   dest_mach=alef
             sub_mach=alef
             sv_opt='sv=on'
             besc_opt='besc=off'
             ;;
  *) bail "Invalid destination machine name: $dest_mach" ;;
esac

if [ -n "$berunpath" ]; then
  if [ -n "$BERUNPATH_cl"  ]; then
    # The user has supplied a value for BERUNPATH
    if [ x"$berunpath" != x"$BERUNPATH_cl" ]; then
      echo " *** The user has supplied a value for BERUNPATH --> $BERUNPATH_cl <--"
      echo " *** This is inconsistent with the default value --> $berunpath <-- on the destination machine $dest_mach"
      echo " *** The user supplied value will be used."
    fi
  else
    # Set BERUNPATH appropriate for the destination machine
    BERUNPATH_opt="BERUNPATH=$berunpath"
  fi
fi

# Assign strings for use in informational messages below
TO=`echo $masterdir_opt|awk -F= '{if($2=="on"){print "onto masterdir on cfs"}}' -`
[ -z "$TO" ] && TO=`echo $shortermdir_opt|\
    awk -F= '{if($2=="off"){print "onto long term cfs"}else{print "onto short term cfs"}}' -`
if [ $del_nfile -eq 0 ]; then
  [ $del_after_dump -eq 1 ] && TO="$TO then deleted"
fi

FROM=`echo $vic_opt|awk -F= '{if($2=="on"){print "copied from Victoria"}}' -`
if [ -z "$FROM" ]; then
  FROM=`echo $sv_opt|\
    awk -F= '{if($2=="off"){print "the back end"}else{print "the front end"}}' -`
  FROM="$FROM ($dest_mach)"
fi

if [ $dump_list -eq 1 ]; then
  # Use cccjob::dump_list to create the submission job

  # Create a temporary file containing the list of file names to dump
  flist=qdump$$_flist
  rm -f $flist
  touch $flist
  n=0
  while [ $n -lt $nfile ]; do
    n=`expr $n + 1`
    eval curr_fname=\$file$n
    # check for shell wild cards and if found add this pattern to the pattern list
    has_wild=`echo $curr_fname | sed -n '/[][?*]/p'`
    if [ -n "$has_wild" ]; then
      if [ -z "$patterns" ]; then
        patterns="$curr_fname"
      else
        patterns="${patterns}:$curr_fname"
      fi
    elif [ -n "$sfx" ]; then
      # Append each suffix to the suppled file name
      for s in $sfx; do
        echo $curr_fname$s >> $flist
      done
    else
      # Use the supplied file name verbatim
      echo $curr_fname >> $flist
    fi
  done
  if [ -n "$patterns" ]; then
    # Assign the variable containing the assignment for cccjob
    dump_sublist_pattern_opt="dump_sublist_pattern='$patterns'"

    # Add a comment to flist indicating that a pattern is also in use
    echo " " >> $flist
    patt_list=`echo $patterns|sed 's/:/   /g'`
    echo "# Patterns to be expanded at run time:   $patt_list" >> $flist
  fi
  [ ! -s $flist ] && bail "The file list is empty"

  if [ $del_nfile -gt 0 ]; then
    # Create a temporary file containing the list of file names to be deleted
    del_flist=qdump$$_del_flist
    rm -f $del_flist
    touch $del_flist
    n=0
    while [ $n -lt $del_nfile ]; do
      n=`expr $n + 1`
      eval curr_fname=\$del_file$n
      # check for shell wild cards and if found add this pattern to the pattern list
      has_wild=`echo $curr_fname | sed -n '/[][?*]/p'`
      if [ -n "$has_wild" ]; then
        if [ -z "$patterns" ]; then
          patterns="$curr_fname"
        else
          patterns="${patterns}:$curr_fname"
        fi
      # elif [ -n "$sfx" ]; then
      #   # Append each suffix to the suppled file name
      #   for s in $sfx; do
      #     echo $curr_fname$s >> $del_flist
      #   done
      else
        # Use the supplied file name verbatim
        echo $curr_fname >> $del_flist
      fi
    done
    if [ -n "$patterns" ]; then
      # Assign the variable containing the assignment for cccjob
      dump_del_sublist_pattern_opt="dump_del_sublist_pattern='$patterns'"
  
      # Add a comment to del_flist indicating that a pattern is also in use
      echo " " >> $del_flist
      patt_list=`echo $patterns|sed 's/:/   /g'`
      echo "# Patterns to be expanded at run time:   $patt_list" >> $del_flist
    fi
    [ ! -s $del_flist ] && bail "The delete file list is empty"
  fi

  if [ -n "$CCCJOB_ROOT" ]; then
    CCCJOB_ROOT_opt='CCCJOB_ROOT=$CCRNSRC/cccjob_dir/beta'
  else
    CCCJOB_ROOT_opt=''
  fi

  sublist_def=qdump$$_sublist_def
  cat > $sublist_def <<EOF
    runid=${runid:=qdump}
    crawork=qdump$$
    $QUIET
    with_lsarc=off
    $sv_opt
    $besc_opt
    $shortermdir_opt
    $cfsuser_opt
    $masterdir_opt
    $vic_opt
    $CCRNTMP_opt
    $RUNPATH_opt
    $BERUNPATH_opt
    $RMTRUNPATH_opt
    $dump_sublist_pattern_opt
    $dump_sublist_maxarcsize_opt
    $dump_sublist_max_files_per_arc_opt
    $CCCJOB_ROOT_opt
EOF

  # Build the batch string
  if [ $del_after_dump -eq 1 ]; then
    if [ -z "$del_flist" ]; then
      del_flist=$flist
    fi
    JOBDESC="dump_sublist=${flist}:s del_list=${del_flist}:s"
  else
    JOBDESC="dump_sublist=${flist}:s"
  fi
  cccjob --out=$outfile --job="$JOBDESC" --stop=1:1 $sublist_def ||
         bail "Unable to create $outfile"
  rm -f $sublist_def

  [ ! -s "$outfile" ] && bail "Empty or missing output file $outfile"

  # Print the list of file to be dumped
  echo "Files to be dumped from $FROM ${TO}:"
  cat $flist
  echo " "
  [ -n "$flist" ] && rm -f $flist

  if [ $del_nfile -gt 0 ]; then
    # Print the list of file to be deleted
    echo "Files to be deleted after dumping the files above:"
    cat $del_flist
    echo " "
  fi
  [ -n "$del_flist" ] && rm -f $del_flist

else
  # Use cccjob::mdump to create the submission job

  # Create a temporary copy of tmplt while we parse tmplt for uxxx/runid/year/month
  usrtmplt=$tmplt

  # It is assumed that the template is of the form ${uxxx}_${runid}_${year}_m${month}
  # where the month field may be missing and if the month is missing then the year
  # field may also be missing

  # Remove any trailing underscore on the template
  tmplt=`echo $tmplt|sed 's/_ *$//'`
  month=`echo $tmplt|\
         awk '{i=match($0,/_m[0-9][0-9]$/);
               if(i>0){s=substr($0,i+2); printf "%d",s}}' -`
  # Strip the month field from the template
  [ -n "$month" ] && tmplt=`echo $tmplt|sed 's/_m[0-9][0-9]$//'`

  # Remove any trailing underscore on the template
  tmplt=`echo $tmplt|sed 's/_ *$//'`
  year=`echo $tmplt|\
        awk '{i=match($0,/_[0-9][0-9]*$/);
              if(i>0){s=substr($0,i+1); printf "%d",s}}' -`
  # Strip the year field from the template
  [ -n "$year" ] && tmplt=`echo $tmplt|sed 's/_[0-9][0-9]*$//'`

  # If month is defined then year must also be defined
  [ -n "$month" -a -z "$year" ] && bail "Missing year in file name template: $usrtmplt"

  # If there are no underscores left in tmplt then it is poorly formed
  have_=`echo $tmplt|sed -n '/_/p'`
  [ -z "$have_" ] && bail "Invalid uxxx/runid in file name template: $usrtmplt"

  # Extract uxxx_def, the first "_" separated field in tmplt,
  # to be used as the default value for uxxx
  uxxx_def=`echo $tmplt|awk '{sub(/_.*$/,""); printf "%s",$0}' -`
  # Strip the uxxx_def field from the template
  eval tmplt=\`echo $tmplt\|sed \'s/\^${uxxx_def}_//\'\`
  uxxx=${uxxx:=$uxxx_def}

  # What is left of the template must be runid
  runid=${runid:=$tmplt}

  # Both uxxx and runid must be defined by now
  [ -z "$uxxx"  ] && bail "uxxx is not defined, check file name template: $usrtmplt"
  [ -z "$runid" ] && bail "runid is not defined, check file name template: $usrtmplt"

  # Reset tmplt to the user supplied value
  tmplt=$usrtmplt

  # Define start and stop
  if [ -z "$start" ]; then
    # The user did not supply start=year:month on the command line
    [ -z "$year" ] && bail "Missing year in file_name_template"
    if [ -z "$month" ]; then
      # Start from the first month of this year
      start=$year
    else
      # Start from a user specified month of this year
      start=${year}:$month
    fi
  fi

  # Define the year/month associated with start
  syear=`echo $start|awk -F: '{printf "%d",$1}' -`
  smonth=`echo $start|awk -F: '{printf "%s",$2}' -`

  if [ -z "$stop" ]; then
    # The user did not supply stop=year:month on the command line
    # Set stop year = start year
    if [ -z "$smonth" ]; then
      # Stop at the last month of this year
      stop=$syear
    else
      # Stop at a user specified month of this year
      stop=${syear}:$smonth
    fi
  fi

  # Define the year/month associated with stop
  xyear=`echo $stop|awk -F: '{printf "%d",$1}' -`
  # If stop does not contain any ":" then set xmonth=12
  xmonth=`echo $stop|awk -F: '{if(NF<2){printf "%s","12"}else{printf "%s",$2}}' -`

  # Reset smonth so that if start does not contain any ":" then set smonth=1
  smonth=`echo $start|awk -F: '{if(NF<2){printf "%s","1"}else{printf "%s",$2}}' -`

  [ "$xyear" -lt "$syear" ] && bail "Stop year = $xyear is less that start year = $syear"

  # Determine the total number of months in the interval between start and stop
  total_months=`echo $syear $smonth $xyear $xmonth|\
                awk '{if ($1<=0 || $3<=0 || $3<$1) {print "0"; exit}
                      if ($2<1 || $2>12 || $4<1 || $4>12) {print "0"; exit}
                      if ($1 == $3) {m=$4-$2+1}
                      else {m=($3-$1-1)*12+13-$2+$4}; printf "%d",m}' -`
  [ $total_months -le 0 ] && \
      bail "total_months=$total_months is out of range. Check start and stop times."

  # Sanity checks on the value of months
  [ -z "$months" ] && bail "months must be assigned a value"
  # Ensure that months is a positive integer
  [ `expr "$months" : '[0-9][0-9]*'` -le 0 ] &&
    bail "months=$months is not a positive integer"

  if [ $months -le 0 ]; then
    # Set the value of months used in the cccjob command below to the total number of
    # months in the interval between start and stop
    months=$total_months
  fi

  # Build the batch string
  cccjob --out=$outfile --job="mdump:s:${months}m" --start=$start --stop=$stop \
         --Override_total_months_check $QUIET mdump_with_lock_file=off with_lsarc=off \
         crawork=qdump$$ uxxx=$uxxx runid=$runid mdump_suffix_list="$sfx" months=$months \
         $sv_opt $besc_opt $shortermdir_opt $cfsuser_opt $masterdir_opt $vic_opt \
         $CCRNTMP_opt $RUNPATH_opt $BERUNPATH_opt $RMTRUNPATH_opt \
         || bail "Unable to create $outfile"
  [ ! -s "$outfile" ] && bail "Empty or missing output file $outfile"

  # Print a list of file names to be dumped by evaluating the submission job
  export FROM TO
  perl -ne '
    BEGIN {$FROM = $ENV{FROM}; $TO = $ENV{TO}}
    # Ignore comment lines other the the "#end_of_job" line
    unless (/^\s*#\s*end_of_job\s*/) {next if /^\s*#/}
    # Ignore lines of the form ". source"
    next if /^\s*\.\s+/;
    # Ignore blank lines
    next if /^\s*$/;
    $job .= $_;
    if (/^\s*#\s*end_of_job\s*/ ) {
      push @JOBS, $job;
      $job = "";
    }
    END {
      # Uncomment the following line to append any lines that
      # may appear following the last "#end_of_job" line
      # if ($job) {push @JOBS, $job};
      $job = "";
      print "Files to be dumped from $FROM ${TO}.\n";
      print "Blank lines within this list indicate a new tdumper job.\n\n";
      foreach $job (@JOBS) {
        $script = q(#!/bin/sh) . "\n" . $job;
        $script .= q(
    nn=0
    while [ $nn -lt $join ]; do
      nn=`expr $nn + 1`
      eval echo \$file$nn
    done);
        @files = `$script`;
        print @files, "\n";
      }
    }
    ' $outfile
fi

if [ $batch_mode -eq 0 ]; then
  # Allow the user to preview before submission
  echo " "
  echo_n "### Preview submission job (y/n) (default n) > "
  read ans
  ans=`echo $ans|sed -n '/^ *[yY]/p'`
  if [ -n "$ans" ]; then
    # Determine which pager to use below
    PAGER=less
    which $PAGER >/dev/null || PAGER=more
    which $PAGER >/dev/null || PAGER=pg
    which $PAGER >/dev/null || bail "Unable to find a pager"
    $PAGER $outfile
  fi
fi

if [ $batch_mode -eq 0 ]; then
  # Query user about immediate submission of this job
  echo " "
  echo_n "### Submit this job now (y/n) (default n) > "
  read ans
  ans=`echo $ans|sed -n '/^ *[yY]/p'`
  if [ -n "$ans" ]; then
    rsub $outfile $sub_mach
  else
    keep=1
  fi
else
  # This is in batch mode so we always attempt to submit and clean up
  rsub $outfile $sub_mach
  keep=0
fi

if [ $keep -eq 0 ]; then
  # Clean up the submission job
  [ -n "$outfile" ] && rm -f $outfile
else
  echo "Batch script $outfile was not submitted but remains on disk."
fi
