/*
* Copyright (C) 2012-2013 Robin Haberkorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef __QREGISTERS_H
#define __QREGISTERS_H
#include
#include
#include
#include
#include "sciteco.h"
#include "interface.h"
#include "undo.h"
#include "rbtree.h"
#include "parser.h"
#include "document.h"
/*
* Classes
*/
class QRegisterData {
protected:
tecoInt integer;
TECODocument string;
public:
/*
* whether to generate UndoTokens (unnecessary in macro invocations)
*/
bool must_undo;
QRegisterData() : integer(0), must_undo(true) {}
virtual ~QRegisterData() {}
virtual tecoInt
set_integer(tecoInt i)
{
return integer = i;
}
virtual void
undo_set_integer(void)
{
if (must_undo)
undo.push_var(integer);
}
virtual tecoInt
get_integer(void)
{
return integer;
}
inline void
update_string(void)
{
string.update();
}
virtual void set_string(const gchar *str);
virtual void undo_set_string(void);
virtual void append_string(const gchar *str);
virtual inline void
undo_append_string(void)
{
undo_set_string();
}
virtual gchar *get_string(void);
virtual void edit(void);
virtual void undo_edit(void);
friend class QRegisterStack;
};
class QRegister : public RBTree::RBEntry, public QRegisterData {
public:
gchar *name;
QRegister(const gchar *_name)
: QRegisterData(), name(g_strdup(_name)) {}
virtual
~QRegister()
{
g_free(name);
}
int
operator <(RBEntry &entry)
{
return g_strcmp0(name, ((QRegister &)entry).name);
}
virtual void edit(void);
virtual void undo_edit(void);
void execute(bool locals = true) throw (State::Error, ReplaceCmdline);
bool load(const gchar *filename);
inline void
undo_load(void)
{
undo_set_string();
}
};
class QRegisterBufferInfo : public QRegister {
public:
QRegisterBufferInfo() : QRegister("*") {}
tecoInt
set_integer(tecoInt v)
{
return v;
}
void undo_set_integer(void) {}
tecoInt get_integer(void);
void set_string(const gchar *str) {}
void undo_set_string(void) {}
void append_string(const gchar *str) {}
void undo_append_string(void) {}
gchar *get_string(void);
void edit(void);
};
class QRegisterTable : public RBTree {
class UndoTokenRemove : public UndoToken {
QRegisterTable *table;
QRegister *reg;
public:
UndoTokenRemove(QRegisterTable *_table, QRegister *_reg)
: table(_table), reg(_reg) {}
void
run(void)
{
delete table->remove(reg);
}
};
bool must_undo;
public:
QRegisterTable(bool _undo = true);
inline void
undo_remove(QRegister *reg)
{
if (must_undo)
undo.push(new UndoTokenRemove(this, reg));
}
inline QRegister *
insert(QRegister *reg)
{
reg->must_undo = must_undo;
RBTree::insert(reg);
return reg;
}
inline QRegister *
insert(const gchar *name)
{
return insert(new QRegister(name));
}
inline QRegister *
insert(gchar name)
{
return insert(CHR2STR(name));
}
inline QRegister *
operator [](const gchar *name)
{
QRegister reg(name);
return (QRegister *)find(®);
}
inline QRegister *
operator [](gchar chr)
{
return operator [](CHR2STR(chr));
}
void edit(QRegister *reg);
inline QRegister *
edit(const gchar *name)
{
QRegister *reg = operator [](name);
if (!reg)
return NULL;
edit(reg);
return reg;
}
};
class QRegisterStack {
class Entry : public QRegisterData {
public:
SLIST_ENTRY(Entry) entries;
Entry() : QRegisterData() {}
};
class UndoTokenPush : public UndoToken {
QRegisterStack *stack;
/* only remaining reference to stack entry */
Entry *entry;
public:
UndoTokenPush(QRegisterStack *_stack, Entry *_entry)
: UndoToken(), stack(_stack), entry(_entry) {}
~UndoTokenPush()
{
if (entry)
delete entry;
}
void run(void);
};
class UndoTokenPop : public UndoToken {
QRegisterStack *stack;
public:
UndoTokenPop(QRegisterStack *_stack)
: UndoToken(), stack(_stack) {}
void run(void);
};
SLIST_HEAD(Head, Entry) head;
public:
QRegisterStack()
{
SLIST_INIT(&head);
}
~QRegisterStack();
void push(QRegister ®);
bool pop(QRegister ®);
};
class QRegSpecMachine : public MicroStateMachine {
StringBuildingMachine string_machine;
bool initialize;
bool is_local;
gint nesting;
gchar *name;
public:
QRegSpecMachine(bool _init = false)
: MicroStateMachine(),
initialize(_init),
is_local(false), nesting(0), name(NULL) {}
~QRegSpecMachine()
{
g_free(name);
}
void reset(void);
QRegister *input(gchar chr) throw (State::Error);
};
/*
* Command states
*/
/*
* Super class for states accepting Q-Register specifications
*/
class StateExpectQReg : public State {
QRegSpecMachine machine;
public:
StateExpectQReg(bool initialize = false);
private:
State *custom(gchar chr) throw (Error, ReplaceCmdline);
protected:
virtual State *got_register(QRegister ®)
throw (Error, ReplaceCmdline) = 0;
};
class StatePushQReg : public StateExpectQReg {
private:
State *got_register(QRegister ®) throw (Error);
};
class StatePopQReg : public StateExpectQReg {
public:
StatePopQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
class StateEQCommand : public StateExpectQReg {
public:
StateEQCommand() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
class StateLoadQReg : public StateExpectFile {
private:
State *done(const gchar *str) throw (Error);
};
class StateCtlUCommand : public StateExpectQReg {
public:
StateCtlUCommand() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
class StateSetQRegString : public StateExpectString {
public:
StateSetQRegString() : StateExpectString(false) {}
private:
State *done(const gchar *str) throw (Error);
};
class StateGetQRegString : public StateExpectQReg {
private:
State *got_register(QRegister ®) throw (Error);
};
class StateGetQRegInteger : public StateExpectQReg {
private:
State *got_register(QRegister ®) throw (Error);
};
class StateSetQRegInteger : public StateExpectQReg {
public:
StateSetQRegInteger() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
class StateIncreaseQReg : public StateExpectQReg {
public:
StateIncreaseQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
class StateMacro : public StateExpectQReg {
private:
State *got_register(QRegister ®) throw (Error, ReplaceCmdline);
};
class StateMacroFile : public StateExpectFile {
private:
State *done(const gchar *str) throw (Error);
};
class StateCopyToQReg : public StateExpectQReg {
public:
StateCopyToQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®) throw (Error);
};
namespace States {
extern StatePushQReg pushqreg;
extern StatePopQReg popqreg;
extern StateEQCommand eqcommand;
extern StateLoadQReg loadqreg;
extern StateCtlUCommand ctlucommand;
extern StateSetQRegString setqregstring;
extern StateGetQRegString getqregstring;
extern StateGetQRegInteger getqreginteger;
extern StateSetQRegInteger setqreginteger;
extern StateIncreaseQReg increaseqreg;
extern StateMacro macro;
extern StateMacroFile macro_file;
extern StateCopyToQReg copytoqreg;
}
namespace QRegisters {
/* object declared in main.cpp */
extern QRegisterTable globals;
extern QRegisterTable *locals;
extern QRegister *current;
void undo_edit(void);
enum Hook {
HOOK_ADD = 1,
HOOK_EDIT,
HOOK_CLOSE,
HOOK_QUIT
};
void hook(Hook type);
}
#endif