Next: , Previous: (nodebrain), Up: (nodebrain)

NodeBrain Library

This document is for the NodeBrain Library. It describes the NodeBrain C API, intended for C programmers developing modules or embedding the rule engine in an application. See the NodeBrain Guide for information on using the rule engine as the nb command. Rule programmers should reference NodeBrain Tutorial, NodeBrain Language, module manuals, and kit manuals for additional information.

Release 0.9.03, December 2014

Copyright © 2014 Ed Trettevik <eat@nodebrain.org>

Permission is granted to copy, distribute and/or modify this document under the terms of either the MIT License (Expat) or NodeBrain License. See the Licenses section at the end of this document for details.

Short Table of Contents

References

Table of Contents


Next: , Previous: Top, Up: Top

1 Introduction

The NodeBrain Library provides the core logic of the NodeBrain Rule Engine, and a C API used to interact with the rule engine, either as a program that uses the rule engine, or as a plugin module that extends the functionality of the rule engine.

The library (libnb) is provided by the nodebrain package, bundled with the nb program and a set of modules. The library is versioned based on changes to the API, rule syntax, and rule behavior. This is different than, but related to, package versions.

Prior to release 0.9.03, every release produced a unique file name (e.g. libnb-0.9.02.so) and there was no implied binary compatibility. Starting with release 0.9.03, the library has switched to the libtool versioning scheme in preparation for a 1.0 release to start a series of compatible releases for which upgrades can be performed without rebuilding or modifying using applications.

Package     Example     Description
Version 1.2.03 major.minor.patch [patch is 2 digit]
Release 1.2.03 Released version [not all versions are released]
Downstream 1.2.03-1 version-DownstreamRelease

Library     Example     Description
Revision 1203 Package version with periods removed
Edition 1.0 Interface and behavior number
Series 1 Compatibility series number
Spec 1.0.1203 edition.revision

On Linux, the library revision number is included in the file name, revealing the package version number.

On other platforms the revision is not included in the file name, in which case, you will need to execute nb to display the package version and library spec. On Mac OS X, the library and module files look like this.

The following rules determine how the spec will change for a new release.

The following rules apply to release numbers.


Next: , Previous: Introduction, Up: Top

2 Concepts

This chapter provides an outline of NodeBrain interfaces to help you choose the method most appropriate for you application. You may find that interfaces other than the C API provided by the NodeBrain Library are sufficient for your application.


Next: , Up: Concepts

2.1 Interface Structure

The figure below illustrates the available interface options and the relationship between NodeBrain and the components you may elect to write or use.

./Interfaces.png


Next: , Previous: Interface Structure, Up: Concepts

2.2 Command Language

The primary interface to NodeBrain is the command language. Use the command language to specify what you want NodeBrain to do. Familiarity with the language is required for using the interfaces described in this section. See the NodeBrain Language manual for more information.

2.2.1 Interactive Session

An interactive session may be launched by invoking the nb program from a shell command prompt as shown below.

     $ nb
     > command

NodeBrain commands are entered in response to the command prompt ">".

2.2.2 Source Files

The easiest way to provide commands to the interpreter is by directing it to process source files.

     $ nb file

The source command may also be used to direct the interpreter to process a source file, provided you already have an interface to the interpreter. In interactive mode, the source command is entered at the prompt.

     > source file

2.2.3 Piping Commands to NodeBrain

Commands may be piped to NodeBrain's stdin using a shell command as follows.

     $ script | nb =

Pipes can also be used within a script as illustrated by the following Perl script.

     #!/usr/bin/perl
     open(NB,"| nb =")||die;
     print(NB "command1");
     print(NB "command2");
     close(NB);

2.2.4 Piping Action Messages from NodeBrain

Output directed to NodeBrain's stdout using the ^ directive may be sent to another script to handle required actions.

     $ nb source | script

This may also be done by invoking NodeBrain from within a script as illustrated by this Perl script.

     #!/usr/bin/perl
     open(NB,"nb source |")||die;
     while(<NB>){
       ... take action ...
       }
     close(NB);


Next: , Previous: Command Language, Up: Concepts

2.3 Servant Interface

The servant interface is designed to enable programs and scripts written in any language to communicate easily with the NodeBrain interpreter by reading from stdin and writing to stdout and stderr. This is a convenient interface that you should consider as an alternative to the C API.

2.3.1 Source and Action Servants

A source servant is any command or script that writes NodeBrain commands to stdout to be interpreted by the invoking NodeBrain process. This is similar to CGI programs or scripts that write HTML on stdout to a web server.

     > -:  command  Interpret stdout, log stderr and send to attached client
     > -|: command  Interpret stdout, log stderr only
     > =:  command  Interpret stdout, send stderr to generated output file
     > =|: command  Interpret stdout, log stderr

An action servant is any program or script invoked by NodeBrain to perform an action—often a rule action.

     > -  command    Output to log file and attached client
     > -| command    Output to log file only
     > =  command    Output to generated output file
     > =| command    Output to log file

See the NodeBrain Language manual for a complete description of the servant commands, - and =.

2.3.2 Servant Node Module

The Servant module provides a way to define servants for repeated use, and enables the use of pipes for both stdin and stdout. This enables a program or script to persistently function as a source servant and/or action servant.

     define term node servant:[|] servantCommand

This is a convenient way to add functionality to a rule set using languages best suited for implementing the needed functionality. Although a servant runs as a separate process, it is a logical extension of the parent NodeBrain process.

This interface also enables communication between servants. One servant may write a NodeBrain command to stdout, which when interpreted by the parent NodeBrain causes a message to be sent to stdin of another servant.

The servant module is described in the Servant NodeBrain Module manual.

2.3.3 Using NodeBrain as a Servant

You can use one NodeBrain script as a servant to another NodeBrain script since NodeBrain supports the trivial servant interface as both a parent and a child process. In such a case, the text messages exchanged in both directions must be valid NodeBrain commands. This is a way to split a NodeBrain agent into multiple processes, taking advantage of multiple CPU's and concurrent processing.


Next: , Previous: Servant Interface, Up: Concepts

2.4 Interface Modules

Some of the modules distributed with NodeBrain support various ways of communicating with the rule engine. The Mail, Pipe, Snmptrap, Syslog, and Webster modules support communication via standard protocols. These can be used to communicate with non-NodeBrain components. For example, the Webster module enables you to send commands to a NodeBrain agent using a web browser.

In addition, the Peer and Message modules enable communication between NodeBrain agents using NodeBrain specific protocols. It is possible for servants written in your favorite language, running under two different NodeBrain agents, to communicate with one another via messages sent between agents using a module specific protocol without the servants having any knowledge of the protocol. For example, a servant script might write the following command to stdout.

     foo:bar:hello

If foo is defined as a node within the parent agent that securely forwards commands to a peer agent, and bar is defined as a servant in the peer, then hello will be sent to the peer's servant on stdin. If the peer-to-peer nodes were defined as foo on both ends, and the servants were both defined as bar, then the peer servant could return a message with the same foo:bar: prefix. The Message module supports broadcasting messages to all agents within a cabal with assured one-time delivery.


Next: , Previous: Interface Modules, Up: Concepts

2.5 Library Functions

The NodeBrain Library provides the C API, the topic of this manual. The C API is the most difficult method of interfacing with NodeBrain. Although this is the least efficient approach in terms of your time spent implementint a solution, it can sometimes provide the most efficient solution. So while most of this chapter is intended to discourage the use of the C API when unnecessary, you are encouraged to use it when you feel it provides the best option for your requirements.

Each function is part of one of three major logical components: Cerebrum, Medulla, and Spine. Within each, functions are further divided into logical sets. We refer to each individual set as an API, each larger component set as an API, and the full set provided by the library as the NodeBrain C API.

