#!/bin/bash
 version=3.05
  myname=$(basename $0)

<<'DOC'
= mk - a TeX and LaTeX maker

= Synopsis
mk [options] [file]	

mk-specific options:
-C, --Clean		Remove all unnecessary files generated by latex and bibtex
-c, --clean		Same, except for the pdf or postscript files
    --ps		Generate postscript version of document (default: pdf)
-e, --edit=STRING	use STRING as the file to be edited

vpp-related options:
-b, --batch=STRING	run in batch using STRING for print command
-p, --printer=STRING	print to printer named STRING
-d, --doublesided	printer is double sided
    --[no]view		do [not] view the document
    --[no]print		do [not] offer printing interaction

General options:
-r, --rc=STRING		use STRING as an rc file, instead of |~/.mkrc|.
    --norc		don't read the |~/.mkrc| file
-V, --version		print version and exit
-v, --[no]verbose	be [not] verbose (quiet is the default)
-h, --help		print this help and exit
-H, --Help		print full documentation via less and exit

Defaults:
    --print --view --noverbose main

Required other programs:
- /bash/ >=4.00
- /vpp/ >=3.00 (CTAN)
- /texi2dvi/ >= 1.152 (CTAN or /texinfo/ package)
- /tex/ and friends (CTAN or /texlive/ package)

= Description
mk is a Bash script that, in close collaboration with vpp (short for View
and Print PDF/PostScript), is helpful in the cyclic process of editing, compiling,
viewing, and printing a latex, xelatex, or plain tex document. Essentially,
mk uses texi2dvi for compilation, vpp for viewing and printing.

Having an existing LaTeX document, say |main.tex| (see the section
/Locating the source/ for the creation of new documents and for other
extensions than |.tex|), you run mk by typing:

    $ mk main

or, since /main/ happens to be mk's default filename:

    $ mk

Now, if |main.tex| is a valid LaTeX source, mk compiles it,
including any table of contents, indices, bibliography references, included
files, and so on, and /vpp/ takes over and displays the resulting /PDF/ or,
with the |--ps| option, /PostScript/ output. When you leave the viewer you
will see a prompt:

    vpp command (h for help):

If you are satisfied with the displayed output, you can now decide to print
all or part of your document (see the section /Page selection/), or you can
simply quit by typing 'q'. On the other hand, if you decide that you want
to change the source and have another try, you can edit the source by
typing 'e' to get back to mk and (re)edit your source. After saving your
work and leaving your editor, another compilation and display cycle will be
performed, based on the new source.

Essentially, mk uses /texi2dvi/ for compilation. /texi2dvi/
always runs TeX at least once, even though this may be unnecessary.
Therefore, TeX will be run with the |--recorder| option, which reports all
the target's dependencies in a .fls file. In every cycle, mk analyzes the
.fls and the tex and bibtex .log files to see if a compilation is needed.
When errors have occurred, mk uses the log files to find out which file
has to be edited, and at which line. This can also be an |\input|ed file, a
style file, or any other file on which the target depend. However, files in
the TEXMFMAIN tree are excluded.

= Editor

vpp uses the contents of environment variable EDITOR to find your editer.
If that variable is empty, /vim/ is used. Note that your editor should not
fork off your shell, so if you specify /gvim/, for example, specify it with
the option |--force|.

= Page selection

As said in the introduction, after a successful compilation and display of
the resulting /PDF/ or /PostScript/ output, the user is prompted with:

    vpp command (h for help):

on typing 'h' /vpp/ displays examples of possible commands:

   Examples of print commands:
       5       to print page 5
       5-      to print pages 5 through the end
       5-7     to print pages 5, 6 and 7
       -7      to print the first 7 pages
       5-7,19- to print pages 5, 6, 7 and 19 through the end
       a       to print the whole document
       -       to print the whole document
       a x3    to print 3 copies of the document
       x3      the same
       5 x3    to print 3 copies of page 5
       t       print the whole document two sided
       t 2-    print two sided starting at page 2
       b       to print the whole document as an a5 size booklet
       b -12   to print the first 12 pages as an a5 size booklet
   Other commands:
       e       (if called by mk) edit the tex source and rerun mk
       c       (if called by mk) rerun mk
       v       (re)view the ps/pdf file
       oxyz    send pdf output to file xyz.pdf instead of printer
       pxyz    print to printer xyz
       dx      tell vpp printer is doublesided (x=t) or singlesided (x=f)
       h       display this help
       ?       display this help
       q       quit

