1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
--[[ parse through the *.menu tables and return a "menu" table
Written for Alpine Configuration Framework (ACF) -- see www.alpinelinux.org
Copyright (C) 2007 Nathan Angelacos
Licensed under the terms of GPL2
]]--
module(..., package.seeall)
require("format")
-- returns a table of the "*.menu" tables
-- uses the system "find" command
-- startdir should be the app dir.
local get_candidates = function (startdir)
local t = {}
local fh = io.popen('find ' .. format.escapespecialcharacters(startdir) .. ' -name "*.menu"')
for x in fh:lines() do
t[#t + 1] = x
end
return t
end
-- Split string into priority and name, convert '_' to space
local parse_menu_entry = function (entry)
local name, priority
if (string.match(entry, "^%d")) then
priority, name = string.match(entry, "(%d+)(.*)")
else
name = entry
end
name = string.gsub(name, "_", " ")
return name, priority
end
-- Parse menu file entry, returning cat, group, tab, action and priorities
local parse_menu_line = function (line)
local result = nil
--skip comments and blank lines
if nil == (string.match(line, "^#") or string.match(line,"^$")) then
local item = {}
for i in string.gmatch(line, "%S+") do
item[#item + 1] = i
end
if #item >= 1 then
result = {}
result.cat, result.cat_prio = parse_menu_entry(item[1])
if (item[2]) then result.group, result.group_prio = parse_menu_entry(item[2]) end
if (item[3]) then result.tab = parse_menu_entry(item[3]) end
if (item[4]) then result.action = parse_menu_entry(item[4]) end
end
end
return result
end
-- Function to compare priorities, missing priority moves to the front, same priority sorted alphabetically
local prio_compare = function(x,y)
if x.priority == y.priority then
if x.name < y.name then return true end
return false
end
if nil == x.priority then return true end
if nil == y.priority then return false end
if tonumber(x.priority) < tonumber(y.priority) then return true end
return false
end
-- returns a table of all the menu items found, sorted by priority
get_menuitems = function (startdir)
local cats = {}
local reversecats = {}
startdir = (string.gsub(startdir, "/$", "")) --remove trailing /
for k,filename in pairs(get_candidates(startdir)) do
local controller = mvc.basename(filename, ".menu")
local prefix = (string.gsub(mvc.dirname(filename), startdir, ""))
-- open the menu file, and parse the contents
local handle = io.open(filename)
for x in handle:lines() do
local result = parse_menu_line(x)
if result then
for i = 1,1 do -- loop so break works
-- Add the category
if nil == reversecats[result.cat] then
table.insert ( cats,
{ name=result.cat,
groups = {},
reversegroups = {} } )
reversecats[result.cat] = #cats
end
local cat = cats[reversecats[result.cat]]
cat.priority = cat.priority or result.cat_prio
-- Add the group
if nil == result.group then break end
if nil == cat.groups[cat.reversegroups[result.group]] then
table.insert ( cat.groups,
{ name = result.group,
controller = controller,
prefix = prefix,
tabs = {} } )
cat.reversegroups[result.group] = #cat.groups
end
local group = cat.groups[cat.reversegroups[result.group]]
group.priority = group.priority or result.group_prio
-- Add the tab
if nil == result.tab or nil == result.action then break end
local tab = { name = result.tab, action = result.action }
table.insert(group.tabs, tab)
end
end
end
handle:close()
end
-- Now that we have the entire menu, sort by priority
-- Categories first
table.sort(cats, prio_compare)
-- Then groups
for x, cat in ipairs(cats) do
cat.reversegroups = nil -- don't need reverse table anymore
table.sort(cat.groups, prio_compare)
end
return cats
end
|