コード例 #1
0
/* 
*  Internal function to remove a node from a tree - used by assert() method
*
*  Returns:
*    0 - don't remove the parent node
*    1 - consider removing the parent node (if no value or root)
*    2 - remove the parent node (even if it has a value and/or root)
*/
static int removeNode(nbCELL context,BTree *tree,BTreeNode **nodeP,nbSET *argSetP){
  NB_TreePath path;
  BTreeNode *node=*nodeP;
  nbCELL argCell;
  int code=1;

  argCell=nbListGetCellValue(context,argSetP);
  if(argCell==NULL){
    if(node==NULL) return(3);  // the perfect match - nothing to nothing
    code=2; 
    return(2);                   //
    }
  else{
    if(node==NULL) return(0);  // can't match to empty tree
    if(tree->options&BTREE_OPTION_ORDER) 
      node=(BTreeNode *)nbTreeLocateValue(&path,argCell,(NB_TreeNode **)nodeP,treeCompare,context);
    else node=nbTreeLocate(&path,argCell,(NB_TreeNode **)nodeP);   
    nbCellDrop(context,argCell);
    if(node==NULL) return(0);          // didn't find argument
    switch(removeNode(context,tree,&node->root,argSetP)){
      case 0: return(0);
      case 1:
        if(node->root!=NULL) return(0);  // still need this node
        break;
      // For case 2 we just fall thru to unlink the node
      }
    }
  if(node->root!=NULL) return(0);  
  nbTreeRemove(&path);  // Remove node from binary search tree
  if(node->bnode.key!=NULL) node->bnode.key=nbCellDrop(context,(nbCELL)node->bnode.key);  // release key
  //if(node->root!=NULL) node->root =removeTree(context,tree,node->root);
  nbFree(node,sizeof(BTreeNode));
  return(code);
  }
コード例 #2
0
ファイル: nb_audit.c プロジェクト: postfix/nodebrain-nb
/*
*  destroy() method
*
*    undefine <node>
*
*/
static int auditDestroy(nbCELL context,void *skillHandle,nbAudit *audit){
  if(audit->trace) nbLogMsg(context,0,'T',"auditDestroy called");
  auditDisable(context,skillHandle,audit);
  nbCellDrop(context,audit->fileNameCell);
  nbCellDrop(context,audit->scheduleCell);
  nbCellDrop(context,audit->translatorCell);
  nbCellDrop(context,audit->translatorNameCell);
  nbFree(audit,sizeof(struct NB_MOD_AUDIT));
  return(0);
  }
コード例 #3
0
// Prune a tree at the selected node without removing the selected node
//
static void treePrune(nbCELL context,BTreeSkill *skillHandle,BTree *tree,nbCELL arglist,char *text){
  BTreeNode *node=NULL;
  nbSET argSet;
  nbCELL argCell;
  void *ptr;

  argSet=nbListOpen(context,arglist);
  if(argSet==NULL){
    if(tree->root!=NULL){
      removeTree(context,tree,tree->root);
      tree->root=NULL;
      }
    }
  else{
    ptr=&tree->root;
    if(argSet!=NULL){
      while((argCell=nbListGetCellValue(context,&argSet))!=NULL && (node=treeFindArg(context,tree,argCell,&ptr))!=NULL){ 
        nbCellDrop(context,argCell);
        ptr=&node->root;   
        }
      if(argCell!=NULL){
        nbLogMsg(context,0,'E',"Entry not found.");
        return;
        }
      if(node->root!=NULL){
        removeTree(context,tree,node->root);
        node->root=NULL;
        }
      }
    }
  }
コード例 #4
0
static void treeSet(nbCELL context,BTreeSkill *skillHandle,BTree *tree,nbCELL arglist,char *text){
  NB_TreePath path;
  BTreeNode *node=NULL,**nodeP=&tree->root;
  nbSET argSet;
  nbCELL argCell;
  double average,deviation;

  average=strtod(text,&text);
  while(*text==' ') text++;
  if(*text!=','){
    nbLogMsg(context,0,'E',"Expecting ',' at: %s",text);
    return;
    }
  text++;
  deviation=strtod(text,&text);
  while(*text==' ') text++;
  if(*text!=';'){
    nbLogMsg(context,0,'E',"Expecting ';' at: %s",text);
    return;
    }
  if(arglist==NULL || (argSet=nbListOpen(context,arglist))==NULL){
    nbLogMsg(context,0,'E',"Expecting argument list");
    return;
    }
  argCell=nbListGetCellValue(context,&argSet);
  while(argCell!=NULL){
    if(tree->options&BTREE_OPTION_ORDER)
      node=nbTreeLocateValue(&path,argCell,(NB_TreeNode **)nodeP,treeCompare,context);
    else node=nbTreeLocate(&path,argCell,(NB_TreeNode **)nodeP);
    if(node==NULL){
      node=nbAlloc(sizeof(BTreeNode));
      memset(node,0,sizeof(BTreeNode));
      nbTreeInsert(&path,(NB_TreeNode *)node);
      nodeP=&(node->root);
      while((argCell=nbListGetCellValue(context,&argSet))!=NULL){
        node=nbAlloc(sizeof(BTreeNode));
        memset(node,0,sizeof(BTreeNode));
        node->bnode.key=(void *)argCell;
        *nodeP=node;
        nodeP=&(node->root);
        }
      node->average=average;
      node->deviation=deviation;
      node->threshold=deviation*tree->tolerance;
      node->level=0;
      return;
      }
    nodeP=&(node->root);
    nbCellDrop(context,argCell);
    argCell=nbListGetCellValue(context,&argSet);
    }
  if(node){
    /* matched - change value */
    node->average=average;
    node->deviation=deviation;
    node->threshold=(double)((int)1<<node->level)*deviation*tree->tolerance;
    }
  return;
  }
コード例 #5
0
//
// Recursively remove all nodes in a binary tree
// 
static void *removeTree(nbCELL context,BTree *tree,BTreeNode *node){
  node->bnode.key=nbCellDrop(context,node->bnode.key);
  if(node->bnode.left!=NULL) node->bnode.left=removeTree(context,tree,(BTreeNode *)node->bnode.left);
  if(node->bnode.right!=NULL) node->bnode.right=removeTree(context,tree,(BTreeNode *)node->bnode.right);
  if(node->root!=NULL) node->root=removeTree(context,tree,node->root);
  nbFree(node,sizeof(BTreeNode));
  return(NULL);
  }
コード例 #6
0
/*
*  evaluate() method
*
*    ... <node>[(<args>)] ...
*
*    define r1 on(table("a",2,"hello")=4);
*
*/
static nbCELL baselineEvaluate(nbCELL context,BTreeSkill *skillHandle,BTree *tree,nbCELL arglist){
  nbCELL    argCell;
  nbSET     argSet;
  BTreeNode *node=NULL,*root=tree->root;

  if(skillHandle->trace || tree->options&BTREE_OPTION_TRACE){
    nbLogMsg(context,0,'T',"nb_tree::baselineEvaluate()");
    nbLogPut(context,"tree");
    if(arglist!=NULL) nbCellShow(context,arglist);
    nbLogPut(context,"\n");
    }
  if(arglist==NULL){  // request for tree value
    return(NB_CELL_UNKNOWN);  // for now, let it be Unknown
    }
  argSet=nbListOpen(context,arglist);
  if(argSet==NULL) return(tree->notfound); // tree() returns default value
  argCell=nbListGetCellValue(context,&argSet);
  while(argCell!=NULL && argSet!=NULL){
    if(tree->options&BTREE_OPTION_ORDER){
      if(tree->options&BTREE_OPTION_PARTITION)
        node=nbTreeFindFloor(argCell,(NB_TreeNode *)root,treeCompare,context);
      else node=nbTreeFindValue(argCell,(NB_TreeNode *)root,treeCompare,context); 
      }
    else node=nbTreeFind(argCell,(NB_TreeNode *)root);
    if(node==NULL){
      nbCellDrop(context,argCell);
      return(tree->notfound);
      }
    nbCellDrop(context,argCell);
    argCell=nbListGetCellValue(context,&argSet);
    root=node->root;
    }
  // matched on arguments
  // return(tree->found);    // could alternatively return a real object with value of node->value
  return(nbCellCreateReal(context,node->value));
  }
コード例 #7
0
/*
*  construct() method
*
*    define <term> node <skill>[(<args>)][:<text>]
*
*    <args> - port_number or "interface_address[:port_number]"
*    <text> - flag keywords
*               trace   - display input packets
*               dump    - display dump of SNMP UDP packets
*               silent  - don't echo generated NodeBrain commands 
*
*    define snmptrap node snmptrap;
*    define snmptrap node snmptrap:dump,silent;
*    define snmptrap node snmptrap("127.0.0.1");
*    define snmptrap node snmptrap(50162);
*    define snmptrap node snmptrap("127.0.0.1:50162");
*    define snmptrap node snmptrap("127.0.0.1:50162"):silent;
*/
static void *serverConstruct(nbCELL context,void *skillHandle,nbCELL arglist,char *text){
  NB_MOD_Snmptrap *snmptrap;
  nbCELL cell=NULL;
  nbSET argSet;
  char *cursor=text,*delim,saveDelim;
  double r,d;
  char interfaceAddr[16];
  unsigned int port=162;
  int type,trace=0,dump=0,echo=1;
  int len;
  char *str;

  *interfaceAddr=0;

  argSet=nbListOpen(context,arglist);   
  cell=nbListGetCellValue(context,&argSet); 
  if(cell!=NULL){
    type=nbCellGetType(context,cell);
    if(type==NB_TYPE_STRING){
      str=nbCellGetString(context,cell);
      delim=strchr(str,':');
      if(delim==NULL) len=strlen(str);
      else len=delim-str;
      if(len>15){
        nbLogMsg(context,0,'E',"Inteface IP address may not be greater than 15 characters");
        nbCellDrop(context,cell);
        return(NULL);
        }
      strncpy(interfaceAddr,str,len);
      *(interfaceAddr+len)=0; 
      if(delim!=NULL){
        delim++;
        port=(unsigned int)atoi(delim);
        }
      nbCellDrop(context,cell);
      }
    else if(type==NB_TYPE_REAL){
      r=nbCellGetReal(context,cell);
      nbCellDrop(context,cell);
      port=(unsigned int)r;
      d=port;
      if(d!=r || d==0){
        nbLogMsg(context,0,'E',"Expecting non-zero integer UDP port number");
        return(NULL);
        }
      }
    else{
      nbLogMsg(context,0,'E',"Expecting interface (\"address[:port]\") or (port) as argument list");
      return(NULL);
      }
    cell=nbListGetCellValue(context,&argSet); 
    if(cell!=NULL){
      nbLogMsg(context,0,'E',"Only one argument expected - ignoring additional arguments");
      nbCellDrop(context,cell);
      }
    }
  if(*text!=0){
    cursor=text;
    while(*cursor==' ') cursor++;
    while(*cursor!=';' && *cursor!=0){
      delim=strchr(cursor,' ');
      if(delim==NULL) delim=strchr(cursor,',');
      if(delim==NULL) delim=strchr(cursor,';');
      if(delim==NULL) delim=cursor+strlen(cursor);  // 2013-01-14 eat - VID 969-0.8.13-3 FP but replaced strchr(cursor,0)
      saveDelim=*delim;
      *delim=0;
      if(strcmp(cursor,"trace")==0){trace=1;}
      else if(strcmp(cursor,"dump")==0){trace=1;dump=1;}
      else if(strcmp(cursor,"silent")==0) echo=0; 
      *delim=saveDelim;
      cursor=delim;
      if(*cursor==',') cursor++;
      while(*cursor==' ') cursor++;
      }
    }
  snmptrap=nbAlloc(sizeof(NB_MOD_Snmptrap));
  snmptrap->socket=0;
  strcpy(snmptrap->interfaceAddr,interfaceAddr);
  snmptrap->port=port;
  snmptrap->trace=trace;
  snmptrap->dump=dump;
  snmptrap->echo=echo;
  snmptrap->handlerContext=NULL;
  snmptrap->syntaxContext=NULL;
  snmptrap->attributeContext=NULL;
  nbListenerEnableOnDaemon(context);  // sign up to enable when we daemonize
  return(snmptrap);
  }
