Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local args = {...}
- --- The options that the user specified
- local plain = false
- local count = nil
- local ignoreCase = false
- local writeNamesOnce = false
- local lineNumber = nil
- local quiet = false
- local fileError = true
- local invert = false
- local matchWhole = false
- local printNames = false
- --- Table with patterns to check for
- local patternList = {}
- --- Table with paths to files that hold patterns
- local patternFiles = {}
- --- An iterator that will return the next line from the input
- local readLines
- --- A function to parse all the command line arguments and stores them in the options table/pattern list/patternfile
- local function parseOptions(args, options, printMsg, errorMsg)
- if not args or not options then
- return false, "The arguments and the valid options have to be given."
- end
- errorMsg = errorMsg or 'Not a valid option: '
- local current = nil
- local pos = 1
- return function()
- if #args <= 0 then
- return nil, 'Nothing left to process'
- end
- if not current or #current < pos then
- if string.find(args[1], "^%-%w") then
- current = string.sub(args[1], 2, #args[1])
- pos = 1
- table.remove(args, 1)
- else
- return nil
- end
- end
- local char = current:sub(pos,pos)
- pos = pos + 1
- if char == '-' then
- return nil
- end
- local i, j = string.find(options, char..':*')
- if not i then
- if printMsg then
- print(errorMsg..char)
- end
- return false, char
- elseif j - i == 0 then
- return char, nil
- elseif j - i == 1 then
- if not args[1] or args[1]:sub(1,1) == '-' then
- return false, char..' needs an argument'
- else
- return char, table.remove(args, 1)
- end
- elseif j - i == 2 then
- if args[1] and args[1]:sub(1,1) ~= '-' then
- return char, table.remove(args, 1)
- else
- return char, nil
- end
- end
- end
- end
- --- A function that prints the usage of Grep
- local function printUsage()
- print('Usage: '..shell.getRunningProgram()..' [-F][-c| -l| -q][-insvx] [-e pattern] [-f file] [pattern] [file...]')
- end
- local function fileError(file)
- if opts.fileError then
- print(shell.getRunningProgram()..': '..file..': No such file or directory')
- end
- end
- --- A function to process the command line arguments
- local function processOptions()
- for opt, arg in parseOptions(args, 'Fce:f:ilnqsvx') do
- if opt == 'F' then
- plain = true
- elseif opt == 'c' then
- counter = 0
- elseif opt == 'e' then
- table.insert(patternList, arg)
- elseif opt == 'f' then
- table.insert(patternFile, shell.resolve(arg))
- elseif opt == 'i' then
- ignoreCase = true
- elseif opt == 'l' then
- writeNamesOnce = true
- elseif opt == 'n' then
- lineNumber = 1
- elseif opt == 'q' then
- quiet = true
- elseif opt == 's' then
- fileError = false
- elseif opt == 'v' then
- invert = true
- elseif opt == 'x' then
- matchWhole = true
- elseif opt == 'E' then
- elseif opt == false then
- printUsage()
- return false
- end
- end
- --- Read the pattern files and add the patterns to the patternList
- for i = 1, #patternFiles do
- if fs.exists(patternFiles[i]) then
- file = io.open(patternFiles[i], 'r')
- for pat in file:lines() do
- table.insert(patternList, pat)
- end
- file:close()
- else
- fileError(patternFiles[i])
- end
- end
- --- Check if their are patterns, if not, get args[1] and add it to the list
- if #patternList == 0 then
- if #args < 1 then
- printUsage()
- return false -- No patterns and no arguments, end the program
- else
- table.insert(patternList, table.remove(args, 1))
- end
- end
- --- Prepare an interator for reading
- if #args > 0 then
- readLines = function()
- local files = args
- local curHand = nil
- local curFile
- return function()
- if not curFile and #files > 0 then -- No current file, but there are files left
- if fs.exists(files[1]) then
- curFile = table.remove(files, 1)
- curHand = fs.open(curFile, 'r')
- if lineNumber then lineNumber = 1 end
- else
- fileError(tables.remove(files, 1))
- return false
- end
- end
- local line = curHand.readLine()
- if not line then
- curFile = nil
- curHand.close()
- if #files < 1 then
- return nil
- else
- return false
- end
- else
- return line, curFile
- end
- end
- end
- else
- readLines = function() return read end
- end
- return true
- end
- local function printMatchedLine(line, file)
- if not count then
- if matchFile ~= file and writeNamesOnce then
- print(file)
- elseif printNames and not count then
- write(file..':')
- end
- if lineNumber then write(lineNumber..':') end
- print(line)
- elseif matchFile ~= file then
- if printNames then write(matchFile..':') end
- print(count)
- count = 1
- else
- count = count + 1
- end
- end
- --- Builds a case insensitive pattern, code from stackOverflow (questions/11401890/case-insensitive-lua-pattern-matching)
- local function caseInsensitivePattern(pattern)
- -- find an optional '%' (group 1) followed by any character (group 2)
- local p = pattern:gsub("(%%?)(.)", function(percent, letter)
- if percent ~= "" or not letter:match("%a") then
- -- if the '%' matched, or `letter` is not a letter, return "as is"
- return percent .. letter
- else
- -- else, return a case-insensitive character class of the matched letter
- return string.format("[%s%s]", letter:lower(), letter:upper())
- end
- end)
- return p
- end
- --- Main
- if #args < 1 then
- printUsage()
- return 2
- end
- if not processOptions() then
- return 2
- end
- if #args > 1 then printNames = true end
- local matchFile = nil
- for line, file in readLines() do
- if line then
- local match = false
- for _, pattern in pairs(patternList) do
- if ignoreCase then pattern = caseInsensitivePattern(pattern) end
- local i, j = line:find(pattern, 1, plain)
- if not matchWhole then
- match = i and true or match
- else
- if j == #line and i == 1 then match = true end
- end
- end
- if match ~= invert then
- if quiet then return 0 end
- if not count then
- if matchFile ~= file and writeNamesOnce then
- print(file)
- elseif printNames and not count then
- write(file..':')
- end
- if lineNumber then write(lineNumber..':') end
- print(line)
- elseif matchFile ~= file then
- if printNames then write(matchFile..':') end
- print(count)
- count = 1
- else
- count = count + 1
- end
- matchFile = file
- end
- if lineNumber then lineNumber = lineNumber + 1 end
- end
- end
- return matchFile and 0 or 1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement