modules - The way to implement new functions in Extenso
modules
The first thing to setup is the name of the module in the configuration file:
Module exemple { Library : "/usr/local/lib/libsnexemple.so" Init : "snexemple_init" vara : "valuea" varb : "valueb" }
The value vara and varb are parameters for the module. You can add as many as you want.
The function snexemple_init is the initialization routine which exposes all functions:
sncode snexemple_init(snconfig *c, snmodules *m) { SNDEBUG( "snexemple_init(c=%x,m=%x,%s)\n", c, m, m->library); apr_hash_set(c -> sfcts, "twice", 5, (void *)snexemple_twice); SNDEBUG("var %p vara = %s\n", m -> module_var, (char *) apr_hash_get(m -> module_var, "vara", 4)); SNDEBUG("return from snexemple_init\n"); return snok; }
This example exposes the function twice or addw the twice function to the hash array of all predefined functions.
The initialization of the file is:
#include#define SNDEBUG(x...) { fprintf(stderr, "Pid %d file %s line %d ", getpid(), __FILE__, __LINE__); fprintf(stderr, x); } #define SNERROR(p, errcode, x...) snexec_error(p, errcode, x); int snexemple_twice(snfctcall *fc) { snparser *p = fc -> p; /* Parser pointer */ snvalue *s = fc -> s; /* Stack */ bool fctcb = fc -> fctcb; /* Is this a callback */ int nbargs = fc -> nbargs; /* Number of args */ int *sp = fc -> sp; /* Stack pointer */ ...
This defines the SNERROR macros and SNDEBUG. If the user doesn’t want debugging information, then one needs to redefine SNDEBUG to nothing.
The function twice is responded to do the job. It must check the arguments, see if there is an error, and do the job. It must clear the stack of its argument and MUST return a new item on the stack. Clearing the stack is done with:
(*sp)-=(nbargs-1);
Returning an element on the stack is done with:
v = &s[*sp-1]; v -> typeval = SNIVAL; v -> ival = i >> 2; v -> narg = false;
The arguement fctcb is a boolean that determine if this function is call as a callback or as a function.
If this function is call as a callback, then the following variables are also defines:
It returns snok if there is no error. It returns SNERROR(p, snerrexec, "Function twice required 1 argument.\n"); if there is an error
Full codes of this example:
/*----------------------------------------------------------------------------*/ /*! \file This file is a module example. \version 1.0 Initial Version \date Sun Feb 2 17:17:54 2003 \author Pierre Laplante \verbatim Copyright © 2011 SedNove Inc. 439 OAK St-Lambert, QC, Canada All rights reserved. Wed Feb 5 22:09:31 2003 Pierre.Laplante@sednove.com \endverbatim */ /*----------------------------------------------------------------------------*/ #include#define SNDEBUG(x...) { fprintf(stderr, "Pid %d file %s line %d ", getpid(), __FILE__, __LINE__); fprintf(stderr, x); } #define SNERROR(p, errcode, x...) snexec_error(p, errcode, x); /*----------------------------------------------------------------------------*/ /// /// Fonction twice /// /*----------------------------------------------------------------------------*/ int snexemple_twice(snfctcall *fc) { snparser *p = fc -> p; /* Parser pointer */ snvalue *s = fc -> s; /* Stack */ bool fctcb = fc -> fctcb; /* Is this a callback */ int nbargs = fc -> nbargs; /* Number of args */ int *sp = fc -> sp; /* Stack pointer */ int i,j; snvalue *v; SNDEBUG("snexemple_twice(p=%x, nbargs=%d, sp=%d, s=%x)\n", (unsigned int)p, nbargs, *sp, s); if (nbargs != 1) return SNERROR(p, snerrexec, "Function twice required 1 argument.\n"); if (fctcb) return SNERROR(p, snerrexec, "Function twice can't be used in a callback.\n"); v = &s[*sp-1]; if (v -> typeval != SNIVAL) return SNERROR(p, snerrexec, "Function twice expected an integer.\n"); i = v -> ival; SNDEBUG("value = %d\n", v -> ival); (*sp)-=(nbargs-1); v = &s[*sp-1]; v -> typeval = SNIVAL; v -> ival = i << 1; v -> narg = false; return snok; } /*----------------------------------------------------------------------------*/ /// /// Fonction decr /// /*----------------------------------------------------------------------------*/ int snexemple_decr(snfctcall *fc) { snparser *p = fc -> p; /* Parser pointer */ snvalue *s = fc -> s; /* Stack */ bool fctcb = fc -> fctcb; /* Is this a callback */ int nbargs = fc -> nbargs; /* Number of args */ int *sp = fc -> sp; /* Stack pointer */ int i,j; snvalue *v; SNDEBUG("snexemple_decr(p=%x, nbargs=%d, sp=%d, s=%x)\n", (unsigned int)p, nbargs, *sp, s); if (nbargs != 1) return SNERROR(p, snerrexec, "Function desc required 1 argument.\n"); if (!fctcb) return SNERROR(p, snerrexec, "Function decr can't be used as a function.\n"); v = &s[*sp-1]; if (v -> typeval != SNRVAL) return SNERROR(p, snerrexec, "Function decr expected a variable.\n"); v = v -> rval; if (v -> typeval != SNIVAL) return SNERROR(p, snerrexec, "Function decr expected a integer variable.\n"); v -> ival--; i = v -> ival; SNDEBUG("value of %s is now = %d\n", p -> cb -> varname, v -> ival); (*sp)-=(nbargs-1); v = &s[*sp-1]; v -> typeval = SNIVAL; v -> ival = i; v -> narg = false; p -> cb -> var -> ival = i * 2; p -> cb -> var -> typeval = SNIVAL; return snok; } /*------------------------------------------------------------------------------*/ /*! \brief snexemple_init Initialise functions for this module \author Pierre Laplante \date Wed Aug 13 15:50:20 2003 */ /*------------------------------------------------------------------------------*/ sncode snexemple_init(snconfig *c, snmodules *m) { SNDEBUG( "snexemple_init(c=%x,m=%x,%s)\n", c, m, m->library); apr_hash_set(c -> sfcts, "twice", 5, (void *)snexemple_twice); apr_hash_set(c -> sfcts, "decr", 4, (void *)snexemple_decr); SNDEBUG("return from snexemple_init\n"); return snok; }
Written by Pierre Laplante and Caroline Laplante, <laplante@sednove.com>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.
1.0 2014-09-09 21:24:14 laplante@sednove.com