texlive[43848] Build/source/texk/web2c/mfluadir/mfluatrap: fix kpse

commits+lscarso at tug.org commits+lscarso at tug.org
Sun Apr 16 23:13:23 CEST 2017


Revision: 43848
          http://tug.org/svn/texlive?view=revision&revision=43848
Author:   lscarso
Date:     2017-04-16 23:13:23 +0200 (Sun, 16 Apr 2017)
Log Message:
-----------
fix kpse call (thank to A. Kakuto)

Added Paths:
-----------
    trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua
    trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_svg_backend.lua
    trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua

Added: trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua
===================================================================
--- trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua	2017-04-16 21:13:23 UTC (rev 43848)
@@ -0,0 +1,2857 @@
+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 at +  begin print(octant_dir[octant]); print_char("'");
+--   loop at +  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 
+
+
+

Added: trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_svg_backend.lua
===================================================================
--- trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_svg_backend.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_svg_backend.lua	2017-04-16 21:13:23 UTC (rev 43848)
@@ -0,0 +1,538 @@
+--
+--
+-- Experimental svg back end
+--
+--
+
+--print ("mflua_svg_backend")
+local MFbuiltin = mflua.MFbuiltin
+local MF        = mflua.MF
+print_scaled    = mflua.MF.print_scaled
+
+local svg = svg or {} 
+svg = { 
+   ['enabled']=true,
+   ['enabled_raw']=false,
+   ['output_dir']='svg',
+   ['svg_preamble'] = [=[<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="15cm" height="15cm" viewBox="%s %s %s %s"
+     xmlns="http://www.w3.org/2000/svg" version="1.1">
+  <title>cubic Bézier commands in path data</title>
+  <desc>B char</desc>
+  <style type="text/css"><![CDATA[
+    .Border { fill:none; stroke:blue; stroke-width:1 }
+    .Connect { fill:none; stroke:#888888; stroke-width:2 }
+    .SamplePath { fill:none; stroke:black; stroke-width:1 }
+    .EndPoint { fill:none; stroke:#888888; stroke-width:2 }
+    .CtlPoint { fill:#888888; stroke:none }
+    .AutoCtlPoint { fill:none; stroke:blue; stroke-width:4 }
+    .Label { font-size:22; font-family:Verdana }
+  ]]></style>
+    <g transform="matrix(1 0 0 -1 0 0)">
+     <g transform="translate(0 %s)">
+  %s 
+     </g>
+   </g>
+  </svg>]=],
+   ['emsize']= 1000,
+   ['filename']= 'SourceCode',
+   ['font'] = [=[
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg>
+<metadata>
+Created by FontForge 20110222 at Sun Sep 18 10:37:34 2011
+ By root
+Copyleft 2002, 2003, 2005 Free Software Foundation.
+ </metadata>
+<defs>
+<font id="SourceCode" >
+  <font-face 
+    font-size='%s' 
+    units-per-em="%s"
+    ascent='800' descent='200'	  
+    x-height='%s'	 
+    font-family="SourceCode"
+    font-weight="400"
+    font-stretch="normal"
+    panose-1="2 2 6 3 5 4 5 2 3 4"
+    alphabetic='0' 	 
+      />
+   <missing-glyph horiz-adv-x="280" />
+
+   %s
+  </font>
+</defs></svg>
+]=],
+['glyph'] = 
+ [==[<glyph glyph-name="%s" unicode="%s" orientation="h" 
+      horiz-adv-x="%s" vert-adv-y="%s" 
+      d="%s" >%s
+    </glyph>
+]==],
+['hkern'] = [==[<hkern g1="%s" u1="%s" g2="%s" u2="%s" k="%s" />]==],
+['vkern'] = [==[<vkern g1="%s" u1="%s" g2="%s" u2="%s" k="%s" />]==],
+['hkerns']='',
+['vkerns']='',
+['char']={
+ ['0']={glyph_name='uni0393',unicode='&#x0393;'}, -- U+0393 GREEK CAPITAL LETTER GAMMA 
+ ['1']={glyph_name='uni0394',unicode='&#x0394;'}, --U+0394 GREEK CAPITAL LETTER DELTA
+ ['2']={glyph_name='uni0398',unicode='&#x0398;'}, -- U+0398 GREEK CAPITAL LETTER THETA
+ ['3']={glyph_name='uni039b',unicode='&#x039b;'}, -- U+039B GREEK CAPITAL LETTER LAMBDA
+ ['4']={glyph_name='uni039e',unicode='&#x039e;'}, --U+039E GREEK CAPITAL LETTER XI
+ ['5']={glyph_name='uni03a0',unicode='&#x03a0;'}, --U+03A0 GREEK CAPITAL LETTER PI
+ ['6']={glyph_name='uni03a3',unicode='&#x03a3;'}, -- U+03A3 GREEK CAPITAL LETTER SIGMA
+ ['7']={glyph_name='uni03a5',unicode='&#x03a5;'}, --U+03A5 GREEK CAPITAL LETTER UPSILON
+ ['8']={glyph_name='uni03a6',unicode='&#x03a6;'}, -- U+03A6 GREEK CAPITAL LETTER PHI
+ ['9']={glyph_name='uni03a8',unicode='&#x03a8;'}, -- U+03A8 GREEK CAPITAL LETTER PSI
+ ['10']={glyph_name='uni03a9',unicode='&#x03a9;'}, -- U+03A9 GREEK CAPITAL LETTER OMEGA
+ ['11']={glyph_name='unifb00',unicode='ff'}, -- U+FB00 LATIN SMALL LIGATURE FF
+ ['12']={glyph_name='unifb01',unicode='fi'}, --U+FB01 LATIN SMALL LIGATURE FI
+ ['13']={glyph_name='unifb02',unicode='fl'}, -- U+FB02 LATIN SMALL LIGATURE FL
+ ['14']={glyph_name='unifb03',unicode='ffi'}, --U+FB03 LATIN SMALL LIGATURE FFI
+ ['15']={glyph_name='unifb04',unicode='ffl'}, -- U+FB04 LATIN SMALL LIGATURE FFL
+ ['16']={glyph_name='uni0131',unicode='&#x0131;'}, -- U+0131 LATIN SMALL LETTER DOTLESS I
+ ['17']={glyph_name='uni0237',unicode='&#x0237;'}, -- U+0237 LATIN SMALL LETTER DOTLESS J
+ ['18']={glyph_name='uni0060',unicode='&#x0060;'}, -- U+0060 GRAVE ACCENT
+ ['19']={glyph_name='uni00b4',unicode='&#x00b4;'}, -- U+00B4 ACUTE ACCENT
+ ['20']={glyph_name='uni02c7',unicode='&#x02c7;'}, -- U+02C7 CARON
+ ['21']={glyph_name='uni02d8',unicode='&#x02d8;'}, -- U+02D8 BREVE
+ ['22']={glyph_name='uni00af',unicode='&#x00af;'}, -- U+00AF MACRON
+ ['23']={glyph_name='uni02da',unicode='&#x02da;'}, -- U+02DA RING ABOVE
+ ['24']={glyph_name='uni00b8',unicode='&#x00b8;'}, -- U+00B8 CEDILLA
+ ['25']={glyph_name='uni00df',unicode='&#x00df;'}, -- U+00DF LATIN SMALL LETTER SHARP S
+ ['26']={glyph_name='uni00e6',unicode='&#x00e6;'}, -- U+00E6 LATIN SMALL LETTER AE
+ ['27']={glyph_name='uni0153',unicode='&#x0153;'}, -- U+0153 LATIN SMALL LIGATURE OE
+ ['28']={glyph_name='uni00f8',unicode='&#x00f8;'}, -- U+00F8 LATIN SMALL LETTER O WITH STROKE
+ ['29']={glyph_name='uni00c6',unicode='&#x00c6;'}, --U+00C6 LATIN CAPITAL LETTER AE
+ ['30']={glyph_name='uni0152',unicode='&#x0152;'}, --U+0152 LATIN CAPITAL LIGATURE OE
+ ['31']={glyph_name='uni00D8',unicode='&#x00D8;'}, --U+00D8 LATIN CAPITAL LETTER O WITH STROKE 
+ ['32']={glyph_name='uni0337',unicode='&#x0337;'}, --U+0337 COMBINING SHORT SOLIDUS OVERLAY
+ ['33']={glyph_name='uni0021',unicode='&#x0021;'}, 
+ ['34']={glyph_name='uni201d',unicode='&#x201d;'}, -- U+201D RIGHT DOUBLE QUOTATION MARK
+ ['35']={glyph_name='uni0023',unicode='&#x0023;'}, 
+ ['36']={glyph_name='uni0024',unicode='&#x0024;'}, 
+ ['37']={glyph_name='uni0025',unicode='&#x0025;'}, 
+ ['38']={glyph_name='uni0026',unicode='&#x0026;'}, 
+ ['39']={glyph_name='uni0027',unicode='&#x0027;'}, 
+ ['40']={glyph_name='uni0028',unicode='&#x0028;'}, 
+ ['41']={glyph_name='uni0029',unicode='&#x0029;'}, 
+ ['42']={glyph_name='uni002a',unicode='&#x002a;'}, 
+ ['43']={glyph_name='uni002b',unicode='&#x002b;'}, 
+ ['44']={glyph_name='uni002c',unicode='&#x002c;'}, 
+ ['45']={glyph_name='uni002d',unicode='&#x002d;'}, -- U+002D HYPHEN-MINUS
+ ['46']={glyph_name='uni002e',unicode='&#x002e;'}, 
+ ['47']={glyph_name='uni002f',unicode='&#x002f;'}, 
+ ['48']={glyph_name='uni0030',unicode='&#x0030;'}, 
+ ['49']={glyph_name='uni0031',unicode='&#x0031;'}, 
+ ['50']={glyph_name='uni0032',unicode='&#x0032;'}, 
+ ['51']={glyph_name='uni0033',unicode='&#x0033;'}, 
+ ['52']={glyph_name='uni0034',unicode='&#x0034;'}, 
+ ['53']={glyph_name='uni0035',unicode='&#x0035;'}, 
+ ['54']={glyph_name='uni0036',unicode='&#x0036;'}, 
+ ['55']={glyph_name='uni0037',unicode='&#x0037;'}, 
+ ['56']={glyph_name='uni0038',unicode='&#x0038;'}, 
+ ['57']={glyph_name='uni0039',unicode='&#x0039;'}, 
+ ['58']={glyph_name='uni003a',unicode='&#x003a;'}, 
+ ['59']={glyph_name='uni003b',unicode='&#x003b;'}, 
+ ['60']={glyph_name='uni00a1',unicode='&#x00a1;'}, -- U+00A1 INVERTED EXCLAMATION MARK, but only if ligs>1
+ ['61']={glyph_name='uni003d',unicode='&#x003d;'}, 
+ ['62']={glyph_name='uni00bf',unicode='&#x00bf;'}, --U+00BF INVERTED QUESTION MARK
+ ['63']={glyph_name='uni003f',unicode='&#x003f;'}, 
+ ['64']={glyph_name='uni0040',unicode='&#x0040;'}, 
+ ['65']={glyph_name='uni0041',unicode='&#x0041;'}, 
+ ['66']={glyph_name='uni0042',unicode='&#x0042;'}, 
+ ['67']={glyph_name='uni0043',unicode='&#x0043;'}, 
+ ['68']={glyph_name='uni0044',unicode='&#x0044;'}, 
+ ['69']={glyph_name='uni0045',unicode='&#x0045;'}, 
+ ['70']={glyph_name='uni0046',unicode='&#x0046;'}, 
+ ['71']={glyph_name='uni0047',unicode='&#x0047;'}, 
+ ['72']={glyph_name='uni0048',unicode='&#x0048;'}, 
+ ['73']={glyph_name='uni0049',unicode='&#x0049;'}, 
+ ['74']={glyph_name='uni004a',unicode='&#x004a;'}, 
+ ['75']={glyph_name='uni004b',unicode='&#x004b;'}, 
+ ['76']={glyph_name='uni004c',unicode='&#x004c;'}, 
+ ['77']={glyph_name='uni004d',unicode='&#x004d;'}, 
+ ['78']={glyph_name='uni004e',unicode='&#x004e;'}, 
+ ['79']={glyph_name='uni004f',unicode='&#x004f;'}, 
+ ['80']={glyph_name='uni0050',unicode='&#x0050;'}, 
+ ['81']={glyph_name='uni0051',unicode='&#x0051;'}, 
+ ['82']={glyph_name='uni0052',unicode='&#x0052;'}, 
+ ['83']={glyph_name='uni0053',unicode='&#x0053;'}, 
+ ['84']={glyph_name='uni0054',unicode='&#x0054;'}, 
+ ['85']={glyph_name='uni0055',unicode='&#x0055;'}, 
+ ['86']={glyph_name='uni0056',unicode='&#x0056;'}, 
+ ['87']={glyph_name='uni0057',unicode='&#x0057;'}, 
+ ['88']={glyph_name='uni0058',unicode='&#x0058;'}, 
+ ['89']={glyph_name='uni0059',unicode='&#x0059;'}, 
+ ['90']={glyph_name='uni005a',unicode='&#x005a;'}, 
+ ['91']={glyph_name='uni005b',unicode='&#x005b;'}, 
+ ['92']={glyph_name='uni201c',unicode='&#x201c;'}, -- U+201C LEFT DOUBLE QUOTATION MARK
+ ['93']={glyph_name='uni005d',unicode='&#x005d;'}, 
+ ['94']={glyph_name='uni0302',unicode='&#x0302;'}, --U+0302 COMBINING CIRCUMFLEX ACCENT
+ ['95']={glyph_name='uni0307',unicode='&#x0307;'}, --U+0307 COMBINING DOT ABOVE
+ ['96']={glyph_name='uni2018',unicode='&#x2018;'}, --U+2018 LEFT SINGLE QUOTATION MARK
+ ['97']={glyph_name='uni0061',unicode='&#x0061;'}, 
+ ['98']={glyph_name='uni0062',unicode='&#x0062;'}, 
+ ['99']={glyph_name='uni0063',unicode='&#x0063;'}, 
+ ['100']={glyph_name='uni0064',unicode='&#x0064;'}, 
+ ['101']={glyph_name='uni0065',unicode='&#x0065;'}, 
+ ['102']={glyph_name='uni0066',unicode='&#x0066;'}, 
+ ['103']={glyph_name='uni0067',unicode='&#x0067;'}, 
+ ['104']={glyph_name='uni0068',unicode='&#x0068;'}, 
+ ['105']={glyph_name='uni0069',unicode='&#x0069;'}, 
+ ['106']={glyph_name='uni006a',unicode='&#x006a;'}, 
+ ['107']={glyph_name='uni006b',unicode='&#x006b;'}, 
+ ['108']={glyph_name='uni006c',unicode='&#x006c;'}, 
+ ['109']={glyph_name='uni006d',unicode='&#x006d;'}, 
+ ['110']={glyph_name='uni006e',unicode='&#x006e;'}, 
+ ['111']={glyph_name='uni006f',unicode='&#x006f;'}, 
+ ['112']={glyph_name='uni0070',unicode='&#x0070;'}, 
+ ['113']={glyph_name='uni0071',unicode='&#x0071;'}, 
+ ['114']={glyph_name='uni0072',unicode='&#x0072;'}, 
+ ['115']={glyph_name='uni0073',unicode='&#x0073;'}, 
+ ['116']={glyph_name='uni0074',unicode='&#x0074;'}, 
+ ['117']={glyph_name='uni0075',unicode='&#x0075;'}, 
+ ['118']={glyph_name='uni0076',unicode='&#x0076;'}, 
+ ['119']={glyph_name='uni0077',unicode='&#x0077;'}, 
+ ['120']={glyph_name='uni0078',unicode='&#x0078;'}, 
+ ['121']={glyph_name='uni0079',unicode='&#x0079;'}, 
+ ['122']={glyph_name='uni007a',unicode='&#x007a;'}, 
+ ['123']={glyph_name='uni2013',unicode='&#x2013;'}, -- U+2013 EN DASH
+ ['124']={glyph_name='uni2014',unicode='&#x2014;'}, -- U+2014 EM DASH
+ ['125']={glyph_name='uni030b',unicode='&#x030b;'}, --U+030B COMBINING DOUBLE ACUTE ACCENT
+ ['126']={glyph_name='uni0303',unicode='&#x0303;'}, --U+0303 COMBINING TILDE
+ ['127']={glyph_name='uni0308',unicode='&#x0308;'}, --U+0308 COMBINING DIAERESIS
+ ['128']={glyph_name='uni0080',unicode='&#x0080;'}, 
+ ['129']={glyph_name='uni0081',unicode='&#x0081;'}, 
+ ['130']={glyph_name='uni0082',unicode='&#x0082;'}, 
+ ['131']={glyph_name='uni0083',unicode='&#x0083;'}, 
+ ['132']={glyph_name='uni0084',unicode='&#x0084;'}, 
+ ['133']={glyph_name='uni0085',unicode='&#x0085;'}, 
+ ['134']={glyph_name='uni0086',unicode='&#x0086;'}, 
+ ['135']={glyph_name='uni0087',unicode='&#x0087;'}, 
+ ['136']={glyph_name='uni0088',unicode='&#x0088;'}, 
+ ['137']={glyph_name='uni0089',unicode='&#x0089;'}, 
+ ['138']={glyph_name='uni008a',unicode='&#x008a;'}, 
+ ['139']={glyph_name='uni008b',unicode='&#x008b;'}, 
+ ['140']={glyph_name='uni008c',unicode='&#x008c;'}, 
+ ['141']={glyph_name='uni008d',unicode='&#x008d;'}, 
+ ['142']={glyph_name='uni008e',unicode='&#x008e;'}, 
+ ['143']={glyph_name='uni008f',unicode='&#x008f;'}, 
+ ['144']={glyph_name='uni0090',unicode='&#x0090;'}, 
+ ['145']={glyph_name='uni0091',unicode='&#x0091;'}, 
+ ['146']={glyph_name='uni0092',unicode='&#x0092;'}, 
+ ['147']={glyph_name='uni0093',unicode='&#x0093;'}, 
+ ['148']={glyph_name='uni0094',unicode='&#x0094;'}, 
+ ['149']={glyph_name='uni0095',unicode='&#x0095;'}, 
+ ['150']={glyph_name='uni0096',unicode='&#x0096;'}, 
+ ['151']={glyph_name='uni0097',unicode='&#x0097;'}, 
+ ['152']={glyph_name='uni0098',unicode='&#x0098;'}, 
+ ['153']={glyph_name='uni0099',unicode='&#x0099;'}, 
+ ['154']={glyph_name='uni009a',unicode='&#x009a;'}, 
+ ['155']={glyph_name='uni009b',unicode='&#x009b;'}, 
+ ['156']={glyph_name='uni009c',unicode='&#x009c;'}, 
+ ['157']={glyph_name='uni009d',unicode='&#x009d;'}, 
+ ['158']={glyph_name='uni009e',unicode='&#x009e;'}, 
+ ['159']={glyph_name='uni009f',unicode='&#x009f;'}, 
+ ['160']={glyph_name='uni00a0',unicode='&#x00a0;'}, 
+ ['161']={glyph_name='uni00a1',unicode='&#x00a1;'}, 
+ ['162']={glyph_name='uni00a2',unicode='&#x00a2;'}, 
+ ['163']={glyph_name='uni00a3',unicode='&#x00a3;'}, 
+ ['164']={glyph_name='uni00a4',unicode='&#x00a4;'}, 
+ ['165']={glyph_name='uni00a5',unicode='&#x00a5;'}, 
+ ['166']={glyph_name='uni00a6',unicode='&#x00a6;'}, 
+ ['167']={glyph_name='uni00a7',unicode='&#x00a7;'}, 
+ ['168']={glyph_name='uni00a8',unicode='&#x00a8;'}, 
+ ['169']={glyph_name='uni00a9',unicode='&#x00a9;'}, 
+ ['170']={glyph_name='uni00aa',unicode='&#x00aa;'}, 
+ ['171']={glyph_name='uni00ab',unicode='&#x00ab;'}, 
+ ['172']={glyph_name='uni00ac',unicode='&#x00ac;'}, 
+ ['173']={glyph_name='uni00ad',unicode='&#x00ad;'}, 
+ ['174']={glyph_name='uni00ae',unicode='&#x00ae;'}, 
+ ['175']={glyph_name='uni00af',unicode='&#x00af;'}, 
+ ['176']={glyph_name='uni00b0',unicode='&#x00b0;'}, 
+ ['177']={glyph_name='uni00b1',unicode='&#x00b1;'}, 
+ ['178']={glyph_name='uni00b2',unicode='&#x00b2;'}, 
+ ['179']={glyph_name='uni00b3',unicode='&#x00b3;'}, 
+ ['180']={glyph_name='uni00b4',unicode='&#x00b4;'}, 
+ ['181']={glyph_name='uni00b5',unicode='&#x00b5;'}, 
+ ['182']={glyph_name='uni00b6',unicode='&#x00b6;'}, 
+ ['183']={glyph_name='uni00b7',unicode='&#x00b7;'}, 
+ ['184']={glyph_name='uni00b8',unicode='&#x00b8;'}, 
+ ['185']={glyph_name='uni00b9',unicode='&#x00b9;'}, 
+ ['186']={glyph_name='uni00ba',unicode='&#x00ba;'}, 
+ ['187']={glyph_name='uni00bb',unicode='&#x00bb;'}, 
+ ['188']={glyph_name='uni00bc',unicode='&#x00bc;'}, 
+ ['189']={glyph_name='uni00bd',unicode='&#x00bd;'}, 
+ ['190']={glyph_name='uni00be',unicode='&#x00be;'}, 
+ ['191']={glyph_name='uni00bf',unicode='&#x00bf;'}, 
+ ['192']={glyph_name='uni00c0',unicode='&#x00c0;'}, 
+-- ['193']={glyph_name='uni00c1',unicode='&#x00c1;'}, 
+ ['193']={glyph_name='uni0060',unicode='&#x0060;'}, 
+-- ['194']={glyph_name='uni00c2',unicode='&#x00c2;'}, 
+ ['194']={glyph_name='uni00b4',unicode='&#x00b4;'}, 
+-- ['195']={glyph_name='uni00c3',unicode='&#x00c3;'}, 
+ ['195']={glyph_name='uni005e',unicode='&#x005e;'}, 
+ ['196']={glyph_name='uni00c4',unicode='&#x00c4;'}, 
+ ['197']={glyph_name='uni00c5',unicode='&#x00c5;'}, 
+ ['198']={glyph_name='uni00c6',unicode='&#x00c6;'}, 
+ ['199']={glyph_name='uni00c7',unicode='&#x00c7;'}, 
+ ['200']={glyph_name='uni00c8',unicode='&#x00c8;'}, 
+ ['201']={glyph_name='uni00c9',unicode='&#x00c9;'}, 
+ ['202']={glyph_name='uni00ca',unicode='&#x00ca;'}, 
+ ['203']={glyph_name='uni00cb',unicode='&#x00cb;'}, 
+ ['204']={glyph_name='uni00cc',unicode='&#x00cc;'}, 
+ ['205']={glyph_name='uni00cd',unicode='&#x00cd;'}, 
+ ['206']={glyph_name='uni00ce',unicode='&#x00ce;'}, 
+ ['207']={glyph_name='uni00cf',unicode='&#x00cf;'}, 
+ ['208']={glyph_name='uni00d0',unicode='&#x00d0;'}, 
+ ['209']={glyph_name='uni00d1',unicode='&#x00d1;'}, 
+ ['210']={glyph_name='uni00d2',unicode='&#x00d2;'}, 
+ ['211']={glyph_name='uni00d3',unicode='&#x00d3;'}, 
+ ['212']={glyph_name='uni00d4',unicode='&#x00d4;'}, 
+ ['213']={glyph_name='uni00d5',unicode='&#x00d5;'}, 
+ ['214']={glyph_name='uni00d6',unicode='&#x00d6;'}, 
+ ['215']={glyph_name='uni00d7',unicode='&#x00d7;'}, 
+ ['216']={glyph_name='uni00d8',unicode='&#x00d8;'}, 
+ ['217']={glyph_name='uni00d9',unicode='&#x00d9;'}, 
+ ['218']={glyph_name='uni00da',unicode='&#x00da;'}, 
+ ['219']={glyph_name='uni00db',unicode='&#x00db;'}, 
+ ['220']={glyph_name='uni00dc',unicode='&#x00dc;'}, 
+ ['221']={glyph_name='uni00dd',unicode='&#x00dd;'}, 
+ ['222']={glyph_name='uni00de',unicode='&#x00de;'}, 
+ ['223']={glyph_name='uni00df',unicode='&#x00df;'}, 
+ ['224']={glyph_name='uni00e0',unicode='&#x00e0;'}, 
+ ['225']={glyph_name='uni00e1',unicode='&#x00e1;'}, 
+ ['226']={glyph_name='uni00e2',unicode='&#x00e2;'}, 
+ ['227']={glyph_name='uni00e3',unicode='&#x00e3;'}, 
+ ['228']={glyph_name='uni00e4',unicode='&#x00e4;'}, 
+ ['229']={glyph_name='uni00e5',unicode='&#x00e5;'}, 
+ ['230']={glyph_name='uni00e6',unicode='&#x00e6;'}, 
+ ['231']={glyph_name='uni00e7',unicode='&#x00e7;'}, 
+ ['232']={glyph_name='uni00e8',unicode='&#x00e8;'}, 
+ ['233']={glyph_name='uni00e9',unicode='&#x00e9;'}, 
+ ['234']={glyph_name='uni00ea',unicode='&#x00ea;'}, 
+ ['235']={glyph_name='uni00eb',unicode='&#x00eb;'}, 
+ ['236']={glyph_name='uni00ec',unicode='&#x00ec;'}, 
+ ['237']={glyph_name='uni00ed',unicode='&#x00ed;'}, 
+ ['238']={glyph_name='uni00ee',unicode='&#x00ee;'}, 
+ ['239']={glyph_name='uni00ef',unicode='&#x00ef;'}, 
+ ['240']={glyph_name='uni00f0',unicode='&#x00f0;'}, 
+ ['241']={glyph_name='uni00f1',unicode='&#x00f1;'}, 
+ ['242']={glyph_name='uni00f2',unicode='&#x00f2;'}, 
+ ['243']={glyph_name='uni00f3',unicode='&#x00f3;'}, 
+ ['244']={glyph_name='uni00f4',unicode='&#x00f4;'}, 
+ ['245']={glyph_name='uni00f5',unicode='&#x00f5;'}, 
+ ['246']={glyph_name='uni00f6',unicode='&#x00f6;'}, 
+ ['247']={glyph_name='uni00f7',unicode='&#x00f7;'}, 
+ ['248']={glyph_name='uni00f8',unicode='&#x00f8;'}, 
+ ['249']={glyph_name='uni00f9',unicode='&#x00f9;'}, 
+ ['250']={glyph_name='uni00fa',unicode='&#x00fa;'}, 
+ ['251']={glyph_name='uni00fb',unicode='&#x00fb;'}, 
+ ['252']={glyph_name='uni00fc',unicode='&#x00fc;'}, 
+ ['253']={glyph_name='uni00fd',unicode='&#x00fd;'}, 
+ ['254']={glyph_name='uni00fe',unicode='&#x00fe;'}, 
+ ['255']={glyph_name='uni00ff',unicode='&#x00ff;'}, 
+ ['256']={glyph_name='uni0100',unicode='&#x0100;'}, 
+         },
+
+}
+
+local function _eval_tonumber(q,offset)
+   local qx,qy,xo,yo
+   local w 
+   local _offset = offset 
+   if _offset == nil then _offset = '(0,0)' end
+   w=string.gmatch(q,"[-0-9.]+"); qx,qy=w(),w()
+   w=string.gmatch(_offset,"[-0-9.]+"); xo,yo=w(),w()
+   return {tonumber(qx+xo),tonumber(qy+yo)}
+end
+
+
+local function get_svg_glyph(valid_curves,char,cycles,tfm)
+   -- Write the svg
+   --
+   --  print('BEZ  MFbuiltin.hppp='..print_scaled(MFbuiltin.hppp()))
+   --  print('BEZ  MFbuiltin.vppp='..print_scaled(MFbuiltin.vppp()))
+   --  print('BEZ  MFbuiltin.designsize='..print_scaled(MFbuiltin.designsize()))
+   local tfm = tfm
+   local index = tostring( char['index'] ) -- better a string or a number
+   local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt 
+   local char_wd=tonumber( char['char_wd'] ) -- pt
+   local char_ht=tonumber( char['char_ht'] ) -- pt
+   local char_dp=tonumber( char['char_dp'] ) -- pt
+
+   --local xheight =  0.458333 *  design_size -- must be read from tfm !!
+
+   local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* 72.27)
+   local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* 72.27)
+   assert(x_resolution==y_resolution, string.format('Error on _get_svg_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution))
+
+   local resolution = x_resolution 
+   local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em
+   local em_unit  = emsize  
+
+   local em_unit_for_pixel = (72.27/design_size) * (emsize / resolution)
+   local bp_for_pt = 72/72.27
+   local char_wd_emunit = (char_wd/design_size) *em_unit
+   local char_ht_emunit = (char_ht/design_size) *em_unit
+   local char_dp_emunit = (char_dp/design_size) *em_unit
+    
+   local outdir = mflua.svg.output_dir or '.'
+   local fname  = tostring(char['charname'])
+   if fname and fname ~= '' then 
+      mflua.svg.char[index] ={glyph_name='', unicode = ''};
+      mflua.svg.char[index].glyph_name = fname
+      local w = string.gmatch(fname,'uni(.+)')
+      local unicode_hex = w()
+      mflua.svg.char[index].unicode = [[&#x]] .. unicode_hex ..';'
+   end
+      
+   fname = mflua.svg.char[index].glyph_name
+   assert(fname~=nil, string.format("Error on svg file name for char index %s: it's nil",index))
+   --local f = io.open(outdir..'/'.. fname..'.svg','w')
+   local w = string.gmatch(fname,'uni(.+)')
+   local unicode_hex = w()
+   local unicode =  mflua.svg.char[index].unicode
+   local unicode_range = 'U+'..unicode_hex
+   local glyph_name = fname 
+   local bezier = ''
+   local maxx,maxy=-1e9,-1e9
+   local minx,miny=1e9,1e9
+   for i,cycle in pairs(cycles) do 
+      local path=''
+      local _i=1
+      for _,j in ipairs(cycle) do 
+	 --local curve = valid_curves[j]
+	 local curve = j 
+	 local p,c1,c2,q,offset=curve[1],curve[2],curve[3],curve[4],curve[5]
+	 p=_eval_tonumber(p,offset)
+	 c1=_eval_tonumber(c1,offset)
+	 c2=_eval_tonumber(c2,offset)
+	 q=_eval_tonumber(q,offset)
+	 -- em_unit_for_pixel
+	 p[1],p[2] = p[1]*em_unit_for_pixel,p[2]*em_unit_for_pixel
+	 q[1],q[2] = q[1]*em_unit_for_pixel,q[2]*em_unit_for_pixel
+	 c1[1],c1[2] = c1[1]*em_unit_for_pixel,c1[2]*em_unit_for_pixel
+	 c2[1],c2[2] = c2[1]*em_unit_for_pixel,c2[2]*em_unit_for_pixel
+	 if _i==1 then bezier = bezier..string.format("M%s %s ",p[1],p[2]) end
+	 _i=_i+1	 
+	 bezier = bezier .. string.format("C%s %s %s %s %s %s\n",c1[1],c1[2],c2[1],c2[2],q[1],q[2])
+	  --print("BEZ bez="..bezier)
+	 if p[1]>maxx then maxx=p[1] end
+	 if c1[1]>maxx then maxx=c1[1] end
+	 if c2[1]>maxx then maxx=c2[1] end
+	 if q[1]>maxx then maxx=q[1] end
+	 if p[2]>maxy then maxy=p[2] end
+	 if c1[2]>maxy then maxy=c1[2] end
+	 if c2[2]>maxy then maxy=c2[2] end
+	 if q[2]>maxy then maxy=q[2] end
+	 --
+	 if p[1]<minx then minx=p[1] end
+	 if c1[1]<minx then minx=c1[1] end
+	 if c2[1]<minx then minx=c2[1] end
+	 if q[1]<minx then minx=q[1] end
+	 if p[2]<miny then miny=p[2] end
+	 if c1[2]<miny then miny=c1[2] end
+	 if c2[2]<miny then miny=c2[2] end
+	 if q[2]<miny then miny=q[2] end
+      end
+      bezier = bezier .. 'Z\n'
+   end
+   --print('BEZ (x,y) (X,Y)=',minx,miny,maxx,maxy)
+   --print('BEZ', svg_glyph,glyph_name,unicode,char_wd_emunit,char_ht_emunit,bezier)
+   local trunk = ''
+   local svg_glyph = mflua.svg.glyph
+   local svg_font = mflua.svg.font
+   trunk = string.format(svg_glyph,
+			 glyph_name,unicode,
+			 char_wd_emunit,
+			 char_ht_emunit,
+			 bezier,'')
+   local svg_preamble = mflua.svg.svg_preamble
+   local paths = string.format('<path style="fill:#000000;stroke=none;fill-rule:nonzero" d="%s" />', bezier)
+   local raw=string.format(svg_preamble,minx,miny,maxx,maxy,-maxy,paths)
+   return trunk,raw
+end -- _get_svg_glyph
+
+
+local function svg_kern_and_lig(chartable,t,tfm)
+   --
+   -- Store kerns and ligs
+   -- 
+   local current_chars={}
+   local index
+   local kern, next_char,additional_space
+   local bp_for_pt = 72/72.27
+   local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* bp_for_pt)
+   local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* bp_for_pt)
+   local design_size=tfm.font.designsize -- pt
+   assert(x_resolution==y_resolution, string.format('Error on _get_svg_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution))
+   local resolution = x_resolution 
+   local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em
+   local em_unit  = emsize  
+   local em_unit_for_pixel = (bp_for_pt/design_size) * (emsize / resolution)
+
+   local hkern,vkern = '' ,''
+   for i,_ in ipairs(t) do 
+      index = t[i]
+      current_chars[index]=true
+   end
+   for i,_ in ipairs(t) do 
+      index = t[i]
+      if tfm.chars[index] and  tfm.chars[index].kern then 
+	 kerntable = tfm.chars[index].kern
+	 for _,k in ipairs(kerntable) do 
+	    next_char,additional_space = tostring(k.next_char),tonumber(k.additional_space)
+	    --
+	    if additional_space~=0 then 
+	       local a_name,a_unicode = mflua.svg.char[tostring(index)].glyph_name,mflua.svg.char[tostring(index)].unicode
+	       local b_name,b_unicode = mflua.svg.char[next_char].glyph_name,mflua.svg.char[next_char].unicode
+	       hkern = hkern .. "\n".. string.format(mflua.svg.hkern,
+						     a_name,a_unicode,
+						     b_name,b_unicode,
+						     additional_space*design_size*em_unit_for_pixel)
+	    end
+	 end
+      end
+   end
+   return hkern,vkern
+end
+
+local function store_svg_font(tfm)
+   -- local outdir = mflua.svg.output_dir or '.'
+   -- local fname = mflua.svg.filename
+   -- assert(fname~=nil, string.format("Error on svg file name for %s: it's nil",fname))
+   -- local f = io.open(outdir..'/'.. fname..'.svg','w')
+   local svg_font = mflua.svg.font
+   local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt 
+   local emsize = mflua.svg.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em
+   local bp_for_pt = 72/72.27
+   local xheight =  tfm.font.x_height * design_size --0.458333 *  design_size -- must be read from tfm !!
+   local trunk =''
+   local char = mflua.svg.char
+   for index=0,2^16-1 do
+      if not(char[tostring(index)]==nil) then 
+	 --print("BEZ char[tostring(index)].data=",index,char[tostring(index)].data)
+	 trunk= trunk.. (char[tostring(index)].data or '')
+      end
+   end
+   trunk = trunk.."\n"..mflua.svg.hkerns.."\n"..mflua.svg.vkerns
+   trunk = string.format(svg_font,
+			 string.format("%2.2f",design_size*bp_for_pt),
+			 emsize,
+			 string.format("%2.2f",xheight*bp_for_pt),
+			 trunk)
+   return trunk
+
+
+end
+
+svg.get_svg_glyph    = get_svg_glyph
+svg.svg_kern_and_lig = svg_kern_and_lig
+svg.store_svg_font   = store_svg_font
+
+return svg

Added: trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua
===================================================================
--- trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua	                        (rev 0)
+++ trunk/Build/source/texk/web2c/mfluadir/mfluatrap/mflua_ttx_backend.lua	2017-04-16 21:13:23 UTC (rev 43848)
@@ -0,0 +1,743 @@
+--
+--
+-- Experimental ttx back end
+--
+--
+
+
+local format = string.format
+local table_insert = table.insert
+local table_concat = table.concat
+local print_int    = mflua.MF.print_int
+local abs = math.abs
+
+local ttx	= {}
+local xmlstream = {}
+
+local scrt	= {} -- general table for local use
+
+local function DUMP(t)
+   if type(t) == 'table' then 
+      print("table",#table)
+      for k,v in pairs(t) do print(k,v) end
+   end
+end
+
+
+local xml_comment                      = 'c'
+local xml_processing_instruction       = 'p'
+local xml_element                      = 'e'
+local xml_header                       = 'h'
+
+
+--------------------------------------------------------------------------------
+--
+-- Errors and warning
+--------------------------------------------------------------------------------
+local function warning(t,msg)
+   print("Warning:"..msg..".")
+   print("Element:")
+   if type(t)=='table' then
+      for k,v in pairs(t) do print(k,v) end
+      print(#t.." values")
+   else
+      print(tostring(s))
+   end
+end
+
+
+--------------------------------------------------------------------------------
+--
+-- Element management
+--------------------------------------------------------------------------------
+
+
+-- Todo: valid XML  totext & toattr & tocomment 
+local function totext(s)
+   if not(type(s)=='string') then
+      warning(s,"text:the data in not a string")
+   end
+   return tostring(s)
+end
+
+local function toattr(s)
+   if not(type(s)=='string') then
+      warning(s,"attr.:the data in not a string")
+   end
+   return tostring(s)
+end
+
+local function tocomment(s)
+   if not(type(s)=='string') then
+      warning(s,"comment:the data in not a string")
+   end
+   return tostring(s)
+end
+
+local function new_comment(text)
+   local t ={}
+   t[0]=xml_comment 
+   t[1]=false
+   t[2]=tocomment(text)
+   return t
+end
+
+local function new_element(name,attr)
+   local t ={}
+   t[0]=xml_element
+   t[1]=tostring(name)
+   if attr and type(attr)=='table' then
+      for k,v in pairs(attr) do
+	 if type(k)~='number' then
+	    t[k]=v
+	 end
+      end
+   end
+   return t
+end
+
+local function get_elementname(t)
+   if t and type(t)=='table' then
+      return t[1]
+   else
+      return nil
+   end
+end
+
+local function insert_child(f,c)      
+   table_insert(f,c)
+end
+
+local function insert_child_at_beginning(f,c)      
+   -- f[1] is always the name
+   table_insert(f,2,c)
+end
+
+local function insert_children(f,cc)      
+   for j=1,#cc do 
+      table_insert(f,cc[j])
+   end
+end
+
+
+--
+-- get all the children (not descendants!)
+-- of source that match target name and attr.
+-- The existence of an attribute can be checked
+-- with @attrname=true (not @attrname="true") in
+-- target
+local function get_children(source,target)
+   local res={}
+   local t_attr={}
+   -- only key/val from target
+   for k,v in pairs(target) do
+      if type(k)=='number' then
+	 t_attr[k]=v
+      end
+   end
+   for i=2,#source do
+      local e = source[i]
+      if e[1]==target[1] then
+	 local found=true
+	 for k,v in pairs(t_attr) do
+	    if not(e[k] and ((e[k]==v) or (v==true))) then
+	       found=false
+	       break
+	    end
+	 end
+	 if found then
+	    res[#res+1]=e
+	 end
+      end
+   end
+   return res
+end
+
+--------------------------------------------------------------------------------
+--
+-- Serialization
+---------------------------------------------------------------------------------
+
+local function  serialize_comment(t) 
+   if not(t[0]== xml_comment) then
+      warning(t,'the node to serialize is not a comment')
+      return
+   end
+   local name=t[1] -- false, discarded
+   local elem={}
+   elem[#elem+1]='<--'
+   elem[#elem+1]=tocomment(t2)
+   elem[#elem+1]='-->'
+   elem[#elem+1]='\n'
+   xmlstream[#xmlstream+1] = table_concat(elem)
+end
+
+
+local function  serialize_processing_instruction(t) 
+   if not(t[0]== xml_processing_instruction) then
+      warning(t,'the node to serialize is not a processing_instruction')
+      return
+   end
+   local name=t[1]
+   local elem={}
+   elem[#elem+1]='<?'
+   elem[#elem+1]=name
+   local _t={}
+   for k,v in pairs(t) do
+      if not(type(k)=='number') then
+	 _t[#_t+1]=k
+     end
+   end
+   for j=1,#_t do 
+      elem[#elem+1]=format([[ %s="%s"]],_t[j],toattr(t[_t[j]])) 
+   end
+   elem[#elem+1]='?>'
+   elem[#elem+1]="\n"
+   xmlstream[#xmlstream+1] = table_concat(elem)
+end
+
+local function  serialize_xml_header(t) 
+   local _t={}
+   local elem={}
+   elem[#elem+1]='<?'
+   elem[#elem+1]='xml '
+   elem[#elem+1]=t
+   elem[#elem+1]='?>'
+   elem[#elem+1]='\n'
+   xmlstream[#xmlstream+1] = table_concat(elem)
+end
+
+local function  serialize_empty_elem(t) 
+  local name=t[1]
+  local elem={}
+  elem[#elem+1]='<'
+  elem[#elem+1]=name
+  local _t={}
+  for k,v in pairs(t) do
+     if not(type(k)=='number') then
+	_t[#_t+1]=k
+     end
+  end
+  table.sort(_t)
+  for j=1,#_t do 
+     elem[#elem+1]=format([[ %s="%s"]],_t[j],toattr(t[_t[j]]))
+  end
+  elem[#elem+1]='/>'
+  elem[#elem+1]="\n"
+  xmlstream[#xmlstream+1] = table_concat(elem)
+end
+
+local function  serialize_elem(t) 
+   if #t==1 then 
+    serialize_empty_elem(t) 
+  else
+   local name=t[1]
+   local elem={}
+   elem[#elem+1]='<'
+   elem[#elem+1]=name
+   -- attributes 
+   local _t={}
+   for k,v in pairs(t) do
+      if not(type(k)=='number') then
+	 _t[#_t+1]=k
+      end
+   end
+   table.sort(_t)
+   for j=1,#_t do 
+      elem[#elem+1]=format([[ %s="%s"]],_t[j],toattr(t[_t[j]])) --
+   end
+   elem[#elem+1]='>'
+   elem[#elem+1]="\n"
+   xmlstream[#xmlstream+1] = table_concat(elem)
+   elem = {}
+   for j=2,#t do
+      if type(t[j])=='table' then
+	 serialize_elem(t[j])
+      elseif type(t[j])=='string' then
+	 xmlstream[#xmlstream+1] = totext(t[j])
+      end
+   end
+   elem[#elem+1]='</'
+   elem[#elem+1]=name
+   elem[#elem+1]='>'
+   elem[#elem+1]="\n"
+   xmlstream[#xmlstream+1] = table_concat(elem)
+  end
+end
+
+
+--------------------------------------------------------------------------------
+--
+-- First children of XML ttx, plus utilities
+--------------------------------------------------------------------------------
+
+local ttFont     
+local GlyphOrder 
+local GlyphID    
+local head       
+local hhea       
+local maxp       
+local OS_2,panose -- handy to have        
+local name       
+local cmap       
+local post       
+local CFF, CFFFont, Private   -- handy to have        
+local FFTM       
+local GDEF  
+local hmtx       
+
+-- Important, child of CFFFont 
+local CharStrings
+
+local function get_GlyphID(id,name)
+   return new_element('GlyphID',{['id']=tostring(id),['name']=tostring(name)})
+end
+
+local function put_head(name,value)
+   table_insert(head, new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_hhea(name,value)
+   table_insert(hhea, new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_maxp(name,value)
+    table_insert(maxp,new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_OS_2(name,value)
+    table_insert(OS_2,new_element(name, {['value']=tostring(value)}))
+end
+-- handy 
+local function put_panose(name,value)
+    table_insert(panose,new_element(name, {['value']=tostring(value)}))
+end
+
+local function get_map(code,name)
+   return new_element('map', {['code']=tostring(code),['name']=tostring(name)})
+end
+
+local function put_post(name,value)
+    table_insert(post,new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_CFF(name,value)
+    table_insert(CFF,new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_CFFFont(name,value)
+    table_insert(CFFFont,new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_Private(name,value)
+    table_insert(Private,new_element(name, {['value']=tostring(value)}))
+end
+
+local function put_FFTM(name,value)
+    table_insert(FFTM,new_element(name, {['value']=tostring(value)}))
+end
+
+local function get_ClassDef(glyph,class)
+   return new_element('ClassDef', {['glyph']=tostring(glyph),['class']=tostring(class)})
+end
+
+local function get_mtx(name,width,lsb)
+   return new_element('mtx', {['name']=tostring(name),['width']=tostring(width),['lsb']=tostring(lsb)})
+end
+
+--
+-- convenient method for a cmap0
+--
+-- local function get_cmap0_maps(maps) 
+--    local t = {}
+--    if not(#maps==256) then
+--       warning(maps,"maps has not 256 values")
+--    end
+--    local s=(#maps>=256 and 256) or #maps
+--    for j=1,s do
+--       t[#t+1]=get_map(format("0x%x",j-1),maps[j])
+--    end
+--    return t
+-- end
+
+local function get_raw_cmap0() 
+   local t = {}
+   for j=0,255 do 
+      t[format("0x%02x",j)] = ".notdef"
+   end
+   return t
+end
+
+
+
+
+--for i=1,255 do table_insert(GlyphOrder,new_element('GlyphID', {['id']=i, ['name']="uni"..tostring(i)})) end
+--local ttFont = dofile('ttx_sample.lua')
+--savettfont(ttFont)
+
+
+--------------------------------------------------------------------------------
+--
+-- Create & save xml font
+--------------------------------------------------------------------------------
+
+local function checkall(tfm)
+   -- several checks here
+   -- fix cmap0
+   -- local t = {}
+   -- for k,_ in pairs(scrt.cmap.rawcmap0) do t[#t+1]=k end
+   -- table.sort(t)
+   -- for k=1,256 do
+   --    insert_child(scrt.cmap.cmap0, get_map(t[k],scrt.cmap.rawcmap0[t[k]]))
+   -- end
+   
+end
+
+local function savettxfont(t)
+   serialize_xml_header([[version="1.0" encoding="UTF-8"]])
+   serialize_elem(t) 
+   return table_concat(xmlstream)
+   
+end
+
+local function makefont(tfm)
+   --
+   checkall(tfm)
+   serialize_xml_header([[version="1.0" encoding="UTF-8"]])
+   serialize_elem(ttFont)
+   return table_concat(xmlstream)
+end
+
+
+
+
+--------------------------------------------------------------------------------
+--
+-- mflua layer
+--------------------------------------------------------------------------------
+
+local function _eval_tonumber(q,offset)
+   local qx,qy,xo,yo
+   local w 
+   local _offset = offset 
+   if _offset == nil then _offset = '(0,0)' end
+   w=string.gmatch(q,"[-0-9.]+"); qx,qy=w(),w()
+   w=string.gmatch(_offset,"[-0-9.]+"); xo,yo=w(),w()
+   return {tonumber(qx+xo),tonumber(qy+yo)}
+end
+
+local function setup(tfm,index,chartable)
+   -- Default emsize is 1000 of CFF
+   ttx.emsize = ttx.emsize or 1000
+
+   scrt.font_space = tfm.printfloat(ttx.emsize*(tfm.font.space),3)
+   
+   ttFont     = new_element('ttFont', {['sfntVersion']="OTTO", ['ttLibVersion']="3.1"})
+   GlyphOrder = new_element('GlyphOrder')
+   GlyphID    = new_element('GlyphID', {['id']="0", ['name']=".notdef"})
+   head       = new_element('head')
+   hhea       = new_element('hhea')
+   maxp       = new_element('maxp')
+   OS_2       = new_element('OS_2')
+   name       = new_element('name')
+   cmap       = new_element('cmap')
+   post       = new_element('post')
+   CFF        = new_element('CFF')
+   -- FFTM       = new_element('FFTM') --FontForge TimeStamp table
+   GDEF       = new_element('GDEF')
+   hmtx       = new_element('hmtx')
+
+   -- handy 
+   panose     = new_element('panose')
+   CFFFont    = new_element('CFFFont',{['name']="SourceCode"})
+   Private    = new_element('Private')
+
+   CharStrings= new_element('CharStrings')
+   
+   table_insert(ttFont,GlyphOrder)
+   table_insert(ttFont,head)
+   table_insert(ttFont,hhea)
+   table_insert(ttFont,maxp)
+   table_insert(ttFont,OS_2)
+   table_insert(ttFont,name)
+   table_insert(ttFont,cmap)
+   table_insert(ttFont,post)
+   table_insert(ttFont,CFF)
+--   table_insert(ttFont,FFTM)
+   table_insert(ttFont,GDEF)
+   table_insert(ttFont,hmtx)
+   
+   table_insert(GlyphOrder,GlyphID)
+
+   if ttx.userdata.head then
+      for k,v in pairs(ttx.userdata.head) do
+	 put_head(k,v)
+      end
+   end
+
+   if ttx.userdata.hhea then
+      for k,v in pairs(ttx.userdata.hhea) do
+	 put_hhea(k,v)
+      end
+   end
+
+   if ttx.userdata.maxp then
+      for k,v in pairs(ttx.userdata.maxp) do
+	 put_maxp(k,v)
+      end
+   end
+
+   if ttx.userdata.OS_2 then
+      for k,v in pairs(ttx.userdata.OS_2) do
+	 put_OS_2(k,v)
+      end
+   end
+
+   if ttx.userdata.panose then
+      for k,v in pairs(ttx.userdata.panose) do
+	 put_panose(k,v)
+      end
+   end
+   insert_child(OS_2,panose)
+   
+   if ttx.userdata.namerecord then
+      local _e
+      local t
+      for i=1,#ttx.userdata.namerecord do
+	 t = ttx.userdata.namerecord[i]
+	 _e = new_element('namerecord',{['nameID']=t.nameID,['platformID']=t.platformID,
+			     ['platEncID']=t.platEncID, ['langID']=t.langID, ['unicode']=t.unicode})
+	 insert_child(_e,t.value); insert_child(name,_e)
+      end
+   end
+      
+   
+   local cmap0,cmap4_0,cmap4_3
+   cmap4_0 = new_element('cmap_format_4', {['platformID']="0",['platEncID']="3",['language']="0",})
+   --cmap0   = new_element('cmap_format_0', {['platformID']="1",['platEncID']="0",['language']="0",})
+   cmap4_3 = new_element('cmap_format_4', {['platformID']="3",['platEncID']="1",['language']="0",})
+
+   
+   insert_child(cmap4_0,get_map("0x0",".notdef"))
+   insert_child(cmap4_3,get_map("0x0",".notdef"))
+   
+   scrt.cmap = scrt.cmap or {}
+   scrt.cmap.cmap4_0  = cmap4_0 
+   scrt.cmap.cmap4_3  = cmap4_3 
+   --scrt.cmap.cmap0    = cmap0
+   --scrt.cmap.rawcmap0 = get_raw_cmap0() 
+
+   
+   insert_child(cmap,{'tableVersion', ['version']="0"})
+   insert_child(cmap,cmap4_0)
+   --insert_child(cmap,cmap0)
+   insert_child(cmap,cmap4_3)
+
+
+   if ttx.userdata.post then
+      for k,v in pairs(ttx.userdata.post) do
+	 put_post(k,v)
+      end
+   end
+   
+   put_CFF('major',"1")
+   put_CFF('minor',"0")
+   insert_child(CFF,CFFFont)
+
+   if ttx.userdata.CFFFont then
+      for k,v in pairs(mflua.ttx.userdata.CFFFont) do
+	 put_CFFFont(k,v)
+      end
+   end
+   
+   insert_child(CFFFont,{'Encoding', ['name']=mflua.ttx.userdata.CFFFont.Encoding})
+
+   insert_child(CFFFont,Private)
+   if ttx.userdata.CFFFont.Private then
+      for k,v in pairs(ttx.userdata.CFFFont.Private) do
+	 put_Private(k,v)
+      end
+   end
+
+   local subrs = new_element('Subrs')
+   scrt.subrs  = subrs
+   if ttx.userdata.CFFFont.Private.Subrs then
+      for k,v in pairs(ttx.userdata.CFFFont.Private.Subrs) do
+	 insert_child(subrs,{'CharString', ['index']=k, v})
+      end
+   end
+      insert_child(Private,subrs)
+
+   -- .notdef char
+   local notdef = new_element('CharString', {['name']=".notdef"})
+   insert_child(notdef,"107 endchar\n")
+   insert_child_at_beginning(CharStrings, notdef)
+   
+   insert_child(CFFFont,CharStrings)
+
+   --
+   -- TODO: check GlobalSubrs!!
+   --
+   local globsubrs = new_element('GlobalSubrs')
+   insert_child(CFF,globsubrs)
+   if ttx.userdata.CFF.GlobalSubrs then
+      for k,v in pairs(ttx.userdata.CFF.GlobalSubrs) do
+	 insert_child(globsubrs,{'CharString', ['index']=k, v})
+      end
+   end
+   
+   --
+   -- fontforge timestamp table.
+   --
+   -- put_FFTM('version', "1")
+   -- put_FFTM('FFTimeStamp', "Fri Oct  7 21:32:10 2016")
+   -- put_FFTM('sourceCreated', "Tue Apr  4 13:38:00 2017")
+   -- put_FFTM('sourceModified', "Wed Apr  5 16:26:11 2017")
+
+
+   local glyphclassdef = new_element('GlyphClassDef',{['Format']="2"})
+   insert_child(GDEF,{'Version',['value']="0x00010000"})
+   insert_child(GDEF,glyphclassdef)
+   scrt.gdef               = scrt.gdef or {}
+   scrt.gdef.glyphclassdef = glyphclassdef
+
+   local LigCaretList = new_element('LigCaretList')
+   insert_child(LigCaretList,new_element('Coverage',{['Format']="2"}))
+   insert_child(GDEF,LigCaretList)
+
+   insert_child(hmtx, get_mtx('.notdef',scrt.font_space,"0"))
+end
+
+
+local function reverse(cycle)
+   local t={}
+   local curve
+   local p,c1,c2,q
+   for i=#cycle,1,-1 do
+      curve=cycle[i]
+      p,c1,c2,q=curve[1],curve[2],curve[3],curve[4]
+      curve[1],curve[2],curve[3],curve[4]=q,c2,c1,p
+      t[#t+1]=curve
+   end
+   return t
+end
+
+local function _reverse(cycle)
+  local cv1, cv2
+  local p,c1,c2,q
+  local l=#cycle
+  for i=1,l/2 do
+     cv1=cycle[i]
+     cv2=cycle[l+1-i]
+     p,c1,c2,q = cv1[1],cv1[2],cv1[3],cv1[4]
+     cv1[1],cv1[2],cv1[3],cv1[4] = q,c2,c1,p 
+     p,c1,c2,q = cv2[1],cv2[2],cv2[3],cv2[4]
+     cv2[1],cv2[2],cv2[3],cv2[4] = q,c2,c1,p 
+     cycle[l+1-i]=cv1
+     cycle[i]=cv2
+   end
+end
+
+
+
+local function make_glyph(valid_curves,char,cycles,tfm)
+   -- Write the ttx
+   --
+   --  print('BEZ  MFbuiltin.hppp='..print_scaled(MFbuiltin.hppp()))
+   --  print('BEZ  MFbuiltin.vppp='..print_scaled(MFbuiltin.vppp()))
+   --  print('BEZ  MFbuiltin.designsize='..print_scaled(MFbuiltin.designsize()))
+   local tfm = tfm
+   local mflua_index = tonumber( char['index'] ) -- better a string or a number
+   local index = mflua_index
+   if mflua.ttx.userdata.charindex and mflua.ttx.userdata.charindex[index] then
+      index = mflua.ttx.userdata.charindex[index]
+   end
+   
+   local design_size=tonumber ( print_scaled(MFbuiltin.designsize()) ) --pt 
+   local char_wd=tonumber( char['char_wd'] ) -- pt
+   local char_ht=tonumber( char['char_ht'] ) -- pt
+   local char_dp=tonumber( char['char_dp'] ) -- pt
+
+   local cmap4_0  = scrt.cmap.cmap4_0
+   local cmap4_3  = scrt.cmap.cmap4_3
+   --local rawcmap0 = scrt.cmap.rawcmap0
+
+   local glyphclassdef =  scrt.gdef.glyphclassdef
+
+   --local xheight =  0.458333 *  design_size -- must be read from tfm !!
+
+   local x_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.hppp()) )* 72.27)
+   local y_resolution = math.floor(0.5+tonumber( print_scaled(MFbuiltin.vppp()) )* 72.27)
+   assert(x_resolution==y_resolution, format('Error on _make_glyph x_res=%d and y_res=%d differ',x_resolution,y_resolution))
+
+   local resolution = x_resolution 
+   local emsize = ttx.emsize -- 1000, type 1, also known as em_unit: 1000 emsize = 1em
+   local em_unit  = emsize  
+
+   local em_unit_for_pixel = (72.27/design_size) * (emsize / resolution)
+   local bp_for_pt = 72/72.27
+   local char_wd_emunit = (char_wd/design_size) *em_unit
+   local char_ht_emunit = (char_ht/design_size) *em_unit
+   local char_dp_emunit = (char_dp/design_size) *em_unit
+    
+   local glyph_name  = tostring(char['charname'])
+   if glyph_name and glyph_name ~= '' and not(index==0) then 
+      table_insert(GlyphOrder,get_GlyphID(index,glyph_name))
+   end
+   local content = {}
+   if (abs(char_wd_emunit-scrt.font_space)>1e-4) then
+      table_insert(content,format("%0.3f w",char_wd_emunit-scrt.font_space,print_int(1000*(tfm.font.space)))) 
+   end
+   --table_insert(content,"stem ?")  -- TODO
+   --table_insert(content,"mask ?")  -- TODO
+   local origin = {0,0}
+   for i,cycle in pairs(cycles) do 
+      local p,c1,c2,q,offset
+      cycle = reverse(cycle)
+      for i1,curve in ipairs(cycle) do 
+	 p,c1,c2,q,offset=curve[1],curve[2],curve[3],curve[4],curve[5]
+	 p =_eval_tonumber(p ,offset)
+	 c1=_eval_tonumber(c1,offset)
+	 c2=_eval_tonumber(c2,offset)
+	 q =_eval_tonumber(q ,offset)
+	 -- em_unit_for_pixel
+	 p[1],p[2]   = p[1] *em_unit_for_pixel,  p[2]*em_unit_for_pixel
+	 q[1],q[2]   = q[1] *em_unit_for_pixel,  q[2]*em_unit_for_pixel
+	 c1[1],c1[2] = c1[1]*em_unit_for_pixel, c1[2]*em_unit_for_pixel
+	 c2[1],c2[2] = c2[1]*em_unit_for_pixel, c2[2]*em_unit_for_pixel
+	 if i1==1 then
+	    table_insert(content,format("%0.2f %0.2f rmoveto",p[1]-origin[1],p[2]-origin[2]))
+	    origin = {p[1],p[2]}
+	 end
+	 --table_insert(content,format("%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f rrcurveto",
+	 table_insert(content,format("%0.0f %0.0f %0.0f %0.0f %0.0f %0.0f rrcurveto",
+				     c1[1] -p[1], c1[2]-p[2],
+				     c2[1]-c1[1], c2[2]-c1[2],
+				     q[1] -c2[1],  q[2]-c2[2],p[1],p[2],c1[1],c1[2],c2[1],c2[2],q[1],q[2]))
+      end
+   end
+   table_insert(content,"endchar\n")
+   local CharString = new_element('CharString', {['name']=glyph_name})
+   insert_child(CharString,table_concat(content,"\n"))
+
+   insert_child(CharStrings,CharString)
+   insert_child(cmap4_0,get_map(format("0x%x",index),glyph_name))
+   --rawcmap0[format("0x%x",1+index%256)] = glyph_name
+   insert_child(cmap4_3,get_map(format("0x%x",index),glyph_name))
+   
+   insert_child(glyphclassdef, get_ClassDef(glyph_name,"1"))
+   insert_child(hmtx, get_mtx(glyph_name,char_wd_emunit,"80"))
+   
+   
+end -- make_glyph
+
+
+
+
+
+ttx.make_glyph = make_glyph
+ttx.makefont   = makefont
+ttx.setup      = setup
+ttx.userdata   = {}
+
+return ttx



More information about the tex-live-commits mailing list