Component     Set           Interface
Cerebrum Interface to interpreter
Skull Host programs interface to an embedded rule engine
Module Module registration of callback methods
Node Interface to nodes
Cell Interface to cells
Skill Rule engine calls back to modules
Medulla Process and asynchronous IO management (breathing and heart rate)
File Functions to add/replace/remove file handlers to respond to files that become ready for read or write operations.
Queue Functions to add/replace/remove file handlers to respond to files that become ready for read or write operations.
Process Functions that spawn and terminate child processes and provide queued asynchronous communication between the parent and child processes. This function group makes use of the File and Queue functions, as well as functions in the Spine.
Wait This function group is based on the select() function on Unix/Linux and WaitForMultipleObjects() on Windows.
Spine Interface to the host operating system
Servant Child process interface layered on top of the process function group. This interface is more restricted.
Process Child process interface
Network Network communications

2.5.1 Cerebrum

The Cerebrum is a subset of functions that provide the internal services of the interpreter. These functions are intended only for C programmers wanting to extend the functionality of NodeBrain by writing skulls or modules. A skull is a program that embeds the rule engine and must conform to the structure imposed by the Medulla. The nb program is itself a skull. A module is a plugin to the rule engine, providing additional capabilities.

2.5.2 Medulla

The Medulla is a subset of functions appropriate for a server application. These functions are intended for use by NodeBrain, but may be used by other C programs. Simply include the Medulla header (nb/nbmedulla.h) and link with the NodeBrain Library (-lnb). These functions impose a structure on the calling program that may not be easy to incorporate into an existing program. When the Medulla is operating in server mode it may conflict with a program's use of timers and IO not designed for use with the Medulla.

2.5.3 Spine

The Spine is a subset of functions that provide an interface to the host operating system, without dependence on a NodeBrain environment. These functions are primarily intended for use by other NodeBrain functions, but may be used by any C program. Simply include the spine header (nb/nbspine.h) and link with the NodeBrain Library (-lnb).


Next: , Previous: Library Functions, Up: Concepts

2.6 Selecting an Interface

It seems wise to start with simple interfaces and move to more complex interfaces only as necessary. If you follow this advice you will consider the interfaces in the order described here.

Start by writing rules and using existing components.

Frequently a NodeBrain application can be accomplished using existing programs and modules. All you need to do in many cases is write your NodeBrain rules and save them as source files. You can use most existing utilities and shell commands as action servants.

Write servants in your favorite language.

If you need to write servants, you should start by writing simple servants in your favorite programming language—shell scripts, other scripting languages (e.g. Perl or Python), or compiled languages (e.g. C/C++). Servants may be parent or child processes in relation to NodeBrain, and need only conform to NodeBrain's assumptions about stdin, stdout, stderr. Servants are often very simple programs. Even when you write a complex servant, you are working in a language familiar to you and the interface to NodeBrain never gets more complicated than reading from stdin and/or writing to stdout.

Write a module to extend NodeBrain.

If you are a C programmer, and want an integrated extension to NodeBrain, write a module. This enables you to enhance NodeBrain without modifying the interpreter. This is significantly more complicated than writing servants, and there is a greater (although hopefully not great) risk of encountering compatibility issues with future releases of NodeBrain. A module provides method functions called by the interpreter to handle assertions, cell expressions, and commands. This enables a module to extend the language in predefined ways.

Write a skull program to extend NodeBrain.

There may be cases where you want the NodeBrain interpreter embedded within your program. This is generally not recommended because it requires recompiling your program to upgrade to a new release of NodeBrain. However, if you think an integrated program is the right approach for your application, this option is available.

Modify NodeBrain.

If NodeBrain just doesn't work for you as released, but you see a way to modify it to make it work, this is a fine approach also. The downside of this approach is the burden of maintaining your own copy. However, if your change could benefit others, you may be able to escape the burden of maintenance by submitting your change as a proposal to the NodeBrain project.


Previous: Selecting an Interface, Up: Concepts

2.7 Methods

In this document, a method is a function you write for NodeBrain to call. Most methods are passed as a callback function in a call to a NodeBrain API function. A couple are symbols in a dynamic module that follow a naming convension enabling NodeBrain to resolve them.


Next: , Previous: Concepts, Up: Top

3 Skull Functions

This set of functions is used to embed the rule engine in a C program, a skull from the rule engine's perspective. This chapter covers only functions designed specifically for skull programs. After starting the rule engine you may use functions described in other chapters.

An example of a skull program follows. The numstrdiff skill implements an Evaluation method that computes the difference between the sum of all number arguments and the sum of the lengths of all string arguments. Other types of arguments are silently ignored.

     #include <nb/nb.h>
     
     static nbCELL numstrdiffEvaluate(
       nbCELL context,void *skillHandle,
       void *knowledgeHandle,nbCELL arglist){
     
       nbSET argSet;
       nbCELL cell;
       double length=0;
       int len=0;
       int type;
     
       argSet=nbListOpen(context,arglist);
       while((cell=nbListGetCellValue(context,&argSet))){
         type=nbCellGetType(context,cell);  // get cell type
         if(type==NB_TYPE_STRING){
           len+=strlen(nbCellGetString(context,cell)); // sum string lengths
           }
         else if(type==NB_TYPE_REAL){
           length+=nbCellGetReal(context,cell);        // sum numbers
           }
         nbCellDrop(context,cell);  // release each cell when done with it
         }
       cell=nbCellCreateReal(context,length-len);  // create cell with difference
       return(cell);  // return sum of numbers minus sum of string lengths
       }
     
     static void *numstrdiffBind(
       nbCELL context,void *moduleHandle,
       nbCELL skill,nbCELL arglist,char *text){
     
       nbCELL facet=nbSkillFacet(context,skill,""); // get primary facet
       nbSkillMethod(context,facet,NB_NODE_EVALUATE,numstrdiffEvaluate);
       return(NULL);
       }
     
     int main(int argc,char *argv[]){
       nbCELL context;
     
       context=nbStart(argc,argv);
       nbSkillDeclare(context,numstrdiffBind,NULL,"","numstrdiff",NULL,"");
       nbCmd(context,"define differ node numstrdiff;",NB_CMDOPT_ECHO);
       nbCmd(context,"show (differ(5,\"abcdefg\",2,\"abc\"));",NB_CMDOPT_HUSH);
       nbCmd(context,"show (differ(10,5,\"abcdefg\",2,\"abc\"));",NB_CMDOPT_HUSH);
       return(nbStop(context));
       }

The output from the three calls to nbCmd above should look like this.

     > define differ node numstrdiff;
     () = -3 == differ(5,"abcdefg",2,"abc")
     () = 7 == differ(10,5,"abcdefg",2,"abc")


Next: , Up: Skull Functions

3.1 nbStart - Start rule engine

     nbCELL nbStart(
       int argc,      // standard C main routine argument count
       char *argv[]); // standard C main routine arguments
     
     Returns: Context handle for use in calls to other API functions

The nbStart function is used to initialize the rule engine as specified by the arguments. Only rule engine startup ("++") arguments are processed.


Next: , Previous: nbStart, Up: Skull Functions

3.2 nbServe - Serve engine arguments

     nbCELL nbServe(
       int argc,      // standard C main routine argument count
       char *argv[]); // standard C main routine arguments
     
     Returns: Context handle for use in calls to other API functions

The nbServe function is used to process a set of rule engine arguments, ignoring startup ("++") arguments. This routine does not return until all arguments have been processed as described for the nb program. This means if the arguments put the engine in a server mode (daemon or servant), this function will not return until a stop command is issued in daemon mode, or an end-of-file on stdin is reached in servant mode.


Previous: nbServe, Up: Skull Functions

3.3 nbStop - Stop rule engine

     int nbStop(
       nbCELL context); // Context handle
     
     Returns: Rule engine exit code

The nbStop function closes files and releases memory allocated by NodeBrain.

Warning: This routine is not yet fully implemented. It does not clean up the environment. Repeated calls to nbStart and nbStop will create a major memory leak. So, you should only call nbStart and nbStop once in your program for now.


