NYAOS 3000でバッチファイルとかの拡張子を省略できるようにする

NYAOS 3000ではバッチファイルとかの拡張子を省略できない。これがけっこう不便なのでnyaos.filterを使って省略できるようにしてみた。

でも作ってから気がついたんだけど、もう既にid:thincaさんの続・NYAOS 3000 で bat ファイルとかを拡張子なしで実行する - 永遠に未完成があるんですね。一応の違いはパイプに対応しているという点と、suffixの拡張子は展開しないと言うところ。

5/26: パイプが使えなくなるバグを修正 / NYAOS3k 2.97_0のnyaos.filter2テーブルに対応
5/28: .vbs等が実行できないので補完する拡張子にPATHEXTを使わないように変更

-- MIT License (http://d.hatena.ne.jp/wantora/20101212/1292141801)

cmdutils = {}
cmdutils.pathext = {'.com', '.exe', '.bat', '.cmd'}

-- nnstring.cppのNnString::splitToより
function cmdutils.split(cmdline, sep)
	local quote = false
	local pos = 1
	
	while pos <= #cmdline do
		local s = cmdline:sub(pos, pos)
		
		if s == '"' then
			quote = not quote
		elseif s:match('^[\129-\159\224-\252]$') then
			pos = pos + 1
		elseif (not quote) and s:match(sep) then
			break
		end
		
		pos = pos + 1
	end
	
	return cmdline:sub(1, pos - 1), cmdline:sub(pos + 1), cmdline:sub(pos, pos)
end

local function command_appendext(cmd)
	local names = {}
	
	for _, ext in ipairs(cmdutils.pathext) do
		if cmd:lower():match(ext .. '$') then return cmd end
		table.insert(names, cmd .. ext)
	end
	
	for dir in ('.;'..os.getenv('PATH')):gmatch('[^;]+') do
		for _, name in ipairs(names) do
			if nyaos.access(dir..'\\'..name, 0) then return name end
		end
	end
	
	return cmd
end

local function command_expand(cmdline)
	local cmd, rest, sep = cmdutils.split(cmdline:gsub('^%s*', ''), '%s')
	
	local cmd2 = cmd:match('^"(.*)"$')
	if cmd2 then
		cmd = '"'..command_appendext(cmd2)..'"'
	else
		cmd = command_appendext(cmd)
	end
	
	return cmdline:match('^%s*')..cmd..sep..rest
end

function nyaos.filter2.expandext(cmdline)
	local cmds = {}
	local first, rest, sep = nil, cmdline
	
	while #rest > 0 do
		first, rest, sep = cmdutils.split(rest, '|')
		table.insert(cmds, command_expand(first))
		table.insert(cmds, sep)
	end
	
	return table.concat(cmds)
end