#! lua

assert(riscos.version,"DigDirSED requires RiscLua 5.00 or later")
local cfg = assert(dofile "<DigDirSED$Dir>.config", "Bad config syntax")

local sys,dir in riscos
local dim = \ (s) => s .. '\0' end -- is nothing sacred?

local result  = false
local thisdir = cfg.directory
local pathpat = cfg.pathpattern.." "
local textpat = cfg.textpattern
local exclusiontypes = cfg.exclusiontypes
local exclusionpath  = cfg.exclusionpath
local casesensitive  = cfg.casesensitive

local dirtype_OK = { }
for _, t in ipairs (cfg.dirtypes) do
  dirtype_OK[t] = true
end -- for

local filetype_OK = { }
for _, t in ipairs (cfg.filetypes) do
  filetype_OK[t] = true
end -- for

--[[
-- Convert our textpattern such that the search becomes case insensitive
-- We do this by replacing each letter with [Xx], ie 'a' becomes [Aa] etc.
-- We need to be careful about classes though, so they are temporarily
-- converted to numbers (%a -> %96) and turned back afterwards.
--]]
function caseless(pat)
  pat = string.gsub(pat, '%%(%a)', function (v) return "%"..string.byte(v) end)
  pat = string.gsub(pat, '(%a)', function (v) return '['..string.upper(v)..string.lower(v)..']' end)
  pat = string.gsub(pat, '%%(%d+)', function (v) return "%"..string.char(v) end)
  return pat
end -- function


--[[
--]]
function filetypeMatch(fileType)
  local match = (filetype_OK[fileType] == true)
  if exclusiontypes then match = not match end
  return match
end -- function


--[[
--]]
function pathMatch(pPtr,fPtr,allowDot)
  local diff,invert,match,stop,fChr,pChr

  repeat
    if string.sub(pathpat,pPtr,pPtr) == "*" then
      allowDot = false ; pPtr = pPtr + 1
      if string.sub(pathpat,pPtr,pPtr) == "*" then
        allowDot = true ; pPtr = pPtr + 1
      end -- if

      repeat
        match = pathMatch(pPtr,fPtr,allowDot)
        stop = match
        if not stop then
          pChr = string.sub(pathpat,pPtr,pPtr)
          fChr = string.sub(fileName,fPtr,fPtr) ; fPtr = fPtr + 1

          if fChr <= " " then match = (pChr <= " ") ; stop = true end -- if
          if fChr == "." and not allowDot then match = false ; stop = true end -- if
        end -- if
      until (stop)
    else
      pChr = string.sub(pathpat,pPtr,pPtr) ; pPtr = pPtr + 1
      fChr = string.sub(fileName,fPtr,fPtr) ; fPtr = fPtr + 1
      --      diff = bit32.band(bit32.bxor(pChr, fChr), 0xDF)
      diff = (string.byte(pChr) ^^ string.byte(fChr)) & 0xDF

      if diff ~= 0 then stop = true end
      if pChr == ";" then pChr = string.char(0x0) end
      if (pChr <= " ") or (fChr <= " ") then stop = true end
      if stop then match = (pChr <= " ") and (fChr <= " ") end
    end -- if

  until (stop)
  return match
end -- function


--[[
--]]
function searchdir(thisdir,textpat)
  --print(thisdir)
  for leaf,ftype in dir(thisdir) do
    --print(leaf,ftype)
    --print(filetype_OK[ftype])
    local path = thisdir.."."..leaf
    fileName = path.." "
    if ftype >= 0x1000 then
      if dirtype_OK[ftype] then searchdir(path,textpat) end
    elseif filetypeMatch(ftype) then
      if pathMatch(1,1,false) ~= exclusionpath then
        local linenumber = 0
        for line in io.lines(path) do
          linenumber = linenumber + 1
          local match = line:find(textpat)
          if match then
            result = true
            sys("DDEUtils_ThrowbackSend",2,0,dim(path),linenumber,0,dim(line))
          end -- if
        end -- for
      end -- if
    end -- if
  end -- for
end -- function

if not casesensitive then textpat = caseless(textpat) end
sys("DDEUtils_ThrowbackStart")
searchdir(thisdir,textpat)
if not result then
  local message = "Nothing found"
  sys("DDEUtils_ThrowbackSend",2,0,dim(thisdir),1,0,dim(message))
end -- if
sys("DDEUtils_ThrowbackEnd")
sys("OS_CLI",dim("Sound 1 &4000 &5000 10"))