With these examples, no further explanation should be necessary, except
that, when twosided (|t|) or booklet (|b|) printing is selected for a
single-sided printer, printing will be performed in two shifts, one for
the front side and one for the backside. Between the shifts, another
prompt appears:

    printer ready? then turn stack and type return

You will have to arrange your printer such that, with the printed sides up,
the first page printed will be at the bottom of the stack, and the last
page printed will be on top. Normally you will then have your output come
out the back of your printer. 'Turn the stack' then means: rotate it over
the long side of the paper and feed it back into the printer for the other
side to be printed.

For further information on /vpp/, look in its manpage by typing

    $ vpp --help

or read the /vpp/ documentation.

= Locating the source

mk locates the LaTeX source in several steps: (here the source extension
|.tex| is supposed, but |.ltx|, |.drv| and |.dtx| will also be tried)

- If you supply no arguments, the file |main.tex| in the current directory
  is assumed.
- If you supply an argument (say /myfile/), mk adds a |.tex| extension if
  it isn't there and looks for |myfile.tex| in the current directory.
- If |myfile.tex| is not found in the current directory, mk looks
  in the 'alternate directory' (say |/Documents|) if you have
  defined one (see the section 'RC files').
- If the source was not found in |/Documents|, mk thinks that you may have
  a subdirectory /myfile/ in |/Documents| where the source may live under
  the name |main.tex|
- If that file is not there, mk now concludes that the source does not
  yet exist and reports this, telling at the same time which files have
  been tried.
- Finally, if all the above did not lead to a source file, mk dies.

= The TeX format to be used

mk will try to find out what TeX format is is needed to compile the source.
The most straightforward way to tell mk what format to use is to insert a
starting comment line which starts with |%!|, followed by the name of the
tex engine to use; for example:

    %!xelatex

If no such line is found, mk looks for a |\usepackage{fontspec}| or
|\RequirePackage{fontspec}| and, if found, uses /xelatex/. The
|\usepackage| may have options, but they must be on the same line.

If still no decision could be made, mk looks for |\documentclass| and
chooses /pdflatex/ or, with the |--ps| option, /latex/

Finally, if no match was found, /pdftex/ is assumed or, with the
|--ps| option, |tex|.

= Options

mk comes with several options. Before evaluating any options, mk will
try to read a system rc file, a user rc file, and, finally an rc file in
the current directory. The default values for most options can be set in
these files. See the section 'RC files' for more information.

You can also set option defaults in an alias. For example:

    $ alias mk='mk -noverbose'

--help	
	Prints help information and lets you type 'm' to display the complete man
	page or anything else to quit.
--version	
	Prints name and version and then quits.
--quiet	
	Suppresses messages about the progress mk is making. This is the
	default.
--rc=file	
	execute the specified /file/ before processing. The contents of
	the /file/ may override options specified before the |--rc|
	option, therefore it is a good idea to have the habit of specifying the
	|--rc| option first.
--norc	
	do not read the |~/.mkrc| file, even if it exists.
--batch=string	
	Prevents the |--print| option to interrogate the user about pages
	to be printed. Instead the document is printed according to the mandatory
	/string/. Also sets viewing off. Thus the command
	   mk --batch '2-3 x3' test
	prints 3 copies of pages 2 and 3 of |test.tex|, without viewing.
--clean	
	Clean up (remove) all unnecessary files generated by /latex/ and /bibtex/
	except for the /PDF/ or /PostScript/ files.
--Clean	
	Clean up (remove) all unnecessary files generated by LaTeX and /bibtex/
	including the /PDF/ or /PostScript/ files.
--print	
	Present the print prompt. This is the default. This option is normally
	used to suppress the print prompt, for example when using mk from other
	scripts that generate LaTeX documents that have only to be displayed or
	stored without even being displayed.
--ps	
	Generate /PostScript/ version of document. The default is to generate a
	/PDF/ document.
--view	
	Run the file viewer. This is the default. This option is normally used to
	suppress starting the viewer, for example when using mk from other
	scripts that generate LaTeX documents that have only to be printed.
