]> code.citadel.org Git - citadel.git/blobdiff - webcit/subst.c
* implement conditional switches; if true will skip to next "X" with the same value.
[citadel.git] / webcit / subst.c
index 4fea084856abc38041e5f0dcde5365099e1e1633..c46b0855edc64c1719df2edb8b1bcdc6cee14fad 100644 (file)
@@ -26,21 +26,12 @@ HashList *TemplateCache;
 HashList *LocalTemplateCache;
 
 HashList *GlobalNS;
+HashList *Iterators;
+HashList *Contitionals;
 
-typedef struct _TemplateToken {
-       const char *pTokenStart;
-       size_t TokenStart;
-       size_t TokenEnd;
-       const char *pTokenEnd;
-
-       const char *pName;
-       size_t NameEnd;
-
-       int HaveParameters;
-       int nParameters;
-       size_t ParamStart [10];
-       size_t ParamEnd [10];
-} WCTemplateToken;
+#define SV_GETTEXT 1
+#define SV_CONDITIONAL 2
+#define SV_NEG_CONDITIONAL 3
 
 typedef struct _WCTemplate {
        StrBuf *Data;
@@ -49,7 +40,6 @@ typedef struct _WCTemplate {
        WCTemplateToken **Tokens;
 } WCTemplate;
 
-typedef void (*WCHandlerFunc)(int nArgs, WCTemplateToken **Tokens); /*TODO: subset of that */
 typedef struct _HashHandler {
        int nMinArgs;
        int nMaxArgs;
@@ -255,6 +245,42 @@ void SVPut(char *keyname, size_t keylen, int keytype, char *Data)
        ptr->wcs_value = strdup(Data);
 }
 
+/**
+ * \brief Add a substitution variable (local to this session)
+ * \param keyname the replacementstring to substitute
+ * \param keytype the kind of the key
+ * \param format the format string ala printf
+ * \param ... the arguments to substitute in the formatstring
+ */
+void SVPutLong(char *keyname, size_t keylen, long Data)
+{
+       void *vPtr;
+       wcsubst *ptr = NULL;
+       struct wcsession *WCC = WC;
+
+       
+       /**
+        * First look if we're doing a replacement of
+        * an existing key
+        */
+       /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
+       if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
+               ptr = (wcsubst*)vPtr;
+               if (ptr->wcs_value != NULL)
+                       free(ptr->wcs_value);
+       }
+       else    /** Otherwise allocate a new one */
+       {
+               ptr = (wcsubst *) malloc(sizeof(wcsubst));
+               safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
+               Put(WCC->vars, keyname, keylen, ptr,  deletevar);
+       }
+
+       ptr->wcs_function = NULL;
+       ptr->wcs_type = WCS_LONG;
+       ptr->lvalue = Data;
+}
+
 /**
  * \brief Add a substitution variable (local to this session) that does a callback
  * \param keyname the keystring to substitute
@@ -294,27 +320,56 @@ inline void SVCALLBACK(char *keyname, var_callback_fptr fcn_ptr)
 
 
 
+void SVPUTBuf(const char *keyname, int keylen, StrBuf *Buf, int ref)
+{
+       wcsubst *ptr;
+       void *vPtr;
+       struct wcsession *WCC = WC;
+
+       /**
+        * First look if we're doing a replacement of
+        * an existing key
+        */
+       /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
+       if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
+               ptr = (wcsubst*)vPtr;
+               if (ptr->wcs_value != NULL)
+                       free(ptr->wcs_value);///TODO: respect type
+       }
+       else    /** Otherwise allocate a new one */
+       {
+               ptr = (wcsubst *) malloc(sizeof(wcsubst));
+               safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
+               Put(WCC->vars, keyname, keylen, ptr,  deletevar);
+       }
+
+       ptr->wcs_value = NULL;
+       ptr->wcs_type = (ref)?WCS_STRBUF:WCS_STRBUF_REF;
+       ptr->wcs_function = (var_callback_fptr) Buf; ////TODO
+}
+
 /**
  * \brief back end for print_value_of() ... does a server command
  * \param servcmd server command to execute on the citadel server
  */
