# ---------------------------------------------------------------------------
# This file belongs to the EPSTOMF package.
# ---------------------------------------------------------------------------
# You are entitled to do with the file whatever you wish. If you alter a file,
# however, please remove the line containing the comment:
#
#      `This file belongs to the EPSTOMF package.'
#
# in order to avoid mess.
# ---------------------------------------------------------------------------
# AUTHORS: B. Jackowski, P. Pianowski, M. Ry\'cko
# HISTORY:
#    version 0.50: Tuesday, August 15th, 1995
#        * first less or more complete version
#    version 0.51: Monday, October 23rd, 1995
#        * comments adjusted to a new distribution
#    version 0.52: Monday, November 6th, 1995
#        * miter limit is a dimensionless quantity
#    version 0.53: Wednesday, March 19th, 1997
#        * degenerated (single-node) paths used to be processed improperly
#        * font dimens specified explicitly
#        * `plain' option added (a METAFONT code without referring to the
#          MFTOEPS package is generated if variable `plain' is set to 1)
#    version 0.54: Thursday, January 29th, 1998
#        * this and previous versions were stimulated (stipulated in fact :-)
#          by Samy Alex Za\"\i{}mi -- thanks!
#        * all kinds of end-of-line characters are accepted in
#          input files; this, however, necessitates using Gnu AWK
#        * a patch was added to cope (somehow) with PageDraw's (ver. 2.0)
#          EPSes that do not conform to the definition of a ``canonical''
#          EPS given below, nonetheless, they are ``nearly canonical''
#          and something can be done 
#        * in order to avoid annoying gftodvi's messages
#          ``Too many labels'' and ``Too many labels and/or rules''
#          the command |labels| is preceded by a percent sign if
#          suspiciously many nodes occur
# ---------------------------------------------------------------------------
# This is an AWK program for the translation of a ``canonical'' (see below)
# EPS file into METAFONT lingo; the resulting METAFONT program inputs MFTOEPS
# macros (ver. >= 0.61). EPS files created using the MFTOEPS package are
# accepted by this converter.
# ---
# The crucial features of a ``canonical'' EPS file are listed below:
#  0. General assumptions:
#     a) parameters of a command appear in one line along with the command;
#     b) only explicit numerical values are admissible (variables are not
#        interpreted);
#     c) all numbers are expressed in PostScript points (called in TeX
#        ``big points'': 1/72in), i.e., no local transformations are involved;
#     d) prior to painting a curve (fill or stroke) its parameters
#        for filling or stroking are explicitly set;
#     e) only the commands listed in items 1--11 are interpreted.
#  1. `gsave' and `grestore' are represented by `q' and `Q', respectively;
#     malformed grouping structure may yield unpredictable results.
#  2. `moveto' is represented by `m'.
#  3. `lineto' is represented by either `l' or `L'.
#  4. `curveto' is represented by either `c' or `C'.
#  5. `setlinewidth' is represented by `w'.
#  6. `setlinejoin' is represented by `j'.
#  7. `setlinecap' is represented by `J'.
#  8. `setmiterlimit' is represented by `M'.
#  9. `setdash' is represented by `d'.
# 10. Curves start with `*u' and end with `*U'; no `q'/`Q' commands are
#     expected to occur inside a curve, i.e., between `*u' and `*U' commands;
#     `q'/`Q' pairs occuring outside a curve, i.e., between `*U' and `*u'
#     commands, are ignored; actually, the latter situation should not
#     occur either.
# 11. Component paths of a multi-path curve end consistently either
#     with `f' (filling), or `s'/`S' (stroking of closed and open paths,
#     resp.), or `h W n' (clipping; in fact, only `n' is taken taken into
#     account).
# 12. Structural comments `%%BoundingBox' and `%%EndSetup' should occur at
#     the beginning of the file (in this order).
# ---
# COMMENTS:
# 1. The engine works in such a way that at first a necessary information
#    about paths is collected; during this stage only the coordinates of
#    nodes are written; after processing all the data the ``painting'' code
#    is generated; this complicates the AWK code a bit due to controlling
#    `gsave'/`grestore' nesting; a simplified approach is used: instead of
#    recording the full nesting tree, a ``backbone'' of a nesting structure
#    is reconstructed (cf. item 10 above).
# 2. A little bit more complicated (in comparison with other commands) is
#    the translation of `d' (`setdash') command; in addition to the
#    assumptions specified above, it is assumed that at least one space
#    precedes `[' and `d', and follows `]'.
# 3. Some complexity is also involved at the METAFONT level at the stage of
#    computing of a bounding box; as a default, the graphic object is shifted
#    such that the left lower corner of the bounding box coincides with
#    the origin of the coordinate system; by manual alteration of the
#    resulting METAFONT file the user can easily control the situation, e.g.,
#    vertical or horizontal shift (or both) can be prohibited, the original
#    bounding box can be preserved, etc.; one should also remember that
#    if clipping is involved, the computed bounding box may be invalid.
# 4. Due to rounding errors the original EPS file and the EPS file generated
#    from a resulting METAFONT file may differ.
# ---------------------------------------------------------------------------
BEGIN {
 skipping=1
 path_max=0
 group_max=0
 node_max=0
 xl=0; yl=0; xh=72; yh=72; # emergency default
# `q'/`Q' nesting is controled by the following three variables
# (`ignore_grestore' controls ignoring `q'/`Q' pairs between curves):
 nesting_level=0; nesting_group=0; ignore_grestore=0
 RS="\015|\012|\015\012"
}
# ---
(skipping==1) && ($0 ~ /^%%BoundingBox:/) {xl=$2; yl=$3; xh=$4; yh=$5}
# ---
(skipping==1) && $0=="%%EndSetup" {skipping=0;
 print "%%% fill fill_C draw_C clip_C set_BB find_BB close_path"
 print "%%% fill fix_fill_cmyk fix_draw_cmyk"
 print "%%% fill fix_line_width fix_line_join fix_line_cap"
 print "%%% fill fix_miter_limit fix_dash"
 print "%%% message write_preamble"
 print "%%% endchar write_postamble g_save g_restore"
 print "%%% addto ~"
 print "%%\\input mftform"
 if (!plain) print "input mftoeps;"
 print "numeric w#, h#, d#, xl#, yl#, xh#, yh#, xs#, ys#;"
 print "xl#=" xl "bp#; yl#=" yl "bp#; xh#=" xh "bp#; yh#=" yh "bp#;";
 print "if false: noxs:=0; fi % no horizontal shift, ignored by default"
 print "if false: noys:=0; fi % no vertical shift, ignored by default"
 if (!plain) {
   print "if false: oribb:=0; fi",
         "% preserving the original bounding box, ignored by default"
   print "pinbb:=0; % default: shifting the object such that |(xl,yl)=(0,0)|"
 }
 print "xs#=if known noxs: 0 else: -xl# fi;"
 print "ys#=if known noys: 0 else: -yl# fi;"
 print "w#=max(0,xh#+xs#); h#=max(0,yh#+ys#); d#=max(0,-yl#-ys#);"
 print "%"
 fn=FILENAME; gsub(/^.*[\/\\]/,"",fn); gsub(/\.[^\/\\]*$/,"",fn)
 print "font_identifier:=\"" fn "\";";
 print "font_size round(w#);"
 print "font_slant 0;"
 print "font_normal_space w#;"
 print "font_normal_stretch 0;"
 print "font_normal_shrink 0;"
 print "font_x_height h#;"
 print "font_quad w#;"
 print "font_extra_space 0;"
 print "message \"The font size = \" & decimal(designsize) & \"pt#\";"
 print "message \"\";"
 print "%"
 if (!plain) print "extra_eps_setup:=\"pixels_per_inch:=72\";",
                   "% better resolution for this case"
 print (plain ? "" : "eps_") "mode_setup; define_pixels(xs, ys);"
 print "%"
 print "def ~ text xy = \\\\ = (bp*xpart(xy)+xs,bp*ypart(xy)+ys) enddef;"
 print "%%% step C B L M"
 print "def M = M_ ( enddef;"
 print "def M_(suffix $) = z$ enddef;"
 print "def B = ) B_ ( enddef;"
 print "def B_(suffix $) = .. controls z$a and z$b .. z$ enddef;"
 print "def L = ) L_ ( enddef;"
 print "def L_(suffix $) = -- z$ enddef;"
 print "def C = ) enddef;"
 print "def close_path suffix p ="
 print " p:=p if (point 0 of p)=(point length(p) of p): & else: -- fi cycle;"
 print "enddef;"
 print "%%% labels B L M"
 print "%%% fi C"
 if (plain) {
   print "% ---"
   print "def eofill expr P ="
   print " begingroup save pp_; picture pp_;"
   print "  interim turningcheck:=0;"
   print "% the following |addto|s are supposed to fill disjoint areas:"
   print "  pp_:=nullpicture; addto pp_ contour P.t_;"
   print "  cull pp_ keeping (1,infinity); addto currentpicture also pp_;"
   print "  pp_:=nullpicture; addto pp_ contour reverse P.t_;"
   print "  cull pp_ keeping (1,infinity); addto currentpicture also pp_;"
   print "  cull currentpicture keeping(1,1);"
   print " endgroup"
   print "enddef;"
   print "def fill_C text t ="
   print " begingroup"
   print "  save rr_; picture rr_; % must not be |pp_| (see |eofill|)"
   print "  begingroup"
   print "   save currentpicture; def currentpicture = rr_ enddef; % danger!"
   print "   currentpicture:=nullpicture; for qq_:=t: eofill qq_; endfor"
   print "  endgroup;"
   print "  addto currentpicture also rr_; cullit;"
   print " endgroup"
   print "enddef;"
   print "def draw_C text t = for pp_:=t: draw pp_; endfor enddef;"
   print "def clip_C text t = enddef;"
 }
 print "% ---"
 print "beginchar("0",w#,h#,d#); path p[\\\\];"
}
# ---
skipping==0 {
 for (i=1; i<=NF; i+=1) {
# ---
  if ($i=="q") {++nesting_level; ++ignore_grestore}
# ---
  if ($i=="Q") {
   --nesting_level
   if (ignore_grestore>0) {--ignore_grestore} else {++nesting_group}
   }
# ---
  if ($i=="*u") {
   print ""; print "% BEGIN of GROUP", group_max ";"
   ignore_grestore=0; first_path[group_max]=path_max
  }
# ---
  if ($i=="k") {
   fix_fill_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1)
  }
# ---
  if ($i=="K") {
   fix_draw_cmyk[group_max]=$(i-4) "," $(i-3) "," $(i-2) "," $(i-1)
  }
# ---
  if ($i=="w") fix_line_width[group_max]=$(i-1) "bp"
# ---
  if ($i=="j") fix_line_join[group_max]=$(i-1)
# ---
  if ($i=="J") fix_line_cap[group_max]=$(i-1)
# ---
  if ($i=="M") fix_miter_limit[group_max]=$(i-1)
# ---
  if ($i=="d") {# this is a little bit more complex case (see comment 2)
   l=i-2; # $(i-1)="d", $(i-1) is the offset
   for (j=l; $j !~ /\[/; --j) {}
# $j contains the opening bracket for `setdash'
# $l contains the closing bracket for `setdash'
   gsub(/\[/,"",$j); gsub(/\]/,"",$l) # delete both brackets
   was_something=0
   fix_dash[group_max]="("; # construct parameters for `fix_dash'
   for (k=j; k<=l; ++k) {
    if ($k != "") {
     if (was_something==1) {aux=","} else {was_something=1; aux=""}
     fix_dash[group_max]=fix_dash[group_max] aux $k "bp"
    }
   }
   fix_dash[group_max]=fix_dash[group_max] ") " $(i-1) "bp"
  }
# ---
  if ($i=="m") {
   print "% begin of path", path_max ";"
   print "%%\\BMU\\COLS"
   print "z" node_max "~" $(i-2) "," $(i-1) ";"
   node_path[node_max]=path_max; first_node[path_max]=node_max; ++node_max
  }
# ---
  if (($i=="l") || ($i=="L")) {
   print "z" node_max "~" $(i-2) "," $(i-1) ";"
   node_path[node_max]=path_max; arc_type[node_max]="L"; ++node_max
  }
# ---
  if (($i=="c") || ($i=="C")) {
   print "z" node_max "a~" $(i-6) "," $(i-5) ";"
   print "z" node_max "b~" $(i-4) "," $(i-3) ";"
   print "z" node_max "~" $(i-2) "," $(i-1) ";"
   node_path[node_max]=path_max; arc_type[node_max]="B"; ++node_max
  }
# ---
  if (($i=="f") || ($i=="s") || ($i=="S") || ($i=="n")) {
   print "%%\\EMU";
   path_group[path_max]=group_max; last_node[path_max]=node_max-1;
   group_type[group_max]=$i; # should be consistent for all paths in a group
   if (($i=="f") || ($i=="s") || ($i=="n")) is_closed_path=1
   else is_closed_path=0
   aux="p" path_max "=M" first_node[path_max]
   if (first_node[path_max]<last_node[path_max])
    for (j=first_node[path_max]+1; j<=last_node[path_max]; ++j) {
     aux=aux " " arc_type[j] j
     if (j==last_node[path_max]) aux=aux " C;"
     if (length(aux)>70) {print aux; aux=""}
    } else aux=aux " C;" # degenerated case
   if (aux!="") print aux
   if (is_closed_path==1) print "close_path p" path_max ";"
   print "% end of path", path_max ";"
   ++path_max
  }
# ---
  if ($i=="*U") {
   print "% END of GROUP", group_max ";";
   group_nesting_level[group_max]=nesting_level;
   group_nesting_group[group_max]=nesting_group;
   last_path[group_max]=path_max-1;
   ++group_max
  }
 }
}
# ---
END {
 node_max--
 path_max--
 group_max--
# ---
 if (!plain) {
   print ""
   print "if known oribb:"
   print " set_BB " xl "bp+xs," yl "bp+ys," xh "bp+xs," yh "bp+ys;"
   print "elseif known pinbb:"
   print " find_BB p0 for i:=1 upto "  path_max": , p[i] endfor;"
   print " for i:=0 upto "  node_max":"
   print "  x[i]:=x[i]-xl_crd; y[i]:=y[i]-yl_crd;"
   print "  if known x[i]a: x[i]a:=x[i]a-xl_crd; fi"
   print "  if known x[i]b: x[i]b:=x[i]b-xl_crd; fi"
   print "  if known y[i]a: y[i]a:=y[i]a-yl_crd; fi"
   print "  if known y[i]b: y[i]b:=y[i]b-yl_crd; fi"
   print " endfor"
   print " for i:=0 upto "  path_max": p[i]:=p[i] shifted -llxy; endfor"
   print " set_BB origin, urxy-llxy;"
   print "else:"
   print " find_BB p0 for i:=1 upto "  path_max": , p[i] endfor;"
   print "fi"
   print "write_preamble jobname;"
 }
# ---
# one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2'
 if (!plain) for (j=0; j<=group_nesting_level[0]-2; ++j) {print "g_save;"}
 for (g=0; g<=group_max; ++g) {
  if (plain) {
    if (fix_line_width[g]!="")
      print "pickup pencircle scaled " fix_line_width[g] ";"
  } else {
  if (g>0) {
     k=group_nesting_group[g]-group_nesting_group[g-1];
     # k == number of groups closed in the meantime
     for (j=1; j<=k; ++j) print "g_restore;"
     k=group_nesting_level[g-1]-k; l=group_nesting_level[g];
     # k == current nesting level, l == resulting nesting level
     for (j=1; j<=(k-l); ++j) print "g_restore;"
     for (j=-1; j>=(k-l); --j) print "g_save;"
    }
    if (fix_fill_cmyk[g]!="") print "fix_fill_cmyk " fix_fill_cmyk[g] ";"
    if (fix_draw_cmyk[g]!="") print "fix_draw_cmyk " fix_draw_cmyk[g] ";"
    if (fix_line_width[g]!="") print "fix_line_width " fix_line_width[g] ";"
    if (fix_line_join[g]!="") print "fix_line_join " fix_line_join[g] ";"
    if (fix_line_cap[g]!="") print "fix_line_cap " fix_line_cap[g] ";"
    if (fix_miter_limit[g]!="") print "fix_miter_limit " fix_miter_limit[g] ";"
    if (fix_dash[g]!="") print "fix_dash " fix_dash[g] ";"
  }
  if (group_type[g]=="f") aux="fill_C"
  if ((group_type[g]=="s") || (group_type[g]=="S")) aux="draw_C"
  if (group_type[g]=="n") aux="clip_C"
  for (j=first_path[g]; j<=last_path[g]; ++j) {
   aux=aux " p" j (j==last_path[g] ? ";" : ",")
   if (length(aux)>70) {print aux; aux=""}
  }
  if (aux!="") print aux
 }
# ---
 if ((group_max<0) && (path_max>0)) {
# something went wrong (non-conforming EPS?);
# let's undertake a desperate defense of the nearly wasted task:
  g=0; aux="fill_C" # emergency initialization
  if (group_type[g]=="f") aux="fill_C"
  if ((group_type[g]=="s") || (group_type[g]=="S")) aux="draw_C"
  if (group_type[g]=="n") aux="clip_C"
  for (j=0; j<=path_max; ++j) {
   aux=aux " p" j (j==path_max ? ";" : ",")
   if (length(aux)>70) {print aux; aux=""}
  }
  if (aux!="") print aux
 }
# ---
# one extra `gsave'/`grestore' pair is always added by MFTOEPS, hence `-2'
 for (j=0; j<=group_nesting_level[group_max]-2; ++j) print "g_restore;"
 if (!plain) print "write_postamble;"
 # not to many nodes please (otherwise gftodvi is likely to break down):
 print (node_max>800 ? "% " : "") "labels(range" 1 "thru" node_max ");"
 print "endchar;"
 print "% ---"
 print "end."
 print "%%\\end"
}