aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cmdline.cpp4
-rw-r--r--goto.cpp4
-rw-r--r--goto.h4
-rw-r--r--parser.cpp122
-rw-r--r--parser.h83
-rw-r--r--qbuffers.cpp46
-rw-r--r--qbuffers.h24
7 files changed, 174 insertions, 113 deletions
diff --git a/cmdline.cpp b/cmdline.cpp
index 5c6c14b..e2103ac 100644
--- a/cmdline.cpp
+++ b/cmdline.cpp
@@ -56,7 +56,9 @@ cmdline_keypress(gchar key)
for (const gchar *p = insert; *p; p++) {
strcat(cmdline, (gchar[]){*p, '\0'});
- if (!macro_execute(cmdline)) {
+ try {
+ macro_execute(cmdline);
+ } catch (...) {
cmdline[old_cmdline_len] = '\0';
break;
}
diff --git a/goto.cpp b/goto.cpp
index 4b2ce15..63ccc05 100644
--- a/goto.cpp
+++ b/goto.cpp
@@ -171,7 +171,7 @@ StateLabel::StateLabel() : State()
}
State *
-StateLabel::custom(gchar chr)
+StateLabel::custom(gchar chr) throw (Error)
{
gchar *new_str;
@@ -203,7 +203,7 @@ StateLabel::custom(gchar chr)
}
State *
-StateGotoCmd::done(const gchar *str)
+StateGotoCmd::done(const gchar *str) throw (Error)
{
gint64 value;
gchar **labels;
diff --git a/goto.h b/goto.h
index 84157b1..622f58c 100644
--- a/goto.h
+++ b/goto.h
@@ -15,12 +15,12 @@ public:
StateLabel();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateGotoCmd : public StateExpectString {
private:
- State *done(const gchar *str);
+ State *done(const gchar *str) throw (Error);
};
namespace States {
diff --git a/parser.cpp b/parser.cpp
index 59c5df2..7e4da4a 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -1,3 +1,4 @@
+#include <stdarg.h>
#include <string.h>
#include <glib.h>
@@ -43,8 +44,8 @@ static gint nest_level = 0;
gchar *strings[2] = {NULL, NULL};
gchar escape_char = '\x1B';
-bool
-macro_execute(const gchar *macro)
+void
+macro_execute(const gchar *macro) throw (State::Error)
{
while (macro[macro_pc]) {
#ifdef DEBUG
@@ -53,23 +54,15 @@ macro_execute(const gchar *macro)
States::current);
#endif
- if (!State::input(macro[macro_pc])) {
- interface.msg(Interface::MSG_ERROR,
- "Syntax error \"%c\"", macro[macro_pc]);
- return false;
- }
-
+ State::input(macro[macro_pc]);
macro_pc++;
}
-
- return true;
}
bool
file_execute(const gchar *filename)
{
gchar *macro, *p = NULL;
- bool rc;
macro_pc = 0;
States::current = &States::start;
@@ -80,16 +73,28 @@ file_execute(const gchar *filename)
if (macro[0] == '#')
p = MAX(strchr(macro, '\r'), strchr(macro, '\n'));
- rc = macro_execute(p ? p+1 : macro);
- g_free(macro);
- if (!rc)
+ try {
+ macro_execute(p ? p+1 : macro);
+ } catch (...) {
+ g_free(macro);
return false;
+ }
+ g_free(macro);
macro_pc = 0;
States::current = &States::start;
return true;
}
+State::Error::Error(const gchar *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ interface.vmsg(Interface::MSG_ERROR, fmt, ap);
+ va_end(ap);
+}
+
State::State()
{
for (guint i = 0; i < G_N_ELEMENTS(transitions); i++)
@@ -107,18 +112,14 @@ State::eval_colon(void)
return true;
}
-bool
-State::input(gchar chr)
+void
+State::input(gchar chr) throw (Error)
{
State *state = States::current;
for (;;) {
State *next = state->get_next_state(chr);
- if (!next)
- /* Syntax error */
- return false;
-
if (next == state)
break;
@@ -130,12 +131,10 @@ State::input(gchar chr)
undo.push_var<State *>(States::current);
States::current = state;
}
-
- return true;
}
State *
-State::get_next_state(gchar chr)
+State::get_next_state(gchar chr) throw (Error)
{
State *next = NULL;
guint upper = g_ascii_toupper(chr);
@@ -144,12 +143,14 @@ State::get_next_state(gchar chr)
next = transitions[upper];
if (!next)
next = custom(chr);
+ if (!next)
+ throw SyntaxError(chr);
return next;
}
gchar *
-StateExpectString::machine_input(gchar chr)
+StateExpectString::machine_input(gchar chr) throw (Error)
{
switch (machine.mode) {
case Machine::MODE_UPPER:
@@ -225,7 +226,7 @@ StateExpectString::machine_input(gchar chr)
reg = qregisters[g_ascii_toupper(chr)];
if (!reg)
- return NULL;
+ throw InvalidQRegError(chr);
return state == Machine::STATE_CTL_EQ
? reg->get_string()
@@ -243,7 +244,7 @@ original:
}
State *
-StateExpectString::custom(gchar chr)
+StateExpectString::custom(gchar chr) throw (Error)
{
gchar *insert, *new_str;
@@ -311,12 +312,12 @@ StateExpectQReg::StateExpectQReg() : State()
}
State *
-StateExpectQReg::custom(gchar chr)
+StateExpectQReg::custom(gchar chr) throw (Error)
{
QRegister *reg = qregisters[g_ascii_toupper(chr)];
if (!reg)
- return NULL;
+ throw InvalidQRegError(chr);
return got_register(reg);
}
@@ -418,7 +419,7 @@ StateStart::delete_words(gint64 n)
}
State *
-StateStart::custom(gchar chr)
+StateStart::custom(gchar chr) throw (Error)
{
gint64 v;
tecoBool rc;
@@ -656,7 +657,7 @@ StateStart::custom(gchar chr)
} else if (eval_colon()) {
expressions.push(FAILURE);
} else {
- return NULL; /* FIXME */
+ throw MoveError("J");
}
break;
@@ -666,7 +667,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("C");
break;
case 'R':
@@ -675,7 +676,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("R");
break;
case 'L':
@@ -684,7 +685,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("L");
break;
case 'B':
@@ -693,7 +694,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw MoveError("B");
break;
case 'W': {
@@ -728,7 +729,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(FAILURE);
else
- return NULL; /* FIXME */
+ throw MoveError("W");
}
break;
}
@@ -739,7 +740,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw Error("Not enough words to delete with <V>");
break;
case 'Y':
@@ -748,7 +749,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw Error("Not enough words to delete with <Y>");
break;
case '=':
@@ -792,7 +793,7 @@ StateStart::custom(gchar chr)
if (eval_colon())
expressions.push(rc);
else if (IS_FAILURE(rc))
- return NULL; /* FIXME */
+ throw RangeError(chr);
if (len == 0 || IS_FAILURE(rc))
break;
@@ -807,7 +808,7 @@ StateStart::custom(gchar chr)
}
default:
- return NULL;
+ throw SyntaxError(chr);
}
return this;
@@ -819,7 +820,7 @@ StateFlowCommand::StateFlowCommand() : State()
}
State *
-StateFlowCommand::custom(gchar chr)
+StateFlowCommand::custom(gchar chr) throw (Error)
{
switch (chr) {
/*
@@ -880,7 +881,7 @@ StateFlowCommand::custom(gchar chr)
break;
default:
- return NULL;
+ throw SyntaxError(chr);
}
return &States::start;
@@ -892,7 +893,7 @@ StateCondCommand::StateCondCommand() : State()
}
State *
-StateCondCommand::custom(gchar chr)
+StateCondCommand::custom(gchar chr) throw (Error)
{
gint64 value = 0;
bool result;
@@ -959,7 +960,7 @@ StateCondCommand::custom(gchar chr)
result = g_ascii_isupper((gchar)value);
break;
default:
- return NULL;
+ throw Error("Invalid conditional type \"%c\"", chr);
}
if (!result) {
@@ -978,7 +979,7 @@ StateControl::StateControl() : State()
}
State *
-StateControl::custom(gchar chr)
+StateControl::custom(gchar chr) throw (Error)
{
switch (g_ascii_toupper(chr)) {
case 'O':
@@ -1036,7 +1037,7 @@ StateControl::custom(gchar chr)
break;
default:
- return NULL;
+ throw Error("Unsupported command <^%c>", chr);
}
return &States::start;
@@ -1051,17 +1052,18 @@ StateECommand::StateECommand() : State()
}
State *
-StateECommand::custom(gchar chr)
+StateECommand::custom(gchar chr) throw (Error)
{
switch (g_ascii_toupper(chr)) {
case 'F':
BEGIN_EXEC(&States::start);
if (!ring.current)
- return NULL; /* FIXME */
+ throw Error("No buffer selected");
if (IS_FAILURE(expressions.pop_num_calc()) &&
ring.current->dirty)
- return NULL; /* FIXME */
+ throw Error("Buffer \"%s\" is dirty",
+ ring.current->filename ? : "(Unnamed)");
ring.close();
break;
@@ -1071,14 +1073,14 @@ StateECommand::custom(gchar chr)
if (IS_FAILURE(expressions.pop_num_calc()) &&
ring.is_any_dirty())
- return NULL; /* FIXME */
+ throw Error("Modified buffers exist");
undo.push_var<bool>(quit_requested);
quit_requested = true;
break;
default:
- return NULL;
+ throw SyntaxError(chr);
}
return &States::start;
@@ -1090,7 +1092,7 @@ StateECommand::custom(gchar chr)
* syntactically
*/
void
-StateInsert::initial(void)
+StateInsert::initial(void) throw (Error)
{
int args;
@@ -1112,7 +1114,7 @@ StateInsert::initial(void)
}
void
-StateInsert::process(const gchar *str, gint new_chars)
+StateInsert::process(const gchar *str, gint new_chars) throw (Error)
{
interface.ssm(SCI_BEGINUNDOACTION);
interface.ssm(SCI_ADDTEXT, new_chars,
@@ -1123,14 +1125,14 @@ StateInsert::process(const gchar *str, gint new_chars)
}
State *
-StateInsert::done(const gchar *str __attribute__((unused)))
+StateInsert::done(const gchar *str __attribute__((unused))) throw (Error)
{
/* nothing to be done when done */
return &States::start;
}
void
-StateSearch::initial(void)
+StateSearch::initial(void) throw (Error)
{
gint64 v;
@@ -1143,6 +1145,10 @@ StateSearch::initial(void)
parameters.count = 1;
parameters.from = (gint)v;
parameters.to = (gint)expressions.pop_num_calc();
+
+ if (!Validate::pos(parameters.from) ||
+ !Validate::pos(parameters.to))
+ throw RangeError("S");
} else {
parameters.count = (gint)v;
if (v >= 0) {
@@ -1246,7 +1252,8 @@ StateSearch::class2regexp(MatchState &state, const gchar *&pattern,
}
gchar *
-StateSearch::pattern2regexp(const gchar *&pattern, bool single_expr)
+StateSearch::pattern2regexp(const gchar *&pattern,
+ bool single_expr)
{
MatchState state = STATE_START;
gchar *re = NULL;
@@ -1357,7 +1364,8 @@ error:
}
void
-StateSearch::process(const gchar *str, gint new_chars __attribute__((unused)))
+StateSearch::process(const gchar *str,
+ gint new_chars __attribute__((unused))) throw (Error)
{
static const gint flags = G_REGEX_CASELESS | G_REGEX_MULTILINE |
G_REGEX_DOTALL | G_REGEX_RAW;
@@ -1447,7 +1455,7 @@ StateSearch::process(const gchar *str, gint new_chars __attribute__((unused)))
}
State *
-StateSearch::done(const gchar *str)
+StateSearch::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);
diff --git a/parser.h b/parser.h
index e7bbd1e..936e530 100644
--- a/parser.h
+++ b/parser.h
@@ -10,6 +10,44 @@
#define MAX_TRANSITIONS 127
class State {
+public:
+ class Error {
+ public:
+ Error(const gchar *fmt, ...);
+ };
+
+ class SyntaxError : public Error {
+ public:
+ SyntaxError(gchar chr)
+ : Error("Syntax error \"%c\" (%d)", chr, chr) {}
+ };
+
+ class MoveError : public Error {
+ public:
+ MoveError(const gchar *cmd)
+ : Error("Attempt to move pointer off page with <%s>",
+ cmd) {}
+ MoveError(gchar cmd)
+ : Error("Attempt to move pointer off page with <%c>",
+ cmd) {}
+ };
+
+ class RangeError : public Error {
+ public:
+ RangeError(const gchar *cmd)
+ : Error("Invalid range specified for <%s>", cmd) {}
+ RangeError(gchar cmd)
+ : Error("Invalid range specified for <%c>", cmd) {}
+ };
+
+ class InvalidQRegError : public Error {
+ public:
+ InvalidQRegError(const gchar *name)
+ : Error("Invalid Q-Register \"%s\"", name) {}
+ InvalidQRegError(gchar name)
+ : Error("Invalid Q-Register \"%c\"", name) {}
+ };
+
protected:
/* static transitions */
State *transitions[MAX_TRANSITIONS];
@@ -29,15 +67,16 @@ protected:
public:
State();
- static bool input(gchar chr);
- State *get_next_state(gchar chr);
+ static void input(gchar chr) throw (Error);
+ State *get_next_state(gchar chr) throw (Error);
protected:
static bool eval_colon(void);
virtual State *
- custom(gchar chr)
+ custom(gchar chr) throw (Error)
{
+ throw SyntaxError(chr);
return NULL;
}
};
@@ -75,13 +114,13 @@ public:
StateExpectString() : State() {}
private:
- gchar *machine_input(gchar key);
- State *custom(gchar chr);
+ gchar *machine_input(gchar key) throw (Error);
+ State *custom(gchar chr) throw (Error);
protected:
- virtual void initial(void) {}
- virtual void process(const gchar *str, gint new_chars) {}
- virtual State *done(const gchar *str) = 0;
+ virtual void initial(void) throw (Error) {}
+ virtual void process(const gchar *str, gint new_chars) throw (Error) {}
+ virtual State *done(const gchar *str) throw (Error) = 0;
};
class QRegister;
@@ -94,14 +133,14 @@ public:
StateExpectQReg();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
protected:
/*
* FIXME: would be nice to pass reg as reference, but there are
* circular header dependencies...
*/
- virtual State *got_register(QRegister *reg) = 0;
+ virtual State *got_register(QRegister *reg) throw (Error) = 0;
};
class StateStart : public State {
@@ -113,7 +152,7 @@ private:
tecoBool move_lines(gint64 n);
tecoBool delete_words(gint64 n);
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateControl : public State {
@@ -121,7 +160,7 @@ public:
StateControl();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateFlowCommand : public State {
@@ -129,7 +168,7 @@ public:
StateFlowCommand();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateCondCommand : public State {
@@ -137,7 +176,7 @@ public:
StateCondCommand();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateECommand : public State {
@@ -145,14 +184,14 @@ public:
StateECommand();
private:
- State *custom(gchar chr);
+ State *custom(gchar chr) throw (Error);
};
class StateInsert : public StateExpectString {
private:
- void initial(void);
- void process(const gchar *str, gint new_chars);
- State *done(const gchar *str);
+ void initial(void) throw (Error);
+ void process(const gchar *str, gint new_chars) throw (Error);
+ State *done(const gchar *str) throw (Error);
};
class StateSearch : public StateExpectString {
@@ -176,9 +215,9 @@ private:
bool escape_default = false);
gchar *pattern2regexp(const gchar *&pattern, bool single_expr = false);
- void initial(void);
- void process(const gchar *str, gint new_chars);
- State *done(const gchar *str);
+ void initial(void) throw (Error);
+ void process(const gchar *str, gint new_chars) throw (Error);
+ State *done(const gchar *str) throw (Error);
};
extern gint macro_pc;
@@ -210,7 +249,7 @@ extern enum Mode {
extern gchar *strings[2];
extern gchar escape_char;
-bool macro_execute(const gchar *macro);
+void macro_execute(const gchar *macro) throw (State::Error);
bool file_execute(const gchar *filename);
#endif
diff --git a/qbuffers.cpp b/qbuffers.cpp
index 28b54dc..d8294ed 100644
--- a/qbuffers.cpp
+++ b/qbuffers.cpp
@@ -495,7 +495,7 @@ StateEditFile::do_edit(const gchar *filename)
}
void
-StateEditFile::initial(void)
+StateEditFile::initial(void) throw (Error)
{
gint64 id = expressions.pop_num_calc(1, -1);
@@ -510,7 +510,7 @@ StateEditFile::initial(void)
}
State *
-StateEditFile::done(const gchar *str)
+StateEditFile::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -554,18 +554,18 @@ StateEditFile::done(const gchar *str)
}
State *
-StateSaveFile::done(const gchar *str)
+StateSaveFile::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);
if (!ring.save(*str ? str : NULL))
- return NULL;
+ throw Error("Unable to save file");
return &States::start;
}
State *
-StateEQCommand::got_register(QRegister *reg)
+StateEQCommand::got_register(QRegister *reg) throw (Error)
{
BEGIN_EXEC(&States::loadqreg);
register_argument = reg;
@@ -573,7 +573,7 @@ StateEQCommand::got_register(QRegister *reg)
}
State *
-StateLoadQReg::done(const gchar *str)
+StateLoadQReg::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -593,7 +593,7 @@ StateLoadQReg::done(const gchar *str)
}
State *
-StateCtlUCommand::got_register(QRegister *reg)
+StateCtlUCommand::got_register(QRegister *reg) throw (Error)
{
BEGIN_EXEC(&States::setqregstring);
register_argument = reg;
@@ -601,7 +601,7 @@ StateCtlUCommand::got_register(QRegister *reg)
}
State *
-StateSetQRegString::done(const gchar *str)
+StateSetQRegString::done(const gchar *str) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -612,7 +612,7 @@ StateSetQRegString::done(const gchar *str)
}
State *
-StateGetQRegInteger::got_register(QRegister *reg)
+StateGetQRegInteger::got_register(QRegister *reg) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -623,7 +623,7 @@ StateGetQRegInteger::got_register(QRegister *reg)
}
State *
-StateSetQRegInteger::got_register(QRegister *reg)
+StateSetQRegInteger::got_register(QRegister *reg) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -634,7 +634,7 @@ StateSetQRegInteger::got_register(QRegister *reg)
}
State *
-StateIncreaseQReg::got_register(QRegister *reg)
+StateIncreaseQReg::got_register(QRegister *reg) throw (Error)
{
BEGIN_EXEC(&States::start);
@@ -646,11 +646,10 @@ StateIncreaseQReg::got_register(QRegister *reg)
}
State *
-StateMacro::got_register(QRegister *reg)
+StateMacro::got_register(QRegister *reg) throw (Error)
{
gint pc = macro_pc;
gchar *str;
- bool rc;
BEGIN_EXEC(&States::start);
@@ -664,18 +663,23 @@ StateMacro::got_register(QRegister *reg)
macro_pc = 0;
str = reg->get_string();
- rc = macro_execute(str);
+ try {
+ macro_execute(str);
+ } catch (...) {
+ g_free(str);
+ macro_pc = pc;
+ States::current = this;
+ throw; /* forward */
+ }
g_free(str);
macro_pc = pc;
States::current = this;
- if (!rc)
- return NULL;
return &States::start;
}
State *
-StateCopyToQReg::got_register(QRegister *reg)
+StateCopyToQReg::got_register(QRegister *reg) throw (Error)
{
gint64 from, len;
Sci_TextRange tr;
@@ -687,6 +691,10 @@ StateCopyToQReg::got_register(QRegister *reg)
from = interface.ssm(SCI_GETCURRENTPOS);
sptr_t line = interface.ssm(SCI_LINEFROMPOSITION, from) +
expressions.pop_num_calc();
+
+ if (!Validate::line(line))
+ throw RangeError("X");
+
len = interface.ssm(SCI_POSITIONFROMLINE, line) - from;
if (len < 0) {
@@ -696,6 +704,10 @@ StateCopyToQReg::got_register(QRegister *reg)
} else {
gint64 to = expressions.pop_num();
from = expressions.pop_num();
+
+ if (!Validate::pos(from) || !Validate::pos(to))
+ throw RangeError("X");
+
len = to - from;
}
diff --git a/qbuffers.h b/qbuffers.h
index 01e7ae7..18d1462 100644
--- a/qbuffers.h
+++ b/qbuffers.h
@@ -305,58 +305,58 @@ class StateEditFile : public StateExpectString {
private:
void do_edit(const gchar *filename);
- void initial(void);
- State *done(const gchar *str);
+ void initial(void) throw (Error);
+ State *done(const gchar *str) throw (Error);
};
class StateSaveFile : public StateExpectString {
private:
- State *done(const gchar *str);
+ State *done(const gchar *str) throw (Error);
};
class StateEQCommand : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateLoadQReg : public StateExpectString {
private:
- State *done(const gchar *str);
+ State *done(const gchar *str) throw (Error);
};
class StateCtlUCommand : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateSetQRegString : public StateExpectString {
private:
- State *done(const gchar *str);
+ State *done(const gchar *str) throw (Error);
};
class StateGetQRegInteger : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateSetQRegInteger : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateIncreaseQReg : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateMacro : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
class StateCopyToQReg : public StateExpectQReg {
private:
- State *got_register(QRegister *reg);
+ State *got_register(QRegister *reg) throw (Error);
};
namespace States {