aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-19 22:12:16 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-20 06:07:33 +0100
commit90f203bff189706c2dec34482475b89d0a232597 (patch)
treea13c16ca7f73b779f941e0543bcff81d97e84b4d
parentb804417f36ef398f1223e439fd5ac9f2ade046eb (diff)
downloadsciteco-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.cpp2
-rw-r--r--goto.cpp183
-rw-r--r--goto.h69
-rw-r--r--main.cpp4
-rw-r--r--parser.cpp6
-rw-r--r--qbuffers.cpp7
-rw-r--r--rbtree.h19
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;
diff --git a/goto.cpp b/goto.cpp
index c64a896..0db7a2b 100644
--- a/goto.cpp
+++ b/goto.cpp
@@ -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;
diff --git a/goto.h b/goto.h
index 622f58c..b44ffa2 100644
--- a/goto.h
+++ b/goto.h
@@ -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
diff --git a/main.cpp b/main.cpp
index e186171..a1da02d 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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();
diff --git a/parser.cpp b/parser.cpp
index 89486a1..25c940b 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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, &macro, 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 = &macro_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
diff --git a/rbtree.h b/rbtree.h
index f1e920a..d5f2a6e 100644
--- a/rbtree.h
+++ b/rbtree.h
@@ -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>