# ---------------------------------------------------------------------------
# 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"
}