1. --****************************************************************************
  2. -- @file Parent script "shell_search"
  3. -- @author Valentin Schmidt
  4. -- @version 0.2
  5. -- @desc Implements file search based on Shell Xtra
  6. -- @requires xtra("Shell")
  7. --****************************************************************************
  8.  
  9. property _sx
  10. property _cbResult
  11. property _cbTarget
  12. property _result
  13. property _detacher
  14.  
  15. ----------------------------------------
  16. -- Only a single instance is needed for all searches in the movie's lifetime.
  17. -- But multiple concurrent asynchronous searches are not supported.
  18. -- @constructor
  19. ----------------------------------------
  20. on new (me)
  21.     me._sx = xtra("Shell").new()
  22.     return me
  23. end
  24.  
  25. ----------------------------------------
  26. -- Blocking search (synchronous)
  27. -- @param {string} searchDir - Supports environment variables like %USERPROFILE%, %APPDATA% etc.
  28. -- @param {string} searchTerm - Supports wildcards "*" (any number of any characters) and "?" (any single character)
  29. -- @param {bool} [firstOnly=FALSE] - If set to TRUE, the search stops when a result was found
  30. -- @return {list}
  31. ----------------------------------------
  32. on search (me, searchDir, searchTerm, firstOnly)
  33.     q = QUOTE
  34.     if (searchTerm contains "*") or (searchTerm contains "?") then
  35.         cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&") do @(echo %f"
  36.         if firstOnly then put "&exit" after cmd
  37.         put ")" after cmd
  38.     else
  39.         patt = searchTerm.char[1..searchTerm.length-1]&"?"
  40.         cmd = "for /r "&q&searchDir&q&" %f in ("&patt&") do @(if %~nxf=="&searchTerm&" (echo %f"
  41.         if firstOnly then put "&exit" after cmd
  42.         put "))" after cmd
  43.     end if
  44.     return me._sx.shell_cmd(cmd, ["timeout":0, "return_list":1])
  45. end
  46.  
  47. ----------------------------------------
  48. -- Non-blocking search (asynchronous)
  49. -- @param {string} searchDir - Supports environment variables like %USERPROFILE%, %APPDATA% etc.
  50. -- @param {string} searchTerm - Supports wildcards "*" (any number of any characters) and "?" (any single character)
  51. -- @param {bool} firstOnly - If set to TRUE, the search stops when a result was found
  52. -- @param {symbol} resultCallback
  53. -- @param {object} [resultTarget=_movie]
  54. ----------------------------------------
  55. on searchAsync (me, searchDir, searchTerm, firstOnly, resultCallback, resultTarget)
  56.     if voidP(resultTarget) then resultTarget = _movie
  57.     me._cbResult = resultCallback
  58.     me._cbTarget = resultTarget
  59.     q = QUOTE
  60.     if (searchTerm contains "*") or (searchTerm contains "?") then
  61.         cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&") do @(echo %f"
  62.         if firstOnly then put "&exit" after cmd
  63.         put ")" after cmd
  64.     else
  65.         cmd = "for /r "&q&searchDir&q&" %f in ("&searchTerm&"*) do @(if "&q&"%~nxf"&q&"=="&q&searchTerm&q&" (echo %f"
  66.         if firstOnly then put "&exit" after cmd
  67.         put "))" after cmd
  68.     end if
  69.     me._result = ""
  70.     me._sx.shell_cmd_thread_stop() -- just in case
  71.     me._sx.shell_cmd_thread(cmd, ["timeout":0, "cb_target":me, "cb_stdout":#_cbResult, "cb_complete":#_cbComplete])
  72. end
  73.  
  74. ----------------------------------------
  75. -- Stops the current asynchronous search process
  76. ----------------------------------------
  77. on searchAsyncStop (me)
  78.     me._sx.shell_cmd_thread_stop()
  79. end
  80.  
  81. ----------------------------------------
  82. -- @private
  83. -- @callback
  84. ----------------------------------------
  85. on _cbResult (me, res)
  86.     put res after _result
  87. end
  88.  
  89. ----------------------------------------
  90. -- @private
  91. -- @callback
  92. ----------------------------------------
  93. on _cbComplete (me)
  94.     me._detacher = timeout().new("_detach_", 1, #_cbCompleteDetached, me)
  95. end
  96.  
  97. ----------------------------------------
  98. -- @private
  99. ----------------------------------------
  100. on _cbCompleteDetached (me)
  101.     me._detacher.forget()
  102.     resList = me._explode(numtochar(13)&numtochar(10), me._result)
  103.     resList.deleteAt(resList.count)
  104.     call(me._cbResult, me._cbTarget, resList)
  105. end
  106.  
  107. ----------------------------------------
  108. -- Explodes string into list
  109. -- @private
  110. -- @param {string} delim
  111. -- @param {string} str
  112. -- @return {list}
  113. ----------------------------------------
  114. on _explode (me, delim, str)
  115.     l = []
  116.     if voidP(str) then return l
  117.     dl = length(delim)
  118.     repeat while TRUE
  119.         pos = offset(delim,str)
  120.         if pos=0 then exit repeat
  121.         if pos>1 then
  122.             l.add(str.char[1..pos-1])
  123.         else
  124.             l.add("")
  125.         end if
  126.         delete char 1 to pos+dl-1 of str
  127.     end repeat
  128.     if pos=0 then pos = 1-dl
  129.     l.add(str.char[pos+dl..str.length])
  130.     return l
  131. end
  132.  
[raw code]