コード例 #8
0
/*
*  construct() method
*
*    define <term> node <skill>[("<ident>"[,<uri>])][:<text>]
*
*    <ident> - name of translator file
*    <uri>   - <proto>://<spec>
*
*              <proto> - only "udp" supported currently
*              <spec>  - only local domain socket file supported currently
*
*    <text>  - flag keywords
*                trace   - display input packets
*                dump    - display dump of syslog packets
*                silent  - don't echo generated NodeBrain commands
*
*    define syslog node syslog.client("foobar");
*/
void *clientConstruct(nbCELL context,void *skillHandle,nbCELL arglist,char *text){
  NB_MOD_Client *client;
  nbCELL cell=NULL;
  nbSET argSet;
  char *cursor=text,*delim,saveDelim;
  int trace=0,dump=0,echo=1;
  char *ident="nodebrain"; 
  char *uri="udp://127.0.0.1:514";
  char *socketname=uri+6;
  int sd;

  argSet=nbListOpen(context,arglist);
  cell=nbListGetCellValue(context,&argSet);
  if(cell){
    if(nbCellGetType(context,cell)!=NB_TYPE_STRING){
      nbLogMsg(context,0,'E',"First argument must be string message identifier");
      return(NULL);
      }
    ident=strdup(nbCellGetString(context,cell));
    if(!ident) nbExit("clientConstruct: Out of memory - terminating");
    nbCellDrop(context,cell);
    }
  cell=nbListGetCellValue(context,&argSet);
  if(cell){
    if(nbCellGetType(context,cell)!=NB_TYPE_STRING){
      nbLogMsg(context,0,'E',"Second argument must be string uri");
      return(NULL);
      }
    uri=strdup(nbCellGetString(context,cell));
    if(!uri) nbExit("clientConstruct: Out of memory - terminating");
    nbCellDrop(context,cell);
    cell=nbListGetCellValue(context,&argSet);
    if(cell){
      nbLogMsg(context,0,'E',"The syslog.client skill only accepts two arguments.");
      return(NULL);
      }
    }
  while(*cursor==' ') cursor++;
  while(*cursor!=';' && *cursor!=0){
    delim=strchr(cursor,' ');
    if(delim==NULL) delim=strchr(cursor,',');
    if(delim==NULL) delim=strchr(cursor,';');
    if(delim==NULL) delim=cursor+strlen(cursor);
    saveDelim=*delim;
    *delim=0;
    if(strcmp(cursor,"trace")==0){trace=1;}
    else if(strcmp(cursor,"dump")==0){trace=1;dump=1;}
    else if(strcmp(cursor,"silent")==0) echo=0;
    *delim=saveDelim;
    cursor=delim;
    if(*cursor==',') cursor++;
    while(*cursor==' ' || *cursor==',') cursor++;
    }
  // figure out the uri
  if(strncmp(uri,"udp://",6)){
    nbLogMsg(context,0,'E',"Expecting uri to start with 'udp://' - found %s",uri);
    return(NULL);
    }
  socketname=uri+6;
  // add code here to determine if local or remote
  sd=socket(AF_UNIX,SOCK_DGRAM,0);
  if(sd<0){
    nbLogMsg(context,0,'E',"Unable to obtain socket for %s",uri);
    return(NULL);
    }
  client=nbAlloc(sizeof(NB_MOD_Client));
  client->ident=ident;
  client->uri=uri;
  client->un_addr.sun_family=AF_UNIX;
  sprintf(client->un_addr.sun_path,"%s",socketname);
  client->socket=sd;
  client->trace=trace;
  client->dump=dump;
  client->echo=echo;
  return(client);
  }
