summaryrefslogtreecommitdiff
path: root/Build/source
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2018-02-20 10:17:32 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2018-02-20 10:17:32 +0000
commit64520e9c28f986551d982afb021df96193d23e51 (patch)
treeff58da5f5ab1e1229fa4ad7dda49b128c7aea2f1 /Build/source
parent0fc70469f010d1dcfc019095c95e5eb0028a0503 (diff)
added generic font parser to mflua.lua
git-svn-id: svn://tug.org/texlive/trunk@46684 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source')
-rw-r--r--Build/source/texk/web2c/mfluadir/ChangeLog2
-rw-r--r--Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua935
2 files changed, 936 insertions, 1 deletions
diff --git a/Build/source/texk/web2c/mfluadir/ChangeLog b/Build/source/texk/web2c/mfluadir/ChangeLog
index 12e941cae46..c17f8adce7b 100644
--- a/Build/source/texk/web2c/mfluadir/ChangeLog
+++ b/Build/source/texk/web2c/mfluadir/ChangeLog
@@ -2,7 +2,7 @@
* MFLua 0.9.
* Fixed a bug on clean up string in runscript.
-
+ * Added generic font parser to mflua.lua
2017-04-16 Luigi Scarso <luigi.scarso@gmail.com>
diff --git a/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua
index 2596469d1d8..aa319d756d0 100644
--- a/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua
+++ b/Build/source/texk/web2c/mfluadir/mfluatrap/mflua.lua
@@ -2855,3 +2855,938 @@ mflua.tfm = tfm
+--------------------------------------------------------------------------------
+--
+-- gf module
+--
+--------------------------------------------------------------------------------
+--
+-- In-memory parser, i.e. reads all the gf into memory
+-- and then parses the byte stream
+--
+
+local GF = {}
+do
+
+ local sub = string.sub
+ local len = string.len
+ local byte = string.byte
+ local format = string.format
+ local rep = string.rep
+
+ local gfdata=''
+ local gfdata_index
+ local gfdata_len
+
+ local chars={}
+ local current_char
+ local current_row -- aka n
+ local current_col -- aka m
+ local white=0
+ local black=white+1
+ local paint_switch
+ chars.xxx1 = {}
+ chars.xxx2 = {}
+ chars.xxx3 = {}
+ chars.xxx4 = {}
+ chars.yyy = {}
+ chars.nop = {}
+ chars.all_nop = {} -- collect a xxx1 or xxx2 or xxx3 or xxx4 or yyy or nop
+ chars.locators = {}
+
+
+
+
+ local defDEBUG = false
+ local function DEBUG(k,s)
+ print("DEBUG:"..tostring(k).."="..tostring(s))
+ end
+
+
+ local function error_msg(msg)
+ io.write(format("! mflua GF: char %s: %s",current_char, msg))
+ io.write(format(" position=%s ",gfdata_index))
+ print()
+ end
+ GF.error = error_msg
+
+ local function warning_msg(msg)
+ print(format("\n! mflua GF: char %s: %s.",current_char, msg))
+ end
+ GF.warning = warning_msg
+
+
+
+ --
+ -- read n bytes starting from from gfdata_index included
+ -- and move gfdata_index
+ --
+ local function readbytes(n)
+ if (gfdata_index+n-1)<1 then
+ GF.warning("attempt to read before the beginning of the file")
+ return nil
+ end
+ if (gfdata_index+n-1)>gfdata_len then
+ GF.warning("attempt to read beyond the end of the file")
+ return nil
+ end
+ local s
+ if (n<0) then
+ s = sub(gfdata,gfdata_index+n+1,gfdata_index)
+ elseif n>0 then
+ s = sub(gfdata,gfdata_index,gfdata_index+n-1)
+ else
+ s =''
+ end
+ gfdata_index = gfdata_index+n
+ return s
+ end
+
+
+ local function read4bytes()
+ local b0 = byte(readbytes(1))
+ local b1 = byte(readbytes(1))
+ local b2 = byte(readbytes(1))
+ local b3 = byte(readbytes(1))
+ local v = (b3+b2*256+b1*65536+b0*16777216)
+ if v >2147483647 then
+ v = v -4294967296
+ end
+ return v
+ end
+
+
+ local function readrev4bytes()
+ local b3 = byte(readbytes(-1))
+ local b2 = byte(readbytes(-1))
+ local b1 = byte(readbytes(-1))
+ local b0 = byte(readbytes(-1))
+ local v = (b3+b2*256+b1*65536+b0*16777216)
+ if v >2147483647 then
+ v = v -4294967296
+ end
+ return v
+ end
+
+
+ local function readuntileof()
+ if gfdata_index>gfdata_len then
+ GF.warning("wrong index")
+ return nil
+ end
+ local s = sub(gfdata,gfdata_index,gfdata_len)
+ gfdata_index = gfdata_len +1
+ return s
+ end
+
+
+ local function datanotfinished()
+ return (gfdata_index <= gfdata_len)
+ end
+
+
+ local function moveindex_after(p)
+ gfdata_index = p+1
+ end
+
+
+
+ error = {}
+ error.ok = 0
+ error.base = error.ok
+ error.pre = error.base +1
+ error.parse = error.base +2
+ error.post = error.base +3
+ error.boc = error.base +4
+ error.load = error.base +127
+ error.parse = error.base +128
+ error.parsechar = error.base +129
+ error.paint = {}
+ for j=0,63 do
+ error.paint[j] = error.base +130+j
+ end
+ error.paint_switch=error.base +130+64
+ error.paint1 = error.base +130+64+1
+ error.paint2 = error.base +130+64+2
+ error.paint3 = error.base +130+64+3
+ error.eoc = error.base +130+64+6
+ error.skip0 = error.base +130+64+7
+ error.skip1 = error.base +130+64+8
+ error.skip2 = error.base +130+64+9
+ error.skip3 = error.base +130+64+10
+ error.new_row = {}
+ for j=0,164 do
+ error.new_row[j]= error.base +130+64+10+1+j
+ end
+
+ error.post_post=error.base +130+64+10+1+165
+
+ error.skip223=error.base +130+64+10+1+166
+
+
+ error_name_t = {}
+ for k,v in pairs(error) do
+ error_name_t[v] = k
+ end
+ local function error_name(res)
+ if res==nil then
+ return "unknown error code"
+ elseif error_name_t[res] == nil then
+ return "unknown error code"
+ else
+ return error_name_t[res]
+ end
+ end
+
+ local opcodes = {}
+
+ -- {beginning of the \\{paint} commands}
+ for j=0,63 do
+ local s = format("paint_%d",j)
+ opcodes[s] = j
+ end
+ opcodes.paint1=64 -- {move right a given number of columns, then black${}\swap{}$white}
+ opcodes.paint2=65
+ opcodes.paint3=66
+ opcodes.boc=67 -- {beginning of a character}
+ opcodes.boc1=68 -- {short form of |boc|}
+ opcodes.eoc=69 -- {end of a character}
+ opcodes.skip0=70 -- {skip no blank rows}
+ opcodes.skip1=71 -- {skip over blank rows}
+ opcodes.skip2=72
+ opcodes.skip3=73
+ --opcodes.new_row_0=74 -- {move down one row and then right}
+ --:
+ --opcodes.new_row_164=238
+ for j=0,164 do
+ local s = format("new_row_%d",j)
+ opcodes[s] = j+74
+ end
+
+ --opcodes.max_new_row=164 -- {the largest \\{new\_row} command is |new_row_164|}
+ opcodes.xxx1=239 -- {for \&{special} strings}
+ opcodes.xxx2=240
+ opcodes.xxx3=241 -- {for long \&{special} strings}
+ opcodes.xxx4=242
+ opcodes.yyy=243 -- {for \&{numspecial} numbers}
+ opcodes.nop=244 -- no operation
+ opcodes.char_loc=245 -- {character locators in the postamble}
+ opcodes.char_loc0=246
+ opcodes.pre=247 -- {preamble}
+ opcodes.post=248 -- {postamble beginning}
+ opcodes.post_post=249 -- {postamble ending}
+
+ opcodes.undefined_1=250
+ opcodes.undefined_2=251
+ opcodes.undefined_3=252
+ opcodes.undefined_4=253
+ opcodes.undefined_5=254
+ opcodes.undefined_6=255
+
+ local revopcode = {}
+ for k,v in pairs(opcodes) do revopcode[v] = k end
+
+
+
+ complement_paint_switch = function()
+ local res = error.ok
+ if( paint_switch==black or paint_switch==white) then
+ paint_switch=(paint_switch+1)%2
+ else
+ GF.error("wrong value for paint_switch")
+ res = error.paint_switch
+ end
+ return res
+ end
+
+ local paint = function(n)
+ local res = error.ok
+ local c = chars[current_char]
+ local row = c[current_row]
+ if row==nil then
+ GF.error("error in paint_"..tostring(n)..", row is nil")
+ end
+ if paint_switch==black then
+ for i=current_col,current_col+n-1 do
+ row[i]=true
+ end
+ end
+ res = complement_paint_switch()
+ current_col = current_col + n
+ if res~=error.ok then
+ if n<64 then
+ GF.error("error in paint_"..tostring(n))
+ res = error.paint[n]
+ elseif (64<=n and n<256) then
+ GF.error("error in paint1")
+ res = error.paint1
+ elseif (256<=n and n<65536) then
+ GF.error("error in paint2")
+ res = error.paint2
+ elseif (65536<=n and n<16777216) then
+ GF.error("error in paint3")
+ res = error.paint3
+ end
+ end
+ return res
+ end
+
+
+ opcodes.func = {}
+
+
+ opcodes.func[opcodes.paint_0]= function()
+ local res = error.ok
+ res = complement_paint_switch()
+ if res~=error.ok then
+ GF.error("error in paint_0")
+ res = error.paint[0]
+ end
+ return res
+ end
+
+ --opcodes.func[opcodes.paint_1]= function() return paint(1) end
+ --:
+ --opcodes.func[opcodes.paint_63]= function() return paint(63) end
+ for i=1, 63 do
+ local key = format("paint_%d",i)
+ local index = opcodes[key]
+ opcodes.func[index] = function() return paint(i) end
+ end
+
+ opcodes.func[opcodes.paint1]= function()
+ local res = error.ok
+ local b = byte(readbytes(1))
+ if (64<=b and b<256) then
+ paint(b)
+ else
+ GF.error("wrong value " ..tostring(b) .. " in paint1")
+ res = error.paint1
+ end
+ return res
+ end
+
+
+ opcodes.func[opcodes.paint2]= function()
+ local res = error.ok
+ local b1 = byte(readbytes(1))
+ local b2 = byte(readbytes(1))
+ local b = b2+b1*256
+ if (256<=b and b<65536) then
+ paint(b)
+ else
+ GF.error("wrong value " ..tostring(b) .. " in paint2")
+ res = error.paint2
+ end
+ return res
+ end
+
+
+
+ opcodes.func[opcodes.paint3]= function()
+ local res = error.ok
+ local b1 = byte(readbytes(1))
+ local b2 = byte(readbytes(1))
+ local b3 = byte(readbytes(1))
+ local b = b3+b2*256+ (b1*65536)
+ if (65536<=b and b<16777216) then
+ paint(b)
+ else
+ GF.error("wrong value " ..tostring(b) .. " in paint3")
+ res = error.paint3
+ end
+ return res
+ end
+
+
+ opcodes.func[opcodes.boc]= function()
+ local pos = gfdata_index
+ local c = read4bytes()
+ local p = read4bytes()
+ local min_m = read4bytes()
+ local max_m = read4bytes()
+ local min_n = read4bytes()
+ local max_n = read4bytes()
+ current_char = c
+ chars[current_char] = chars[current_char] or {}
+ chars[current_char]['p'] = p
+ chars[current_char]['max_m'] = max_m
+ chars[current_char]['min_m'] = min_m
+ chars[current_char]['max_n'] = max_n
+ chars[current_char]['min_n'] = min_n
+ chars[current_char]['opened'] = true
+ chars[current_char]['stream_pos'] = gfdata_index
+ chars[current_char]['max_col'] = max_m
+ chars[current_char]['min_col'] = min_m
+ chars[current_char]['max_row'] = max_n
+ chars[current_char]['min_row'] = min_n
+ current_col = min_m
+ current_row = max_n
+ chars[current_char][current_row]={}
+ paint_switch = white
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.boc1]= function()
+ local pos = gfdata_index
+ local c = byte(readbytes(1))
+ local del_m = byte(readbytes(1))
+ local max_m = byte(readbytes(1))
+ local del_n = byte(readbytes(1))
+ local max_n = byte(readbytes(1))
+ local p = -1
+ local min_m = max_m - del_m
+ local min_n = max_n - del_n
+ current_char = c
+ chars[current_char] = chars[current_char] or {}
+ chars[current_char]['p'] = p
+ chars[current_char]['max_m'] = max_m
+ chars[current_char]['min_m'] = min_m
+ chars[current_char]['max_n'] = max_n
+ chars[current_char]['min_n'] = min_n
+ chars[current_char]['opened'] = true
+ chars[current_char]['stream_pos'] = gfdata_index
+ chars[current_char]['max_col'] = max_m
+ chars[current_char]['min_col'] = min_m
+ chars[current_char]['max_row'] = max_n
+ chars[current_char]['min_row'] = min_n
+ current_col = min_m
+ current_row = max_n
+ chars[current_char][current_row]={}
+ paint_switch = white
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.eoc]= function()
+ local res = error.ok
+ if chars[current_char].opened == true then
+ chars[current_char].opened = false
+ res = error.ok
+ else
+ GF.error("error closing char")
+ res = error.eoc
+ end
+ --
+ -- use them as stack to tie the nop
+ -- opcodes to current_char
+ table.insert(chars.xxx1,{current_char,-1})
+ table.insert(chars.xxx2,{current_char,-1})
+ table.insert(chars.xxx3,{current_char,-1})
+ table.insert(chars.xxx4,{current_char,-1})
+ table.insert(chars.yyy,{current_char,-1})
+ table.insert(chars.nop,{current_char,-1})
+ table.insert(chars.all_nop,{'eoc',current_char,-1})
+ return res
+ end
+
+
+ opcodes.func[opcodes.skip0]= function()
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in skip0")
+ return error.skip0
+ end
+ current_row = current_row -1
+ current_col = chars[current_char].min_m
+ paint_switch = white
+ chars[current_char][current_row]={}
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.skip1]= function()
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in skip1")
+ return error.skip1
+ end
+ local b = byte(readbytes(1))
+ current_row = current_row -(b+1)
+ current_col = chars[current_char].min_m
+ paint_switch = white
+ chars[current_char][current_row]={}
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.skip2]= function()
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in skip2")
+ return error.skip2
+ end
+ local b0 = byte(readbytes(1))
+ local b1 = byte(readbytes(1))
+ local b = b1+256*b0
+ current_row = current_row - (b+1)
+ current_col = chars[current_char].min_m
+ paint_switch = white
+ chars[current_char][current_row]={}
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.skip3]= function()
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in skip3 ")
+ return error.skip3
+ end
+ local b0 = byte(readbytes(1))
+ local b1 = byte(readbytes(1))
+ local b2 = byte(readbytes(1))
+ local b = b2+b1*256+b3*65536
+ current_row = current_row - (b+1)
+ current_col = chars[current_char].min_m
+ paint_switch = white
+ chars[current_char][current_row]={}
+ return error.ok
+ end
+
+
+ local function new_row(n)
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in new_row_"..n)
+ return error.new_row[n]
+ end
+ current_row = current_row - 1
+ current_col = chars[current_char].min_m+n
+ paint_switch = black
+ chars[current_char][current_row]={}
+ return error.ok
+
+ end
+
+ opcodes.func[opcodes.new_row_0]= function()
+ if chars[current_char]==nil or chars[current_char].min_m==nil then
+ GF.error("error in new_row_0")
+ return error.new_row[0]
+ end
+ current_row = current_row - 1
+ current_col = chars[current_char].min_m
+ paint_switch = black
+ chars[current_char][current_row]={}
+ return error.ok
+ end
+
+ --opcodes.func[opcodes.new_row_1]= function() new_row(1) end
+ --:
+ --opcodes.func[opcodes.new_row_164]= function() new_row(i)end
+ for i=1, 164 do
+ local key = format("new_row_%d",i)
+ local index = opcodes[key]
+ opcodes.func[index] = function() return new_row(i) end
+ end
+
+ --opcodes.func[opcodes.max_new_row]= function()
+ -- return new_row(opcodes.max_new_row)
+ --end
+
+ opcodes.func[opcodes.xxx1]= function()
+ local stream_pos = gfdata_index
+ local b = byte(readbytes(1))
+ local k = readbytes(b)
+ table.insert(chars.xxx1,{k,stream_pos})
+ table.insert(chars.all_nop,{'xxx1',k,stream_pos})
+ return error.ok
+ end
+
+ opcodes.func[opcodes.xxx2]= function()
+ local stream_pos = gfdata_index
+ local b0 = byte(readbytes(1))
+ local b1 = byte(readbytes(1))
+ local k = readbytes(b1+ b0*256)
+ table.insert(chars.xxx2,{k,stream_pos})
+ table.insert(chars.all_nop,{'xxx2',k,stream_pos})
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.xxx3]= function()
+ local stream_pos = gfdata_index
+ local b0 = byte(readbytes(1))
+ local b1 = byte(readbytes(1))
+ local b2 = byte(readbytes(1))
+ local k = readbytes(b2+ b1*256+b0*65536)
+ table.insert(chars.xxx3,{k,stream_pos})
+ table.insert(chars.all_nop,{'xxx3', k,stream_pos})
+ return error.ok
+ end
+
+ opcodes.func[opcodes.xxx4]= function()
+ local stream_pos = gfdata_index
+ local k = readbytes(read4bytes())
+ -- k must be positive
+ if k<=0 then
+ k = k +4294967296
+ end
+ table.insert(chars.xxx4,{k,stream_pos})
+ table.insert(chars.all_nop,{'xxx4',k,stream_pos})
+ return error.ok
+ end
+
+ opcodes.func[opcodes.yyy]= function()
+ local stream_pos = gfdata_index
+ local v = read4bytes()
+ table.insert(chars.yyy,{v,stream_pos})
+ table.insert(chars.all_nop,{'yyy',v,stream_pos})
+ return error.ok
+ end
+
+ opcodes.func[opcodes.nop]= function()
+ table.insert(chars.nop,gfdata_index)
+ table.insert(chars.all_nop,{'nop','',gfdata_index})
+ return error.ok
+ end
+
+ opcodes.func[opcodes.char_loc]= function()
+ local c = byte(readbytes(1))
+ local dx = read4bytes()
+ local dy = read4bytes()
+ local w = read4bytes()
+ local p = read4bytes()
+ local char_locator = {}
+ char_locator['c'] = c
+ char_locator['dx'] = dx
+ char_locator['dy'] = dy
+ char_locator['w'] = w
+ char_locator['p'] = p
+ table.insert(chars.locators,char_locator)
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.char_loc0]= function()
+ local c = byte(readbytes(1))
+ local dm = byte(readbytes(1))
+ local w = read4bytes()
+ local p = read4bytes()
+ local dy = 0
+ local dx = 65536*dm
+ local char_locator = {}
+ char_locator['c'] = c
+ char_locator['dx'] = dx
+ char_locator['dy'] = dy
+ char_locator['w'] = w
+ char_locator['p'] = p
+ table.insert(chars.locators,char_locator)
+ return error.ok
+ end
+
+
+ opcodes.func[opcodes.pre]= function()
+ local i = byte(readbytes(1))
+ local k = byte(readbytes(1))
+ local x = readbytes(k)
+ chars.GF_format = i
+ chars.GF_comment = x
+ return error.ok
+ end
+
+ opcodes.func[opcodes.post]= function()
+ local p = read4bytes()
+ local ds = read4bytes()
+ local cs = read4bytes()
+ local hppp = read4bytes()
+ local vppp = read4bytes()
+ local min_m = read4bytes()
+ local max_m = read4bytes()
+ local min_n = read4bytes()
+ local max_n = read4bytes()
+ chars['ds'] = ds
+ chars['cs'] = cs
+ chars['hppp'] = hppp
+ chars['vppp'] = vppp
+ chars['min_m'] = min_m
+ chars['max_m'] = max_m
+ chars['min_n'] = min_n
+ chars['max_n'] = max_n
+ return error.ok
+ end
+
+ opcodes.func[opcodes.post_post]= function()
+ local q = read4bytes()
+ local i = byte(readbytes(1))
+ local pad223 = readbytes(4)
+ if ( pad223~='\223\223\223\223' ) then
+ GF.error("error post_post_1 "..pad223)
+ return error.post_post
+ end
+ local s = readuntileof()
+ local ctr223 = rep('\223',len(s))
+ if ctr223 ~= s then
+ GF.error("error post_post_2 "..pad223)
+ return error.post_post
+ end
+ chars.GF_format_post = i
+ return error.ok
+ end
+
+ opcodes.func[opcodes.undefined_1]= function()
+ GF.warning("undefined command 1")
+ return error.ok
+ end
+ opcodes.func[opcodes.undefined_2]= function()
+ GF.warning("undefined command 2")
+ return error.ok
+ end
+ opcodes.func[opcodes.undefined_3]= function()
+ GF.warning("undefined command 3")
+ return error.ok
+ end
+ opcodes.func[opcodes.undefined_4]= function()
+ GF.warning("undefined command 4")
+ return error.ok
+ end
+ opcodes.func[opcodes.undefined_5]= function()
+ GF.warning("undefined command 5")
+ return error.ok
+ end
+ opcodes.func[opcodes.undefined_6]= function()
+ GF.warning("undefined command 6")
+ return error.ok
+ end
+
+
+
+ --------------------------------------------------------------------------------
+ --
+ --------------------------------------------------------------------------------
+
+ local function load(gffile)
+ gfdata = ''
+ local f,res = io.open(gffile,'rb')
+ if f==nil then
+ GF.error(res)
+ gfdata_index=0
+ return error.load
+ else
+ gfdata = f:read("*a")
+ gfdata_len = len(gfdata)
+ gfdata_index =1
+ end
+ f:close()
+ return error.ok
+ end
+
+
+ local function parse_pre()
+ gfdata_index=1
+ local res = error.ok
+ local b = byte(readbytes(1))
+ if b==opcodes.pre then
+ local i=byte(readbytes(1))
+ local k=byte(readbytes(1))
+ local x=readbytes(k)
+ chars.GF_format=i
+ chars.comments=x
+ else
+ GF.error("error parsing pre")
+ res = error.pre
+ end
+ return res
+ end
+
+
+ local function parse_rest()
+ local b = byte(readbytes(1))
+ local func = opcodes.func
+ local res = error.ok
+ local cond = true
+ while (cond) do
+ if func[b] then
+ res = (func[b])()
+ if res~=error.ok then
+ cond = false
+ elseif datanotfinished() then
+ b = byte(readbytes(1))
+ else
+ res = error.ok
+ cond = false
+ end
+ else
+ cond = false
+ GF.error("wrong opcode while parsing char")
+ res = error.parsechar
+ end
+ end
+ return res
+ end
+
+
+ local function parse()
+ if gfdata_len == 0 then
+ GF.error("no data")
+ return error.parse
+ end
+ local res
+ res = parse_pre()
+ if res~=error.ok then
+ GF.error("wrong preamble")
+ return res
+ end
+ res = parse_rest()
+ if not(res==error.ok) then
+ GF.error("error while reading characters")
+ return res
+ end
+ return res
+ end
+
+
+ ----------------------------------------------------------------------------------
+ -- Parse from the end
+ ----------------------------------------------------------------------------------
+
+ local function skip223()
+ local i = gfdata_len
+ local cond = true
+ while cond do
+ local c = byte(sub(gfdata,i,i))
+ if c==223 then
+ i=i-1
+ else
+ cond=false
+ end
+ end
+ if i<3 then
+ GF.error("error skip suffix ")
+ res = error.skip223
+ else
+ res = error.ok
+ gfdata_index = i
+ end
+ return res
+ end
+
+
+ local function parse_char_fromlocator()
+ local cond = true
+ local func = opcodes.func
+ local b,res
+ while cond do
+ b = byte(readbytes(1))
+ if func[b] then
+ res = (func[b])()
+ if res ~= error.ok then
+ cond = false
+ return res
+ elseif b==opcodes.eoc then
+ cond = false
+ else
+ cond = true
+ end
+ else
+ GF.error("wrong char from locator")
+ cond = false
+ return error.parse
+ end
+ end
+ if chars[current_char] and chars[current_char].p == -1 then
+ return error.ok
+ end
+ moveindex_after(chars[current_char].p)
+ return parse_char_fromlocator()
+
+ end
+
+ local function parse_from_end()
+ if gfdata_len == 0 then
+ GF.error("no data")
+ return error.parse
+ end
+ local res = error.ok
+ gfdata_index = gfdata_len
+ res = skip223()
+ if res ~= error.ok then
+ return res
+ end
+ --
+ -- read identification byte
+ --
+ chars.GF_format_post = byte(readbytes(-1))
+ --
+ -- read post_post
+ --
+ local q = readrev4bytes()
+ if q<=0 then
+ q = q +4294967296
+ end
+ if q<1 or q>gfdata_len then
+ GF.error("wrong pointer to post")
+ return error.parse
+ end
+ --
+ -- reading post
+ --
+ moveindex_after(q)
+ q = byte(readbytes(1))
+ if q~=opcodes.post then
+ GF.error("expected post opcode")
+ return error.parse
+ end
+ --
+ res = opcodes.func[opcodes.post]()
+ if res~=error.ok then
+ GF.error("reading postamble")
+ return error.parse
+ end
+ --
+ -- read char locators
+ --
+ local cond = true
+ local char_loc = opcodes.char_loc
+ local char_loc0 = opcodes.char_loc0
+ local post_post = opcodes.post_post
+ local f = opcodes.func
+ while cond do
+ q = byte(readbytes(1))
+ if q==char_loc or q==char_loc0 then
+ f[q]()
+ elseif q==post_post then
+ cond = false
+ res = error.ok
+ else
+ GF.error("reading char locators")
+ cond = false
+ return error.parse
+ end
+ end
+ --
+ -- read chars
+ --
+ if #chars.locators == 0 then
+ GF.error("no char locators")
+ return error.parse
+ end
+ for i,v in ipairs(chars.locators) do
+ local p = v.p
+ if p>-1 then
+ moveindex_after(p)
+ res = parse_char_fromlocator()
+ if res ~= error.ok then
+ break;
+ end
+ end
+ end
+ return res
+ end
+
+
+ --------------------------------------------------------------------------------
+
+ -- Already assigned before:
+ -- GF.warning = warning_msg
+ -- GF.error = error_msg
+ GF.load = load
+ GF.parse = parse
+ GF.chars = chars
+ GF.errorcode = error
+ GF.error_name = error_name
+ GF.parse_from_end = parse_from_end
+ --
+ -- TODO: parsing by reading a file
+ --
+
+
+end
+-- Add GF to the mflua table
+mflua.GF = GF