Installer import into contrib (real import this time)
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / backend / lua / lib / FlowStep.lua
1 -- lib/fsm.lua
2 -- $Id: FlowStep.lua,v 1.18 2005/03/29 21:04:19 cpressey Exp $
3 -- Framework for simple Finite State Machines in Lua.
4
5 -- BEGIN lib/fsm.lua --
6
7 local POSIX = require("posix")
8 local FileName = require("filename")
9 local App = require("app")
10
11 -- Global "class" variable:
12 FSM = {}
13
14 -- Global "static methods":
15
16 -- Create a new FSM object instance.
17 -- This object can then have states added to it with
18 -- fsm:register(StateName, Function), and can be run
19 -- with fsm:run(InitialStateName).
20 FSM.new = function()
21         local fsm = {}
22         local state = {}                -- a dictionary of state name -> state
23         local sequence = {}             -- an array of state number -> state
24         local current_state = nil       -- reference to the current state
25
26         fsm.register = function(fsm, tab)
27                 state[tab.name] = {
28                     name = tab.name,
29                     title = tab.title,
30                     action = tab.action,
31                     position = table.getn(sequence) + 1
32                 }
33                 table.insert(sequence, state[tab.name])
34         end
35
36         fsm.next = function(fsm)
37                 return sequence[current_state.position + 1]
38         end
39
40         fsm.prev = function(fsm)
41                 return sequence[current_state.position - 1]
42         end
43
44         fsm.current = function(fsm)
45                 return current_state
46         end
47
48         local resolve_state = function(x)
49                 if type(x) == "string" then
50                         if state[x] then
51                                 return state[x]
52                         else
53                                 error("No state named '" .. x ..
54                                       "' exists in FSM")
55                         end
56                 elseif type(x) == "number" then
57                         if sequence[x] then
58                                 return sequence[x]
59                         else
60                                 error("No state number " .. tostring(x) ..
61                                       " exists in FSM")
62                         end
63                 elseif x == nil then
64                         return nil
65                 elseif type(x) == "table" then
66                         local i, v
67                         
68                         for i, v in state do
69                                 if x == v then
70                                         return x
71                                 end
72                         end
73                         error("State object `" .. tostring(x) ..
74                               "' does not exist in FSM")
75                 end
76                 error("Invalid state reference: " .. tostring(x))
77         end
78
79         fsm.run = function(fsm, start_state)
80                 local result
81
82                 current_state = resolve_state(start_state)
83                 while current_state do
84                         if type(current_state.action) ~= "function" then
85                                 error("State '" .. current_state.name ..
86                                     "' does not define an action function")
87                         else
88                                 result = current_state.action(fsm)
89                                 current_state = resolve_state(result)
90                         end
91                 end
92         end
93
94         -- Note that we only return the table of functions;
95         -- we do not return the state table.  However, a
96         -- reference ("upvalue" in Lua terminology) to the
97         -- state table is still carried along inside the
98         -- fsm function table; in this way it is retained,
99         -- and it is also protected from modification from
100         -- the outside (i.e. it is encapsulated.)
101         return fsm
102 end
103
104 -- Create a new FSM object instance automatically from
105 -- the Lua script files in the given directory.  Each script
106 -- should end with a return statement that returns a table
107 -- describing the state.
108 FSM.from_dir = function(dir)
109         local fsm = FSM.new()
110         local file_no, files
111         local state, fun
112         local state_count = 0
113
114         files = POSIX.dir(dir)
115         table.sort(files)
116
117         for file_no in files do
118                 local full_file = dir .. "/" .. files[file_no]
119                 local tab
120
121                 if files[file_no] ~= FileName.basename(App.current_script) and
122                    not FileName.is_dir(full_file) and
123                    string.find(files[file_no], "^[^%.].*%.lua$") then
124                         tab = App.run_script(full_file)
125                         if tab then
126                                 fsm:register(tab)
127                                 state_count = state_count + 1
128                         end
129                 end
130         end
131
132         if state_count == 0 then
133                 error("Directory " .. dir .. " should contain at least one FSM scriptlet")
134         end
135
136         return fsm
137 end
138
139 -- Create a new FSM object instance automatically from
140 -- the Lua script files in the same directory as the Lua
141 -- script file that invoked this function.
142 FSM.auto = function(start_state)
143         local path = FileName.dirname(App.current_script)
144         local fsm = FSM.from_dir(path)
145
146         fsm:run(start_state)
147 end
148
149 -- END of lib/fsm.lua --