#!/bin/sh

###############################################################################
# fmtutil: utility to maintain format files.
#
# Thomas Esser, (C) 1998. Public domain.
#
# Commands:
#  --all                      recreate all format files
#  --missing                  create all missing format files
#  --byfmt formatname         (re)create format for `formatname'
#  --byhyphen hyphenfile      (re)create formats that depend on `hyphenfile'
#  --showhyphen formatname    print name of hyphenfile for format `formatname'
#  --help                     show this message
#
# Options:
#  --cnffile file             set configfile for fmtutil
#  --fmtdir directory         set destination directory for format files
###############################################################################

progname=fmtutil

test -f /bin/sh5 && test -z "$RUNNING_SH5" \
  && { UNAMES=`uname -s`; test "x$UNAMES" = xULTRIX; } 2>/dev/null \
  && { RUNNING_SH5=true; export RUNNING_SH5; exec /bin/sh5 $0 ${1+"$@"}; }
unset RUNNING_SH5

test -f /bin/bsh && test -z "$RUNNING_BSH" \
  && { UNAMES=`uname -s`; test "x$UNAMES" = xAIX; } 2>/dev/null \
  && { RUNNING_BSH=true; export RUNNING_BSH; exec /bin/bsh $0 ${1+"$@"}; }
unset RUNNING_BSH

cnf=fmtutil.cnf   # name of the config file

###############################################################################
# setmatch(match)
#   setting the "match state" to true or false. Used to see if there was at
#   least one match.
###############################################################################
setmatch()
{
  match=$1
}

###############################################################################
# getmatch()
#    return success if there was at least one match.
###############################################################################
getmatch()
{
  test "x$match" = xtrue
}

###############################################################################
# cache_vars()
#   locate files / kpathsea variables and export variables to environment
#    this speeds up future calls to e.g. mktexupd
###############################################################################
cache_vars()
{
  : ${MT_VARTEXFONTS=`kpsewhich --expand-var='$VARTEXFONTS' | sed 's%^!!%%'`}
  : ${MT_TEXMFMAIN=`kpsewhich --expand-path='$TEXMFMAIN'`}
  : ${MT_MKTEXNAM=`kpsewhich --format='web2c files' mktexnam`}
  : ${MT_MKTEXNAM_OPT=`kpsewhich --format='web2c files' mktexnam.opt`}
  : ${MT_MKTEXDIR=`kpsewhich --format='web2c files' mktexdir`}
  : ${MT_MKTEXDIR_OPT=`kpsewhich --format='web2c files' mktexdir.opt`}
  : ${MT_MKTEXUPD=`kpsewhich --format='web2c files' mktexupd`}
  : ${MT_MKTEX_CNF=`kpsewhich --format='web2c files' mktex.cnf`}
  : ${MT_MKTEX_OPT=`kpsewhich --format='web2c files' mktex.opt`}
  : ${MT_LSR_PATH=`kpsewhich  -show-path=ls-R`}
  export MT_VARTEXFONTS MT_TEXMFMAIN MT_MKTEXNAM MT_MKTEXNAM_OPT MT_MKTEXDIR
  export MT_MKTEXDIR_OPT MT_MKTEXUPD MT_MKTEX_CNF MT_MKTEX_OPT MT_LSR_PATH
}

