diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-19 22:12:16 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-11-20 06:07:33 +0100 |
commit | 90f203bff189706c2dec34482475b89d0a232597 (patch) | |
tree | a13c16ca7f73b779f941e0543bcff81d97e84b4d | |
parent | b804417f36ef398f1223e439fd5ac9f2ade046eb (diff) | |
download | sciteco-90f203bff189706c2dec34482475b89d0a232597.tar.gz |
make goto tables local to macro invocation: they are declared on the C++ callstack since macro invocations result in nested macro_execute() calls
otherwise a macro could set labels with program counters which are invalid in other macros/the command line
-rw-r--r-- | cmdline.cpp | 2 | ||||
-rw-r--r-- | goto.cpp | 183 | ||||
-rw-r--r-- | goto.h | 69 | ||||
-rw-r--r-- | main.cpp | 4 | ||||
-rw-r--r-- | parser.cpp | 6 | ||||
-rw-r--r-- | qbuffers.cpp | 7 | ||||
-rw-r--r-- | rbtree.h | 19 |
7 files changed, 151 insertions, 139 deletions
diff --git a/cmdline.cpp b/cmdline.cpp index 8fc9dc6..9f500a3 100644 --- a/cmdline.cpp +++ b/cmdline.cpp @@ -136,7 +136,7 @@ process_edit_cmd(gchar key) interface.ssm(SCI_EMPTYUNDOBUFFER); undo.clear(); - goto_table_clear(); + goto_table->clear(); *cmdline = '\0'; macro_pc = 0; @@ -1,5 +1,3 @@ -#include <bsd/sys/tree.h> - #include <glib.h> #include <glib/gprintf.h> @@ -7,7 +5,6 @@ #include "expressions.h" #include "parser.h" #include "undo.h" -#include "rbtree.h" #include "goto.h" namespace States { @@ -17,146 +14,75 @@ namespace States { static gchar *skip_label = NULL; -class GotoTable : public RBTree { - class UndoTokenSet : public UndoToken { - GotoTable *table; - - gchar *name; - gint pc; - - public: - UndoTokenSet(GotoTable *_table, gchar *_name, gint _pc = -1) - : table(_table), name(g_strdup(_name)), pc(_pc) {} - ~UndoTokenSet() - { - g_free(name); - } - - void - run(void) - { - table->set(name, pc); -#ifdef DEBUG - table->dump(); -#endif - } - }; - - class Label : public RBEntry { - public: - gchar *name; - gint pc; - - Label(gchar *_name, gint _pc = -1) - : name(g_strdup(_name)), pc(_pc) {} - ~Label() - { - g_free(name); - } - - int - operator <(RBEntry &l2) - { - return g_strcmp0(name, ((Label &)l2).name); - } - }; - -public: - GotoTable() : RBTree() {} - - gint - remove(gchar *name) - { - gint existing_pc = -1; - - Label label(name); - Label *existing = (Label *)RBTree::find(&label); +GotoTable *goto_table = NULL; - if (existing) { - existing_pc = existing->pc; - RBTree::remove(existing); - delete existing; - } - - return existing_pc; - } +gint +GotoTable::remove(gchar *name) +{ + gint existing_pc = -1; - gint - find(gchar *name) - { - Label label(name); - Label *existing = (Label *)RBTree::find(&label); + Label label(name); + Label *existing = (Label *)RBTree::find(&label); - return existing ? existing->pc : -1; + if (existing) { + existing_pc = existing->pc; + RBTree::remove(existing); + delete existing; } - gint - set(gchar *name, gint pc) - { - if (pc < 0) - return remove(name); - - Label *label = new Label(name, pc); - Label *existing; - gint existing_pc = -1; - - existing = (Label *)RBTree::find(label); - if (existing) { - existing_pc = existing->pc; - g_free(existing->name); - existing->name = label->name; - existing->pc = label->pc; - - label->name = NULL; - delete label; - } else { - RBTree::insert(label); - } - -#ifdef DEBUG - dump(); -#endif - - return existing_pc; - } + return existing_pc; +} - inline void - undo_set(gchar *name, gint pc = -1) - { - undo.push(new UndoTokenSet(this, name, pc)); - } +gint +GotoTable::find(gchar *name) +{ + Label label(name); + Label *existing = (Label *)RBTree::find(&label); - void - clear(void) - { - Label *cur; + return existing ? existing->pc : -1; +} - while ((cur = (Label *)RBTree::min())) { - RBTree::remove(cur); - delete cur; - } +gint +GotoTable::set(gchar *name, gint pc) +{ + if (pc < 0) + return remove(name); + + Label *label = new Label(name, pc); + Label *existing; + gint existing_pc = -1; + + existing = (Label *)RBTree::find(label); + if (existing) { + existing_pc = existing->pc; + g_free(existing->name); + existing->name = label->name; + existing->pc = label->pc; + + label->name = NULL; + delete label; + } else { + RBTree::insert(label); } #ifdef DEBUG - void - dump(void) - { - for (Label *cur = (Label *)RBTree::min(); - cur != NULL; - cur = (Label *)cur->next()) - g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc); - g_printf("---END---\n"); - } + dump(); #endif -}; -static GotoTable table; + return existing_pc; +} +#ifdef DEBUG void -goto_table_clear(void) +GotoTable::dump(void) { - table.clear(); + for (Label *cur = (Label *)RBTree::min(); + cur != NULL; + cur = (Label *)cur->next()) + g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc); + g_printf("---END---\n"); } +#endif /* * Command states @@ -173,7 +99,8 @@ StateLabel::custom(gchar chr) throw (Error) gchar *new_str; if (chr == '!') { - table.undo_set(strings[0], table.set(strings[0], macro_pc)); + goto_table->undo_set(strings[0], + goto_table->set(strings[0], macro_pc)); if (!g_strcmp0(strings[0], skip_label)) { undo.push_str(skip_label); @@ -211,7 +138,7 @@ StateGotoCmd::done(const gchar *str) throw (Error) labels = g_strsplit(str, ",", -1); if (value > 0 && value <= g_strv_length(labels) && *labels[value-1]) { - gint pc = table.find(labels[value-1]); + gint pc = goto_table->find(labels[value-1]); if (pc >= 0) { macro_pc = pc; @@ -2,9 +2,76 @@ #define __GOTO_H #include <glib.h> +#include <glib/gprintf.h> #include "sciteco.h" #include "parser.h" +#include "undo.h" +#include "rbtree.h" + +class GotoTable : public RBTree { + class UndoTokenSet : public UndoToken { + GotoTable *table; + + gchar *name; + gint pc; + + public: + UndoTokenSet(GotoTable *_table, gchar *_name, gint _pc = -1) + : table(_table), name(g_strdup(_name)), pc(_pc) {} + ~UndoTokenSet() + { + g_free(name); + } + + void + run(void) + { + table->set(name, pc); +#ifdef DEBUG + table->dump(); +#endif + } + }; + + class Label : public RBEntry { + public: + gchar *name; + gint pc; + + Label(gchar *_name, gint _pc = -1) + : name(g_strdup(_name)), pc(_pc) {} + ~Label() + { + g_free(name); + } + + int + operator <(RBEntry &l2) + { + return g_strcmp0(name, ((Label &)l2).name); + } + }; + +public: + GotoTable() : RBTree() {} + + gint remove(gchar *name); + gint find(gchar *name); + + gint set(gchar *name, gint pc); + inline void + undo_set(gchar *name, gint pc = -1) + { + undo.push(new UndoTokenSet(this, name, pc)); + } + +#ifdef DEBUG + void dump(void); +#endif +}; + +extern GotoTable *goto_table; /* * Command states @@ -28,6 +95,4 @@ namespace States { extern StateGotoCmd gotocmd; } -void goto_table_clear(void); - #endif @@ -100,6 +100,8 @@ process_options(int &argc, char **&argv) int main(int argc, char **argv) { + static GotoTable cmdline_goto_table; + process_options(argc, argv); interface.ssm(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK); @@ -134,8 +136,8 @@ main(int argc, char **argv) } g_free(mung_file); + goto_table = &cmdline_goto_table; interface.ssm(SCI_EMPTYUNDOBUFFER); - goto_table_clear(); undo.enabled = true; interface.event_loop(); @@ -60,13 +60,18 @@ macro_execute(const gchar *macro) throw (State::Error) } } +/* + * TODO: make this usable from other macro invocations as well + */ bool file_execute(const gchar *filename) { gchar *macro, *p = NULL; + GotoTable file_goto_table; macro_pc = 0; States::current = &States::start; + goto_table = &file_goto_table; if (!g_file_get_contents(filename, ¯o, NULL, NULL)) return false; @@ -84,6 +89,7 @@ file_execute(const gchar *filename) macro_pc = 0; States::current = &States::start; + goto_table = NULL; return true; } diff --git a/qbuffers.cpp b/qbuffers.cpp index 77fefd5..26e4599 100644 --- a/qbuffers.cpp +++ b/qbuffers.cpp @@ -18,6 +18,7 @@ #include "undo.h" #include "parser.h" #include "expressions.h" +#include "goto.h" #include "qbuffers.h" namespace States { @@ -142,6 +143,9 @@ QRegister::undo_edit(void) void QRegister::execute(void) throw (State::Error) { + GotoTable *parent_goto_table = goto_table; + GotoTable macro_goto_table; + State *parent_state = States::current; gint parent_pc = macro_pc; gchar *str; @@ -156,6 +160,7 @@ QRegister::execute(void) throw (State::Error) macro_pc = 0; str = get_string(); + goto_table = ¯o_goto_table; try { macro_execute(str); @@ -163,12 +168,14 @@ QRegister::execute(void) throw (State::Error) g_free(str); macro_pc = parent_pc; States::current = parent_state; + goto_table = parent_goto_table; throw; /* forward */ } g_free(str); macro_pc = parent_pc; States::current = parent_state; + goto_table = parent_goto_table; } bool @@ -49,16 +49,10 @@ public: { RB_INIT(&head); } - virtual ~RBTree() { - RBEntry *cur; - - while ((cur = min())) { - remove(cur); - delete cur; - } + clear(); } inline RBEntry * @@ -92,6 +86,17 @@ public: { return RB_MAX(Tree, &head); } + + inline void + clear(void) + { + RBEntry *cur; + + while ((cur = min())) { + remove(cur); + delete cur; + } + } }; template <typename KeyType, typename ValueType> |