Next: , Previous: Skull Functions, Up: Top

4 Module Functions

A module is a plugin to the rule engine. It provides one or more node skills. A node skill provides a set of skill methods that give a node functionality beyond that which the rule engine provides. Although modules are normally separate dynamically loaded modules, a skull program that embeds the rule engine can also call module functions to create new types of nodes.

The following is a sample module that implements a skill called numstrdiff. Notice the similarity to the skull example in the previous chapter. Here the nbBind method declares the skill instead of a main routine. As noted in the comments, the nbBind method is not always necessary.

     #include <nb/nb.h>
     
     static nbCELL numstrdiffEvaluate(
       nbCELL context,void *skillHandle,
       void *knowledgeHandle,nbCELL arglist){
     
       nbSET argSet;
       nbCELL cell;
       double length=0;
       int len=0;
       int type;
     
       argSet=nbListOpen(context,arglist);
       while((cell=nbListGetCellValue(context,&argSet))){
         type=nbCellGetType(context,cell);  // get cell type
         if(type==NB_TYPE_STRING){
           len+=strlen(nbCellGetString(context,cell)); // sum string lengths
           }
         else if(type==NB_TYPE_REAL){
           length+=nbCellGetReal(context,cell);        // sum numbers
           }
         nbCellDrop(context,cell);  // release each cell when done with it
         }
       cell=nbCellCreateReal(context,length-len);  // create cell with difference
       return(cell);  // return sum of numbers minus sum of string lengths
       }
     
     static void *numstrdiffBind(
       nbCELL context,void *moduleHandle,
       nbCELL skill,nbCELL arglist,char *text){
     
       nbCELL facet=nbSkillFacet(context,skill,""); // get primary facet
       nbSkillMethod(context,facet,NB_NODE_EVALUATE,numstrdiffEvaluate);
       return(NULL);
       }
     
     // if the module is named nb_numstrdiff.so, you can drop nbBind
     // and change numstrdiffBind above from static to extern.
     extern void *nbBind(nbCELL context,char *module,nbCELL argList,char *text){
       nbSkillDeclare(context,numstrdiffBind,NULL,"","numstrdiff",NULL,"");
       return(NULL);
       }


Next: , Up: Module Functions

4.1 nbBind Method - Initialize module

     extern void *nbBind(
       nbCELL context,  // Context handle
       char *module,    // Name of module implicitly or explicitly declared
       nbCELL *argList, // Argument cells if explicitly declared - may be NULL
       char *text);     // Text options if explicitly declared - may be null string
     
     Returns: Module handle - pointer to allocated structure or NULL

You may include an nbBind method in a module to perform initialization tasks. These tasks might include the allocation of a memory structure for use by any of the node skills provided by the module, and/or the declaration of skills. When initialization is not required, the nbBind method may be omitted from a module. This method does not apply to skull programs embedding the rule engine since a skull requires no special opportunity to perform initializaton tasks. For a module, the nbBind method is called once when the module is first loaded.

The argList and text will be null unless explicity declared.

     declare module module dynamic_load_library[[(argList)]:text][;]


Next: , Previous: nbBind Method, Up: Module Functions

4.2 nbBindCellFunction - Bind a cell function to a C function

     int nbBindCellFunction(
       nbCELL context,          // Context handle
       char *name,              // Name of cell function
       void *function,          // C function pointer
       char *binding);          // Name of binding to use for this function
     
     Returns:
       0 - success
      -1 - error (see message) - the cell function was not registered for use

This function is used to make a C function available for use as a cell function. When an appropriate binding is already defined, this can simplify reuse of existing libraries of C functions. It can also simplify the creation of new cell functions, since the new function can be written in C, often without reference to any NodeBrain API functions.

The name of the cell function is prefixed by the name of the module that provides it. This is intended to avoid name collisions. The name is exactly as you want to reference it in a formula, excluding the backtick that tells the interpreter you are referencing a cell function.

     module.function
     math.sqrt

The name of a binding starts with the name of the module that provides it, followed by a space, and then a simplified data type specification. The use of "nb" as a module name is reserved for built-in bindings.

     module ReturnType(Arg1Type,Arg2Type,...)
     nb d(d,d)

The types are represented by single characters.

Type         C Data Type
d double
i int
s char * [string]
c char
C nbCELL [no transformation]

The following bindings are provided initially.

Binding       C Function Type
nb d(d) double f(double)
nb d(d,d) double f(double,double)
nb s(s,i) char *f(char *,int)

The following additional bindings can be anticipated in future releases, along with an API function for declaring new bindings.

Binding       C Function Type
nb d(d[],i) double f(double[],int)
nb s(s,c) char *f(char *,char)
nb s(s,s) char *f(char *,char *)
nb s(s[],i) char *f(char *[],int)
nb i(s,s) int f(char *,char *)
nb i(s[],i) int f(char *[],int)
nb C() nbCELL f()
nb C(C) nbCELL f(nbCELL)
nb C(C,C) nbCELL f(nbCELL,nbCELL)
nb C(C[],i) nbCELL f(nbCELL[],i)

This function is used in example eCellFunctions.c, which you will find in the lib/test directory in the online git repository.


Next: , Previous: nbBindCellFunction, Up: Module Functions

4.3 nbSkillDeclare - Register a skill

     int nbSkillDeclare(
       nbCELL context,          // Context handle
       void *(*bindFunction)(), //
       void *moduleHandle,      // Point to dynamic load module or NULL
       char *moduleName,        // Name of module or null string
       char *skillName,         // Name of skill
       nbCELL argList,          // Argument list or NULL
       char  *text);            // Option text or null string
     
     Returns:
       0 - success
      -1 - error (see message)

This function is used to declare a new skill from within a program or module containing the functions to be used as skill methods. The argList and text arguments are the same as in a skill declaration command.

     declare skill skill module.skill(arglist):text

With the nbSkillDeclare function you don't have an opportunity to alias the skill name, but do have an opportunity to alias the bind function. A common bind function may be used for multiple skills using different argList and text values.


Next: , Previous: nbSkillDeclare, Up: Module Functions

4.4 nbSkillFacet - Register a skill facet

     nbCELL nbSkillFacet(
       nbCELL context, // Context handle
       nbCELL skill,   // Skill cell
       char  *name);   // Facet name - null string for primary facet
     
     Returns: Facet cell for calls to nbSkillMethod

This function is used to add a facet to a skill and/or obtain a cell handle to the facet for use in calls to nbSkillMethod. Specify a null string for the name to get a handle to the primary facet. A multifaceted skill provides a node with multiple sets of skill methods—one set for each facet. Different facets can provide the same or different subsets of all possible methods.

When a node is referenced within a rule or command set, a facet name may be specified after the node name, separated by an underscore. In the example below, the bob node uses the bobbie skill of the robert module. The expression bob_jack(10) is handled by the Evaluate method of the jack facet of the bobbie skill. The expression bob("abc") is handled by the Assert method of the primary facet of the bobbie skill.

     define bob node robert.bobbie;
     define r1 on(bob_jack(10)>17) bob("abc");

Warning: This function is not available prior to version 0.9.00.


Next: , Previous: nbSkillFacet, Up: Module Functions

4.5 nbSkillMethod - Register a skill facet method

     int nbSkillMethod(
       nbCELL context,  // Context handle
       nbCELL facet,    // Facet cell
       int methodId,    // Method identifier code
       void *function); // Method callback function
     
     Returns:
       0 - success
      -1 - error (see message)
     
     Method Identifier Codes:
     
       NB_NODE_ALARM
       NB_NODE_ALERT
       NB_NODE_ASSERT
       NB_NODE_COMMAND
       NB_NODE_COMPUTE
       NB_NODE_CONSTRUCT
       NB_NODE_DESTROY
       NB_NODE_DISABLE
       NB_NODE_ENABLE
       NB_NODE_EVALUATE
       NB_NODE_SOLVE
       NB_NODE_SHOW

