Advertisement
Xetrill

xs_fs.script

Oct 18th, 2013
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.06 KB | None | 0 0
  1. --[[-----------------------------------------------------------------------\\--
  2.     :: PRIVATE ::
  3. --\\-----------------------------------------------------------------------]]--
  4.  
  5. local type, concat, insert, remove, flines, tostring
  6.     = type, table.concat, table.insert, table.remove, io.lines, tostring
  7.  
  8. local m_cwd
  9. local m_roots = {}
  10.  
  11. --[[-----------------------------------------------------------------------\\--
  12.     :: PUBLIC ::
  13. --\\-----------------------------------------------------------------------]]--
  14.  
  15. __FILE__ = "xs_fs"
  16.  
  17. local function isGamePath()
  18.     return s and s:len() > 2 and s:sub(1, 1) == '$' and s:sub(-1) == '$'
  19. end
  20.  
  21. function trailingSlash(path)
  22.     if path:find("\\", path:len(), true) ~= nil then
  23.         return path
  24.     end
  25.     return path .. "\\"
  26. end
  27.  
  28. function basename(path)
  29.     if path:sub(-1) == '\\' then
  30.         path = path:sub(1, path:len() - 1)
  31.     end
  32.  
  33.     do
  34.         local markDir = path:find('\\[^\\]*$')
  35.         local markExt = path:find('.', markDir or 1, true)
  36.  
  37.         if markDir and markExt then
  38.             return path:sub(markDir + 1, markExt - 1)
  39.         elseif markDir and not markExt then
  40.             return path:sub(markDir + 1)
  41.         elseif not markDir and markExt then
  42.             return path:sub(1, markExt - 1)
  43.         end
  44.     end
  45.  
  46.     return path
  47. end
  48.  
  49. -- Takes a relative path and combines it with a root path.
  50. -- Note: This is a 'dump' implementation, it's just some string operations.
  51. -- @param path  the relative path to be rooted.
  52. -- @param root  the root path (can be a fsgame.ltx reference)
  53. -- @return the rooted path
  54. function rootPath(path, root)
  55.     if isGamePath(root) then
  56.         root = gamePath(root)
  57.     end
  58.  
  59.     if path:find(root, 1, true) then
  60.         return path
  61.     end
  62.  
  63.     return trailingSlash(root) .. path
  64. end
  65.  
  66. -- Takes a full (or absolute) path and unroots it, via the given root path.
  67. function leafPath(fullpath, root)
  68.     if isGamePath(root) then
  69.         root = gamePath(root)
  70.     end
  71.     if fullpath:find(root, 1, true) ~= nil then
  72.         return fullpath:sub(root:len() + 1)
  73.     else
  74.         return fullpath
  75.     end
  76. end
  77.  
  78. function getDirectory(path, up)
  79.     if not path or path:len() == 0 then
  80.         return nil
  81.     end
  82.  
  83.     local dirs = xs_utils.split('\\', path)
  84.     if dirs[#dirs]:find('.', -4, true) then
  85.         remove(dirs)
  86.     end
  87.  
  88.     up = up or 0
  89.     while up > 0 do
  90.         remove(dirs)
  91.         up = up - 1
  92.     end
  93.  
  94.     return concat(dirs, '\\')
  95. end
  96.  
  97. -- Retrieves all INI/LTX sections from the specified file, it does so by reading
  98. -- the file line for line and parsing the relevant information.
  99. -- Note, that this function DOES NOT cache any results and should therefore be
  100. -- using with caution and care, and of course rarely.
  101. -- @games CS, CoP
  102. -- @param string path  The file to parse.
  103. -- @param boolean deep  [Optional, default: true]
  104. --                    If true then #includes will be parsed and processed.
  105. -- @return table A listing of all sections from the file specified with path.
  106. function listSections(path, deep)
  107.     if deep == nil then
  108.         deep = true
  109.     end
  110.  
  111.     local root = gamePath('$game_config$')
  112.     path = rootPath(path, root)
  113.  
  114.     local work = { path }
  115.     local list = {}
  116.     local trim = xs_utils.trim
  117.  
  118.     repeat
  119.         local file = remove(work)
  120.  
  121.         -- TODO: Change to use ini_file() instead of Lua's IO. This allows for reading files
  122.         -- from the game's .db archives too.
  123.         for line in flines(file) do
  124.             repeat
  125.                 local line = trim(line)
  126.                 if line:len() == 0 then
  127.                     break
  128.                 end
  129.  
  130.                 if deep and line:sub(1, 8) == '#include' then
  131.                     local b = line:find('"', 8, true) + 1
  132.                     local e = line:find('"', b, true) - 1
  133.                     insert(work, rootPath(line:sub(b, e), getDirectory(file)))
  134.                     break
  135.                 end
  136.  
  137.                 if line:sub(1, 1) ~= '[' then
  138.                     break
  139.                 end
  140.  
  141.                 local mark = (line:find(']', 2, true) or 0) - 1
  142.                 if mark < 0 then
  143.                     break
  144.                 end
  145.  
  146.                 insert(list, line:sub(2, mark))
  147.             until true
  148.         end
  149.     until #work == 0
  150.  
  151.     return list
  152. end
  153.  
  154. function getcwd()
  155.     if m_cwd == nil then
  156.         if io.cwd then
  157.             m_cwd = io.cwd()
  158.         elseif _G.getFS then
  159.             m_cwd = _G.getFS():update_path("$fs_root$", "") or ""
  160.         else
  161.             -- to run from command line
  162.             local p = io.popen('cd')
  163.             m_cwd = trailingSlash(getDirectory(p:read('*l'), 2))
  164.             p:close()
  165.         end
  166.     end
  167.     return m_cwd
  168. end
  169.  
  170. function gamePath(root, ...)
  171.     if type(root) ~= 'string' or root:sub(1, 1) ~= '$' then
  172.         abort('[xs_fs.gamePath]: Invalid #1 argument: %s.' ,tostring(root))
  173.     end
  174.  
  175.     if #m_roots == 0 then
  176.         m_roots['$fs_root$'] = trailingSlash(getcwd())
  177.  
  178.         local trim, map, split -- We Don't Want No[oo] Glo[ooo]bal Lookups!
  179.             = xs_utils.trim, xs_utils.map, xs_utils.split
  180.  
  181.         local paths = {}
  182.         for line in flines(m_roots['$fs_root$'] .. 'fsgame.ltx') do
  183.             repeat
  184.                 line = trim(line)
  185.  
  186.                 if line:len() == 0 or line:find(';', 1, true) == 1 then -- say no to waste
  187.                     break
  188.                 end
  189.  
  190.                 local mark = line:find('=', 1, true)
  191.                 if mark == nil then -- what did you do?!
  192.                     break -- abort() here? after all it means fsgame.ltx is screwed up
  193.                 end
  194.  
  195.                 local key   = trim(line:sub(1, mark - 1))
  196.                 local parts = map(split("|", line:sub(mark + 1)), trim)
  197.  
  198.                 -- parts[1]: (string-boolean, required) recursive
  199.                 -- parts[2]: (string-boolean, required) 'notif' huh? STALKER has NO resource management, so?
  200.                 -- parts[3]: (string, required) root key OR absolute path (app_data_root)
  201.                 -- parts[4]: (string, optional) relative path
  202.                 -- parts[5]: (string, optional) windows wildcard mask (*.ext)
  203.                 -- parts[6]: (string, optional) description
  204.  
  205.                 if #parts > 3 then
  206.                     paths[key] = { path = parts[4], root = parts[3] }
  207.                 elseif parts[3]:sub(1, 1) == '$' then
  208.                     paths[key] = { path = '',       root = parts[3] }
  209.                 else
  210.                     paths[key] = { path = parts[3] }
  211.                 end
  212.             until true
  213.  
  214.             -- This requires that $app_data_root$ is the very first entry in fsgame.ltx
  215.             -- and that $fs_root$ has already been discoverd.
  216.             for key, info in pairs(paths) do
  217.                 if info.root ~= nil then
  218.                     m_roots[key] = trailingSlash(m_roots[info.root]) .. trailingSlash(info.path)
  219.                 else
  220.                     m_roots[key] = trailingSlash(info.path)
  221.                 end
  222.             end
  223.         end
  224.     end
  225.  
  226.     if ... == nil then
  227.         return m_roots[root]
  228.     else
  229.         return m_roots[root] .. concat({ ... }, '\\')
  230.     end
  231. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement