Example C interface

When querying the FEWS database with a small C program like the one below, the result is a string - in simple cases, just the value or values you wanted, in other cases the contents of an XML file, conforming to the FEWS published interface (PI).

The program below is a translation of most of the Java example. It simply prints the answer, but in an actual program you will need to parse the XML content to extract the relevant information:

/*
 * Sample program, using the wrappers
 */

#include <stdio.h>

/*
 * Wrapper code is included
 */
#include "pi_wrapper.c"

/* 
 * Main program
 */

int main( int argc, char *argv[] ) {

    char *result;
    char *stateTimes;
    char *firstTime;
    char *textContents;
    char *zipContents;
    FILE *outf;
    char *startTime;
    char *systemTime;
    char *endTime;
    char *timeZero;
    char *date;
    char *taskId;
    char *taskRunId;
    int   success;

    char *parameters[] = {"QIN", "RQIN"};
    char *locations[]  = {"DETO3", "GPRO3", "FOSO3"};
    int nParameters = 2;
    int nLocations = 3;

    /* Get the library started */
    Init( argv[0] );
    InitPiService( "localhost", 8100 );

    printf( "Current system time: %s\n", getSystemTime( "aa" ) );
    printf( "State times: %s\n", getAvailableStateTimes( "TestConfig", "RSNWELEV_DETO3I" ) );
    printf( "Cold states: %s\n", getColdStateIds( "TestConfig", "RSNWELEV_DETO3I" ) );

    result = getAvailableStateTimes( "TestConfig", "RSNWELEV_DETO3I" );
    stateTimes = strdup( result ) ; /* Save the result - we need it in the next step */

    /* This test is excluded: there is no binary state file in the sample configuration */
#if 0
    /* Extract the first time */

    firstTime = getElement( stateTimes, 0 );
    zipContents = getModuleStateBinary( "TestConfig", "SNOW17_LSMO3U", NULL, -1, &size );

    outf = fopen( "statefile.bin", "wb" );
    fwrite( zipContents, size, outf );
    fclose( outf );

    free( zipContents );
#endif

    /* Note: name of file, extension of file */
    textContents = getClientConfigFile( "MyClientConfigFile", "txt" );
    outf = fopen( "client.txt", "w" );
    fprintf( outf, "%s", textContents );
    fclose( outf );

    printf( "Locations:\n---begin---\n" );
    printf( "%s", getLocations( "aa" ) );
    printf( "---end---\n" );

    printf( "Ensemble members: %s\n", getEnsembleMemberIndices( "aa", "ESP" ) );

    printf( "Log message: %s\n", getLogMessages( "aa", "NWSNWMC00:0000026" ) );

    /* Use pre-formatted strings for these test programs */
    startTime = "2009-04-01T00:00:00+00:00";
    endTime   = "2009-04-11T00:00:00+00:00";

    systemTime = getSystemTime( "aa" );

#define TRUE  1
#define FALSE 0

    printf( "Timeseries:\n---begin---\n" );
    printf( "%s", getTimeSeries( "TestConfig", "Reservoir", NULL,
                      startTime, systemTime, endTime,
                      parameters, nParameters, locations, nLocations,
                      NULL, -1, FALSE ) );
    printf( "---end---\n" );

    /*
     * Running a task ...
     */
    printf( "Running Santiam_Forecast ...\n" );

    taskId = createTask( "aa" );
    date   = getSystemTime( "aa" );

    taskRunId = runTask( "aa", taskId, "Santiam_Forecast", date, date, date, NULL, NULL,
                    "Test user", "PiWebservice taskrun" );

    success = waitForTask( "aa", taskRunId, 120000); /* Wait for 120 seconds = 120000 ms */

    printf( "%s\n", (success? "OK!" : "Problem!") );

    TearDown();
}

Some notes

The program in the attachment uses several external libraries to take care of the actual connection. These libraries are: the Tcl library (version 8.4 or 8.5 should do) and the TclSOAP extension. More on this below.

As for the C interface itself:

  • Not all the services documented on the Wiki work for the sample configuration, as a local data store is not provided. This means that not all services could be tested, but the main ones can be.
  • The C example produces the same output as the Tcl example, but there is a caveat when using the C interface: most wrapper functions return a pointer to the Tcl result. Upon the next call to one of these wrapper functions, this pointer will be either invalidated ("dangling pointer") or the contents of the memory it points to is changed. A solution would be to make a duplicate of the return value (see getModuleStateBinary() for instance), but that puts the responsibility of cleaning up at the user's side.
  • Several C functions have extra arguments: getTimeSeries() takes two lists of IDs, the length of these lists is stored in an extra argument. For returning the zipped contents of a module state file, I have also introduced an extra argument (C's strings are terminated with a null byte, unless you use some count).
  • For convenience I have written a function that extracts an element from a space-separated list of words etc. This function contains a memory leak, but that should not present a big problem.

To link the program using the gcc compiler, use:

gcc -o example example.c -I. -ltcl84

Code

The C code for the wrapper functions and a Tcl example are available via the attachments.

More on the Tcl libraries

The Tcl library and the TclSOAP extension can be downloaded from ActiveState (http://www.activestate.com).
The TclSOAP extension uses the TclDOM 2.6 extension and Tcllib. All of these are available as open source.

  • No labels