This function is used within a skill Bind method within a skull or module to bind a method to a skill facet. You must first obtain a facet cell using a call to nbSkillFacet with the skill cell provided as an argument to the Bind method.

Warning: This function is not available prior to version 0.9.00.


Next: , Previous: nbSkillMethod, Up: Module Functions

4.6 nbSkillSetMethod - Bind a skill method

     int nbSkillSetMethod(
       nbCELL context,   // Context handle
       NB_Skill *skill,  // Skill cell
       int methodId,     // Method identifier code
       void *function);  // Method callback function
     
     Returns:
       0 - success
      -1 - error (see message)
     
     Method Identifier Codes:
     
       NB_NODE_ALARM
       NB_NODE_ALERT
       NB_NODE_ASSERT
       NB_NODE_COMMAND
       NB_NODE_COMPUTE
       NB_NODE_CONSTRUCT
       NB_NODE_DESTROY
       NB_NODE_DISABLE
       NB_NODE_ENABLE
       NB_NODE_EVALUATE
       NB_NODE_SOLVE
       NB_NODE_SHOW

This function is used within a skull or a Bind method within a module to bind a method to a skill. The skill cell is provided as an argument to a skill Bind method.

Warning: This function is deprecated but supported for compatibility with older modules. Starting with release 0.9.01, use the nbSkillFacet and nbSkillMethod functions instead.


Next: , Previous: nbSkillSetMethod, Up: Module Functions

4.7 nbVerbDeclare - Register a command verb

     int nbVerbDeclare(
       nbCELL context,        // Context handle
       "module.verb", // Verb
       int auth,              // Authorization flags
       int flags,             // Reserved flags - always 0
       void *handle,          // Handle for module command method
       void *handler,         // Module command method
       char *helpText);       // A short string of help text
     
     Returns:
       0 - successful
      -1 - error (see message)
     
     Authorization Flags:
       NB_AUTH_CONNECT - connection permission
       NB_AUTH_ASSERT  - assert and alert permission
       NB_AUTH_DEFINE  - define, undefine, redefine permission
       NB_AUTH_DECLARE - declare permision (owner)
       NB_AUTH_SYSTEM  - shell command permission
       NB_AUTH_CONTROL - rank, set, stop (owner)

This function is used to create new commands. The verb is specified as module.verb to avoid conflict with commands provided by the rule engine.


Previous: nbVerbDeclare, Up: Module Functions

4.8 Module Command Method - Handle a registered command verb

     int moduleCmdVerb(
       nbCELL context, // Context cell
       void *handle,   // Handle specified in call to nbVerbDeclare
       char *verb,     // Verb specified in call to nbVerbDeclare
       char *text);    // Command body - text after verb
     
     Returns:
       0 - successful
      -1 - error (see message)

The module command method is provided to process commands you define using nbVerbDeclare. This method is invoked each time a module command is specified as follows.

     module.verb text

If your module has not been loaded, the rule engine loads the module first, if found. This will invoke your nbBind method, which calls nbVerbDeclare to register the command, and then the associated module command method is called. If the module is loaded by the verb is not defined, then an error message is displayed.


Next: , Previous: Module Functions, Up: Top

5 Skill Methods

A skill method is a function provided by a module to perform a particular task for nodes of a given type. The type of node is really defined by the set of skill methods associated with it. From this perspective, the notions of class and object in an object oriented language like C++ or Java are similar to our notions of skill and node. Skill methods are like class methods without the important object oriented notion of inheritance.

Some of the methods are passed a list of cells as an argument. The nbListOpen and nbListGetCellValue functions may be used to iterate throught the cell list. The nbCellGetType, nbCellGetString, and nbCellGetReal functions are often used to convert the cell values into C data types.

     type skill[_facet]Method(nbCELL context,...,nbCELL argList,...){
       nbCELL cell;
       nbSET set;
       int type;
       char *string;
       double real;
     
       set=nbListOpen(context,arglist);
       while((cell=nbListGetCellValue(context,set))){
         type=nbCellGetType(context,cell);
         if(type==NB_TYPE_STRING){
           string=nbCellGetString(context,cell);
           ...
           }
         else if(type==NB_TYPE_REAL){
           real=nbCellGetReal(context,cell);
           ...
           }
         else ...
         nbCellDrop(context,cell); // release cell fi done with it
         }
       }

If you want to access the cells in the argList instead of their values, then use the nbListGetCell function instead of nbListGetCellValue. This is necessary in cases where the cell provides a trigger condition for which you want to monitor the value instead of just obtaining the current value. It is also necessary to use this approach when the cells are not assumed to be enabled, as in the Compute method.

     type skill[_facet]Method(nbCELL context,...,nbCELL argList,...){
       nbCELL cell;
       nbSET set;
     
       set=nbListOpen(context,arglist);
       while((cell=nbListGetCell(context,set))){
         ... process cell ...
         nbCellDrop(context,cell); // release cell if done with it
         }
       }


Next: , Up: Skill Methods

5.1 Alarm - Handle node alarm

     void *skill[_facet]Alarm(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL cell);      // Optional cell to process on alarm
     
     Returns: void

     synapse=nbSynapseOpen(context,skillHandle,nodeHandle,cell,skill[_facet]Alarm);
     nbSynapseSetTimer(context,synapse,seconds);


Next: , Previous: Alarm Method, Up: Skill Methods

5.2 Alert - Handle node sentence alert

     static oid *skill[_facet]Alert(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList,    // Argument cell list or NULL
       nbCELL value);     // Value cell
     
     Returns:
       0 - success
      -1 - error (see message)


Next: , Previous: Alert Method, Up: Skill Methods

5.3 Assert - Handle node sentence assertion

     static void *skill[_facet]Assert(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList,    // Argument cell list or NULL
       nbCELL value);     // Value cell
     
     Returns:
       0 - success
      -1 - error (see message)

The Assert method is called to support assertions. It is intended to store knowledge in a node's memory for later reference. However, you can use it to take whatever action you like.

The general syntax for an assertion to a node includes an optional facet, arguments and a cell expression providing the value. There are shortcuts for three special values.

     node[_facet](argList)=valueCellExpression
     node[_facet](argList)    same as    node[_facet](argList)=1
     !node[_facet](argList)   same as    node[_facet](argList)=!
     ?node[_facet](argList)   same as    node[_facet](argList)=?

This syntax may appear in an assert command, alert command, or in a rule action. When the node is specified in the command prefix, it is implied on an argument list. The last three lines in the example below show three ways the treeAssert method could get called.

     define spruce node tree;
     assert spruce("abc","def")=27;            # assert command
     spruce. assert ("abc","def")=27;          # assert command with node as prefix
     define r1 on(a=2) spruce("abc","def")=27; # rule with assertion


Next: , Previous: Assert Method, Up: Skill Methods

5.4 Bind - Create a skill handle and bind methods

     void *skillBind(
       nbCELL context, // Context handle
       void *module,   // Module handle
       nbCELL skill,   // Skill cell for registering methods
       nbCELL argList, // Argument cell list or NULL
       char *text);    // Text options or null string
     
     Returns:    Skill handle - pointer to an allocated structure, or NULL

The Bind method is invoked by nbSkillDeclare, which is called either by a skull program, a module's nbBind method, or by the rule engine for skills that are referenced without prior declaration. The Bind method is called once for a give skill. It is responsible for binding skill methods to the skill using the functions described in the Node Module Functions chapter.

The argList and text arguments are null unless explicitly declared as shown below, or specified in a call to nbSkillDeclare.

     declare skillAlias skill module.skill[(argList)][:text|;]


Previous: Destroy Method, Up: Skill Methods

5.5 Command - Handle node command

     static int skill[_facet]Command(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList,    // Argument cell list or NULL
       char *text);       // Command text or null string
     
     Returns:
       0 - successful
      -1 - error (see message)