-void pvo_do_cmd(char *servcmd) {
+void pvo_do_cmd(StrBuf *Target, char *servcmd) {
        char buf[SIZ];
+       int len;
 
        serv_puts(servcmd);
-       serv_getln(buf, sizeof buf);
+       len = serv_getln(buf, sizeof buf);
 
        switch(buf[0]) {
                case '2':
                case '3':
                case '5':
-                       wprintf("%s\n", &buf[4]);
+                       StrBufAppendPrintf(Target, "%s\n", &buf[4]);
                        break;
                case '1':
-                       fmout("CENTER");
+                       _fmout(Target, "CENTER");
                        break;
                case '4':
-                       wprintf("%s\n", &buf[4]);
+                       StrBufAppendPrintf(Target, "%s\n", &buf[4]);
                        serv_puts("000");
                        break;
        }
@@ -324,7 +379,7 @@ void pvo_do_cmd(char *servcmd) {
  * \brief Print the value of a variable
  * \param keyname get a key to print
  */
-void print_value_of(const char *keyname, size_t keylen) {
+void print_value_of(StrBuf *Target, const char *keyname, size_t keylen) {
        struct wcsession *WCC = WC;
        wcsubst *ptr;
        void *fcn();
@@ -332,21 +387,28 @@ void print_value_of(const char *keyname, size_t keylen) {
 
        /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
        if (keyname[0] == '=') {
-               DoTemplate(keyname+1, keylen - 1);
+               DoTemplate(keyname+1, keylen - 1, NULL, NULL);
        }
        /** Page-local variables */
        if ((WCC->vars!= NULL) && GetHash(WCC->vars, keyname, keylen, &vVar)) {
                ptr = (wcsubst*) vVar;
                switch(ptr->wcs_type) {
                case WCS_STRING:
-                       wprintf("%s", (const char*)ptr->wcs_value);
+                       StrBufAppendBufPlain(Target, (const char*)ptr->wcs_value, -1, 0);
                        break;
                case WCS_SERVCMD:
-                       pvo_do_cmd(ptr->wcs_value);
+                       pvo_do_cmd(Target, ptr->wcs_value);
                        break;
                case WCS_FUNCTION:
                        (*ptr->wcs_function) ();
                        break;
+               case WCS_STRBUF:
+               case WCS_STRBUF_REF:
+                       StrBufAppendBuf(Target, (StrBuf*) ptr->wcs_function, 0);
+                       break;
+               case WCS_LONG:
+                       StrBufAppendPrintf(Target, "%l", ptr->lvalue);
+                       break;
                default:
                        lprintf(1,"WARNING: invalid value in SV-Hash at %s!", keyname);
                }
@@ -368,7 +430,7 @@ void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
                                sizeof(WCTemplateToken*) * 
                                Template->TokenSpace * 2);
                        memcpy(NewTokens, Template->Tokens, 
-                              sizeof(WCTemplateToken) * Template->nTokensUsed);
+                              sizeof(WCTemplateToken*) * Template->nTokensUsed);
                        free(Template->Tokens);
                        Template->TokenSpace *= 2;
                        Template->Tokens = NewTokens;
@@ -377,21 +439,136 @@ void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
        Template->Tokens[(Template->nTokensUsed)++] = NewToken;
 }
 
-WCTemplateToken *NewTemlpateSubstitute(const char *pStart, const char *pTmplStart, const char *pTmplEnd)
+TemplateParam *GetNextParamter(StrBuf *Buf, const char **pCh, const char *pe)
+{
+       const char *pch = *pCh;
+       const char *pchs, *pche;
+       TemplateParam *Parm = (TemplateParam *) malloc(sizeof(TemplateParam));
+       char quote = '\0';
+       
+       /* Skip leading whitespaces */
+       while ((*pch == ' ' )||
+              (*pch == '\t')||
+              (*pch == '\r')||
+              (*pch == '\n')) pch ++;
+       if (*pch == '"')
+               quote = '"';
+       else if (*pch == '\'')
+               quote = '\'';
+       if (quote != '\0') {
+               pch ++;
+               pchs = pch;
+               Parm->Type = TYPE_STR;
+               while (pch <= pe &&
+                      ((*pch != quote) ||
+                       ( (pch > pchs) && (*(pch - 1) == '\\'))
+                              )) {
+                       pch ++;
+               }
+               pche = pch;
+               if (*pch != quote) {
+                       lprintf(1, "Error evaluating template param [%s]\n", *pCh);
+                       pch ++;
+                       free(Parm);
+                       return NULL;
+               }
+               else {
+                       StrBufPeek(Buf, pch, -1, '\0');         
+                       lprintf(1, "DBG: got param [%s]\n", pchs);
+                       Parm->Start = pchs;
+                       Parm->len = pche - pchs;
+                       pch ++; /* move after trailing quote */
+               }
+       }
+       else {
+               Parm->Type = TYPE_LONG;
+               pchs = pch;
+               while ((pch <= pe) &&
+                      (isdigit(*pch) ||
+                       (*pch == '+') ||
+                       (*pch == '-')))
+                       pch ++;
+               pch ++;
+               if (pch - pchs > 1){
+                       StrBufPeek(Buf, pch, -1, '\0');
+                       Parm->lvalue = atol(pchs);
+                       Parm->Start = pchs;
+                       pch++;
+               }
+               else {
+                       Parm->lvalue = 0;
+                       lprintf(1, "Error evaluating template long param [%s]", *pCh);
+                       free(Parm);
+                       return NULL;
+               }
+       }
+       while ((*pch == ' ' )||
+              (*pch == '\t')||
+              (*pch == '\r')||
+              (*pch == ',' )||
+              (*pch == '\n')) pch ++;
+
+       *pCh = pch;
+       return Parm;
+}
+
+WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf, 
+                                      const char *pStart, 
+                                      const char *pTmplStart, 
+                                      const char *pTmplEnd)
 {
+       const char *pch;
+       TemplateParam *Param;
        WCTemplateToken *NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
 
+       NewToken->Flags = 0;
        NewToken->pTokenStart = pTmplStart;
        NewToken->TokenStart = pTmplStart - pStart;
        NewToken->TokenEnd =  (pTmplEnd - pStart) - NewToken->TokenStart;
        NewToken->pTokenEnd = pTmplEnd;
-       
-       NewToken->pName = pTmplStart + 2;
        NewToken->NameEnd = NewToken->TokenEnd - 2;
+       
+       StrBufPeek(Buf, pTmplStart, + 1, '\0');
+       StrBufPeek(Buf, pTmplEnd, -1, '\0');
+       pch = NewToken->pName = pTmplStart + 2;
+
        NewToken->HaveParameters = 0;;
        NewToken->nParameters = 0;
-       NewToken->ParamStart[0] = 0;
-       NewToken->ParamEnd[0] = 0;
+
+       while (pch < pTmplEnd - 1) {
+               if (*pch == '(') {
+                       StrBufPeek(Buf, pch, -1, '\0');
+                       NewToken->NameEnd = pch - NewToken->pName;
+                       pch ++;
+                       while (pch < pTmplEnd - 1) {
+                               Param = GetNextParamter(Buf, &pch, pTmplEnd - 1);
+                               if (Param != NULL) {
+                                       NewToken->HaveParameters = 1;
+                                       if (NewToken->nParameters > MAXPARAM) {
+                                               lprintf(1, "Only %ld Tokens supported!\n", MAXPARAM);
+                                               return NULL;
+                                       }
+                                       NewToken->Params[NewToken->nParameters++] = Param;
+                               }
+                               else break;
+                       }
+                       if((NewToken->NameEnd == 1) &&
+                          (NewToken->HaveParameters == 1))
+                          
+                       {
+                               if ((NewToken->nParameters == 1) &&
+                                   (*(NewToken->pName) == '_'))
+                                       NewToken->Flags = SV_GETTEXT;
+                               else if ((NewToken->nParameters >= 2) &&
+                                        (*(NewToken->pName) == '?'))
+                                       NewToken->Flags = SV_CONDITIONAL;
+                               else if ((NewToken->nParameters >=2) &&
+                                        (*(NewToken->pName) == '!'))
+                                       NewToken->Flags = SV_NEG_CONDITIONAL;
+                       }
+               }
+               else pch ++;            
+       }
        return NewToken;
 }
 
@@ -409,53 +586,118 @@ void FreeWCTemplate(void *vFreeMe)
        free(FreeMe);
 }
 
-void EvaluateToken(StrBuf *Target, WCTemplateToken *Token)
+
+int EvaluateConditional(WCTemplateToken *Token, void *Context, int Neg, int state)
+{
+       void *vConditional;
+       ConditionalStruct *Cond;
+
+       if ((Token->Params[0]->len == 1) &&
+           (Token->Params[0]->Start[0] == 'X'))
+               return (state != 0)?Token->Params[1]->lvalue:0;
+
+       if (!GetHash(Contitionals, 
+                Token->Params[0]->Start,
+                Token->Params[0]->len,
+                &vConditional)) {
+               lprintf(1, "Conditional %s Not found!\n", 
+                       Token->Params[0]->Start);
+       }
+           
+       Cond = (ConditionalStruct *) vConditional;
+
+       if (Cond == NULL) {
+               lprintf(1, "Conditional %s Not found!\n", 
+                       Token->Params[0]->Start);
+               return 0;
+       }
+       if (Token->nParameters < Cond->nParams) {
+               lprintf(1, "Conditional [%s] needs %ld Params!\n", 
+                       Token->Params[0]->Start,
+                       Cond->nParams);
+               return 0;
+       }
+       if (Cond->CondF(Token, Context) == Neg)
+               return Token->Params[1]->lvalue;
+       return 0;
+}
+
+int EvaluateToken(StrBuf *Target, WCTemplateToken *Token, void *Context, int state)
 {
        void *vVar;
 // much output, since pName is not terminated...
 //     lprintf(1,"Doing token: %s\n",Token->pName);
-       if (GetHash(GlobalNS, Token->pName, Token->NameEnd, &vVar)) {
+       if (Token->Flags == SV_GETTEXT) {
+               TmplGettext(Target, Token->nParameters, Token);
+       }
+       else if (Token->Flags == SV_CONDITIONAL) {
+               return EvaluateConditional(Token, Context, 1, state);
+       }
+       else if (Token->Flags == SV_NEG_CONDITIONAL) {
+               return EvaluateConditional(Token, Context, 0, state);
+       }
+       else if (GetHash(GlobalNS, Token->pName, Token->NameEnd, &vVar)) {
                HashHandler *Handler;
                Handler = (HashHandler*) vVar;
                if ((Token->nParameters < Handler->nMinArgs) || 
-                   (Token->nParameters < Handler->nMaxArgs)) {
+                   (Token->nParameters > Handler->nMaxArgs)) {
                        lprintf(1, "Handler [%s] doesn't work with %ld params", 
                                Token->pName,
                                Token->nParameters);
                }
                else {
-                       Handler->HandlerFunc(Token->nParameters,
-                                            &Token); /*TODO: subset of that */
+                       Handler->HandlerFunc(Target, 
+                                            Token->nParameters,
+                                            Token,
+                                            Context); /*TODO: subset of that */
                
                        
                }
        }
        else {
-               print_value_of(Token->pName, Token->NameEnd);
+               print_value_of(Target, Token->pName, Token->NameEnd);
        }
+       return 0;
 }
 
-void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target)
+void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context)
 {
        int done = 0;
-       int i;
+       int i, state;
        const char *pData, *pS;
        long len;
 
        pS = pData = ChrPtr(Tmpl->Data);
        len = StrLength(Tmpl->Data);
        i = 0;
+       state = 0;
        while (!done) {
                if (i >= Tmpl->nTokensUsed) {
-                       StrBufAppendBufPlain(Target, pData, len, 0);
+                       StrBufAppendBufPlain(Target, 
+                                            pData, 
+                                            len - (pData - pS), 0);
                        done = 1;
                }
                else {
                        StrBufAppendBufPlain(
                                Target, pData, 
                                Tmpl->Tokens[i]->pTokenStart - pData, 0);
-                       EvaluateToken(Target, Tmpl->Tokens[i]);
+                       state = EvaluateToken(Target, Tmpl->Tokens[i], Context, state);
+                       while ((state != 0) && (i+1 < Tmpl->nTokensUsed)) {
+                       /* condition told us to skip till its end condition */
+                               i++;
+                               if ((Tmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
+                                   (Tmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
+                                       if (state == EvaluateConditional(Tmpl->Tokens[i], 
+                                                                        Context, 
+                                                                        Tmpl->Tokens[i]->Flags,
+                                                                        state))
+                                               state = 0;
+                               }
+                       }
                        pData = Tmpl->Tokens[i++]->pTokenEnd + 1;
+                       if (i >= Tmpl->nTokensUsed)
+                               done = 1;
                }
        }
 }
@@ -529,7 +771,8 @@ void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
                if (pch + 1 >= pE)
                        continue;
                pte = pch;
-               PutNewToken(NewTemplate, NewTemlpateSubstitute(pS, pts, pte));
+               PutNewToken(NewTemplate, 
+                           NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte));
                pch ++;
        }
        Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
@@ -540,12 +783,14 @@ void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
  * \brief Display a variable-substituted template
  * \param templatename template file to load
  */
-void DoTemplate(const char *templatename, long len) 
+void DoTemplate(const char *templatename, long len, void *Context, StrBuf *Target
 {
        HashList *Static;
        HashList *StaticLocal;
        void *vTmpl;
-
+       
+       if (Target == NULL)
+               Target = WC->WBuf;
        if (WC->is_mobile) {
                Static = WirelessTemplateCache;
                StaticLocal = WirelessLocalTemplateCache;
@@ -562,7 +807,7 @@ void DoTemplate(const char *templatename, long len)
        }
        if (vTmpl == NULL) 
                return;
-       ProcessTemplate(vTmpl, WC->WBuf);       
+       ProcessTemplate(vTmpl, Target, Context);        
 }
 
 int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big)
@@ -629,66 +874,175 @@ void InitTemplateCache(void)
                        LocalTemplateCache);
 }
 
