1 // BotInterp.C -*- C++ -*-
2 // Copyright (c) 1998 Etienne BERNARD
3 // Copyright (C) 2002,2005,2008 Clinton Ebadi
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include "BotInterp.H"
37 #include <libguile/regex-posix.h>
41 Hook::operator< (const Hook & h) const
43 if (priority < h.priority)
47 else if (priority > h.priority)
51 else if (fallthru && h.fallthru)
55 else if (fallthru && !h.fallthru)
59 else if (!fallthru && h.fallthru)
65 // NOTE: This should never be reached
70 BotInterp::BotInterp(Bot *b, String fn)
72 hook_mutex (true), timer_mutex (true)
74 logPort = scm_open_file (Utils::str2scm (fn),
75 Utils::str2scm ("a"));
77 scm_gc_protect_object(logPort);
81 BotInterp::Execute(String command)
83 Interp::Execute(bot, command);
87 BotInterp::LoadScript(String filename)
89 Interp::LoadScript(bot, filename);
93 BotInterp::ScriptLog()
105 HookFind (std::string r, std::string n)
109 bool operator() (const Hook * hook) const
110 { return hook->regex_str == rx && hook->name == name; }
115 BotInterp::AddHook(int hooktype, SCM regex, SCM function, int pri, bool fall,
118 if (scm_string_p(regex) == SCM_BOOL_F)
121 BotLock hook_lock (hook_mutex);
122 std::string rx = Utils::to_upper (Utils::scm2str (regex));
123 SCM r = scm_make_regexp (regex,
124 scm_list_n (scm_variable_ref (scm_c_lookup ("regexp/icase")),
126 HookFind hook_find (rx, name);
127 HookList& hook_list = hooks[hooktype];
129 scm_gc_protect_object(r);
130 scm_gc_protect_object(function);
132 HookList::iterator it = std::find_if (hook_list.begin (),
136 if (it != hook_list.end())
140 scm_gc_unprotect_object(found->function);
141 scm_gc_unprotect_object (r);
143 found->function = function;
144 found->priority = pri;
145 found->fallthru = fall;
147 hook_list.erase (it);
148 Utils::push_sorted (hook_list, found, hook_sort_p);
154 Utils::push_sorted (hook_list,
155 new Hook(hooktype, rx, r, function, pri, fall, name),
163 BotInterp::RunHooks(int hooktype, std::string match, SCM args)
165 BotLock hook_lock (hook_mutex);
171 // We want to execute higher priority hooks first, so we start at
172 // the end of the list instead of the beginning
174 for (HookList::reverse_iterator it = hooks[hooktype].rbegin();
175 it != hooks[hooktype].rend();
178 if (scm_regexp_exec((*it)->regex, Utils::str2scm (match),
179 SCM_UNDEFINED, SCM_UNDEFINED) != SCM_BOOL_F)
181 bool fallthru_p = (*it)->fallthru;
182 wd.func = (*it)->function;
183 result = scm_c_with_throw_handler (SCM_BOOL_T,
185 Interp::LazyApplyWrapper,
186 static_cast<void *> (&wd),
187 (scm_t_catch_handler) Interp::EmptyHandler,
199 BotInterp::AddTimer(int delay, SCM function)
201 BotLock timer_lock (timer_mutex);
202 int when = time(NULL) + delay;
204 scm_gc_protect_object(function);
206 Timer *timer = new Timer (++counter, when, function);
207 Utils::push_sorted (timers, timer, timer_sort_p);
209 return scm_from_int (counter);
214 BotInterp::DelTimer(SCM timer)
216 BotLock timer_lock (timer_mutex);
218 int count = scm_to_int (timer);
219 TimerList::iterator it = timers.begin();
220 TimerList::iterator end = timers.end();
222 for ( ; it != end; ++it)
224 if ((*it)->count == count)
226 scm_gc_unprotect_object((*it)->function);
238 BotInterp::RunTimers(int now)
240 BotLock timer_lock (timer_mutex);
241 struct wrapper_data wd;
242 wd.args = scm_list_n (SCM_UNDEFINED);
244 while (!timers.empty ())
246 // Keep a stack allocated copy of the front of the timer queue
247 // just in case the timer is deleted while being executed (which
248 // is very unlikely as the only place this could occur is if the
249 // timer deleted itself)
250 Timer current_timer = *timers.front () ;
252 if (current_timer.when <= now)
254 wd.func = current_timer.function;
256 scm_c_with_throw_handler (SCM_BOOL_T,
257 (scm_t_catch_body) Interp::LazyApplyWrapper,
259 (scm_t_catch_handler) Interp::EmptyHandler,
263 // The timer list may have been modified by the timer
264 // callback; if it has in such a way that the first queue
265 // item has changed (adding a timer in the past) then we
266 // switch the slow path for deleting a timer
267 if (current_timer.count == timers.front()->count)
269 scm_gc_unprotect_object (current_timer.function);
270 delete timers.front ();
275 DelTimer (scm_from_int (current_timer.count));