The Command method is called to support extended node commands. This method may be used to implement your own command language for use within NodeBrain rules. It may also be used to implement commands to control specific nodes. We list some possibilities here, but you are free to use it as you like.

Node commands start with the node name which must be followed by a left parenthesis starting an argument cell list or a colon starting command text.

     define node node definition
     node[(argList)][:text][;]


Next: , Previous: Evaluate Method, Up: Skill Methods

5.6 Compute - Handle node sentence computation

     static nbCELL skill[_facet]Compute(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList);   // Argument cell list or NULL
     
     Returns: Value cell

The Compute method is similar to the Evaluate method, only it doesn't assume the argument cells are currently enabled. You need only implement this method if you want to achieve a performance improvement over NodeBrain's default handling for this method. By default, NodeBrain enables the argument list (causing all argument expressions to be enabled and evaluated), calls the Evaluate method, and then disables the argument list. For some types of nodes you can avoid unnecessary evaluation of disabled argument expressions by providing your own Compute method. For example, an implementation of AND or OR would only require computation of the second argument if the first argument were True for AND or not True for OR.

Use the nbCellCompute function to compute the value of arguments. The following example computes all argument cells for illustration only—this would make the Compute method unnecessary.

     static nbCELL fooCompute(nbCELL context,void *skillHandle,void *nodeHandle,nbCELL argList){
       nbCELL cell,valueCell;
       nbSET set;
     
       set=nbListOpen(context,argList);
       while((cell=nbListGetCell(context,set))){
         valueCell=nbCellCompute(context,cell);
         ...
         }
       }


Next: , Previous: Bind Method, Up: Skill Methods

5.7 Construct - Handle node definition

     static void *skillConstruct(
       nbCELL context,     // Context handle
       void *skillHandle,  // Pointer to skill configuration structure
       nbCELL argList,     // Argument cell list or NULL
       char *text);
     
     Returns: Knowledge handle - pointer to an allocated structure

The Construct method is called when a node is defined. It is responsible for processing the argument cells and interpreting text provided in the definition. It may allocate a structure for knowledge representation. It returns a pointer to the allocated memory structure which is referenced as nodeHandle in the description of other methods.

The argList and text arguments are from the node definition as shown below.

     define node node [module.]skill[(argList)][:text | ;]


Next: , Previous: Solve Method, Up: Skill Methods

5.8 Enable - Handle node enable command

     static nbCELL skill[_facet]Enable(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle); // Pointer to node knowledge structure
     
     Returns:
       0 - success
      -1 - error (see message)

The Enable method is called to support the enable command for a node. You should only implement this method for skills that requirement management of enabled and disabled states.

     define node node definition
     enable node;

Some skills require a node to be enabled when the rule engine daemonizes—switches to background agent mode. This can be scheduled using the nbListenerEnableOnDaemon function.


Next: , Previous: Construct Method, Up: Skill Methods

5.9 Evaluate - Handle node sentence evaluation

     static nbCELL skill[_facet]Evaluate(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList);   // Argument cell list or NULL
     
     Returns: Value cell

The Evaluate method is called to produce a value for a node condition. This method assumes the argument values have already been determined. It is normally invoked for a node condition when an argument value has changed.


Next: , Previous: Disable Method, Up: Skill Methods

5.10 Destroy - Handle node destruction

     static nbCELL skill[_facet]Destroy(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle); // Pointer to node knowledge structure
     
     Returns:
       0 - success
      -1 - error (see message)

The Destroy method is used to free up memory allocated for a node's knowledge representation. This is only be implemented for skills implementing the Construct method. While it is preferable to implement this method when Construct is implemented, it is not required. If it is not implemented, NodeBrain will be unable to undefine a node associated with the skill.

     define node node definition
     ...
     undefine node


Next: , Previous: Enable Method, Up: Skill Methods

5.11 Disable - Handle node disable command

     static nbCELL skill[_facet]Disable(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle); // Pointer to node knowledge structure
     
     Returns:
       0 - success
      -1 - error (see message)

The Disable method is called to support the disable command for a node. You will normally implement this method only when you also implement the Enable method.

     define node node definition
     ...
     disable node


Next: , Previous: Compute Method, Up: Skill Methods

5.12 Show - Handle request to display node

     static nbCELL skill[_facet]Solve(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       int option);       // Option
     
     Returns:
       0 - success
      -1 - error (see message)
     
     Options:
       NB_SHOW_ITEM   - Show as single string without \n for glossary display
       NB_SHOW_REPORT - Show a multi-line report of skill and knowledge structures

The Show method is called to display a text representation of a node. When NB_SHOW_ITEM is specified, this method displays a single string for use when displaying a term glossary. This is done using the nbLogPut function with arguments like the printf function without including \n. When NB_SHOW_REPORT is specified, a multi-line report of a node's skill memory and node memory is produced using nbLogPut with \n characters included as needed to format the report.

In the example below the rule engine asks the spruce tree to display in NB_SHOW_REPORT format. While listing the terms in the spruce glossary, the fir tree is asked to display in NB_SHOW_ITEM format.

     define spruce node tree;
     spruce. define a cell 5;
     spruce. define fir node tree;
     show spruce


Next: , Previous: Show Method, Up: Skill Methods

5.13 Solve - Resolve unknowns and compute node sentence

     static nbCELL skill[_facet]Solve(
       nbCELL context,    // Context handle
       void *skillHandle, // Pointer to skill configuration structure
       void *nodeHandle,  // Pointer to node knowledge structure
       nbCELL argList);   // Argument cell list or NULL
     
     Returns: Value cell

This Solve method is similar to the Compute method, only it uses the nbCellSolve function to resolve argument cells instead of nbCellCompute. The nbCellSolve function is more determined than the nbCellCompute function. When nbCellCompute is asked to compute an term with an Unknown definition, it returns the Unknown object. When nbCellSolve is asked to solve for an term with an Unknown definition, it attempts to obtain a definition and compute a value. A solve method should only solve for argument cells as necessary to produce a value.

You need only implement the Solve method if you want your node to work in diagnostic mode more efficiently than NodeBrain's default behavior. By default, NodeBrain will attempt to solve for all argument cell expressions and then invoke your Evaluate method.


Next: , Previous: Skill Methods, Up: Top

6 Node Functions

API functions described in this chapter interact with nodes and the first argument is a node context handle. You may use the context returned by nbStart or the first argument passed to a skill method as the node context handle. You may also use a node context handle returned by other API functions.


Next: , Up: Node Functions

6.1 nbCmd - Interpret command

     int nbCmd(
       nbCELL context, // Node context handle
       char  *command, // Pointer to skill configuration structure
       int    option); // Argument cell list or NULL
     
     Returns:
      -1 - Syntax or semantic error. (See message)
       0 - Successfully processed
       n - Command specific return code
     
     Options:
       0               - Use options defined for the context
       NB_CMDOPT_ECHO  - echo the command
       NB_CMDOPT_HUSH  - suppress echo
       NB_CMDOPT_TRACE - trace command execution

The nbCmd function gives a skull program or module the full range of functionality provided by the NodeBrain command language.


Next: , Previous: nbCmd, Up: Node Functions

6.2 nbListenerEnableOnDaemon - Schedule enable when daemonized

     int nbListenerEnableOnDaemon(
       nbCELL context); // Node context handle
     
     Returns: 0

This function is normally used by a skill's Construct method when it needs to delay going into an active state until an agent deamonizes (goes into the background). At this time all of the rules required by the node have been loaded. The rules and other cells defined for a node are defined after the node is constructed. The Enable method may look at these cells to complete configuration before going into and enable state. If a node listens on a network socket for events to process against the rules defined for the node, this is another reason to wait until all the rules have been defined before listening. The nbListenerEnableOnDaemon function provides a call to the Enable method at the appropriate time. Many skills will not need a delayed enable, and some will not even implement an Enable method.


Next: , Previous: nbListenerEnableOnDaemon, Up: Node Functions

6.3 nbLogMsg - Write a message to the log

     int nbLogMsg(
       nbCELL context,  // Node context handle
       int   msgNumber, // Message number - 0 to 999
       char  msgType,   // Message type
       char *format,    // Format string for printf function
       ...);            // Variable number of arguments
     
     Returns:
      -1 - Error  (See message)
       0 - Successfully processed
     
     Message Types:
       (T)race
       (I)nformation
       (W)arning
       (E)rror
       (L)ogic error

The nbLogMsg function is used to write a message to the log, stderr. A message is prefixed with a time stamp, message identifier, module name, and node name.

In the example below, the message identifier of NM000E has three components. The number "000" and type "E" are provided by the caller. The "NM" identifies it as coming from the nbLogMsg function used by skulls and modules. The rule engine uses an internal form of this function that generates "NB" message identifiers. If you use non-zero message numbers, they only need to be unique per module because the module name is listed right after the message identifier. The node name helps to identify which node produced the message, since there may be many nodes using a given modules.

     > define fred node tree;
     > fred:sksksks
     2014/02/23 17:01:49 NM000E tree .fred: Verb "sksksks" not recognized.

The message above was produced by the following call to nbLogMsg.

     nbLogMsg(context,0,'E',"Verb \"%s\" not recognized.",verb);


Next: , Previous: nbLogMsg, Up: Node Functions

6.4 nbLogPut - Write text to the log

     int nbLogMsg(
       nbCELL context,  // Node context handle
       char *format,    // Format string for printf function
       ...);            // Variable number of arguments
     
     Returns:
      -1 - Error  (See message)
       0 - Successfully processed

The nbLogPut function is called to write to the log, stderr. With this function you have complete control of the output. You may find this function has no advantage over fprintf; This is often true. But use of this function provides a place to insert additional functionality, like temporarily splitting log data out to a second file. More importantly, it handles buffering of output to stderr consistent with other nbLogXXX functions.


Next: , Previous: nbLogPut, Up: Node Functions

6.5 nbNodeGetName - Get the simple name of a node

     char *nbNodeGetName(
       nbCELL context); // Node context handle
     
     Returns: Pointer to a node's simple name, not the full path name.

The nbNodeGetName function can be used to get the simple name of a node when passed as a context perameter to a function. In the example below, the node name is UserTypeHost.

     define UserTypeHost node cache:(~(8h):user,type,host);

If you need the fully qualified path name for a node, use the nbCellGetName function instead. Use the nbTermLocate function to get the root cell named "_" to use as the context in your call to nbCellGetName.


Next: , Previous: nbNodeGetName, Up: Node Functions

6.6 nbNodeGetTermCellArray - Get an array of terms defined within a node

     int nbNodeGetTermCellArray(
       nbCELL context,  // Node context handle
       nbCELL cell[],   // Array of term cells returned - lesser of size and return value
       int size);       // Number of entries in the cell[] array
     
     Returns:
       n>=0 - Number of terms defined in the context node.  This number may be
              larger than the array size, indicating the array is full and you
              need to provide a new array with n entries to get all terms.

The nbNodeGetTermCellArray function is called to obtain an unordered array of term cells defined within the context node. You may use the nbCellGetName function to get the name of a term cell relative to the context node. You may use the nbCellGetValueName function to get the name of the term cell's value. Other cell functions may be used to peform other operations appropriate for a term cell.


Next: , Previous: nbNodeGetTermCellArray, Up: Node Functions

6.7 nbNodeGetTermNameString - Get a string of term names within a node

     int nbNodeGetTermNameString(
       nbCELL context,  // Node context handle
       char  *buffer),  // Buffer to hold term names
       int    size);    // size of buffer
     
     Returns:
       n>0  - Bytes remaining in buffer (null terminator is part of this count)
       n<=0 - Buffer must be increased by 1-n bytes

The nbNodeGetTermNameString function is called to capture a single string showing the names of all terms defined within a node. The returned string is a comma separated list of names.

For node x in the following example, the returned string would be a,b,c,d,e,r1 in random order.

     define x node;
     x. define a cell 5;
     x. define b cell 3;
     x. define c cell a+b;
     x. define d cell a-b;
     x. define e cell "abc";
     x. define r1 on(d);


Next: , Previous: nbNodeGetTermNameString, Up: Node Functions

6.8 nbNodeGetTermValueString - Get a string of term names and values within a node

     int nbNodeGetTermValueString(
       nbCELL context,  // Node context handle
       char  *buffer),  // Buffer to hold terms - name and value string
       int    size);    // size of buffer
     
     Returns:
       n>0  - Bytes remaining in buffer (null terminator is part of this count)
       n<=0 - Buffer must be increased by 1-n bytes

The nbNodeGetTermValueString function is called to capture a single string showing the name and value of all terms defined within a node. The returned string looks similar to an assertion, with comma separated name=value pairs. However, you can not use this string to restore a node to the current state, since that would destroy the formulas. Also, a disabled cells are shown with a value of #, which is not valid assertion syntax.

For node x in the following example, the returned string would be a=5,b=3,c=#,d=2,e="abc",r1=# in random order. Note that c and r1 are not referenced by any rule, causing their value to be disabled.

     define x node;
     x. define a cell 5;
     x. define b cell 3;
     x. define c cell a+b;
     x. define d cell a-b;
     x. define e cell "abc";
     x. define r1 on(d);


Previous: nbNodeGetTermValueString, Up: Node Functions

6.9 nbNodeGetTermFormulaString - Get a string of term names and formulas within a node

Warning: This function is incomplete in release 0.9.03. Terms have definitions that are objects to the interpreter. When the object that defines a term is a cell that can be represented by a cell expression, it is called a formula, and the cell expression is the cell name. Many types of cells that qualify as formulas have not been updated with a getName method to return their string representation. Since they all have the ability to print their string representation in support of the show command, it will not be difficult to add the new getName method for each cell type. But until that is complete, many types of cells will rely on a default getName method that returns "('?')" as the cell name. So this function should be treated as experimental for now.

     int nbNodeGetTermFormulaString(
       nbCELL context,  // Node context handle
       char  *buffer),  // Buffer to hold terms - name and definition string
       int    size);    // size of buffer
     
     Returns:
       n>0  - Bytes remaining in buffer (null terminator is part of this count)
       n<=0 - Buffer must be increased by 1-n bytes

The nbNodeGetTermFormulaString function is called to capture a single string showing the name and formula of all terms defined within a node. The returned string looks similar to an assertion, with comma separated name==formula pairs.

For node x in the following example, the returned string would be a==5,b==3,c==(a+b),d==2,e=="abc",r1==d in random order.

     define x node;
     x. define a cell 5;
     x. define b cell 3;
     x. define c cell a+b;
     x. define d cell a-b;
     x. define e cell "abc";
     x. define r1 on(d);


Next: , Previous: Node Functions, Up: Top

7 Cell Functions

The functions described in this chapter are for interacting with the rule engine at the cell level. It is possible to extend NodeBrain by adding your own "action" commands without using any of these functions. However, most programs that use the NodeBrain Library to extend NodeBrain will need to use some of these functions.


Next: , Up: Cell Functions

7.1 nbCellCompute - Compute value of disabled cell

     nbCELL nbCellCompute(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to compute
     
     Returns: Constant cell representing computed value
     
     Warning: When you are finished with the returned value cell, you
              must call nbCellDrop to release it to avoid a memory leak.
     
     See also: nbCellEvaluate, nbCellGetValue, and nbCellSolve.

Use nbCellCompute to compute the value of a cell that may be disabled. A cell is disabled when there are no enabled rules depending on it. The value of a disabled cell is not maintained in response to assertions. A call to nbCellCompute will return the value of an enabled cell just like nbCellGetValue. But for a disabled cell, nbCellCompute will recursively call nbCellCompute on operand cells and then nbCellEvaluate to compute the cell value. The resulting value is the same as would have already been assigned if the cell had been enabled.


Next: , Previous: nbCellCompute, Up: Cell Functions

7.2 nbCellCreate - Create cell from expression

     nbCELL nbCellCreate(
       nbCELL context,         // Node context handle
       char  *cellExpression); // Cell expression
     
     Returns: Cell handle, or NULL on error (see message)
     
     Warning: When you are finished with the returned cell, you must
              call nbCellDrop to release it to avoid a memory leak.

The nbCellCreate function is used to obtain a handle to a cell. If the specified cell does not exist, it is created and a handle is returned. If the cell already exists, a handle to the existing cell is returned.


Next: , Previous: nbCellCreate, Up: Cell Functions

7.3 nbCellCreateReal - Create number cell

     nbCELL nbCellCreateReal(
       nbCELL context,  // Node context handle
       double real);    // Real number
     
     Returns: Handle for real number cell
     
     Warning: When you are finished with the returned cell, you must
              call nbCellDrop to release it to avoid a memory leak.
     
     Warning: Prior to version 0.9.01 this function failed to grab
              the created cell as intended. If you have code that used
              this function under prior versions that accidentally
              worked, it may break under 0.9.01 and above, requiring
              a fix to the calling code.

The nbCellCreateReal function is used to obtain a handle to a real number cell. If the specified cell does not exist, it is created and a handle is returned. If the cell already exists, a handle to the existing cell is returned. The value returned by this function is the same as nbCellCreate would return if passed the string representation of the number.


Next: , Previous: nbCellCreateReal, Up: Cell Functions

7.4 nbCellCreateString - Create string cell

     nbCELL nbCellString(
       nbCELL context,  // Node context handle
       char  *string);  // String
     
     Returns: Handle for string cell
     
     Warning: When you are finished with the returned cell, you must
              call nbCellDrop to release it to avoid a memory leak.

The nbCellCreateString function is used to obtain a handle to a string cell. If the specified cell does not exist, it is created and a handle is returned. If the cell already exists, a handle to the existing cell is returned. The value returned by this function is the same as nbCellCreate would return if passed the string enclosed in double quotes.


Next: , Previous: nbCellCreateString, Up: Cell Functions

7.5 nbCellDrop - Release cell

     nbCELL nbCellDrop(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to drop
     
     Returns: NULL (always)

Each cell has a reference count. The nbCellDrop function is called to decrement the reference count and free the cell if the count drops to zero.

While you may explicitly reserve a cell with a call to nbCellGrab, you must also know when other functions that return a cell pointer have placed a reserve on it for you. If so, you are still responsible for issuing a nbCellDrop when you are finished with the pointer. While this is a burden, it is required for the rule engine to know when an application is finished with a cell.

As you might imagine, you will get very unhappy results if you make too many calls to nbCellDrop. You can easily cause a cell to be released and the memory reused while there are still other pointers to the location of the released cell. One could say the result is unpredictable, but it is probably better to say the result is predictably bad.

     # drop cell and clear my pointer to it
     nodeHandle->somethingCell=nbCellDrop(nodeHandle->somethingCell);


Next: , Previous: nbCellDrop, Up: Cell Functions

7.6 nbCellEvaluate - Compute enabled cell value after change

     nbCELL nbCellEvaluate(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to compute
     
     Returns: Constant cell representing cell value
     
     Warning: When you are finished with the returned value cell, you
              must call nbCellDrop to release it to avoid a memory leak.
     
     See also: nbCellCompute, nbCellGetValue, and nbCellSolve

Use nbCellEvaluate to compute the value of an enabled cell after a change to an operand. This function simply provides an interface to the evaluation method of the cell. Normally the rule engine is aware of the need to call a cell evaluation method and performs this step automatically. However, it is possible for an application to implement cells for which the rule engine is not aware of all operands involved in an evaluation. In such a case, there are operands that are not cells known to the rule engine. Any change to these operands would then require the application to call nbCellEvaluate, or directly call the evaluation method.


Next: , Previous: nbCellEvaluate, Up: Cell Functions

7.7 nbCellGetReal - Get number from number cell

     double nbCellGetReal(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Real number cell
     
     Returns: Real number stored in specified cell

Use nbCellGetReal to extract a C double value from a real number cell.


Next: , Previous: nbCellGetReal, Up: Cell Functions

7.8 nbCellGetString - Get string from string cell

     char *nbCellGetString(
       nbCELL context,  // Node context handle
       nbCELL cell);    // String cell
     
     Returns: String stored in specified cell

Use nbCellGetString to extract a C char pointer from a string cell.


Next: , Previous: nbCellGetString, Up: Cell Functions

7.9 nbCellGetType - Get cell type code

     int nbCellGetType(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to inspect
     
     Returns: Cell type code
     
     Type Codes:
       NB_TYPE_UNDEFINED
       NB_TYPE_DISABLED
       NB_TYPE_FALSE
       NB_TYPE_UNKNOWN
       NB_TYPE_PLACEHOLDER
       NB_TYPE_STRING
       NB_TYPE_REAL
       NB_TYPE_LIST
       NB_TYPE_TERM
       NB_TYPE_NODE
       NB_TYPE_VERB
       NB_TYPE_TEXT

The nbCELL data type is a pointer to a cell. When returned by a library function, or passed to a method, you can call nbCellGetType to determine what type of cell you have. If it is not an expected type, you can call nbLogMsg to report an error.


Next: , Previous: nbCellGetType, Up: Cell Functions

7.10 nbCellGetValue - Get enabled cell value

     nbCELL nbCellGetValue(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to compute
     
     Returns: Constant cell representing cell value
     
     Warning: The returned cell has not been grabbed so you mush call
              nbCellGrab if you want to retain a reference.  Then call
              nbCellDrop when you no longer need a reference.
     
     See also: nbCellCompute, nbCellEvaluate, and nbCellSolve.

Use nbCellGetValue to get the current value of an enabled cell. This function is used when there is no need to compute a new value in response to changing operands—when you can assume the rule engine has already responded to changes at the level of the cell in the axon tree (bottom up tree of dependencies).


Next: , Previous: nbCellGetValue, Up: Cell Functions

7.11 nbCellGrab - Reserve cell

     nbCELL nbCellGrab(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to drop
     
     Returns: The cell argment
     
     See also: nbCellDrop

Each cell has a reference count. The nbCellGrab function is called to increment the reference count to ensure the cell will not be released while in use—while there is a pointer to it.

     nbCELL cell=...; // obtained somehow without a grab
     nodeHandle=malloc(sizeof(mynode));
     nodeHandle->somethingCell=nbCellGrab(context,cell);

Make sure you know if the process you use to create or obtain a cell pointer has already grabbed the cell on your behalf. If so, you should only call nbCellGrab if you need an additional grab—when you store the cell pointer more than once and have the possibility of calling nbCellDrop on each pointer independently. When you are finished with a cell pointer that you have reserved using a call to nbCellGrab, or that was grabbed for you by another function, you must release the cell pointer with a call to nbCellDrop to avoid a memory leak.


Next: , Previous: nbCellGrab, Up: Cell Functions

7.12 nbCellGetName - Get the name of a cell relative to a given context

     int nbCellGetName(
       nbCELL context,  // Node context handle
       nbCELL term,     // Cell for which the name is requested
       char **nameP,    // Pointer to name buffer for value returned
                        // This is advanced to the end of the name
       int    size);    // Size of name buffer
     
     Returns:
       n>0  - Bytes remaining in name buffer (null terminator is part of this count)
       n<=0 - Name buffer must be increased by 1-n bytes

The nbCellGetName function is called to get the name of a cell relative to a context node. The name of a cell is a string representation, just as one might enter it in a cell expression. In the sample rules below, there are six cells with the names foobar, a, b, (a&b), sally, and "abc".

     define foobar cell a and b;
     define sally  cell "abc";


Next: , Previous: nbCellGetName, Up: Cell Functions

7.13 nbCellSolve - Solve for value of cell

     nbCELL nbCellSolve(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Cell to compute
     
     Returns: Constant cell representing cell value
     
     Warning: When you are finished with the returned value cell, you
              must call nbCellDrop to release it to avoid a memory leak.
     
     See also: nbCellCompute, nbCellEvaluate, and nbCellGetValue.

Use nbCellSolve to compute the value of a cell for which the value is unknown because it references terms that are undefined. The goal of nbCellSolve is to obtain definitions for referenced undefined terms sufficient to derive a value other than Unknown for the cell, if possible. A term is undefined if it has no formula. The value of an undefined term is Unknown, but a term can have a value of Unknown without being undefined, because a formula can evalute to Unknown. When a term definition is a constant (e.g. "abc"), the value is the same constant. It is often the case in diagnostic mode, where nbCellSolve is used, that we expect to obtain a constant definition for a term, in which case it is the same as directly seeking a value.

For example, a call to nbCellCompute for the cell A or B, where A and B are undefined, will first attempt to obtain a formula (definition) for A and solve the formula to obtain a value for A. If the value is True, the value of A is returned and no attempt is made to obtain a definition for B. For A and B, a False or Unknown value for A would be sufficient to compute the cell value without bothering with B. Like a good doctor or car mechanic, a NodeBrain diagnostic rule writer should specify the conditions so the least expensive tests are performed first, enabling the most expensive tests to be avoided when possible.

Warning: This feature of NodeBrain requires additional work to refine the methods by which definitions can be obtained. Currently, prompts in interactive mode and scripts in background mode are supported.


Next: , Previous: nbCellSolve, Up: Cell Functions

7.14 nbCellGetValueName - Get the name of a cell's value

     int nbCellGetValueName(
       nbCELL context,  // Node context handle
       nbCELL term,     // Cell for which the name is requested
       char **nameP,    // Pointer to name buffer for value returned
                        // This is advanced to the end of the name
       int    size);    // Size of name buffer
     
     Returns:
       n>0  - Bytes remaining in name buffer (null terminator is part of this count)
       n<=0 - Name buffer must be increased by 1-n bytes

The nbCellGetValueName function is called to get the name of a cell's value cell relative to a context node. Since values are constant cells, they are typically strings and real numbers. The name of a string is a character string encoded in double quotes. The name of real number is a string representation of the number.

The name returned by this function is the same as one would get by using nbCellGetValue to get the value cell and then using nbCellGetName on it to get the name of the value cell.


Next: , Previous: nbCellGetValueName, Up: Cell Functions

7.15 nbListOpen - Open a cell list to iterate

     nbSET nbListOpen(
       nbCELL context,  // Node context handle
       nbCELL cell);    // List cell to open
     
     Returns: List set cell cursor

The nbListOpen function is used to obtain a set iterator for a list of cells. Skill methods often use this function, and related functions, to process an argument list, which is represented as a list of cells.


Next: , Previous: nbListOpen, Up: Cell Functions

7.16 nbListGetCell - Get next cell in list

     nbCELL nbListGetCell(
       nbCELL context,  // Node context handle
       nbSET cell);     // List set cell cursor
     
     Returns: Next cell in the set, or NULL at end of list
     
     Warning: The returned cell has been grabbed, so you must
              call nbCellDrop when it is no longer needed.

The nbListGetCell function is used obtain the next cell in a list of cells. The next cell is returned and the set iterator advances. A NULL value is returned when the end of the list is reached.


Next: , Previous: nbListGetCell, Up: Cell Functions

7.17 nbListGetCellValue - Get value of next cell in list

     nbCELL nbListGetCellValue(
       nbCELL context,  // Node context handle
       nbSET cell);     // List set cell cursor
     
     Returns: Value cell for Next cell in the set, or NULL if end of list
     
     Warning: The returned cell has been grabbed, so you must
              call nbCellDrop when it is no longer needed.

The nbListGetCellValue function returns the value of the next cell in a list. The value of a cell is itself a cell. The set iterator steps within the list on each call and NULL returned at the end of the list.


Next: , Previous: nbListGetCellValue, Up: Cell Functions

7.18 nbSynapseOpen - Register an Alarm method


Next: , Previous: nbSynapseOpen, Up: Cell Functions

7.19 nbSynapseSetTimer - Set an alarm


Next: , Previous: nbSynapseSetTimer, Up: Cell Functions

7.20 nbTermCreate - Create a new term

     nbCELL nbTermCreate(
       nbCELL context,     // Node context handle
       char *identifier,   // Term to create within context
       nbCELL definition); // Cell that defines the term
     
     Returns: Term cell, or NULL on error (see message)
     
     Warning: The returned cell has been grabbed, so you must
              call nbCellDrop when it is no longer needed.

The nbTermCreate function is used to create a new term within the specified context. The definition of the term is provided by a cell handle obtained by another library function, perhaps nbCellCreate.


Next: , Previous: nbTermCreate, Up: Cell Functions

7.21 nbTermGetDefinition - Get term definition cell

     nbCELL nbTermGetDefinition(
       nbCELL context,  // Node context handle
       nbCELL cell);    // Term cell whose definition is requested
     
     Returns: Cell defining the formula for computing the value of
              the term.  This can also be stated as the cell whose
              value the term inherits, or for which the term is an
              alias.
     
     Warning: The returned cell has not been grabbed so you mush call
              nbCellGrab if you want to retain a reference.  Then call
              nbCellDrop when you no longer need a reference.
     

The nbTermGetDefinition function is used to get the cell referenced by a term, which is the cell that computes the value of the term.


Next: , Previous: nbTermGetDefinition, Up: Cell Functions

7.22 nbTermLocate - Locate an existing term

     nbCELL nbTermLocate(
       nbCELL context,     // Node context handle
       char *identifier);  // Term identifier to locate
     
     Returns: Term cell handle, or NULL if not found
     
     Warning: The returned cell has not been grabbed, so you must
              call nbCellGrab if you want to retain a reference.
              Then call nbCellDrop when you no longer need a
              reference.

The nbTermLocate function is used lookup a term within the specified context.


Previous: nbTermLocate, Up: Cell Functions

7.23 nbTermSetDefinition - Assign new definition to term

     nbCELL nbTermSetDefinition(
       nbCELL context,     // Node context handle
       nbCELL term,        // Term to update
       nbCELL definition); // Cell that defines the term
     
     Returns: Cell handle of new value
     
     Warning: The returned cell has been grabbed, so you must
              call nbCellDrop when it is no longer needed.

The nbTermSetDefinition function is used to redefine a term. The new value returned is the value of the new definition.

     nbCELL term,definition,value;
     nbCmd(context,"assert a=1,b=1;",0);
     definition=nbCellCreate(context,"a*b");
     term=nbTermCreate(context,"bob",definition);
     definition=nbCellDrop(context,definition);
     definition=nbCellCreate(context,"a+b");
     value=nbTermSetDefinition(context,term,definition); // Redefine "bob"
     // value
     nbCellDrop(context,term);
     nbCellDrop(context,definition);
     nbCellDrop(context,value);


Next: , Previous: Cell Functions, Up: Top

8 Medulla Functions


Next: , Previous: Medulla Functions, Up: Top

9 Spine Functions


Next: , Previous: Spine Functions, Up: Top

Licenses

NodeBrain is free software; you can modify and/or redistribute it, including this document, under the terms of either the MIT License (Expat) or the NodeBrain License.


MIT License

Copyright © 2014 Ed Trettevik <eat@nodebrain.org>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


NodeBrain License

Copyright © 2014 Ed Trettevik <eat@nodebrain.org>

Permission to use and redistribute with or without fee, in source and binary forms, with or without modification, is granted free of charge to any person obtaining a copy of this software and included documentation, provided that the above copyright notice, this permission notice, and the following disclaimer are retained with source files and reproduced in documention included with source and binary distributions.

Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.


Previous: Licenses, Up: Top

Index