-void tmplput_serv_ip(int nArgs, WCTemplateToken **Tokens)
+void tmplput_serv_ip(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
+{
+       StrBufAppendPrintf(Target, "%d", WC->ctdl_pid);
+}
+
+void tmplput_serv_nodename(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
+{
+       StrEscAppend(Target, NULL, serv_info.serv_nodename, 0, 0);
+}
+
+void tmplput_serv_humannode(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
+{
+       StrEscAppend(Target, NULL, serv_info.serv_humannode, 0, 0);
+}
+
+void tmplput_serv_fqdn(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
+{
+       StrEscAppend(Target, NULL, serv_info.serv_fqdn, 0, 0);
+}
+
+void tmmplput_serv_software(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       wprintf("%d", WC->ctdl_pid);
+       StrEscAppend(Target, NULL, serv_info.serv_software, 0, 0);
 }
 
-void tmplput_serv_nodename(int nArgs, WCTemplateToken **Tokens)
+void tmplput_serv_rev_level(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       escputs(serv_info.serv_nodename);
+       StrBufAppendPrintf(Target, "%d.%02d",
+                           serv_info.serv_rev_level / 100,
+                           serv_info.serv_rev_level % 100);
 }
 
-void tmplput_serv_humannode(int nArgs, WCTemplateToken **Tokens)
+void tmmplput_serv_bbs_city(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       escputs(serv_info.serv_humannode);
+       StrEscAppend(Target, NULL, serv_info.serv_bbs_city, 0, 0);
 }
 
-void tmplput_serv_fqdn(int nArgs, WCTemplateToken **Tokens)
+void tmplput_current_user(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       escputs(serv_info.serv_fqdn);
+       StrEscAppend(Target, NULL, WC->wc_fullname, 0, 0);
 }
 
-void tmmplput_serv_software(int nArgs, WCTemplateToken **Tokens)
+void tmplput_current_room(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       escputs(serv_info.serv_software);
+       StrEscAppend(Target, NULL, WC->wc_roomname, 0, 0);
 }
 
-void tmplput_serv_rev_level(int nArgs, WCTemplateToken **Tokens)
+
+typedef struct _HashIterator {
+       HashList *StaticList;
+       RetrieveHashlistFunc GetHash;
+       HashDestructorFunc Destructor;
+       SubTemplFunc DoSubTemplate;
+} HashIterator;
+
+void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
 {
-       wprintf("%d.%02d",
-               serv_info.serv_rev_level / 100,
-               serv_info.serv_rev_level % 100);
+       void *vIt;
+       HashIterator *It;
+       HashList *List;
+       HashPos  *it;
+       long len; 
+       const char *Key;
+       void *vContext;
+       StrBuf *SubBuf;
+       int oddeven = 0;
+       
+       if (!GetHash(Iterators, 
+                    Tokens->Params[0]->Start,
+                    Tokens->Params[0]->len,
+                    &vIt))
+               return;
+       It = (HashIterator*) vIt;
+       if (It->StaticList == NULL)
+               List = It->GetHash();
+       else
+               List = It->StaticList;
+
+       SubBuf = NewStrBuf();
+       it = GetNewHashPos();
+       while (GetNextHashPos(List, it, &len, &Key, &vContext)) {
+               svprintf(HKEY("ITERATE:ODDEVEN"), WCS_STRING, "%s", (oddeven)?"odd":"even");
+               It->DoSubTemplate(SubBuf, vContext);
+               DoTemplate(Tokens->Params[1]->Start,
+                          Tokens->Params[1]->len,
+                          vContext, SubBuf);
+                       
+               StrBufAppendBuf(Target, SubBuf, 0);
+               FlushStrBuf(SubBuf);
+       }
+       DeleteHashPos(&it);
+       It->Destructor(List);
 }
 
-void tmmplput_serv_bbs_city(int nArgs, WCTemplateToken **Tokens)
+int ConditionalVar(WCTemplateToken *Tokens, void *Context)
 {
-       escputs(serv_info.serv_bbs_city);
+       void *vsubst;
+       wcsubst *subst;
+       
+       if (!GetHash(WC->vars, 
+                    Tokens->Params[2]->Start,
+                    Tokens->Params[2]->len,
+                    &vsubst))
+               return 0;
+       subst = (wcsubst*) vsubst;
+       switch(subst->wcs_type) {
+       case WCS_STRING:
+               if (Tokens->nParameters < 4)
+                       return 0;
+               return (strcmp(Tokens->Params[3]->Start, subst->wcs_value) == 0);
+       case WCS_SERVCMD:
+               lprintf(1, "  -> Server [%s]\n", subst->wcs_value);////todo
+               return 0;
+       case WCS_FUNCTION:
+               return (subst->wcs_function!=NULL);
+       case WCS_STRBUF:
+       case WCS_STRBUF_REF:
+               if (Tokens->nParameters < 4)
+                       return 0;
+               return (strcmp(Tokens->Params[3]->Start, ChrPtr((StrBuf*) subst->wcs_function)) == 0);
+       case WCS_LONG:
+               if (Tokens->nParameters < 4)
+                       return (subst->lvalue != 0);
+               return (subst->lvalue == Tokens->Params[3]->lvalue);
+       default:
+               lprintf(1,"  WARNING: invalid type: [%ld]!\n", subst->wcs_type);
+       }
+       return 0;
 }
 
-void tmplput_current_user(int nArgs, WCTemplateToken **Tokens)
+void RegisterITERATOR(const char *Name, long len, 
+                     HashList *StaticList, 
+                     RetrieveHashlistFunc GetHash, 
+                     SubTemplFunc DoSubTempl,
+                     HashDestructorFunc Destructor)
 {
-       escputs(WC->wc_fullname);
+       HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator));
+       It->StaticList = StaticList;
+       It->GetHash = GetHash;
+       It->DoSubTemplate = DoSubTempl;
+       It->Destructor = Destructor;
+       Put(Iterators, Name, len, It, NULL);
 }
 
-void tmplput_current_room(int nArgs, WCTemplateToken **Tokens)
+void RegisterConditional(const char *Name, long len, 
+                        int nParams,
+                        WCConditionalFunc CondF)
 {
-       escputs(WC->wc_roomname);
+       ConditionalStruct *Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
+       Cond->nParams = nParams;
+       Cond->CondF = CondF;
+       Put(Contitionals, Name, len, Cond, NULL);
 }
 
 void 
 InitModule_SUBST
 (void)
 {
-       RegisterNS(HKEY("SERV_PID"), 0, 0, tmplput_serv_ip);
-       RegisterNS(HKEY("SERV_NODENAME"), 0, 0, tmplput_serv_nodename);
-       RegisterNS(HKEY("SERV_HUMANNODE"), 0, 0, tmplput_serv_humannode);
-       RegisterNS(HKEY("SERV_FQDN"), 0, 0, tmplput_serv_fqdn);
-       RegisterNS(HKEY("SERV_SOFTWARE"), 0, 0, tmmplput_serv_software);
-       RegisterNS(HKEY("SERV_REV_LEVEL"), 0, 0, tmplput_serv_rev_level);
-       RegisterNS(HKEY("SERV_BBS_CITY"), 0, 0, tmmplput_serv_bbs_city);
-       RegisterNS(HKEY("CURRENT_USER"), 0, 0, tmplput_current_user);
-       RegisterNS(HKEY("CURRENT_ROOM"), 0, 0, tmplput_current_room);
+       RegisterNamespace("SERV_PID", 0, 0, tmplput_serv_ip);
+       RegisterNamespace("SERV_NODENAME", 0, 0, tmplput_serv_nodename);
+       RegisterNamespace("SERV_HUMANNODE", 0, 0, tmplput_serv_humannode);
+       RegisterNamespace("SERV_FQDN", 0, 0, tmplput_serv_fqdn);
+       RegisterNamespace("SERV_SOFTWARE", 0, 0, tmmplput_serv_software);
+       RegisterNamespace("SERV_REV_LEVEL", 0, 0, tmplput_serv_rev_level);
+       RegisterNamespace("SERV_BBS_CITY", 0, 0, tmmplput_serv_bbs_city);
+       RegisterNamespace("CURRENT_USER", 0, 0, tmplput_current_user);
+       RegisterNamespace("CURRENT_ROOM", 0, 0, tmplput_current_room);
+       RegisterNamespace("ITERATE", 2, 4, tmpl_iterate_subtmpl);
+       RegisterConditional(HKEY("COND:SUBST"), 3, ConditionalVar);
 }
 
 /*@}*/