local a=rawget(_G,'loadstring')or load;local b=rawget(_G,'unpack')or rawget(table,'unpack')local c,d=table.insert,table.concat;local ipairs,type=ipairs,type;local io,_G=io,_G;local print,rawget=print,rawget;local e={FLOAT='[%+%-%d]%d*%.?%d*[eE]?[%+%-]?%d*',INTEGER='[+%-%d]%d*',IDEN='[%a_][%w_]*',OPTION='[%a_][%w_%-]*'}local function f(g,h,i)if type(h)~=i then error("argument "..g.." must be "..i,2)end end;local j={}local k={['<']='>',['(']=')',['{']='}',['[']=']'}local l={a=1,c=0,d=1,l=1,p=0,u=1,w=1,x=1,s=0}local function m(n)return'('..n..')'end;local function o(p)return p:gsub('[%-%.%+%[%]%(%)%^%%%?%*]','%%%0'):gsub('%$%%(%S)','$%1')end;local function q(r)return r:gsub("()%s+()",function(s,t)local u=r:sub(s-2,s-1)if u:match('%$[vifadxlu]')or u:match('^[^%$]?[%w_]$')then local v=r:sub(t,t+1)if v:match('%$[vifadxlu]')or v:match('^[%w_]')then return'%s+'end end;return'%s*'end)end;local w={v=m(e.IDEN),i=m(e.INTEGER),f=m(e.FLOAT),o=m(e.OPTION),r='(%S.*)',p='([%a]?[:]?[\\/%.%w_]+)'}function j.custom_pattern(x,r)w[x]=r end;function j.create_pattern(p,y)f(1,p,'string')local z,A={},{}if type(p)=='string'then p=o(p)else local B={}for C,n in ipairs(p)do B[C]=o(n)end;p=d(B,'.-')end;local D=1;local function E(F,type)F=F or D;c(z,F)A[F]=type;D=D+1 end;local G=p:find('{%a+}')if y and y.at_start then p='^'..p end;if p:sub(-1,-1)=='$'then p=p:sub(1,-2)..'$r'if G then p=p..'{rest}'end end;local H;if G then H={}p=p:gsub('{(%a+)}',function(F)c(H,F)return''end)end;p=q(p)local I=1;local J;local K=p:gsub('%$%S',function(n)local type,F;type=n:sub(2,2)if H then F=H[I]I=I+1 end;if not H and type=='q'then E(nil,'Q')else E(F,type)end;local B;if w[type]then B=w[type]elseif type=='q'then E(F,type)B='(["\'])(.-)%'..D-2 else local L=k[type]if L then B='(%b'..type..L..')'elseif l[type]or l[type:lower()]then B='(%'..type..'+)'else J="unknown format type or character class"end end;return B end)if J then return nil,J else return K,z,A end end;local function M(n)return n=='d'or n=='i'or n=='f'end;function j.create_spec_fun(p,y)local A,z;local N={}p,z,A=j.create_pattern(p,y)if not p then return p,z end;local G=type(z[1])=='string'for C=1,#z do c(N,'mm'..C)end;N[1]=N[1]or"mm1"local O=('return (function(s,res)\n\tlocal %s = s:match(%q)\n'):format(d(N,','),p)O=O..'\tif not mm1 then return false end\n'local I=1;for C,P in ipairs(z)do if P~='_'then local Q='mm'..C;if M(A[P])then Q='tonumber('..Q..')'elseif k[A[P]]then Q=Q..':sub(2,-2)'end;if G then O=('%s\tres.%s = %s\n'):format(O,P,Q)else if A[P]~='Q'then O=('%s\tres[%d] = %s\n'):format(O,I,Q)I=I+1 end end end end;return O..'\treturn true\nend)\n',G end;function j.compile(p,y)f(1,p,'string')local O,H=j.create_spec_fun(p,y)if not O then return nil,H end;if rawget(_G,'_DEBUG')then print(O)end;local R,J=a(O,'tmp')if J then return nil,J end;return R(),H end;local S={}function j.match(p,T,B,y)f(1,p,'string')f(2,T,'string')f(3,B,'table')if not S[p]then S[p]=j.compile(p,y)end;return S[p](T,B)end;function j.match_at_start(p,T,B)return j.match(p,T,B,{at_start=true})end;function j.fields(p,P)f(1,p,'string')if not P then return nil,"no file object"end;local O,J=j.compile(p)if not O then return nil,J end;local B={}return function()while true do local T=P:read()if not T then return end;if O(T,B)then local U=B;B={}return b(U)end end end end;local V={}function j.pattern(p,O)f(1,p,'string')local W,X=j.compile(p)c(V,{pat=W,named=X,callback=O})end;function j.read(P,Y)local Z,J;if not P then return nil,"no file object"end;if type(P)=='string'then P,J=io.open(P)if not P then return nil,J end;Z=true end;if Y then for _,a0 in ipairs(Y)do j.pattern(a0[1],a0[2])end end;local B={}for T in P:lines()do for _,a1 in ipairs(V)do if a1.pat(T,B)then if a1.callback then if a1.named then a1.callback(B)else a1.callback(b(B))end end;B={}break end end end;if Z then P:close()end end;return j