コード例 #9
0
/*
*  construct() method
*
*    define <term> node <skill>("<translator>",[<binding>])[:<text>]
*
*    <translator> - name of translator file
*    <binding>    - port_number or "interface_address[:port_number]"
*    <text>       - flag keywords
*                     trace   - display input packets
*                     dump    - display dump of syslog packets
*                     silent  - don't echo generated NodeBrain commands 
*
*    define syslog node syslog.server("syslog.nbx");
*    define syslog node syslog.server("syslog.nbx"):dump,silent;
*    define syslog node syslog.server("syslog.nbx","127.0.0.1");
*    define syslog node syslog.server("syslog.nbx",50162);
*    define syslog node syslog.server("syslog.nbx","127.0.0.1:50162");
*    define syslog node syslog.server("syslog.nbx","127.0.0.1:50162"):silent;
*/
void *serverConstruct(nbCELL context,void *skillHandle,nbCELL arglist,char *text){
  NB_MOD_Server *server;
  nbCELL cell=NULL;
  nbSET argSet;
  char *cursor=text,*delim,saveDelim;
  double r,d;
  char interfaceAddr[512];
  unsigned int port=514;
  int type,trace=0,dump=0,echo=1;
  int len;
  char *str;
  char *transfilename;
  nbCELL translator;
  char *uri="";;

  *interfaceAddr=0;

  argSet=nbListOpen(context,arglist);
  cell=nbListGetCellValue(context,&argSet);
  if(cell==NULL){
    nbLogMsg(context,0,'E',"Translator configuration file required as first argument");
    return(NULL);
    }
  type=nbCellGetType(context,cell);
  if(type!=NB_TYPE_STRING){
    nbLogMsg(context,0,'E',"First argument must be string identifying translator configuration file");
    return(NULL);
    }
  transfilename=nbCellGetString(context,cell);
  translator=nbTranslatorCompile(context,0,transfilename);
  if(translator==NULL){
    nbLogMsg(context,0,'E',"Unable to load translator '%s'",transfilename);
    return(NULL);
    }
  cell=nbListGetCellValue(context,&argSet);
  if(cell!=NULL){
    type=nbCellGetType(context,cell);
    if(type==NB_TYPE_STRING){
      str=nbCellGetString(context,cell);
      uri=strdup(str);
      if(!uri) nbExit("serverConstruct: Out of memory - terminating");
      if(strncmp(str,"udp://",6)==0) str+=6;  // allow for uri
      delim=strchr(str,':');
      if(delim==NULL) len=strlen(str);
      else len=delim-str;
      if(len>15 && *str>='0' && *str<='9'){
        nbLogMsg(context,0,'E',"Inteface IP address may not be greater than 15 characters");
        nbCellDrop(context,cell);
        return(NULL);
        }
      if(len>sizeof(interfaceAddr)-1){
        nbLogMsg(context,0,'E',"Socket specification too long for buffer at--->%s",str);
        nbCellDrop(context,cell);
        return(NULL);
        }
      strncpy(interfaceAddr,str,len);
      *(interfaceAddr+len)=0; 
      if(delim!=NULL){
        delim++;
        port=(unsigned int)atoi(delim);
        }
      nbCellDrop(context,cell);
      }
    else if(type==NB_TYPE_REAL){
      r=nbCellGetReal(context,cell);
      nbCellDrop(context,cell);
      port=(unsigned int)r;
      d=port;
      if(d!=r || d==0){
        nbLogMsg(context,0,'E',"Expecting non-zero integer UDP port number");
        return(NULL);
        }
      }
    else{
      nbLogMsg(context,0,'E',"Expecting (\"file\") or (\"address[:port]\") or (port) as argument list");
      return(NULL);
      }
    cell=nbListGetCellValue(context,&argSet);
    if(cell!=NULL){
      nbLogMsg(context,0,'E',"The syslog skill only accepts two argument.");
      return(NULL);
      }
    }
  while(*cursor==' ') cursor++;
  while(*cursor!=';' && *cursor!=0){
    delim=strchr(cursor,' ');
    if(delim==NULL) delim=strchr(cursor,',');
    if(delim==NULL) delim=strchr(cursor,';');
    if(delim==NULL) delim=cursor+strlen(cursor);
    saveDelim=*delim;
    *delim=0;
    if(strcmp(cursor,"trace")==0){trace=1;}
    else if(strcmp(cursor,"dump")==0){trace=1;dump=1;}
    else if(strcmp(cursor,"silent")==0) echo=0; 
    *delim=saveDelim;
    cursor=delim;
    if(*cursor==',') cursor++;
    while(*cursor==' ' || *cursor==',') cursor++;
    }
  server=nbAlloc(sizeof(NB_MOD_Server));
  server->uri=uri;
  server->socket=0;
  strcpy(server->interfaceAddr,interfaceAddr);
  server->port=port;
  server->translator=translator;
  server->trace=trace;
  server->dump=dump;
  server->echo=echo;
  nbLogMsg(context,0,'I',"calling nbListenerEnableOnDaemon");
  nbListenerEnableOnDaemon(context);  // sign up to enable when we daemonize
  return(server);
  }
