--****************************************************************************
-- @file Parent script "shell_search"
-- @author Valentin Schmidt
-- @version 0.2
-- @desc Implements file search based on Shell Xtra
-- @requires xtra("Shell")
--****************************************************************************
property _sx
property _cbResult
property _cbTarget
property _result
property _detacher
----------------------------------------
-- Only a single instance is needed for all searches in the movie's lifetime.
-- But multiple concurrent asynchronous searches are not supported.
-- @constructor
----------------------------------------
on new (me)
me._sx = xtra("Shell").new()
return me
end
----------------------------------------
-- Blocking search (synchronous)
-- @param {string} searchDir - Supports environment variables like %USERPROFILE%, %APPDATA% etc.
-- @param {string} searchTerm - Supports wildcards "*" (any number of any characters) and "?" (any single character)
-- @param {bool} [firstOnly=FALSE] - If set to TRUE, the search stops when a result was found
-- @return {list}
----------------------------------------
on search (me, searchDir, searchTerm, firstOnly)
q = QUOTE
if (searchTerm contains "*") or (searchTerm contains "?") then
cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&") do @(echo %f"
if firstOnly then put "&exit" after cmd
put ")" after cmd
else
patt = searchTerm.char[1..searchTerm.length-1]&"?"
cmd = "for /r "&q&searchDir&q&" %f in ("&patt&") do @(if %~nxf=="&searchTerm&" (echo %f"
if firstOnly then put "&exit" after cmd
put "))" after cmd
end if
return me._sx.shell_cmd(cmd, ["timeout":0, "return_list":1])
end
----------------------------------------
-- Non-blocking search (asynchronous)
-- @param {string} searchDir - Supports environment variables like %USERPROFILE%, %APPDATA% etc.
-- @param {string} searchTerm - Supports wildcards "*" (any number of any characters) and "?" (any single character)
-- @param {bool} firstOnly - If set to TRUE, the search stops when a result was found
-- @param {symbol} resultCallback
-- @param {object} [resultTarget=_movie]
----------------------------------------
on searchAsync (me, searchDir, searchTerm, firstOnly, resultCallback, resultTarget)
if voidP(resultTarget) then resultTarget = _movie
me._cbResult = resultCallback
me._cbTarget = resultTarget
q = QUOTE
if (searchTerm contains "*") or (searchTerm contains "?") then
cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&") do @(echo %f"
if firstOnly then put "&exit" after cmd
put ")" after cmd
else
cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&"*) do @(if "&q&"%~nxf"&q&"=="&q&searchTerm&q&" (echo %f"
if firstOnly then put "&exit" after cmd
put "))" after cmd
end if
me._result = ""
me._sx.shell_cmd_thread_stop() -- just in case
me._sx.shell_cmd_thread(cmd, ["timeout":0, "cb_target":me, "cb_stdout":#_cbResult, "cb_complete":#_cbComplete])
end
----------------------------------------
-- Stops the current asynchronous search process
----------------------------------------
on searchAsyncStop (me)
me._sx.shell_cmd_thread_stop()
end
----------------------------------------
-- @private
-- @callback
----------------------------------------
on _cbResult (me, res)
put res after _result
end
----------------------------------------
-- @private
-- @callback
----------------------------------------
on _cbComplete (me)
me._detacher = timeout().new("_detach_", 1, #_cbCompleteDetached, me)
end
----------------------------------------
-- @private
----------------------------------------
on _cbCompleteDetached (me)
me._detacher.forget()
resList = me._explode(numtochar(13)&numtochar(10), me._result)
resList.deleteAt(resList.count)
call(me._cbResult, me._cbTarget, resList)
end
----------------------------------------
-- Explodes string into list
-- @private
-- @param {string} delim
-- @param {string} str
-- @return {list}
----------------------------------------
on _explode (me, delim, str)
l = []
if voidP(str) then return l
dl = length(delim)
repeat while TRUE
pos = offset(delim,str)
if pos=0 then exit repeat
if pos>1 then
l.add(str.char[1..pos-1])
else
l.add("")
end if
delete char 1 to pos+dl-1 of str
end repeat
if pos=0 then pos = 1-dl
l.add(str.char[pos+dl..str.length])
return l
end