Glue code for the LibWWW to Tcl

Creating glue code for the LibWWW

- Introduction
- Creating Glue Code
- Adding Glue Code to the Interpreter

### Introduction:

The glue code from C to Tcl of the LibWWW was created to create Tcl scripts to test the Library. The main software tool utilized isDejaGnu. The glue code was created for the testing of individual core functions of the library. With glue code, they became functions in the Tcl interpreter. The Tcl interpreter was altered to include the glue code. Thus, aside from testing, the tcl shell can be used to create small applications using tcl/tk.

### Creating Tcl glue code

The glue code itself follows a standard format:

>     int function_name_tcl(ClientData clientData, Tcl_Interp *interp,
>     		      int argc, char **argv) {
>         if (argc == 2) {
>     	char *str    = argv[1];

>     	....variable initialization....

>     	....function calls...

>     	Tcl_AppendResult(interp, result, NULL);
>     	return TCL_OK;
>         }
>         else {

>     	....alert user to improper function call - wrong number of arguments?

>     	return TCL_ERROR;
>         }
>     }

The tcl function can be broken up into a number of possible parts:

- Arguments
- Variable Initialization
- Hash Table retrieving
- Function calling
- Hash Table storing
- Converting function output to strings for Tcl
- Errors
- Tcl Status

#### Arguments

Function arguments are treated just like command line arguments for C. To check the function has the right number of parameters, you check argc. Otherwise you return an error statement.

#### Variable Intialization

All variables in connection to the function need to be initialized. This includes all variables for the function parameters and function outputs. Also, there is also the need to initialize enough Tcl hash table pointers for the number of data structures you have.

#### Hash Table retrieving

This is only used if there are data structures that can't be represented by the standard things like numbers, characters or strings. Retrieval involves creating an entry pointer to the hash table with the proper associated keyname. If there is no such keyname, it will return NULL, which should be checked for. Then the structures need to be retrieved out of the table.

#### Function calling

Once the data structures are retrieved, the function can be called with all the necessary parameters.

#### Hash Table storing

If there is an output from the function that is a data structure that needs to be added to the hash table, you store it with a unique keyname. The keyname should be returned to the tcl interpreter, so it may be called again.

#### Converting function output to strings for Tcl

Since the Tcl interpreter always wants a string output, it is necessary to convert outputs to strings. For numbers, this just involves printing the number to a string. For enumerations, the options are to print the associated value, or create a function to return the proper name. For data structures, returning the keyname associated with the hash table is the proper representation.

#### Errors

For any case, where checks do not return the proper boolean, you should always try to output a string the the Tcl Interpreter describing the error.

#### Tcl Status

To properly exit the function, and to give Tcl notification of what kind of failure took place, you should return a Tcl flag. This should be usually TCL_OK or TCL_ERROR. I believe there are others.

Examples of Tcl glue code.

### Adding to it Tcl Interpreter

Adding functions to the library involves creating a main program which will be a new Tcl interpreter with your functions. Here's a rough coding of what should be there:

>     #include "tcl.h" /*This includes the Tcl libraries and Expect Libraries*/

>     ...other includes

>     Tcl_HashTable hash_table_name   /*Intializing hash tables*/

>     typedef struct{
>         char           *name;
>         Tcl_CmdProc    *proc;
>         ClientData     data;
>         int            flags;
>     } LibraryFunction;

>     static LibraryFunction www_commands[] = {
>         { "C_function_name", C_function_name_tcl,		   NULL, 0 },
>     	...other functions...
>         {0}
>     };

>     int main_Init(Tcl_Interp *interp) {
>         LibraryFunction *c;

>         /*Hash Table initialization*/
>         Tcl_InitHashTable(&Hash_Table_name, TCL_STRING_KEYS);
>         for(c = www_commands; c->name; c++){
>     	Tcl_CreateCommand(interp, c->name, c->proc, c->data,
>     			  NULL /* delete proc*/);
>         }
>     }

>     void main_Terminate() {
>         Tcl_DeleteHashTable(&Hash_Table_name);
>     }

What's important here is adding the function name to the www_commands[]. This adds your function to the tcl interpreter.

Standard Methods for variable input/output:

Boolean Input

    int boolean_var;
    char *boolean_string = argv[?];
    if (Tcl_GetBoolean(interp, boolean_string, &boolean_var)==TCL_OK) {
    ....body....
    }

Integer Input

int input;

    char *integer_string = argv[?];
    if (Tcl_GetInt(interp, integer_string, &input) == TCL_OK) {
    ....body....
    }

Boolean Output

    BOOL result = Somefunction(some_argument);
    Tcl_AppendResult(interp, result ? "YES" : "NO", NULL);

Setting a Variable passed in the parameters

In the cases where a pointer to a variable is passed in to a function, and the assignment must be passed out, use this function from Tcl.

    Tcl_SetVar(interp, tcl_var_name, char* newValue, int flags);