コード例 #10
0
/*
*  assert() method
*
*    assert <node>[(args)][=<value>]
*
*    assert table("a",2,"hello")=5;   # set value to 5
*    assert table("a",2,"hello");     # set value to 1
*    assert !table("a",2,"hello");    # set value to 0
*    assert ?table("a",2,"hello");    # remove from table
*    assert table("a",2,"hello")=??   # remove from table
*
*/
static int baselineAssert(nbCELL context,void *skillHandle,BTree *tree,nbCELL arglist,nbCELL value){
  NB_TreePath path;
  BTreeNode *node=NULL,**nodeP=&tree->root;
  nbCELL argCell;
  nbSET  argSet;
  int cellType;
  double real;
  int qualifiers=0;
  nbCELL element[32];
  double deviation;

  if(arglist==NULL) return(0); // perhaps we should set the value of the tree itself
  argSet=nbListOpen(context,arglist);
  if(value==NB_CELL_UNKNOWN){
    if(argSet==NULL && tree->root!=NULL) tree->root=removeTree(context,tree,tree->root);
    else removeNode(context,tree,&tree->root,&argSet);
    return(0);
    }
  cellType=nbCellGetType(context,value);
  if(cellType!=NB_TYPE_REAL){
    nbLogMsg(context,0,'E',"Value must be a number");
    return(0);
    }
  real=nbCellGetReal(context,value);
  if(argSet==NULL) return(0);
  argCell=nbListGetCellValue(context,&argSet);
  while(argCell!=NULL){
    element[qualifiers]=argCell;
    qualifiers++;
    if(tree->options&BTREE_OPTION_ORDER) 
      node=nbTreeLocateValue(&path,argCell,(NB_TreeNode **)nodeP,treeCompare,context);
    else node=nbTreeLocate(&path,argCell,(NB_TreeNode **)nodeP);
    if(node==NULL){
      node=nbAlloc(sizeof(BTreeNode));
      memset(node,0,sizeof(BTreeNode));
      nbTreeInsert(&path,(NB_TreeNode *)node);
      nodeP=&(node->root);
      while((argCell=nbListGetCellValue(context,&argSet))!=NULL){
        node=nbAlloc(sizeof(BTreeNode));
        memset(node,0,sizeof(BTreeNode));
        node->bnode.key=(void *)argCell;
        *nodeP=node;
        nodeP=&(node->root);
        }
      node->value=real;
      // note we don't set deviation, threshold and level until the end of the period.
      return(0);
      }
    nodeP=&(node->root);
    nbCellDrop(context,argCell);
    argCell=nbListGetCellValue(context,&argSet);
    }
  if(tree->options&BTREE_OPTION_SUM){
    // need to check for zero average and deviation here!
    node->value+=real;
    if(node->average==0 && node->deviation==0) return(0);
    deviation=fabs(node->value-node->average);
    if(node->value>node->average && deviation>node->threshold) baselineAlert(context,skillHandle,tree,node,element,qualifiers,deviation);
    }
  else{
    node->value=real;  // update value and check limits
    if(node->average==0 && node->deviation==0) return(0);
    deviation=fabs(node->value-node->average);
    if(deviation>node->threshold) baselineAlert(context,skillHandle,tree,node,element,qualifiers,deviation);
    }
  return(0);
  }
