local function PRINTDBG(s) end
local function chMF(t,k) if t[k] then print(k.." already inserted") os.exit(1) end end 

PRINTDBG("mflua.lua")

--------------------------------------------------------------------------------
--
-- kpse 
--
--------------------------------------------------------------------------------
--    "new"
--    "set_program_name"
--    "init_prog"
--    "readable_file"
--    "find_file"
--    "expand_path"
--    "expand_var"
--    "expand_braces"
--    "var_value"
--    "show_path"
--    "lookup"
--    "version"
--    "default_texmfcnf"


--------------------------------------------------------------------------------
--
-- These are hardcoded into  mflua.MFbuiltin table:
--
--------------------------------------------------------------------------------
MFbuiltin = mflua.MFbuiltin or {}
-- function:	link
-- function:	info
-- function:	x_coord
-- function:	y_coord
-- function:	left_type
-- function:	right_type
-- function:	left_x
-- function:	left_y
-- function:	right_x
-- function:	right_y
-- function:	n_sin_cos
-- 
-- function:	LUAGLOBALGET_boundary_char
-- function:	LUAGLOBALGET_char_code
-- function:	LUAGLOBALGET_char_dp
-- function:	LUAGLOBALGET_char_dx
-- function:	LUAGLOBALGET_char_dy
-- function:	LUAGLOBALGET_char_ext
-- function:	LUAGLOBALGET_char_ht
-- function:	LUAGLOBALGET_char_ic
-- function:	LUAGLOBALGET_char_wd
-- function:	LUAGLOBALGET_cur_edges
-- function:	LUAGLOBALGET_cur_exp
-- function:	LUAGLOBALGET_cur_pen
-- function:	LUAGLOBALGET_designsize
-- function:	LUAGLOBALGET_fillin
-- function:	LUAGLOBALGET_granularity
-- function:	LUAGLOBALGET_hppp
-- function:	LUAGLOBALGET_mem_top
-- function:	LUAGLOBALGET_octant
-- function:	LUAGLOBALGET_turning_check
-- function:	LUAGLOBALGET_vppp
-- function:	LUAGLOBALGET_x_offset
-- function:	LUAGLOBALGET_y_offset

--
-- It's handy to have them as local 
--

local link       = MFbuiltin.link
local info       = MFbuiltin.info
local x_coord    = MFbuiltin.x_coord
local y_coord    = MFbuiltin.y_coord
local left_type  = MFbuiltin.left_type
local right_type = MFbuiltin.right_type
local left_x     = MFbuiltin.left_x
local left_y     = MFbuiltin.left_y
local right_x    = MFbuiltin.right_x
local right_y    = MFbuiltin.right_y
local n_sin_cos  = MFbuiltin.n_sin_cos



--------------------------------------------------------------------------------
-- Global table mflua.
-- Important subtable:
-- * mflua.MFbuiltin that stores the hardwired functions;
-- * mflua.MF that stores some constants from MetaFont, as also some functions
--   from PascalWEB rewritten in Lua (almost 1:1 translation).   
-- Use them with care !
--------------------------------------------------------------------------------

mflua = mflua or {}
mflua.MF = mflua.MF  or {}


--------------------------------------------------------------------------------
--
-- As in MetaFont:
--
--------------------------------------------------------------------------------

local min_quarterword = 0	        --{smallest allowable value in a |quarterword|}
local max_quarterword = 255 		--{largest allowable value in a |quarterword|}
local min_halfword = 0 	    		--{smallest allowable value in a |halfword|}
local max_halfword = 65535  		--{largest allowable value in a |halfword|}

local mem_min = 0                       -- {smallest index in the |mem| array, must not be less than |min_halfword|}

local quarter_unit = 2^14  		-- {$2^{14}$, represents 0.250000}
local half_unit = 2^15   		-- {$2^{15}$, represents 0.50000}
local three_quarter_unit = 3*(2^14) 	-- {$3\cdot2^{14}$, represents 0.75000}
local unity = 2^16 			-- {$2^{16}$, represents 1.00000}
local two = 2^17 			-- {$2^{17}$, represents 2.00000}
local three = 2^16+2^16  		-- {$2^{17}+2^{16}$, represents 3.00000}


chMF(mflua.MF,min_quarterword);mflua.MF.min_quarterword = min_quarterword
chMF(mflua.MF,max_quarterword);mflua.MF.max_quarterword = max_quarterword
chMF(mflua.MF,min_halfword);mflua.MF.min_halfword = min_halfword
chMF(mflua.MF,max_halfword);mflua.MF.max_halfword = max_halfword
chMF(mflua.MF,mem_min);mflua.MF.mem_min = mem_min
chMF(mflua.MF,quarter_unit);mflua.MF.quarter_unit = quarter_unit
chMF(mflua.MF,half_unit);mflua.MF.half_unit = half_unit
chMF(mflua.MF,three_quarter_unit);mflua.MF.three_quarter_unit = three_quarter_unit
chMF(mflua.MF,unity);mflua.MF.unity = unity
chMF(mflua.MF,two);mflua.MF.two = two
chMF(mflua.MF,three);mflua.MF.three = three



-- @ Given integers |x| and |y|, not both zero, the |n_arg| function
-- returns the |angle| whose tangent points in the direction $(x,y)$.
-- This subroutine first determines the correct octant, then solves the
-- problem for |0<=y<=x|, then converts the result appropriately to
-- return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
-- (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
-- |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)

-- The octants are represented in a ``Gray code,'' since that turns out
-- to be computationally simplest.

negate_x=1
negate_y=2
switch_x_and_y=4
first_octant=1
second_octant=first_octant+switch_x_and_y
third_octant=first_octant+switch_x_and_y+negate_x
fourth_octant=first_octant+negate_x
fifth_octant=first_octant+negate_x+negate_y
sixth_octant=first_octant+switch_x_and_y+negate_x+negate_y
seventh_octant=first_octant+switch_x_and_y+negate_y
eighth_octant=first_octant+negate_y


local negate_x=1
local negate_y=2
local switch_x_and_y=4
local first_octant=1
local second_octant=first_octant+switch_x_and_y
local third_octant=first_octant+switch_x_and_y+negate_x
local fourth_octant=first_octant+negate_x
local fifth_octant=first_octant+negate_x+negate_y
local sixth_octant=first_octant+switch_x_and_y+negate_x+negate_y
local seventh_octant=first_octant+switch_x_and_y+negate_y
local eighth_octant=first_octant+negate_y

chMF(mflua.MF,negate_x);mflua.MF.negate_x = negate_x
chMF(mflua.MF,negate_y);mflua.MF.negate_y = negate_y
chMF(mflua.MF,switch_x_and_y);mflua.MF.switch_x_and_y = switch_x_and_y
chMF(mflua.MF,first_octant);mflua.MF.first_octant = first_octant
chMF(mflua.MF,second_octant);mflua.MF.second_octant = second_octant
chMF(mflua.MF,third_octant);mflua.MF.third_octant = third_octant
chMF(mflua.MF,fourth_octant);mflua.MF.fourth_octant = fourth_octant
chMF(mflua.MF,fifth_octant);mflua.MF.fifth_octant = fifth_octant
chMF(mflua.MF,sixth_octant);mflua.MF.sixth_octant = sixth_octant
chMF(mflua.MF,seventh_octant);mflua.MF.seventh_octant = seventh_octant
chMF(mflua.MF,eighth_octant);mflua.MF.eighth_octant = eighth_octant


local octant_dir = {}
octant_dir[first_octant]="ENE-1"
octant_dir[second_octant]="NNE-2"
octant_dir[third_octant]="NNW-3"
octant_dir[fourth_octant]="WNW-4"
octant_dir[fifth_octant]="WSW-5"
octant_dir[sixth_octant]="SSW-6"
octant_dir[seventh_octant]="SSE-7"
octant_dir[eighth_octant]="ESE-8"

chMF(mflua.MF,octant_dir);mflua.MF.octant_dir = octant_dir

-- @ Finally we come to the last steps of |make_spec|, when boundary nodes
-- are inserted between cubics that move in different octants. The main
-- complication remaining arises from consecutive cubics whose octants
-- are not adjacent; we should insert more than one octant boundary
-- at such sharp turns, so that the envelope-forming routine will work.
-- For this purpose, conversion tables between numeric and Gray codes for
-- octants are desirable.
-- @<Glob...@>=
-- @!octant_number:array[first_octant..sixth_octant] of 1..8;
-- @!octant_code:array[1..8] of first_octant..sixth_octant;

local octant_code = {}
octant_code[1]=first_octant;
octant_code[2]=second_octant;
octant_code[3]=third_octant;
octant_code[4]=fourth_octant;
octant_code[5]=fifth_octant;
octant_code[6]=sixth_octant;
octant_code[7]=seventh_octant;
octant_code[8]=eighth_octant;
chMF(mflua.MF,octant_code);mflua.MF.octant_code = octant_code


local octant_number = {}
for k=1, 8 do octant_number[octant_code[k]]=k; end
chMF(mflua.MF,octant_number);mflua.MF.octant_number = octant_number