--edit=file	
	Normally, mk lets you edit the main source file, but here you can
	specify another file to be edited instead. This is useful, for example,
	if you are are fixing a style file or another input file.

= RC file and customization

Unless the option |--norc| has been used, the file |~/.mkrc| will be sourced,
if it exists, before reading the command line options.

You can use this rc file to set the default values for the options, by
setting the global shell variable named after the long version of the
options. For example:

    verbose=true # run in verbose mode

So if you usually like mk to work in verbose mode, you can indicate so in
your rc file and change your mind in some cases by using the
|--noverbose| option.

Other variables, not having a corresponding command line option, that can
be set in the rc files, and their default values, are:

extraoptions=	
	adds one or more extra options to the /tex/ (/latex, xelatex/ et
	cetera) command. Example: |extraoptions='-shell-escape -quiet'|
othercleans=	
	can be set to a file regular expression; in the cleaning operation, 
	caused by the |--clean| option, this variable wil be eval'ed, and the
	resulting files will be removed. This is useful, for example, when the 
	|gnuplottex| package is used; this package generates intermediate files
	named |$base-gnuplottex-fig*|, where the variable |$base| contains the
	basename (without extension) of your tex source file. So after adding:
	    othercleans='${base}-gnuplottex-fig*'
	to your |./mkrc| file, the cleaning operation will get rid of these
	files, too.
texi2dviquiet=false	
	Normally, in verbose mode, you also see the complete tex log output,
	because texi2dvi will be verbose, too. This obscures most other
	output. You can keep texi2dvi quiet in verbose mode by setting this
	variable to true:
	   texi2dviquiet=true
skip_pattern=	
	can be set to a file wild card pattern. Files matching this pattern on
	which the /(la)tex/ source file may depend will not be checked for changes.
	For example, if you use a write-protected TeX-tree in the directory
	mytextree it makes sense to set |skip_pattern=mytextree|
	unless you set |skip_pattern| explicitly, it will be set to match the
	TEXMFMAIN tree.
altdir=	
	If |altdir| is non-empty and a file to be compiled does not exist in the
	current directory, it will be given another try after prefixing it with
	the contents of |altdir|. So if you like to have your LaTeX file in
	|/Documents/myfile.tex| you can set |altdir| to |/Documents| and run
	mk from any directory with:
	   $ mk myfile
	However, a directory like |/Documents| does not make much sense if
	many of your LaTeX documents do not consist of a single file, but are
	constituted of an ensemble of a main LaTeX source and one or more
	|\include|d and |\input|ed files such as graphics. You will then probably
	prefer to have a subdirectory in |/Documents| for every LaTeX
	document. Therefore, if mk does not find |myfile.tex| in the
	alternate directory, it will assume that /myfile/ is a
	subdirectory with a main LaTeX source in it, called |main.tex|.
default=main	
	This is the default for the base name of your LaTeX document.
warnings_to_skip=()	
	Warnings appearing in the log file will be reported after a
	successful run. Warnings matching any of the rexgexp's in this
	array will be skipped, however. For example, one could enter here:
	    warnings_to_skip=(
	      'Package hyperref Warning: Token not allowed in a PDFDocEncoded string',
	      'Package array Warning: Column [XY] is already defined on '
	    )
	The first message appears when the /hyperref/ package is used and section
	titles contain LaTeX-commands, the second message appears when
	the /ctable/ package is used, because it intentionally changes the X and
	Y column specifiers.

= TeXWorks and mk

mk can be used for one-click typesetting:

- edit -> preferences -> Typesetting
- add a new tool `mk' and give it three parameters:
    --noview
    --noprint
    $basename
- Deselect "Auto-hide output panel unless errors occur"

mk runs pdflatex with the |--synctex=1| option, so you will be
able to jump betwee source and pdf-ouput.

= Bugs
Currently, mk is only available for Linux. It depends on /texi2dvi/.
Spaces in the basename of TeX sources are not allowed (neither does the
texi2dvi script on which mk is based.)

= Changes
Changes with respect to version 3.01:
- let vpp save its output in the working directory
- removed crappy version testing on texi2dvi - use texi2dvi from the /texinfo/ package

= Author and copyright
Author	Wybo Dekker
Email	U{Wybo@dekkerdocumenten.nl}{wybo@dekkerdocumenten.nl}
License	Released under the U{www.gnu.org/copyleft/gpl.html}{GNU General Public License}
DOC

    die() { echo -e "$myname: $Err$@$Nor"; exit 1; } 1>&2
   Warn() { echo -e "$myname: $War$@$Nor"; } 1>&2
   warn() { $verbose && Warn "$@"; }
   help() { sed -n '/^= Synopsis/,/^= /p' $0|sed '1s/.*/Usage:/;/^= /d'; exit; }
helpall() { sed -n '/^<<.DOC.$/,/^DOC$/p' $0|sed -n '1d;$d;p'|less; exit; }
version() { echo $version; exit; }
install() { which instscript>&/dev/null && instscript -zp $myname; exit; }

Err='\e[31;1m' # light red	]
Fil='\e[33m'   # brown		]
Com='\e[34;1m' # light blue	]
Lin='\e[32;1m' # light green	]
War='\e[35;1m' # light magenta	]
Nor='\e[0m'    # reset color	]
test ${BASH_VERSINFO[0]} -ge 4 || die "Need bash version >= 4 (you have $BASH_VERSION)"

<<'DOC' #------ function findsource --------------------------------------------
= findsource
parameters	the script's first and only argument, maybe nil
description	find the file to be compiled; if the argument is:
		   nil:     main.{tex,ltx,drv.dtx}
		   xxx:     {xxx,xxx/main,$altdir/xxx/main}.{tex,ltx,drv.dtx}
		   xxx.ext: {.,$altdir}/xxx.ext 
globals set:	   base dir ext fullpath
globals used:      IFS PWD altdir default 
returns:	0 on succes, 1 otherwise
DOC
#-------------------------------------------------------------------------------
findsource() {
   local arg=${1%.} 			# remove final . (may be there by auto completion)
   local file=${arg##*/}		# remove path
   dir=${arg:0:${#arg}-${#file}}	# get the directory's full path
   dir=${dir%/}				# remove final /
   base=${file%.[^.]*}			# remove (last) extension (a.b.c -> a.b)
   ext=${file:${#base} + 1}

   # check ext:
   local i ok=false
   for i in '' tex ltx drv dtx; do test "$ext" = "$i" && ok=true; done
   $ok || echo "unrecognized extension ($ext)"

   if [ -n "$base" -a -z "$dir" ]; then
      # if a basename was specified, but dir is empty, look for the source in
      # the current dir or, if absent there, in the alterative dir
      dir=("$PWD" "$altdir")
      # if there is no extension, we first look for $base.{tex,ltx,drv,dtx}, then
      # for $base/main.{tex,ltx,drv,dtx}
      test -z "$ext" && base=("$base" "$base/$default")
   fi

   : ${base:=$default}
   : ${dir:=$PWD}
   test -z $ext && ext=(tex ltx drv dtx)

   fullpath=
   local tried=() found=false
   for d in "${dir[@]}"; do
      for b in "${base[@]}"; do
         for e in tex ltx drv dtx; do
            fullpath="$d/$b.$e"
            test -e "$fullpath" && { found=true; break 3; }
            tried+=("$fullpath")
         done
      done
   done

   $found || { 
      Warn "Not found; I tried:"
      for i in "${tried[@]}"; do echo "$i"; done
      die "Giving up!"
   }
   warn "source: $fullpath"
   dir="${fullpath%/*}"
   ext="${fullpath##*.}"
   base="${fullpath:${#dir}+1:${#fullpath}-${#ext}-${#dir}-2}"
}

<<'DOC' #------ function run --------------------------------------------
= run
parameters:	command to be run, with its parameters
description:	Run a command; show what's run if |$verbose|.
		If the command exits with 1, that's considered an error,
		other values have a special meaning and are supposed to be a
		success
globals  set:	    
globals used:	    Com Err Lin Nor
returns:	the exit value of the command
DOC
#-------------------------------------------------------------------------------
run() {
   eval "$@"
   local ev=$?
   test $ev -eq 1 &&
      warn "$Nor${Fil}sys call: $Com$1$Err - failed" ||
      warn "$Nor${Fil}sys call: $Com$1$Lin - succeeded$Nor, exit status=$Err$ev"
   return $ev
}

<<'DOC' #------ function settexdeps --------------------------------------------
= settexdeps
parameters:	-
description:	Scans |$base.fls| for tex dependencies and places those in the
		array texdeps. Any dependencies with future timestamps are
		touched in order to prevent mk from looping.
globals  set:	    texdeps
globals used:	    base PWD skip_pattern
returns:	0
DOC
#-------------------------------------------------------------------------------
settexdeps() {
   texdeps=()
   local fls="$base.fls" n=0 c f
   test -e "$fls" || {
      warn "no file $fls in $PWD"
      return
   }
   while IFS=' ' read c f; do
      let n++
      [[ $n == 1 && $c != PWD ]] && die "$fls is not a TeX fls file"
      [[ $c == INPUT && ! $f =~ $skip_pattern ]] && texdeps+=($f)
   done <$fls
   texdeps=($(echo ${texdeps[@]}|xargs -n1|sed 's/^\.\///'|sort -u))

   local tmp=$(tempfile)
   warn "tex dependencies:"
   for i in ${texdeps[@]}; do
      warn "\t$i"
      if [[ $i -nt $tmp ]]; then
         Warn "Touching file with future filestamp: $i"
         touch "$i"
      fi 
   done
   rm $tmp
}

<<'DOC' #------ function setbibdeps --------------------------------------------
= setbibdeps
parameters:	-
description:	Scan aux file (|$base.aux|) for bib-files needed and places those
		in the array bibdeps. Any dependencies with future timestamps are
		touched in order to prevent mk from looping.
globals  set:	    bibdeps
globals used:	    base
returns:	-
DOC
#-------------------------------------------------------------------------------
setbibdeps() {
   local aux="$base.aux" i tmp=$(tempfile)
   test -e "$aux" || return
   bibdeps=($(sed -n '
        /\\bibdata{.*}/{
          s/.*\\bibdata{\(.*\)}.*/\1/   # a.bib,b,c.bib
          s/\.bib//g                    # a,b,c
          s/,/ /g                       # a b c
          p
        }' "$aux"))
   [[ ${#bibdeps[@]} > 0 ]] || return

   for i in ${!bibdeps[@]}; do
      local b=${bibdeps[i]}.bib
      # replace each bib with its full path found by kpsewhich
      bibdeps[i]=$(kpsewhich "$b") || die "bib file $b not found"
   done
   bibdeps=($(echo ${bibdeps[@]}|xargs -n1|sed 's/^\.\///'|sort -u))

   local tmp=$(tempfile)
   warn "bib dependencies:"
   for i in ${bibdeps[@]}; do
      warn "\t$i"
      if [[ $i -nt $tmp ]]; then
         Warn "Touching file with future filestamp: $i"
         touch "$i"
      fi 
   done
   rm $tmp
}

<<'DOC' #------ function compile --------------------------------------------
= compile
parameters:	-
description:	runs the command in |texcommand|
globals  set:	-
globals used:	    base bibdeps target texcommand texdeps 
returns:	0 on success, else 1
DOC
#-------------------------------------------------------------------------------
compile() {
   local exitvalue=1 i go success
   while true; do
      # If there is an .fls file, and the target is there, then compile only if
      # there are texdeps or bibdeps that are newer than target.
      # If there are bibdeps newer than target, remove .bbl, forcing texi2dvi to run bibtex
      # Returns true if a compilation was actually performed.
      go=false
      if [ -e "$base.fls" -a -e "$target" ]; then
         setbibdeps
         settexdeps
         for i in ${bibdeps[@]}; do
            if [ $i -nt "$target" ]; then
               rm -f $base.bbl
               warn "newer than target: $i"
               go=true
               break
            fi
         done
         if ! $go; then
            for i in ${texdeps[@]}; do
               if [ $i -nt "$target" ]; then
                  warn "newer than target: $i"
                  go=true
                  break
               fi
            done
         fi
      else
         go=true
      fi
      $go || break
      rm -f "$target" # if compilation generates no output, we want to be able to detect that
      run "$texcommand" && success=true || success=false
      # texi2dvi claims to be successful if it produces no output:
      [[ -e "$target" ]] || success=false
      settexdeps
      setbibdeps
      $success || show_error_and_edit
      exitvalue=0
   done
   return $exitvalue
}

<<'DOC' #------ function show_error_and_edit --------------------------------------------
= show_error_and_edit
parameters:	-
description:	Show compilation errors via texlog_extract and (unless edit is empty)
		edit the source file where the error is in, opening the editor at the line
		where the error is..
globals  set:	    IFS
globals used:	    Lin base bibdeps edit target warnings_to_skip 
returns:	0
DOC
#-------------------------------------------------------------------------------
show_error_and_edit() {
   local m n i errorfile linenum
   test -e $target -a -n "$edit" && rm -f $target

   warn ${Lin}warnings_to_skip:
   for i in "${warnings_to_skip[@]}"; do warn "\t$i"; done

   IFS=$'\n' m=($(texlog_extract $base))
   n=true
   for i in ${m[@]}; do
      if $n; then
         IFS=$' ' read linenum errorfile <<< $i
         n=false
      else
          echo "$i"
      fi
   done

   test -z $edit && exit

   : ${errorfile:=$edit}
   errorfile="${errorfile%%[\{ ]*}" # remove {...} and spaces at the end
   if [[ $errorfile == *.bbl ]]; then
      rm -f "$errorfile"
      if [[ ${#bibdeps[@]} > 1 ]]; then
         Warn "Look in your bibliography file(s)"
         select i in ${bibdeps[@]}; do edit "$i" 1 true && exit; break; done
      else
         edit "${bibdeps[0]}" 1 true && exit
      fi
   else
      edit "'$errorfile'" $linenum true && exit
   fi
}

<<'DOC' #------ function edit --------------------------------------------
= edit
parameters:	1 file to be edited; if empty: contents of edit variable is used
		2 line number where edit should start; if empty, use 1
		3 true if an error was detected in the file and user must decide 
		if file shall be edited 
description:	Start the user's editor to edit the file in argument 1; if the 
		call was induced by the detection of an error in that file, the
		user will be asked if he want to edit the file, or to quit.
globals  set:	-
globals used:	    edit
returns:	1 if the file was edited, else 0
DOC
#-------------------------------------------------------------------------------
edit() { # edfile,linenum,error
   local edfile="$1" linenum=$2 error=$3
   if $error; then
      Warn "error in $edfile"
      test -t 1 || return 0 # return if stdout is not to a terminal
      while true; do
         echo -n "=====> e(dit) q(uit) "
         read x
         case "$x" in
         (q) return;;
         (e) break;;
         (*) echo you must type e or q
         esac
      done
   fi
   : ${linenum:=1}
   : ${edfile:=$edit}
   test -e $edfile || edfile=$edit # this happens when tex finds unexpected EOF
   eval "$EDITOR +$linenum $edfile"
   return 1
}

<<'DOC' #------ function handle_options --------------------------------------------
= handle_options
parameters:	uses script's arguments
description:	Handles the options
globals  set:	    Clean batch clean doublesided dvips edit input norc print
		    printer ps rc verbose view
globals used:	    HOME verbose
returns:	0
DOC
#-------------------------------------------------------------------------------
handle_options() {
   local options
   if ! options=$(getopt \
      -n $myname \
      -o Cce:b:p:dvr:hHVI \
      -l Clean,clean,ps,edit:,batch:,printer:,doublesided,view,noview,print,noprint,verbose,noverbose,rc:,norc,help,Help,version -- "$@"
   ); then exit 1; fi
   eval set -- "$options"
   while [ $# -gt 0 ]; do
      case $1 in
      # mk specific options:
      (-C|--Clean)	 Clean=true;	shift;;
      (-c|--clean)	 clean=true;	shift;;
      (   --ps)		 ps=true;	shift;;
      (-e|--edit)	 edit=${2/\~/$HOME};	shift 2;;
      # vpp-related options:
      (-b|--batch)	 batch=$2;	shift 2;;
      (-p|--printer)	 printer=$2;	shift 2;;
      (-d|--doublesided) doublesided=true;  shift;;
      (   --view)	 view=true;	shift;;
      (   --noview)	 view=false;	shift;;
      (   --print)	 print=true;	shift;;
      (   --noprint)	 print=false;	shift;;
      # General options:
      (-v|--verbose)	 verbose=true;	shift;;
      (   --noverbose)	 verbose=false;  shift;;
      (-r|--rc)		 rc=$2;		shift 2
                            test -e $rc ||
   			 die "RC-file $rc, given with the --rc option, does not exist"
   			 ;;
      (   --norc)	 norc=true;	shift;;
      (-h|--help)    	 help;;
      (-H|--Help)    	 helpall;;
      (-V|--version) 	 version;;
      (-I)           	 install;;
      (--)		 shift;	break;;
      (*)		 break;;
      esac
   done
   # verbose is now set:
   $verbose || dvips='dvips -q'
   # remaining argument, if any, is the input file:
   input="$@"
}

# if --rc was used, source its argument
# if not, execute ~/.${myname}rc if it exists

<<'DOC' #------ function read_rc --------------------------------------------
= read_rc
parameters:	-
description:	If the |--norc| option was used, does nothing. Otherwise, sources
		the file in variable |rc|; if that is empty, use the ~/.mkrc if
		it exists.
globals  set:	-
globals used:	    HOME myname rc
returns:	0
DOC
#-------------------------------------------------------------------------------
read_rc() {
   : ${rc:=$HOME/.${myname}rc}
   [[ -n $rc && -s $rc ]] && { warn "Sourcing $rc"; . $rc; }
}

# do we have all executables needed?

<<'DOC' #------ function check_needs --------------------------------------------
= check_needs
parameters:	-
description:	Checks if all executables neede are available.
globals  set:	    EDITOR
globals used:	    EDITOR print ps view
returns:	1 if there are missing executables, else 0
DOC
#-------------------------------------------------------------------------------
check_needs() {
   local j i needed=(kpsewhich texi2dvi)
   $ps && needed+=(dvips latex) || needed+=(pdflatex)
   $print || $view && needed+=(vpp)
   for i in ${!needed[@]}; do
      which ${needed[$i]} >/dev/null && unset needed[$i]
   done
   [[ ${#needed[@]} > 0 ]] && die "missing executables: ${needed[@]}"
   # test texi2dvi's version:
   i="$(texi2dvi -v |grep ^texi2dvi|tr -dc '[\ 0-9]' | sed 's/.* //')"
   test "$i" -ge 1166 ||
      die "Your texi2dvi is too old ($i);$Nor Get a new version with:\n$Com"\
          "   wget ftp.gnu.org/gnu/texinfo/texi2dvi && chmod 755 texi2dvi$Nor\n"\
          "   and move texi2dvi to a directory in your PATH."
   # make sure we have an editor
   : ${EDITOR:=vim}
}

          altdir=.
           batch=
           Clean=false
           clean=false
        cleanext=(tui tuo chk dvi log ent fls aux bbl blg hd ilg toc lof lot idx ind out glo gls tmp synctex.gz)
     compileexit=98
         default=main
     doublesided=false
           dvips=dvips
            edit=
        editexit=99
           latex=
            norc=false
        pdflatex=
           print=true
         printer=
              ps=false
              rc=
             sep="\n"
    skip_pattern=
   texi2dviquiet=false
         verbose=false
            view=true
warnings_to_skip=()

[[ $@ =~ --norc ]] || read_rc
handle_options "$@"

check_needs

vppoptions=--mk
    $verbose && vppoptions+=" --verbose"
$doublesided && vppoptions+=" --doublesided"
test "$printer" = "" || vppoptions+=" --printer=$printer"

if [[ -n $batch ]]; then
   view=false
   j=($batch)
   for i in ${j[@]}; do
      echo $i
      #                                                                  v--meer?--v
      [[ $i =~ ^(q|b|t|a|x[0-9]+|([0-9]+-?[0-9]*|[0-9]*-?[0-9]+),?)+$|^o[a-zA-Z0-9_-]+$ ]] ||
         die "Illegal argument ($i) in --batch argument ($batch)\n"\
             "use q if you want no printout"
   done
   vppoptions+=" --batch='$batch'"
   [[ $batch == *q ]] && print=false
fi

# default skip pattern:
: ${skip_pattern:=^$(kpsewhich --expand-var '$TEXMFMAIN')}

: ${clean:=$clean}
   $ps && targetext=dvi vpptargetext=ps || targetext=pdf vpptargetext=pdf
$print && vppoptions+=" --print"        || vppoptions+=" --noprint"
 $view && vppoptions+=" --view"         || vppoptions+=" --noview"

findsource "$input"

target=$base.$targetext
vpptarget=$base.$vpptargetext

trap "rm -rf $base.t2d" 0 1 2 15

: ${edit:=$fullpath}
if [ -n "$edit" ]; then # if '', then no editing
   test -e "$edit" || die "can't find source file ($edit)"
   test -r "$edit" || die "can't read source file ($edit)"
   test -w "$edit" || die "can't write source file ($edit)"
fi

pwd=$(pwd)
cd "$dir"

if $clean || $Clean; then
   for i in ${cleanext[@]}; do
      rm -f $base.$i
   done
   eval "othercleans=$othercleans"
   for i in $othercleans; do rm -f $i; done
   if $Clean; then
      # It may be useful to protect target, in order to prevent that they become
      # recompiled with changed style files:
      for i in $(echo $target $vpptarget | xargs -n1 |sort -u); do
         if [ -e $i -a ! -w $i ]; then
            echo "$i is write-protected, so I'll keep it!" 1>&2
         else
            rm -f $i
         fi
      done
   fi
   exit
fi

# find out the tex format to use:
format=
i=$(head -1 "$base.$ext")
if [[ $i =~ ^%!([[:alnum:]]+) ]]; then
   format=${BASH_REMATCH[1]}
elif grep -E '\\(RequirePackage|usepackage)(\s*\[.*\])?\{(fontspec|polyglossia)\}' "$base.$ext" >/dev/null; then
   format=xelatex
elif grep "\\documentclass" "$base.$ext" >/dev/null; then
   $ps && format=latex || format=pdflatex
else
   $ps && format=tex || format=pdftex
fi
$ps && [[ $format =~ (pdf|xe) ]] && die "You can not use the --ps option on a $format source!"


# texi2dviquiet, if set tot true in rc-file, keeps texi2dvi quiet, even in verbose mode
# extraoptions can be set in rc file; could be, e.g., -shell-escape
# We set TEXINDY to true, thus disabling texi2dvi's indexing facilities,
# because those can't handle indexes created by the ltxdoc class

$texi2dviquiet || ! $verbose && q=--quiet || q=
texcommand="TEXINDY=true LATEX='$format -halt-on-error -recorder -synctex=1 $extraoptions' texi2dvi --no-line-error $q $base.$ext 2>/dev/null"

while true; do
   if [[ "$target" =~ [[:space:]] ]]; then
      die "mk does not (yet) handle filenames with spaces!"
      # neither does texi2dvi !
   elif [ -e $target -a ! -w $target ]; then
      warn "Target $target is write-protected, so I'll not re-compile it!"
      sleep 2
   else
      compile && ready=true || ready=false
      if [ -s $target ]; then # target exists and is non-zero
         test "$targetext" = dvi && $dvips
      elif [ ! -e $target ]; then
         Warn "After compilation, an empty $target was found"
         ready=false
      else
         Warn "After compilation, no file $target was found"
         if [ "$targetext" = 'pdf' ]; then
            Warn "One possible cause is that your file pdftex.cfg"
            Warn "contains 'output_format 0' instead of 'output_format 1'"
         fi
         die "Quitting..."
      fi
      if $ready; then
         rerun=false
         # A glossary file, if it exists, is always rewritten in a compilation:
         if [ -e "$base.glo" ]; then
            makeindex -q -s gglo.ist -o "$base.gls" "$base.glo"
            rerun=true
         fi
         if [ -e "$base.idx" ]; then
            # don't know how to find out if a non-standard index style is used,
            # so just check for a dtx extension and then suppose gind style
            if [ "$ext" = 'dtx' ]; then
               makeindex -q -s gind.ist -o "$base.ind" "$base.idx"
            else
               makeindex -q "$base"
            fi
            rerun=true
         fi
         if $rerun; then
            run "$texcommand" || show_error_and_edit
         fi
      fi
   fi

   $view || $print && {
      ( cd $pwd
        run "vpp $vppoptions $dir/$vpptarget"
      )
      case $? in
      ($editexit)	edit $edit 1 false || continue ;;
      ($compileexit)	rm -f $target; continue ;;
      (0)		break ;;
      (*)		edit $edit 1 true || continue ;;
      esac
   }
   break
done
edit=
show_error_and_edit