コード例 #11
0
/*
*  construct() method
*
*    define <term> node <skill>[(<args>)][:<text>]
*
*    define <term> node baseline("<directory>",<weight>,<tolerance>,<cycle>,<interval>)[:<options>];
*/
static void *baselineConstruct(nbCELL context,BTreeSkill *skillHandle,nbCELL arglist,char *text){
  int options=0;
  nbCELL found=NULL;
  nbCELL notfound=NULL;
  nbCELL cell;
  BTree *tree;
  char *cursor=text,*delim,ident[256];
  int len;
  nbSET  argSet;
  char *directory;
  double weight=0.5,tolerance=3,cycle=7*24*60,periods=24;
  double interval=60;

  argSet=nbListOpen(context,arglist);
  cell=nbListGetCellValue(context,&argSet);
  if(cell==NULL || nbCellGetType(context,cell)!=NB_TYPE_STRING){
    nbLogMsg(context,0,'E',"Baseline directory string required as first argument");
    return(NULL);
    }
  directory=nbCellGetString(context,cell);  // we don't drop this cell because we reference it
  cell=nbListGetCellValue(context,&argSet);
  if(cell!=NULL){
    if(nbCellGetType(context,cell)!=NB_TYPE_REAL || (weight=nbCellGetReal(context,cell))<0 || weight>1){
      nbLogMsg(context,0,'E',"Second argument must be numeric weight between 0 and 1");
      return(NULL);
      }
    nbCellDrop(context,cell);
    cell=nbListGetCellValue(context,&argSet);
    if(cell!=NULL){
      if(nbCellGetType(context,cell)!=NB_TYPE_REAL || (tolerance=nbCellGetReal(context,cell))<0){
        nbLogMsg(context,0,'E',"Third argument must be non-negative numeric tolerance");
        return(NULL);
        }
      nbCellDrop(context,cell);
      cell=nbListGetCellValue(context,&argSet);
      if(cell!=NULL){
        if(nbCellGetType(context,cell)!=NB_TYPE_REAL || (cycle=nbCellGetReal(context,cell))<1 || cycle!=(int)cycle){
          nbLogMsg(context,0,'E',"Forth argument must be positive integer number of minutes in a cycle");
          return(NULL);
          }
        nbCellDrop(context,cell);
        cell=nbListGetCellValue(context,&argSet);
        if(cell!=NULL){
          if(nbCellGetType(context,cell)!=NB_TYPE_REAL || (interval=nbCellGetReal(context,cell))<1 || interval!=(int)interval || (periods=cycle/interval)<1 || periods!=(int)periods){
            nbLogMsg(context,0,'E',"Fifth argument must be positive integer number of minutes in an interval by which %d is evenly divisable",cycle);
            return(NULL);
            }
          nbCellDrop(context,cell);
          cell=nbListGetCellValue(context,&argSet);
          if(cell!=NULL){
            nbLogMsg(context,0,'E',"Only five arguments supported");
            return(NULL);
            }
          }
        }
      }
    }
  if(skillHandle!=NULL && skillHandle->trace) nbLogMsg(context,0,'T',"baselineConstruct() called");
  while(*cursor==' ') cursor++;
  while(*cursor!=0 && *cursor!=';'){
    delim=cursor;
    while(*delim>='a' && *delim<='z') delim++;
    len=delim-cursor;
    if(len>sizeof(ident)-1){
      nbLogMsg(context,0,'E',"Option not recognized at \"%s\".",cursor);
      return(NULL);
      }
    strncpy(ident,cursor,len);
    *(ident+len)=0;
    cursor=delim; 
    while(*cursor==' ') cursor++;
    if(strcmp(ident,"trace")==0) options|=BTREE_OPTION_TRACE;
    else if(strcmp(ident,"order")==0) options|=BTREE_OPTION_ORDER;
    else if(strcmp(ident,"partition")==0) options|=BTREE_OPTION_PARTITION|BTREE_OPTION_ORDER;
    else if(strcmp(ident,"sum")==0) options|=BTREE_OPTION_SUM;
    else if(strcmp(ident,"static")==0) options|=BTREE_OPTION_STATIC;
    else if(strcmp(ident,"found")==0 || strcmp(ident,"notfound")==0){
      if(*cursor!='='){
        nbLogMsg(context,0,'E',"Expecting '=' at \"%s\".",cursor);
        return(NULL);
        }
      cursor++;
      cell=nbCellParse(context,&cursor);
      if(cell==NULL){
        nbLogMsg(context,0,'E',"Syntax error in cell expression.");
        return(NULL);
        }
      if(strcmp(ident,"found")==0) found=cell;
      else notfound=cell;
      }
    else{
      nbLogMsg(context,0,'E',"Option not recognized at \"%s\".",cursor);
      return(NULL);
      }
    while(*cursor==' ') cursor++;
    if(*cursor==','){
      cursor++;
      while(*cursor==' ') cursor++;
      }
    else if(*cursor!=0 && *cursor!=';'){
      nbLogMsg(context,0,'E',"Expecting ',' ';' or end of line at \"%s\".",cursor);
      return(NULL);
      }
    }
  if(notfound==NULL) notfound=NB_CELL_UNKNOWN;
  if(found==NULL) found=notfound;
  tree=(BTree *)nbAlloc(sizeof(BTree));
  tree->options=options;
  tree->notfound=notfound;
  tree->found=found;
  tree->root=NULL;
  tree->directory=directory;
  tree->cycle=cycle*60;
  tree->periods=periods;
  tree->interval=interval*60;
  tree->weight=weight;
  tree->tolerance=tolerance*1.25;
  nbListenerEnableOnDaemon(context);  // sign up to enable when we daemonize
  return(tree);
  }