###############################################################################
# help()
#   display help message and exit
###############################################################################
help()
{
  cat <<'eof'
Usage: fmtutil [option] ... cmd [argument]

Valid options:
  --cnffile file
  --fmtdir directory
  --quiet                    (not implemented, just for compatibility)
  --test                     (not implemented, just for compatibility)
  --dolinks                  (not implemented, just for compatibility)
  --force                    (not implemented, just for compatibility)

Valid commands:
  --all                      recreate all format files
  --missing                  create all missing format files
  --byfmt formatname         (re)create format for `formatname'
  --byhyphen hyphenfile      (re)create formats that depend on `hyphenfile'
  --showhyphen formatname    print name of hyphenfile for format `formatname'
  --edit                     edit fmtutil.cnf file
  --help                     show this message
eof
  exit
}

###############################################################################
# abort(errmsg)
#   print `errmsg' to stderr and exit with error code 1
###############################################################################
abort()
{
  echo "$progname: $1." >&2
  exit 1
}

###############################################################################
# main()
#   parse commandline arguments, initialize variables,
#   switch into temp. direcrory, execute desired command
###############################################################################
main()
{
  destdir=     # global variable: where do we put the format files?
  cnf_file=    # global variable: full name of the config file
  cmd=         # desired action from command line
  while
    case $1 in
      --cnffile)
          shift; cnf_file=$1;;
      --cnffile=*)
          cnf_file=`echo "$1" | sed 's/--cnffile=//'`; shift ;;
      --fmtdir)
          shift; destdir=$1;;
      --fmtdir=*)
          destdir=`echo "$1" | sed 's/--fmtdir=//'`; shift ;;
      --all|-a)
          cmd=all;;
      --edit|-e)
          cmd=edit;;
      --missing|-m)
          cmd=missing;;
      --byfmt|-f)
          shift; cmd=byfmt; arg=$1;;
      --byfmt=*)
          cmd=byfmt; arg=`echo "$1" | sed 's/--byfmt=//'`; shift ;;
      --byhyphen|-h)
          shift; cmd=byhyphen; arg=$1;;
      --byhyphen=*)
          cmd=byhyphen; arg=`echo "$1" | sed 's/--byhyphen=//'`; shift ;;
      --showhyphen|-s)
          shift; cmd=showhyphen; arg=$1;;
      --showhyphen=*)
          cmd=showhyphen; arg=`echo "$1" | sed 's/--showhyphen=//'`; shift ;;
      --help|-help)
          cmd=help;;
      --quiet|--test|--dolinks|--force)
          ;;
      "") break;;
      *) echo "$progname: unknown option \`$1' ignored." >&2;;
    esac
  do test $# -gt 0 && shift; done

  case "$cmd" in
    help|"") help;;
  esac
  cache_vars

  # if no cnf_file from command-line, look it up with kpsewhich:
  test -z "$cnf_file" && cnf_file=`kpsewhich --format='web2c files' $cnf`
  test -f "$cnf_file" || abort "config file \`$cnf' not found"

  # showhyphen and edit do not need any temp. directory, so do it here:
  case "$cmd" in
    showhyphen)
      show_hyphen_file "$arg"
      exit $?;;
    edit)
      ${VISUAL-${EDITOR-vi}} $cnf_file
      exit;;
  esac

  # set up destdir:
  test -z "$MT_TEXMFMAIN" && abort "could not expand variable \$TEXMFMAIN"
  if test -z "$destdir"; then
    : ${VARTEXMF=`kpsewhich -expand-var='$VARTEXMF'`}
    test -z "$VARTEXMF" && VARTEXMF=$MT_TEXMFMAIN
    destdir=$VARTEXMF/web2c
  fi
  test -d "$destdir" || abort "format directory \`$destdir' does not exist"

  # find mktexupd script:
  test -n "$MT_MKTEXUPD" || MT_MKTEXUPD="$TEXMFMAIN/web2c/mktexupd"

  thisdir=`pwd 2>/dev/null`
  if test -n "$thisdir"; then
    : ${KPSE_DOT=$thisdir}
    TEXINPUTS="$thisdir:$TEXINPUTS"
  fi
  tmpdir=${TMP-/tmp}/$progname.$$
  trap 'cd /; cd "$thisdir"; rm -rf "$tmpdir"; exit 0' 0 1 2 3 7 13 15
  mkdir "$tmpdir" || abort "could not create directory \`$tmpdir'"
  cd "$tmpdir" || exit 1

  # make local paths absolute:
  case "$destdir" in
    /*) ;;
    *)  destdir="$thisdir/$destdir";;
  esac
  case "$cnf_file" in
    /*) ;;
    *)  cnf_file="$thisdir/$cnf_file";;
  esac


  # execute the desired command:
  case "$cmd" in 
    all)
      recreate_all;;
    missing)
      create_missing;;
    byfmt)
      create_one_format "$arg";;
    byhyphen)
      recreate_by_hyphenfile "$arg";;
  esac

  # install the log files and format files:
  for i in *.log; do
    test -f "$i" || continue
    rm -f "$destdir/$i"
    mv "$i" "$destdir/$i"
  done
  for i in *fmt; do
    test -f "$i" || continue
    rm -f "$destdir/$i"
    mv "$i" "$destdir/$i" \
      && echo "$progname: $destdir/$i successfully generated." >&2
    $MT_MKTEXUPD "$destdir" "$i"
  done
  if test -f "$destdir/tex.fmt" && test ! -f "$destdir/plain.fmt"; then
    ln -s tex.fmt "$destdir/plain.fmt"
    $MT_MKTEXUPD "$destdir" plain.fmt
  fi
  if test -f "$destdir/tex.efmt" && test ! -f "$destdir/plain.efmt"; then
    ln -s tex.efmt "$destdir/plain.efmt"
    $MT_MKTEXUPD "$destdir" plain.efmt
  fi
}

###############################################################################
# parse_line(config_line) sets global variables:
#   format:  name of the format, e.g. pdflatex
#   engine:  name of the TeX engine, e.g. tex, etex, pdftex
#   texargs: flags for initex and name of the ini file (e.g. -mltex frlatex.ini)
#   fmtfile: name of the format file (without directory, but with extension)
#
# exit code: returns error code if the ini file is not installed
###############################################################################
parse_line()
{
  format=$1
  engine=$2
  hyphenation=$3
  shift; shift; shift
  texargs="$@"

  eval lastarg=\$$#
  inifile=`echo $lastarg | sed 's%^\*%%'`

  case "$engine" in
    *etex) fmtfile="$format.efmt";;
    *)     fmtfile="$format.fmt";;
  esac

  # See if we can find $inifile for return code:
  kpsewhich -progname=$format -format=tex $inifile >/dev/null 2>&1
}

###############################################################################
# find_hyphenfile(format, hyphenation) searches for hyphenation along
#                                      searchpath of format
# exit code: returns error is file is not found
###############################################################################
find_hyphenfile()
{
  format="$1"; hyphenation="$2"
  kpsewhich -progname="$format" -format=tex "$hyphenation"
}

###############################################################################
# find_info_for_name(format) 
#   Look up the config line for format `format' and call parse_line to set
#   global variables.
###############################################################################
find_info_for_name()
{
  format="$1"

  set x `awk '$1 == format {print; exit}' format="$format" "$cnf_file"`; shift
  test $# = 0 && abort "no info for format \`$format'"
  parse_line "$@"
}

###############################################################################
# run_initex()
#   Calls initex. Assumes that global variables are set by parse_line.
###############################################################################
run_initex()
{
  # use -efmt=xxx for e-TeX and -fmt=xxx for other engines:
  case "$engine" in
    *etex) fmtswitch="-efmt=$format";;
    *)     fmtswitch="-fmt=$format";;
  esac

  case "$format" in
    cont-??) prgswitch=-progname=context;;
    *)       prgswitch=-progname=$format;;
  esac

  rm -f $fmtfile
  $engine -ini $fmtswitch $prgswitch $texargs </dev/null
  test -f $fmtfile || {
    abort "\`$engine -ini $fmtswitch $prgswitch $texargs' failed"
    rm -f $fmtfile
  }
}

###############################################################################
# recreate_loop(hyphenfile)
#   for each line in config file: check match-condition and recreate format
#   if there is a match
###############################################################################
recreate_loop()
{
  OIFS=$IFS
  IFS='
'
  set `echo x; sed '/^#/d; /^[ 	]*$/d' "$cnf_file"`; shift
  IFS=$OIFS
  for line in "$@"; do
    parse_line $line || continue
    check_match || continue
    echo; echo
    run_initex
  done
}

###############################################################################
# check_match()
#   recreate all formats
###############################################################################
check_match()
{
  this_hyphenfile=`find_hyphenfile "$format" "$hyphenation"`
  eval $match_cmd && setmatch true
}

###############################################################################
# create_one_format(fmtname)
#   (re)create the format file for the format `fmtname'
###############################################################################
create_one_format()
{
  fmtname=$1

  find_info_for_name $fmtname || abort "format \`$fmtname' not available"
  run_initex
}

###############################################################################
# create_missing()
#   create all missing format files
###############################################################################
create_missing()
{
  match_cmd='test ! -f $destdir/$fmtfile'
  recreate_loop
}

###############################################################################
# recreate_all()
#   recreate all formats
###############################################################################
recreate_all()
{
  match_cmd=true
  recreate_loop
}

###############################################################################
# recreate_by_hyphenfile(hyphenfile)
#   recreate all formats that depend on hyphenfile
###############################################################################
recreate_by_hyphenfile()
{
  hyphenfile=$1

  match_cmd="test x\$this_hyphenfile = x$hyphenfile"

  # No match before the loop:
  setmatch false

  recreate_loop

  # Now check if there was at least one match:
  getmatch || abort "no format depends on \`$hyphenfile'"
}


###############################################################################
# show_hyphen_file(format)
#   prints full name of the hyphenfile for format
#
# exit code: returns error code if the ini file is not installed or if
#            the hyphen file cannot be found
###############################################################################
show_hyphen_file()
{
  fmtname=$1

  find_info_for_name "$fmtname" || abort "no info for format \`$fmtname'"
  if test "x$hyphenation" = x-; then
    echo -
    exit 0
  fi
  find_hyphenfile "$format" "$hyphenation" || abort "hyphenfile \`$hyphenation' not found"
}

main "$@"