-- It is convenient to define a \.{WEB} macro |t_of_the_way| such that
-- |t_of_the_way(a)(b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
-- @d t_of_the_way_end(#)==#,t@=)@>
-- @d t_of_the_way(#)==#-take_fraction@=(@>#-t_of_the_way_end
--
-- TO implement !!
-- function t_of_the_way(a,b,t)
--  return take_fraction(a-b,t)
-- end 

local endpoint = 0 		-- {|left_type| at path beginning and |right_type| at path end} 
local knot_node_size = 7 	-- {number of words in a knot node} */

local left_curl=left_x 		-- {curl information when entering this knot}
local left_given=left_x 	-- {given direction when entering this knot}
local left_tension=left_y 	-- {tension information when entering this knot}
local right_curl=right_x 	-- {curl information when leaving this knot}
local right_given=right_x 	-- {given direction when leaving this knot}
local right_tension=right_y 	-- {tension information when leaving this knot}
local explicit =1 		-- {|left_type| or |right_type| when control points are known}
local given = 2 		-- {|left_type| or |right_type| when a direction is given}
local curl = 3 			-- {|left_type| or |right_type| when a curl is desired}
local open = 4 			-- {|left_type| or |right_type| when \MF\ should choose the direction}

local right_octant=right_x 	-- {the octant code before a transition}
local left_octant=left_x 	-- {the octant after a transition}
local right_transition=right_y 	-- {the type of transition}
local left_transition=left_y 	-- {ditto, either |axis| or |diagonal|}
local axis=0 			-- {a transition across the $x'$- or $y'$-axis}
local diagonal=1 		-- {a transition where $y'=\pm x'$}

local mem_top = MFbuiltin.mem_top()
local sentinel= mem_top 	--{end of sorted lists}
local null = mem_min		--  {the null pointer}
local knil=info			-- {inverse of the |link| field, in a doubly linked list}
local zero_w=4
local void=null+1

local zero_field=4096 		-- {amount added to coordinates to make them positive}


chMF(mflua.MF,endpoint);mflua.MF.endpoint = endpoint
chMF(mflua.MF,knot_node_size);mflua.MF.knot_node_size = knot_node_size

chMF(mflua.MF,left_curl);mflua.MF.left_curl = left_curl
chMF(mflua.MF,left_given);mflua.MF.left_given = left_given
chMF(mflua.MF,left_tension);mflua.MF.left_tension = left_tension
chMF(mflua.MF,right_curl);mflua.MF.right_curl = right_curl
chMF(mflua.MF,right_given);mflua.MF.right_given = right_given
chMF(mflua.MF,right_tension);mflua.MF.right_tension = right_tension
chMF(mflua.MF,explicit);mflua.MF.explicit = explicit
chMF(mflua.MF,given);mflua.MF.given = given
chMF(mflua.MF,curl);mflua.MF.curl = curl
chMF(mflua.MF,open);mflua.MF.open = open

chMF(mflua.MF,right_octant);mflua.MF.right_octant = right_octant
chMF(mflua.MF,left_octant);mflua.MF.left_octant = left_octant
chMF(mflua.MF,right_transition);mflua.MF.right_transition = right_transition
chMF(mflua.MF,left_transition);mflua.MF.left_transition = left_transition
chMF(mflua.MF,axis);mflua.MF.axis = axis
chMF(mflua.MF,diagonal);mflua.MF.diagonal = diagonal

chMF(mflua.MF,mem_top);mflua.MF.mem_top = mem_top
chMF(mflua.MF,sentinel);mflua.MF.sentinel = sentinel
chMF(mflua.MF,null);mflua.MF.null = null
chMF(mflua.MF,knil);mflua.MF.knil = knil
chMF(mflua.MF,zero_w);mflua.MF.zero_w = zero_w
chMF(mflua.MF,void);mflua.MF.void = void

chMF(mflua.MF,zero_field);mflua.MF.zero_field = zero_field


-- @d incr(#) == #:=#+1 {increase a variable by unity}
local function incr(p)
 return p+1
end
chMF(mflua.MF,incr);mflua.MF.incr = incr

-- decr(#) == #:=#-1 {decrease a variable by unity}
local function decr(p)
 return p-1
end 
chMF(mflua.MF,decr);mflua.MF.decr = decr

-- double(#) == #:=#+# {multiply a variable by two}
local function double(p)
 return 2*p
end
chMF(mflua.MF,double);mflua.MF.double = double



-- @ An array of digits in the range |0..9| is printed by |print_the_digs|.
-- @<Basic print...@>=
-- procedure print_the_digs(@!k:eight_bits);
--   {prints |dig[k-1]|$\,\ldots\,$|dig[0]|}
-- begin while k>0 do
--   begin decr(k); print_char("0"+dig[k]);
--   end;
-- end;
local function  print_the_digs(k,dig) 
  local res = ''
  while k > 0 do
   k=k-1
   res= res .. dig[k+1]
  end 
  return res 
end
chMF(mflua.MF,print_the_digs);mflua.MF.print_the_digs = print_the_digs


-- @<Basic print...@>=
-- procedure print_int(@!n:integer); {prints an integer in decimal form}
-- var k:0..23; {index to current digit; we assume that $|n|<10^{23}$}
-- @!m:integer; {used to negate |n| in possibly dangerous cases}
-- begin k:=0;
-- if n<0 then
--   begin print_char("-");
--   if n>-100000000 then negate(n)
--   else  begin m:=-1-n; n:=m div 10; m:=(m mod 10)+1; k:=1;
--     if m<10 then dig[0]:=m
--     else  begin dig[0]:=0; incr(n);
--       end;
--     end;
--   end;
-- repeat dig[k]:=n mod 10; n:=n div 10; incr(k);
-- until n=0;
-- print_the_digs(k);
-- end;
local function print_int(n) -- {prints an integer in decimal form}
 local  k  -- 0..23; {index to current digit; we assume that $|n|<10^{23}$}
 local m  --  {used to negate |n| in possibly dangerous cases}
 local dig = {}
 local done
 local res
 local sign=''
 k=0
 if n<0 then
  --begin print_char("-");
  sign='-'
  if n>-100000000 
   then 
    n=-n 
   else
    m=-1-n; n=math.floor(m/10) ; m=math.fmod(m,10)+1; k=1;  
    if m<10 
     then 
      dig[1]=m  
     else
      dig[1]=0; n=n+1
    end
   end
 end
 done=false
 while not done do
  dig[k+1]=math.fmod(n,10); n=math.floor(n/10); k=k+1;
  if n==0 then done=true end 
 end 
 res = print_the_digs(k,dig)
 return sign .. res 
end 
chMF(mflua.MF,print_int);mflua.MF.print_int = print_int



-- @<Basic printing...@>=
-- procedure print_scaled(@!s:scaled); {prints scaled real, rounded to five
--   digits}
-- var @!delta:scaled; {amount of allowable inaccuracy}
-- begin if s<0 then
--   begin print_char("-"); negate(s); {print the sign, if negative}
--   end;
-- print_int(s div unity); {print the integer part}
-- s:=10*(s mod unity)+5;
-- if s<>5 then
--   begin delta:=10; print_char(".");
--   repeat if delta>unity then
--     s:=s+@'100000-(delta div 2); {round the final digit '}
--   print_char("0"+(s div unity)); s:=10*(s mod unity); delta:=delta*10;
--   until s<=delta;
--   end;
-- end;
local function print_scaled(s)
 local delta
 local res = ''
 local done
 if s== nil then print("\nWarning: print_scale called with  nil argument."); return res end
 if s<0 then 
  res = '-'
  s=-s
 end
 res = res .. print_int(math.floor(s/unity)) -- {print the integer part}
 s=10*(math.fmod(s,unity))+5
 if s ~= 5   then
  delta=10; res = res .. '.'
  done = false
  while not done do 
   if delta>unity then
     s=s+half_unit-(math.floor(delta/2))  -- {round the final digit}
   end 
   res = res .. math.floor(s/unity); s=10*math.fmod(s,unity); delta=delta*10;
   if  s<=delta then done = true end
  end;
 end 
 return res
end
chMF(mflua.MF,print_scaled);mflua.MF.print_scaled = print_scaled



-- @<Basic printing...@>=
-- procedure print_two(@!x,@!y:scaled); {prints `|(x,y)|''}
-- begin print_char("("); print_scaled(x); print_char(","); print_scaled(y);
-- print_char(")");
-- end;
local function print_two(x,y) -- {prints `|(x,y)|'}
 local res 
 -- debug 
 -- print("print_two(x,y)",x,y)
 res = '(' .. print_scaled(x) .. ',' .. print_scaled(y) .. ')'
 return res
end
chMF(mflua.MF,print_two);mflua.MF.print_two = print_two

-- procedure unskew(@!x,@!y:scaled;@!octant:small_number);
-- begin case octant of
-- first_octant: set_two(x+y)(y);
-- second_octant: set_two(y)(x+y);
-- third_octant: set_two(-y)(x+y);
-- fourth_octant: set_two(-x-y)(y);
-- fifth_octant: set_two(-x-y)(-y);
-- sixth_octant: set_two(-y)(-x-y);
-- seventh_octant: set_two(y)(-x-y);
-- eighth_octant: set_two(x+y)(-y);
-- end; {there are no other cases}
-- end;
local function unskew ( x , y , octant ) 
  local curx,cury
  if octant == 1 then
      curx = x + y ;
      cury = y ;
  elseif octant == 5 then
      curx = y ;
      cury = x + y ;
  elseif octant == 6 then
      curx = -y ;
      cury = x + y ;
  elseif octant == 2 then
      curx = -x - y ;
      cury = y ;
  elseif octant == 4 then
      curx = -x - y ;
      cury = -y ;
  elseif octant == 8 then
      curx = -y ;
      cury = -x - y ;
  elseif octant == 7 then
      curx = y ;
      cury = -x - y ;
  elseif octant == 3 then
      curx = x + y ;
      cury = -y ;
   end
  return curx,cury 
end
chMF(mflua.MF,unskew);mflua.MF.unskew = unskew

-- print_two_true(#)==unskew(#,octant); print_two(cur_x,cur_y)
local function print_two_true(x,y,octant)
 local cur_x,cur_y ,res
 cur_x,cur_y = unskew ( x , y , octant )
 res = print_two(cur_x,cur_y)
 return res
end
chMF(mflua.MF,print_two_true);mflua.MF.print_two_true = print_two_true
--
-- Debug only
--
-- function mflua_print_path(h)
--    print("mflua_print_path")
--    local p,q
--    local res 
--    local done
--    local done1
--    local f
--    done = false
--    done1 = false 
--    p = h
--    res = '' 
--    while not done do
--       q = link(p)
--       if (p==0) or (q==0) then
-- 	 res = "???"
-- 	 -- do something with res -- 
-- 	 return 0
--       end
--       res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res)
--       if right_type(p) == endpoint then
-- 	 if left_type(p)== open then print("{open?}") end -- {can't happen}
-- 	 if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error}
-- 	 done1 = true --  goto done1;
--       elseif right_type(p) == explicit then 
-- 	 -- begin "@<Print control points between |p| and |q|, then |goto done1|@>"
-- 	 res = res .. "..controls " ..  print_two(right_x(p),right_y(p)) .. " and ";
-- 	 if left_type(q) ~= explicit then print("??")  -- {can't happen}
-- 	 else res = res .. print_two(left_x(q),left_y(q));
-- 	    done1 = true -- goto done1;
-- 	 end
-- 	 -- end "@<Print control points between |p| and |q|, then |goto done1|@>"
--       elseif right_type(p) == open then 
-- 	 -- begin "@<Print information for a curve that begins |open|@>" 
-- 	 if (left_type(p) ~= explicit) and (left_type(p)~=open) then
-- 	    res = res .. "{open?}" -- {can't happen}
-- 	 end  
-- 	 -- end "@<Print information for a curve that begins |open|@>" 
--       elseif (right_type(p) == curl) or (right_type(p) == given) then 
-- 	 -- @ A curl of 1 is shown explicitly, so that the user sees clearly that
-- 	 -- \MF's default curl is present.
-- 	 -- begin @<Print information for a curve that begins |curl|...@>=
-- 	 if left_type(p)==open then res = res .. "??" end --  {can't happen}
-- 	 if right_type(p)==curl then
-- 	    res = res .. "{curl ".. print_scaled(right_curl(p))
-- 	 else  n_sin_cos(right_given(p)); res = res .."{"
-- 	    res = res .. print_scaled(n_cos) .. "," ..  print_scaled(n_sin)
-- 	 end
-- 	 res = res .."}"
-- 	 -- end @<Print information for a curve that begins |curl|...@>=
--       else res = res .. "???" -- {can't happen}
--       end 
--       if not done1 then -- mimic label done 1
-- 	 if left_type(q)~=explicit then res = res .. "..control?" --   {can't happen}
-- 	 else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then
-- 	       -- begin "@<Print tension between |p| and |q|@>;" 
-- 	       res = res .. "..tension "
-- 	       if right_tension(p)<0 then res = res .. "atleast" end 
-- 	       res = res .. print_scaled(math.abs(right_tension(p)))
-- 	       if right_tension(p) ~= left_tension(q) then
-- 		  res = res .. " and "
-- 		  if left_tension(q)<0 then res = res .. "atleast" end
-- 		  res = res .. print_scaled(math.abs(left_tension(q)))
-- 	       end
-- 	    end -- "@<Print tension between |p| and |q|@>;"
-- 	 end
--       end --- LABEL:  done1 
--       -- begin @<Print two dots...@>=
--       p = q
--       res = res .. " .." 
--       if left_type(p)==given then
-- 	 n_sin_cos(left_given(p)); res = res .. "{"
-- 	 res = res  .. print_scaled(n_cos); res = res .. ",";
-- 	 res = res .. print_scaled(n_sin); res = res .. "}";
--       else if left_type(p)==curl then
-- 	    res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}";
-- 	 end;
--       end
--       -- end @<Print two dots...@>=
--       -- end "@<Print information for adjacent knots |p| and |q|@>"
--       if p == h then done =true end
--    end
--    if left_type(h) ~= endpoint then 
--       res = res .. "cycle" 
--    else 
--       res = res
--    end
--    -- do something with res --
--    return res 
-- end



-- n_max(#)==link(#+1) {maximum row number present, plus |zero_field|}
local function n_max(p)
 return link(p+1)
end 
chMF(mflua.MF,n_max);mflua.MF.n_max = n_max


-- sorted_loc(#)==#+1 {where the |sorted| link field resides}
local function sorted_loc(p)
 return p+1 
end
chMF(mflua.MF,sorted_loc);mflua.MF.sorted_loc = sorted_loc


-- @d sorted(#)==link(sorted_loc(#)) {beginning of the list of sorted edge weights}
local function sorted(p)
 return link(sorted_loc(p))
end
chMF(mflua.MF,sorted);mflua.MF.sorted = sorted


-- @d unsorted(#)==info(#+1) {beginning of the list of unsorted edge weights}
local function unsorted(p)
 return info(p+1)
end
chMF(mflua.MF,unsorted);mflua.MF.unsorted = unsorted

-- @d ho(#)==#-min_halfword
--   {to take a sixteen-bit item from a halfword}
-- See mf.ch 
-- ho(#) == #
local function ho(p) 
 return p
end
chMF(mflua.MF,ho);mflua.MF.ho = ho
--
-- @d m_offset(#)==info(#+3) {translation of $m$ data in edge-weight nodes}
--
function m_offset(p)
 return info(p+3)
end



-- @ @<Declare the procedure called |print_weight|@>=
-- procedure print_weight(@!q:pointer;@!x_off:integer);
-- var @!w,@!m:integer; {unpacked weight and coordinate}
-- @!d:integer; {temporary data register}
-- begin d:=ho(info(q)); w:=d mod 8; m:=(d div 8)-m_offset(cur_edges);
-- if file_offset>max_print_line-9 then print_nl(" ")
-- else print_char(" ");
-- print_int(m+x_off);
-- while w>zero_w do
--   begin print_char("+"); decr(w);
--   end;
-- while w<zero_w do
--   begin print_char("-"); incr(w);
--   end;
-- end;
local function print_weight(q,x_off)
 local w,m	-- {unpacked weight and coordinate}
 local d   	--{temporary data register}
 local cur_edges = MFbuiltin.cur_edges()
 local res = '' 
 local temp
 d=ho(info(q)); w=math.fmod(d,8); m=math.floor(d/8)-m_offset(cur_edges);
 res = tostring(print_int(m+x_off))
 while w>zero_w do
    --print(tostring(print_int(m+x_off)) .. " w=" .. w.. " " .. zero_w .. " " .. (w-zero_w))    
    res = res .. "+" ; w=decr(w); 
 end
 while w<zero_w do
    --print(tostring(print_int(m+x_off)) .. " w=" .. w.. " " .. zero_w .. " " .. (w-zero_w))    
    res = res .. "-" ; w=incr(w)
 end
 --print("res=" .. res .. "w=" .. math.fmod(d,8)-zero_w) 
 return res, math.fmod(d,8)-zero_w,tostring(print_int(m+x_off))
end
chMF(mflua.MF,print_weight);mflua.MF.print_weight = print_weight

-- Others utilities functions  
local function odd(n)
   return  math.fmod(n,2) == 1
end
chMF(mflua.MF,odd);mflua.MF.odd = odd

--------------------------------------------------------------------------------
--
-- Read-only callbacs aka Sensors
--
--------------------------------------------------------------------------------

local function begin_program()
 PRINTDBG("begin_program")
end

local function PRE_start_of_MF() 
 PRINTDBG("PRE_start_of_MF")
end

local function PRE_main_control() 
 PRINTDBG("PRE_main_control")
end

local function POST_main_control() 
 PRINTDBG("POST_main_control")
end

local function mflua_initialize() 
 PRINTDBG("mflua_initialize")
end

local function POST_final_cleanup() 
 PRINTDBG("POST_final_cleanup")
end

local function printpath(h,s,nuline)
 PRINTDBG("printpath")
 local p,q
 local res 
 local done
 local done1
 local f
 done = false
 done1 = false 
 p = h
 res = '' 
 while not done do
  q = link(p)
  if (p==0) or (q==0) then
     res = "???"
     -- do something with res -- 
     return 0
  end
  -- We can choose to follow the pascal-web way
  -- or to follow the C-web2c way
  -- begin "@<Print information for adjacent knots |p| and |q|@>"
  res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res)
  if right_type(p) == endpoint then
    if left_type(p)== open then print("{open?}") end -- {can't happen}
    if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error}
    done1 = true --  goto done1;
  elseif right_type(p) == explicit then 
      -- begin "@<Print control points between |p| and |q|, then |goto done1|@>"
      res = res .. "..controls " ..  print_two(right_x(p),right_y(p)) .. " and ";
      if left_type(q) ~= explicit then print("??")  -- {can't happen}
      else res = res .. print_two(left_x(q),left_y(q));
      done1 = true -- goto done1;
      end
      -- end "@<Print control points between |p| and |q|, then |goto done1|@>"
  elseif right_type(p) == open then 
      -- begin "@<Print information for a curve that begins |open|@>" 
      if (left_type(p) ~= explicit) and (left_type(p)~=open) then
        res = res .. "{open?}" -- {can't happen}
      end  
      -- end "@<Print information for a curve that begins |open|@>" 
  elseif (right_type(p) == curl) or (right_type(p) == given) then 
      -- @ A curl of 1 is shown explicitly, so that the user sees clearly that
      -- \MF's default curl is present.
      -- begin @<Print information for a curve that begins |curl|...@>=
      if left_type(p)==open then res = res .. "??" end --  {can't happen}
      if right_type(p)==curl then
        res = res .. "{curl ".. print_scaled(right_curl(p))
      else  n_sin_cos(right_given(p)); res = res .."{"
       res = res .. print_scaled(n_cos) .. "," ..  print_scaled(n_sin)
      end
      res = res .."}"
      -- end @<Print information for a curve that begins |curl|...@>=
  else res = res .. "???" -- {can't happen}
  end 
  if not done1 then -- mimic label done 1
  if left_type(q)~=explicit then res = res .. "..control?" --   {can't happen}
  else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then
    -- begin "@<Print tension between |p| and |q|@>;" 
    res = res .. "..tension "
    if right_tension(p)<0 then res = res .. "atleast" end 
    res = res .. print_scaled(math.abs(right_tension(p)))
    if right_tension(p) ~= left_tension(q) then
       res = res .. " and "
       if left_tension(q)<0 then res = res .. "atleast" end
       res = res .. print_scaled(math.abs(left_tension(q)))
    end
    end -- "@<Print tension between |p| and |q|@>;"
  end
  end --- LABEL:  done1 
  -- begin @<Print two dots...@>=
  p = q
  res = res .. " .." 
  if left_type(p)==given then
    n_sin_cos(left_given(p)); res = res .. "{"
    res = res  .. print_scaled(n_cos); res = res .. ",";
    res = res .. print_scaled(n_sin); res = res .. "}";
  else if left_type(p)==curl then
      res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}";
     end;
  end
  -- end @<Print two dots...@>=
  -- end "@<Print information for adjacent knots |p| and |q|@>"
  if p == h then done =true end
 end
 if left_type(h) ~= endpoint then res = res .. "cycle" end
 -- do something with res --
 res = "%%Print path\n" ..  "drawoptions(withcolor black withpen pencircle scaled 1pt);\n" .. "draw " ..  res .. " ;\n" 
 --print(res)
 -- local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
 -- local char = mflua.chartable[index] or {}
 -- char['char_wd'] = print_scaled(MFbuiltin.char_wd()) 
 -- char['char_ht'] = print_scaled(MFbuiltin.char_ht()) 
 -- char['char_dp'] = print_scaled(MFbuiltin.char_dp()) 
 -- char['char_ic'] = print_scaled(MFbuiltin.char_ic())  
 -- char['res']     =   char['res']  or "" 
 -- char['res']     =   char['res']  .. res 
 -- mflua.chartable[index] = char 
end


-- @ The |print_edges| subroutine gives a symbolic rendition of an edge
-- structure, for use in `\&{show}\' commands. A rather terse output
-- format has been chosen since edge structures can grow quite large.

-- @<Declare subroutines for printing expressions@>=
-- @t\4@>@<Declare the procedure called |print_weight|@>@;@/
-- procedure print_edges(@!s:str_number;@!nuline:boolean;@!x_off,@!y_off:integer);
-- var @!p,@!q,@!r:pointer; {for list traversal}
-- @!n:integer; {row number}
-- begin
-- mflua_printedges(s,nuline,x_off,y_off);
-- print_diagnostic("Edge structure",s,nuline);
-- p:=knil(cur_edges); n:=n_max(cur_edges)-zero_field;
-- while p<>cur_edges do
--   begin q:=unsorted(p); r:=sorted(p);
--   if(q>void)or(r<>sentinel) then
--     begin print_nl("row "); print_int(n+y_off); print_char(":");
--     while q>void do
--       begin print_weight(q,x_off); q:=link(q);
--       end;
--     print(" |");
--     while r<>sentinel do
--       begin print_weight(r,x_off); r:=link(r);
--       end;
--     end;
--   p:=knil(p); decr(n);
--   end;
-- end_diagnostic(true);
-- end;
local function printedges(s,nuline,x_off,y_off)
   PRINTDBG("printedges")
   local p,q,r  --  for list traversal
   local n=0      --  row number
   local cur_edges = MFbuiltin.cur_edges()
   local res =''
   local y =  {} 
   local xr = {}  
   local xq = {} 
   local f, start_row, end_row ,start_row_1, end_row_1 
   local edge
   local w,w_integer,row_weight,xoff
   local chartable = mflua.chartable 
   local index 
   local char
   p = knil(cur_edges)
   n = n_max(cur_edges)-zero_field
   while p ~=  cur_edges do
      xq = {}; xr = {}
      q=unsorted(p); r=sorted(p)
      if(q>void)or(r~=sentinel) then
	 res = "mflua row " .. print_int(n+y_off) ..":"  
	 while (q>void)  do
	    w, w_integer,xoff = print_weight(q,x_off)
	    xq[#xq+1] = {xoff,w_integer}
	    res = res .. w; q=link(q);
	 end
	 res = res .. " |"
	 while r~=sentinel do
	    w,w_integer,xoff = print_weight(r,x_off) 
	    xr[#xr+1]= {xoff,w_integer}
	    res = res .. w .. ' '; r=link(r)
	 end
	 y[#y+1] = {print_int(n+y_off),xq,xr}
      end
      -- print(res)
      p=knil(p);n=decr(n);
   end 
   -- 
   -- local management of y, xq, xr 
   --
   --f = mflua.print_specification.outfile1
   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   char = chartable[index] or {}
   --print("#xq=".. #xq)
   for i,v in ipairs(y) do 
      xq,xr = v[2],v[3]
      -- for j=1, #xq, 2 do end ??
      row_weight=0
      for j=1, #xr, 1 do 
	 local xb = xr[j][1]
	 local xwb = xr[j][2]
	 row_weight=row_weight+xwb
	 xr[j][3]=row_weight
	 --print(v[1],xr[j][1],xr[j][2],xr[j][3])
      end
   end
  char['edges'] =   char['edges'] or {}
  char['edges'][#char['edges']+1] = {y,x_off,y_off}

   char['pre_res']     =   char['pre_res']  or "" 
   for i,v in ipairs(y) do 
      xq,xr = v[2],v[3]
      -- for j=1, #xq, 2 do end ??
      row_weight=0
      char['pre_res']     =   char['pre_res']  .. "%% print edges " .. v[1] .. "\n"
      for j=1, #xr-1, 1 do 
	 local xb,xe = xr[j][1],xr[j+1][1]
	 local xsb,xse = xr[j][3],xr[j+1][3]
	 res = ""
	 if xsb>0 then
	    local color = {'0.7white','0.5white','0.4white'}
	    local col = color[xsb] or 'black'
	    res = res .. "drawoptions(withcolor " .. col .. " withpen pencircle scaled 0.1pt);\n" 
	    edge = string.format("fill (%s,%s) -- (%s,%s) -- (%s,%s+1) --  (%s,%s+1) --  cycle  shifted (-(%s),-(%s));\n",
	       xb,v[1],xe,v[1],xe,v[1],xb,v[1],x_off,y_off)
	    res = res .. edge 
	    --
	    res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.1pt);\n" 
	    edge = string.format("draw (%s,%s) -- (%s,%s) -- (%s,%s+1) --  (%s,%s+1) --  cycle  shifted (-(%s),-(%s));\n",
	       xb,v[1],xe,v[1],xe,v[1],xb,v[1],x_off,y_off)
	    res = res .. edge 
	 end
	 -- print(v[1],xr[j][1],xr[j][2],xr[j][3])
	 char['pre_res']     =   char['pre_res']  .. res
      end
   end
end
mflua.MF.printedges = printedges




-- @ The |print_pen| subroutine illustrates these conventions by
-- reconstructing the vertices of a polygon from \MF\'s complicated 
-- internal offset representation.
-- @<Declare subroutines for printing expressions@>=

local function print_pen(p,s,nuline)
   local nothing_printed -- {:boolean has there been any action yet?}
   local k 		--1..8; {octant number}
   local h 		-- pointer; {offset list head}
   local m,n 		-- integer; {offset indices}
   local w,ww  		-- :pointer; {pointers that traverse the offset list}
   local res = ''
  -- begin print_diagnostic("Pen polygon",s,nuline);
   nothing_printed=true; -- print()
   for k=1,8 do
      local octant=octant_code[k]; h=p+octant; n=info(h); w=link(h);
      -- print("%% octant",octant_dir[octant],n,w)
      if not(odd(k)==true) then w=knil(w) end  -- {in even octants, start at $w_{n+1}$}
      for m=1, n+1 do
	 if odd(k)==true then ww=link(w)  else ww=knil(w)    end
	 -- print("%% ".. m .. "/" .. n+1 .. " w=" .. print_two_true(x_coord(w),y_coord(w),octant) .. " ww=" .. print_two_true(x_coord(ww),y_coord(ww),octant))
	 if (x_coord(ww)~=x_coord(w)) or (y_coord(ww)~=y_coord(w)) then
	    ---@<Print the unskewed and unrotated coordinates of node |ww|@>;
	    if nothing_printed then nothing_printed=false else  -- print(" .. ") 
	    end
	    -- print(print_two_true(x_coord(ww),y_coord(ww),octant))
	    res = res .. print_two_true(x_coord(ww),y_coord(ww),octant)
	 end
	 w=ww;
      end -- for m=1, n+1 do
   end -- for k=1,8 do
   if nothing_printed==true then
      w=link(p+first_octant); print(print_two(x_coord(w)+y_coord(w),y_coord(w)));
      res = res .. print_two(x_coord(w)+y_coord(w),y_coord(w))
   end;
   res = res  .. " .. cycle"; --end_diagnostic(true);
   return res 
end -- function
mflua.MF.print_pen = print_pen

mflua.offset_prep = mflua.offset_prep or  {}

local function _get_pen(p)
   local nothing_printed -- {:boolean has there been any action yet?}
   local k 		--1..8; {octant number}
   local h 		-- pointer; {offset list head}
   local m,n 		-- integer; {offset indices}
   local w,ww  		-- :pointer; {pointers that traverse the offset list}
   local res = {}
   nothing_printed=true; 
   for k=1,8 do
      local octant=octant_code[k]; h=p+octant; n=info(h); w=link(h);
      if not(odd(k)==true) then w=knil(w) end  -- {in even octants, start at $w_{n+1}$}
      for m=1, n+1 do
	 if odd(k)==true then ww=link(w)  else ww=knil(w)    end
	 if (x_coord(ww)~=x_coord(w)) or (y_coord(ww)~=y_coord(w)) then
	    ---@<Print the unskewed and unrotated coordinates of node |ww|@>;
	    if nothing_printed then nothing_printed=false else  -- print(" .. ") 
	    end
	    -- print(print_two_true(x_coord(ww),y_coord(ww),octant))
	    res[#res+1] = print_two_true(x_coord(ww),y_coord(ww),octant)
	 end
	 w=ww;
      end -- for m=1, n+1 do
   end -- for k=1,8 do
   if nothing_printed==true then
      w=link(p+first_octant); 
      res[#res+1] = print_two(x_coord(w)+y_coord(w),y_coord(w))
   end;
   -- print(" .. cycle"); --end_diagnostic(true);
   return res 
end
mflua.offset_prep._get_pen = _get_pen

local function _get_offset_coords(p,octant)
  local nothing_printed -- {:boolean has there been any action yet?}
  local k 		--1..8; {octant number}
  local h 		-- pointer; {offset list head}
  local m,n 		-- integer; {offset indices}
  local w,ww  		-- :pointer; {pointers that traverse the offset list}
  local res ={}  
  nothing_printed=true; --print()
  k=octant_number[octant]; 
  h=p+octant; n=info(h); w=link(h);
  if not(odd(k)==true) then w=knil(w) end  -- {in even octants, start at $w_{n+1}$}
  for m=1, n+1 do
   if odd(k)==true then ww=link(w)  else ww=knil(w)    end
   res[m] = print_two_true(x_coord(w),y_coord(w),octant)
   w=ww;
  end -- for m=1, n+1 do
  return res 
end -- function
mflua.offset_prep._get_offset_coords = _get_offset_coords


-- @ Given a pointer |c| to a nonempty list of cubics,
-- and a pointer~|h| to the header information of a pen polygon segment,
-- the |offset_prep| routine changes the list into cubics that are
-- associated with particular pen offsets. Namely, the cubic between |p|
-- and~|q| should be associated with the |k|th offset when |right_type(p)=k|.

-- List |c| is actually part of a cycle spec, so it terminates at the
-- first node whose |right_type| is |endpoint|. The cubics all have
-- monotone-nondecreasing $x(t)$ and $y(t)$.

mflua.do_add_to = mflua.do_add_to or {} 
mflua.do_add_to.bezier_octant          = {}
mflua.do_add_to.bezier_octant_envelope = {}
mflua.do_add_to.bezier_octant_I        = {} 
mflua.do_add_to.bezier_octant_contour  = {} 


local function print_specification(c,h)
   local p,q,n,nh
   local octant
   local cur_spec
   local res,res1 = "",""
   local offsets = {}
   local cubic,cubics ={},{}
   local f   
   local first_point, first_point_offset

   local bezier,beziers ={},{}
   local offset_list = {}
   local path_list ={}
   local bezier_octant
   local pen_key = ''
   local temp1 = mflua.print_specification.temp1

   cur_spec=c
   p=cur_spec 
   --n=info(h) 
   --lh=link(h)	--{now |lh| points to $w_0$}
   octant = left_octant(p)
   offsets =  mflua.offset_prep._get_offset_coords(MFbuiltin.cur_pen(),octant)
   
   -- for l=1,#offsets do print("SPEC " .. offsets[l] )end

   cubics['offsets'] = offsets
   cubics['octant_number'] = octant_number[octant]

   beziers['offsets'] = offsets
   beziers['octant_number'] = octant_number[octant]
   beziers['pen'] = mflua.offset_prep._get_pen(MFbuiltin.cur_pen())  
   
   for i,v in ipairs(beziers['pen']) do  
     --print(  "BEZ pen=",i,v)  
     pen_key = pen_key..v
   end
   --if not(mflua.pen[pen_key] == nil) then
      --table.foreach(mflua.pen[pen_key],print)
   --end   
   --
   --res = res .. "%% cur_pen " .. tostring(MFbuiltin.cur_pen()) .."\n"
   --res = res .. string.format("%%%% current octant %s, octant number %s, offset %s\n",octant_dir[MFbuiltin.octant()],octant_number[octant],print_int(n))
   --res = res .. "pair offset[];\n"
   --for i,v in ipairs(offsets) do
   --  res = res .. string.format("offset%s:=%s;\n",i-1,v)
   --end
   --res = res .. "pair OffSet; OffSet:=offset"..print_int(n) ..";\n" 
   --res = res .. "path p; p:= " .. print_two_true(x_coord(p),y_coord(p),octant) .. "\n"
   --cubic['p'] = print_two_true(x_coord(p),y_coord(p),octant)
   first_point = print_two_true(x_coord(p),y_coord(p),octant)
   first_point_offset = print_int(right_type(p))
   --
   --print(res);
   local end_loop_1 = false
   while end_loop_1 == false do
     local end_loop_2 = false
     while end_loop_2 == false do
     	q=link(p);
        if right_type(p)==endpoint then 
	   end_loop_2=true 
	else    
	   cubic['p'] = print_two_true(x_coord(p),y_coord(p),octant);
           cubic['control1'] = print_two_true(right_x(p),right_y(p),octant)
           cubic['control2'] = print_two_true(left_x(q),left_y(q),octant)
	   cubic['q'] =  print_two_true(x_coord(q),y_coord(q),octant)
	   cubic['offset'] =  print_int(right_type(p))
	   cubic['segment'] =  print_int(left_type(q)-1)
	   cubics[#cubics+1] = cubic
	   cubic = {}
	   bezier['p'] = print_two_true(x_coord(p),y_coord(p),octant);
           bezier['control1'] = print_two_true(right_x(p),right_y(p),octant)
           bezier['control2'] = print_two_true(left_x(q),left_y(q),octant)
	   bezier['q'] =  print_two_true(x_coord(q),y_coord(q),octant)
	   bezier['offset'] =  print_int(right_type(p))
	   bezier['segment'] =  print_int(left_type(q)-1)
	   beziers[#beziers+1] = bezier
	   bezier = {}
	   p=q
       end 
     end 
     -- not_found label 
     if q==cur_spec then 
       end_loop_1=true 
     else
       p=q; octant=left_octant(p); -- print("% entering octant `");
     end
     --  We don't want all the octans of the cubic
     --  only the pieces of the current octant
     end_loop_1 = not(MFbuiltin.octant() == octant)
   end
   if #cubics == 0 then
     cubics['single_point'] = first_point
     cubics['single_point_offset'] = first_point_offset
   end
   -- done label: 
   -- We can now use the results
   --
   -- No curves stored
   if #beziers == 0 then
     beziers['single_point'] = first_point
     beziers['single_point_offset'] = first_point_offset
   end
   if #beziers['offsets'] == 1 then 
      offset_list[#offset_list+1] = {0,beziers['offsets'][1]}
      offset_list[#offset_list+1] = {1,beziers['offsets'][1]}
   else
      for i,v in ipairs(beziers['offsets']) do
	 if odd(beziers['octant_number']) == true then  
	    offset_list[#offset_list+1] = {(i-1),v}
	 else
	    offset_list[#offset_list+1] = {#beziers['offsets']-i+1,v}
	 end
     end
   end
   beziers['offset_list']=offset_list
   beziers['path_list'] = {}
   if #beziers == 0 then
      path_list['p'] = beziers['single_point']
      if odd(beziers['octant_number']) == true then  
	 path_list['offset'] = beziers['single_point_offset']
      else
	 path_list['offset'] = #beziers['offsets']-beziers['single_point_offset']
      end      
      beziers['path_list'][#beziers['path_list']+1] = path_list
      path_list={}
   else   
      for i,v in ipairs(beziers) do
	 bezier = v 
	 path_list['p'] = bezier['p'] 
	 path_list['control1'] = bezier['control1'] 
	 path_list['control2'] = bezier['control2'] 
	 path_list['q'] = bezier['q'] 
	 path_list['offset'] = bezier['offset']
	 beziers['path_list'][#beziers['path_list']+1] = path_list
	 path_list={}
      end
   end
   bezier_octant =mflua.do_add_to.bezier_octant 
   bezier_octant[#bezier_octant+1] = beziers
   res = ""
   res = res .. "%% cur_pen " .. tostring(MFbuiltin.cur_pen()) .."\n"
   --res = res .. string.format("%%%% current octant %s, offset %s\n",octant_dir[MFbuiltin.octant()],print_int(n))
   res = res .. string.format("%%%% current octant %s\n",octant_dir[MFbuiltin.octant()])
   res = res .. "pair offset[];\n"
   if #cubics['offsets'] == 1 then 
      res = res .."%% Only one offset\n"
      res = res ..string.format("offset%s:=%s;\n",0,cubics['offsets'][1])
      res = res ..string.format("offset%s:=%s;\n",1,cubics['offsets'][1])
   else 
      for i,v in ipairs(cubics['offsets']) do
	 if odd(cubics['octant_number']) == true then  
            res = res .. string.format("offset%s:=%s;\n",(i-1),v)
	 else
            res = res .. string.format("offset%s:=%s;\n",#cubics['offsets']-i+1,v)
	 end
     end
   end
   res = res .. "%% cubics['octant_number'])=" .. cubics['octant_number'] .. "\n"
   res = res .. "%% #cubics=" .. #cubics .. "\n"
   if #cubics == 0 then
     res = res .. "path p; p:=" .. cubics['single_point'] .. ";\n"
     res = res .. "drawoptions(withcolor red withpen pencircle scaled 0.1pt);\n"
     temp1 = temp1 +1             
     if odd(cubics['octant_number']) == true then  
     	   res = res .. "draw p shifted offset" .. cubics['single_point_offset']  ..  ";\n"
           res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n",
 	      	 		       	cubics['single_point'],cubics['single_point_offset'],temp1,cubics['single_point'],cubics['single_point_offset'])
     else
            res = res .. "draw p shifted offset" .. #cubics['offsets']-cubics['single_point_offset']  ..  ";\n"
            res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n",
	       	cubics['single_point'],#cubics['offsets']-cubics['single_point_offset'],temp1,cubics['single_point'],#cubics['offsets']-cubics['single_point_offset'])
     end      
   end
   -- if #cubics == 0 then this for loop is never executed
   for i,v in ipairs(cubics) do
     cubic = v 
     res = res .. "path p; p:= " .. cubic['p'] .."\n"
     res = res .. " .. controls " .. cubic['control1'] .." and " .. cubic['control2']
     res = res .. " .. " ..  cubic['q'] .."\n ;\n"
     res = res .. 'label("'.. octant_dir[MFbuiltin.octant()] ..'"' .. ",0.5[" .. cubic['p'] .. "," .. cubic['q']  .."]) shifted offset" .. cubic['offset'] .. ";\n"
     res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.2pt);\n"
     res = res .. "draw p shifted offset" .. cubic['offset'] ..  ";\n"
     temp1 = temp1 +1
     res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(-0.5,-0.5)) shifted offset%s;\n",
 	      	 		       	cubic['p'],cubic['offset'],temp1,cubic['p'],cubic['offset'])
     temp1 = temp1 +1
     res = res .. string.format("pickup pencircle scaled 0.2pt;drawdot(%s) shifted offset%s withcolor 0.75white;label(\"%s\",%s+(0.5,0.5)) shifted offset%s;\n",
 	      	 		       	cubic['q'],cubic['offset'],temp1,cubic['q'],cubic['offset'])

   end
   mflua.print_specification.temp1 = temp1 
   res = res .. string.format("%%%%mflua.print_specification.temp1 = %s\n" ,mflua.print_specification.temp1)
   --print("\n%%POST START\n".. res .. "%%POST END\n")
   -- f = io.open("envelope.tex",'a')
   -- f = mflua.print_specification.outfile1
   -- f:write("\n%%POST START\n".. res .. "\n%%POST END\n")
   --f:close()
end
mflua.MF.print_specification = print_specification 



local function PRE_offset_prep(c,h)
  PRINTDBG("PRE_offset_prep")
  -- local p = c
  -- print("\nBEZ TEST".. print_int(right_type(p)))
  -- print ("BEZ TEST".. print_two(x_coord(p),y_coord(p)))
  -- print ("BEZ TEST".. print_two(right_x(p),right_y(p)))
  -- p = link(p)
  -- print ("BEZ TEST".. print_two(left_x(p),left_y(p)))
end

local function POST_offset_prep(c,h)
  PRINTDBG("POST_offset_prep")
  -- print("\nPOST print pen"); mflua.MF.print_pen(MFbuiltin.cur_pen(),"" , "")  
  -- print("\nPOST print specification") 
  --res = print_pen(MFbuiltin.cur_pen(),"" , "")  
  --print(" PRINT PEN " .. res )
  mflua.MF.print_specification(c,h)
end


mflua.do_add_to = mflua.do_add_to or {}

local function _get_cycle(h)
   local p,q
   local res = ''
   local done
   local done1
   local f
   local cycle = {}
   done = false
   done1 = false 
   p = h
   while not done do
      q = link(p)
      if (p==0) or (q==0) then
	 return '???'
      end
      cycle[#cycle+1] = {tonumber(print_scaled(x_coord(p))), tonumber(print_scaled(y_coord(p)))} -- p
      --res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res)
      if right_type(p) == endpoint then
	 if left_type(p)== open then return "{open?}" end -- {can't happen}
	 if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error}
	 done1 = true --  goto done1;
      elseif right_type(p) == explicit then 
	 -- begin "@<Print control points between |p| and |q|, then |goto done1|@>"
	 --res = res .. "..controls " ..  print_two(right_x(p),right_y(p)) .. " and ";
	 cycle[#cycle+1] = {tonumber(print_scaled(right_x(p))), tonumber(print_scaled(right_y(p)))} -- c1
	 if left_type(q) ~= explicit then return "??"  -- {can't happen}
	 else
	    --res = res .. print_two(left_x(q),left_y(q));
	    cycle[#cycle+1] = {tonumber(print_scaled(left_x(q))), tonumber(print_scaled(left_y(q)))} -- c2
	    done1 = true -- goto done1;
	 end
	 -- end "@<Print control points between |p| and |q|, then |goto done1|@>"
      elseif right_type(p) == open then 
	 -- begin "@<Print information for a curve that begins |open|@>" 
	 if (left_type(p) ~= explicit) and (left_type(p)~=open) then
	    return "{open?}" -- {can't happen}
	 end  
	 -- end "@<Print information for a curve that begins |open|@>" 
      elseif (right_type(p) == curl) or (right_type(p) == given) then 
	 -- @ A curl of 1 is shown explicitly, so that the user sees clearly that
	 -- \MF's default curl is present.
	 -- begin @<Print information for a curve that begins |curl|...@>=
	 if left_type(p)==open then res = res .. "??" end --  {can't happen}
	 if right_type(p)==curl then
	    res = res .. "{curl ".. print_scaled(right_curl(p))
	 else  n_sin_cos(right_given(p)); res = res .."{"
	    res = res .. print_scaled(n_cos) .. "," ..  print_scaled(n_sin)
	 end
	 res = res .."}"
	 -- end @<Print information for a curve that begins |curl|...@>=
      else return "???" -- {can't happen}
      end 
      if not done1 then -- mimic label done 1
	 if left_type(q)~=explicit then return  "..control?" --   {can't happen}
	 else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then
	       -- begin "@<Print tension between |p| and |q|@>;" 
	       res = res .. "..tension "
	       if right_tension(p)<0 then res = res .. "atleast" end 
	       res = res .. print_scaled(math.abs(right_tension(p)))
	       if right_tension(p) ~= left_tension(q) then
		  res = res .. " and "
		  if left_tension(q)<0 then res = res .. "atleast" end
		  res = res .. print_scaled(math.abs(left_tension(q)))
	       end
	    end -- "@<Print tension between |p| and |q|@>;"
	 end
      end --- LABEL:  done1 
      -- begin @<Print two dots...@>=
      p = q
      --res = res .. " .." 
      if left_type(p)==given then
	 n_sin_cos(left_given(p)); res = res .. "{"
	 res = res  .. print_scaled(n_cos); res = res .. ",";
	 res = res .. print_scaled(n_sin); res = res .. "}";
      else if left_type(p)==curl then
	    res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}";
	 end;
      end
      -- end @<Print two dots...@>=
      -- end "@<Print information for adjacent knots |p| and |q|@>"
      if p == h then done =true end
   end
   if left_type(h) ~= endpoint then 
      res = res .. "cycle" 
   end
   -- do something with res --
   return res ,cycle
end
mflua.do_add_to._get_cycle = _get_cycle


-- @p procedure print_spec(@!s:str_number);
-- label not_found,done;
-- var @!p,@!q:pointer; {for list traversal}
-- @!octant:small_number; {the current octant code}
-- begin print_diagnostic("Cycle spec",s,true);
-- @.Cycle spec at line...@>
-- p:=cur_spec; octant:=left_octant(p); print_ln;
-- print_two_true(x_coord(cur_spec),y_coord(cur_spec));
-- print(" % beginning in octant `");
-- loop@+  begin print(octant_dir[octant]); print_char("'");
--   loop@+  begin q:=link(p);
--     if right_type(p)=endpoint then goto not_found;
--     @<Print the cubic between |p| and |q|@>;
--     p:=q;
--     end;
-- not_found: if q=cur_spec then goto done;
--   p:=q; octant:=left_octant(p); print_nl("% entering octant `");
--   end;
-- @.entering the nth octant@>
-- done: print_nl(" & cycle"); end_diagnostic(true);
-- end;
local function _print_spec(cur_spec)
 --print("\n.....Hello world from _print_spec!.....")
 local p,q 
 local octant
 --local res = '' 
 local knot = {} 
 local knots = {} 
 -- local res = {}
 local endloop1 = false
 local endloop2 = false

 p=cur_spec; octant=left_octant(p); --print()
 -- res = res .. print_two_true(x_coord(cur_spec),y_coord(cur_spec),octant)
 knot[#knot+1] = print_two_true(x_coord(cur_spec),y_coord(cur_spec),octant)
 while (endloop1 == false)  do
    -- print('%%' .. octant_dir[octant])
    endloop2 = false
    while (endloop2 == false)  do
       q = link(p)
       if right_type(p)==endpoint then 
	  endloop2 = true -- goto not_found;
       else
	  -- print(' @<Print the cubic between |p| and |q|@>;')
	  -- c1
	  knot[#knot+1] = print_two_true(right_x(p),right_y(p),octant)
	  -- c2
	  knot[#knot+1] = print_two_true(left_x(q),left_y(q),octant)
	  -- q
	  knot[#knot+1] = print_two_true(x_coord(q),y_coord(q),octant)
	  -- segment
	  knot[#knot+1] = print_int(left_type(q)-1)
	  knots[#knots+1] = knot
	  knot = {} 
	  -- res = res .." ..controls "
	  -- res = res .. print_two_true(right_x(p),right_y(p),octant)
	  -- res = res .." and "
	  -- res = res ..print_two_true(left_x(q),left_y(q),octant)
	  -- res = res .. "\n .."
	  -- res = res .. print_two_true(x_coord(q),y_coord(q),octant)
	  -- res = res .." % segment " ..print_int(left_type(q)-1) .. "\n";
	  p=q;
	  knot[#knot+1] = print_two_true(x_coord(p),y_coord(p),octant)
       end
    end -- endloop2
    -- not_found
    if q == cur_spec then 
       endloop1 = true 
    else
       p=q; octant=left_octant(p) --  print("% entering octant `");
    end
 end -- endloop1
 --done: 
 -- print(" & cycle") ; end_diagnostic(true);
 -- print("%BEZ TEST\ndraw "..res .. ";\n")
 -- table.foreach(knots,function (k) table.foreach(knots[k],print) end)
 return knots
end
mflua.do_add_to._print_spec = _print_spec


local function _store_current_envelope()
   local bezier_octant_envelope = mflua.do_add_to.bezier_octant_envelope 
   local bezier_octant = mflua.do_add_to.bezier_octant 
   if (#bezier_octant_envelope == 0) then
      local _t = {} 
      for i,v in ipairs(bezier_octant) do _t[i] = v end
      bezier_octant_envelope[1] = _t
   else
      local _cnt=0 
      for i,v in ipairs(bezier_octant_envelope) do _cnt=_cnt+#v end
      local _t = {} 
      for i,v in ipairs(bezier_octant) do if i>_cnt then _t[#_t+1] = v end end
      bezier_octant_envelope[#bezier_octant_envelope+1] = _t
   end
   mflua.do_add_to.bezier_octant_envelope = bezier_octant_envelope 
   return 0
end
mflua.do_add_to._store_current_envelope = _store_current_envelope


local function _postprocessing()
   local bezier_octant
   local beziers,offsets

   local path_list
   local prev_point 
   local path_cnt
   local res = "%% postprocessing envelope\n"
   local f
   local chartable = mflua.chartable 
   local index 
   local char

   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   --print("CHAR " .. index)
   --print("%% postprocessing envelope "..index.. ' ' .. #chartable)
   
   res = res .. "path p[];\n"

   --  The last part of envelope added
   bezier_octant = mflua.do_add_to.bezier_octant_envelope[#mflua.do_add_to.bezier_octant_envelope] 

   path_cnt = 1
   for i,v in ipairs(bezier_octant) do
      beziers = v
      offsets = beziers['offsets']
      path_list = beziers['path_list'] 
      local offset_list = beziers['offset_list']
      for i,path in ipairs(path_list) do
	 local shifted 
         local p,c1,c2,q,offset = 
	    path['p'],path['control1'],path['control2'],path['q'],path['offset']  	 
	 for i,v in ipairs(offset_list) do 
	    if v[1] == (0+offset) then 
	       shifted = v[2] 
	       break 
	    end 
	 end 
	 if (q == nil) then
	    res = res .. string.format("p%d:=(%s) shifted %s;%% shifted 1\n",
				       path_cnt,p,shifted)
	 else
	    res = res .. string.format("p%d:=(%s .. controls %s and %s .. %s) shifted %s;%% shifted 2\n",
				       path_cnt,p,c1,c2,q,shifted)
	 end
	 path_cnt = path_cnt +1
      end	 
   end
   res = res .. "%% path_cnt=" .. path_cnt .. " char_code=" .. print_int(MFbuiltin.char_code()) .. " char_ext=" .. print_int(MFbuiltin.char_ext()) 
   res = res ..  " char_wd=" .. print_scaled(MFbuiltin.char_wd()) 
   res = res ..  " char_ht=" .. print_scaled(MFbuiltin.char_ht()) 
   res = res ..  " char_dp=" .. print_scaled(MFbuiltin.char_dp()) 
   res = res ..  " char_ic=" .. print_scaled(MFbuiltin.char_ic())  
   res = res ..  " \n"

   res = res .. "drawoptions(withcolor (" .. math.random().."," .. math.random()..",".. math.random()..  ") withpen pencircle scaled 0.4pt);\n"
   res = res .. "draw p1"
   for i=2,path_cnt-1 do 
      res = res .. string.format(" --  p%d",i)
   end 
   res = res .. " --cycle;\n"

   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   char = chartable[index] or {}
   char['char_wd'] = print_scaled(MFbuiltin.char_wd()) 
   char['char_ht'] = print_scaled(MFbuiltin.char_ht()) 
   char['char_dp'] = print_scaled(MFbuiltin.char_dp()) 
   char['char_ic'] = print_scaled(MFbuiltin.char_ic())  
   char['envelope'] = char['envelope'] or {}
   char['envelope'][#char['envelope']+1] = bezier_octant
   char['res']     =   char['res']  or "" 
   char['res']     =   char['res']  .. res 
   char['index'] = index
   chartable[index] = char 
end
mflua.do_add_to._postprocessing = _postprocessing


local function _store_current_contour()
   local bezier_octant_contour = mflua.do_add_to.bezier_octant_contour
   local bezier_octant_I = mflua.do_add_to.bezier_octant_I 
   if (#bezier_octant_contour == 0) then
      local _t = {} 
      for i,v in ipairs(bezier_octant_I) do _t[i] = v end
      bezier_octant_contour[1] = _t
   else
      local _cnt=0 
      for i,v in ipairs(bezier_octant_contour) do _cnt=_cnt+#v end
      local _t = {} 
      for i,v in ipairs(bezier_octant_I) do if i>_cnt then _t[#_t+1] = v end end
      bezier_octant_contour[#bezier_octant_contour+1] = _t
   end
   mflua.do_add_to.bezier_octant_contour = bezier_octant_contour 
   return 0
end
mflua.do_add_to._store_current_contour = _store_current_contour


local function _postprocessing_contour()
   local bezier_octant_contour,contour,path_list
   local chartable = mflua.chartable 
   local index 
   local char
   local res  = ""
   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   res = res .. "%% postprocessing contour for " .. index ..";\n"
   res = res .. "path p[];\n"
   print("CHAR " .. index)
   bezier_octant_contour = mflua.do_add_to.bezier_octant_contour[#mflua.do_add_to.bezier_octant_contour]
   
   path_cnt = 1
   for i,v in ipairs(bezier_octant_contour) do
      contour = v
      path_list = contour['path_list']
      for i,path in ipairs(path_list) do
	 local p,c1,c2,q = path['p'],path['control1'],path['control2'],path['q']
	 if (q == nil) then
	    res = res .. string.format("p%d:=(%s);\n",   path_cnt,p)
	 else
	    res = res .. string.format("p%d:=(%s .. controls %s and %s .. %s);\n",path_cnt,p,c1,c2,q)
	 end
	 path_cnt = path_cnt +1
      end	 
   end
   if path_cnt > 1 then 
      res = res .. "drawoptions(withcolor black withpen pencircle scaled 0.3pt);\n"
      res = res .. "draw  p1"
      for i=2,path_cnt-1 do 
	 res = res .. string.format(" --  p%d",i)
      end 
      res = res .. " --cycle ;\n"
   end


   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   --print("BEZ index="..index)
   char = chartable[index] or {}
   char['char_wd'] = print_scaled(MFbuiltin.char_wd()) 
   char['char_ht'] = print_scaled(MFbuiltin.char_ht()) 
   char['char_dp'] = print_scaled(MFbuiltin.char_dp()) 
   char['char_ic'] = print_scaled(MFbuiltin.char_ic())  
   char['contour'] = char['contour'] or {}
   char['contour'][#char['contour']+1] = bezier_octant_contour
   char['res']     =   char['res']  or "" 
   char['res']     =   char['res']  .. res 
   char['index'] = index
   chartable[index] = char 
  return 0
end
mflua.do_add_to._postprocessing_contour = _postprocessing_contour

-- local function _circular_list_geti(l,i) 
--    local size = #l
--    if size==0 then 
--     return nil
--    end
--    return l[1+(i-1)%size] 
-- end


local function _store_current_cycle(hs) 
   local res, current_cycle 
   res, current_cycle = mflua.do_add_to._get_cycle(hs)
   --print( mflua_print_path(hs) )
   if res=='cycle' then 
      -- for i=0,(#current_cycle/3)-1 do 
      --    local l = current_cycle
      --    local base = i*3
      --    local p,c1,c2,q = _circular_list_geti(l,base+1) , _circular_list_geti(l,base+2),_circular_list_geti(l,base+3),_circular_list_geti(l,base+4)    
      --    print (string.format("%d/%d (%f,%f) .. controls (%f,%f) and (%f,%f) .. (%f,%f) ",(i-1)%3,#current_cycle,
      -- 				 p[1],p[2],c1[1],c1[2],c2[1],c2[2],q[1],q[2]))
       
      -- end  
     local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
     local char = mflua.chartable[index] or {}
     char['cycle'] = char['cycle'] or  {}
     char['cycle'][#char['cycle']+1] = current_cycle
     
     mflua.chartable[index] = char 
   else
      print("Error:"..res)
   end
end      
mflua.do_add_to._store_current_cycle = _store_current_cycle


local function PRE_make_spec_rhs(rhs)
   PRINTDBG("PRE_make_spec_rhs")
   mflua.do_add_to._store_current_cycle(rhs) 
end 

local function POST_make_spec_rhs(rhs)
   PRINTDBG("POST_make_spec_rhs")
   --print("post rhs MFbuiltin.turning_number=",MFbuiltin.turning_number() ) ;
end 


local function PRE_make_spec_lhs(lhs)
  PRINTDBG("PRE_make_spec_lhs")
  mflua.do_add_to._store_current_cycle(lhs) 
end 

local function POST_make_spec_lhs(lhs)
  PRINTDBG("PRE_make_spec_lhs")
  print("post lhs MFbuiltin.turning_number=",MFbuiltin.turning_number() ) ;
end 

local function PRE_fill_envelope_rhs(rhs)
   PRINTDBG("PRE_fill_envelope_rhs")
   local knots ,knots_list
   local index,char
   local chartable = mflua.chartable 
   knots = mflua.do_add_to._print_spec(rhs)
   index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   char = chartable[index] or {}
   knots_list = char['knots'] or {}
   knots_list[#knots_list+1] = knots 
   char['knots'] = knots_list
   chartable[index] = char 
end 

local function POST_fill_envelope_rhs(rhs) 
   PRINTDBG("POST_fill_envelope_rhs")
   mflua.do_add_to._store_current_envelope()
   mflua.do_add_to._postprocessing()
end 

local function PRE_fill_envelope_lhs(lhs)
   PRINTDBG("PRE_fill_envelope_lhs")
end 

local function POST_fill_envelope_lhs(lhs) 
   PRINTDBG("POST_fill_envelope_lhs")
   mflua.do_add_to._store_current_envelope()
   mflua.do_add_to._postprocessing()
end 

local function PRE_fill_spec_rhs(rhs)
   PRINTDBG("PRE_fill_spec_rhs")
   --print_specification_contour(rhs)
end 

local function POST_fill_spec_rhs(rhs) 
   PRINTDBG("POST_fill_spec_rhs")
   mflua.do_add_to._store_current_contour()
   mflua.do_add_to._postprocessing_contour()
end 

local function PRE_fill_spec_lhs(lhs)
   PRINTDBG("PRE_fill_spec_lhs")
   --print_specification_contour(lhs)
end 

local function POST_fill_spec_lhs(lhs) 
   PRINTDBG("POST_fill_spec_lhs")
   mflua.do_add_to._store_current_contour()
   mflua.do_add_to._postprocessing_contour()
end 


--------------------------------------------------------------------------------
--
-- fill_spec 
--
--------------------------------------------------------------------------------

mflua.fill_spec = mflua.fill_spec or {}

-- @ Here's a routine that prints a cycle spec in symbolic form, so that it
-- is possible to see what subdivision has been made.  The point coordinates
-- are converted back from \MF's internal ``rotated'' form to the external
-- ``true'' form. The global variable~|cur_spec| should point to a knot just
-- after the beginning of an octant boundary, i.e., such that
-- |left_type(cur_spec)=endpoint|.
local function print_specification_contour(h)
   local p,q,n,nh
   local octant
   local cur_spec
   local res = ""
   local f   
   local first_point, first_point_offset
   local path_cnt
   local bezier_contour,beziers_contour ={},{}
   local offset_list = {}
   local path_list ={}
   local bezier_octant_I
   cur_spec=h
   p=cur_spec 
   octant = left_octant(p)
   beziers_contour['octant_number'] = octant_number[octant]
   first_point = print_two_true(x_coord(p),y_coord(p),octant)
   first_point_offset = print_int(right_type(p))
   local end_loop_1 = false
   while end_loop_1 == false do
     local end_loop_2 = false
     while end_loop_2 == false do
     	q=link(p);
        if right_type(p)==endpoint then 
	   end_loop_2=true 
	else    
	   bezier_contour['p'] = print_two_true(x_coord(p),y_coord(p),octant);
           bezier_contour['control1'] = print_two_true(right_x(p),right_y(p),octant)
           bezier_contour['control2'] = print_two_true(left_x(q),left_y(q),octant)
	   bezier_contour['q'] =  print_two_true(x_coord(q),y_coord(q),octant)
	   beziers_contour[#beziers_contour+1] = bezier_contour
	   bezier_contour = {}
	   p=q
       end 
     end 
     -- not_found label 
     if q==cur_spec then 
       end_loop_1=true 
     else
       p=q; octant=left_octant(p); -- print("% entering octant `");
     end
     --  We don't want all the octans of the cycle
     --  only the pieces of the current octant
     end_loop_1 = not(MFbuiltin.octant() == octant)
   end
   -- done label: 
   -- We can now use the results
   -- No curves stored
   if #beziers_contour == 0 then
     beziers_contour['single_point'] = first_point
   end
   beziers_contour['path_list'] = {}
   if #beziers_contour == 0 then
      path_list['p'] = beziers_contour['single_point']
      beziers_contour['path_list'][#beziers_contour['path_list']+1] = path_list
      path_list={}
   else   
      for i,v in ipairs(beziers_contour) do
	 bezier_contour = v 
	 path_list['p'] = bezier_contour['p'] 
	 path_list['control1'] = bezier_contour['control1'] 
	 path_list['control2'] = bezier_contour['control2'] 
	 path_list['q'] = bezier_contour['q'] 
	 beziers_contour['path_list'][#beziers_contour['path_list']+1] = path_list
	 path_list={}
      end
   end
   bezier_octant_I =mflua.do_add_to.bezier_octant_I 
   bezier_octant_I[#bezier_octant_I+1] = beziers_contour
  return 0
end
mflua.MF.print_specification_contour = print_specification_contour


local function PRE_move_to_edges(p) 
   PRINTDBG("PRE_move_to_edges")
   mflua.MF.print_specification_contour(p)
end


local function POST_move_to_edges(p) 
   PRINTDBG("POST_move_to_edges")
end


--
-- scan_direction
--

mflua.scan_direction = mflua.scan_direction  or {}

local function _print_path(h,s,nuline)
   local p,q
   local res 
   local done
   local done1
   local f
   done = false
   done1 = false 
   p = h
   res = '' 
   while not done do
      q = link(p)
      if (p==0) or (q==0) then
	 res = "???"
	 -- do something with res -- 
	 return 0
      end
      res = res .. print_two(x_coord(p),y_coord(p)); -- print("res=",res)
      if right_type(p) == endpoint then
	 if left_type(p)== open then print("{open?}") end -- {can't happen}
	 if (left_type(q) ~= endpoint) or (q ~= h) then q=null end -- {force an error}
	 done1 = true --  goto done1;
      elseif right_type(p) == explicit then 
	 -- begin "@<Print control points between |p| and |q|, then |goto done1|@>"
	 res = res .. "..controls " ..  print_two(right_x(p),right_y(p)) .. " and ";
	 if left_type(q) ~= explicit then print("??")  -- {can't happen}
	 else res = res .. print_two(left_x(q),left_y(q));
	    done1 = true -- goto done1;
	 end
	 -- end "@<Print control points between |p| and |q|, then |goto done1|@>"
      elseif right_type(p) == open then 
	 -- begin "@<Print information for a curve that begins |open|@>" 
	 if (left_type(p) ~= explicit) and (left_type(p)~=open) then
	    res = res .. "{open?}" -- {can't happen}
	 end  
	 -- end "@<Print information for a curve that begins |open|@>" 
      elseif (right_type(p) == curl) or (right_type(p) == given) then 
	 -- @ A curl of 1 is shown explicitly, so that the user sees clearly that
	 -- \MF's default curl is present.
	 -- begin @<Print information for a curve that begins |curl|...@>=
	 if left_type(p)==open then res = res .. "??" end --  {can't happen}
	 if right_type(p)==curl then
	    res = res .. "{curl ".. print_scaled(right_curl(p))
	 else  n_sin_cos(right_given(p)); res = res .."{"
	    res = res .. print_scaled(n_cos) .. "," ..  print_scaled(n_sin)
	 end
	 res = res .."}"
	 -- end @<Print information for a curve that begins |curl|...@>=
      else res = res .. "???" -- {can't happen}
      end 
      if not done1 then -- mimic label done 1
	 if left_type(q)~=explicit then res = res .. "..control?" --   {can't happen}
	 else if (right_tension(p) ~= unity) or (left_tension(q) ~= unity) then
	       -- begin "@<Print tension between |p| and |q|@>;" 
	       res = res .. "..tension "
	       if right_tension(p)<0 then res = res .. "atleast" end 
	       res = res .. print_scaled(math.abs(right_tension(p)))
	       if right_tension(p) ~= left_tension(q) then
		  res = res .. " and "
		  if left_tension(q)<0 then res = res .. "atleast" end
		  res = res .. print_scaled(math.abs(left_tension(q)))
	       end
	    end -- "@<Print tension between |p| and |q|@>;"
	 end
      end --- LABEL:  done1 
      -- begin @<Print two dots...@>=
      p = q
      res = res .. " .." 
      if left_type(p)==given then
	 n_sin_cos(left_given(p)); res = res .. "{"
	 res = res  .. print_scaled(n_cos); res = res .. ",";
	 res = res .. print_scaled(n_sin); res = res .. "}";
      else if left_type(p)==curl then
	    res = res .. "{curl "; res = res .. print_scaled(left_curl(p)) .. "}";
	 end;
      end
      -- end @<Print two dots...@>=
      -- end "@<Print information for adjacent knots |p| and |q|@>"
      if p == h then done =true end
   end
   if left_type(h) ~= endpoint then 
      res = res .. "cycle" 
   else 
      res = res
   end
   -- do something with res --
   return res 
   --res = "drawoptions(withcolor black withpen pencircle scaled 1pt);\n" .. "draw " ..  res .. " ;\n" 
   --print(res)
   -- local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   -- local char = mflua.chartable[index] or {}
   -- char['char_wd'] = print_scaled(MFbuiltin.char_wd()) 
   -- char['char_ht'] = print_scaled(MFbuiltin.char_ht()) 
   -- char['char_dp'] = print_scaled(MFbuiltin.char_dp()) 
   -- char['char_ic'] = print_scaled(MFbuiltin.char_ic())  
   -- char['res']     =   char['res']  or "" 
   -- char['res']     =   char['res']  .. res 
   -- mflua.chartable[index] = char 
   -- return 0
end
mflua.scan_direction.print_path = _print_path

local function PRE_make_choices(p)
   PRINTDBG("PRE_make_choices")
   -- _print_path(p,"PRE make choice",false)
end

local function POST_make_choices(p)
   PRINTDBG("POST_make_choices")
   --local res = ''
   --res = _print_path(p,"POST make choice",false)
   --print(res)
end

local function print_retrograde_line(x0,y0,cur_x,cur_y)
   PRINTDBG("print_retrograde_line")
   local chartable = mflua.chartable 
   local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   local char = chartable[index] or {}
   local tab = char['retrograde_line'] or  {}
   tab[#tab+1] = {print_two(x0,y0),print_two(cur_x,cur_y)}
   char['retrograde_line'] = tab
   --print("%%Retrograde line")
   --print("drawoptions(withcolor (0,0.6,0) withpen pencircle scaled 0.09pt);")
   --print("draw "..  print_two(x0,y0) .. " -- " .. print_two(cur_x,cur_y) ..";")
end


local function PRE_make_ellipse(major_axis,minor_axis,theta,tx,ty,q)
   PRINTDBG("PRE_make_ellipse")
 --print("major_axis,minor_axis,theta,tx,ty,q=",major_axis,minor_axis,theta,tx,ty,q)
end

local function POST_make_ellipse(major_axis,minor_axis,theta,tx,ty,q)
   PRINTDBG("POST_make_ellipse")
   --print("major_axis,minor_axis,theta,tx,ty,q=",print_two(major_axis,minor_axis),theta*(2^-20),print_two(tx,ty),print_two(x_coord(q),y_coord(q)))
   local flag=true
   local p=q
   local res = ''
   local xy
   local i = 0
   while flag do
      i=i+1
  res = res ..print_two(x_coord(p),y_coord(p))
  p=link(p)
  if p==q then flag=false end
   end 
   mflua.pen[res] = {print_two(major_axis,minor_axis),  
		     theta*(2^-20),print_two(tx,ty)}

end



local function print_transition_line_from(x,y)
   PRINTDBG("print_transition_line_from")
   local octant = MFbuiltin.octant()
   --local res = ""
   local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   local chartable = mflua.chartable
   local char = chartable[index] or {}
   local p = print_two_true(x,y,octant)
   local c1 = p
   char['transition_lines'] =  char['transition_lines'] or {}
   char['transition_lines'][#char['transition_lines']+1]={p,p} 
   return 0
end 


local function print_transition_line_to(x,y)
   PRINTDBG("print_transition_line_to")
   local octant = MFbuiltin.octant()
   local index = (0+print_int(MFbuiltin.char_code())) +  (0+print_int(MFbuiltin.char_ext()))*256
   local chartable = mflua.chartable
   local char = chartable[index] or {}
   local q = print_two_true(x,y,octant)
   local c2 = q
   char['transition_lines_set'] =  char['transition_lines_set'] or {}
   char['transition_lines'] =  char['transition_lines'] or {}
   local _t = char['transition_lines'][#char['transition_lines']]
   local p = _t[1]
   --
   -- avoid multiple lines
   --
   --print("BEZ char['transition_lines_set'][p..q]=",char['transition_lines_set'][p..q])
   if char['transition_lines_set'][p..q]==true or char['transition_lines_set'][q..p]==true then
      char['transition_lines'][#char['transition_lines']]=nil
      return 0
   end
   char['transition_lines_set'][p..q]=true
   char['transition_lines_set'][q..p]=true
   --
   -- remove curves that degenerate into points
   --
   if p~=q then
      _t[#_t+1] = c2
      _t[#_t+1] = q
      _t[#_t+1] = '(0,0)'
      _t[#_t+1] = 'transition_line'
   else
      char['transition_lines'][#char['transition_lines']]=nil
   end
   return 0
end 


local function end_program()
   PRINTDBG("end_program")
   local f = kpse.find_file('end_program.lua','lua')
   if f==nil then 
      print("Warning: end_program.lua not found")
      return 
   end
   local func,errmsg  = loadfile(f)
   if not(func) then
      print(errmsg)
      os.exit(1)
   end
   status, msg = pcall(func)
   if not(status) then
      print(msg)
      os.exit(status)
   end
end    


--
-- Add local function to mflua
--

mflua.begin_program			 = begin_program
mflua.PRE_start_of_MF			 = PRE_start_of_MF
mflua.PRE_main_control			 = PRE_main_control
mflua.POST_main_control			 = POST_main_control
mflua.mflua_initialize			 = mflua_initialize
mflua.POST_final_cleanup		 = POST_final_cleanup
mflua.printpath				 = printpath
mflua.printedges			 = printedges
mflua.PRE_offset_prep			 = PRE_offset_prep
mflua.POST_offset_prep			 = POST_offset_prep

mflua.PRE_make_spec_rhs			 = PRE_make_spec_rhs
mflua.POST_make_spec_rhs		 = POST_make_spec_rhs
mflua.PRE_make_spec_lhs			 = PRE_make_spec_lhs
mflua.POST_make_spec_lhs		 = POST_make_spec_lhs
mflua.PRE_fill_envelope_rhs		 = PRE_fill_envelope_rhs
mflua.POST_fill_envelope_rhs		 = POST_fill_envelope_rhs
mflua.PRE_fill_envelope_lhs		 = PRE_fill_envelope_lhs
mflua.POST_fill_envelope_lhs		 = POST_fill_envelope_lhs
mflua.PRE_fill_spec_rhs			 = PRE_fill_spec_rhs
mflua.POST_fill_spec_rhs		 = POST_fill_spec_rhs
mflua.PRE_fill_spec_lhs			 = PRE_fill_spec_lhs
mflua.POST_fill_spec_lhs		 = POST_fill_spec_lhs

mflua.PRE_move_to_edges			 = PRE_move_to_edges 
mflua.POST_move_to_edges		 = POST_move_to_edges

mflua.PRE_make_choices			 = PRE_make_choices
mflua.POST_make_choices			 = POST_make_choices

mflua.print_retrograde_line		 = print_retrograde_line

mflua.PRE_make_ellipse			 = PRE_make_ellipse
mflua.POST_make_ellipse			 = POST_make_ellipse

mflua.print_transition_line_from	 = print_transition_line_from
mflua.print_transition_line_to		 = print_transition_line_to

mflua.end_program			 = end_program           


--------------------------------------------------------------------------------
--
-- Other setups, mostly depend on old routines 
--
--------------------------------------------------------------------------------

mflua.max_recursion_level = 32



mflua.bit = 7					 -- should be 4 
mflua.pen = {}					 -- collect bezier curves of the pens

mflua.pi = 2*math.atan2(1,0)
mflua.print_specification = mflua.print_specification or {}
mflua.print_specification.temp1 = 0
mflua.print_specification.p  = ""
mflua.print_specification.q  = ""
mflua.threshold_path_removed = 4		 -- how many path we can safely remove 
mflua.threshold_extra_step = 2			 -- add values/mflua.threshold_extra_step time values 
mflua.threshold_small_path_check_point = 3	 -- check  3 pixels for horiz/vert. paths 
mflua.threshold_small_pen_path = 0.001		 -- _fix_wrong_pending_path
mflua.threshold_fix = 1				 -- _fix_wrong_pending_path
mflua.threshold = 1				 -- _remove_small_path
mflua.threshold_degree = 2			 -- _remove_small_path
mflua.threshold_degree_1 = 90			 -- _remove_small_path
mflua.threshold_degree_2 = 270			 -- _remove_small_path
mflua.threshold_small_curve = 2			 -- _remove_reduntant_curves
mflua.threshold_normal_curve = 4		 -- _remove_reduntant_curves
mflua.threshold_min_dist = 0.5			 -- _remove_reduntant_curves
mflua.threshold_pending_path = 0.002		 -- _remove_reduntant_curves
mflua.threshold_pen = 5				 -- _remove_redundant_segments
mflua.threshold_bug = 4				 -- _fix_intersection_bug
mflua.threshold_min_bug = 0.03			 -- _fix_intersection_bug
mflua.threshold_equal_path=0.03			 -- _remove_duplicate_pen_path
mflua.threshold_straight_line = 0.125            -- _is_a_straight_line
mflua.threshold_fix_knots = 0.125		 -- _fix_knots
mflua.threshold_fix_knots_1 = 0.0005		 -- _fix_knots
mflua.threshold_fix_knots_2 = 0.4		 -- _fix_knots
mflua.threshold_remove_redundant_pen = 0.02      -- remove_redundant_pen 
mflua.threshold_remove_redundant_curves = 3      -- _remove_redundant_curves
mflua.threshold_merge_segments =  5e-5		 -- _merge_segments
mflua.threshold_join_curves =  0.049		 -- _build_cycles try and error
mflua.set_poly_done={}
mflua.mflua_exe = 'mflua'
mflua.turningnumber_file='mflua_tn'
mflua.fill_envelope = {}
mflua.fill_envelope.temp_transition = ""
mflua.pen = {}



--

mflua.chartable  ={}
mflua.max_curves =1e4


function mflua.lock(params) 
   if params ==nil then 
      return io.open('LOCK1','w') 
   else 
      return io.open(tostring(params),'w') 
   end 
end

function mflua.unlock(params) 
   if params == nil then 
      return os.remove('LOCK1') 
   else
      return os.remove(tostring(params))
   end
end

function mflua.checklock(params) 
   if params == nil then 
      if io.open("LOCK1") ~= nil then return true else return false end
   else
      if io.open(tostring(params)) ~= nil then return true else return false end
   end
end


function mflua.dot(P1,P2)
   return P1[1]*P2[1]+P1[2]*P2[2]
end

function mflua.angle(p,q) 
   local dot = mflua.dot  
   if math.abs(1 - dot(p,q)/(math.sqrt(dot(p,p))*math.sqrt(dot(q,q)))) <0.0001 then 
      return 0 
   else 
      return math.acos(dot(p,q)/(math.sqrt(dot(p,p))*math.sqrt(dot(q,q))))
   end 
end
-- function mflua.vec(a,w,b1) if b1 == nil then b=w else b = b1 end ; return {b[1]-a[1],b[2]-a[2]} end
-- mflua.vec(a,b) == mflua.vec(a,'->',b)
function mflua.round(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p p={w(),w()};
   return string.format("(%6.5f,%6.5f)",tostring(p[1]),tostring(p[2]) )
end

function mflua.round5(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p; p={w(),w()};
   return string.format("(%6.5f,%6.5f)",tostring(p[1]),tostring(p[2]) )
end

function mflua.round2(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p; p={w(),w()};
   return string.format("(%6.2f,%6.2f)",tostring(p[1]),tostring(p[2]) )
end

function mflua.round1(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p; p={w(),w()};
   return string.format("(%6.1f,%6.1f)",tostring(p[1]),tostring(p[2]) )
end

function mflua.round0(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p; p={w(),w()};
   return string.format("(%6.0f,%6.0f)",tostring(p[1]),tostring(p[2]) )
end

function mflua.floor(p)
   local w=string.gmatch(p,"[-0-9.]+");
   local p; p={w(),w()};
   return string.format("(%d,%d)",math.floor(p[1]),math.floor(p[2]) )
end

function mflua.round5_table(p)
   return {tonumber(string.format("%6.5f",tostring(p[1]))),tonumber(string.format("%6.5f",tostring(p[2])))}
end

function mflua.number_to_string_round5(p)
   return string.format("(%6.5f,%6.5f)",p[1],p[2])
end


function mflua.vec(a,b)
   return {b[1]-a[1],b[2]-a[2]}
end

function mflua.modul_vec(a,b)
   local dot = mflua.dot
   local P ={b[1]-a[1],b[2]-a[2]}
   return math.sqrt(dot(P,P))
end

function mflua.approx_curve_lenght(p,c1,c2,q)
   return  mflua.modul_vec(p,c1) + mflua.modul_vec(c1,c2) + mflua.modul_vec(c2,q) + mflua.modul_vec(p,q)
end


-- to permit multiple instances of mflua
if io.open('LOCK1')==nil and io.open('LOCK_ELLIPSE')==nil then 
   mflua.print_specification.filename  = "envelope.tex"
   mflua.print_specification.outfile1  = io.open(mflua.print_specification.filename,'w')
end





--------------------------------------------------------------------------------
--
-- tfm module
--
--------------------------------------------------------------------------------
local tfm = {}
tfm.bits = 
   function(a,l) 
      local bita = {}
      local a = a
      for k=1,l do 
	 local r=math.fmod(a,2)  
	 a=math.floor(a/2) 
	 bita[k]=r
      end 
      return bita
   end
tfm.bitand =
   function(a,b,l)
      local bita,bitb,bitc = tfm.bits(a,l), tfm.bits(b,l),{}
      local c= 0
      for k=1,l do 
	 bit1,bit2 = bita[k],bitb[k]
	 if (bit1==1) and (bit2==1) then 
	    bitc[k]=1
	 else
	    bitc[k]=0
	 end
	 c = c+2^(k-1)*bitc[k]
      end 
      return c,bitc
   end
tfm.bitor =
   function(a,b,l)
      local bita,bitb,bitc = tfm.bits(a,l), tfm.bits(b,l),{}
      local c= 0
      for k=1,l do 
	 bit1,bit2 = bita[k],bitb[k]
	 if (bit1==1) or (bit2==1) then 
	    bitc[k]=1
	 else
	    bitc[k]=0
	 end
	 c = c+ 2^(k-1)*bitc[k]
      end 
      return c,bitc
   end
tfm.bitnot =
   function(a,l)
      local bita,bitb = tfm.bits(a,l),{}
      local b= 0
      for k=1,l do 
	 bit1 = bita[k]
	 if (bit1==1) then 
	    bitb[k]=0
	 else
	    bitb[k]=1
	 end
	 b = b+ 2^(k-1)*bitb[k]
      end 
      return b,bitb
   end
tfm.printbits=
   function(t,l) 
      local r = ''
      local l = l or #t
      if l==0 then return '' end 
      for k=l,1,-1 do 
	 local v = t[k] or '0'
	 r=r..v
      end 
      return r
   end

tfm.stop_flag = 128 
tfm.kern_flag = 128 

tfm.parameters = {}
tfm.parameters.init =
   function()
      -- 8. The first 24 bytes (6 words) of a TFM file contain twelve 16-bit integers that give the lengths of the
      -- various subsequent portions of the file. These twelve integers are, in order:
      -- lf = length of the entire file, in words;
      -- lh = length of the header data, in words;
      -- bc = smallest character code in the font;
      -- ec = largest character code in the font;
      -- nw  = number of words in the width table;
      -- nh  = number of words in the height table;
      -- nd  = number of words in the depth table;
      -- ni = number of words in the italic correction table;
      -- nl = number of words in the lig/kern table;
      -- nk  = number of words in the kern table;
      -- ne  = number of words in the extensible character table;
      -- np  = number of font parameter words.
      -- They are all nonnegative and less than 2^15 . We must have bc - 1<=  ec <= 255, ne<=  256, and
      -- 	 lf = 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np .
      -- When two or more 8-bit bytes are combined to form an integer of 16 or more bits, the most
      -- significant bytes appear first in the file. This is called BigEndian order.
      
      if tfm.content ==nil or type(tfm.content)~= 'string' then
	 return false, 'Error on file content'
      end
      tfm.parameters.w = string.gmatch(tfm.content,"[%z%Z]")
      local w = tfm.parameters.w
      local W1,W2

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (lf)'  end
      tfm.parameters.lf = 256*string.byte(W1)+string.byte(W2) -- length of the entire file, in words;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (lh)'  end
      tfm.parameters.lh = 256*string.byte(W1)+string.byte(W2) -- length of the header data, in words;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (bc)'  end
      tfm.parameters.bc = 256*string.byte(W1)+string.byte(W2) -- smallest character code in the font;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ec)'  end
      tfm.parameters.ec = 256*string.byte(W1)+string.byte(W2) -- largest character code in the font;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nw)'  end
      tfm.parameters.nw = 256*string.byte(W1)+string.byte(W2) -- number of words in the width table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nh)'  end
      tfm.parameters.nh = 256*string.byte(W1)+string.byte(W2) -- number of words in the height table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nd)'  end
      tfm.parameters.nd = 256*string.byte(W1)+string.byte(W2) -- number of words in the depth table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ni)'  end
      tfm.parameters.ni = 256*string.byte(W1)+string.byte(W2) -- number of words in the italic correction table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nl)'  end
      tfm.parameters.nl = 256*string.byte(W1)+string.byte(W2) -- number of words in the lig/kern table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (nk)'  end
      tfm.parameters.nk = 256*string.byte(W1)+string.byte(W2) -- number of words in the kern table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (ne)'  end
      tfm.parameters.ne = 256*string.byte(W1)+string.byte(W2) -- number of words in the extensible character table;

      W1,W2=w(),w();if W1==nil or W2==nil then return false, 'Error on parsing content (np)'  end
      tfm.parameters.np = 256*string.byte(W1)+string.byte(W2) -- number of font parameter words.
      return 
   end

tfm.parameters.check = 
   function()
      local w  = tfm.parameters.w  
      local lf = tfm.parameters.lf
      local lh = tfm.parameters.lh
      local bc = tfm.parameters.bc
      local ec = tfm.parameters.ec
      local nw = tfm.parameters.nw
      local nh = tfm.parameters.nh
      local nd = tfm.parameters.nd
      local ni = tfm.parameters.ni
      local nl = tfm.parameters.nl
      local nk = tfm.parameters.nk
      local ne = tfm.parameters.ne
      local np = tfm.parameters.np
      local status = true 
      local status_cnt = 0
      local status_msg = 'OK'
      local function _assert(cond,msg)
	 if cond==false then
	    --print(msg) 
	    status_msg = msg
	    status_cnt = status_cnt +1
	 end
      end
      if status_cnt == 0 then _assert(lf == 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ,"Error on lf") end
      if status_cnt == 0 then _assert(0<=lf  and lf <2^15,"lf  out of range") end
      if status_cnt == 0 then _assert(0<=lh  and lh <2^15,"lh  out of range") end
      if status_cnt == 0 then _assert(0<=bc  and bc <2^15,"bc  out of range") end
      if status_cnt == 0 then _assert(0<=ec  and ec <2^15,"ec  out of range") end
      if status_cnt == 0 then _assert(0<=nw  and nw <2^15,"nw  out of range") end
      if status_cnt == 0 then _assert(0<=nh  and nh <2^15,"nh  out of range") end
      if status_cnt == 0 then _assert(0<=nd  and nd <2^15,"nd  out of range") end
      if status_cnt == 0 then _assert(0<=ni  and ni <2^15,"ni  out of range") end
      if status_cnt == 0 then _assert(0<=nl  and nl <2^15,"nl  out of range") end
      if status_cnt == 0 then _assert(0<=nk  and nk <2^15,"nk  out of range") end
      if status_cnt == 0 then _assert(0<=ne  and ne <2^15,"ne  out of range") end
      if status_cnt == 0 then _assert(0<=np  and np <2^15,"np  out of range") end
      if status_cnt == 0 then _assert( (bc-1)<=ec and ec<= 255, "Error on bc and ec") end
      if status_cnt == 0 then _assert(ne<= 256, "ne >256")			      end
      if status_cnt > 0 then status=false end
      return status,status_msg 
   end

   
tfm.int_to_frac = 
   function(d)
      if not (0<=d and d<2^32) then 
	 return nil, string.format("Error: %s out of range (-%s,%s-2^-20)",d,2^31,2^31) 
      else 
	 if d<=2147483647 then 
	    return d/2^20,'ok'
	 else
	    return (d-2^32)/2^20,'ok'
	 end
      end
      
   end
tfm.tag_meaning = 
   function(d)
      local t = {'vanilla character','character has a ligature/kerning program',
		 'character has a successor in a charlist','character is extensible'}
      local d = tonumber(d) or -1
      if d<0 or d>3 then return '' end
      return t[tonumber(d+1)]
   end

tfm.getface = 
   function(d)
      --If the value is less than 18, it has the following
      --interpretation as a "weight, slope, and expansion": Add 0 or 2 or 4 (for medium or bold or light) to
      --0 or 1 (for roman or italic) to 0 or 6 or 12 (for regular or condensed or extended). For example, 13 is
      --0+1+12, so it represents medium italic extended. A three-letter code (e.g., MIE) can be used for such
      --face data.
      -- d = 3⋅rce_bit⋅2^{2,1} + ri_bit + mbl_bit⋅2^{2,1}  , rce_bit,ri_bit,mbl_bit ∈ {0,1}
      -- d%2 = ri_bit := ri 
      -- d%3 - d%2 = mbl⋅2^{2,1} := mbl
      -- d - d%3 =  3⋅rce⋅2^{2,1} := rce
      if d>17 then return '' end
      local mbl,ri, rce = '*','*','*'
      local _ri = d % 2 
      if _ri==0 then ri ='R' else ri ='I' end
      local _mbl = (d%3) -(d%2) 
      if _mbl == 0 then mbl='M' end
      if _mbl == 2 then mbl='B' end
      if _mbl == 4 then mbl='E' end
      local _rce = d - (d%3) 
      if _rce == 0 then rce = 'M' end
      if _rce == 1 then rce = 'I' end
      if _rce == 12 then rce = 'E' end
      return mbl..ri..rce, {_mbl,_ri,_rce}
   end

tfm.printfloat =
   function(d,p)
      local d,p = tostring(d), tonumber(p) or 6
      local f = string.format("%%.%df",p)
      return string.format(f,d)
   end 

tfm.array = {}
tfm.array.check = 
   function()
      local width     = tfm.array.width       
      local height    = tfm.array.height      
      local depth     = tfm.array.depth       
      local italic    = tfm.array.italic      
      local status = true 
      local status_cnt = 0
      local status_msg = 'OK'
      local function _assert(cond,msg)
	 if cond==false then
	    --print(msg) 
	    status_msg = msg
	    status_cnt = status_cnt +1
	 end
      end
      _assert(width[0]==0,'Error in width[0]')
      _assert(height[0]==0,'Error in height[0]')
      _assert(depth[0]==0,'Error in depth[0]')
      _assert(italic[0]==0,'Error in italic[0]')
      if status_cnt > 0 then status=false end
      return status,status_msg 

   end

tfm.dump={} 
tfm.dump.kernprogram =
   function(d,c)
      local char_info = tfm.array.char_info
      local lig_kern  = tfm.array.lig_kern 
      local kern      = tfm.array.kern 
      local current_step = d
      local current_char = c
      local skip_byte=lig_kern[current_step][1]
      local next_char=lig_kern[current_step][2]
      local op_byte=lig_kern[current_step][3]
      local remainder=lig_kern[current_step][4]
      local _print = tfm.printdebug()
      _print("-------")
      _print("skip_byte=",skip_byte)
      _print("next_char=",next_char,'C '..string.char(next_char),'O '..string.format("%o",next_char))
      _print("op_byte=",op_byte)
      _print("remainder=",remainder,string.format("O %o",remainder))
      if op_byte <tfm.kern_flag  then -- a ligature step
	 -- op_byte= 4a+2b+c where 0<=a<=b+c and 0<=b,c<=1.
	 local a,b,c
	 c=  op_byte%2
	 b = ((op_byte-c)%4)/2
	 a = (op_byte-2*b-c)/4
	 _print("ligature step: a,b,c=",a,b,c)
	 if b==0 then 
	    _print("current char: deleted") 
	 else 
	    _print("current char: not deleted" ) 
	 end 
	 if c==0 then 
	    _print("next char: deleted") 
	 else 
	    _print("next char: not deleted ") 
	 end
	 if a==0 then 
	    _print("no next char") 
	 else 
	    -- we must pass over the next a characters
	    -- local _,_remainder,_,_,_tag,_ = char_info[current_char+a]
	    -- if _tag==1 then 
	    --    local kern_program = tfm.dump.kernprogram(_remainder,current_char+a)
	    -- end
	 end 
	 tfm.chars[current_char] = tfm.chars[current_char] or {}
	 tfm.chars[current_char].ligature =  tfm.chars[current_char].ligature or {}
	 tfm.chars[current_char].ligature[#tfm.chars[current_char].ligature+1]= 
	    {['next_char']=next_char,['a']=a,['b']=b,['c']=c}

      else -- a kern step
	 local additional_space = kern[256*(op_byte-128)+remainder]
	 _print("kern step:additional_space=",tfm.printfloat(additional_space))
	 tfm.chars[current_char] = tfm.chars[current_char] or {}
	 tfm.chars[current_char].kern =  tfm.chars[current_char].kern or {}
	 tfm.chars[current_char].kern[#tfm.chars[current_char].kern+1] = 
	    {['next_char']=next_char,['additional_space']=additional_space}
      end

      if skip_byte>=tfm.stop_flag then 
	 -- end
	 return 
      else 
	 -- take next instruction	 
	 tfm.dump.kernprogram(current_step+1+skip_byte,current_char)
      end
   end


tfm.build = {}
tfm.build.header =
   function(i,j,w)
      local _i,_j,_a = i,j,{}
      for i=_i,_j do 
	 if i<=1 or i>17 then 
	    _a[i] =2^24*string.byte(w())+2^16*string.byte(w())+2^8*string.byte(w())+string.byte(w())
	 elseif 2<=i and i<=16 then 
	    _a[i] =w()..w()..w()..w()
	 elseif i==17 then 
	    _a[i] ={string.byte(w()),string.byte(w()),string.byte(w()),string.byte(w())}
	 end
      end
      return _a
   end

tfm.build._bytearray = 
   function(i,j,w) 
      local _i,_j,_a = i,j,{}
      for i=_i,_j do 
	 _a[i] ={string.byte(w()),string.byte(w()),string.byte(w()),string.byte(w())}
      end
      return _a
   end
tfm.build.char_info = tfm.build._bytearray
tfm.build.lig_kern  = tfm.build._bytearray
tfm.build.exten     = tfm.build._bytearray

tfm.build._dimension = 
   function(i,j,w) 
      local _i,_j,_a = i,j,{}
      for i=_i,_j do 
	 _a[i] = tfm.int_to_frac(2^24*string.byte(w())+2^16*string.byte(w())+2^8*string.byte(w())+string.byte(w()))
      end
      return _a
   end
tfm.build.width  = tfm.build._dimension
tfm.build.height = tfm.build._dimension
tfm.build.depth  = tfm.build._dimension
tfm.build.italic = tfm.build._dimension
tfm.build.kern   = tfm.build._dimension
tfm.build.param  = tfm.build._dimension

tfm.build.all = 
   function()
      local w  = tfm.parameters.w  
      local lf = tfm.parameters.lf
      local lh = tfm.parameters.lh
      local bc = tfm.parameters.bc
      local ec = tfm.parameters.ec
      local nw = tfm.parameters.nw
      local nh = tfm.parameters.nh
      local nd = tfm.parameters.nd
      local ni = tfm.parameters.ni
      local nl = tfm.parameters.nl
      local nk = tfm.parameters.nk
      local ne = tfm.parameters.ne
      local np = tfm.parameters.np
      tfm.array.header    = tfm.build.header(0,lh-1,w)
      tfm.array.char_info = tfm.build.char_info(bc,ec,w)
      tfm.array.width     = tfm.build.width( 0,nw-1,w)
      tfm.array.height    = tfm.build.height(0,nh-1,w)
      tfm.array.depth     = tfm.build.depth( 0,nd-1,w)
      tfm.array.italic    = tfm.build.italic(0,ni-1,w) 
      tfm.array.lig_kern  = tfm.build.lig_kern(0,nl-1,w)
      tfm.array.kern      = tfm.build.kern(0,nk-1,w)
      tfm.array.exten     = tfm.build.exten(0,ne-1,w)
      tfm.array.param     = tfm.build.param(1,np,w)
   end

tfm.debug = 1
tfm.printdebug = 
   function()
      if tfm.debug==1 then
	 return print
      else
	 return function(...) end
      end
   end

tfm.getdata={}
tfm.getdata.char_info = 
   function(i)
      local char_info = tfm.array.char_info
      local width_index = char_info[i][1]
      local height_index_plus_depth_index = char_info[i][2]
      local italic_index_plus_tag = char_info[i][3]
      local remainder = char_info[i][4]
      local depth_index = height_index_plus_depth_index % 16
      local height_index= (height_index_plus_depth_index -depth_index)/16
      local tag = italic_index_plus_tag % 4
      local italic_index = (italic_index_plus_tag -tag)/4
      return width_index,remainder,depth_index,height_index,tag,italic_index
   end
tfm.chars = {}
tfm.font = {}

tfm.run=
   function(name)
      local name = name
      local _print = tfm.printdebug
      local header    ={}        
      local char_info ={}    
      local width     ={}    
      local height    ={}    
      local depth     ={}    
      local italic    ={}    
      local lig_kern  ={}    
      local kern      ={}    
      local exten     ={}    
      local param     ={}    
      local w   
      local lf 
      local lh 
      local bc 
      local ec 
      local nw 
      local nh 
      local nd 
      local ni 
      local nl 
      local nk 
      local ne 
      local np 

      if  kpse.find_file(name)==nil then 
	 name = name .. ".tfm"
      end
      if  kpse.find_file(name)==nil then 
	 return false, "Error: file "..tostring(name).." not found" 
      end
      tfm.name = name
      tfm.file = io.open(tfm.name,'rb')
      if tfm.file == nil then 
	 return false, "Error on opening file "..tostring(tfm.name) 
      end 
      tfm.content = tfm.file:read("*a")
      status,status_msg = tfm.parameters.init()
      if status== false then 
	 _print("ERROR="..tostring(status_msg))
	 return false, tostring(status_msg)
      end

      status,status_msg = tfm.parameters.check()
      if status == false then 
	 _print("ERROR="..tostring(status_msg))
	 return false, tostring(status_msg)
      end
      -- Build all arrays
      tfm.build.all() 
      header    = tfm.array.header          
      char_info = tfm.array.char_info   
      width     = tfm.array.width       
      height    = tfm.array.height      
      depth     = tfm.array.depth       
      italic    = tfm.array.italic      
      lig_kern  = tfm.array.lig_kern    
      kern      = tfm.array.kern        
      exten     = tfm.array.exten       
      param     = tfm.array.param       

      w  = tfm.parameters.w  
      lf = tfm.parameters.lf
      lh = tfm.parameters.lh
      bc = tfm.parameters.bc
      ec = tfm.parameters.ec
      nw = tfm.parameters.nw
      nh = tfm.parameters.nh
      nd = tfm.parameters.nd
      ni = tfm.parameters.ni
      nl = tfm.parameters.nl
      nk = tfm.parameters.nk
      ne = tfm.parameters.ne
      np = tfm.parameters.np

      status,status_msg = tfm.array.check()
      if status == false then 
	 _print("ERROR="..tostring(status_msg))
	 return false, tostring(status_msg)
      end
      tfm.font.checksum =header[0]
      tfm.font.designsize = tfm.int_to_frac(header[1])
      local coding_scheme 
      if header[2]~= nil then 
	 coding_scheme = '' 
	 for j=2,11 do coding_scheme=coding_scheme..tostring(header[j]) end 
	 tfm.font.coding_scheme=coding_scheme
	 _print(string.format("CODING SCHEME:%s",tfm.font.coding_scheme))
      end
      local font_identifier
      if header[12]~= nil then 
	 font_identifier = '' 
	 for j=12,16 do font_identifier=font_identifier..tostring(header[j]) end 
	 tfm.font.font_identifier=font_identifier
	 _print(string.format("FONT IDENTIFIER:%s",tfm.font.font_identifier))
      end
      local  seven_bit_safe_flag ,face
      if header[17]~= nil then
	 seven_bit_safe_flag ,face = header[17][1],header[17][4]
	 tfm.font.seven_bit_safe_flag = seven_bit_safe_flag
	 tfm.font.face = face
	 _print(string.format("SEVEN_BIT_SAFE_FLAG=%x",seven_bit_safe_flag))
	 local f,t = tfm.getface(face)
	 face = f 
	 _print(string.format("FACE=%s (mbl=%d,ri=%d,rce=%d)",face,t[1],t[2],t[3]))
      end
      local _pf = tfm.printfloat
      for current_char=bc,ec do
      --for current_char=102,102 do
	 local width_index,remainder,depth_index,height_index,tag,italic_index = tfm.getdata.char_info(current_char) 
	 tfm.chars[current_char] = tfm.chars[current_char] or {}
	 tfm.chars[current_char].width  = width[width_index]
	 tfm.chars[current_char].height = height[height_index]
	 tfm.chars[current_char].depth  = depth[depth_index]
	 tfm.chars[current_char].italic = italic[italic_index]
	 tfm.chars[current_char].tag    = tag
	 _print(i,string.format("O %o",current_char),string.char(current_char),
	       'WIDTH='.._pf(width[width_index]), 
	       'HEIGHT='.._pf(height[height_index]),
	       'DEPTH='.._pf(depth[depth_index]),
	       'ITALIC='.._pf(italic[italic_index]),
	       'TAG='..tfm.tag_meaning(tag)
	    )
	 if tag==1 then -- character has a ligature/kerning program
	    local kern_program = tfm.dump.kernprogram(remainder,current_char)
	 end
      end
      tfm.font.slant = param[1]
      _print("SLANT=".._pf(tfm.font.slant))

      tfm.font.space  = param[2]
      _print("SPACE=".._pf(tfm.font.space))

      tfm.font.space_stretch  = param[3]
      _print("SPACE_STRETCH=".._pf(tfm.font.space_stretch))

      tfm.font.space_shrink  = param[4]
      _print("SPACE_SHRINK=".._pf(tfm.font.space_shrink))

      tfm.font.x_height = param[5]
      _print("X_HEIGHT=".._pf(tfm.font.x_height))

      tfm.font.quad = param[6]
      _print("QUAD=".._pf(tfm.font.quad))

      tfm.font.extra_space = param[7]
      _print("EXTRA_SPACE=".._pf(tfm.font.extra_space))
      
      return true,'ok'

   end
--------------------------------------------------------------------------------

-- Add tfm to the mflua table
mflua.tfm = tfm 



