"--[[ Copyright (C) 2020 Momi-g\n"
"\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 3 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
"--]]\n"
"\n"
"\n"
"local ctxx={}\n"
"--[=[*\n"
"@_name	tdup\n"
"@auther momi-g\n"
"@brief	duplicate table, from penlight lib 'deepcopy()'\n"
"@_synopsys	tb tdup(t1, nil/t2)	\n"
"@_eg\n"
"	t1={1,2,3};	t2={}\n"
"	tdup(t1, t2)	-- or  t2=tdup(t1)\n"
"	\n"
"@param t1 copy srctb. \n"
"@param t2 dsttb.  \n"
"@return tb. same data with t2.\n"
"@_note cite from https://github.com/Tieske/Penlight\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-05-11\n"
"]=]\n"
"\n"
"function ctxx.tdup(t1, t2) \n"
"	if t2==nil then  t2={}  end \n"
"	if type(t1) ~=\"table\"  or  type(t2) ~= \"table\" then \n"
"		ctxx.errstop(\"(ag1,ag2) must be (tb,tb/nil): \"..ctxx.vinfo(t1,t2), 2)\n"
"	 end \n"
"	t2 = ctxx.tdupsub(t1,{})\n"
"	return t2\n"
" end\n"
"function ctxx.tdupsub(tb, loopck) \n"
"-- copied from penlight lib.\n"
"-- https://github.com/Tieske/Penlight\n"
"	if type(tb)~=\"table\" then return tb end \n"
"	if loopck[tb] then return loopck[tb]  end \n"
"	--loopckはアドレスstrをkeyにしてloopを管理\n"
"	local mt = getmetatable(tb)\n"
" 	local res = {}	--for use pointer. dmytbl.\n"
"	loopck[tb]=res\n"
" 	for k,v in pairs(tb)  do do \n"
"		k=ctxx.tdupsub(k, loopck)\n"
"		v=ctxx.tdupsub(v, loopck)\n"
"		res[k]=v\n"
"	 end::_luka_LOOPNEXT::end \n"
"	setmetatable(res,mt)\n"
"	return res\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	eqv\n"
"@auther momi-g\n"
"@brief	compare values using recursive check, from penlight lib 'deepcompare()'\n"
"@_synopsys	bool eqv( obj1, obj2)\n"
"@_eg\n"
"	aa={1,2,3};	bb=\"hw\"\n"
"	if( eqv(aa, bb) ) then print(\"same_data\") end\n"
"@param obj1	compdata. accept any types, num/func/tb etc. \n"
"@param obj2 same as obj1 \n"
"@return bool	true/false\n"
"@_note https://github.com/Tieske/Penlight\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-05-11\n"
"]=]\n"
"function ctxx.eqv(t1,t2)  return ctxx.tcompsub(t1,t2, {})  end\n"
"function ctxx.tcompsub(t1,t2, loopck) \n"
"	if loopck[t1]  and  loopck[t1][t2]  then return true end \n"
"	local ty1 = type(t1)\n"
"	local ty2 = type(t2)\n"
"	if ty1 ~= ty2 then return false end \n"
"--non-table types can be directly compared\n"
"	if ty1 ~= 'table' then  return t1 == t2  end \n"
"--as well as tables which have the metamethod __eq\n"
"	local mt = getmetatable(t1)\n"
"	for k1 in pairs(t1)  do do  if t2[k1]==nil then return false end   end::_luka_LOOPNEXT::end \n"
"	for k2 in pairs(t2)  do do  if t1[k2]==nil then return false end   end::_luka_LOOPNEXT::end \n"
"	loopck[t1] = loopck[t1]  or  {}\n"
"	loopck[t1][t2] = true\n"
"	for k1,v1 in pairs(t1) do do \n"
"		local v2 = t2[k1]\n"
"		if  not  ctxx.tcompsub(v1,v2,loopck)  then return false end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return true\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	sopairs\n"
"@auther momi-g\n"
"@brief	rtn key-sorted val when use forloop\n"
"@_synopsys	k,v sopairs(tb)\n"
"@_eg\n"
"	tb={[10]=11, [\"bob\"]=20, [\"alice\"]=30, [4]=33 }\n"
"	for k,v in sopairs(tb) do\n"
"		print(v)	--> true,4,10,alice,bob,false  >> 9,33,11,30,20,99\n"
"	end\n"
"@param tb	tb consists of keytype num/str. sort as num<str if type is mixed.\n"
"@return k,v	sorted key/val\n"
"@_note\n"
"cite: http://lua-users.org/wiki/SortedIteration\n"
"license: http://lua-users.org/wiki/GuestBook... permissive more than MIT? \n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-11-20\n"
"]=]\n"
"\n"
"local function cmp_multitype(op1, op2) \n"
"	local type1, type2 = type(op1), type(op2)\n"
"	if type1 ~= type2 then  return type1 < type2  \n"
"	elseif type1 == \"number\"  or  type1 == \"string\" then  return op1 < op2  \n"
"	elseif type1 == \"boolean\" then  return op1 == true  \n"
"	else  return tostring(op1) < tostring(op2)  end \n"
" end\n"
"local function __genOrderedIndex( t ) \n"
"	local orderedIndex = {}\n"
"	for  key in pairs(t)  do do  table.insert( orderedIndex, key )  end::_luka_LOOPNEXT::end \n"
"	table.sort( orderedIndex, cmp_multitype )\n"
"	return orderedIndex\n"
" end\n"
"local function orderedNext(t, state) \n"
"	local key = nil\n"
"	if state == nil then \n"
"		t.__orderedIndex = __genOrderedIndex( t )\n"
"		key = t.__orderedIndex[1]\n"
"	 else \n"
"		for i = 1,table.getn(t.__orderedIndex)  do do \n"
"			if t.__orderedIndex[i] == state then  key = t.__orderedIndex[i+1]  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"	 end \n"
"	if key then  return key, t[key]  end \n"
"	t.__orderedIndex = nil\n"
"	return\n"
" end\n"
"function ctxx.sopairs(t) return orderedNext, t, nil  end\n"
"\n"
"--[=[*\n"
"@_name	tsize\n"
"@auther momi-g\n"
"@brief	count tb atms\n"
"@_synopsys	num tsize(tb/nil)\n"
"@_eg\n"
"	aa={1,2,3, msg=\"hw\", {10,20}, {100,200} }\n"
"	local sz = tsize(aa)	-->	6\n"
"@param tb	tgt. use blanktb{} if nil.\n"
"@return num	count result\n"
"@_note -\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-05-11\n"
"]=]\n"
"function ctxx.tsize(t) \n"
"	if type(t)~=\"table\"  and  t~=nil then  return nil, ctxx.fperr(nil, \"bad argtype: \"..ctxx.vinfo(t)) end \n"
"	t=t or {}\n"
"	local i = 0\n"
"	for k in pairs(t) do do  i=i+1  end::_luka_LOOPNEXT::end \n"
"	return i\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	loadstring\n"
"@auther momi-g\n"
"@brief	eval wrapper of lua5.1/loadstring() and lua5.3/load()\n"
"@_synopsys	rtns loadstring(str, pseudo_name/nil)\n"
"@_eg\n"
"	local buf=\"print('hello'); print('world')\"\n"
"	local myfunc, emsg = loadstring(buf, \"abc\")\n"
"	myfunc()	--> disp hw\n"
"@param str	luacode\n"
"@param pseudo_name	funcname used in debug.info() etc.\n"
"@return rtns	5.1 loadstirng() or 5.3 load() return val.\n"
"@_note -\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-05-11\n"
"]=]\n"
"local loadstring=loadstring\n"
"function ctxx.loadstring(cmd, name) \n"
"	if loadstring==nil then  return load(cmd, name, \"t\", _G)  end \n"
"	return loadstring(cmd, name)\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	flwrite, flwrite_add, flread\n"
"@auther momi-g\n"
"@brief	read/write filename/filehandle data\n"
"@_synopsys	str, emsg flwrite(fh/flname, str/nil)\n"
"	str, emsg flwrite_add(fh/flname, str/nil)\n"
"	str, emsg flread(fh/flname)\n"
"@_eg\n"
"	local res, emsg = flwrite(\"./my.log\", \"hw\")\n"
"	res, emsg = flwrite_add(\"./my.log\", \"g\\0w\")	--> res=gw, #res=3\n"
"	res, emsg = flread(\"./my.log\")	--> res=hwg(\\0)w	#res=5\n"
"	flwrite(io.stdout, \"abc\")	--> same as print(\"abc\")\n"
"\n"
"@param fh/flname	write/read tgt. use as filename if string\n"
"@param str/nil	write str. conv to blankstr \"\" if nil. \n"
"@return str	write/read str. rtn nil, emsg if err.\n"
"@details flwrite(file) is always overwrite the file.\n"
"	run open() - read/write - flush() - close() if tgt is file\n"
"	run (none) - read/write - flush() - (none)	if tgt is fh\n"
"@_note -\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.3, 2021-03-19\n"
"]=]\n"
"function ctxx.flwrite(tgt, str) \n"
"	local rc, emsg, cflg=nil, nil, nil\n"
"	if type(tgt)==\"string\" then  cflg=1; tgt, emsg = io.open(tgt, \"wb\")  end \n"
"	if io.type(tgt)~=\"file\"  then \n"
"		return nil, emsg or ctxx.fperr(nil, \"invalid 1st arg file/fh: \"..ctxx.vinfo(tgt), 2)\n"
"	 end \n"
"	str=str or \"\"\n"
"	if type(str)~=\"string\"  then \n"
"		return nil, ctxx.fperr(nil, \"2nd arg allows only string/nil: \"..ctxx.vinfo(str), 2)\n"
"	 end \n"
"	rc, emsg = tgt.write(tgt, str)\n"
"	tgt.flush(tgt)\n"
"	if emsg then  return nil, emsg  end \n"
"	if cflg then  tgt.close(tgt)  end \n"
"	return str\n"
" end\n"
"function ctxx.flwrite_add(tgt, str) \n"
"	local rc, emsg, cflg=nil, nil, nil\n"
"	if type(tgt)==\"string\" then  tgt, emsg = io.open(tgt, \"ab\"); cflg=1  end \n"
"	if io.type(tgt)~=\"file\"  then \n"
"		return nil, emsg or ctxx.fperr(nil, \"invalid 1st arg file/fh: \"..ctxx.vinfo(tgt), 2)\n"
"	 end \n"
"	str=str or \"\"\n"
"	if type(str)~=\"string\"  then \n"
"		return nil, ctxx.fperr(nil, \"2nd arg allows only string/nil: \"..ctxx.vinfo(str), 2)\n"
"	 end \n"
"	rc, emsg = tgt.write(tgt, str)\n"
"	tgt.flush(tgt)\n"
"	if emsg then  return nil, emsg  end \n"
"	if cflg then  tgt.close(tgt)  end \n"
"	return str\n"
" end\n"
"\n"
"function ctxx.flread(tgt) \n"
"	local str, emsg, cflg=nil, nil, nil\n"
"	if type(tgt)==\"string\" then  cflg=1; tgt, emsg = io.open(tgt, \"rb\")  end \n"
"	if io.type(tgt)~=\"file\" then \n"
"		return nil, emsg or ctxx.fperr(nil, \"invalid 1st arg file/fh: \"..ctxx.vinfo(tgt), 2)\n"
"	 end \n"
"	str, emsg = tgt.read(tgt, \"*a\")\n"
"	if emsg then  return nil, emsg  end \n"
"	if cflg then  tgt.close(tgt)  end \n"
"	return str\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	sleep\n"
"@auther momi-g\n"
"@brief	second sleep function, busyloop wait\n"
"@_synopsys	(nortn) sleep(num)\n"
"@_eg	sleep(2)\n"
"@param num wait second time(int). cpu usage will be 100%. \n"
"@return nortn\n"
"@_note \n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-04-09\n"
"]=]\n"
"function ctxx.sleep(num) \n"
"	if  type(num) ~= \"number\"  then  ctxx.errstop(\"argtype isnt num: \"..ctxx.vinfo(num) )  end \n"
"	local s=os.time()\n"
"	while 1 do do \n"
"		if  os.difftime( os.time(), s ) > num  then \n"
"			 do break end \n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	ismain\n"
"@auther momi-g\n"
"@brief	test nowfunc is run as stackroot or not, mimic of py3 'if __main__'\n"
"@_synopsys	bool ismain(num/nil)\n"
"@_eg\n"
"	if( ismain(1) ){ print(\"run as root call\") }\n"
"	ismain()	--> same as ismain(1)\n"
"	local function myf() print(ismain(2)) end	--> callsrc func is main or not\n"
"@param num funclv, same as error(). nil is use as num 1. \n"
"@return 1rtn. bool\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.4, 2021-01-31\n"
"]=]\n"
"\n"
"-- mainチャンクとstackのカウント数でチェック\n"
"function ctxx.ismain(num) \n"
"	if  type(num) ~= \"number\"  and  num ~= nil  then \n"
"		ctxx.errstop(\"argtype isnt num/nil: \"..ctxx.vinfo(num) )\n"
"	 end \n"
"	num=num or 1\n"
"	local pos=1\n"
"	while  debug.getinfo(pos) do do pos=pos+1 end::_luka_LOOPNEXT::end \n"
"	local mpos=pos-1\n"
"	while  debug.getinfo(mpos)  and  debug.getinfo(mpos).what ~= \"main\" do do mpos=mpos-1 end::_luka_LOOPNEXT::end \n"
"	local cnt=0\n"
"	while  debug.getinfo(num+1+cnt)  do do cnt=cnt+1 end::_luka_LOOPNEXT::end \n"
"	return (pos-mpos==cnt)\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	ismwd\n"
"@auther momi-g\n"
"@brief	tests srccode is called as Mainfile + exist in pWD  \n"
"@_synopsys	bool, emsg ismwd(num/nil)	\n"
"@_eg\n"
"	-- aa.lua\n"
"		-- copy&paste func --\n"
"	if( ! ismwd()){ print(\"selfcode doesnt exists in PWD. chdir to src path\") }\n"
"	local u = require(\"myutil\")\n"
"	local mod = loadfile(\"./mymod.lua\")\n"
"	\n"
"	local function aa_main()\n"
"		if( ! ismwd(2) ){ print(\"chdir to src path\") }\n"
"		print(\"hw\")\n"
"	end\n"
"\n"
"	-- ~$ lua aa.lua	...suc. disp hw\n"
"	-- ~$ lua ./aa.lua	...suc\n"
"	-- ~$ lua ../aa.lua	...fail\n"
"	-- ~$ lua /work/aa.lua (!= ./aa.lua)	...fail\n"
"	-- ~$ lua /home/dir/aa.lua (==./aa.lua)	...fail\n"
"	\n"
"	-- c-lang call:	luaL_loadfile(L, \"./aa.lua\")	..suc\n"
"	-- c-lang call:	luaL_loadfile(L, \"../aa.lua\")	..fail\n"
"\n"
"	-- call from lua: ...fail\n"
"	load(\"aa.lua\")		--> inner call\n"
"	load(\"..direct srccode..\")	--> not file\n"
"\n"
"@param num funclv, same as error(). nil is use as num 1. \n"
"@return 1/2rtn. true if suc. false + emsg if fail.\n"
"@details\n"
" satisfy the follow if pass this func\n"
"  - this funcsrc is a file(*.lua, *.so etc) and pwd ./ is the file dir\n"
"  - this src is called as stack lv 1, same as main()\n"
" this allows you to:\n"
"  - call in the same dir files with loadfile(\"./foo.lua\"), require(\"foo\")\n"
"\n"
" ..lua lacks chdir api. lua modload sys is complex, changed frequently and poor.\n"
" lfs has dirapi(c-lang) but dependency grows.\n"
" this func protects your code portability by restricting how to call your src.\n"
"\n"
"@_conforming lua5.3, luajit2.0+\n"
"@version 1.0.2, 2020-11-08\n"
"]=]\n"
"--getinfo(0)はgetinfo, 1はismwd(), 2はa.lua, 3がvm, 4でゼロになるはず。\n"
"local function ismwd(num) \n"
"	num=num or 1\n"
"	assert( type(num) == \"number\")\n"
"	local info=debug.getinfo(2).source..\":\"..debug.getinfo(2,\"l\").currentline..\":\"..debug.getinfo(2).name..\"(): \"\n"
"	local sname = debug.getinfo(1+num).source\n"
"	if   not (debug.getinfo(3+num)==nil  and  debug.getinfo(2+num))  then \n"
"		return false, info..\"err. \"..sname..\" must be loaded as root func\"\n"
"	 end \n"
"	if string.sub(sname, 1, 1)~=\"@\" then return false,\"err: this code must be loaded as file: \"..sname  end \n"
"	sname = string.sub(sname, 2)\n"
"	local sep = string.match(package.path, \".%?\")\n"
"	if sep==\"\" then  return false, \"err: failed to get dirsep from path ENV (/ etc): \"..sname  end \n"
"	sep=string.sub(sep, 1,1)	-- win\\ or unix/\n"
"	local buf = string.gsub(sname, \".*%\"..sep, \"\")	--del head ./, allow only a.lua ./a,lua\n"
"	if buf~=sname  and  \".\"..sep..buf ~= sname then \n"
"		return false, \"err: this file must be loaded as './foo' or 'foo'. run from srcdir: \"..sname\n"
"	 end \n"
"	return true\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	v2bool\n"
"@auther momi-g\n"
"@brief	exchange var to bool\n"
"@_synopsys	v2bool(obj)\n"
"@_eg	flg = v2bool(\"123\")	--> true\n"
"@return 1 bool\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-04-07\n"
"]=]\n"
"function ctxx.v2bool(obj) \n"
"	if obj then return true end \n"
"	return false\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	istypes\n"
"@auther momi-g\n"
"@brief	check object types.\n"
"@_synopsys	char/nil istypes(obj, fmt/nil)\n"
"@_eg\n"
"	res = istypes(23, \"sN\") --> res=nil. 23 is (n)um. \"sN\"==(s)tr || (N)il\n"
"	res = istypes(\"abc\") --> conv to istypes(\"abc\", \"A\"). res=\"s\"\n"
"	res = istypes(10.1) --> res=\"n\"\n"
"	res = istypes(10.1, \"i\") --> res=nil\n"
"@param obj target obj you want to ck\n"
"@param fmt allow type chars. (N)il,(b)ool,(n)um,(s)tr,(t)bl,(f)unc,(u)data,\n"
"(T)hread and (i)nt,(A)ll. 'A' is conv to 'NbnstfuT'. 'i' is not primary type.\n"
"@return char/nil	always returns 1char except for 2arg compmode+fail...(nil).\n"
"@details	rtn \"_\" if detect non-basic type in 1arg mode, istypes(ffi.new) etc.\n"
"@_note\n"
" loop 1000	u.istypes(123, \"A\")	--> real	1.580 ms	...slow 50 time \n"
" loop 1000	types(123)	--> real	0.027 ms\n"
" loop 1000	nilfunc()	--> real	0.050 ms\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.4, 2020-07-13\n"
"]=]\n"
"function ctxx.istypes(obj, str) \n"
"	local f1=0\n"
"	if str==nil then str=\"NbnstfuT\";f1=1 end \n"
"	if type(str)~=\"string\" then  ctxx.errstop(\"2nd arg is not string: \"..type(str), 2)  end \n"
"	if  string.find(str, \"A\")  then str = \"NbnstfuT\"..str  end \n"
"	if  string.match(str, \"[^NbnstfuTAi]\")  then \n"
"		ctxx.errstop(\"bad typechar [NbnstfuTAi]: \"..str, 2)\n"
"	 end \n"
"	local tbl={}\n"
"	local res=type(obj)\n"
"	local ires=\"_\"\n"
"	if  res==\"nil\"  then  res=\"N\"  \n"
"	elseif  res==\"boolean\"  then  res=\"b\"  \n"
"	elseif  res==\"number\"  then \n"
"		res=\"n\"\n"
"		local i,r = math.modf(obj)\n"
"		if r==0 then ires=\"i\" end \n"
"	 \n"
"	elseif  res==\"string\"  then  res=\"s\"  \n"
"	elseif  res==\"table\"  then 	res=\"t\"  \n"
"	elseif  res==\"function\"  then  res=\"f\"  \n"
"	elseif  res==\"userdata\"  then  res=\"u\"  \n"
"	elseif  res==\"thread\"  then 	res=\"T\"  end \n"
"	local buf = string.find(str, res)\n"
"	--救済。integer\n"
"	if buf==nil then \n"
"		res=nil\n"
"		buf = string.find(str, ires)\n"
"		if buf~=nil then res=ires end \n"
"	 end \n"
"	if f1==1 and buf==nil then res=\"_\" end \n"
"	return res\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	tb2va\n"
"@auther momi-g\n"
"@brief	conv tbseq to va_args, wrapper of unpack/table.unpack\n"
"@_synopsys	va tb2va(tb/nil)\n"
"@_eg\n"
"tbuf={10, \"aa\", nil, \"cc\", name=\"alice\"}\n"
"print(\"atm is:\", tb2va(tbuf) )	--> atm is: 10 aa, ignore not seq atms.\n"
"\n"
"--~$ lua 1 \"alice\" abc\n"
"print(\"args: \", tb2va(_G) )		--> 1, alice, abc\n"
"\n"
"@param tb	tgt. use blanktb{} if nil.\n"
"@return va	splitted seqtb atms. ignore not seqdata.\n"
"@details	-\n"
"@_note -\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-07-29\n"
"]=]\n"
"\n"
"local unpack_wrap=unpack\n"
"function ctxx.tb2va(tb) \n"
"	if tb==nil then  tb={}  end \n"
"	if type(tb)~=\"table\" then  ctxx.errstop(\"1st arg allows only tb/nil: \"..ctxx.vinfo(tb), 2)  end \n"
"	if unpack_wrap==nil then unpack_wrap=table.unpack end \n"
"	if unpack_wrap==nil then  ctxx.errstop(\"5.1/5.3 unpack/table.unpack is nil. new lua version?\")  end \n"
"	return unpack_wrap(tb)\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	getlovars\n"
"@auther momi-g\n"
"@brief	get callsrcfunc localvars(nameselect), getlocal() wrapper.\n"
"@_synopsys	obj/tbl getlovars(num/nil, str/nil)\n"
"@_eg\n"
"	local a, b = 11, 22\n"
"	local function myf()	--stklv 1\n"
"		local b=99\n"
"		res = getlovars(1, \"a\")	--> nil\n"
"		res = getlovars(2, \"a\")	--> 11\n"
"		res = getlovars(1)	--> {b=99}\n"
"	end\n"
"	myf()	--run\n"
"	local c=44	--not counted\n"
"\n"
"@param num stack level. 1:self 2:callsrc 3-:more. rtn nil if lv is erange.\n"
"@param str/nil target name. rtn alldata tbl if nil\n"
"@return 1rtn.  rtn obj/tbl if 2nd param is exist/nil	rtn nil,emsg if err.\n"
"@_note external local vars(called 'upvalue' in lua) isnt local vars.  \n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.2, y2020m04d07\n"
"]=]\n"
"\n"
"function ctxx.getlovars(lv, key) \n"
"	local rtn={}\n"
"	local emsg=nil\n"
"	local i=1\n"
"\n"
"	if type(lv)==\"nil\" then lv=1 end \n"
"	if type(lv)~=\"number\" or  ctxx.istypes(key, \"sN\")==nil then \n"
"		emsg = ctxx.sprintf(\"%s(): bad args. 1,num/nil 2,num/nil/str: %s %s\"\n"
"		,ctxx.S_FUNC(1), type(lv), type(key) )\n"
"		error(emsg, 2)\n"
"	 end \n"
"	local buf = debug.getinfo(1+lv)\n"
"	if lv<0 or buf==nil then \n"
"		emsg=ctxx.fperr(nil, \"1st arg, stack lv is out of stack depth\", 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	while true do do \n"
"		local k, v = debug.getlocal(1+lv, i)\n"
"		if k==nil then   do break end   end \n"
"		rtn[k] = v\n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	if key~=nil then rtn=rtn[key]  end \n"
"	return rtn\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	setlovars\n"
"@auther momi-g\n"
"@brief	set callsrcfunc localvars(nameselect), setlocal() wrapper.\n"
"@_synopsys\n"
"str setlovars(num, str, obj)\n"
"@_eg\n"
"	local a, b = 123, 999\n"
"	local res = setlovars(1, \"a\", 10)	--> res = \"a\"\n"
"	print(a) --> 10\n"
"@param num stack level. 1:self 2:callsrc 3-:more. rtn nil if lv is erange.\n"
"@param str target name.  \n"
"@param obj input data.  \n"
"@return 1 rtn.  suc:not nil/false	fail:nil, emag\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.2, y2020m04d07\n"
"]=]\n"
"function ctxx.setlovars(lv, key, data) \n"
"	local rtn = debug.getinfo(1+lv)\n"
"	local i=1\n"
"	if lv<0 or rtn==nil then \n"
"		emsg=ctxx.fperr(nil, \"1st arg, stack lv is out of stack depth\", 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	while 1 do do \n"
"		local k, v = debug.getlocal(1+lv, i)\n"
"		if k==key or k==nil then   do break end   end \n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	if k==nil then \n"
"		emsg=ctxx.fperr(nil, \"2nd arg, no such local name\", 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	rtn = debug.setlocal(1+lv, i, data)\n"
"	return rtn\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	getscvars\n"
"@auther momi-g\n"
"@brief	get scopevars(local + external local + global) using stklv+varname.\n"
"@_synopsys	tbl/obj getscvars(num/nil, str/nil)\n"
"@_eg\n"
"	local a=1\n"
"	local function myf()	--stklv 1\n"
"		local b=99\n"
"		rtn = getscvars(1, \"b\")	--> 99\n"
"		rtn = getscvars(2, \"b\")	--> 13\n"
"		rtn = getscvars(1, \"c\")	--> nil\n"
"		rtn = getscvars(1)	--> {a=1,b=99,myf=func, +globals} ...scope vars tbl.\n"
"	end\n"
"	local b=13\n"
"	myf()	--run. stklv 2\n"
"	local c=34	--out of count\n"
"@param num stack lv. 1:self 2:callsrc 3-:more. rtn nil,emsg if lv is erange.\n"
"@param str target keyname. rtns datatbl if nil.  \n"
"@return 1rtn. target value or all value tbl. rtn nil,emsg if err.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.1, y2020m04d07\n"
"]=]\n"
"function ctxx.getscvars(lv, key) \n"
"	if type(lv)~=\"number\"  then  ctxx.errstop(\"1st arg must be num: \"..type(slv), 2)  end \n"
"	if key~=nil  and  type(key)~=\"string\"  and  type(key)~=\"number\"  then \n"
"		ctxx.errstop(\"2nd arg must be mun/str/nil: \"..type(key), 2)\n"
"	 end \n"
"	\n"
"	local rtn={}\n"
"	local emsg=nil\n"
"	\n"
"	lv=lv+1\n"
"	local buf = debug.getinfo(lv)\n"
"	if lv<=0 or buf==nil then \n"
"		emsg=ctxx.fperr(nil, \"1st arg, stklv is out of stkdepth\", 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	local i=1\n"
"	--local\n"
"	while true do do \n"
"		local k, v = debug.getlocal(lv, i)\n"
"		if k==nil then   do break end   end \n"
"		rtn[k] = v\n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--scope\n"
"	local buf = debug.getinfo(lv).func\n"
"	i=1\n"
"	while true do do \n"
"		local k, v = debug.getupvalue(buf, i)\n"
"		if k==nil then   do break end   end \n"
"		if rtn[k] == nil then  rtn[k] = v  end \n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--global\n"
"	i=1\n"
"	for k,v in pairs(_G)  do do  if rtn[k] == nil then  rtn[k] = v  end   end::_luka_LOOPNEXT::end \n"
"	if key~=nil then rtn=rtn[key]  end \n"
"	if rtn==nil then \n"
"		emsg=ctxx.fperr(nil, \"err. key isnt used: \"..key , 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	return rtn\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	setscvars\n"
"@auther momi-g\n"
"@brief	set scopevars(local + external local + global) using stklv+varname.\n"
"@_synopsys	suc setscvars(num/nil, str, obj)\n"
"@_eg\n"
"	local a=1\n"
"	local function myf()	--stklv 1\n"
"		local b=10\n"
"		setscvars(1, \"b\", 100)\n"
"		setscvars(1, \"z\", 200)\n"
"		print(b, z)	--> 100, 200\n"
"		setscvars(1, \"a\", \"hw\" )	--> 'a' is external local var, a=1 >> a=\"hw\".\n"
"	end\n"
"	local b=13\n"
"	myf()	--run. stklv 2\n"
"	print(a, b, z)	-->	hw, 13, nil\n"
"@param num stack lv. 1:self 2:callsrc 3-:more. rtn nil,emsg if lv is erange.\n"
"@param str target keyname. rtns datatbl if nil.  \n"
"@param obj the value you want to set.  \n"
"@return 1rtn. not nil/false value. rtn nil,emsg if err.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.1, y2020m04d07\n"
"]=]\n"
"\n"
"function ctxx.setscvars(lv, key, data) \n"
"	if type(lv)~=\"number\"  then  ctxx.errstop(\"1st arg must be num: \"..type(slv), 2)  end \n"
"	if key~=nil  and  type(key)~=\"string\"  and  type(key)~=\"number\"  then \n"
"		ctxx.errstop(\"2nd arg must be mun/str/nil: \"..type(key), 2)\n"
"	 end \n"
"	lv=lv+1\n"
"	local rtn = debug.getinfo(lv)\n"
"	local i=1\n"
"	if lv<=0 or rtn==nil then \n"
"		emsg=ctxx.fperr(nil, \"1st arg, stklv is out of stkdepth\", 2)\n"
"		return nil, emsg\n"
"	 end \n"
"	--local\n"
"	while 1 do do \n"
"		local k, v = debug.getlocal(lv, i)\n"
"		if k==nil then   do break end   end \n"
"		if k==key then \n"
"			local rtn = debug.setlocal(lv, i, data)\n"
"			return rtn\n"
"		 end \n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--scope\n"
"	i=1\n"
"	local buf = debug.getinfo(lv).func\n"
"	while 1 do do \n"
"		local k, v = debug.getupvalue(buf, i)\n"
"		if k==nil then   do break end   end \n"
"		if k==key then \n"
"			local rtn = debug.setupvalue(buf, i, data)\n"
"			return rtn\n"
"		 end \n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--global\n"
"	for k,v in pairs(_G)  do do \n"
"		if k == key then \n"
"			_G[k] = data\n"
"			return key\n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	--nohit\n"
"	emsg=ctxx.fperr(nil, \"err. key isnt used: \"..key , 2)\n"
"	return nil, emsg\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	S_FILE, S_LINE, S_FUNC\n"
"@auther momi-g\n"
"@brief	mimic C macro __FILE__, __LINE__, __func__, all rtns (S)tr (not num).\n"
"@_synopsys\n"
"	str S_FILE()	--> conv to S_FILE(1)\n"
"	str S_FILE(num)\n"
"@_eg\n"
" 1:	function f_aa() f_bb();	end\n"
" 2:	function f_bb()\n"
" 3:		print( S_FILE(1),S_LINE(), S_FUNC() )\n"
" 4:		print( S_FILE(2), S_LINE(2), S_FUNC(2) )\n"
" 5:	end\n"
" 6:	f_bb()	--> mylua.lua, 3, f_bb //  mylua.lua, 6/nil, [C?]/nil 	\n"
" 7:	f_aa()	--> mylua.lua, 3, f_bb //  mylua.lua, 1(f_bb call pos), f_aa \n"
"@param num fcall depth. same as debug.getinfo(num). 1:self 2:call src 3:...\n"
"@return 1 str. res will get strange string if name resolve failed (closure etc).\n"
"@details this func uses debug.getinfo(). recommend you to use small lv, 1 or 2.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.3, y2020m07d16\n"
"]=]\n"
"\n"
"function ctxx.S_FILE(i) \n"
"	local rmsg=\"\"\n"
"	if type(i)==\"nil\" then i=1 end \n"
"	if type(i)==\"number\" then \n"
"		rmsg = debug.getinfo(1+i,\"S\")\n"
"		if rmsg==nil then rmsg=\"nil\" \n"
"		elseif 1 then rmsg = rmsg.short_src end \n"
"	 \n"
"	elseif true then  error(ctxx.S_FUNC(1)..\"(): 1st arg is not num/nil: \"..type(i), 1)  end \n"
"	if rmsg==nil then  rmsg = \"nil\"  end \n"
"	return rmsg\n"
" end\n"
"function ctxx.S_LINE(i) \n"
"	local rmsg=\"\"\n"
"	if type(i)==\"nil\" then i=1 end \n"
"	if type(i)==\"number\" then \n"
"		rmsg = debug.getinfo(1+i,\"l\")\n"
"		if rmsg==nil then rmsg=\"nil\" \n"
"		elseif 1 then rmsg = rmsg.currentline end \n"
"	 \n"
"	elseif true then  error(ctxx.S_FUNC(1)..\"(): 1st arg is not num/nil: \"..type(i), 1)  end \n"
"	if rmsg==nil then  rmsg = \"nil\"  end \n"
"	return rmsg\n"
" end\n"
"function ctxx.S_FUNC(i) \n"
"	local rmsg=\"\"\n"
"--if(1){return \"now_debugging...\" }\n"
"	if type(i)==\"nil\" then i=1 end \n"
"	if type(i)==\"number\" then \n"
"		rmsg = debug.getinfo(1+i,\"n\")\n"
"		if rmsg==nil then  rmsg = \"nil\"  \n"
"		elseif 1 then rmsg = rmsg.name end \n"
"	 \n"
"	elseif true then  error(ctxx.S_FUNC(1)..\"(): 1st arg is not num/nil: \"..type(i), 1)  end \n"
"	return rmsg\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	tblconv, tbconv\n"
"@auther momi-g\n"
"@brief	tbl filter, grep key+value and sort. \n"
"@_synopsys	tbl tblconv(tbl/nil, str)\n"
"@_eg\n"
"	tbl = {[-3]=9, \"aa\", 10, [7]=20, a=1, b=\"hw\", c=true}\n"
"	res= tblconv(tbl, \"ind:n\")	--> {[-3]=9, nil, 10, [7]=20}, \"aa\" is not n(um)\n"
"	res= tblconv(tbl, \"key:sn\")	--> {a=1, b=\"hw\"}, s(tr) or n(um), \"c\" is bool.\n"
"	res= tblconv(tbl, \"seq:n\")	--> {nil, 10}, pickup 0<ind keys until nil.\n"
"	res= tblconv(tbl, \"indn:n\")	--> {[-1]9, 10, 20}, ind + n(ormalize)\n"
"	res= tblconv(tbl, \"seqn:n\")	--> {10}, seq + n(ormalize)\n"
"	res= tblconv(tbl, \"swap\")	--> {aa=1,[10]2,[20]7,[1]a,hw=\"b\",[9]-3}, ig \"c\"\n"
"	\n"
"	args= {[-2]=\"lua\",[-1]=\"-la\",[0]=\"b.lua\",\"t1\",\"t2\"}	--~$ lua -la b.lua t1 t2\n"
"	res= tblconv(args, \"seqn:s\") --> {\"t1\", \"t2\"}\n"
"@param tbl(must)	target tbl. nil is conv to {}, blanktbl.\n"
"@param str(must)	filter cmd. out_tbltype:src_datatypes. dtype allows blank. \n"
"	tbltype: ind,indn,seq,seqn,key,swap. ind is numkey, key is strkey.\n"
"	dtypes: (N)il,(b)ool,(n)um,(s)tr,(t)bl,(f)unc,(u)data,(T)hread,(A)ll or blank(All)\n"
"@return 1rtn. converted tbl. rtn nil,emsg if err. \n"
"@details \"swap\" ignores dtypes except \"ns\". \"ind:Nsn\" greps arr[num]=nil||str||num.\n"
"	\"key:NbnstfuT\" is equals to \"key:A\" / \"key:\" / \"key\".\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.1.3, y2020m04d05\n"
"]=]\n"
"function ctxx.tblconv(tbl, cmd) \n"
"	local rtn={}\n"
"	local buf=nil\n"
"	local cnt=1\n"
"	local emsg=\"\"\n"
"	\n"
"	if tbl==nil then tbl={}  end \n"
"	if  type(tbl)~=\"table\"  or  type(cmd)~=\"string\"  then \n"
"		ctxx.errstop(\"invaild args. f(tbl/nil, str): \"..type(tbl)..\", \"..type(cmd), 2)\n"
"	 end \n"
"	local b1, b2 = string.match (cmd, \"([a-z]+):?([a-zA-Z]*)\")\n"
"	if b1==nil then b1=\"\" end \n"
"	if b2==nil or b2==\"\" then  b2=\"A\"  end \n"
"	buf={ [\"ind\"]=1,[\"indn\"]=1,[\"seq\"]=1,[\"seqn\"]=1,[\"key\"]=1,[\"swap\"]=1 }\n"
"	if buf[b1] == nil  or  string.match(b2, \"[^NbnstfuTA]\")  then \n"
"		ctxx.errstop( \"err. 2nd argfmt is invalid: \"..cmd, 2 )\n"
"	 end \n"
"	if b1 == \"seq\"  then \n"
"		for k,v in ipairs(tbl)  do do  if  ctxx.istypes(v, b2)  then rtn[k]=v  end   end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if b1 == \"seqn\"  then \n"
"		for k,v in ipairs(tbl)  do do if  ctxx.istypes(v, b2)  then  rtn[1+#rtn]=v  end   end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if b1 == \"ind\" then \n"
"		for k,v in pairs(tbl)  do do \n"
"			if type(k)==\"number\"  and  ctxx.istypes(v, b2)  then  rtn[k]=v  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if b1 == \"indn\" then \n"
"		--ソートと詰めなおしを兼ねる。1,3,4,5みたいな飛び飛びインデックスを1,2,3,4へ\n"
"		--詰め込んで行ってvalueでソートをかければいけるか\n"
"		local kbuf={}\n"
"		for k,v in pairs(tbl)  do do \n"
"			if type(k)==\"number\"  and  ctxx.istypes(v, b2)  then 	kbuf[1+#kbuf] = k  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		table.sort(kbuf)	--キーは-1とか1の数値なので標準ソートでいける。\n"
"		local pbuf={}\n"
"		local nbuf={}\n"
"		--kbufのvalueはtblのキーなので、並び替えではこうなる。\n"
"		for k,v in ipairs(kbuf)  do do \n"
"			if 0<v then  pbuf[1+#pbuf]=tbl[v]  \n"
"			elseif v<0 then  nbuf[1+#nbuf]=tbl[v]  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		--合体\n"
"		local buf= -#nbuf\n"
"		for k,v in ipairs(nbuf)  do do \n"
"			pbuf[buf]=v\n"
"			buf=buf+1\n"
"		 end::_luka_LOOPNEXT::end \n"
"		--[0]は無視してたので追加\n"
"		pbuf[0]=tbl[0]\n"
"		rtn=pbuf\n"
"		goto lbl_RTN\n"
"	 end \n"
"	if b1 == \"key\" then \n"
"		for k,v in pairs(tbl)  do do \n"
"			if type(k)==\"string\"  and  ctxx.istypes(v, b2)  then  rtn[k]=v  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if b1 == \"swap\" then \n"
"		for k,v in pairs(tbl)  do do \n"
"			if  ctxx.istypes(v, \"sn\")  and  ctxx.istypes(v, b2)  then 	rtn[v]=k  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	::lbl_RTN::\n"
"	return rtn\n"
" end\n"
"-- add rename\n"
"ctxx.tbconv = ctxx.tblconv\n"
"\n"
"\n"
"--[=[*\n"
"@_name	vinfo\n"
"@auther momi-g\n"
"@brief	make value infomsg \n"
"@_synopsys	str vinfo(obj...)\n"
"@_eg\n"
"	a=12; b=\"hw\"\n"
"	res = vinfo(a,b)	--> res = \"12:n, hw:s\"\n"
"@param obj...	target obj.\n"
"@return 1str. shortmsg about input arg value/type. this func always succeeds.\n"
" types is : (N)il,(b)ool,(n)um,(s)tr,(t)bl,(f)unc,(u)data,(T)hread\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m04d03\n"
"]=]\n"
"function ctxx.vinfo(...) \n"
"	local rtn = \"\"\n"
"	local i=1\n"
"	local max=select(\"#\", ...)\n"
"	while i<=max do do \n"
"		local v=select(i, ...)\n"
"		rtn=rtn.. \", \"..tostring(v)..\":\"..ctxx.istypes(v)\n"
"		i=i+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	return string.sub(rtn, 3)\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	tbdump\n"
"@auther momi-g\n"
"@brief	dump tbdata with reuse/eval format \n"
"@_synopsys	str tbdump(tb)\n"
"@_eg\n"
"	tb={1, {b=12} }\n"
"	str = tbdump(tb)\n"
"	print(str)	--> {1, {[\"b\"]=12} }\n"
"@param tb	target. key/val type allows only num,str,bool / num,str,bool,tb\n"
"@return str. rtn nil,emsg if err.\n"
"@note raise stackoverflow if tb nest is too deep. ok:-50  err:100-\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, 2020-11-25\n"
"]=]\n"
"function ctxx.tbdump(tb) \n"
"	if type(tb)~=\"table\" then  return nil, ctxx.fperr(nil, \"1st arg is not tb: \"..ctxx.vinfo(tb), 2)  end \n"
"	local memo={}\n"
"	local indent=\"\"\n"
"	return ctxx.tbdumpsub(tb, indent, memo)\n"
" end\n"
"function ctxx.tbdumpsub(tb, indent, memo) \n"
"	memo[tb]=1\n"
"	local str=\"{\\n\"\n"
"	for k,v in pairs(tb)  do do \n"
"		if type(k)==\"number\" then  k=tostring(k)  \n"
"		elseif type(k)==\"string\" then  k=string.format('%q',k)  \n"
"		elseif type(k)==\"bool\" then  k=tostring(k)  \n"
"		elseif 1 then  return nil, ctxx.fperr(nil, \"bad key/val type, nsb/nsbt: \"..ctxx.vinfo(k,v), 2)  end \n"
"		k=\"[\"..k..\"]\"\n"
"		if type(v)==\"number\" then  v=tostring(v)  \n"
"		elseif type(v)==\"string\" then  v=string.format('%q',v)  \n"
"		elseif type(v)==\"bool\" then  v=tostring(v)  \n"
"		elseif type(v)==\"table\" then \n"
"			if memo[v] then  return nil, ctxx.fperr(nil, \"detect tb ptrloop: \"..ctxx.vinfo(k,v), 2)  end \n"
"			local emsg\n"
"			v, emsg=ctxx.tbdumpsub(v, indent..\"\\t\", memo)\n"
"			if emsg then return nil, emsg end \n"
"		 \n"
"		elseif 1 then  return nil, ctxx.fperr(nil, \"bad key/val type, nsb/nsbt: \"..ctxx.vinfo(k,v), 2)  end \n"
"		str=str..indent..k..\"=\"..v..\",\\n\"\n"
"	 end::_luka_LOOPNEXT::end \n"
"	memo[tb]=nil\n"
"	str=str..indent..\"}\"\n"
"	return str\n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	tinfo,	ftinfo\n"
"@auther momi-g\n"
"@brief	make tblinfo string \n"
"@_synopsys	str tinfo(tbl/nil)	/	str ftinfo(io, tbl/nil)\n"
"@_eg\n"
"	res = tinfo( {11,22, {a=1,33} })	--> stderr + res holds infostr.\n"
"	res = ftinfo( io.stderr, {1,2,3} )	-->	output + res\n"
"@param tbl/nil	target tbl.\n"
"@param io	io.stderr, io.stdout etc. noout if nil.\n"
"@return 1str rtn \"some_msg\" str if param is nil\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.1.6, 2020-12-12\n"
"]=]\n"
"local\n"
"function tinfosub(tb, tbname, ofs, mtbl) \n"
"	local tadd = string.match( tostring(tb), \"0[0-9a-fA-FxX]+\")\n"
"	mtbl[tadd]=1\n"
"	if type(tbname)==\"string\" then  tbname='\"'..tbname..'\"'  end \n"
"	tbname=tostring(tbname)\n"
"	\n"
"	local str=ofs..\"{ \"..tbname..\" :\"..tadd..\"\\n\"\n"
"	for k,v in pairs(tb)  do do \n"
"		if type(v) == \"table\" then \n"
"			tadd = string.match( tostring(v), \"0[0-9a-fA-FxX]+\")\n"
"			--loop系発見\n"
"			if mtbl[tadd] then \n"
"				str = str..ofs..\"\\t{ \"..tostring(k)..\" \"..tostring(tadd)..\" (sametb) }\\n\"\n"
"			 \n"
"			else \n"
"				str=str..tinfosub(v, k, ofs..\"\\t\", mtbl)\n"
"			 end \n"
"		 \n"
"		elseif 1 then \n"
"			if type(k)~=\"number\" then k='\"'..tostring(k)..'\"' end \n"
"			local buf=ctxx.istypes(v)\n"
"			str=str..ofs..tostring(k)..\" = \"..tostring(v)..\":\"..buf..\",\\n\"\n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	str=string.gsub(str,\",\\n$\",\"\\n\")\n"
"	str=str..ofs..\"}\\n\"\n"
"	return str\n"
" end\n"
"function ctxx.tinfo(tb)  return ctxx.ftinfo(io.stderr, tb)  end\n"
"function ctxx.ftinfo(fh, tb) \n"
"	if type(tb)~=\"table\" then return nil, ctxx.fperr(nil, \"2nd arg must be table: \"..ctxx.vinfo(tb), 2)  end \n"
"	local str = tinfosub(tb, \"\", \"\", {} )\n"
"	ctxx.fprintf(fh, \"%s\\n\", str )\n"
"	return str\n"
" end\n"
"ctxx.tbinfo=ctxx.tinfo\n"
"ctxx.ftbinfo=ctxx.ftinfo\n"
"\n"
"\n"
"--[=[*\n"
"@_name	dbg, fdbg\n"
"@auther momi-g\n"
"@brief	printf debug helper. \n"
"@_synopsys	str dbg(...)\n"
"@_eg\n"
"	a=123\n"
"	dbg( a, {22,33}, func ) --> output data to stderr. tbl is expanded.\n"
"	msg = fdbg(io.stdout, a, {22,33}, func ) --> change fh. noout if nil\n"
"@param va_args	all type obj. \n"
"@return 1 str. copy of disp msg\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.1, y2020m04d03\n"
"]=]\n"
"\n"
"function ctxx.fdbg(fh, ...) \n"
"	if  not  io.type(fh)  and fh~=nil then  ctxx.errstop(\"1st arg is not filetype: \"..ctxx.vinfo(fh), 2)  end \n"
"	local msg=\"dbg( \"\n"
"	local submsg=\"\"\n"
"	local buf\n"
"	--#は渡された...の引数の個数マーク\n"
"	for i=1,select(\"#\", ...)  do do \n"
"		buf=select(i, ...)\n"
"		if type(buf)==\"table\" then \n"
"			msg=msg..\"tbl:\"..i..\", \"\n"
"			submsg=submsg..\"tbl\"..i..\":\"..ctxx.ftinfo(nil, buf)..\"\\n\"\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		msg=msg..tostring(buf)..\":\"..ctxx.istypes(buf)..\", \"\n"
"		::lbl_NEXT::\n"
"	 end::_luka_LOOPNEXT::end \n"
"	msg=string.gsub(msg, \", $\", \" )\")\n"
"	if #submsg~=0 then 	msg=msg..\"\\n\"..submsg  end \n"
"	if  select(\"#\", ...)==0 then 	msg=\"dbg()\\n\"  end \n"
"--print(\"dbgfunc_1\", msg)\n"
"--	msg = \"(): \"..msg..\"\\n\\n\"\n"
"--print( ctxx.S_FILE(2) )\n"
"--print( ctxx.S_LINE(2) )\n"
"--print( ctxx.S_FUNC(2) )\n"
"--	msg = ctxx.S_FILE(2)..\" \"..ctxx.S_LINE(2)..\": func_SEGV_mode(): \"..msg..\"\\n\\n\"\n"
"	msg = (ctxx.S_FILE(2) or \"\")..\" \"..(ctxx.S_LINE(2) or \"\")..\": \"..(ctxx.S_FUNC(2) or \"\")..\"(): \"..msg..\"\\n\\n\"\n"
"\n"
"--	msg = ctxx.S_FILE(2)..\" \"..ctxx.S_LINE(2)..\": \"..ctxx.S_FUNC(2)..\"(): \"..msg..\"\\n\\n\"\n"
"--	msg = string.format(\"%s %s: %s(): %s\\n\\n\", ctxx.S_FILE(2)\n"
"--	, ctxx.S_LINE(2), ctxx.S_FUNC(2), msg)\n"
"--	msg = ctxx.sprintf(\"%s %s: %s(): %s\\n\", ctxx.S_FILE(2)\n"
"--	, ctxx.S_LINE(2), ctxx.S_FUNC(2), msg)\n"
"	if fh then \n"
"--print(\"dbgfunc_2\")\n"
"		fh.write(fh, msg)\n"
"--	ctxx.fprintf(fh,\"%s\\n\",msg)\n"
"--print(\"dbgfunc_3\")\n"
"--		fh.flush(fh)\n"
"	 end \n"
"	return msg\n"
" end\n"
"function ctxx.dbg(...)  return ctxx.fdbg(io.stderr, ...)  end\n"
"\n"
"--[=[*\n"
"@_name	clit, sprintf, fprintf, printf\n"
"@auther momi-g\n"
"@brief	C style print format.\n"
"@_synopsys\n"
"	str clit(str)\n"
"	str sprintf(str, ...) / printf(str, ...)\n"
"	str fprintf(nil/fh, str, ...)\n"
"@_eg\n"
"	str = clit( [[\\041]]..\"\\041\" )	--> \"!)\", C\\041==33, lua\\041==41\n"
"	str = clit( [[he\\llo\\012world%d\\n]] )	--> he\\llo(\\n)world%d(\\n)\n"
"	str = sprintf([[hello\\012world%d\\n]], 33 )	--> \"hello(\\n)world33(\\n)\"\n"
"@param clit(str) '\\' works as posix escfmt. \\ooo, \\xFF, \\ + abntvrf?\\'\",\\uU\n"
"@param printf(str) str is passed to clit() then passed to string.format().  \n"
"@param nil/fh	io.stdout, io.stderr etc. no out if nil is set. \n"
"@param str	if arg 'str' is nil, conv to \"\", blank string.\n"
"@return 1 str. rtn nil,emsg if err.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.1.3, 2021-06-27\n"
"]=]\n"
"\n"
"local\n"
"function sprintfsub(fmt, ...) \n"
"	local emsg\n"
"	fmt, emsg=ctxx.clit(fmt)\n"
"	if fmt==nil then return nil, emsg end \n"
"	return string.format(fmt, ...)\n"
" end\n"
"function ctxx.sprintf(fmt, ...) \n"
"	return sprintfsub(fmt, ...)\n"
" end\n"
"function ctxx.fprintf(fh, fmt, ...) \n"
"	local emsg\n"
"	fmt, emsg=sprintfsub(fmt, ...)\n"
"	if fh==nil then  return fmt  end \n"
"	if fmt==nil then return nil, emsg end \n"
"	fh.write(fh, fmt)\n"
"	return fmt\n"
" end\n"
"function ctxx.printf(fmt, ...) \n"
"	local buf, emsg = ctxx.fprintf(io.stdout, fmt, ...)\n"
"	if buf==nil then return nil, emsg end \n"
"	return buf\n"
" end\n"
"\n"
"-- \\ooo\\a系以外のescは放置 >> 修正 [[ \\123\\x00 ]] 系で完全対応させる\n"
"function ctxx.clit(fmt) \n"
"	if fmt==nil then fmt=\"\" end \n"
"	if type(fmt)~=\"string\" then \n"
"		local emsg = ctxx.fperr(nil, \"1st arg is not nil/str: \"..type(fmt), 2)\n"
"		return nil,emsg\n"
"	 end \n"
"	--\\000 octtype\n"
"	local pos=1\n"
"	local sres = \"\"\n"
"\n"
"	while pos<=#fmt do do \n"
"		local raw  = string.match(fmt, \"^[^\\\\]+\", pos)\n"
"		local elit = string.match(fmt, \"^\\\\[abfnrtv\\\\?\\\"\\']\", pos)\n"
"		local eoct = string.match(fmt, \"^\\\\[0-3]?[0-7]?[0-7]\", pos)\n"
"		local hh = \"[0-9a-fA-F]\"\n"
"		local ehex = string.match(fmt, \"^\\\\x\"..hh..hh, pos)\n"
"		local euni = string.match(fmt, \"^\\\\u\"..hh..hh..hh..hh, pos)\n"
"		local eUNI = string.match(fmt, \"^\\\\U\"..hh..hh..hh..hh..hh..hh..hh..hh , pos)\n"
"		local s = raw or elit or eoct or ehex or euni or eUNI\n"
"		if raw then  sres=sres..s; pos=pos+string.len(s)  \n"
"		elseif elit then \n"
"			pos=pos+string.len(s)\n"
"			local cbuf = string.sub(s, 2, 2)\n"
"			if cbuf==\"\\\\\" then  sres=sres..\"\\\\\" \n"
"			elseif cbuf==\"a\" then sres=sres..\"\\a\" \n"
"			elseif cbuf==\"b\" then sres=sres..\"\\b\" \n"
"			elseif cbuf==\"f\" then sres=sres..\"\\f\" \n"
"			elseif cbuf==\"n\" then sres=sres..\"\\n\" \n"
"			elseif cbuf==\"r\" then sres=sres..\"\\r\" \n"
"			elseif cbuf==\"t\" then sres=sres..\"\\t\" \n"
"			elseif cbuf==\"v\" then sres=sres..\"\\v\" end \n"
"		 \n"
"		elseif eoct then \n"
"			pos=pos+string.len(s)\n"
"			local buf = string.sub(s, 2)\n"
"			local num = tonumber(buf, 8)\n"
"			local cbuf = string.char(num)\n"
"			sres=sres..cbuf\n"
"		 \n"
"		elseif ehex then \n"
"			pos=pos+string.len(s)\n"
"			local buf = string.sub(s, 3)\n"
"			local num=tonumber(buf, 16)\n"
"			local cbuf = string.char(num)\n"
"			sres=sres..cbuf\n"
"		 \n"
"		elseif euni or eUNI then \n"
"			pos=pos+string.len(s)\n"
"			local buf = ctxx.strconv(s, \"uc:b\")\n"
"			sres=sres..buf\n"
"		 \n"
"		elseif s==nil then \n"
"			--if s==nil, err\n"
"			local emsg = ctxx.fperr(nil,\"bad escchar: \"..string.sub(fmt,pos,pos+20),2)\n"
"			return nil, emsg\n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return sres\n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	matchlit, matchmlit, matchcmt, matchmcmt\n"
"@auther momi-g\n"
"@brief	grep 1st lit (\"\",'',[?[..]?]), cmt(--(\\n), --[?[..]?]) str. skip endesc \\\" \\'. \n"
"@_synopsys\n"
"	str,num,num matchlit(str/nil, num/nil)	...mlit,cmt,mcmt style is same as lit\n"
"@_eg\n"
"	str, s, e = matchlit( [[12\"4\\041\\\"\\2\" zzz \"yy\" ]] )	--> 4\\041\\\"\\2, 3, 13\n"
"	str, s, e = matchlit( [[12'4\\041\\'\\2' zzz \"yy\" ]], 4 )	--> \\2, 10, 13\n"
"	str, s, e = matchlit( \"12345\" )	--> nil, nil, nil\n"
"	str, s, e = matchlit( \"123'5\" )	--> nil, 4, nil\n"
"	str, s, e = matchmlit( \"[[345]]\" )	--> 345, 1, 7\n"
"	str, s, e = matchcmt(\"--[[567\\n]]\")	--> [[567, 1, 8\n"
"	str, s, e = matchmcmt(\"12'4--[==[ab'c]==]\")	--> ab'c, 5, 18\n"
"@param str base string. conv to \"\" if nil.\n"
"@param num/nil search start position. set 1 if nil.\n"
"@return 3rtn. 1:match str. 2/3:charpos with open/close. 3rd is nil if close not found. \n"
"@_details lit() / mlit() / cmt() / mcmt() dont care about each other.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.1.3, y2020m04d08\n"
"]=]\n"
"\n"
"function ctxx.matchlit(str, pos) \n"
"	if pos==nil then pos=1 end \n"
"	if type(str)~=\"string\" then  ctxx.errstop(\"1st arg must be 'string': \"..type(str),2 )  end \n"
"	if type(pos)~=\"number\" then  ctxx.errstop(\"2nd arg must be 'nil/num': \"..type(pos),2 )  end \n"
"\n"
"	local rtn=nil\n"
"	local cc=nil\n"
"	local s,ss,e,ee, _ = nil,nil,nil,nil\n"
"	while pos <= #str do do \n"
"		if cc==nil then \n"
"			s = string.find(str, \"['\\\"]\", pos)\n"
"			if s==nil then  do break end  end \n"
"			cc = string.sub(str, s,s)\n"
"			pos=s+1\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if cc~=nil then \n"
"			_, e = string.find(str, cc, pos, true)\n"
"			if e==nil then  do break end  end \n"
"			_, ee = string.find(str, '\\\\\\\\', pos, true)\n"
"			if ee~=nil  and  ee<e then pos=ee+1; goto lbl_NEXT end \n"
"			_, ee = string.find(str, '\\\\'..cc, pos, true)\n"
"			if ee==e then  pos=e+1;goto lbl_NEXT  end \n"
"			rtn = string.sub(str, s+1, e-1)\n"
"			 do break end \n"
"		 end \n"
"		::lbl_NEXT::\n"
"	 end::_luka_LOOPNEXT::end \n"
"	return rtn, s, e\n"
" end\n"
"\n"
"function ctxx.matchcmt(str, pos) \n"
"	if pos==nil then pos=1 end \n"
"	if type(str)~=\"string\" then  ctxx.errstop(\"1st arg must be 'string': \"..type(str),2 )  end \n"
"	if type(pos)~=\"number\" then  ctxx.errstop(\"2nd arg must be 'nil/num': \"..type(pos),2 )  end \n"
"	local rtn=nil\n"
"	local s, e = string.find(str, \"[-][-]\", pos)\n"
"	local ss, ee = string.find(str, \"[-][-][%[]=*[%[]\", pos)\n"
"\n"
"	if s~=nil  and  ss==nil  or  s~=nil  and  s<ss then \n"
"		ss, ee = string.find(str, \"\\n\", s)\n"
"		if ee~=nil then rtn = string.sub(str, s, ee) end \n"
"	 end \n"
"	return rtn, s, ee\n"
" end\n"
"\n"
"--multi系は[[--]]が同じなのでpre--で共通化\n"
"local\n"
"function match_sub(str, pos, pre) \n"
"	if pos==nil then pos=1 end \n"
"	if type(str)~=\"string\" then  ctxx.errstop(\"1st arg must be 'string': \"..type(str), 2 )  end \n"
"	if type(pos)~=\"number\" then  ctxx.errstop(\"2nd arg must be 'nil/num': \"..type(pos), 2 )  end \n"
"	local rtn, spos, epos=nil\n"
"	local emsg=nil\n"
"	local buf=nil\n"
"	local s,e,ss,ee=nil,nil,nil,nil\n"
"	\n"
"	s, e = string.find(str, pre..\"[%[]=*[%[]\", pos)\n"
"	if s==nil then goto lbl_RTN end \n"
"	spos=s\n"
"\n"
"	buf = string.match(str, \"[%[]=*[%[]\", pos)\n"
"	buf = string.gsub(buf, \"[%[]\", \"]\")	-- [==[ --> ]==]\n"
"	ss, ee = string.find(str, buf, e+1,true)\n"
"	if ss==nil then  goto lbl_RTN  end \n"
"	epos=ee\n"
"	rtn = string.sub(str, e+1, ss-1)\n"
"	::lbl_RTN::\n"
"	return rtn, spos, epos	--後ろ二つはrawのまま。その方が対応範囲が広い\n"
" end\n"
"function ctxx.matchmlit(str, pos)  return match_sub(str, pos, \"\")  end\n"
"function ctxx.matchmcmt(str, pos)  return match_sub(str, pos, \"[-][-]\")  end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	strconv\n"
"@auther momi-g\n"
"@brief	str converter, utf8byte/utf8/unicode, supports sequential input.\n"
"@_synopsys	str/nil,str/nil,str/nil strconv(str1, str2, num/nil)\n"
"@_eg\n"
"	str,lft,emsg = strconv(\"hw\",\"b:u8\")	--> str=\\150 \\167, lft=\"\", emsg=nil\n"
"	str,lft,emsg = strconv(\"hw\", \"b:uc\") --> str=\\u{0068}\\u{0077} (4/8lowerchar)\n"
"	str = strconv([[\\u{068}\\u{77}]],\"uc:b\") --> str=\"hw\" (uni-in: n-degits)\n"
"	str = strconv([[\\150\\167]], \"u8:b\") --> str=\"hw\" (u8-in: only 3-degits)\n"
"	str=strconv(\"longmsg\",\"b:u8\",60) --> ..(\\n).. output maxlen is 60 in oneline.\n"
"	\n"
"	--\"あい\" >> \\201\\204 + \\343\\201(valid)>> \\201\\204\\3 + 43\\201(illegal split)\n"
"	str,lft,emsg=strconv([[\\201\\204\\3]],\"u8:b\") --> \"あ\", [[\\3]], \"invalid seq\"\n"
"	buf = lft .. [[43\\201]]\n"
"	str,lft,emsg = strconv(buf, \"u8:b\")	--> \"い\", \"\", nil\n"
"	\n"
"	str,lft,emsg = strconv([[\\777]], \"u8:b\") --> nil, nil, \"out of utf8rule\"\n"
"	\n"
"@param str1 srcstr. b:lua_str, u8:\\ooo (3oct) uc:\\u{xx} (lower/UPPER n-hex char)\n"
"@param str2 b(yte),u8,uc combination. \"src:out\".\n"
"@param num max strlen of output. works only at 'uc/u8' out. no split if nil(dfl).\n"
"@return 3rtn. 1:converted str 2:unprocessed str 3:emsg. see detail.\n"
"@details\n"
" rtn case is as follows\n"
" - completely suc: r1,r2,r3 = str,str,NIL\n"
" - partially suc : r1,r2,r3 = str,str,str\n"
" - fail. invalid input: r1,r2,r3 = NIL,NIL,str\n"
" others \n"
" - u8src needs 3-degits. 1-2 degits causes err. ucsrc allows n-hex degits.\n"
" - u8/uc src ignores not numchar. (\"150%*167\",\"u8:b\")(\"6A 0x77\",\"uc:u8\") is safe.\n"
" - u8out splits sequence with \" \" for each char. maxlen doesnt split sequence.\n"
" - uc-in allows lower/upper char. uc-out outputs lower char with 4/8 hex degits.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.4, 2020-09-05\n"
"]=]\n"
"\n"
"function ctxx.strconv(str, ini, mlen) \n"
"	local emsg=nil\n"
"	local rstr=\"\"\n"
"	local nstr=\"\"	--残り連結推奨文字列\n"
"	local src=\"\"\n"
"	local dst=\"\"\n"
"	local buf=\"\"\n"
"	if mlen~=nil  and  (type(mlen)~=\"number\"  or  mlen<16) then \n"
"		ctxx.errstop(\"3rd arg must be nil / 16=<num: \"..ctxx.vinfo(mlen) )\n"
"	 end  \n"
"	if type(str) ~=\"string\"  or  type(ini) ~=\"string\" then \n"
"		ctxx.errstop(\"invalid args type. 1st,2nd needs str: \"..ctxx.vinfo(str,ini) )\n"
"	 end \n"
"	--matchは全てstring返し。nilはnomatchだけ。\n"
"	src, dst = string.match(ini, \"([a-z0-9]+):([a-z0-9]+)\")\n"
"	if src==nil then  ctxx.errstop(\"invalid convert command: \"..ctxx.vinfo(ini) )  end \n"
"\n"
"	buf = {uc=1, u8=1, b=1}\n"
"	if buf[src]==nil  or  buf[dst]==nil then \n"
"		ctxx.errstop(\"invalid convert setting (b:uc etc): \"..ctxx.vinfo(ini) )\n"
"	 end \n"
"	if src==dst then  ctxx.errstop(\" srctype == outyupe is not support: \"..ctxx.vinfo(ini) )  end \n"
"	\n"
"	--while系の共通変数。メモってnrtnで再利用前提なあたり\n"
"	local uc,len,pos,ppos = 0,0,1,1\n"
"	local s,e,ns,n = 0,0,0,0\n"
"	if src==\"uc\" then \n"
"		local fmt='%c'	--byte out\n"
"		if dst == 'u8' then  fmt='\\\\%.3o'  end \n"
"		while 1 do do \n"
"			s,e = string.find(str, \"[0-9a-fA-F]+\", pos)\n"
"			if s~=nil then  ns=string.sub(str, s,e)  end \n"
"			if s==nil then  pos=#str;  do break end   end \n"
"			pos=e+1\n"
"			ppos=e+1\n"
"			n=tonumber(ns, 16)\n"
"			if n>0x10FFFF then \n"
"				emsg=\"erange unicode: \"..string.format(\"%.4x\", n)\n"
"				rstr=nil;nstr=nil; goto lbl_RTN\n"
"			 end \n"
"			len, buf=0,0\n"
"			if  n <= 0x7F then len=0; buf=0 \n"
"			elseif  n <= 0x7FF then len=1; buf=6*(2^5) \n"
"			elseif  n <= 0xFFFF then len=2; buf=14*(2^4) \n"
"			elseif  n <= 0x10FFFF then len=3; buf=30*(2^3) end \n"
"\n"
"			buf=buf + math.modf(n/(2^(6*len)) )\n"
"			rstr=rstr .. string.format(fmt, buf)\n"
"			n=math.fmod(n, 2^(6*len) ) \n"
"\n"
"			while len~=0 do do \n"
"				len=len-1\n"
"				buf=math.modf(n/(2^(6*len)) ) + 2^7	-- 10xxxxxx\n"
"				rstr=rstr .. string.format(fmt, buf)\n"
"				n=math.fmod(n, 2^(6*len) ) \n"
"			 end::_luka_LOOPNEXT::end \n"
"			if dst == 'u8' then  rstr=rstr..\" \"  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if src==\"u8\" then \n"
"		while 1 do do \n"
"			s,e = string.find( str, \"[0-9][0-9]?[0-9]?\", pos )\n"
"			if s~=nil then  ns=string.sub(str, s,e)  end \n"
"			if s==nil then  pos=#str;  do break end   end \n"
"			pos=e+1\n"
"			--尻尾はちぎれている可能性があるので、それ以外の not 3-degits\n"
"			if #ns ~= 3  and  e~= #str then \n"
"				emsg=\"u8 input allows only octal 3-digits: \"..string.sub( str, s,s+10)\n"
"				rstr=nil; nstr=nil;  do break end \n"
"			 \n"
"			elseif #ns ~= 3 then \n"
"				emsg=\"u8 input allows only octal 3-digits: \"..string.sub( str, s,s+10)\n"
"				 do break end \n"
"			 end \n"
"			\n"
"			local n=tonumber(ns, 8)\n"
"			if len==0 then \n"
"				if math.modf(n/(2^7) ) == 0 then  len=1 ; uc=math.fmod(n, 2^7)  \n"
"				elseif math.modf(n/(2^5) ) == 6 then  len=2 ; uc=math.fmod(n, 2^5)  \n"
"				elseif math.modf(n/(2^4) ) == 14 then  len=3; uc=math.fmod(n, 2^4)  \n"
"				elseif math.modf(n/(2^3) ) == 30 then  len=4; uc=math.fmod(n, 2^4)  \n"
"				elseif 1==1 then \n"
"					emsg=\"invalid utf8 1st byte\"..string.sub( str, s,s+10)\n"
"					rstr=nil; nstr=nil;  do break end \n"
"				 end \n"
"			 \n"
"			elseif len~=0  and  math.modf(n/(2^6) )==2  then  uc=uc*(2^6) + math.fmod(n, 2^6)  			\n"
"			elseif 1 then \n"
"				emsg=\"invalid utf8 seq\"..string.sub( str, s,s+10)\n"
"				rstr=nil; nstr=nil;  do break end \n"
"			 end \n"
"			len=len-1\n"
"			\n"
"			--出力による切り替え\n"
"			if dst==\"b\" then  rstr = rstr..string.format('%c', n)  \n"
"			elseif dst==\"uc\"  and  len==0 then \n"
"			--	local buf=string.format('\\\\u{%.4X}', uc)\n"
"				local buf=string.format('\\\\u{%.4x}', uc)\n"
"			--	if(8<#buf){ buf=string.format('\\\\U{%.8X}', uc) }\n"
"				if 8<#buf then  buf=string.format('\\\\u{%.8x}', uc)  end \n"
"				rstr=rstr..buf\n"
"				uc=0\n"
"			 end \n"
"			if len==0 then ppos=pos end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		if len~=0 then  emsg=\"detect invalid utf8 EOS.\"  end \n"
"		goto lbl_RTN\n"
"	 end \n"
"	if src==\"b\" then \n"
"		if dst==\"u8\" then \n"
"			for i=1, #str do do \n"
"				n = string.byte(str, i)\n"
"				if math.modf(n/(2^6) ) ~= 2  then  rstr=rstr..\" \"  end 	\n"
"				rstr=rstr..string.format('\\\\%.3o', n)\n"
"			 end::_luka_LOOPNEXT::end \n"
"			rstr = string.sub (rstr, 2 )\n"
"			ppos=#str+1\n"
"			goto lbl_RTN\n"
"		 end \n"
"		if dst==\"uc\" then \n"
"			len=0\n"
"			for i=1, #str do do \n"
"				n = string.byte(str, i)\n"
"				if len==0 then \n"
"					if math.modf(n/(2^7) ) == 0 then  len=1; buf=0 ; uc=math.fmod(n, 2^7)  \n"
"					elseif math.modf(n/(2^5) ) == 6 then  len=2 ; buf=0x80;uc=math.fmod(n, 2^5)  \n"
"					elseif math.modf(n/(2^4) ) == 14 then  len=3; buf=0x800;uc=math.fmod(n, 2^4)  \n"
"					elseif math.modf(n/(2^3) ) == 30 then  len=4; buf=0x10000;uc=math.fmod(n, 2^4)  \n"
"					elseif 1==1 then ctxx.errstop(\"unreachable code: uc decode failed\"..i, 1)  end \n"
"				 \n"
"				elseif 1 then  uc=uc*(2^6) + math.fmod(n, 2^6)  end \n"
"				len=len-1\n"
"				if len==0 then \n"
"				--	ns=string.format('\\\\u{%.4X}', uc)\n"
"					ns=string.format('\\\\u{%.4x}', uc)\n"
"				--	if(8<#ns){ ns=string.format('\\\\U{%.8X}', uc) }\n"
"					if 8<#ns then  ns=string.format('\\\\u{%.8x}', uc)  end \n"
"					rstr=rstr..ns\n"
"					ppos=i+1\n"
"					if uc<buf then \n"
"						--add min unicode ck\n"
"						emsg=\"detect risky utf8byte seq: pos \"..i\n"
"						rstr=nil; nstr=nil; goto lbl_RTN\n"
"					 end \n"
"				 end \n"
"			 end::_luka_LOOPNEXT::end \n"
"			goto lbl_RTN\n"
"		 end \n"
"	 end \n"
"	::lbl_RTN::\n"
"	if rstr~=nil  and  mlen~=nil  and  dst~=\"b\" then \n"
"		local ptn=\"\"\n"
"		local buf=\"\"\n"
"		local offset=1\n"
"		--頭の位置をとらえる\n"
"		if dst==\"u8\" then  ptn=\" [^ ]*$\"; offset = offset+1  end 	--頭に\" \" が乗っかる\n"
"		if dst==\"uc\" then  ptn=\"\\\\[^\\\\]*$\" end \n"
"		while mlen<#rstr do do \n"
"			local lbuf = string.sub(rstr, 1, mlen+1)\n"
"			local s, e = string.find(lbuf, ptn)\n"
"			if s<mlen+1 then  lbuf = string.sub(rstr, 1, s-1)  \n"
"			elseif 1 then  lbuf = string.sub(rstr, 1, mlen)  end \n"
"			buf=buf..\"\\n\"..lbuf\n"
"			rstr=string.sub(rstr, #lbuf+offset)\n"
"		 end::_luka_LOOPNEXT::end \n"
"		if #rstr~=0 then  rstr=buf..\"\\n\"..rstr  end \n"
"		rstr=string.gsub(rstr, \"^[\\n]\", \"\", 1)\n"
"	 end \n"
"	if rstr~=nil then  nstr=string.sub(str, ppos)  end \n"
"	return rstr, nstr, emsg\n"
" end\n"
"ctxx.u8conv = ctxx.strconv\n"
"\n"
"\n"
"--[=[*\n"
"@_name	stsort\n"
"@auther momi-g\n"
"@brief	table.sort() wrapper, Stable Table sort. \n"
"@_synopsys	nortn stsort(tbl, func)\n"
"@_eg\n"
"	tbl={ 2, 1.9, 1.1, 3}\n"
"	function comp(a, b)\n"
"		return ( math.modf(a) < math.modf(b) )\n"
"	end		--(1.9, 1,1):1<1 false,	(1.1, 1,9):1<1 false\n"
"	\n"
"	stsort(tbl, comp)		--> tbl={1.9, 1.1, 2, 3}	...save order\n"
"	\n"
"@param tbl	seqtbl\n"
"@param func	compare function \n"
"@return nothing\n"
"@details	usage is completely the same as table.sort()\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.0, y2020m04d07\n"
"]=]\n"
"function ctxx.stsort(tbl, comp) \n"
"	local alttbl={}\n"
"	for k,v in ipairs(tbl)  do do  alttbl[k]={k, v}  end::_luka_LOOPNEXT::end \n"
"	local function altcomp(bf, af) \n"
"		--bool変換。nilとか123とかありえる\n"
"		local ck1 = 1 and comp(bf[2], af[2])\n"
"		local ck2 = 1 and comp(af[2], bf[2])\n"
"		if ck1~=ck2 then  return ck1  end \n"
"		return ( bf[1]<af[1] )\n"
"	 end\n"
"	table.sort(alttbl, altcomp)\n"
"	for k,v in ipairs(alttbl)  do do  tbl[k]=v[2]  end::_luka_LOOPNEXT::end \n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	ttrm\n"
"@auther momi-g\n"
"@brief	compare tbl keys and remove overlap member.\n"
"@_synopsys	tbl, num ttrm(tbl1, tbl2)\n"
"@_eg\n"
"	res, cnt = ttrm( {a=1,b=2,10,20}, {a=99,55} )	--> res={b=2,20}, cnt=2\n"
"@param tbl1 main tbl.\n"
"@param tbl2 sub tbl.\n"
"@return  2 rtn. 1:maintbl data which has removed subtbl keys.	2:rtntbl size\n"
"@details roughly equals to: cat maintbl | grep -v subtbl_keys\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m03d08\n"
"]=]\n"
"\n"
"function ctxx.ttrm(a,b) \n"
"	if a==nil then a={} end \n"
"	if b==nil then b={} end \n"
"	local rtn= {}\n"
"	local cnt=0\n"
"\n"
"	if type(a)~=\"table\"  or  type(a)~=\"table\" then \n"
"		local msg=ctxx.ferrdisp(io.stderr, \"CODE_ERR: args is not tbl: \"..a..\"/\"..b,1)\n"
"		rtn=nil\n"
"		cnt=msg\n"
"		goto lbl_RTN\n"
"	 end \n"
"	for k,v in pairs(a) do do \n"
"		if b[k]==nil then  rtn[k]=v; cnt=cnt+1  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	::lbl_RTN::\n"
"	return rtn, cnt\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	tsrm\n"
"@auther momi-g\n"
"@brief	remove keys from tbl using sequence data.\n"
"@_synopsys	tbl, num tsrm(tbl1, tbl2)\n"
"@_eg\n"
"	res, cnt = tsrm( {a=11,b=22,10,30}, {\"b\", 2} )	--> res={a=11,10}, cnt=2\n"
"@param tbl1 maintbl.\n"
"@param tbl2 subtbl. demands sequence with num/str data.\n"
"@return 2 rtn. 1:maintbl data which has removed keys by subtbl.	2:rtntbl size\n"
"@details subtbl{} is keyname *sequence* you want del.\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m03d08\n"
"]=]\n"
"\n"
"function ctxx.tsrm(tbl, keys) \n"
"	local rtn= {}\n"
"	local cnt= ctxx.tsize(tbl)\n"
"	if tbl==nil then tbl={}  end \n"
"	if keys==nil then leys={}  end \n"
"	if type(tbl)~=\"table\"  or  type(keys)~=\"table\" then \n"
"		local msg=ctxx.ferrdisp(io.stderr, \"CODE_ERR: args is not tbl: \"..a..\"/\"..b,1)\n"
"		rtn=nil\n"
"		cnt=msg\n"
"		goto lbl_RTN\n"
"	 end \n"
"	for k,v in ipairs(keys) do do \n"
"		if type(v)~=\"string\"  and  type(v)~=\"number\"  then \n"
"			local msg=ctxx.sprintf(\n"
"			\"CODE_ERR: 2nd arg, keylist is not str/num: keys[%s]/%s%s\",\n"
"			k,type(v),\":\"..v)\n"
"			local msg = ctxx.ferrdisp(io.stderr, msg, 1)\n"
"			rtn=nil\n"
"			cnt=msg\n"
"			goto lbl_RTN\n"
"		 end \n"
"		if tbl[v] ~= nil then  tbl[v]=nil; cnt=cnt-1  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	rtn=tbl\n"
"	::lbl_RTN::\n"
"	return rtn, cnt\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	ttgrep\n"
"@auther momi-g\n"
"@brief	compare tbls and grep match keys data\n"
"@_synopsys	tbl, num ttgrep(tbl1, tbl2)\n"
"@_eg\n"
"	res, cnt = tsrm( {a=11,b=22,10,30}, {a=100, 2} )	--> res={a=11,30}, cnt=2\n"
"@param tbl1 maintbl.\n"
"@param tbl2 subtbl.\n"
"@return 2 rtn. 1:parts of maintbl which key is detect in subtbl too. 2:rtntbl size\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m03d08\n"
"]=]\n"
"function ctxx.ttgrep(a,b) \n"
"	if a==nil then a={} end \n"
"	if b==nil then b={} end \n"
"	local rtn= {}\n"
"	local cnt=0\n"
"\n"
"	if type(a)~=\"table\"  or  type(a)~=\"table\" then \n"
"		local msg=ctxx.ferrdisp(io.stderr, \"CODE_ERR: args is not tbl: \"..a..\"/\"..b,1)\n"
"		rtn=nil\n"
"		cnt=msg\n"
"		goto lbl_RTN\n"
"	 end \n"
"	for k,v in pairs(a) do do \n"
"		if b[k]~=nil then  rtn[k]=v; cnt=cnt+1  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	::lbl_RTN::\n"
"	return rtn, cnt\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	tsgrep\n"
"@auther momi-g\n"
"@brief	select tbl data using keyname sequence\n"
"@_synopsys	tbl, num tsgrep(tbl1, tbl2)\n"
"@_eg\n"
"	res, cnt = tsrm( {a=11,b=22,30,10}, {\"b\",1,3} )	--> res={b=22,30}, cnt=2\n"
"@param tbl1 maintbl.\n"
"@param tbl2 subtbl.\n"
"@return 2 rtn. 1:parts of maintbl which is select by subtbl(sequence). 2:rtntbl size\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m03d08\n"
"]=]\n"
"function ctxx.tsgrep(tbl, keys) \n"
"	local rtn= {}\n"
"	local cnt= 0\n"
"	if tbl==nil then tbl={} end \n"
"	if keys==nil then leys={} end \n"
"	if type(tbl)~=\"table\"  or  type(keys)~=\"table\" then \n"
"		local msg=ctxx.ferrdisp(io.stderr, \"CODE_ERR: args is not tbl: \"..a..\"/\"..b,1)\n"
"		rtn=nil\n"
"		cnt=msg\n"
"		goto lbl_RTN\n"
"	 end \n"
"	for k,v in ipairs(keys) do do \n"
"		if type(v)~=\"string\"  and  type(v)~=\"number\"  then \n"
"			local msg=ctxx.sprintf(\n"
"			\"CODE_ERR: 2nd arg, keylist is not str/num: keys[%s]/%s%s\",\n"
"			k,type(v),\":\"..v)\n"
"			local msg = ctxx.ferrdisp(io.stderr, msg, 1)\n"
"			rtn=nil\n"
"			cnt=msg\n"
"			goto lbl_RTN\n"
"		 end \n"
"		if tbl[v] ~= nil then  rtn[v]=tbl[v]; cnt=cnt+1  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	::lbl_RTN::\n"
"	return rtn, cnt\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	tmerge\n"
"@auther momi-g\n"
"@brief	concat tbl, overlapped keydata is ignored.\n"
"@_synopsys	tbl, num tmerge(tbl1, ...)\n"
"@_eg\n"
"	res, cnt = tmerge( {a=1,30}, {a=9,c=7,1,3} ) --> res={a=1,c=7,30,3}, cnt=4\n"
"@param tbl1 basetbl.\n"
"@param va_args addtbls.\n"
"@return 2 rtn. 1:merged tbl	.	2:tbl size\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.0, y2020m03d08\n"
"]=]\n"
"function ctxx.tmerge(...) \n"
"	--#は渡された...の引数の個数マーク\n"
"	local ac=select(\"#\", ...)\n"
"	local av = {...}\n"
"	local rtn={}\n"
"	local emsg=nil\n"
"	for i=1, ac do do \n"
"		if type(av[i]) == \"table\" then \n"
"			for k,v in pairs(av[i])  do do \n"
"				rtn[k] = rtn[k]  or  v\n"
"			 end::_luka_LOOPNEXT::end \n"
"		 \n"
"		elseif av[i]~=nil then \n"
"			emsg=ctxx.sprintf(\"arg is not tbl/nil: av[%d]=%s\", i, tostring(av[i]) )\n"
"			return nil, ctxx.fperr(nil, emsg, 2)\n"
"		 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	--ig nil\n"
"	::lbl_RTN::\n"
"	return rtn, ctxx.tsize(rtn)\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	tmergeo\n"
"@auther momi-g\n"
"@brief	concat tbl, overlap keydata is overwrite.\n"
"@_synopsys	tbl, num tmergeo(tbl1, ...)\n"
"@_eg\n"
"	res, cnt = tmergeo( {a=1,b=2}, {a=9,c=7,10} ) --> res={a=9,b=2,c=7,10}, cnt=4\n"
"@param tbl1 basetbl.\n"
"@param va_args addtbls.\n"
"@return 2 rtn. 1:merged tbl	.	2:tbl size\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.0.1, y2020m05d10\n"
"]=]\n"
"function ctxx.tmergeo(...) \n"
"	local ac=select(\"#\", ...)\n"
"	local av = {...}\n"
"	local rtn={}\n"
"	local emsg=nil\n"
"	for i=1, ac do do \n"
"		local pos=ac+1-i\n"
"		if type(av[pos]) == \"table\" then \n"
"			for k,v in pairs(av[pos])  do do \n"
"				rtn[k] = rtn[k]  or  v\n"
"			 end::_luka_LOOPNEXT::end \n"
"		 \n"
"		elseif av[pos]~=nil then \n"
"			emsg=ctxx.sprintf(\"arg is not tbl/nil: av[%d]=%s\", pos, tostring(av[pos]) )\n"
"			return nil, ctxx.fperr(nil, emsg, 2)\n"
"		 end \n"
"		--ig nil\n"
"	 end::_luka_LOOPNEXT::end \n"
"	::lbl_RTN::\n"
"	return rtn, ctxx.tsize(rtn)\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	perr, fperr, errstop\n"
"@auther momi-g\n"
"@brief	make or print short errmsg.\n"
"@_synopsys\n"
"str perr(str/nil, num/nil)\n"
"str fperr(fh/nil, str/nil, num/nil)\n"
"nortn errstop(str/nil, num/nil)\n"
"@_eg\n"
"	emsg = fperr(io.stdout, \"abc is invalid\" ) --> emsg=\"errinfo+msg\" + output\n"
"	emsg = perr( \"aa is invalid\", 1) --> equals to ferrinfo + fh=io.stderr\n"
"	errstop(\"aa is invalid\", 2) --> error() wrapper. add func() name.\n"
"@param str errmsg. conv to \"\" if nil.\n"
"@param num stack lv as error(). 1:nowpos, 2:callsrc, 3-:more. set 1 if nil.\n"
"@param fh output target. noout if nil.\n"
"@return 0/1 rtn. 1:errmsg. perr(), errstop() outputs errmsg + \"\\n\".\n"
"@_conforming lua5.1+ , luajit2.0+\n"
"@version 1.1.1, y2020m05d01\n"
"]=]\n"
"\n"
"function ctxx.errstop(msg, n) \n"
"	if n==nil then n=1 end \n"
"	local fname=ctxx.S_FUNC(2)\n"
"	error(fname..\"(): \"..msg, n+1)\n"
" end\n"
"function ctxx.perr(msg, n) \n"
"	return ctxx.fperr(io.stderr, msg, n)\n"
" end\n"
"function ctxx.fperr(fh, msg, n) \n"
"	local rtn=nil\n"
"	local emsg=nil\n"
"	if fh~=nil  and  io.type(fh)==nil then \n"
"		ctxx.errstop(\"1st arg is not file handle\", 2)\n"
"	 end \n"
"	if msg==nil then msg=\"\" end \n"
"	if type(msg)~=\"string\" then \n"
"		ctxx.errstop(\"2nd arg is not str/nil: \"..type(msg), 2)\n"
"	 end \n"
"	if n==nil then n=1 end \n"
"	n=n+1\n"
"	local dobj=debug.getinfo(n, \"nlSf\");--(1)test()info. (2)test_parent() info\n"
"--	rtn = ctxx.fprintf(nil, \"%s %s: %s(): %s\", tostring(dobj.short_src)\n"
"--			, tostring(dobj.currentline), tostring(dobj.name), msg )\n"
"--	//fix, add \"%s\" \n"
"	rtn = ctxx.fprintf(nil, \"ERR %s(): %s\", tostring(dobj.name), msg )\n"
"	ctxx.fprintf(fh, \"%s\", rtn..\"\\n\")\n"
"	return rtn\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	laptime, flaptime\n"
"@auther momi-g\n"
"@brief	disp pg working time, os.clock() wrapper.\n"
"@_synopsys\n"
"str laptime(num/str/nil)\n"
"str flaptime(fh, num/str/nil)\n"
"@_eg\n"
"	res = laptime(0)	--> if num 0, timer reset + start. res=0\n"
"	msg = laptime() 	--> get ival time. disp to stderr. msg=\"sys 100 ms\" etc.\n"
"	msg = laptime(\"hw\") --> msg=\"sys 100 ms: hw\"\n"
"	msg = flaptime(io.stdout, \"hw\") --> disp to stdout.\n"
"@param num	if num==0, reset timer and start. if not 0, disp/get used time.\n"
"@param fh	file handle to disp info. no msg disp if nil set.\n"
"@return 1 rtn. 1: passed time msg. units of time are \"s/ms\" or others.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.5, 2021-03-03\n"
"]=]\n"
"\n"
"local laptimebuff=0\n"
"function ctxx.laptime(key)  return ctxx.flaptime(io.stderr, key)  end\n"
"function ctxx.flaptime(fh, key) \n"
"	local res=\"\"\n"
"	if key==nil then key=\"-\" end \n"
"	if key==0 then  laptimebuff=os.clock()  \n"
"	elseif 1 then \n"
"		local i=1\n"
"		res=os.clock()-laptimebuff\n"
"		local sym={[1]=\"s\", [2]=\"ms\", [3]=\"us\", [4]=\"ns\"}\n"
"		while i<2 do do \n"
"			if res>=1 then  do break end  end \n"
"			i=i+1\n"
"			res=res*1000\n"
"		 end::_luka_LOOPNEXT::end \n"
"		res= ctxx.sprintf(\"sys	%.3f %s\", res, sym[i])\n"
"		res=res..\": \"..tostring(key)..\"\\n\"\n"
"		ctxx.fprintf(fh, \"%s\", res)\n"
"		return res\n"
"	 end \n"
"	return 0\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	cktp\n"
"@auther momi-g\n"
"@brief	check args type if global var '_debug' != nil.\n"
"@_synopsys	suc cktp(str...)\n"
"@_eg\n"
"	function myf(lv, word, ...)\n"
"		rtn, emsg = cktp(\"N,s,n\", \"n,sN,A...\", \"\")\n"
"	end\n"
"	_debug=1\n"
"	myf()	--> suc: rtn is not nil. hit the last setting \"\".\n"
"	myf(8)	--> fail: rtn is nil. no setting hits to \"n\". \n"
"	myf(8,\"a\")	--> suc: args is \"n,s\" and hits \"n,sN,A...\" (vaarg allow noarg)\n"
"	_debug=nil\n"
"	myf(8)	--> suc: rtn is not nil.\n"
"	\n"
"@param str	allow types fmt. \"n,sN,A...\" means 1st:num 2nd:str or Nil 3-:Alltypes\n"
"@return	1 rtn. suc:not nil/false	fail:nil,emsg (no setfmt hits callstyle)\n"
"@details\n"
" types are (N)il,(b)ool,(n)um,(s)tr,(t)bl,(f)unc,(u)data,(T)hread + (A)ll,(i)nt\n"
" \",\" is splitter. \"...\" means vaargs. note that vaargs contains noarg.\n"
" if \"tn...\", noarg or all vaargs must be tbl or num.\n"
" cktp() makes your func slow 500-1000 times. test 1000 call result is below.\n"
" real	29.579 ms	(insert cktp(), _debug=1 )\n"
" real	0.033 ms	(no use cktp(), _debug=nil )\n"
" ...recommend you to use this func for dev, betatest or rarely called function.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.4, y2020m04d09\n"
"]=]\n"
"\n"
"function ctxx.cktp(...) \n"
"	if  _debug==nil  then return 0 end \n"
"	if select(\"#\", ...) == 0 then return 0 end \n"
"	--origargs\n"
"	local argc = debug.getinfo(2).nparams\n"
"	local argv={}\n"
"	local emsg=\"\"\n"
"	for i=1, argc do do \n"
"		local k,v = debug.getlocal(2, i)\n"
"		local cc=ctxx.istypes(v)\n"
"		if type(v)==\"number\" then \n"
"			local _,buf=math.modf(v)\n"
"			if buf==0 then  cc=cc..\"(i)\" end \n"
"		 end \n"
"		argv[#argv+1] = cc\n"
"		emsg=emsg..\",\"..cc\n"
"	 end::_luka_LOOPNEXT::end \n"
"	local i=0\n"
"	while 1 do do \n"
"		i=i+1\n"
"		local k,v = debug.getlocal(2, -i)\n"
"		if k==nil then   do break end   end \n"
"		local cc=ctxx.istypes(v)\n"
"		if type(v)==\"number\" then \n"
"			local _,buf=math.modf(v)\n"
"			if buf==0 then  cc=cc..\"(i)\" end \n"
"		 end \n"
"		argv[#argv+1] = cc\n"
"		emsg=emsg..\",\"..cc\n"
"	 end::_luka_LOOPNEXT::end \n"
"	emsg=\"(\"..string.sub(emsg, 2)..\"): demands\"\n"
"	--allowtype list\n"
"	local tlist={}\n"
"	for k,v in ipairs({...})  do do \n"
"		--emsg用メモ\n"
"		if  type(v)~=\"string\"  then \n"
"			ctxx.errstop(\"invalid args. eg) cktp('s,ft,N') cktp('Nns,Sn','N') etc\", 2)\n"
"		 end \n"
"		local buf=string.gsub(v, \"[^NbnstfuTAi., ]\", \"\")\n"
"		if buf ~= v then \n"
"			ctxx.errstop(\"detect argchar other than 'NbnstfuTAi,. ' : \"..v, 2)\n"
"		 end \n"
"		if #buf==0 then  emsg=emsg..\"/(noarg) \"  \n"
"		elseif 1 then  emsg=emsg..\"/ \"..v  end \n"
"		\n"
"		--tlistはbuf={\"num\", \"str\"} などのhashリスト. 1-でvaargのみ[-1]\n"
"		local tbuf={}\n"
"		local pos=1\n"
"		local apos=1\n"
"		while 1 do do \n"
"			--要求typeの加工\n"
"			--3argなら,が二つでスプリット。\n"
"			local s,e = string.find(v, \"[^,]+\", pos)\n"
"			if s==nil then  do break end  end \n"
"			if tbuf[-1]~=nil then \n"
"				--...の後は,が無いのでここにこないはず\n"
"				ctxx.errstop(\"invalid args. '...' allows only last arg\"..v, 2)\n"
"			 end \n"
"			local fmt = string.sub(v, s, e)\n"
"			pos=e+1\n"
"			s = string.find(fmt, \"...\", 1, true)\n"
"			if s~=nil then apos=-1 end \n"
"			fmt=string.gsub(fmt, \"[^NbnstfuTAi]\", \"\")\n"
"			local buf={}\n"
"			if string.find(fmt, \"A\") then fmt=\"NbnstfuTi\" end \n"
"			if string.find(fmt, \"i\") then buf.i=1 end \n"
"			if string.find(fmt, \"N\") then buf.N=1 end \n"
"			if string.find(fmt, \"b\") then buf.b=1 end \n"
"			if string.find(fmt, \"n\") then buf.n=1 end \n"
"			if string.find(fmt, \"s\") then buf.s=1 end \n"
"			if string.find(fmt, \"t\") then buf.t=1 end \n"
"			if string.find(fmt, \"f\") then buf.f=1 end \n"
"			if string.find(fmt, \"u\") then buf.u=1 end \n"
"			if string.find(fmt, \"T\") then buf.t=1 end \n"
"			tbuf[apos]=buf\n"
"			apos=apos+1\n"
"		 end::_luka_LOOPNEXT::end \n"
"		tlist[#tlist+1]=tbuf\n"
"	 end::_luka_LOOPNEXT::end \n"
"--ctxx.dbg(tlist, argv, emsg)\n"
"\n"
"	--argv, tlistの比較。[-1]のvaarg以外はindを同じで比較可能。\n"
"	--実引数の数は全て仮引数に自動修正されるので分からない\n"
"	--()は(nil)と同様の処理をすることで全体的にうまくまとまる。\n"
"	local flg=nil\n"
"	local hit=nil\n"
"	for k,v in ipairs(tlist)  do do \n"
"		flg=1\n"
"		for n,t in ipairs(argv)  do do \n"
"			--一つじゃないのはn(i)のみ\n"
"			local tt=\"dmy\"	\n"
"			if #t~=1 then t=\"n\"; tt=\"i\" end \n"
"			if v[n]==nil  and  v[-1]~=nil then v[n]=v[-1] end \n"
"			if v[n]==nil then  v[n]={[\"N\"]=1 }  end  --args数は自動一致調整. nil補完\n"
"			--実引数のtypeがtlistにあるか判定。intはnumと被るので二段判定\n"
"			if  v[n][t] == nil  and  v[n][tt] == nil  then  flg=nil;  do break end   end 	\n"
"		 end::_luka_LOOPNEXT::end \n"
"		hit=k\n"
"		if flg==1 then  do break end  end 	--全argが成功した\n"
"	 end::_luka_LOOPNEXT::end \n"
"	if flg==1 then return hit end 	--nil,false以外だけど、hitfmtの位置を返しとこう\n"
"	emsg=\"invalid args type: \"..emsg\n"
"	return nil, emsg\n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	ckopt\n"
"@auther momi-g\n"
"@brief	cmdline option parser.\n"
"@_synopsys	tb1,tb2 ckopt(str, tb_ini, tb_av)\n"
"@_eg\n"
"	av={ \"-h\", \"-c9\", \"-d\", \"10.4\", \"abc\", \"-v\", \"99\" }\n"
"\n"
"	ini={	# 1:key 2:opt 3:dfl 4:type 5-:eval testcode. concat code string.\n"
"	{\"verbose\",	\"-v\",	\"0\",	\"bool\" }\n"
"	,{\"usage\",	\"-h\",	\"0\",	\"bool\", \"usage();os.exit(0)\" }\n"
"	,{\"count\",	\"-c\",	\"1\",	'int', \"return (1<n and n<10),'invalid range'\"}\n"
"	,{\"delay\",	\"-d\",	0.3,	\"dbl\" }\n"
"	,{\"log\", \"-f\",io.stderr,\"str\",\"local fh=io.open(s);raw.v=fh\",\"return fh\"}\n"
"	}\n"
"\n"
"	opt, agleft = ckopt(\"\", ini, av)\n"
"	--> opt.count==9, opt.log==io.stderr ...etc\n"
"	--> agleft=={\"abc\", \"-v\", \"99\"}\n"
"\n"
"@param str	parse mode. set \"xq\" if eXpantion + Quiet mode. dfl:\"\".\n"
"	x: expantion. dfl mode works under the posix Utility Syntax Guidelines.\n"
"	 'x' allows symbol charopt, '-@', '-_' '-+' etc. '--' works as optend.\n"
"	 'x' parses until detect '--' or args end. eg) a.out abc -h >> hit -h\n"
"\n"
"	q: quiet. dfl mode outputs emsg and exit(1) if err. q mode rtns nil,emsg. \n"
"\n"
"@param tb_ini	optsetting table. must:clm1-4	no_must:clm5,6...\n"
"	- clm1 :keyname used for access the parsed result. str.  \n"
"	- clm2 :cmdline short option char. needs prefix hyphen '-'. str.\n"
"	- clm3 :dfl val. dfl val skips testfunc. anytype.\n"
"	- clm4 :cmdin type. 'bool/int/dbl/str'. bool is changed to 0/1. str.\n"
"	- clm5-:optional. rawcode str you want to test cmdin val. expands as below.\n"
" \n"
" local function tf(raw)\n"
" 	local s,n = raw.s, raw.n	--> 's' is cmdin optarg str. n=tonumber(s)\n"
" 	-- clm5 --\n"
" 	-- clm6 --\n"
" 	...\n"
" 	return 1	--> test suc/fail == no_fail / 0,nil,false\n"
" 	-- return 0,'bad filename'	--> set emsg to 2nd rtnarg if you want\n"
" end\n"
"	\n"
"	...preset local s,n is cmdin val str/num. special val 'raw.v' is used to\n"
"	set val directly to result.\n"
"	eg) (testcode) \"raw.v='xyz';return 1\"		--> opt.count == \"xyz\"\n"
"\n"
"@param tb_av	parse target str array. index key + str val. use {} if nil.\n"
"@return tb1	main result tb. each opt has 3 data. rtn nil,emsg if err+q mode.\n"
"	rtn.(keyname): main val.	eg) opt.help==1, rtn.filename==io.stderr etc	\n"
"	rtn.(?_dfl): dfl val.	eg) opt.help_dfl==\"0\"\n"
"	rtn.(?_cmdstr):cmdin str. set nil if opt is dfl. eg)res.usage_cmdstr==\"1\"\n"
"@return tb2	left args. remove optdata and shift args. str array.\n"
"	eg) av={\"-c9\", \"zz\", \"-h\", \"--\", \"abc\"} --(x mode)--> tb2={\"zz\", \"abc\"}\n"
"\n"
"@details -\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@_note\n"
" ckopt(\"\", ini, av)	--> 0.180ms\n"
" for(i=1,100000) do a=a+1 end --> 0.200ms ...parse cost is equals to 100k steps?\n"
" \n"
" http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02\n"
" https://docs.oracle.com/cd/E19455-01/816-3518/6m9ptvr12/index.html\n"
" https://www.mm2d.net/main/prog/c/getopt-03.html\n"
" https://wp.mikeforce.net/gnome/category/gtk\n"
" https://documents.mikeforce.net/gtk+-2.14.x-refs/gtk/html/gtk-General.html#gtk-init-with-args\n"
" http://catb.org/%7Eesr/writings/taoup/html/ch10s05.html\n"
"@version 1.1.1, 2021-03-18\n"
"]=]\n"
"\n"
"function ctxx.ckopt(mode, tb, args) \n"
"	args=args or {}\n"
"	if type(mode)~=\"string\" then  error(ctxx.fperr(nil, \"ag1 isnt string\"), 2)  end \n"
"	if type(tb)	~=\"table\"   then  error(ctxx.fperr(nil, \"ag2 isnt table\"), 2)  end \n"
"	if type(args)~=\"table\"  then  error(ctxx.fperr(nil, \"ag3 isnt table\"), 2)  end \n"
"	--iniのstringからフォーマットを読み取ってarrにsplit\n"
"	local function test_i(str) \n"
"		local ck=string.find(str, \".\", 1, true)\n"
"		if ck~=nil then  return 0  end \n"
"		ck=tonumber(str)\n"
"		if ck==nil then return 0  end \n"
"		return 1\n"
"	 end\n"
"	local function test_d(str) \n"
"		local ck=tonumber(str)\n"
"		if ck==nil then return 0  end \n"
"		return 1\n"
"	 end\n"
"	local function errstop(emsg) \n"
"		local buf=io.output()\n"
"		io.output(io.stderr)\n"
"		io.write(emsg)\n"
"		io.output(buf)\n"
"		os.exit(1)\n"
"	 end\n"
"	-- convert setting to ini\n"
"	local ini={}	--ini.a.name, ini.a.dfl=100, .tp=\"str\", testf=nil こんなの\n"
"	for i,darr in ipairs(tb)  do do \n"
"		if type(darr[1])~=\"string\" or type(darr[2])~=\"string\" or type(darr[4])~=\"string\"  then \n"
"			errstop(\"ckopt ini err: [1][2][4] must be str: \"..tostring(darr[1])..\"\\n\")\n"
"		 end \n"
"		if string.sub(darr[2],1,1)~=\"-\" or string.len(darr[2])~=2  then \n"
"			errstop(\"ckopt ini err: optchar must be 2char start with hyphen, '-h' etc: \"..tostring(darr[1])..\"\\n\")\n"
"		 end \n"
"		if   not  string.match (\"int/bool/dbl/str\", darr[4])  then \n"
"			errstop(\"ckopt ini err: bad opttype (int/bool/dbl/str): \"..tostring(darr[1])..\"\\n\")\n"
"		 end \n"
"		--name\n"
"		local char = string.sub(darr[2],2,2)\n"
"		local rg=\"[0-9a-zA-Z]\"\n"
"		if  string.match(mode, \"x\")  then  rg=ctxx.fprintf(nil, [=[[\\040-\\054\\056-\\176]]=])  end \n"
"--		if( string.match(mode, \"x\") ){ rg=ctxx.printf([[]])\"[\\32-\\44\\46-\\126]\" }	// - ...45\n"
"		if   not string.match(char, rg)  then \n"
"			errstop(\"ckopt ini err: bad optchar: -\"..char..\"\\n\")\n"
"		 end \n"
"		ini[char] = {}\n"
"		ini[char].name = darr[1]\n"
"		ini[char].dfl = darr[3]\n"
"		ini[char].tp = darr[4]\n"
"		\n"
"		--testcode\n"
"		local cmd=\"local function testfunc(raw) local s,n = raw.s, raw.n;do\"\n"
"		for i=5, #darr do do \n"
"			local tp = type(darr[i] )\n"
"			if  tp ~=\"string\"  then \n"
"				errstop(\"ckopt ini err: testcode must be str: \"..tostring(darr[1])..\"\\n\")\n"
"			 end \n"
"			cmd=cmd..\"\\n\"..darr[i]\n"
"		 end::_luka_LOOPNEXT::end \n"
"		cmd=cmd..\"\\nend;return 1;end;return testfunc;\"\n"
"		local fbuf\n"
"		if loadstring==nil then  fbuf= load(cmd, nil, \"t\", _G)()  end \n"
"		if loadstring~=nil then  fbuf= loadstring(cmd)()  end \n"
"		ini[char].testf = fbuf\n"
"	 end::_luka_LOOPNEXT::end \n"
"	--parse_args\n"
"	local agleft={}\n"
"	local ex = string.match(mode, \"x\")\n"
"	local apos = 1\n"
"	local aposmax = #args\n"
"	local cpos = 2\n"
"	local optarg=\"\"\n"
"	local emsg=nil\n"
"\n"
"	while 1 do do \n"
"::lb_NEXT::\n"
"		optarg=\"\"\n"
"		--[0]ck,  p@tget. optarg get	--, arg, argskip, -ab -c123\n"
"		if  args[apos] ==nil  then   do break end  end \n"
"		if  string.len(args[apos]) <cpos  then  args[apos]=nil;apos=apos+1;cpos=2;goto lb_NEXT  end \n"
"		if  args[apos]==\"--\"   then  args[apos]=nil; do break end  end \n"
"		if  string.sub(args[apos],1,2)==\"--\"  or  string.sub(args[apos], 1,1)~=\"-\" then \n"
"			if  ex==nil then   do break end   end 	--longopt\n"
"			apos=apos+1;cpos=2;goto lb_NEXT\n"
"		 end \n"
"\n"
"		local optc = string.sub(args[apos], cpos, cpos)\n"
"		if  ini[optc] ==nil then  emsg=\"no such opt: -\"..optc..\"\\n\"; do break end   end \n"
"		if  ini[optc].tp == \"bool\" then  ini[optc].val=1;optarg=\"1\";cpos=cpos+1;goto lb_TESTF  end \n"
"\n"
"		cpos=cpos+1\n"
"		optarg = string.sub(args[apos], cpos)\n"
"		args[apos]=nil\n"
"		apos=apos+1\n"
"		cpos=2\n"
"		if  optarg==\"\"  then \n"
"			optarg = args[apos]\n"
"			if args[apos]==nil then  emsg=\"optarg not found: -\"..optc..\"\\n\"; do break end   end \n"
"			args[apos]=nil\n"
"			apos=apos+1\n"
"		 end \n"
"		if ini[optc].tp==\"str\" then  ini[optc].val=optarg  end \n"
"		if ini[optc].tp==\"int\" then \n"
"			local ck=test_i(optarg)\n"
"			if ck==0 then  emsg=\"optarg is not int: -\"..optc..\",\"..optarg..\"\\n\"; do break end   end \n"
"			ini[optc].val=tonumber(optarg)\n"
"		 end \n"
"		if ini[optc].tp==\"dbl\" then \n"
"			local ck=test_d(optarg)\n"
"			if ck==0 then emsg=\"optarg is not dbl: -\"..optc..\",\"..optarg..\"\\n\"; do break end   end \n"
"			ini[optc].val=tonumber(optarg)\n"
"		 end \n"
"::lb_TESTF::\n"
"		ini[optc].cmdin=optarg\n"
"		local raw={s=optarg, n=tonumber(optarg), v=ini[optc].val}\n"
"		local rc, str = ini[optc].testf(raw)\n"
"		str=str or \"\"\n"
"		if  not rc then  emsg=\"bad optarg: -\"..optc..\", \"..optarg..\" :\"..str..\"\\n\";  do break end   end \n"
"		ini[optc].val=raw.v	--更新\n"
"		goto lb_NEXT\n"
"	 end::_luka_LOOPNEXT::end \n"
"	\n"
"	--rtn or errstop\n"
"	if emsg then \n"
"		local rc = string.match(mode, \"q\")\n"
"		if rc~=nil then  return nil, emsg  end \n"
"		errstop(emsg)\n"
"	 end \n"
"	--result\n"
"	local res={}\n"
"	for optc,info in pairs(ini)  do do \n"
"		res[info.name]=ini[optc].val or ini[optc].dfl\n"
"		res[info.name..\"_cmdstr\"]=ini[optc].cmdin\n"
"		res[info.name..\"_dfl\"]=ini[optc].dfl\n"
"	 end::_luka_LOOPNEXT::end \n"
"	local nargs={}\n"
"	for i=1, aposmax  do do \n"
"		if args[i]~=nil  then  nargs[#nargs+1]=args[i]  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return res, nargs\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	ag2opt\n"
"@auther momi-g\n"
"@brief	getopt/getopts like args parser\n"
"@_synopsys	tbl,tbl ag2opt(str, tbl)\n"
"@_eg\n"
"	ag={ \"-abzz\", \"-4\", \"23\", [\"dmy\"]=\"ig\"  }	--> key \"dmy\" is ignored.\n"
"	opts, args = ag2opt(\"av4:\", ag)	--> opts={a=1,[\"4\"]=\"23\"}, args={\"bzz\"}\n"
"	opts, args = ag2opt(\"ab:\", ag)	--> errstop. -4 is not set as opt.\n"
"	opts, args = ag2opt(\":ab:\", ag)	--> nil, emsg... silent mode.\n"
"@param str	optfmt. same as posix getopts. top \":\" works as silent flg.\n"
"@param tbl	parse target. seq table with strvalue. ignores not seqkey.\n"
"@return 2 rtn. 1:opttbl. key is optchar.	2:left args. order is saved.\n"
"@details if opt is flgtype, rtndata is 1(num) or nil. this func checks all args\n"
"	except argend or \"--\". this is the only one deference from posix.\n"
"@_note	https://github.com/cheusov/lua-alt-getopt/issues (Aleksey Cheusov, MIT)\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.4, 2020-05-08\n"
"]=]\n"
"function ctxx.ag2opt(fmt, ag) \n"
"	local ferr=ctxx.errstop\n"
"	if string.sub(fmt, 1,1) == \":\"  then \n"
"		ferr= function(a, b) return a end\n"
"		fmt=string.sub(fmt, 2)\n"
"	 end \n"
"	\n"
"	local buf, bbuf, pos = nil, nil, 1\n"
"	local subflg={}	--subargを持つか否か\n"
"	local agtbl={}\n"
"	local optbl={}\n"
"\n"
"	--fmtck\n"
"	buf = string.find(fmt, \"::\")\n"
"	if buf then   print(fmt, buf); ctxx.errstop(\"optfmt is 'a:bd' etc\", 2)  end \n"
"	buf = string.find(fmt, \"[a-zA-Z0-9:]+\")\n"
"	if  not buf then  ctxx.errstop(\"optfmt is 'a:bd' etc\", 2)  end \n"
"	if type(ag)~=\"table\" then  ctxx.errstop(\"2nd arg must be tbl: \"..type(ag), 2)  end \n"
"	\n"
"	while pos<=#fmt do do \n"
"		buf = string.match(fmt, \"[a-zA-Z0-9:]\", pos)\n"
"		if buf==\":\"  and  bbuf~=nil then  subflg[bbuf]=1  end \n"
"		if buf~=\":\" then  subflg[buf]=0  end \n"
"		bbuf=buf\n"
"		pos=pos+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"\n"
"	--切り取り型に変更した。\n"
"	pos=1\n"
"	while pos<=#ag do do \n"
"		if type(ag[pos])~=\"string\" then \n"
"			ctxx.errstop(\"argtbl must be string: \"..pos..\" \"..type(ag[pos]), 2)\n"
"		 end \n"
"		buf = string.match(ag[pos], \"^-[a-zA-Z0-9].*\" )\n"
"		if buf~=nil then \n"
"			local head=string.sub(buf,2,2)\n"
"			if subflg[head] == nil then \n"
"				local emsg=ferr(\"no such option: -\"..head, 2)\n"
"				return nil, emsg\n"
"			 end \n"
"			buf=string.sub(buf,2)\n"
"			while 0<#buf do do \n"
"				head, buf = string.match(buf, \"(.)(.*)\")\n"
"				buf=buf or \"\"\n"
"				if subflg[head] ==0 then  optbl[head]=1  \n"
"				elseif subflg[head] ==1  and  buf~=\"\" then  optbl[head]=buf; buf=\"\"  \n"
"				elseif subflg[head] ==1  and  buf==\"\" then \n"
"					pos=pos+1\n"
"					if  ag[pos]==nil then \n"
"						local emsg=ferr(\"arg lacks optarg: -\"..buf, 2)\n"
"						return nil, emsg\n"
"					 end \n"
"					optbl[head]=ag[pos]\n"
"				 end \n"
"			 end::_luka_LOOPNEXT::end \n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if ag[pos]==\"--\" then \n"
"			pos=pos+1\n"
"			for i=pos, #ag do do  agtbl[#agtbl+1]=ag[pos]  end::_luka_LOOPNEXT::end \n"
"			 do break end \n"
"		 end \n"
"		agtbl[#agtbl+1]=ag[pos]\n"
"		::lbl_NEXT::\n"
"		pos=pos+1\n"
"	 end::_luka_LOOPNEXT::end \n"
"	return optbl, agtbl\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	grepmcmtf,	grepmcmts\n"
"@auther momi-g\n"
"@brief	gather multiline cmt from luasrc.\n"
"@_synopsys	tbl grepmcmtf(str, num/nil)		/	tbl grepmcmts(str)\n"
"@_eg\n"
"	rtn = grepmcmtf(\"file.lua\")		--> rtn = { \"cmt1, \"cmt2\", \"cmt3\" }\n"
"	rtn = grepmcmtf(\"file.lua\", 2048)	--set innerbuff size. dfl 1024.\n"
"	\n"
"	src = '--[[ cmt_11 ]]	print(\"hw\");  --[==[cmt_22]==] --[[12 cmt]]'\n"
"	rtn = grepmcmts(src)		-->  { \" cmt_11 \", \"cmt_22\", \"12 cmt\" }\n"
"\n"
"@param str1	target obj. filename(mcmtf) or luacode string(mcmts).\n"
"@param num	grepmcmt() buffsize for read file at once.\n"
"@return 1rtn. seqtbl of cmtstr. rtn nil,emsg if err.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.0, y2020m04d09\n"
"]=]\n"
"\n"
"--common\n"
"local\n"
"function grepcmtc(str) \n"
"	local r1=nil	--result mcmt string\n"
"	local r2=nil	-- lft str 食べ残し。再代入に必要になる。\n"
"	while 1 do do \n"
"		local rtn, s1, e1 = ctxx.matchmcmt(str)\n"
"		local _, s2, e2 = ctxx.matchlit(str)\n"
"		local __, s3, e3 = ctxx.matchmlit(str)\n"
"		local ___, s4, e4 = ctxx.matchcmt(str)	--追加修正\n"
"		local min=nil\n"
"		--ここが間違ってた。{} =={} は常にfalse. テーブルはポインタ参照評価だから。\n"
"		--代わりに遅延評価とラスト返却に書き換える。さらにlineコメントも追加しないとダメ。\n"
"		if  (s1 or s2 or s3 or s4) == nil  then  r1=nil; r2=str;  do break end   end 	--該当なし\n"
"		--どれかしらヒットしてる. s1でなくても\n"
"		\n"
"		if s1==nil then s1=#str  end \n"
"		if s2==nil then s2=#str  end \n"
"		if s3==nil then s3=#str  end \n"
"		if s4==nil then s4=#str  end \n"
"		min=math.min(s1,s2,s3,s4)\n"
"		\n"
"		--本命 minの関係と--単独とのレースで先に出る必要がある\n"
"		if s1==min then \n"
"			if e1==nil then r1=nil; r2=string.sub(str, s1);  do break end  end \n"
"			r1=rtn\n"
"			r2 = string.sub(str, e1+1)\n"
"			 do break end \n"
"		 end \n"
"		if s2==min then \n"
"			if e2==nil then r1=nil; r2=string.sub(str, s2);  do break end  end \n"
"			str = string.sub(str, e2+1)\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if s3==min then \n"
"			if e3==nil then r1=nil; r2=string.sub(str, s3);  do break end  end \n"
"			str = string.sub(str, e3+1)\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		if s4==min then \n"
"			if e4==nil then r1=nil; r2=string.sub(str, s4);  do break end  end \n"
"			str = string.sub(str, e4+1)\n"
"			goto lbl_NEXT\n"
"		 end \n"
"		::lbl_NEXT::\n"
"	 end::_luka_LOOPNEXT::end \n"
"	return r1, r2\n"
" end\n"
"\n"
"function ctxx.grepmcmts(str) \n"
"	local tbl={}\n"
"	while 1 do do \n"
"		rtn, str = grepcmtc(str)\n"
"		if rtn~=nil then tbl[#tbl+1]=rtn end \n"
"		if rtn==nil then  do break end  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return tbl\n"
" end\n"
"\n"
"function ctxx.grepmcmtf(fname, buffsize) \n"
"	local rtn, emsg = io.open(fname, \"r\")\n"
"	if rtn==nil then return rtn, emsg end \n"
"	local sv=io.input()\n"
"	io.input(rtn)	--fhをstdinに設定する\n"
"	local tbl={}\n"
"	local str=\"\"\n"
"	rtn=\"\"\n"
"	while 1 do do \n"
"		local buf = io.read(buffsize)  or  \"\"\n"
"		str=str..buf\n"
"		rtn, str = grepcmtc(str)\n"
"		if rtn==nil  and  buf==\"\" then  do break end  end \n"
"		if rtn~=nil then tbl[#tbl+1]=rtn end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	io.input(sv)	--reset\n"
"	return tbl\n"
" end\n"
"\n"
"--[=[*\n"
"@_name	lua_gazcmt\n"
"@auther momi-g\n"
"@brief	grep, filter, sort multiline comment from luasrc\n"
"@_synopsys	tb lua_gazcmt(func/str1/nil [, str2/false, ...])\n"
"@_eg\n"
"	--mydoc.lua\n"
"	local function myf() print(\"hw\") end	\n"
"	--[[todo abc]]\n"
"	--[[doc abc]]\n"
"	--[[debug_msg ]]\n"
"	\n"
"	--run\n"
"	tb = lua_gazcmt(\"mylua.lua\") --> {\"todo abc\", \"doc abc\", \"debug_msg\",  }\n"
"	lua_gazcmt(myf) --> search myf() srcfile and run. same as above.\n"
"	lua_gazcmt(nil) --> conv to current file, (debug.getinfo(1).source).\n"
"	lua_gazcmt(myf,\"[d][o]\") --> {\"todo abc\", \"doc abc\" } ..luaptn filter\n"
"	\n"
"	lua_gazcmt(myf,\"abc$\",\"[d]o\" ) --> {\"todo abc\", \"doc abc\" }  ..multiple filter\n"
"	lua_gazcmt(myf,\"abc\",\"do\") --> {\"doc abc\",\"todo abc\"} ..sort. see below.\n"
"	lua_gazcmt(myf,\"abc\",false,\"doc\" ) --> { \"todo abc\" } ..abc && (!doc)\n"
"\n"
"@param str1/func/nil	srcobj. filename / func_srcfile / current_file.\n"
"@param str2/false...	luaptn for filtering. 'false' remove next arg ptn.\n"
" if last ptn is [a-Z0-9_]+ and out of 'false' effect, it is used as rtntbl\n"
" sortkey. sort rule is,\n"
" 1- exact word match (\"abc\" / \"()abc[],\" / \"a+abc.zz\" etc)\n"
" 2- forward match (\"abcde\" / \",abcord\"  etc. ignore symbols)\n"
" 3- patical match (\"cabc\" / \"fabcompany\" etc)\n"
" ..then younger wordpos cmt comes first.\n"
"\n"
"@return	1rtn. rtn cmttb. rtn {} if nohit. rtn nil,emsg if err.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 2.0.0, 2021-06-18\n"
"]=]\n"
"\n"
"--ファクトリ. 単語を受け取って最速位置で発見したとき、exact,forward, partial\n"
"--の優先順位で、かぶったときだけposが強い方が勝利。辞書方式。\n"
"local\n"
"function wordsort(word) \n"
"	local p1 = \"[^a-zA-Z0-9_]\"..word..\"[^a-zA-Z0-9_]\"\n"
"	local p2 = \"[^a-zA-Z0-9_]\"..word\n"
"	local p3 = word\n"
"	local tbl = {p1, p2, p3}\n"
"	\n"
"	local function rtn(bf, af) \n"
"		--事前にwordは含有済\n"
"		for  k,v in ipairs(tbl)  do do \n"
"			local s = string.find(bf, v)\n"
"			local ss = string.find(af, v)\n"
"			if s~=nil  and  ss==nil then return true end 	--bfが無いってことはそれ以上の格\n"
"			if s~=nil  and  ss~=nil  and  s<ss then return true end \n"
"			if s==nil  and  ss~=nil then return nil end 	--bfが無いってことはそれ以上の格\n"
"			if s~=nil  and  ss~=nil  and  ss<s then return nil end \n"
"			--if(s==ss) { return true }	//区別不能.次の単語でソート \n"
"		 end::_luka_LOOPNEXT::end \n"
"		return true	--全滅。一致処理は上流で始末する.stsort()を使う\n"
"	 end\n"
"	return rtn\n"
" end\n"
"\n"
"function ctxx.lua_gazcmt(src, ...) \n"
"	local rtn, emsg = ctxx.cktp(\"fsN, bs...\")\n"
"	if rtn==nil then  ctxx.errstop(emsg, 2)  end \n"
"	\n"
"	--vaからpとnを分ける\n"
"	local ptbl = {}\n"
"	local ntbl = {}\n"
"	local tbl = {...}\n"
"	if #tbl==0 then tbl={\"\"} end \n"
"	local lastptn=nil\n"
"	local flg=0\n"
"	local buf=nil\n"
"	local buffsize=1024\n"
"	for k,v in ipairs(tbl)  do do \n"
"		if   not ctxx.istypes(v, \"sb\")  or  v==true  or  flg == -1  and  type(v)~=\"string\"  then \n"
"			flg=-1; do break end \n"
"		 end \n"
"		if  v==false  then  flg= -1  \n"
"		elseif flg<0 then  ntbl[1+#ntbl]=v; flg=0 \n"
"		elseif  type(v)==\"string\"  then  ptbl[1+#ptbl]=v; flg=1 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	if flg == -1 then  ctxx.errstop(\"3rd- arg is invalid type: \"..ctxx.vinfo(v) )  end \n"
"	lastptn=ptbl[#ptbl]\n"
"	if flg==0 then  lastptn=ntbl[#ntbl]  end \n"
"	\n"
"	--一覧取得\n"
"	if type(src)==\"function\"  or  src==nil then \n"
"		src=src  or  2	--nil追加。使われているソースファイル名を自動取得\n"
"		local buf=debug.getinfo(src).source\n"
"		local ck = string.sub(buf, 1, 1)\n"
"		if ck == \"@\" then  src = string.sub(buf, 2)  \n"
"		elseif ck == \"=\" then \n"
"			buf = string.sub(buf, 2)\n"
"			return nil, \"failed to get luasrc. C-API?: \"..buf\n"
"		 end \n"
"		rtn, emsg = ctxx.grepmcmtf(src, buffsize)\n"
"		if  rtn==nil  then  return nil, emsg  end \n"
"	 \n"
"	elseif  type(src) == \"string\"  then \n"
"		rtn, emsg = ctxx.grepmcmtf(src, buffsize)\n"
"		if rtn==nil then return nil, emsg end \n"
"	 end \n"
"	--ptblを集める\n"
"	tbl={}\n"
"	for k,v in ipairs(rtn)  do do  \n"
"		local ck=nil\n"
"		for kk,vv in ipairs(ptbl)  do do \n"
"			ck = string.find(v, vv)\n"
"			if  not ck then  do break end  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		if ck then  tbl[1+#tbl]=v  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	rtn=tbl\n"
"	\n"
"	--ntblを差っ引く\n"
"	tbl={}\n"
"	for k,v in ipairs(rtn)  do do \n"
"		ck=nil\n"
"		for kk,vv in ipairs(ntbl)  do do \n"
"			ck = string.find(v, vv)\n"
"			if ck then  do break end  end \n"
"		 end::_luka_LOOPNEXT::end \n"
"		if ck==nil then  tbl[1+#tbl]=v  end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	rtn=tbl\n"
"	--ラストptnでtblかソート単体か\n"
"	buf=string.find(lastptn, \"^[a-zA-Z0-9_]+$\")	-- ラストptnがpでexact系\n"
"	if flg==1  and  buf ~=nil then \n"
"		local comp=wordsort(buf)\n"
"		ctxx.stsort(rtn, comp)\n"
"	 end \n"
"	return rtn\n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	srcinfo, ffsrcinfo\n"
"@auther momi-g\n"
"@brief	disp lua srccode doccmt list\n"
"@_synopsys\n"
" str srcinfo(tbl1, str, tbl2)\n"
" str ffsrcinfo(fh, func/filename, tbl1, str, tbl2)\n"
" ..all args allows nil. tbl={}, str=\"\", fh: noout, func/file: self file \n"
"@_eg\n"
"--abc.lua\n"
"	function myf() return 123 end\n"
"	--[[dc(\\n)	@name myf(\\n)	@param	some msg1(\\n) ]]\n"
"	--[==[dc(\\n)	@funcname myf2(\\n)	]==]\n"
"	--[[ todo myname_abc ]]\n"
"		\n"
"	rtn = srcinfo( {\"^dc\", \"[m][y]\"}, \"name[^\\n]*\\n\", _G.arg )\n"
"	\n"
"	-- ~$ lua abc.lua		#>> @name myf , @name myf2\n"
"	-- ~$ lua abc.lua myf2	#>> disp myf2 cmtstr if hit only 1 cmt\n"
"	-- ~$ lua abc.lua my	#>> if multiple cmt hit, disp list\n"
"	-- ~$ lua abc.lua func my	#>> search including both word cmt. (AND search)\n"
"	-- ~$ lua abc.lua my 1	#>> if last arg is num, select cmt from list.\n"
"\n"
"	ffsrcinfo( io.stderr, \"xyz.lua\", ... )	--> targetting other file doccmt\n"
"	ffsrcinfo()	--> ffsrcinfo( io.stdout, \"now.lua\",  {}, \"\", {} )\n"
"	ffsrcinfo( nil, myf, ... )	--> search myf() srcfile and use. nodisp.\n"
"\n"
"@param fh output file handle. strinfo() is set to io.stdout. noout if nil.\n"
"@param func/filename cmtsrc. search srcfile if func. use as filename if str.\n"
"@param tbl1 filter for def doc(luaptn). gather multiline cmt satisfying allptn.\n"
" javadoc: {\"^[*]\",\"param\",\"auth\"} --> start with '*' and includes param + auth\n"
" other: {\"api$\",false,\"p[o]em\",false,\"egg\"} --> contains neither poem nor egg\n"
"@param	str	title ptn of cmt. uses 1st hit str. used for disp cmtlist. \n"
"@param	tbl2	userin ptntbl. if last word is num, select cmt. see above eg.\n"
"@return	str	result msg. same as disp msgstr. rtn nil,emsg if err/fail.\n"
"@details userin search word isnt only applyed to titlestr but all cmtstr.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.0, y2020m04d09\n"
"]=]\n"
"\n"
"function ctxx.srcinfo(ctbl,lptn,tbl)  return ctxx.ffsrcinfo(io.stdout, nil, ctbl, lptn, tbl)  end\n"
"function ctxx.ffsrcinfo(fh, src, ctbl, lptn, argtbl) \n"
"	local rtn, emsg = ctxx.cktp(\"A,fsN,tN,sN,tN\")\n"
"	if rtn==nil then  ctxx.errstop(emsg, 2)  end \n"
"	if  fh~=nil  and  io.type(fh) ~= \"file\"  then \n"
"		ctxx.errstop(\"invalid filehandle: \"..ctxx.vinfo(fh) )\n"
"	 end \n"
"	--nil support\n"
"	fh=fh or io.stdout\n"
"	src=src or debug.getinfo(2, \"f\").func\n"
"	ctbl=ctbl or {}\n"
"	lptn=lptn or \"\"\n"
"	argtbl=argtbl or {}\n"
"\n"
"	local lnum = tonumber( argtbl[#argtbl] )\n"
"	if lnum~=nil then  argtbl[#argtbl] = nil  end \n"
"	for k,v in ipairs(argtbl)  do do  if v~=nil then  ctbl[1+#ctbl]=v  end 	 end::_luka_LOOPNEXT::end \n"
"	local rtn, emsg = ctxx.lua_gazcmt(src, ctxx.tb2va(ctbl) )\n"
"\n"
"	if rtn==nil then  return rtn, emsg  end \n"
"	if #rtn==0 then  rtn = \"no doccmt exists: \"..src  \n"
"	elseif #rtn ~= 1  and  lnum==nil then \n"
"		local buf=\"\"\n"
"		for k,v in ipairs(rtn)  do do \n"
"			local lbuf = string.match(v, lptn) or \"\"\n"
"			buf=buf..lbuf\n"
"		 end::_luka_LOOPNEXT::end \n"
"		rtn=buf\n"
"	 \n"
"	elseif 1 then \n"
"		lnum=lnum or 1\n"
"		rtn[lnum]=rtn[lnum] or \"nodoc or select num is erange\"\n"
"		rtn=rtn[lnum]..\"\\n\"\n"
"	 end \n"
"	ctxx.fprintf(fh, \"%s\\n\", rtn)\n"
"	return rtn\n"
" end\n"
"\n"
"\n"
"\n"
"--[=[*\n"
"@_name	srcpath, srcdir, srcdirsep, srcname, srcnametop, srcnamesuf \n"
"@auther momi-g\n"
"@brief	portable path getter like dirname/$0/arg[0] etc, uses debug.getinfo().\n"
"@_synopsys\n"
"str srcpath(nil/num),	str srcdir(nil/num),	str srcdirsep(nil/num)\n"
"str srcname(nil/num),	str srcnametop(nil/num),	str srcnamesuf(nil/num)	\n"
"@_eg\n"
"	-- abc.lua...\n"
"	m = require(\"modname\")\n"
"	src =	m.srcpath()		--> ./dir/abc.lua,	 .\\win\\abc.lua	etc\n"
"	dname =	m.srcdir()		--> ./dir/,	 .\\win\\		...rtn str with dirsep end.\n"
"	sep = m.srcdirsep()		--> \\ or /, win or notwin.\n"
"	name=	m.srcname()		--> abc.lua\n"
"	top =	m.srcnametop()	--> abc	...top .shortest match until dotchar \".\".\n"
"	suf =	m.srcnamesuf()	--> .lua, .tar.gz	...suffixes. rest of topname.	\n"
"	src = dname .. name	--> ./dir/abc.lua\n"
"	\n"
"	buf = srcpath(1)	-->	exit if failed to get fname(used in loadstring() etc)\n"
"	rtn,emsg = srcpath()	-->	nil,emsg if failed to get fname\n"
"\n"
"@param num nil/1. errmode switch. nil:rtn nil,emsg		1:os.exit(1)\n"
"@return	str	result path/dir/sep str. rtn nil,emsg if param = nil. \n"
"@details	srcdir() rtns not blank str. (filename aaa.lua -> dir == ./ etc) \n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.1, y2020m07d16\n"
"]=]\n"
"\n"
"local\n"
"function errfunc(mode, msg) \n"
"	if mode~=nil then \n"
"		ctxx.fperr(io.stderr, msg, 2)\n"
"		os.exit(1)\n"
"	 end \n"
"	local rtn = ctxx.fperr(nil, msg, 2)\n"
"	return nil, rtn\n"
" end\n"
"function ctxx.srcpath(mode) \n"
"	local buf = debug.getinfo(2, \"S\").source\n"
"	local ck = string.match(buf, \".\")\n"
"	if ck ~= \"@\" then \n"
"		return errfunc(mode, \"failed to get filename, srcchar: \"..ck)\n"
"	 end \n"
"	return string.sub(buf, 2)\n"
" end\n"
"function ctxx.srcdirsep(mode) \n"
"	local sep1 = string.find (package.path, \"/\", 1, true) or 0\n"
"	local sep2 = string.find (package.path, \"\\\\\", 1, true) or 0\n"
"	if sep1==0  and  sep2==0  then \n"
"		return errfunc(mode, \"failed to get dirsep from package.path, LUA_PATH='(blank)' ? \")\n"
"	 end \n"
"	local sep = \"/\"\n"
"	if sep1<sep2 then  sep=\"\\\\\"  end \n"
"	return sep\n"
" end\n"
"function ctxx.srcdir(mode) \n"
"	local base, emsg = ctxx.srcpath(mode)\n"
"	if base==nil then return nil, emsg end \n"
"	\n"
"	local sep = ctxx.srcdirsep(mode)\n"
"	if sep==nil then return nil, emsg end \n"
"	\n"
"	local pos=0\n"
"	for i=1, #base, 1 do do \n"
"		local buf = string.sub(base, i, i)\n"
"		if buf==sep then pos=i end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return string.sub(base, 1, pos)\n"
" end\n"
"\n"
"function ctxx.srcname(mode) \n"
"	local base, emsg = ctxx.srcpath(mode)\n"
"	if base==nil then return nil, emsg end \n"
"	\n"
"	local sep = ctxx.srcdirsep(mode)\n"
"	if sep==nil then return nil, emsg end \n"
"	\n"
"	local pos=1\n"
"	for i=1, #base, 1 do do \n"
"		local buf = string.sub(base, i, i)\n"
"		if buf==sep then pos=i+1 end \n"
"	 end::_luka_LOOPNEXT::end \n"
"	return string.sub(base, pos)\n"
" end\n"
"function ctxx.srcnametop(mode) \n"
"	local base, emsg = ctxx.srcname(mode)\n"
"	if base==nil then return nil, emsg end \n"
"	return string.match (base, \"[^%.]*\")\n"
" end\n"
"function ctxx.srcnamesuf(mode) \n"
"	local base, emsg = ctxx.srcname(mode)\n"
"	if base==nil then return nil, emsg end \n"
"	return string.match (base, \"%..*\")\n"
" end\n"
"\n"
"\n"
"--[=[*\n"
"@_name	toint\n"
"@auther momi-g\n"
"@brief	conv num to int+decimals, 1.01 >> 1, 0.01  -2.9 >> -2, -0.9	\n"
"@_synopsys	num,num toint(num)	\n"
"@_eg\n"
"	num = -10.12\n"
"	print( toint(num) )	-->		-10,	-0.12\n"
"@param num number. not allow string.\n"
"@return	num. os.exit(1) if err. \n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.0.0, y2020m07d01\n"
"]=]\n"
"ctxx.toint = math.modf\n"
"\n"
"--[=[*\n"
"@_name	run_test, frun_test, eq/neq, add_test(not func)\n"
"@auther momi-g\n"
"@brief	lutest, simple unittest tools.\n"
"@_synopsys	\n"
"	eq(...) / neq(...)	...see eg about assert func.\n"
"	n1,n2,msg run_lutest(tbl/nil)\n"
"	n1,n2,msg frun_lutest(fh/nil, tbl/nil)\n"
"@_eg\n"
"	lut=require(\"util\").lutest\n"
"	lut.add_test.abc_myf()	--> 'add_test' is lutest inner table.\n"
"		lut.eq( 1==1 )	--> suc,	true/false test if argc==1\n"
"		lut.eq( 1,1  )	--> suc.	compare ag1/ag2 if argc==2\n"
"		lut.eq( 1,2, \"my errmsg\" )	--> fail.	ag3 == failed msg\n"
"		lut.neq( 1,1 )	--> fail, not equal.\n"
"	end\n"
"	lut.add_test.zzz()\n"
"		lut.neq( 10,20 )\n"
"	end\n"
"	\n"
"	fail,all,msg = lut.run_test()	--> test all suite. disp report to stderr.\n"
"	fail,all,msg = lut.run_test({\"zzz\"}) --> test only select suite (str seqtbl)\n"
"	fail,all,msg = lut.frun_test(io.stdout) --> change fh. noout if nil.\n"
"\n"
"@param n1	num. count failed assert.\n"
"@param n2	num. count all assert.\n"
"@param msg	str. test result report.\n"
"@details\n"
"	run_test() is testsuite runner. test select suite if arg is str seqtbl.\n"
"	rtn failcnt, allcnt, report. frun_test() changes outfh. noout if fh is nil.\n"
"@_conforming lua5.1+, luajit2.0+\n"
"@version 1.1.0, 2020-11-10\n"
"]=]\n"
"\n"
"ctxx.lutest={}\n"
"ctxx.lutest.dispflg=1\n"
"ctxx.lutest.testsuc=0\n"
"ctxx.lutest.testfail=0\n"
"ctxx.lutest.add_test={}\n"
"ctxx.lutest.rmsg=\"\"\n"
"\n"
"local \n"
"function testeq_common(msg, n, a1, a2, ck) \n"
"	local info=\"\"\n"
"	if n==1 then \n"
"		--agが一つだけinfoを変える\n"
"		if ck==true then info=\"eq_test\" end \n"
"		if ck==false then info=\"neq_test\"; a1= not a1 end \n"
"	--	a1= (a1== ck)\n"
"	 end \n"
"	if n==2 then \n"
"		local buf=\"\"\n"
"		if ck==true then buf=\" == \" end \n"
"		if ck==false then buf=\" != \" end \n"
"		info=ctxx.sprintf(\"%s:%s\"..buf..\"%s:%s\",tostring(a1),(ctxx.istypes(a1))\n"
"		, tostring(a2), (ctxx.istypes(a2)) )\n"
"		a1 = ((a1 == a2) == ck)\n"
"	 end \n"
"	if msg~=nil then msg=\" (\"..tostring(msg)..\")\" end \n"
"	msg=msg or \"\"\n"
"	\n"
"	local rmsg=\"\"\n"
"	if a1 then \n"
"		ctxx.lutest.testsuc=ctxx.lutest.testsuc+1\n"
"		if ctxx.lutest.dispflg==2 then  rmsg = \"test suc: \"..info..msg  end \n"
"	 \n"
"	else \n"
"		ctxx.lutest.testfail=ctxx.lutest.testfail+1\n"
"		if ctxx.lutest.dispflg~=0 then  rmsg = \"test FAIL: \"..info..msg  end \n"
"	 end \n"
"		--callソースが狂うので		ctxx.lutest.nowfunc = k;	を使って表示する\n"
"	local buf = ctxx.getlovars(3, \"k\")\n"
"	buf = ctxx.fprintf(nil, \"%s %s: %s(): %s\\n\", ctxx.S_FILE(2), ctxx.S_LINE(2), buf, rmsg )\n"
"	if rmsg~=\"\" then  ctxx.lutest.rmsg = ctxx.lutest.rmsg .. buf  end \n"
"	if  not a1  and  ctxx.lutest.dispflg~=0\n"
"		 or  a1  and  ctxx.lutest.dispflg==2	 then \n"
"		local fh = ctxx.getlovars(3, \"fh\")\n"
"		ctxx.fprintf(fh, \"%s\", buf)\n"
"	 end \n"
"--suc,failでres方式を変える\n"
"	if a1 then 	return buf end \n"
"	return nil, buf\n"
" end\n"
"\n"
"local\n"
"function stoptest(str, n) \n"
"	local buf = ctxx.getlovars(4, \"k\")..\"(): test argc allows \"..str..\": \"..n\n"
"	error(buf, 3)\n"
" end\n"
"function ctxx.lutest.eq(...) \n"
"	local ac = select(\"#\", ...)\n"
"	local a1,a2, msg = select(1, ...)\n"
"	if 3<ac then  stoptest(\"1:expr / 2:a,b / 3:a,b,msg\", ac)  end \n"
"	if 1<ac then  ac=2  end \n"
"	return testeq_common(msg, ac, a1, a2, true)\n"
" end\n"
"function ctxx.lutest.neq(...) \n"
"	local ac = select(\"#\", ...)\n"
"	local a1,a2, msg = select(1, ...)\n"
"	if 3<ac then  stoptest(\"1:expr / 2:a,b / 3:a,b,msg\", ac)  end \n"
"	if 1<ac then  ac=2  end \n"
"	return testeq_common(msg, ac, a1, a2, false)\n"
" end\n"
"\n"
"function ctxx.lutest.run_test(flist, flg) \n"
"	return ctxx.lutest.frun_test(io.stderr, flist, flg)\n"
" end\n"
"function ctxx.lutest.frun_test(fh, flist, flg) \n"
"	if  fh~=nil  and  io.type(fh)==nil  then  ctxx.errstop(\"1st arg is invaild file handle\")  end \n"
"	if  ctxx.istypes(flist, \"Nt\") == nil  then  ctxx.errstop(\"3nd arg must be nil/tbl\")  end \n"
"	if  ctxx.istypes(flg, \"Nn\") == nil  then  ctxx.errstop(\"3rd arg must be nil/num\")  end \n"
"	--set verbosemode\n"
"	if flg==nil or flg==1 then ctxx.lutest.dispflg=1 \n"
"	elseif flg==0 then ctxx.lutest.dispflg=0 \n"
"	elseif flg==2 then ctxx.lutest.dispflg=2 end \n"
"	\n"
"	local tlist={}\n"
"	ctxx.lutest.testsuc=0 \n"
"	ctxx.lutest.testfail=0\n"
"	ctxx.lutest.rmsg=\"\"\n"
"	\n"
"	local fsq=ctxx.tblconv(flist, \"seqn:s\")	--シーケンスのみ集める\n"
"	local emsg=\"\"\n"
"	if  flist ~= nil  and  type(flist) ~= \"table\" then \n"
"		ctxx.errstop(\"err. demands noarg or one seqtbl {'ts_f1', 'ts_f2' ...}\")\n"
"	 end \n"
"	if flist==nil or #fsq==0 then  tlist=ctxx.lutest.add_test  \n"
"	elseif 1 then \n"
"-- grep\n"
"		tlist = ctxx.tsgrep(ctxx.addtest, fsq)\n"
"		if  ctxx.tsize(tlist) ~= ctxx.tsize(fsq)  then \n"
"			local bad = ctxx.ttrm(fsq, tlist)\n"
"			ctxx.errstop(\"testfunc not found. typo?\\n\"..ctxx.tinfo(bad))\n"
"		 end \n"
"	 end \n"
"	for  k,v in pairs(tlist)  do do  v()  end::_luka_LOOPNEXT::end \n"
"	local fnum = ctxx.lutest.testfail\n"
"	local anum = ctxx.lutest.testsuc + ctxx.lutest.testfail\n"
"	local res = ctxx.fprintf(nil, \"fail/run: %d/%d\\n\", fnum, anum )\n"
"	res = \"--test summary:\\n\"..ctxx.lutest.rmsg..res\n"
"	ctxx.fprintf(fh, \"%s\", res)\n"
"	return fnum, anum, res\n"
" end\n"
"\n"
"ctxx.addtest = ctxx.lutest.add_test\n"
"ctxx.test_eq = ctxx.lutest.eq\n"
"ctxx.test_neq = ctxx.lutest.neq\n"
"ctxx.run_lutest = ctxx.lutest.run_test\n"
"ctxx.frun_lutest = ctxx.lutest.frun_test\n"
"\n"
"\n"
"--called_as_main\n"
"if ctxx.ismain()  then \n"
"	ctxx.srcinfo( {\"^[*]\"}, \"@.?name[^\\n]*\\n\", _G.arg )\n"
"	print(\"\\ndocs. ~$ lua abc.lua 'hw' #>> find doc holding 'hw', show list if many\")\n"
"	print(\"select list. ~$ lua abc.lua 'alice' 3	#>> disp 3rd doc of list\")\n"
"	print(\"show api ~$ lua xyz.lua 'myf' 'mike$'	#>> search doc holding all luaptn\")\n"
"--	ctxx.sleep(10)\n"
"	return\n"
"--	os.exit(0)\n"
" end \n"
"--call_as_req\n"
"return ctxx\n"
"\n"
"--[[\n"
" change log\n"
" --\n"
"2021-11-27  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (brp): update build code\n"
"\n"
"2021-06-27  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (lutest): add dispflg, 0,1,2 + fix dispmsg\n"
"	\n"
"	* util.sh.lua (printf): add \\uU esc, fix test\n"
"\n"
"2021-06-18  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (luadoc_orange): reanme+fix lua_gazcmt\n"
"	\n"
"	* util.sh.lua (brp.sh): rewrite build script\n"
"\n"
"2021-05-17  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ismain): fix, add debug.getinfo(n) is nil or tb check\n"
"\n"
"2021-03-18  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (fprintf, flwrite): fix io.output() bug/code\n"
"\n"
"2021-03-18  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ckopt): add argtype test\n"
"\n"
"2021-03-03  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (laptime): fix disp msg, real >> sys.\n"
"\n"
"2021-01-31  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ismain): debug, use debug.getinfo().what\n"
"\n"
"2020-12-12  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ftinfo): fix keyname disp style, \"123\" 0x11 >> 123 :0x11\n"
"\n"
"2020-12-10  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (clit): support all c-posix esc. \\ooo, \\xFF, \\[abntvrf?\\'\"]\n"
"\n"
"2020-11-25  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tbdump): new\n"
"\n"
"	* util.sh.lua (laptime): add msg input api\n"
"\n"
"2020-11-20  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ftinfo): rewrite. code simplify. api isnt change.\n"
"\n"
"2020-11-10  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (lutest): omit some assert func.  v1.1.0.\n"
"\n"
"2020-11-08  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ckopt): change ini fmt. ckopt v1.1.0.\n"
"\n"
"	* util.sh.lua (ismwd): independent from util family, direct paste style\n"
"\n"
"2020-09-07  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tinfosub): change disp fmt, aligned (lptb) indent\n"
"\n"
"2020-09-05  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (strconv): add u8conv func, othername\n"
"	* (strconv): omit UPPERchar from unicode out\n"
"\n"
"2020-08-22  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (testeq_common): fix true/false logic, a1=(a1==a2) -> omit\n"
"\n"
"2020-07-29  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tbl2va): func omit. use tb2va.\n"
"	* (tb2va): new func. unpack/table.unpack wrapper.\n"
"\n"
"2020-07-17  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tbconv): add newname api, tblconv -> tbconv\n"
"	\n"
"	* util.sh.lua (tinfo): change inner msg, lptbl -> lptb\n"
"\n"
"2020-07-16  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tinfo): fix no exist func tinfosub() bug\n"
"	\n"
"	* util.sh.lua (S_FUNC): fix overlv err\n"
"	\n"
"	* util.sh.lua (srcnametop): change funcname, srctop -> srcnametop\n"
"	* (srcnamesuf): same\n"
"	\n"
"	* util.sh.lua (ismain): fix overlv bug\n"
"	\n"
"	* util.sh.lua (astmwd): omit. use assert( ismwd() ) \n"
"	* (ismwd): improve rtn false -> false, emsg \n"
"\n"
"2020-07-13  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (istypes): fix/add out of basic type info \"_\"\n"
"\n"
"2020-07-07  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ismwd, astmwd): make new func\n"
"\n"
"2020-07-04  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tinfo): change dflout nil --> io.stderr\n"
"	\n"
"	* util.sh.lua (tinfosub): fix str concat ..k.. to ..tostring(k).. \n"
"\n"
"2020-06-24  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (srcpath): add newfuncs, srcpath() family\n"
"	\n"
"	* util.sh.lua (S_FILE): fix apidoc typo\n"
"\n"
"2020-06-19  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (tinfo): add newfunc, ftinfo()\n"
"\n"
"2020-05-06  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ckopt): change 1st arg as setting inistr\n"
"\n"
"2020-05-05  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (ag2opt): fix -abc separate bug\n"
"\n"
"2020-05-01  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (fperr): fix errmsg '%s' pfmt bug\n"
"\n"
"2020-04-26  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (srcinfo): fix nohit msg, erange list select\n"
"	\n"
"	* util.sh.lua (ckopt): debug dflini reader, add changed flg tbl opt[0]\n"
"	\n"
"	* util.sh.lua (ag2opt): debug errrtn, stop or msg\n"
"\n"
"2020-04-07  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (*many*): fix/refacter/debug\n"
"\n"
"2020-04-05  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (istypes): add 'i'nteger typeck\n"
"	\n"
"	* util.sh.lua (tbl2va): fix invalid tail return at loadstring\n"
"\n"
"2020-04-04  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua (luadoc_orange): enable nil arg to luaptn\n"
"	* (grepmcmt): update argtype check\n"
"	\n"
"	* util.sh.lua (tblconv): fix seqn,indn work\n"
"\n"
"2020-04-04  Momi-g	<dmy@dmy.dmy>\n"
"\n"
"	* util.sh.lua : v1.0.0 releases.\n"
"]]\n"
/*94675*/
