diff options
| -rw-r--r-- | lualibs-dir.lua | 303 | ||||
| -rw-r--r-- | lualibs-lpeg.lua | 82 | ||||
| -rw-r--r-- | lualibs-table.lua | 80 | ||||
| -rw-r--r-- | lualibs-util-prs.lua | 30 | ||||
| -rw-r--r-- | lualibs-util-str.lua | 25 | 
5 files changed, 370 insertions, 150 deletions
diff --git a/lualibs-dir.lua b/lualibs-dir.lua index 2572120..660529b 100644 --- a/lualibs-dir.lua +++ b/lualibs-dir.lua @@ -9,7 +9,7 @@ if not modules then modules = { } end modules ['l-dir'] = {  -- dir.expandname will be merged with cleanpath and collapsepath  local type, select = type, select -local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub  local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack  local lpegmatch = lpeg.match @@ -21,8 +21,8 @@ local lfs = lfs  local attributes = lfs.attributes  local walkdir    = lfs.dir -local isdir      = lfs.isdir -local isfile     = lfs.isfile +local isdir      = lfs.isdir  -- not robust, will be overloaded anyway +local isfile     = lfs.isfile -- not robust, will be overloaded anyway  local currentdir = lfs.currentdir  local chdir      = lfs.chdir  local mkdir      = lfs.mkdir @@ -31,20 +31,36 @@ local onwindows  = os.type == "windows" or find(os.getenv("PATH"),";",1,true)  -- in case we load outside luatex -if not isdir then -    function isdir(name) -        local a = attributes(name) -        return a and a.mode == "directory" +if onwindows then + +    -- lfs.isdir does not like trailing / +    -- lfs.dir accepts trailing / + +    isdir = function(name) +        name = gsub(name,"([/\\]+)$","/.") +        return attributes(name,"mode") == "directory"      end -    lfs.isdir = isdir -end -if not isfile then -    function isfile(name) -        local a = attributes(name) -        return a and a.mode == "file" +    isfile = function(name) +        return attributes(name,"mode") == "file" +    end + +    lfs.isdir  = isdir +    lfs.isfile = isfile + +else + +    isdir = function(name) +        return attributes(name,"mode") == "directory"      end + +    isfile = function(name) +        return attributes(name,"mode") == "file" +    end + +    lfs.isdir  = isdir      lfs.isfile = isfile +  end  -- handy @@ -53,63 +69,104 @@ function dir.current()      return (gsub(currentdir(),"\\","/"))  end --- optimizing for no find (*) does not save time - ---~ local function globpattern(path,patt,recurse,action) -- fails in recent luatex due to some change in lfs ---~     local ok, scanner ---~     if path == "/" then ---~         ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe ---~     else ---~         ok, scanner = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe ---~     end ---~     if ok and type(scanner) == "function" then ---~         if not find(path,"/$") then path = path .. '/' end ---~         for name in scanner do ---~             local full = path .. name ---~             local mode = attributes(full,'mode') ---~             if mode == 'file' then ---~                 if find(full,patt) then ---~                     action(full) ---~                 end ---~             elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then ---~                 globpattern(full,patt,recurse,action) ---~             end ---~         end ---~     end ---~ end - -local lfsisdir = isdir - -local function isdir(path) -    path = gsub(path,"[/\\]+$","") -    return lfsisdir(path) -end +-- somewhat optimized -lfs.isdir = isdir +local function glob_pattern_function(path,patt,recurse,action) +    if isdir(path) then +        local usedpath +        if path == "/" then +            usedpath = "/." +        elseif not find(path,"/$") then +            usedpath = path .. "/." +            path = path .. "/" +        else +            usedpath = path +        end +        local dirs +        for name in walkdir(usedpath) do +            if name ~= "." and name ~= ".." then +                local full = path .. name +                local mode = attributes(full,'mode') +                if mode == 'file' then +                    if not patt or find(full,patt) then +                        action(full) +                    end +                elseif recurse and mode == "directory" then +                    if not dirs then +                        dirs = { full } +                    else +                        dirs[#dirs+1] = full +                    end +                end +            end +        end +        if dirs then +            for i=1,#dirs do +                glob_pattern_function(dirs[i],patt,recurse,action) +            end +        end +    end +end -local function globpattern(path,patt,recurse,action) -    if path == "/" then -        path = path .. "." -    elseif not find(path,"/$") then -        path = path .. '/' +local function glob_pattern_table(path,patt,recurse,result) +    if not result then +        result = { }      end -    if isdir(path) then -- lfs.isdir does not like trailing / -        for name in walkdir(path) do -- lfs.dir accepts trailing / -            local full = path .. name -            local mode = attributes(full,'mode') -            if mode == 'file' then -                if find(full,patt) then -                    action(full) +    if isdir(path) then +        local usedpath +        if path == "/" then +            usedpath = "/." +        elseif not find(path,"/$") then +            usedpath = path .. "/." +            path = path .. "/" +        else +            usedpath = path +        end +        local dirs +        for name in walkdir(usedpath) do +            if name ~= "." and name ~= ".." then +                local full = path .. name +                local mode = attributes(full,'mode') +                if mode == 'file' then +                    if not patt or find(full,patt) then +                        result[#result+1] = full +                    end +                elseif recurse and mode == "directory" then +                    if not dirs then +                        dirs = { full } +                    else +                        dirs[#dirs+1] = full +                    end                  end -            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then -                globpattern(full,patt,recurse,action)              end          end +        if dirs then +            for i=1,#dirs do +                glob_pattern_table(dirs[i],patt,recurse,result) +            end +        end +    end +    return result +end + +local function globpattern(path,patt,recurse,method) +    local kind = type(method) +    if pattern and sub(patt,1,-3) == path then +        patt = false +    end +    if kind == "function" then +        return glob_pattern_function(path,patt,recurse,method) +    elseif kind == "table" then +        return glob_pattern_table(path,patt,recurse,method) +    else +        return glob_pattern_table(path,patt,recurse,{ })      end  end  dir.globpattern = globpattern +-- never or seldom used so far: +  local function collectpattern(path,patt,recurse,result)      local ok, scanner      result = result or { } @@ -119,18 +176,26 @@ local function collectpattern(path,patt,recurse,result)          ok, scanner, first = xpcall(function() return walkdir(path)      end, function() end) -- kepler safe      end      if ok and type(scanner) == "function" then -        if not find(path,"/$") then path = path .. '/' end +        if not find(path,"/$") then +            path = path .. '/' +        end          for name in scanner, first do -            local full = path .. name -            local attr = attributes(full) -            local mode = attr.mode -            if mode == 'file' then -                if find(full,patt) then +            if name == "." then +                -- skip +            elseif name == ".." then +                -- skip +            else +                local full = path .. name +                local attr = attributes(full) +                local mode = attr.mode +                if mode == 'file' then +                    if find(full,patt) then +                        result[name] = attr +                    end +                elseif recurse and mode == "directory" then +                    attr.list = collectpattern(full,patt,recurse)                      result[name] = attr                  end -            elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then -                attr.list = collectpattern(full,patt,recurse) -                result[name] = attr              end          end      end @@ -143,15 +208,10 @@ local separator  if onwindows then -- we could sanitize here ---     pattern = Ct { ---         [1] = (C(P(".") + S("/\\")^1) + C(R("az","AZ") * P(":") * S("/\\")^0) + Cc("./")) * V(2) * V(3), ---         [2] = C(((1-S("*?/\\"))^0 * S("/\\"))^0), ---         [3] = C(P(1)^0) ---     } -      local slash = S("/\\") / "/" -    pattern = Ct { +--     pattern = Ct { +    pattern = {          [1] = (Cs(P(".") + slash^1) + Cs(R("az","AZ") * P(":") * slash^0) + Cc("./")) * V(2) * V(3),          [2] = Cs(((1-S("*?/\\"))^0 * slash)^0),          [3] = Cs(P(1)^0) @@ -159,7 +219,8 @@ if onwindows then -- we could sanitize here  else -- assume unix -    pattern = Ct { +--     pattern = Ct { +    pattern = {          [1] = (C(P(".") + P("/")^1) + Cc("./")) * V(2) * V(3),          [2] = C(((1-S("*?/"))^0 * P("/"))^0),          [3] = C(P(1)^0) @@ -186,12 +247,11 @@ local function glob(str,t)          elseif isfile(str) then              t(str)          else -            local split = lpegmatch(pattern,str) -- we could use the file splitter -            if split then -                local root, path, base = split[1], split[2], split[3] +            local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter +            if root and path and base then                  local recurse = find(base,"**",1,true) -- find(base,"%*%*") -                local start = root .. path -                local result = lpegmatch(filter,start .. base) +                local start   = root .. path +                local result  = lpegmatch(filter,start .. base)                  globpattern(start,result,recurse,t)              end          end @@ -210,16 +270,12 @@ local function glob(str,t)                  return { str }              end          else -            local split = lpegmatch(pattern,str) -- we could use the file splitter -            if split then -                local t = t or { } -                local action = action or function(name) t[#t+1] = name end -                local root, path, base = split[1], split[2], split[3] -                local recurse =  find(base,"**",1,true) -- find(base,"%*%*") -                local start = root .. path -                local result = lpegmatch(filter,start .. base) -                globpattern(start,result,recurse,action) -                return t +            local root, path, base = lpegmatch(pattern,str) -- we could use the file splitter +            if root and path and base then +                local recurse = find(base,"**",1,true) -- find(base,"%*%*") +                local start   = root .. path +                local result  = lpegmatch(filter,start .. base) +                return globpattern(start,result,recurse,t)              else                  return { }              end @@ -229,11 +285,20 @@ end  dir.glob = glob ---~ list = dir.glob("**/*.tif") ---~ list = dir.glob("/**/*.tif") ---~ list = dir.glob("./**/*.tif") ---~ list = dir.glob("oeps/**/*.tif") ---~ list = dir.glob("/oeps/**/*.tif") +-- local c = os.clock() +-- local t = dir.glob("e:/**") +-- local t = dir.glob("t:/sources/**") +-- local t = dir.glob("t:/**") +-- print(os.clock()-c,#t) + +-- for i=1,3000 do print(t[i]) end +-- for i=1,10 do print(t[i]) end + +-- list = dir.glob("**/*.tif") +-- list = dir.glob("/**/*.tif") +-- list = dir.glob("./**/*.tif") +-- list = dir.glob("oeps/**/*.tif") +-- list = dir.glob("/oeps/**/*.tif")  local function globfiles(path,recurse,func,files) -- func == pattern or function      if type(func) == "string" then @@ -275,10 +340,10 @@ function dir.ls(pattern)      return concat(glob(pattern),"\n")  end ---~ mkdirs("temp") ---~ mkdirs("a/b/c") ---~ mkdirs(".","/a/b/c") ---~ mkdirs("a","b","c") +-- mkdirs("temp") +-- mkdirs("a/b/c") +-- mkdirs(".","/a/b/c") +-- mkdirs("a","b","c")  local make_indeed = true -- false @@ -347,17 +412,17 @@ if onwindows then          return pth, (isdir(pth) == true)      end -    --~ print(dir.mkdirs("","","a","c")) -    --~ print(dir.mkdirs("a")) -    --~ print(dir.mkdirs("a:")) -    --~ print(dir.mkdirs("a:/b/c")) -    --~ print(dir.mkdirs("a:b/c")) -    --~ print(dir.mkdirs("a:/bbb/c")) -    --~ print(dir.mkdirs("/a/b/c")) -    --~ print(dir.mkdirs("/aaa/b/c")) -    --~ print(dir.mkdirs("//a/b/c")) -    --~ print(dir.mkdirs("///a/b/c")) -    --~ print(dir.mkdirs("a/bbb//ccc/")) +    -- print(dir.mkdirs("","","a","c")) +    -- print(dir.mkdirs("a")) +    -- print(dir.mkdirs("a:")) +    -- print(dir.mkdirs("a:/b/c")) +    -- print(dir.mkdirs("a:b/c")) +    -- print(dir.mkdirs("a:/bbb/c")) +    -- print(dir.mkdirs("/a/b/c")) +    -- print(dir.mkdirs("/aaa/b/c")) +    -- print(dir.mkdirs("//a/b/c")) +    -- print(dir.mkdirs("///a/b/c")) +    -- print(dir.mkdirs("a/bbb//ccc/"))  else @@ -408,13 +473,13 @@ else          return pth, (isdir(pth) == true)      end -    --~ print(dir.mkdirs("","","a","c")) -    --~ print(dir.mkdirs("a")) -    --~ print(dir.mkdirs("/a/b/c")) -    --~ print(dir.mkdirs("/aaa/b/c")) -    --~ print(dir.mkdirs("//a/b/c")) -    --~ print(dir.mkdirs("///a/b/c")) -    --~ print(dir.mkdirs("a/bbb//ccc/")) +    -- print(dir.mkdirs("","","a","c")) +    -- print(dir.mkdirs("a")) +    -- print(dir.mkdirs("/a/b/c")) +    -- print(dir.mkdirs("/aaa/b/c")) +    -- print(dir.mkdirs("//a/b/c")) +    -- print(dir.mkdirs("///a/b/c")) +    -- print(dir.mkdirs("a/bbb//ccc/"))  end @@ -424,7 +489,7 @@ dir.makedirs = dir.mkdirs  if onwindows then -    function dir.expandname(str) -- will be merged with cleanpath and collapsepath +    function dir.expandname(str) -- will be merged with cleanpath and collapsepath\          local first, nothing, last = match(str,"^(//)(//*)(.*)$")          if first then              first = dir.current() .. "/" -- dir.current sanitizes diff --git a/lualibs-lpeg.lua b/lualibs-lpeg.lua index 666af21..c203d80 100644 --- a/lualibs-lpeg.lua +++ b/lualibs-lpeg.lua @@ -225,9 +225,12 @@ patterns.integer       = sign^-1 * digit^1  patterns.unsigned      = digit^0 * period * digit^1  patterns.float         = sign^-1 * patterns.unsigned  patterns.cunsigned     = digit^0 * comma * digit^1 +patterns.cpunsigned    = digit^0 * (period + comma) * digit^1  patterns.cfloat        = sign^-1 * patterns.cunsigned +patterns.cpfloat       = sign^-1 * patterns.cpunsigned  patterns.number        = patterns.float + patterns.integer  patterns.cnumber       = patterns.cfloat + patterns.integer +patterns.cpnumber      = patterns.cpfloat + patterns.integer  patterns.oct           = zero * octdigit^1  patterns.octal         = patterns.oct  patterns.HEX           = zero * P("X") * (digit+uppercase)^1 @@ -813,21 +816,76 @@ end  -- experiment: -local function make(t) -    local p +-- local function make(t) +--     local p +--     local keys = sortedkeys(t) +--     for i=1,#keys do +--         local k = keys[i] +--         local v = t[k] +--         if not p then +--             if next(v) then +--                 p = P(k) * make(v) +--             else +--                 p = P(k) +--             end +--         else +--             if next(v) then +--                 p = p + P(k) * make(v) +--             else +--                 p = p + P(k) +--             end +--         end +--     end +--     return p +-- end + +-- local function make(t) +--     local p = P(false) +--     local keys = sortedkeys(t) +--     for i=1,#keys do +--         local k = keys[i] +--         local v = t[k] +--         if next(v) then +--             p = p + P(k) * make(v) +--         else +--             p = p + P(k) +--         end +--     end +--     return p +-- end + +-- function lpeg.utfchartabletopattern(list) -- goes to util-lpg +--     local tree = { } +--     for i=1,#list do +--         local t = tree +--         for c in gmatch(list[i],".") do +--             local tc = t[c] +--             if not tc then +--                 tc = { } +--                 t[c] = tc +--             end +--             t = tc +--         end +--     end +--     return make(tree) +-- end + +local function make(t,hash) +    local p = P(false)      local keys = sortedkeys(t)      for i=1,#keys do          local k = keys[i]          local v = t[k] -        if not p then +        local h = hash[v] +        if h then              if next(v) then -                p = P(k) * make(v) +                p = p + P(k) * (make(v,hash) + P(true))              else -                p = P(k) +                p = p + P(k) * P(true)              end          else              if next(v) then -                p = p + P(k) * make(v) +                p = p + P(k) * make(v,hash)              else                  p = p + P(k)              end @@ -838,16 +896,20 @@ end  function lpeg.utfchartabletopattern(list) -- goes to util-lpg      local tree = { } +    local hash = { }      for i=1,#list do          local t = tree          for c in gmatch(list[i],".") do -            if not t[c] then -                t[c] = { } +            local tc = t[c] +            if not tc then +                tc = { } +                t[c] = tc              end -            t = t[c] +            t = tc          end +        hash[t] = list[i]      end -    return make(tree) +    return make(tree,hash)  end  -- inspect ( lpeg.utfchartabletopattern { diff --git a/lualibs-table.lua b/lualibs-table.lua index d231830..ca067fb 100644 --- a/lualibs-table.lua +++ b/lualibs-table.lua @@ -164,14 +164,14 @@ local function sortedhash(t,cmp)          end          local n = 0          local m = #s -        local function kv(s) +        local function kv() -- (s)              if n < m then                  n = n + 1                  local k = s[n]                  return k, t[k]              end          end -        return kv, s +        return kv -- , s      else          return nothing      end @@ -400,7 +400,7 @@ local function simple_table(t)                  if tv == "number" then                      nt = nt + 1                      if hexify then -                        tt[nt] = format("0x%04X",v) +                        tt[nt] = format("0x%X",v)                      else                          tt[nt] = tostring(v) -- tostring not needed                      end @@ -451,7 +451,7 @@ local function do_serialize(root,name,depth,level,indexed)              local tn = type(name)              if tn == "number" then                  if hexify then -                    handle(format("%s[0x%04X]={",depth,name)) +                    handle(format("%s[0x%X]={",depth,name))                  else                      handle(format("%s[%s]={",depth,name))                  end @@ -502,7 +502,7 @@ local function do_serialize(root,name,depth,level,indexed)              if compact and first and tk == "number" and k >= first and k <= last then                  if tv == "number" then                      if hexify then -                        handle(format("%s 0x%04X,",depth,v)) +                        handle(format("%s 0x%X,",depth,v))                      else                          handle(format("%s %s,",depth,v)) -- %.99g                      end @@ -543,25 +543,25 @@ local function do_serialize(root,name,depth,level,indexed)              elseif tv == "number" then                  if tk == "number" then                      if hexify then -                        handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) +                        handle(format("%s [0x%X]=0x%X,",depth,k,v))                      else                          handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif tk == "boolean" then                      if hexify then -                        handle(format("%s [%s]=0x%04X,",depth,k and "true" or "false",v)) +                        handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))                      else                          handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and lpegmatch(propername,k) then                      if hexify then -                        handle(format("%s %s=0x%04X,",depth,k,v)) +                        handle(format("%s %s=0x%X,",depth,k,v))                      else                          handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then -                        handle(format("%s [%q]=0x%04X,",depth,k,v)) +                        handle(format("%s [%q]=0x%X,",depth,k,v))                      else                          handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end @@ -570,7 +570,7 @@ local function do_serialize(root,name,depth,level,indexed)                  if reduce and tonumber(v) then                      if tk == "number" then                          if hexify then -                            handle(format("%s [0x%04X]=%s,",depth,k,v)) +                            handle(format("%s [0x%X]=%s,",depth,k,v))                          else                              handle(format("%s [%s]=%s,",depth,k,v))                          end @@ -584,7 +584,7 @@ local function do_serialize(root,name,depth,level,indexed)                  else                      if tk == "number" then                          if hexify then -                            handle(format("%s [0x%04X]=%q,",depth,k,v)) +                            handle(format("%s [0x%X]=%q,",depth,k,v))                          else                              handle(format("%s [%s]=%q,",depth,k,v))                          end @@ -600,7 +600,7 @@ local function do_serialize(root,name,depth,level,indexed)                  if not next(v) then                      if tk == "number" then                          if hexify then -                            handle(format("%s [0x%04X]={},",depth,k)) +                            handle(format("%s [0x%X]={},",depth,k))                          else                              handle(format("%s [%s]={},",depth,k))                          end @@ -616,7 +616,7 @@ local function do_serialize(root,name,depth,level,indexed)                      if st then                          if tk == "number" then                              if hexify then -                                handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", "))) +                                handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))                              else                                  handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))                              end @@ -636,7 +636,7 @@ local function do_serialize(root,name,depth,level,indexed)              elseif tv == "boolean" then                  if tk == "number" then                      if hexify then -                        handle(format("%s [0x%04X]=%s,",depth,k,v and "true" or "false")) +                        handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))                      else                          handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))                      end @@ -653,7 +653,7 @@ local function do_serialize(root,name,depth,level,indexed)                   -- local f = getinfo(v).what == "C" and dump(function(...) return v(...) end) or dump(v) -- maybe strip                      if tk == "number" then                          if hexify then -                            handle(format("%s [0x%04X]=load(%q),",depth,k,f)) +                            handle(format("%s [0x%X]=load(%q),",depth,k,f))                          else                              handle(format("%s [%s]=load(%q),",depth,k,f))                          end @@ -668,7 +668,7 @@ local function do_serialize(root,name,depth,level,indexed)              else                  if tk == "number" then                      if hexify then -                        handle(format("%s [0x%04X]=%q,",depth,k,tostring(v))) +                        handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))                      else                          handle(format("%s [%s]=%q,",depth,k,tostring(v)))                      end @@ -727,7 +727,7 @@ local function serialize(_handle,root,name,specification) -- handle wins          end      elseif tname == "number" then          if hexify then -            handle(format("[0x%04X]={",name)) +            handle(format("[0x%X]={",name))          else              handle("[" .. name .. "]={")          end @@ -1114,3 +1114,49 @@ function table.values(t,s) -- optional sort flag          return { }      end  end + +-- maybe this will move to util-tab.lua + +-- for k, v in table.filtered(t,pattern)          do ... end +-- for k, v in table.filtered(t,pattern,true)     do ... end +-- for k, v in table.filtered(t,pattern,true,cmp) do ... end + +function table.filtered(t,pattern,sort,cmp) +    if t and type(pattern) == "string" then +        if sort then +            local s +            if cmp then +                -- it would be nice if the sort function would accept a third argument (or nicer, an optional first) +                s = sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +            else +                s = sortedkeys(t) -- the robust one +            end +            local n = 0 +            local m = #s +            local function kv(s) +                while n < m do +                    n = n + 1 +                    local k = s[n] +                    if find(k,pattern) then +                        return k, t[k] +                    end +                end +            end +            return kv, s +        else +            local n = next(t) +            local function iterator() +                while n do +                    local k = n +                    n = next(t,k) +                    if find(k,pattern) then +                        return k, t[k] +                    end +                end +            end +            return iterator, t +        end +    else +        return nothing +    end +end diff --git a/lualibs-util-prs.lua b/lualibs-util-prs.lua index 2cede91..f51f6fc 100644 --- a/lualibs-util-prs.lua +++ b/lualibs-util-prs.lua @@ -542,8 +542,8 @@ end  -- -local pattern_math = Cs((P("%")/"\\percent " +  P("^")           * Cc("{") * lpegpatterns.integer * Cc("}") + P(1))^0) -local pattern_text = Cs((P("%")/"\\percent " + (P("^")/"\\high") * Cc("{") * lpegpatterns.integer * Cc("}") + P(1))^0) +local pattern_math = Cs((P("%")/"\\percent " +  P("^")           * Cc("{") * lpegpatterns.integer * Cc("}") + anything)^0) +local pattern_text = Cs((P("%")/"\\percent " + (P("^")/"\\high") * Cc("{") * lpegpatterns.integer * Cc("}") + anything)^0)  patterns.unittotex = pattern @@ -551,7 +551,7 @@ function parsers.unittotex(str,textmode)      return lpegmatch(textmode and pattern_text or pattern_math,str)  end -local pattern = Cs((P("^") / "<sup>" * lpegpatterns.integer * Cc("</sup>") + P(1))^0) +local pattern = Cs((P("^") / "<sup>" * lpegpatterns.integer * Cc("</sup>") + anything)^0)  function parsers.unittoxml(str)      return lpegmatch(pattern,str) @@ -648,3 +648,27 @@ function utilities.parsers.runtime(time)      local seconds = mod(time,60)      return days, hours, minutes, seconds  end + +-- + +local spacing = whitespace^0 +local apply   = P("->") +local method  = C((1-apply)^1) +local token   = lbrace * C((1-rbrace)^1) * rbrace + C(anything^1) + +local pattern = spacing * (method * spacing * apply + Carg(1)) * spacing * token + +function utilities.parsers.splitmethod(str,default) +    if str then +        return lpegmatch(pattern,str,1,default or false) +    else +        return default or false, "" +    end +end + +-- print(utilities.parsers.splitmethod(" foo -> {bar} ")) +-- print(utilities.parsers.splitmethod("foo->{bar}")) +-- print(utilities.parsers.splitmethod("foo->bar")) +-- print(utilities.parsers.splitmethod("foo")) +-- print(utilities.parsers.splitmethod("{foo}")) +-- print(utilities.parsers.splitmethod()) diff --git a/lualibs-util-str.lua b/lualibs-util-str.lua index 6f95254..2739a20 100644 --- a/lualibs-util-str.lua +++ b/lualibs-util-str.lua @@ -216,6 +216,7 @@ local striplinepatterns = {      ["retain"]              = p_retain_normal,      ["retain and collapse"] = p_retain_collapse,      ["retain and no empty"] = p_retain_noempty, +    ["collapse"]            = patterns.collapser, -- how about: stripper fullstripper  }  strings.striplinepatterns = striplinepatterns @@ -224,6 +225,8 @@ function strings.striplines(str,how)      return str and lpegmatch(how and striplinepatterns[how] or p_prune_collapse,str) or str  end +-- also see: string.collapsespaces +  strings.striplong = strings.striplines -- for old times sake  -- local str = table.concat( { @@ -534,7 +537,7 @@ end  -- We could probably use just %s with integers but who knows what Lua 5.3 will do? So let's  -- for the moment use %i. -local format_F = function() +local format_F = function() -- beware, no cast to number      n = n + 1      if not f or f == "" then          return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) @@ -1091,3 +1094,23 @@ end  -- string.formatteds = formatteds  --  -- setmetatable(formatteds, { __index = make, __call = use }) + +-- This is a somewhat silly one used in commandline reconstruction but the older +-- method, using a combination of fine, gsub, quoted and unquoted was not that +-- reliable. +-- +-- '"foo"bar \"and " whatever"' => "foo\"bar \"and \" whatever" +-- 'foo"bar \"and " whatever'   => "foo\"bar \"and \" whatever" + +local dquote = patterns.dquote -- P('"') +local equote = patterns.escaped + dquote / '\\"' + 1 +local space  = patterns.space +local cquote = Cc('"') + +local pattern = +    Cs(dquote * (equote - P(-2))^0 * dquote)                    -- we keep the outer but escape unescaped ones +  + Cs(cquote * (equote - space)^0 * space * equote^0 * cquote) -- we escape unescaped ones + +function string.optionalquoted(str) +    return lpegmatch(pattern,str) or str +end  | 
