From 04622f7d2210cbb8036502afadf5bcdcb0394d28 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Feb 2008 13:27:51 +0000 Subject: first steps in implementing object interfaces (stage work for later dynamic class loading) --- conf.c | 16 +++++++++++--- conf.h | 1 + expr.c | 58 +++++++++++++++++++++++++++++++++++++------------ expr.h | 16 ++++++++++---- obj-types.h | 10 ++++++++- obj.c | 22 +++++++++++++------ syslogd.c | 13 ++++++++++- var.c | 27 ++++++++++++++++++++++- var.h | 18 +++++++++++----- vmop.c | 7 ++++-- vmop.h | 1 - vmprg.c | 72 +++++++++++++++++++++++++++++++++++++++++-------------------- vmprg.h | 21 ++++++++++++------ 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 */ -- cgit