#!/bin/sh
#
# This file belongs to MTYPE13 package by Wlodek Bzyl <matwb@univ.gda.pl>
#
#    16.10.2001  * converted to a bash script; this script reads 
#                  its input from stdin or file named on the command
#                  line; output is written to stdout

script_name=$(basename $0)
version=1.3

# Default is no output

help_opt=0
version_opt=0

# Note that we use `"$@"' to let each command-line parameter expand to a 
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o hv --long help,version -a -n 'epsincl' -- "$@"`

if [ $? != 0 ] 
then 
    printf "Try \`%s_name --help' for more information\n" $script_name>&2
    printf "Terminating...\n" >&2
    exit 1
fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
	-h|--help) help_opt=1 ; shift ;;
	-v|--version) version_opt=1 ; shift ;;
	--) shift ; break ;;
	*) echo "Getopt internal error!" ; exit 1 ;;
    esac
done

fname=$1

if [ $version_opt != 0 ]
then
  printf "%s (MTYPE13) %s\n" $script_name $version >&2
  printf "Original DOS batch file written by JNS team.\n" >&2
  printf "Bash script written by Wlodek Bzyl.\n\n" >&2
  printf "Copyright (C) 2002 Wlodek Bzyl.\n" >&2
  printf "This is free software; see the source for copying conditions.  There is NO\n" >&2
  printf "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" >&2
  exit 1
fi

if [ -z "$fname" -o $help_opt != 0 ]
then
  printf "Usage:   %s FILE\n" $script_name
  printf "Example: %s foo.100 > foo.eps\n" $script_name >&2
  printf "Convert FILE generated by MetaPost with embedded EPSes into EPS file.\n" >&2
  printf "Converted FILE is written on standard output.\n\n" >&2
  printf "  -h --help           display this help and exit\n" >&2
  printf "  -v --version        output version information and exit\n\n" >&2
  printf "Report bugs to <matwb@univ.gda.pl>.\n" >&2
  exit 1
fi

if [ ! -f $fname ] ; then
    printf "Could not find \`%s'\n" $fname >&2
    printf "Terminating...\n" >&2
    exit 1
fi

LANG=C gawk -vV=2 '
#
# File: epsincl.awk
#
# made in BOP s.c., bop@bop.com.pl; public domain software
# history:
#          22.05.2003, ver. 0.42: abysmal stupidity corrected:
#                      fshow was replaced by nshow also
#                      in the definition of nshow!
#          16.06.2000, ver. 0.41: another nasty bug fixed: fonts using
#                      character of code 0 were handled improperly
#                      (function out_chars)
#          21.05.2000, ver. 0.40: total re-building triggered by a nasty
#                      bug (several consecutive occurrences of the same
#                      EPS were handled improperly); verbose mode added
#                      outline of a new algorithm:
#                      * prologue is handled separately
#                      * the program leaves unrecognised structures intact
#                      * fshow operator is replaced by nshow
#                        without checking context
#                      * the lines (if there are inclusions) are being kept
#                        in a circular buffer
#                      * the program reacts only to setrgbcolor,
#                        setgray, and fill -- when any of these
#                        commands is spotted, an appropriate action
#                         is triggered
#                      * extra assumptions:
#                        -- no comments are expected between parameters
#                           of the commands being analysed
#                        -- the operators listed above may occur only
#                            once in a line
#                        -- a rectangle can be represented by a series
#                           of 3 or 4 sides forming a closed path, being
#                           either straight lines or Bezier curves.
#          30.01.2000, ver. 0.30: check if the file was already processed
#          05.01.2000, ver. 0.20: first release
#          20.08.1999, ver. 0.10: pre-release
BEGIN {
  initialize_hex()
  #
  while (getline > 0) 
    if (/^%/) process_prologue() 
    else {flush_prologue(); break}
  #
  if (V>0) # verbose mode
    mess("EPSINCL: processing", FILENAME ",", 
      (N>0 ? N " EPS" (N>1?"es":"") " to be included" : "no inclusions"))
  #
  if (N>0) {# EPS contains inclusions
    initialize_buffer()
    do {
      if ((cnum>0) && (LINE~/fill/)) if (check_rectangle(x,y)) {
        flush_to_rectangle()
        IncludeEPS(cnum,x,y)
      }
      if (LINE~/setgray/) cnum=0
      if (LINE~/setrgbcolor/) cnum=check_color()
    } while (read_line())
    flush_buffer()
  } else # EPS does not contain inclusions, clear font data only
    do {gsub(/fshow/, "nshow"); print} while (getline > 0)
}

function IncludeEPS(i,x,y,  comments,s) {
  if (V>1) # very verbose mode
    mess("  Including", Ename[i])
  print "%BeginInclude"
  print "MEPSDict begin /MEPSSave save def gsave"
  print "count /MEPSocount exch def /MEPSdcount countdictstack def"
  print "/showpage {} def /erasepage {} def /copypage {} def"
  # neutralizing commands that set page size (possibly issued by dvips)
  print "/setpage {pop pop pop} def /setpageparams {pop pop pop pop} def"
  print "/setpagedevice {pop} def /note {} def /letter {} def /legal {} def"
  print "/ledger {} def /11x17 {} def /a4 {} def /a3 {} def"
  printf ("[ %f %f %f %f %f %f ] matrix invertmatrix\n",
    Ebbr[i]-Ebbl[i], 0, 0, Ebbu[i]-Ebbd[i], Ebbl[i], Ebbd[i])
  printf ("[ %f %f %f %f %f %f ] matrix concatmatrix\n",
    x[1]-x[0], y[1]-y[0], x[3]-x[0], y[3]-y[0], x[0], y[0])
  print "concat"
  print "0 setlinecap 0 setlinejoin 10 setmiterlimit [] 0 setdash"
  print "1 setlinewidth 0 setgray newpath"
  print "%StartInclude"
#
  comments=1
  while (getline s < Ename[i] >0)
    if ((s!~/^%[%!\*]/) || (comments==0)) {
      comments=0; gsub(/fshow/, "nshow", s); print s
    }
  close(Ename[i])
#
  print "%StopInclude"
  print "count MEPSocount sub {pop} repeat"
  print "countdictstack MEPSdcount sub {end} repeat"
  print "grestore MEPSSave restore end"
  print "%EndInclude"
}

function check_rectangle(x,y,  p,i,j) {
# acceptable order of commands:
# newpath, moveto, three or four times lineto or curve to, closepath, fill
  split_buffer(p,MAX) 
  for (i=p[0]; i>0; --i) if (p[i]=="newpath") break
  if (p[i]!="newpath") return 0
  i++
  if (p[i+2]!="moveto") return 0
  x[0]=p[i]; y[0]=p[i+1]; i+=3
  for (j=1; j<=4; j++) {
    if (p[i+2]=="lineto") {x[j]=p[i]; y[j]=p[i+1]; i+=3} 
    else if (p[i+6]=="curveto") {x[j]=p[i+4]; y[j]=p[i+5]; i+=7}
    else break
  }
  if ((p[i]!="closepath") || (j<3)) return 0
  i++
  if (p[i]!="fill") return 0
  return 1
} 

function flush_to_rectangle(  t) {
# it is assumed that the rectangle description occupies more than one line
  LAST=(LAST+MAX-1) % MAX; t=BUF[LAST]; sub(/^.*fill */,"",t)
  do {LAST=(LAST+MAX-1) % MAX} while (BUF[LAST]!~/newpath/)
  sub(/ *newpath.*$/,"",BUF[LAST]); if (BUF[LAST]!="") LAST=(LAST+1) % MAX
  flush_buffer(); if (t!="") put_buf(t)
}

function check_color(  p,c,i,r,g,b) {
  split_buffer(p,4) # setrgbcolor cannot occupy more than 4 lines, moreover,
                    # it certainly occurs in a current line
  for (i=p[0]; i>0; --i) if (p[i]=="setrgbcolor") break
  if (i<4) return 0
  c=0; r=p[i-3]+0; g=p[i-2]+0; b=p[i-1]+0
  for (i in Ename)
    if ((Ecolr[i]==r) && (Ecolg[i]==g) && (Ecolb[i]==b)) {c=i; break}
  return c
}

function read_line() {
  if (getline == 0) return 0
  put_buf($0); if (LAST==FIRST) prn_buf()
  return 1
}

function split_buffer(p,lim,  f,s) {
  f=LAST-lim; f=((f<FIRST-(LAST<FIRST ? MAX : 0)) ? FIRST : (f+MAX) % MAX)
  s=""
  while (f!=LAST) {s=s " " BUF[f]; f=(f+1) % MAX}
  p[0]=split(s,p,/ +/)
}

function flush_buffer() {while (LAST!=FIRST) prn_buf()}

function put_buf(s) {
  gsub(/fshow/, "nshow", s); BUF[LAST]=LINE=s; LAST=(LAST+1) % MAX
}
function prn_buf() {print BUF[FIRST]; FIRST=(FIRST+1) % MAX}

function initialize_buffer() {
  MAX=40
  LAST=FIRST=0 # cf. tex.web, Sec. 31
  put_buf($0)
}

function process_prologue(){
  if (/^%\*Font:/) 
    f_ch[$2 "\001" $4]=fix_chars(f_ch[$2 "\001" $4],$5)
  else if (/^%EPS/) {
    Ecolr[++N]=$2+0; Ecolg[N]=$3+0; Ecolb[N]=$4+0
    Ename[N]=$5 ""
    Ebbl[N]=$6+0; Ebbd[N]=$7+0; Ebbr[N]=$8+0; Ebbu[N]=$9+0
  } else prologue[++prologue[0]]=$0
}

function flush_prologue(  j,l){
  for (l=1; l<=prologue[0]; ++l) {
   if (prologue[l]~/^%%EndProlog/) j=flush_fonts();
   print prologue[l]
  }
  if (/\/nshow \{.*\} def/) {
    mess("WARNING: input file has already been processed by EPSINCL")
    getline
  }
  if (j>0) print "/nshow {gsave 10 div dup scale 10 fshow grestore} def"
  if (N>0) print "/MEPSDict 50 dict def"
}

function flush_fonts( i,j) {
  j=0
  for (i in f_ch) {
    j++
    split(i,a,"\001")
    printf("%%*Font: %s 10.0 %s %s\n", a[1], a[2], out_chars(f_ch[i]))
  }
  return j
}

function fix_chars(f,c,  a) {
  split(c,a,":")
  return mix_chars((f=="" ? sprintf("%0256d", 0) : f), a[2], hexval(a[1]))
}

function mix_chars(f,c,x,  h,k,l) {
  for (k=1; k<=length(c); k++) {
    h=hb[substr(c,k,1)]
    for (l=1; l<=length(h); l++)
      if (substr(h,l,1)=="1") f=substr(f,1,x+4*k+l-5) "1" substr(f,x+4*k+l-3)
  }
  return f
}

function out_chars(f,  i,j,k,g) {
  i=1 # added in ver. 0.41
  while ((i<256) && (substr(f,i,1)=="0")) ++i
  g=""
  for (j=i; j<=length(f); j+=4) {
    k=sprintf("%-4s", substr(f,j,4)); gsub(/ /,"0",k); g=g bh[k]
  }
  sub (/0+$/,"",g)
  return sprintf("%02X", (i-1)) ":" g
}

function initialize_hex() {
  hd["0"]=0; hd["1"]=1; hd["2"]=2; hd["3"]=3; hd["4"]=4
  hd["5"]=5; hd["6"]=6; hd["7"]=7; hd["8"]=8; hd["9"]=9
  hd["a"]=hd["A"]=10; hd["b"]=hd["B"]=11; hd["c"]=hd["C"]=12
  hd["d"]=hd["D"]=13; hd["e"]=hd["E"]=14; hd["f"]=hd["F"]=15
  #
  hb["0"]="0000"; hb["1"]="0001"; hb["2"]="0010"; hb["3"]="0011"
  hb["4"]="0100"; hb["5"]="0101"; hb["6"]="0110"; hb["7"]="0111"
  hb["8"]="1000"; hb["9"]="1001"; hb["a"]="1010"; hb["b"]="1011"
  hb["c"]="1100"; hb["d"]="1101"; hb["e"]="1110"; hb["f"]="1111"
  #
  for (i in hb) bh[hb[i]]=i
  #
  hb["A"]="1010"; hb["B"]="1011"; hb["C"]="1100"
  hb["D"]="1101"; hb["E"]="1110"; hb["F"]="1111"
}

function hexval(x) {return hd[substr(x,1,1)]*16+hd[substr(x,2,1)]}

function mess(s1,s2,s3) {
  printf s1 > "/dev/tty"
  if (s2!="") printf " " s2 > "/dev/tty"
  if (s3!="") printf " " s3 > "/dev/tty"
  print "" > "/dev/tty"
}' $fname
