/*
* Copyright (C) 2012-2015 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
#include "sciteco.h"
#include "interface.h"
#include "ioview.h"
#include "undo.h"
#include "rbtree.h"
#include "parser.h"
#include "document.h"
namespace SciTECO {
namespace QRegisters {
/* initialized after Interface::main() in main() */
extern IOView view;
}
/*
* Classes
*/
class QRegisterData {
protected:
tecoInt integer;
class QRegisterString : public Document {
public:
~QRegisterString()
{
release_document();
}
private:
ViewCurrent &
get_create_document_view(void)
{
return QRegisters::view;
}
} string;
public:
/*
* Whether to generate UndoTokens (unnecessary in macro invocations).
*
* FIXME: Every QRegister has this field, but it only differs
* between local and global QRegisters. This wastes space.
* There must be a more clever way to inherit this property, e.g.
* by setting QRegisters::current_must_undo.
*/
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;
}
virtual void set_string(const gchar *str, gsize len);
inline void
set_string(const gchar *str)
{
set_string(str, str ? strlen(str) : 0);
}
virtual void undo_set_string(void);
virtual void append_string(const gchar *str, gsize len);
inline void
append_string(const gchar *str)
{
append_string(str, str ? strlen(str) : 0);
}
virtual inline void
undo_append_string(void)
{
undo_set_string();
}
virtual gchar *get_string(void);
virtual gsize get_string_size(void);
virtual gint get_character(gint position);
/*
* The QRegisterStack must currently access the
* integer and string fields directly to exchange
* data efficiently.
*/
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);
void undo_set_eol_mode(void);
void set_eol_mode(gint mode);
/*
* Load and save already care about undo token
* creation.
*/
void load(const gchar *filename);
void save(const gchar *filename);
};
class QRegisterBufferInfo : public QRegister {
public:
QRegisterBufferInfo() : QRegister("*") {}
/* setting "*" is equivalent to nEB */
tecoInt set_integer(tecoInt v);
void undo_set_integer(void);
tecoInt get_integer(void);
void set_string(const gchar *str, gsize len) {}
void undo_set_string(void) {}
void append_string(const gchar *str, gsize len) {}
void undo_append_string(void) {}
gchar *get_string(void);
gsize get_string_size(void);
gint get_character(gint pos);
void edit(void);
};
class QRegisterTable : private RBTree {
class UndoTokenRemove : public UndoTokenWithSize {
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)
{
gchar buf[] = {name, '\0'};
return insert(buf);
}
inline QRegister *
operator [](const gchar *name)
{
QRegister reg(name);
return (QRegister *)find(®);
}
inline QRegister *
operator [](gchar chr)
{
gchar buf[] = {chr, '\0'};
return operator [](buf);
}
void edit(QRegister *reg);
inline QRegister *
edit(const gchar *name)
{
QRegister *reg = operator [](name);
if (!reg)
return NULL;
edit(reg);
return reg;
}
void clear(void);
};
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()
{
delete entry;
}
void run(void);
gsize
get_size(void) const
{
return entry ? sizeof(*this) + sizeof(*entry)
: sizeof(*this);
}
};
class UndoTokenPop : public UndoTokenWithSize {
QRegisterStack *stack;
public:
UndoTokenPop(QRegisterStack *_stack)
: 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);
};
/*
* 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);
protected:
virtual State *got_register(QRegister ®) = 0;
};
class StatePushQReg : public StateExpectQReg {
private:
State *got_register(QRegister ®);
};
class StatePopQReg : public StateExpectQReg {
public:
StatePopQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateEQCommand : public StateExpectQReg {
public:
StateEQCommand() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateLoadQReg : public StateExpectFile {
private:
State *done(const gchar *str);
};
class StateEPctCommand : public StateExpectQReg {
private:
State *got_register(QRegister ®);
};
class StateSaveQReg : public StateExpectFile {
private:
State *done(const gchar *str);
};
class StateQueryQReg : public StateExpectQReg {
private:
State *got_register(QRegister ®);
};
class StateCtlUCommand : public StateExpectQReg {
public:
StateCtlUCommand() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateEUCommand : public StateExpectQReg {
public:
StateEUCommand() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateSetQRegString : public StateExpectString {
bool text_added;
public:
StateSetQRegString(bool building)
: StateExpectString(building) {}
private:
void initial(void);
State *done(const gchar *str);
};
class StateGetQRegString : public StateExpectQReg {
private:
State *got_register(QRegister ®);
};
class StateSetQRegInteger : public StateExpectQReg {
public:
StateSetQRegInteger() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateIncreaseQReg : public StateExpectQReg {
public:
StateIncreaseQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
class StateMacro : public StateExpectQReg {
private:
State *got_register(QRegister ®);
};
class StateMacroFile : public StateExpectFile {
private:
State *done(const gchar *str);
};
class StateCopyToQReg : public StateExpectQReg {
public:
StateCopyToQReg() : StateExpectQReg(true) {}
private:
State *got_register(QRegister ®);
};
namespace States {
extern StatePushQReg pushqreg;
extern StatePopQReg popqreg;
extern StateEQCommand eqcommand;
extern StateLoadQReg loadqreg;
extern StateEPctCommand epctcommand;
extern StateSaveQReg saveqreg;
extern StateQueryQReg queryqreg;
extern StateCtlUCommand ctlucommand;
extern StateEUCommand eucommand;
extern StateSetQRegString setqregstring_nobuilding;
extern StateSetQRegString setqregstring_building;
extern StateGetQRegString getqregstring;
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;
enum Hook {
HOOK_ADD = 1,
HOOK_EDIT,
HOOK_CLOSE,
HOOK_QUIT
};
void hook(Hook type);
}
} /* namespace SciTECO */
#endif