summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-02-21 13:27:51 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-02-21 13:27:51 +0000
commit04622f7d2210cbb8036502afadf5bcdcb0394d28 (patch)
tree1ba5f0321aaf86f6050193dd8283d85a7f4acd39
parent1cc790fae01e4392d4cf96820f6402528f611c44 (diff)
downloadrsyslog-04622f7d2210cbb8036502afadf5bcdcb0394d28.tar.gz
rsyslog-04622f7d2210cbb8036502afadf5bcdcb0394d28.tar.xz
rsyslog-04622f7d2210cbb8036502afadf5bcdcb0394d28.zip
first steps in implementing object interfaces (stage work for later dynamic
class loading)
-rw-r--r--conf.c16
-rw-r--r--conf.h1
-rw-r--r--expr.c58
-rw-r--r--expr.h16
-rw-r--r--obj-types.h10
-rw-r--r--obj.c22
-rw-r--r--syslogd.c13
-rw-r--r--var.c27
-rw-r--r--var.h18
-rw-r--r--vmop.c7
-rw-r--r--vmop.h1
-rw-r--r--vmprg.c72
-rw-r--r--vmprg.h21
13 files changed, 215 insertions, 67 deletions
diff --git a/conf.c b/conf.c
index 4fcf962e..89bc1c33 100644
--- a/conf.c
+++ b/conf.c
@@ -55,6 +55,7 @@
#include "srUtils.h"
/* static data */
+DEFobjCurrIf(expr)
uchar *pModDir = NULL; /* read-only after startup */
/* The following global variables are used for building
@@ -754,11 +755,11 @@ dbgprintf("calling expression parser, pp %p ('%s')\n", *pline, *pline);
CHKiRet(ctokConstructFinalize(ctok));
/* now construct our expression */
- CHKiRet(exprConstruct(&f->f_filterData.f_expr));
- CHKiRet(exprConstructFinalize(f->f_filterData.f_expr));
+ CHKiRet(expr.Construct(&f->f_filterData.f_expr));
+ CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr));
/* ready to go... */
- CHKiRet(exprParse(f->f_filterData.f_expr, ctok));
+ CHKiRet(expr.Parse(f->f_filterData.f_expr, ctok));
/* we now need to parse off the "then" - and note an error if it is
* missing...
@@ -1148,5 +1149,14 @@ cfline(uchar *line, selector_t **pfCurr)
}
+/* "mimic" a real object - we are currently not one... */
+rsRetVal confClassInit(void)
+{
+ DEFiRet;
+ /* request objects we use */
+ CHKiRet(objUse(expr));
+finalize_it:
+ RETiRet;
+}
/* vi:set ai:
*/
diff --git a/conf.h b/conf.h
index 83ad78bf..6a49ff71 100644
--- a/conf.h
+++ b/conf.h
@@ -36,6 +36,7 @@ rsRetVal doModLoad(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal cfline(uchar *line, selector_t **pfCurr);
rsRetVal processConfFile(uchar *pConfFile);
+rsRetVal confClassInit(void); /* TODO: make this a real object! */
/* TODO: remove them below (means move the config init code) -- rgerhards, 2008-02-19 */
extern uchar *pModDir; /* read-only after startup */
diff --git a/expr.c b/expr.c
index f43e6ce7..785d4216 100644
--- a/expr.c
+++ b/expr.c
@@ -36,6 +36,8 @@
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(vmprg)
+DEFobjCurrIf(var)
/* ------------------------------ parser functions ------------------------------ */
@@ -69,17 +71,17 @@ terminal(expr_t *pThis, ctok_t *ctok)
switch(pToken->tok) {
case ctok_SIMPSTR:
- CHKiRet(varConstruct(&pVar));
- CHKiRet(varConstructFinalize(pVar));
+ CHKiRet(var.Construct(&pVar));
+ CHKiRet(var.ConstructFinalize(pVar));
CHKiRet(ctok_tokenUnlinkCStr(pToken, &pCStr));
- CHKiRet(varSetString(pVar, pCStr));
+ CHKiRet(var.SetString(pVar, pCStr));
dbgoprint((obj_t*) pThis, "simpstr\n");
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */
// push val
break;
case ctok_NUMBER:
dbgoprint((obj_t*) pThis, "number\n");
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, NULL)); /* add to program */
// push val
break;
case ctok_FUNCTION:
@@ -89,12 +91,12 @@ terminal(expr_t *pThis, ctok_t *ctok)
break;
case ctok_MSGVAR:
dbgoprint((obj_t*) pThis, "MSGVAR\n");
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, NULL)); /* add to program */
// push val
break;
case ctok_SYSVAR:
dbgoprint((obj_t*) pThis, "SYSVAR\n");
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_PUSHSYSVAR, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHSYSVAR, NULL)); /* add to program */
// push val
break;
case ctok_LPAREN:
@@ -202,7 +204,7 @@ e_cmp(expr_t *pThis, ctok_t *ctok)
if(ctok_tokenIsCmpOp(pToken)) {
dbgoprint((obj_t*) pThis, "cmp\n");
CHKiRet(val(pThis, ctok));
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */
CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
} else {
/* we could not process the token, so push it back */
@@ -233,7 +235,7 @@ e_and(expr_t *pThis, ctok_t *ctok)
/* fill structure */
CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
CHKiRet(e_cmp(pThis, ctok));
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_AND, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_AND, NULL)); /* add to program */
CHKiRet(ctokGetToken(ctok, &pToken));
}
@@ -265,7 +267,7 @@ expr(expr_t *pThis, ctok_t *ctok)
dbgoprint((obj_t*) pThis, "found OR\n");
CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
CHKiRet(e_and(pThis, ctok));
- CHKiRet(vmprgAddVarOperation(pThis->pVmprg, opcode_OR, NULL)); /* add to program */
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_OR, NULL)); /* add to program */
CHKiRet(ctokGetToken(ctok, &pToken));
}
@@ -307,7 +309,7 @@ rsRetVal exprConstructFinalize(expr_t *pThis)
BEGINobjDestruct(expr) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(expr)
if(pThis->pVmprg != NULL)
- vmprgDestruct(&pThis->pVmprg);
+ vmprg.Destruct(&pThis->pVmprg);
ENDobjDestruct(expr)
@@ -362,24 +364,52 @@ exprParse(expr_t *pThis, ctok_t *ctok)
ISOBJ_TYPE_assert(ctok, ctok);
/* first, we need to make sure we have a program where we can add to what we parse... */
- CHKiRet(vmprgConstruct(&pThis->pVmprg));
- CHKiRet(vmprgConstructFinalize(pThis->pVmprg));
+ CHKiRet(vmprg.Construct(&pThis->pVmprg));
+ CHKiRet(vmprg.ConstructFinalize(pThis->pVmprg));
/* happy parsing... */
CHKiRet(expr(pThis, ctok));
dbgoprint((obj_t*) pThis, "successfully parsed/created expression\n");
-vmprgDebugPrint(pThis->pVmprg);
+vmprg.DebugPrint(pThis->pVmprg);
finalize_it:
RETiRet;
}
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(expr)
+CODESTARTobjQueryInterface(expr)
+ if(pIf->ifVersion != exprCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->oID = OBJexpr;
+
+ pIf->Construct = exprConstruct;
+ pIf->ConstructFinalize = exprConstructFinalize;
+ pIf->Destruct = exprDestruct;
+ pIf->Parse = exprParse;
+finalize_it:
+ENDobjQueryInterface(expr)
+
+
/* Initialize the expr class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-19
*/
BEGINObjClassInit(expr, 1) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(vmprg));
+ CHKiRet(objUse(var));
+
OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, exprConstructFinalize);
ENDObjClassInit(expr)
diff --git a/expr.h b/expr.h
index 66516d7d..78005a5a 100644
--- a/expr.h
+++ b/expr.h
@@ -39,11 +39,19 @@ typedef struct expr_s {
} expr_t;
+/* interfaces */
+typedef struct expr_if_s {
+ ifBEGIN; /* This MUST always be the first interface member */
+ INTERFACEObjDebugPrint(expr);
+ rsRetVal (*Construct)(expr_t **ppThis);
+ rsRetVal (*ConstructFinalize)(expr_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(expr_t **ppThis);
+ rsRetVal (*Parse)(expr_t *pThis, ctok_t *ctok);
+} expr_if_t;
+#define exprCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
/* prototypes */
-rsRetVal exprConstruct(expr_t **ppThis);
-rsRetVal exprConstructFinalize(expr_t __attribute__((unused)) *pThis);
-rsRetVal exprDestruct(expr_t **ppThis);
-rsRetVal exprParse(expr_t *pThis, ctok_t *ctok);
PROTOTYPEObjClassInit(expr);
+PROTOTYPEObjQueryInterface(expr);
#endif /* #ifndef INCLUDED_EXPR_H */
diff --git a/obj-types.h b/obj-types.h
index d823af47..3046e96f 100644
--- a/obj-types.h
+++ b/obj-types.h
@@ -296,6 +296,14 @@ typedef struct interface_s {
objID_t oID; /* our object ID (later dynamically assigned) */
} interface_t;
+
+/* the following macro is used to get access to an object (not an instance,
+ * just the class itself!). It must be called before any of the object's
+ * methods can be accessed.
+ */
+#define objUse(obj) \
+ obj##QueryInterface(&obj)
+
/* defines data that must always be present at the very begin of the interface structure */
#define ifBEGIN \
int ifVersion; /* must be set to version requested */ \
@@ -306,7 +314,7 @@ typedef struct interface_s {
* the beginning
*/
#define DEFobjCurrIf(obj) \
- obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION };
+ static obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION };
/* ------------------------------ end object loader system ------------------------------ */
diff --git a/obj.c b/obj.c
index fc6dff67..4177f3ae 100644
--- a/obj.c
+++ b/obj.c
@@ -40,6 +40,7 @@
#include "stream.h"
/* static data */
+DEFobjCurrIf(var)
static objInfo_t *arrObjInfo[OBJ_NUM_IDS]; /* array with object information pointers */
/* some defines */
@@ -612,15 +613,15 @@ static rsRetVal objDeserializeProperties(obj_t *pObj, objID_t oID, strm_t *pStrm
ISOBJ_TYPE_assert(pStrm, strm);
ASSERT(oID > 0 && oID < OBJ_NUM_IDS);
- CHKiRet(varConstruct(&pVar));
- CHKiRet(varConstructFinalize(pVar));
+ CHKiRet(var.Construct(&pVar));
+ CHKiRet(var.ConstructFinalize(pVar));
iRet = objDeserializeProperty(pVar, pStrm);
while(iRet == RS_RET_OK) {
CHKiRet(arrObjInfo[oID]->objMethods[objMethod_SETPROPERTY](pObj, pVar));
iRet = objDeserializeProperty(pVar, pStrm);
}
- varDestruct(&pVar);
+ var.Destruct(&pVar);
if(iRet != RS_RET_NO_PROPLINE)
FINALIZE;
@@ -860,15 +861,24 @@ finalize_it:
/* initialize our own class */
-rsRetVal objClassInit(void)
+rsRetVal
+objClassInit(void)
{
+ DEFiRet;
int i;
-
+
+ /* first, initialize the object system itself. This must be done
+ * before any other object is created.
+ */
for(i = 0 ; i < OBJ_NUM_IDS ; ++i) {
arrObjInfo[i] = NULL;
}
- return RS_RET_OK;
+ /* request objects we use */
+ CHKiRet(objUse(var));
+
+finalize_it:
+ RETiRet;
}
/*
diff --git a/syslogd.c b/syslogd.c
index 1f5d885c..c39e37cf 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -173,6 +173,10 @@
#include "vmop.h"
#include "vmprg.h"
+/* definitions for objects we access */
+DEFobjCurrIf(expr)
+
+
/* We define our own set of syslog defintions so that we
* do not need to rely on (possibly different) implementations.
* 2007-07-19 rgerhards
@@ -1002,7 +1006,7 @@ selectorDestruct(void *pVal)
rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
} else if(pThis->f_filter_type == FILTER_EXPR) {
if(pThis->f_filterData.f_expr != NULL)
- exprDestruct(&pThis->f_filterData.f_expr);
+ expr.Destruct(&pThis->f_filterData.f_expr);
}
llDestroy(&pThis->llActList);
@@ -3413,6 +3417,10 @@ static rsRetVal InitGlobalClasses(void)
DEFiRet;
CHKiRet(objClassInit()); /* *THIS* *MUST* always be the first class initilizer being called! */
+ /* dummy "classes" */
+ CHKiRet(confClassInit());
+
+ /* real ones */
CHKiRet(msgClassInit());
CHKiRet(strmClassInit());
CHKiRet(wtiClassInit());
@@ -3425,6 +3433,9 @@ static rsRetVal InitGlobalClasses(void)
CHKiRet(ctokClassInit());
CHKiRet(exprClassInit());
+ /* request objects we use */
+ CHKiRet(objUse(expr));
+
finalize_it:
RETiRet;
}
diff --git a/var.c b/var.c
index a7e71405..308bd684 100644
--- a/var.c
+++ b/var.c
@@ -104,7 +104,7 @@ varUnsetValues(var_t *pThis)
/* set a string value
*/
-rsRetVal
+static rsRetVal
varSetString(var_t *pThis, cstr_t *pCStr)
{
DEFiRet;
@@ -120,6 +120,31 @@ finalize_it:
}
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(var)
+CODESTARTobjQueryInterface(var)
+ if(pIf->ifVersion != varCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->oID = OBJvar;
+
+ pIf->Construct = varConstruct;
+ pIf->ConstructFinalize = varConstructFinalize;
+ pIf->Destruct = varDestruct;
+ pIf->DebugPrint = varDebugPrint;
+ pIf->SetString = varSetString;
+finalize_it:
+ENDobjQueryInterface(var)
+
+
/* Initialize the var class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-19
diff --git a/var.h b/var.h
index c02b93b2..f400b109 100644
--- a/var.h
+++ b/var.h
@@ -51,12 +51,20 @@ typedef struct var_s {
} var_t;
+/* interfaces */
+typedef struct var_if_s {
+ ifBEGIN; /* This MUST always be the first interface member */
+ INTERFACEObjDebugPrint(var);
+ rsRetVal (*Construct)(var_t **ppThis);
+ rsRetVal (*ConstructFinalize)(var_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(var_t **ppThis);
+ rsRetVal (*SetString)(var_t *pThis, cstr_t *pCStr);
+} var_if_t;
+#define varCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
/* prototypes */
-rsRetVal varConstruct(var_t **ppThis);
-rsRetVal varConstructFinalize(var_t __attribute__((unused)) *pThis);
-rsRetVal varDestruct(var_t **ppThis);
-rsRetVal varSetString(var_t *pThis, cstr_t *pCStr);
PROTOTYPEObjClassInit(var);
-PROTOTYPEObjDebugPrint(var);
+PROTOTYPEObjQueryInterface(var);
#endif /* #ifndef INCLUDED_VAR_H */
diff --git a/vmop.c b/vmop.c
index 978db899..34d70fba 100644
--- a/vmop.c
+++ b/vmop.c
@@ -33,6 +33,7 @@
/* static data */
DEFobjStaticHelpers
+DEFobjCurrIf(var)
/* forward definitions */
@@ -69,7 +70,7 @@ CODESTARTobjDebugPrint(vmop)
dbgoprint((obj_t*) pThis, "opcode: %d\t(%s), next %p, var in next line\n", (int) pThis->opcode, pOpcodeName,
pThis->pNext);
if(pThis->operand.pVar != NULL)
- varDebugPrint(pThis->operand.pVar);
+ var.DebugPrint(pThis->operand.pVar);
ENDobjDebugPrint(vmop)
@@ -205,12 +206,14 @@ finalize_it:
ENDobjQueryInterface(vmop)
-
/* Initialize the vmop class. Must be called as the very first method
* before anything else is called inside this class.
* rgerhards, 2008-02-19
*/
BEGINObjClassInit(vmop, 1) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(var));
+
OBJSetMethodHandler(objMethod_DEBUGPRINT, vmopDebugPrint);
OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmopConstructFinalize);
ENDObjClassInit(vmop)
diff --git a/vmop.h b/vmop.h
index 30e64888..6964f7fd 100644
--- a/vmop.h
+++ b/vmop.h
@@ -77,7 +77,6 @@ typedef struct vmop_if_s {
rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar);
rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName);
} vmop_if_t;
-
#define vmopCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
/* the remaining prototypes */
diff --git a/vmprg.c b/vmprg.c
index 4856ebb2..73b4fda0 100644
--- a/vmprg.c
+++ b/vmprg.c
@@ -44,7 +44,8 @@ ENDobjConstruct(vmprg)
/* ConstructionFinalizer
* rgerhards, 2008-01-09
*/
-rsRetVal vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis)
+static rsRetVal
+vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis)
{
DEFiRet;
ISOBJ_TYPE_assert(pThis, vmprg);
@@ -77,12 +78,36 @@ CODESTARTobjDebugPrint(vmprg)
ENDobjDebugPrint(vmprg)
+/* add an operation (instruction) to the end of the current program. This
+ * function is expected to be called while creating the program, but never
+ * again after this is done and it is being executed. Results are undefined if
+ * it is called after execution.
+ */
+static rsRetVal
+vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp)
+{
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmprg);
+ ISOBJ_TYPE_assert(pOp, vmop);
+
+ if(pThis->vmopRoot == NULL) {
+ pThis->vmopRoot = pOp;
+ } else {
+ pThis->vmopLast->pNext = pOp;
+ }
+ pThis->vmopLast = pOp;
+
+ RETiRet;
+}
+
+
/* this is a shortcut for high-level callers. It creates a new vmop, sets its
* parameters and adds it to the program - all in one big step. If there is no
* var associated with this operation, the caller can simply supply NULL as
* pVar.
*/
-rsRetVal
+static rsRetVal
vmprgAddVarOperation(vmprg_t *pThis, opcode_t opcode, var_t *pVar)
{
DEFiRet;
@@ -106,28 +131,30 @@ finalize_it:
}
-/* add an operation (instruction) to the end of the current program. This
- * function is expected to be called while creating the program, but never
- * again after this is done and it is being executed. Results are undefined if
- * it is called after execution.
+/* queryInterface function
+ * rgerhards, 2008-02-21
*/
-rsRetVal
-vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp)
-{
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, vmprg);
- ISOBJ_TYPE_assert(pOp, vmop);
-
- if(pThis->vmopRoot == NULL) {
- pThis->vmopRoot = pOp;
- } else {
- pThis->vmopLast->pNext = pOp;
+BEGINobjQueryInterface(vmprg)
+CODESTARTobjQueryInterface(vmprg)
+ if(pIf->ifVersion != vmprgCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
}
- pThis->vmopLast = pOp;
- RETiRet;
-}
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->oID = OBJvmprg;
+
+ pIf->Construct = vmprgConstruct;
+ pIf->ConstructFinalize = vmprgConstructFinalize;
+ pIf->Destruct = vmprgDestruct;
+ pIf->DebugPrint = vmprgDebugPrint;
+ pIf->AddOperation = vmprgAddOperation;
+ pIf->AddVarOperation = vmprgAddVarOperation;
+finalize_it:
+ENDobjQueryInterface(vmprg)
/* Initialize the vmprg class. Must be called as the very first method
@@ -136,8 +163,7 @@ vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp)
*/
BEGINObjClassInit(vmprg, 1) /* class, version */
/* request objects we use */
- //objUse(vmop);
- CHKiRet(vmopQueryInterface(&vmop));
+ CHKiRet(objUse(vmop));
/* set our own handlers */
OBJSetMethodHandler(objMethod_DEBUGPRINT, vmprgDebugPrint);
diff --git a/vmprg.h b/vmprg.h
index a2ddf1ba..f69abca1 100644
--- a/vmprg.h
+++ b/vmprg.h
@@ -47,13 +47,22 @@ typedef struct vmprg_s {
} vmprg_t;
+/* interfaces */
+typedef struct vmprg_if_s {
+ ifBEGIN; /* This MUST always be the first interface member */
+ INTERFACEObjDebugPrint(vmprg);
+ rsRetVal (*Construct)(vmprg_t **ppThis);
+ rsRetVal (*ConstructFinalize)(vmprg_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(vmprg_t **ppThis);
+ rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp);
+ rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar);
+} vmprg_if_t;
+
+#define vmprgCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
/* prototypes */
-rsRetVal vmprgConstruct(vmprg_t **ppThis);
-rsRetVal vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis);
-rsRetVal vmprgDestruct(vmprg_t **ppThis);
-rsRetVal vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp);
-rsRetVal vmprgAddVarOperation(vmprg_t *pThis, opcode_t opcode, var_t *pVar);
PROTOTYPEObjClassInit(vmprg);
-PROTOTYPEObjDebugPrint(vmprg);
+PROTOTYPEObjQueryInterface(vmprg);
#endif /* #ifndef INCLUDED_VMPRG_H */