NXDICT - finally

Mark.Koennecke at psi.ch Mark.Koennecke at psi.ch
Fri Oct 3 15:56:27 BST 1997


   High there,

   below is the first beta release of the NXDICT-API. Some things have changed
   from the first ideas. See the enclosed docs for details. The stuff
   consists of several files, which are collected into a shell-archive. 
   Somebody might join it into the central tar file.

					Mark 


/------------------------------ Cut here -----------------------------------\
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile.nxdict
#	  README.nxdict
#	  defines.h
#	  dict.c
#	  lld.c
#	  lld.h
#	  nxdict.c
#	  nxdict.h
#	  nxdict.tex
#	  nxdict.w
#	  nxdictus.tex
#	  stringdict.c
#	  stringdict.h
#	  stringdict.w
#	  test.dict
#
echo "x - extracting Makefile.nxdict (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile.nxdict &&
X#--------------------------------------------------------------------------
X# Makefile for the test program for NXDICT
X# copyleft: Mark Koennecke, August 1997
X#------------------------------------------------------------------------ 
X
XOBJ= napi.o nxdict.o dict.o stringdict.o lld.o
X
X
XCFLAGS= -I/data/koenneck/include -I. -g -c
XLFLAG=  -L/data/koenneck/lib \
X       -lmfhdf -ldf -ljpeg -lz -lm -lc
X.c.o:
X	cc $(CFLAGS) $*.c
X
X
Xdict: $(OBJ) 
X	cc -g -non_shared -o dict $(OBJ) $(LFLAG)
X
Xclean:
X	rm *.o
X	rm dict
SHAR_EOF
chmod 0664 Makefile.nxdict || echo "restore of Makefile.nxdict fails"
echo "x - extracting README.nxdict (Text)"
sed 's/^X//' << 'SHAR_EOF' > README.nxdict &&
X
X     High,
X
X     these are the files for the nxdict-API. You need:
X     - nxdict.*     : nuweb sources, .c and .h files for the API itself.
X     - stringdict.* : a list based string dictionary used for implementing
X                      nxdict.
X     - lld.*        : a PD linked list package from somebody else. All
X                      credits to A. Reitsma, Delft.
X     - dict.c       : a test/ example program.
X     - test.dict    : a test dictionary.
X     - nxdictus.tex : API user documentation, derived from nxdict.tex,
X                      which is the full doc including implementation
X                      details.
X     - Makefile.nxdict : a DigitalUnix Makefile for nxdict.
X
X     Of course you need the napi-files.
X
X     At the time of writing (October,3, 1997) a tiny change in napi.c is
X     necessary to make this work:
X
X     line 82 of napi.c:
X       remove the keyword static from the definitons of NXpData and
X       NXIReportError. This is necessary as NXDICT uses the same error
X       reporting mechanism as the napi itself.
X
X     Consider this early beta. It works for me, though.
X
X     I somebody cares to debug my code or improve on my english, 
X     please edit nxdict.w. 
X
X				Mark Koennecke
X
X				Mark.Koennecke at psi.ch
X 
SHAR_EOF
chmod 0664 README.nxdict || echo "restore of README.nxdict fails"
echo "x - extracting defines.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > defines.h &&
X/*  ======================================================================
X    DEFINES.h       Standard definitions etc.
X                    For simplification or for debugging substitution.
X
X                    v1.02  94-08-11  Stripped version.
X
X _____              This version is Public Domain.
X /_|__|             A.Reitsma, Delft, Nederland.
X/  | \  --------------------------------------------------------------- */
X
X#include <stdlib.h>         /* for malloc() prototype */
X#include <string.h>         /* for memcpy() prototype */
X
X#define MALLOC(size,type)   (type *) malloc( (size) * sizeof( type ))
X#define FREE(mem)           free( mem )
X#define CALLOC(size,type)   (type *) calloc( (size), sizeof( type))
X
X/*  === DEFINES.h end ================================================= */
SHAR_EOF
chmod 0644 defines.h || echo "restore of defines.h fails"
echo "x - extracting dict.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dict.c &&
X
X/*--------------------------------------------------------------------------
X                               D I C T 
X
X This file exercises some of the NXDICT functionality for test purposes.
X It can also serve as an example for the usage of the API.
X
X Mark Koennecke, August 1997
X  
X----------------------------------------------------------------------------*/
X#include <stdlib.h>
X#include <stdio.h>
X#include <assert.h>
X#include <mfhdf.h>
X#include "napi.h"
X#include "nxdict.h"
X
X   int main(int argc, char *argv[])
X   {
X      NXdict pDict = NULL;
X      NXhandle hfil;
X      void *pData = NULL;
X      float fTina[3] = { 0.123, 0.234, 0.456};
X      float fTest[3], fDelta;
X      float fTust[20*20];
X      char pBuffer[132];
X      int i;
X
X      /* test nxdict */
X      NXDinitfromfile("test.dict",&pDict);
X      NXopen("test.hdf",NXACC_CREATE,&hfil);
X      NXDadd(pDict,"Gundula",
X            "/entry1,NXentry/SphereOmeter,NXinstrument/SDS");
X      NXDupdate(pDict,"Bea","/entry1,NXentry/SDS");
X      NXDget(pDict,"Bea",pBuffer,131);
X      printf("Bea = %s\n",pBuffer);
X      NXDget(pDict,"Linda",pBuffer,131);
X      NXDopendef(hfil,pDict,pBuffer);
X      NXDputalias(hfil,pDict,"Tina",fTina);
X      NXDgetalias(hfil,pDict,"Tina",fTest);
X      NXDputalias(hfil,pDict,"Linda",fTust);
X      NXDaliaslink(hfil,pDict,"Eva","Linda");
X      NXDclose(pDict,"close.dict");
X      NXclose(&hfil);
X      printf("NXDICT seemed to have worked \n");
X
X      /* test Utility functions */
X      printf(" Proceeding to test of utility functions \n");
X      NXopen("test2.hdf",NXACC_CREATE,&hfil);
X      NXUwriteglobals(hfil,
X                      "test2.hdf",
X                      "Willibald Wuergehals",
X                      "Rue des Martyrs, 26505 Timbuktu, Legoland ",
X                      "+41-56-3102512",
X                      "Nobody at nowhere.edu",
X                      " 755-898767",
X                      "Dingsbums");
X      NXUentergroup(hfil, "TestGroup", "NXtest");
X      NXclosegroup(hfil);
X      NXUentergroup(hfil, "TestGroup", "NXtest");
X
X      i = 120;
X      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
X      NXclosedata(hfil);
X      NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
X
X      NXUallocSDS(hfil,&pData);
X      NXUfreeSDS(&pData);
X      NXclose(&hfil);
X      printf("All tests seem to have worked OK,  %s %s\n",
X             "but the test is pathetic\n", 
X             "Do not rely, in any circumstances, on this test alone");
X
X 
X   }
SHAR_EOF
chmod 0664 dict.c || echo "restore of dict.c fails"
echo "x - extracting lld.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > lld.c &&
X/* =======================================================================
X    LLD.c           Generic Doubly Linked Lists for fixed size data.
X                    Each List has its own specific data size.
X                    This version uses dummy head and dummy tail nodes.
X                    Which prevents special handling for the first and last
X                    nodes.
X
X                    v1.00  94-08-21
X
X                    Compile with NDEBUG not defined for debugging version.
X                    Compile with NDEBUG defined for production version.
X
X                    The node pointers are restricted to valid values.
X                    They point only in empty lists to invalid data.
X
X                    Possible future enhancements:
X                    - List(s) of free nodes for fast node memory alloc.
X                    - FindFirst() & FindNext().
X                    - Data access via first and/or last node pointers.
X                      (duplicate the functions and change .current to
X                      .first or .last)
X                    - Node deletion via first and/or last node pointers.
X                      (as for access functions, then simplify ...)
X
X _____              This version is Public Domain.
X /_|__|             A.Reitsma, Delft, The Netherlands.
X/  | \  --------------------------------------------------------------- */
X
X#include <stdarg.h>         /* variable arg handling */
X#include <assert.h>         /* debugging */
X#include "defines.h"        /* debugging incl MALLOC (re-) definition   */
X#include "lld.h"            /* also includes portable.h if necessary    */
X
X#define NO_PROBLEMS LIST_NO_PROBLEMS /* local redefinition */
X
Xstruct Node
X{
X    struct Node * next;
X    struct Node * prev;
X    int data;               /* also place-holder for larger items.      */
X};                          /* actual nodes have various sizes,         */
X                            /* but a fixed size within a list.          */
Xstruct ListHead
X{
X    struct Node * current;  /* points to the actual current node        */
X    struct Node * first;    /* always points to dummy head node         */
X    struct Node * last;     /* always points to dummy tail node         */
X    int itemsize ;          /* zero value: used as 'list not used' flag */
X};
X
X#define ERR_MEMORY          -1
X
X#define NODE_MALLOC(list)   (struct Node *) \
X                            MALLOC( ListControl[ list ].itemsize \
X                                    + 2 * sizeof( struct Node * )\
X                                    + sizeof(int), char )
X
X#define NODE_FREE(node)     FREE(node)
X
X/* ---- Local data ---------------------------------------------------- */
X
Xstatic struct ListHead * ListControl = NULL;
Xstatic unsigned int ListCount = 0;
X
X/* ---- LL system mangement ------------------------------------------- */
X
Xstatic int ListInit( int List, int ItemSize )
X{
X    struct Node * Tmp ;
X
X    if( 0 != ItemSize )
X    {
X        /* create dummy head node
X        */
X        Tmp = NODE_MALLOC( List );
X        if( NULL == Tmp )
X        {
X            return ERR_MEMORY ;
X        }
X        Tmp->prev = NULL ;     /* NULL identifies it as dummy head node */
X        Tmp->data = 0xA709 ;   /* dummy value */
X        ListControl[ List ].first = Tmp ;
X
X        /* create dummy tail node
X        */
X        Tmp = NODE_MALLOC( List );
X        if( NULL == Tmp )
X        {
X            NODE_FREE( Tmp );          /* no need to cause memory leaks */
X            ListControl[ List ].first = NULL ; /* or other errors       */
X            return ERR_MEMORY ;        /* even if we're in trouble ...  */
X        }
X        Tmp->next = NULL ;     /* NULL identifies it as dummy tail node */
X        Tmp->data = 0xA725 ;   /* dummy value */
X        Tmp->prev = ListControl[ List ].first ;
X
X        ListControl[ List ].current     =
X        ListControl[ List ].last        =
X        ListControl[ List ].first->next = Tmp ;
X    }
X    else
X    {
X        ListControl[ List ].current =
X        ListControl[ List ].first   =
X        ListControl[ List ].last    = NULL ;
X    }
X
X    ListControl[ List ].itemsize = ItemSize ; /* zero: list not used    */
X    return NO_PROBLEMS ;
X}
X
Xint LLDsystemInit( int ListCountInit )
X{
X    assert( (unsigned) ( ListCountInit -1 ) <= 20 -1 );
X                 /* negative is logic error (cast => neg. is large int) */
X                 /* higher than 20 is ridiculous for an initial setup   */
X                 /* zero is useless                                     */
X
X    if( NULL != ListControl )
X    {
X        return NO_PROBLEMS ; /* LL system already initialized */
X    }
X
X    ListControl = MALLOC( ListCountInit, struct ListHead );
X    if( NULL == ListControl )
X    {
X        return ERR_MEMORY ;
X    }
X    /* MK */
X    memset(ListControl,0,ListCountInit*sizeof(struct ListHead));
X
X    for( ListCount = 0 ; ListCount < (unsigned)ListCountInit ; ListCount++ )
X        ListInit( ListCount, 0 ); /* just mark it as usable ... */
X
X    /* ListCount is now ListCountInit */
X    assert( ListCount == (unsigned)ListCountInit );
X
X    return NO_PROBLEMS;
X}
X
Xint LLDsystemClose(void)
X{
X  if(ListControl)
X  {
X    free(ListControl);
X  }
X  ListControl = NULL;
X  return 1;
X}
Xint LLDcreate( int ItemSize )
X{
X    int List ;
X
X    assert( (unsigned) ( ItemSize -1 ) < 1024 -1 ) ;
X                             /* limit to 1kB. A size of 0 is ridiculous */
X
X    /* trigger automatic system initialisation if neccesary
X    */
X    if( NULL == ListControl  &&  0 != LLDsystemInit( 1 ))
X    {
X        return ERR_MEMORY ;
X    }
X
X    /* Look for empty slot
X    */
X    for( List = 0; List < (int)ListCount; List++ )
X    {
X        if( 0 == ListControl[ List ].itemsize )
X            break;
X    }
X
X    /*  What if NO EMPTY slot ???
X    */
X    if( List == (int)ListCount )
X    {
X        struct ListHead * tmp ;         /* ListControl expansion needed */
X
X        tmp = MALLOC( ListCount + 1, struct ListHead );
X        if( NULL == tmp )
X        {
X            return ERR_MEMORY ;
X        }
X        /* MK */
X        memset(tmp,0,(ListCount+1)*sizeof(struct ListHead));
X        
X        memcpy( tmp, ListControl, ListCount * sizeof( struct ListHead ));
X        /* MK */
X        free(ListControl);
X        ListControl = tmp ;
X        ListCount++ ;
X    }
X
X    /* create dummy head node and set up ListControl for the list.
X    */
X    if( ERR_MEMORY == ListInit( List, ItemSize ))
X    {
X        return ERR_MEMORY ;
X    }
X
X    return List ;
X}
X
Xvoid LLDdelete( int List )
X{
X    struct Node * Tmp ;
X    struct Node * Old ;
X
X    assert( (unsigned) List < ListCount );
X
X    Tmp = ListControl[ List ].first ; /* dummies are also deleted !!!   */
X    while( NULL != Tmp )              /* still assuming last node has   */
X    {                                 /* a NULL next pointer ...        */
X        Old = Tmp ;
X        Tmp = Old->next;
X        NODE_FREE( Old ); /* data already presumed to be deleted */
X    }
X
X    ListInit( List, 0 ); /* 0: mark list as not used. */
X
X    return ;
X}
X
X/* ---- LL system maintenance ----------------------------------------- */
X
Xint LLDcheck( int List )
X{
X    if( NULL == ListControl )
X    {
X        return LIST_SYSTEM_NULL ;
X    }
X
X    if( (unsigned) List >= ListCount )
X    {
X        return LIST_INV_NUMBER ;
X    }
X
X    if( 0 == ListControl[ List ].itemsize )
X    {
X        return LIST_NOT_CREATED ;
X    }
X
X    if( NULL == ListControl[ List ].first
X        || NULL == ListControl[ List ].first->next    /* missing tail ? */
X        || NULL != ListControl[ List ].first->prev )
X    {
X        return LIST_ERR_HEAD ;
X    }
X
X    /* Validate current pointer
X    */
X    if( NULL == ListControl[ List ].current )
X    {
X        return LIST_CORRUPT7 ;    /* shouldn't be NULL with a good head */
X    }
X
X    if( NULL != ListControl[ List ].first->next->next ) /* empty list ? */
X    {                                                   /* not empty.   */
X        struct Node * tmp = ListControl[ List ].first ;
X
X        if( NULL == ListControl[ List ].current->next )
X        {
X            return LIST_CORRUPT6 ; /* a NULL next pointer is only valid */
X        }                          /* for an empty list.                */
X
X        /* look for .current in list,
X           checking the .prev links along the way
X        */
X        do
X        {
X            tmp = tmp->next ;
X
X            if( NULL == tmp || NULL == tmp->prev
X                || tmp != tmp->prev->next )
X            {
X                return LIST_CORRUPT5 ;  /* current not found in list */
X            }                           /* or link to/from next node */
X                                        /* invalid                   */
X        }while( tmp != ListControl[ List ].current );
X
X        /* Found .current in list. Also without link errors.
X           Now look for valid last node pointer in the list,
X           checking the .prev links along the way
X           Note that .current itself is never supposed to be equal
X           to .last (which points to the dummy tail) !
X        */
X        if( NULL == ListControl[ List ].last )
X        {
X            return LIST_ERR_LAST ;
X        }
X
X        do
X        {
X            tmp = tmp->next ;
X            if( NULL == tmp || NULL == tmp->prev
X                || tmp != tmp->prev->next )
X            {
X                return LIST_CORRUPT4 ;  /* last not found in list    */
X            }                           /* or link to/from prev node */
X                                        /* invalid                   */
X        }while( tmp != ListControl[ List ].last );
X
X        /* Found .last in list but is it really a valid last pointer?
X           Note: tmp == .last
X        */
X        if( NULL != tmp->next )
X        {
X            return LIST_CORRUPT3 ;
X        }
X
X        return NO_PROBLEMS ;
X    }
X
X    /* .first->next->next == NULL  =>  list is empty
X    */
X    if( ListControl[ List ].current != ListControl[ List ].first->next )
X    {
X        return LIST_CORRUPT2 ;
X    }
X
X    if( ListControl[ List ].last != ListControl[ List ].first->next
X        || ListControl[ List ].last
X                             != ListControl[ List ].current->prev->next )
X    {
X        return LIST_CORRUPT1 ;
X    }
X
X    return LIST_EMPTY ;
X}
X
X/* ---- node management ----------------------------------------------- */
X
Xint LLDnodeInsert( int List, ... )      /* insert _BEFORE_ current node */
X{
X    va_list DataPtr ;
X    int Retval ;
X
X    /* set DataPtr to the address of "..."
X       then action, cleanup and return.
X    */
X    va_start( DataPtr, List );
X
X    Retval = LLDnodeInsertFrom( List, (void *)va_arg(DataPtr,void *) );
X
X    va_end( DataPtr );
X    return Retval ;
X}
X
Xint LLDnodeAdd( int List, ... )          /* insert _AFTER_ current node */
X{
X    va_list DataPtr ;
X    int Retval ;
X
X    /* set DataPtr to the address of "..."
X       then action, cleanup and return.
X    */
X    va_start( DataPtr, List );
X
X    Retval = LLDnodeAddFrom( List, (void *)va_arg(DataPtr,void *) );
X
X    va_end( DataPtr );
X    return Retval ;
X}
X
Xint LLDnodePrepend( int List, ... )             /* insert as first node */
X{
X    va_list DataPtr ;
X    int Retval ;
X
X    /* set DataPtr to the address of "..."
X       then action, cleanup and return.
X    */
X    va_start( DataPtr, List );
X
X    Retval = LLDnodePrependFrom( List, (void *)va_arg(DataPtr,void *) );
X
X    va_end( DataPtr );
X    return Retval ;
X}
X
Xint LLDnodeAppend( int List, ... )               /* insert as last node */
X{
X    va_list DataPtr ;
X    int Retval ;
X
X    /* set DataPtr to the address of "..."
X       then action, cleanup and return.
X    */
X    va_start( DataPtr, List );
X
X    Retval = LLDnodeAppendFrom( List, (void *)va_arg(DataPtr,void *) );
X
X    va_end( DataPtr );
X    return Retval ;
X}
X
Xint LLDnodeInsertFrom( int List, void * Source )
X{                                       /* insert _BEFORE_ current node */
X    struct Node * New ;
X
X    assert( (unsigned) List < ListCount );
X
X    /* create new node if possible
X    */
X    New = NODE_MALLOC( List );
X    if( NULL == New )
X    {
X        return ERR_MEMORY ;
X    }
X
X    /* fill node with data, link to next and previous nodes
X       and adjust current node pointer
X    */
X    memcpy( & New->data, Source, ListControl[ List ].itemsize );
X    New->next = ListControl[ List ].current;
X    New->prev = ListControl[ List ].current->prev;
X
X    ListControl[ List ].current->prev = New ;
X    New->prev->next = New ;
X
X    ListControl[ List ].current = New ;
X
X    return NO_PROBLEMS;
X}
X
Xint LLDnodeAddFrom( int List, void * Source )
X{                                        /* insert _AFTER_ current node */
X    struct Node * New ;
X
X    assert( (unsigned) List < ListCount );
X
X    /* create new node if possible
X    */
X    New = NODE_MALLOC( List );
X    if( NULL == New )
X    {
X        return ERR_MEMORY ;
X    }
X
X    /* fill node with data and link to next and previous nodes
X       with special handling when the current node pointer points
X       to the dummy tail node: i.e it is an empty list.
X       (the same case in a non-empty list is made not to occur.)
X    */
X    memcpy( & New->data, Source, ListControl[ List ].itemsize );
X
X    if( NULL != ListControl[ List ].current->next )
X        ListControl[ List ].current = ListControl[ List ].current->next ;
X
X    New->next = ListControl[ List ].current;
X    New->prev = ListControl[ List ].current->prev;
X
X    ListControl[ List ].current->prev = New ;
X    New->prev->next = New ;
X
X    ListControl[ List ].current = New ;
X
X    return NO_PROBLEMS;
X}
X
Xint LLDnodePrependFrom( int List, void * Source )
X{                                               /* insert as first node */
X    struct Node * New ;
X
X    assert( (unsigned) List < ListCount );
X
X    /* create new node if possible
X    */
X    New = NODE_MALLOC( List );
X    if( NULL == New )
X    {
X        return ERR_MEMORY ;
X    }
X
X    /* fill node with data and link to dummy head and actual first nodes
X    */
X    memcpy( & New->data, Source, ListControl[ List ].itemsize );
X    New->prev = ListControl[ List ].first;     /* == .first->next->prev */
X    New->next = ListControl[ List ].first->next;
X
X    ListControl[ List ].first->next = New;
X    New->next->prev = New ;
X
X    /* Prevent .current from pointing at the dummy tail
X       (New is the only normal node...)
X    */
X    if( NULL == ListControl[ List ].current->next )
X        ListControl[ List ].current = New;
X
X    return NO_PROBLEMS;
X}
X
Xint LLDnodeAppendFrom( int List, void * Source )
X{                                                /* insert as last node */
X    struct Node * New ;
X
X    assert( (unsigned) List < ListCount );
X
X    /* create new node if possible
X    */
X    New = NODE_MALLOC( List );
X    if( NULL == New )
X    {
X        return ERR_MEMORY ;
X    }
X
X    /* fill node with data and link to dummy tail and actual last nodes
X    */
X    memcpy( & New->data, Source, ListControl[ List ].itemsize );
X    New->next = ListControl[ List ].last ;      /* == .last->prev->next */
X    New->prev = ListControl[ List ].last->prev;
X
X    ListControl[ List ].last->prev = New ;
X    New->prev->next = New ;
X
X    /* Prevent .current from pointing at the dummy tail
X       (New is the only normal node...)
X    */
X    if( NULL == ListControl[ List ].current->next )
X        ListControl[ List ].current = New;
X
X    return NO_PROBLEMS;
X}
X
Xvoid LLDnodeDelete( int List )
X{
X    struct Node * Old = ListControl[ List ].current ;
X
X    assert( (unsigned) List < ListCount );
X
X    if( NULL == ListControl[ List ].current->next )
X    {
X        return ;  /* don't delete dummy tail node (list is empty) */
X    }
X
X    /* adjust links
X    */
X    Old->prev->next = Old->next ;
X    Old->next->prev = Old->prev ;
X
X    /* adjust current node pointer
X       prevent it from pointing to the dummy tail node
X    */
X    if( NULL != Old->next->next )
X        ListControl[ List ].current = Old->next ;
X    else
X        ListControl[ List ].current = Old->prev ;
X
X    NODE_FREE( Old );
X
X    return ;
X}
X
Xint LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr )
X{                        /* FindFirst/FindNext format may be needed ... */
X    int RetVal ;
X
X    assert( (unsigned) List < ListCount );
X
X    if( NULL == ListControl[ List ].first->next->next ) /* empty list ? */
X    {
X        return 2; /* a compare usually returns just -1, 0 or 1 !!! */
X    }
X
X    /* note: current->next will never be NULL in a non-empty list */
X
X    if( NULL == Compare ) /* default to memcmp with .itemsize */
X    {
X        while( 0 != (RetVal = memcmp( DataPtr,
X                                      & ListControl[ List ].current->data,
X                                      ListControl[ List ].itemsize ))
X               && NULL != ListControl[ List ].current->next->next )
X        {
X            ListControl[ List ].current=ListControl[ List ].current->next;
X        }
X        return RetVal ;
X    }
X    else
X    {
X        while( 0 != (RetVal = (*Compare)( DataPtr,
X                                   & ListControl[ List ].current->data ))
X               && NULL != ListControl[ List ].current->next->next )
X        {
X            ListControl[ List ].current=ListControl[ List ].current->next;
X        }
X        return RetVal ;
X    }
X}
X
X/* ---- current node pointer management ------------------------------- */
X
Xint  LLDnodePtr2First( int List )
X{
X    assert( (unsigned) List < ListCount );
X
X    ListControl[ List ].current = ListControl[ List ].first->next ;
X
X    return NULL != ListControl[ List ].first->next->next ;
X}
X
Xint  LLDnodePtr2Last( int List )
X{
X    assert( (unsigned) List < ListCount );
X
X    ListControl[ List ].current = ListControl[ List ].last->prev ;
X
X    return NULL != ListControl[ List ].last->prev->prev ;
X}
X
Xint  LLDnodePtr2Next( int List )
X{
X    assert( (unsigned) List < ListCount );
X
X    if( NULL == ListControl[ List ].current->next       /* empty list ? */
X        || NULL == ListControl[ List ].current->next->next ) /* at end ?*/
X    {
X        return 0 ;             /* do not allow the current node pointer */
X    }                          /* to point at the dummy tail node ...   */
X
X    ListControl[ List ].current = ListControl[ List ].current->next ;
X    return 1 ;
X}
X
Xint  LLDnodePtr2Prev( int List )
X{
X    assert( (unsigned) List < ListCount );
X
X    if( NULL == ListControl[ List ].current->prev       /* empty list ? */
X        || NULL == ListControl[ List ].current->prev->prev ) /* begin ? */
X    {
X        return 0 ;             /* do not allow the current node pointer */
X    }                          /* to point at the dummy head node ...   */
X
X    ListControl[ List ].current = ListControl[ List ].current->prev ;
X    return 1 ;
X}
X
X/* ---- stored data management ---------------------------------------- */
X
Xint LLDnodeInt( int List )
X{
X    return ListControl[ List ].current->data;
X}
X
Xlong LLDnodeLong( int List )
X{
X    return *((long *) &ListControl[ List ].current->data );
X}
X
Xvoid * LLDnodePtr( int List )
X{
X    return *((void **) &ListControl[ List ].current->data );
X}
X
Xvoid FAR * LLDnodeFptr( int List )
X{
X    return *((void FAR **) &ListControl[ List ].current->data );
X}
X
Xint LLDnodeDataTo( int List, void * Destination )
X{
X    if( NULL != Destination )
X    {
X        memcpy( Destination,
X                & ListControl[ List ].current->data,
X                ListControl[ List ].itemsize );
X    }
X
X    return ListControl[ List ].itemsize ;       /* size needed for blob */
X}
X
X/* added: Mark Koennecke, 7.4.1997 */
Xint LLDnodeDataFrom( int List, void *source )
X{
X    if( NULL != source )
X    {
X        memcpy(
X                & ListControl[ List ].current->data,
X                source,
X                ListControl[ List ].itemsize );
X    }
X
X    return ListControl[ List ].itemsize ;       /* size needed for blob */
X}
X
X/* ==== LLD.c  end ==================================================== */
SHAR_EOF
chmod 0644 lld.c || echo "restore of lld.c fails"
echo "x - extracting lld.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > lld.h &&
X/* =======================================================================
X    LLD.h           Generic Doubly Linked List for fixed size data-items.
X
X                    v1.00  94-08-21
X
X _____              This version is Public Domain.
X /_|__|             A.Reitsma, Delft, The Netherlands.
X/  | \  --------------------------------------------------------------- */
X
X#include "defines.h"
X
X#ifndef FAR
X#define FAR
X#endif
X
X#ifndef LL__ERR_H
X#define LL__ERR_H       /* same values used in LLS ...                  */
X
Xenum ListErrors         /* return values for LLDcheck()                 */
X{                       /* The highest value is returned                */
X
X    LIST_NO_PROBLEMS,   /* All is OK (multiple use)                     */
X    LIST_EMPTY,         /* No data available                            */
X    LIST_ERRORS,        /* Dummy to separate warnings from              */
X                        /* ---- REAL errors --------------------------- */
X    LIST_CORRUPT1,      /* invalid last node pointer: != first->next    */
X                        /*      (empty list) or link error              */
X    LIST_CORRUPT2,      /* invalid current node pointer: != first->next */
X                        /*      (empty list)                            */
X    LIST_CORRUPT3,      /* invalid last node pointer: Not really last.  */
X    LIST_CORRUPT4,      /* invalid last node pointer: Not in list,      */
X                        /*      or link error after current node        */
X    LIST_ERR_LAST,      /* invalid last node pointer: NULL              */
X    LIST_CORRUPT5,      /* invalid current node pointer: Not in list,   */
X                        /*      or link error before current node       */
X    LIST_CORRUPT6,      /* invalid current->next node pointer: NULL     */
X                        /*      although the list is not empty          */
X    LIST_CORRUPT7,      /* NULL current node pointer                    */
X    LIST_ERR_HEAD,      /* NULL first node pointer                      */
X                        /*      or error in head node                   */
X    LIST_NOT_CREATED,   /* List deleted or not created                  */
X    LIST_INV_NUMBER,    /* List number out of range                     */
X    LIST_SYSTEM_NULL    /* List system not intialized                   */
X};
X
Xtypedef int (*CompFunPtr)( const void *, const void * );
X                                             /* simplifies declarations */
X#endif
X#ifndef LLD_H
X#define LLD_H
X
X/* ---- LL system management and maintenance -------------------------- */
Xint  LLDsystemInit( int ListCount );
X               /* returns -1 on failure. It is not required to call it. */
X               /* A second call does nothing: ListCount is ignored.     */
X
Xint  LLDcreate( int ItemSize );
X                        /* returns list number to use or -1 on failure. */
X                        /* MUST be called before using a list.          */
X                        /* Calls LLsystemInit if necessary.             */
X
Xvoid LLDdelete( int List ); /* delete entire list, data is NOT free()'d */
X
Xint  LLDcheck( int List ); /* returns enum ListErrors value             */
X                           /* its primary purpose is debugging.         */
X
Xint LLDsystemClose(void);
X         /* MK mainly frees memory for the ListControlBlocks */
X/* ---- Node management --------------------------------------------------
X   Functions changing current node pointer to the new node.
X   Each created list has its own -- fixed -- datasize. See LLcreate().
X   An ellipsis "..." indicates the data to insert.
X*/
Xint  LLDnodeInsert( int List, ... );      /* insert BEFORE current node */
Xint  LLDnodeAdd( int List, ... );         /* insert AFTER current node  */
X         /* a return value of -1 indicates a memory allocation problem. */
X
X/* Functions NOT changing the current node pointer.
X   Especially intended for implementation of Queue's and Stacks.
X*/
Xint  LLDnodePrepend( int List, ... );           /* insert as first node */
Xint  LLDnodeAppend( int List, ... );            /* insert as last node  */
X         /* a return value of -1 indicates a memory allocation problem. */
X
X/* The following four functions are essentially the same as the preceeding
X   four. The data is however not passed by value but by reference.
X*/
Xint  LLDnodeInsertFrom( int List, void * Source );
Xint  LLDnodeAddFrom( int List, void * Source );
Xint  LLDnodePrependFrom( int List, void * Source );
Xint  LLDnodeAppendFrom( int List, void * Source );
X
Xvoid LLDnodeDelete( int List );                  /* remove current node */
X        /* current node ptr moved to next node. UNLESS the deleted node */
X        /* was the last node: then current ptr moved to previous node   */
X
Xint  LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr );
X        /* Find *DataPtr in the List using the *Compare function.       */
X        /* Returns the return value of *Compare. 0 == equal == found.   */
X        /* non-zero == not found. Current node is set to found node.    */
X        /* Returns 2 for an empty list.                                 */
X        /* First checked node is current node.                          */
X        /* A NULL Compare-function defaults to the use of memcmp() with */
X        /* the list's itemsize as third (size) parameter.               */
X        /* simple implementation. FindFirst and FindNext may be needed. */
X
X/* ---- current node pointer management ----------------------------------
X   These functions change the current node pointer and return 1 when there
X   was a change. A return of 0 indicates trying to move past the begin or
X   the end of the list, or an empty list. The return value is intended for
X   iteration purposes. I.e. stopping a scan through a list.
X*/
Xint  LLDnodePtr2First( int List );
Xint  LLDnodePtr2Last( int List );
Xint  LLDnodePtr2Next( int List );
Xint  LLDnodePtr2Prev( int List );
X
X/* ---- stored data management -------------------------------------------
X   return typed data:
X*/
Xint  LLDnodeInt( int List );
Xlong LLDnodeLong( int List );
Xvoid * LLDnodePtr( int List );
Xvoid FAR * LLDnodeFptr( int List );
X
X/* 'return' typeless data. The return value is the size of the data.
X   The data is transferred to Destination.
X   If 'Destination' is NULL, the only action is returning the size.
X*/
Xint LLDnodeDataTo( int List, void * Destination );
X
X/*
X  replaces typeless data with source 
X*/
Xint LLDnodeDataFrom(int List, void *source);
X#endif
X/* ==== LLD.h  end ==================================================== */
SHAR_EOF
chmod 0644 lld.h || echo "restore of lld.h fails"
echo "x - extracting nxdict.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > nxdict.c &&
X
X#line 2079 "nxdict.w"
X
X/*---------------------------------------------------------------------------
X                 Nexus Dictionary API implementation file.
X
X  For documentation see the nxdict.tex file which comes with this 
X  distribution.
X
X  copyleft: Mark Koennecke
X            Labor fuer Neutronenstreuung
X            Paul Scherrer Institut
X            CH-5232 Villigen-PSI
X            Switzerland
X            Mark.Koennecke at psi.ch
X
X  No warranties of any kind, whether explicit or implied, taken.
X  Distributed under the GNU copyleft license as documented elsewhere.
X
X  August, 1997
X
X  Version: 1.0
X-----------------------------------------------------------------------------*/
X
X#include <stdlib.h>
X#include <stdio.h>
X#include <assert.h>
X#include <string.h>
X#include <time.h>
X#include <mfhdf.h>
X#include "lld.h"
X#include "napi.h"
X#include "stringdict.h"
X#include "nxdict.h"
X/*------------------ The magic number used for pointer checking */
X#define NXDMAGIC 260558
X/*--------------------------------------------------------------------------
X      Things defined in napi.c for error reporting 
X---------------------------------------------------------------------------*/
X       extern void *NXpData;
X       extern void (*NXIReportError)(void *pData, char *pBuffer);  
X/*--------------------------------------------------------------------------*/
X
X#line 344 "nxdict.w"
X
X    typedef struct __NXdict
X                           {
X                               int iID;
X                               pStringDict pDictionary;
X                           } sNXdict;
X/*------------------ verbosity level -------------------------------------*/
X   static int iVerbosity = 0 ;
X
X#line 2119 "nxdict.w"
X
X/*-------------------------------------------------------------------------*/
X  static char *NXDIReadFile(FILE *fd)
X  {
X     char *pNew = NULL;
X     long lLength = 0;
X 
X     assert(fd); 
X
X     /* determine length of file */
X     fseek(fd,0L,SEEK_END);
X     lLength = ftell(fd);
X     if(lLength <= 0)
X     {
X        return NULL;
X     }
X     fseek(fd,0L,SEEK_SET);
X
X     /* allocate buffer */
X     lLength += 3;
X     pNew = (char *)malloc(lLength*sizeof(char));
X     if(!pNew)
X     {
X       return NULL;
X     }
X     memset(pNew,0,lLength); /* this ensures a 0 at the end */
X
X     /* read file */
X     fread(pNew,sizeof(char),lLength-3,fd);
X     
X     return pNew;
X  }
X/*--------------------------------------------------------------------------*/
X
X#line 472 "nxdict.w"
X
X#define FWORD 1
X#define FHASH 2
X#define FEOL  3
X#define FEOB  4
X#define FEQUAL 5
X#define FSLASH 6
X
X   static char *NXDIfNextToken(char *pPtr, char *pToken, int *iToken)
X   {
X       pToken[0] = '\0';
X       /* skip whitespace */
X       while( (*pPtr == ' ') || (*pPtr == '\t') )
X       {
X         pPtr++;
X       } 
X
X       /* check for special characters */
X       if(*pPtr == '#')
X       {
X         *iToken = FHASH;
X         pToken[0] = *pPtr;
X         pPtr++;
X         return pPtr;
X       }
X       else if(*pPtr == '\n')
X       {
X         *iToken = FEOL;
X         pToken[0] = *pPtr;
X         pPtr++;
X         return pPtr;
X       }
X       else if(*pPtr == '\0')
X       {
X         *iToken = FEOB;
X         pToken[0] = *pPtr;
X         pPtr++;
X         return pPtr;
X       }
X       else if(*pPtr == '=')
X       {
X         *iToken = FEQUAL;
X         pToken[0] = *pPtr;
X         pPtr++;
X         return pPtr;
X       }
X       else if(*pPtr == '\\')
X       {
X         *iToken = FSLASH;
X         pToken[0] = *pPtr;
X         pPtr++;
X         return pPtr;
X       }
X       else 
X       {
X         *iToken = FWORD;
X         /* copy word to pToken */
X         while( (*pPtr != ' ') && (*pPtr != '\t') && 
X                (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') )
X         {
X           *pToken = *pPtr;
X           pPtr++;
X           pToken++;
X         } 
X         *pToken = '\0';
X         return pPtr;
X       }
X      /* not reached */
X      return pPtr;
X   }
X    
X
X#line 2152 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 548 "nxdict.w"
X
X#define AMODE 0
X#define DMODE 1
X
X  static void  NXDIParse(char *pBuffer, pStringDict pDict)
X  {
X     char *pPtr;
X     int iToken;
X     int iMode;
X     char pAlias[132];
X     char pDefinition[1024]; /* this is > 10 lines of definition */
X     char pWord[132];
X
X     assert(pBuffer);
X     assert(pDict);
X
X     iMode = AMODE;
X     pPtr = pBuffer;
X     iToken = -1;
X     pDefinition[0] = '\0';
X     pAlias[0] = '\0';
X     pWord[0] = '\0';
X
X     while(iToken != FEOB)
X     {
X         pPtr = NXDIfNextToken(pPtr,pWord,&iToken);
X         switch(iToken)
X         {
X           case FHASH:
X           case FSLASH: /* skip over \n to next non blank */
X                       while(*pPtr != '\n')
X                       {
X                          pPtr++;
X                          /* check for end of file */
X                          if(*pPtr == '\0')
X                          {
X                            return;
X                          }
X                       }
X                       pPtr++;
X                       break;
X           case FEQUAL: /* do a mode change */
X                       iMode = DMODE;
X                       pDefinition[0] = '\0';
X                       break;
X
X           case FWORD:
X                       if(iMode == AMODE)
X                       {
X                         strcpy(pAlias,pWord);
X                       }  
X                       else
X                       {
X                         strcat(pDefinition,pWord);
X                         strcat(pDefinition," ");
X                       }
X                       break;
X           case FEOL:
X                       if(iMode == DMODE)
X                       {
X                          /* enter in dictionary */
X                          StringDictAddPair(pDict,pAlias,pDefinition);
X                          iMode = AMODE;
X                          pAlias[0] = '\0';
X                       }
X                       break;
X           case FEOB:
X                       if(iMode == AMODE) 
X                       {
X                         /* empty line or a problem */
X                       }          
X                       else
X                       {
X                          /* enter in dictionary */
X                          StringDictAddPair(pDict,pAlias,pDefinition);
X                          iMode = AMODE;
X                          pAlias[0] = '\0';
X                       }
X                       return;
X           default:
X                   assert(0); /* unrecognized token is a programming
X                                 error
X                              */
X                   break;
X         }
X     }
X  }
X
X#line 2154 "nxdict.w"
X
X/*--------------------------------------------------------------------------*/
X  NXstatus NXDinitfromfile(char *filename, NXdict *pData)
X  {
X     NXdict pNew = NULL;
X     FILE *fd = NULL;
X     char *pBuffer = NULL;
X     char pError[512];
X
X
X#line 365 "nxdict.w"
X
X     /* allocate a new NXdict structure */
X     if(iVerbosity == NXalot)
X     {
X         NXIReportError(NXpData, "Allocating new NXdict structure ");
X     }
X     pNew = (NXdict)malloc(sizeof(sNXdict));
X     if(!pNew)
X     {
X         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
X         return NX_ERROR;
X     }
X     
X     /* initialise it */
X     pNew->iID = NXDMAGIC;
X     pNew->pDictionary = CreateStringDict();
X     if(!pNew->pDictionary)
X     {
X         NXIReportError(NXpData, "Insufficient memory for creation of NXdict");
X         free(pNew);
X         return NX_ERROR;
X     }
X
X
X#line 2163 "nxdict.w"
X
X
X#line 392 "nxdict.w"
X
X     /* is there a file name argument */
X     if(filename == NULL)
X     {
X        if(iVerbosity == NXalot)
X        {
X           NXIReportError(NXpData, "NXDinitfrom file finished without data");
X        }
X        *pData = pNew;
X        return NX_OK;
X     }
X
X#line 2164 "nxdict.w"
X
X
X#line 406 "nxdict.w"
X
X      fd = fopen(filename,"rb");
X      if(!fd)
X      {
X         sprintf(pError,"ERROR: file %s NOT found ",filename);
X         NXIReportError(NXpData, pError);
X         NXIReportError(NXpData, "NXDinitfrom file finished without data");
X         *pData = pNew;
X         return NX_ERROR;
X      }
X
X
X
X#line 2165 "nxdict.w"
X 
X
X#line 426 "nxdict.w"
X
X       /* read the file contents */
X       if(iVerbosity == NXalot)
X       {
X          NXIReportError(NXpData, "NXDinitfrom: reading file");
X       }
X       pBuffer = NXDIReadFile(fd);
X       fclose(fd); /* we are done with it then */
X       if(!pBuffer)
X       {
X         sprintf(pError,"ERROR: reading file %s or no memory",filename);
X         NXIReportError(NXpData, pError);
X         NXIReportError(NXpData, "NXDinitfrom file finished without data");
X         *pData = pNew;
X         return NX_ERROR;
X       }
X
X       /* parse it */
X       if(iVerbosity == NXalot)
X       {
X          NXIReportError(NXpData, "NXDinitfrom: parsing dictionary definitions");
X       }
X       NXDIParse(pBuffer, pNew->pDictionary);
X
X#line 2166 "nxdict.w"
X
X
X       if(iVerbosity == NXalot)
X       {
X          NXIReportError(NXpData, "NXDinitfrom: performed successfully");
X       }
X       free(pBuffer);
X       *pData = pNew;
X       return NX_OK;
X  }   
X/*--------------------------------------------------------------------------*/
X
X#line 642 "nxdict.w"
X
X   NXdict NXDIAssert(NXdict handle)
X   {
X      NXdict self = NULL;
X      assert(handle);
X      self = (NXdict)handle;
X      assert(self->iID == NXDMAGIC);
X      return self;
X   }
X
X#line 2177 "nxdict.w"
X
X/*-------------------------------------------------------------------------*/
X
X#line 653 "nxdict.w"
X
X   NXstatus NXDclose(NXdict handle, char *filename)
X   {
X      NXdict self;
X      const char *pKey = NULL;
X      char pValue[1024];
X      FILE *fd = NULL;
X
X      self = NXDIAssert(handle);
X
X      if(filename) /* we must write a file */
X      {
X        if(iVerbosity == NXalot)
X        {
X           sprintf(pValue,"Writing file %s",filename);
X           NXIReportError(NXpData, pValue);
X        }
X        fd = fopen(filename,"w");
X        if(!fd)
X        {
X           sprintf(pValue,"ERROR: opening file %s for write",filename);
X           NXIReportError(NXpData, pValue);
X           return NX_ERROR;
X        }   
X        pKey = StringDictGetNext(self->pDictionary, pValue,1023);
X        while(pKey != NULL)
X        {
X          fprintf(fd,"%s = %s\n",pKey,pValue);
X          pKey = StringDictGetNext(self->pDictionary,pValue,1023);
X        }
X        fclose(fd);
X        if(iVerbosity == NXalot)
X        {
X           sprintf(pValue,"File %s written",filename);
X           NXIReportError(NXpData, pValue);
X        }
X      }
X
X      /* now we send the cleaners in */
X      DeleteStringDict(self->pDictionary);
X      free(self);
X      return NX_OK;
X   }
X
X#line 2179 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 701 "nxdict.w"
X
X   NXstatus NXDadd(NXdict handle, char *alias, char *pDef)
X   {
X     NXdict self;
X     int iRet;
X
X     self = NXDIAssert(handle);
X     iRet = StringDictAddPair(self->pDictionary,alias,pDef);
X     if(!iRet)
X     {
X       return NX_ERROR;
X     }
X     return NX_OK;
X   }
X/*---------------------------------------------------------------------------*/
X   NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int iBufLen)
X   {
X     NXdict self;
X     int iRet;
X
X     self = NXDIAssert(handle);
X     iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen);
X     if(!iRet)
X     {
X       return NX_ERROR;
X     }
X     return NX_OK;
X   }
X/*-------------------------------------------------------------------------*/
X   NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal)
X   {
X     NXdict self;
X     int iRet;
X
X     self = NXDIAssert(handle);
X     iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal);
X     if(!iRet)
X     {
X       return NX_ERROR;
X     }
X     return NX_OK;
X   }
X
X
X#line 2181 "nxdict.w"
X
X/*------------------- The Defintion String Parser -----------------------*/
X/*------- Data structures */
X
X#line 758 "nxdict.w"
X
X  typedef struct {
X                  char pText[20];
X                  int iCode;
X                 }  TokDat;
X
X#line 2184 "nxdict.w"
X
X
X#line 768 "nxdict.w"
X
X#define TERMSDS 100
X#define TERMVG  200
X#define TERMLINK 300
X
X   typedef struct {
X                    char *pPtr;
X                    char pToken[256];
X                    int iToken;
X                    int iDepth;
X                    int iMayCreate;
X                    int iTerminal;
X                  } ParDat;
X
X#line 2185 "nxdict.w"
X
X
X#line 973 "nxdict.w"
X
X   static void DummyError(void *pData, char *pError)
X   {
X     return;
X   }
X
X#line 2186 "nxdict.w"
X
X
X#line 1087 "nxdict.w"
X
X  typedef struct {
X                   char name[256];
X                   char value[256];
X                  }AttItem;
X
X#line 2187 "nxdict.w"
X 
X/*------------------------------------------------------------------------*/
X
X#line 790 "nxdict.w"
X
X/*---------------- Token name defines ---------------------------*/
X#define DSLASH 0
X#define DKOMMA 1
X#define DSDS   2
X#define DLINK  3
X#define DGROUP 4
X#define DRANK  5
X#define DDIM   6
X#define DTYPE  7
X#define DWORD  9
X#define DOPEN  10
X#define DCLOSE 11
X#define DATTR  12
X#define DEND   13
X
X/*----------------- Keywords ----------------------------------------*/
X
X  static TokDat TokenList[8] = { 
X                                {"SDS",DSDS},
X                                {"NXLINK",DLINK},
X                                {"NXVGROUP",DGROUP},
X                                {"-dim",DDIM},
X                                {"-type",DTYPE},
X                                {"-rank",DRANK},
X                                {"-attr",DATTR},
X                                {NULL,0} };
X
X/*-----------------------------------------------------------------------*/
X   static void NXDIDefToken(ParDat *sStat)
X   {
X       int i;
X       
X
X       sStat->pToken[0] = '\0';
X
X       /* skip whitespace */
X       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') )
X       {
X         sStat->pPtr++;
X       } 
X
X       /* check for special characters */
X       if(*(sStat->pPtr) == '/')
X       {
X         sStat->iToken = DSLASH;
X         sStat->pToken[0] = *(sStat->pPtr);
X         sStat->pPtr++;
X         return;
X       }
X       else if(*(sStat->pPtr) == ',')
X       {
X         sStat->iToken = DKOMMA;
X         sStat->pToken[0] = *(sStat->pPtr);
X         sStat->pPtr++;
X         return;
X       }
X       else if(*(sStat->pPtr) == '\0')
X       {
X         sStat->iToken = DEND;
X         sStat->pToken[0] = *(sStat->pPtr);
X         sStat->pPtr++;
X         return;
X       }
X       else if(*(sStat->pPtr) == '{')
X       {
X         sStat->iToken = DOPEN;
X         sStat->pToken[0] = *(sStat->pPtr);
X         sStat->pPtr++;
X         return;
X       }
X       else if(*(sStat->pPtr) == '}')
X       {
X         sStat->iToken = DCLOSE;
X         sStat->pToken[0] = *(sStat->pPtr);
X         sStat->pPtr++;
X         return;
X       }
X       else 
X       {
X         sStat->iToken = DWORD;
X         /* copy word to pToken */
X         i = 0;
X         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') && 
X                (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') &&
X                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') )
X         {
X           sStat->pToken[i] = *(sStat->pPtr);
X           sStat->pPtr++;
X           i++;
X         } 
X         sStat->pToken[i] = '\0';
X
X         /*--------- try to find word in Tokenlist */
X         for(i = 0; i < 7; i++)
X         {
X           if(strcmp(sStat->pToken,TokenList[i].pText) == 0)
X           {
X             sStat->iToken = TokenList[i].iCode;
X             break;
X           }
X         }
X         return;
X       }
X      /* not reached */
X      return;
X   }
X
X
X#line 2189 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 986 "nxdict.w"
X
X   int NXDIParsePath(NXhandle hfil, ParDat *pParse)
X   {
X       int iRet, iToken;
X       void (*ErrFunc)(void *pData, char *pErr); 
X       char pName[132], pClass[132];
X       char pError[256];
X
X       /* get the name */
X       NXDIDefToken(pParse); /* next token */
X       if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP)
X           || (pParse->iToken == DLINK) )
X       {
X         /* put back & OK */
X         pParse->pPtr -= strlen(pParse->pToken);
X         return NX_OK;
X       }
X       if(pParse->iToken != DWORD)
X       {
X          sprintf(pError,"ERROR: parse error at %s, expected vGroup name",
X                  pParse->pToken);
X          NXIReportError(NXpData, pError);
X          return NX_ERROR;
X       }       
X       strcpy(pName,pParse->pToken);
X     
X       /* now we expect a komma */
X       NXDIDefToken(pParse); /* next token */
X       if(pParse->iToken != DKOMMA)
X       {
X          sprintf(pError,"ERROR: parse error at %s, expected komma",
X                  pParse->pToken);
X          NXIReportError(NXpData, pError);
X          return NX_ERROR;
X       }       
X
X       /* next must be the class */
X       NXDIDefToken(pParse); /* next token */
X       if(pParse->iToken != DWORD)
X       {
X          sprintf(pError,"ERROR: parse error at %s, expected vGroup class",
X                  pParse->pToken);
X          NXIReportError(NXpData, pError);
X          return NX_ERROR;
X       }       
X       strcpy(pClass,pParse->pToken);
X
X       /* done reading, ACTION, first install dummy error handler */
X       ErrFunc = NXIReportError;
X       NXMSetError(NXpData, DummyError);
X 
X       /* try opening vGroup */
X       iRet = NXopengroup(hfil, pName, pClass);
X       NXMSetError(NXpData,ErrFunc);
X       if(iRet == NX_OK)
X       {
X         pParse->iDepth++;
X         return NX_OK;
X       } 
X       else
X       {
X          /* we need to create it, if we may */
X          if(pParse->iMayCreate)
X          {
X            iRet = NXmakegroup(hfil,pName,pClass);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X            iRet = NXopengroup(hfil,pName,pClass);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X            pParse->iDepth++;
X            return NX_OK; 
X          }
X          else
X          {
X             /* this is an error */
X             sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, pClass);
X             NXIReportError(NXpData,pError);
X             return NX_ERROR;
X          }
X       }
X       /* not reached */
X       return NX_ERROR;
X   }
X
X#line 2191 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1354 "nxdict.w"
X
X   static int NXDIParseAttr(ParDat *pParse, int iList)
X   {
X     char pError[256];
X     int iRet;
X     AttItem sAtt;
X
X     /* a { is expected */
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DOPEN)
X     {
X        sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X
X     /* a word is expected */
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DWORD)
X     {
X        sprintf(pError,"ERROR: expected attribute name, got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X     strcpy(sAtt.name,pParse->pToken);
X
X     /* a , is expected */
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DKOMMA)
X     {
X        sprintf(pError,"ERROR: expected , , got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X
X     /* a word is expected */
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DWORD)
X     {
X        sprintf(pError,"ERROR: expected attribute value, got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X     strcpy(sAtt.value,pParse->pToken);
X
X     /* a } is expected */
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DCLOSE)
X     {
X        sprintf(pError,"ERROR: expected }, got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X
X     /* enter into list */
X     LLDnodeAppendFrom(iList,&sAtt);
X     return NX_OK;
X   }
X
X#line 2193 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1301 "nxdict.w"
X
X   static int NXDIParseDim(ParDat *pParse, int *iDim)
X   {
X       char pError[256];
X       int iRet, i;
X
X        /* initialise dimensions to 0 */
X        for(i = 0; i < MAX_VAR_DIMS; i++)
X        {
X          iDim[i] = 0;
X        }
X
X        NXDIDefToken(pParse);
X        if(pParse->iToken != DOPEN)
X        {
X          sprintf(pError,"ERROR: expected {, got %s",pParse->pToken);
X          NXIReportError(NXpData,pError);
X          return NX_ERROR;
X        }
X
X        i = 0;      
X        while(pParse->iToken != DCLOSE)
X        {
X           /* get a number */
X           NXDIDefToken(pParse);
X           if(pParse->iToken != DWORD)
X           {
X              sprintf(pError,"ERROR: expected number, got %s",pParse->pToken);
X              NXIReportError(NXpData,pError);
X              return NX_ERROR;
X           }
X           iDim[i] = atoi(pParse->pToken);
X           i++;
X           /* next must be close of komma */
X           NXDIDefToken(pParse);
X           if( (pParse->iToken != DKOMMA) && (pParse->iToken != DCLOSE) )
X           {
X              sprintf(pError,"ERROR: expected , or }, got %s",pParse->pToken);
X              NXIReportError(NXpData,pError);
X              return NX_ERROR;
X           }
X           if(pParse->iToken == DCLOSE)
X           {
X              break;
X           }
X        }
X        return NX_OK;
X   }
X
X#line 2195 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1252 "nxdict.w"
X
X   static TokDat tDatType[] = {
X                      {"DFNT_FLOAT32",DFNT_FLOAT32},   
X                      {"DFNT_FLOAT64",DFNT_FLOAT64},    
X                      {"DFNT_INT8",DFNT_INT8},  
X                      {"DFNT_UINT8",DFNT_UINT8},
X                      {"DFNT_INT16",DFNT_INT16},      
X                      {"DFNT_UINT16",DFNT_UINT16},
X                      {"DFNT_INT32",DFNT_INT32},
X                      {"DFNT_UINT32",DFNT_UINT32},
X                      {NULL,-122} };
X
X
X
X   static int NXDIParseType(ParDat *pParse, int *iType)
X   {
X      char pError[256];
X      int i = 0;
X
X      NXDIDefToken(pParse);
X      if(pParse->iToken != DWORD)
X      { 
X        sprintf(pError,"ERROR: expected data type, got %s", pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X      }
X       
X      /* try to interpret data type */
X      while(tDatType[i].iCode > 0) {
X        if(strcmp(tDatType[i].pText,pParse->pToken) == 0)
X        {
X           *iType = tDatType[i].iCode;
X            return NX_OK;
X        }
X        i++;
X      }
X      /* if we are here, the data type has not been recognized. Reason for
X         some boring error reporting code
X      */
X      sprintf(pError,"ERROR: %s not recognized as valid data type",
X                      pParse->pToken);
X      NXIReportError(NXpData,pError);
X      return NX_ERROR;      
X   }
X
X#line 2197 "nxdict.w"
X
X/*-------------------------------------------------------------------------*/
X
X#line 1095 "nxdict.w"
X
X   static int NXDIParseSDS(NXhandle hfil, ParDat *pParse)
X   {
X      int iType = DFNT_FLOAT32;
X      int iRank = 1;
X      int32 iDim[MAX_VAR_DIMS];
X      int iList;
X      int iRet, iStat;
X      char pError[256];
X      char pName[MAX_NC_NAME];
X      void (*ErrFunc)(void *pData, char *pErr);
X      AttItem sAtt; 
X
X
X       iDim[0] = 1;
X       /* first find the name */
X       NXDIDefToken(pParse);
X       if(pParse->iToken != DWORD)
X       {
X          sprintf(pError,"ERROR: parsing, expected name, got %s",
X                  pParse->pToken);
X          NXIReportError(NXpData,pError);
X          return NX_ERROR;
X       }
X        strcpy(pName,pParse->pToken);
X
X       /* create the attribute list */
X       iList = LLDcreate(sizeof(AttItem));
X       if(iList < 0)
X       {
X          NXIReportError(NXpData, "ERROR: cannot create list in NXDIParseSDS");
X          return NX_ERROR;
X       }
X
X       NXDIDefToken(pParse);
X       while(pParse->iToken != DEND)
X       {
X          switch(pParse->iToken)
X          {
X            case DRANK: /* rank */
X                       NXDIDefToken(pParse); /* advance */
X                       if(pParse->iToken != DWORD)
X                       {
X                         sprintf(pError,
X                         "ERROR: expected int, got %s", pParse->pToken);
X                          NXIReportError(NXpData,pError);
X                          LLDdelete(iList);
X                          return NX_ERROR; 
X                       }
X                       iRank = atoi(pParse->pToken);
X                       break;
X            case DDIM:
X                     iRet = NXDIParseDim(pParse, iDim);
X                     if(iRet == NX_ERROR)
X                     {
X                        LLDdelete(iList);
X                        return iRet;
X                     } 
X                     break;
X            case DTYPE:
X                     iRet = NXDIParseType(pParse, &iType);
X                     if(iRet == NX_ERROR)
X                     {
X                        LLDdelete(iList);
X                        return iRet;
X                     } 
X                     break;
X            case DATTR:
X                     iRet = NXDIParseAttr(pParse, iList);
X                     if(iRet == NX_ERROR)
X                     {
X                        LLDdelete(iList);
X                        return iRet;
X                     } 
X                     break;
X            case DEND:
X                     break;
X            default:
X                     sprintf(pError,"ERROR: cannot identify token %s",
X                                     pParse->pToken);
X                     NXIReportError(NXpData, pError);
X                     LLDdelete(iList);
X                     return NX_ERROR;
X                    
X          }
X          NXDIDefToken(pParse);
X       }
X       
X       /* whew! got all information for doing the SDS */
X       /* first install dummy error handler, try open it, then
X          deinstall again and create if allowed 
X       */
X       ErrFunc = NXIReportError;
X       NXMSetError(NXpData, DummyError);
X 
X       /* try opening SDS */
X       iRet = NXopendata(hfil, pName);
X       NXMSetError(NXpData,ErrFunc);
X       if(iRet == NX_OK)
X       {
X         LLDdelete(iList);
X         return NX_OK;
X       } 
X       else
X       {
X          /* we need to create it, if we may */
X          if(pParse->iMayCreate)
X          {
X            iRet = NXmakedata(hfil,pName,iType, iRank,iDim);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 LLDdelete(iList);
X                 return iRet;
X            }
X            iRet = NXopendata(hfil,pName);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 LLDdelete(iList);
X                 return iRet;
X            }
X            /* put attributes in */
X            iRet = LLDnodePtr2First(iList);
X            while(iRet != 0)
X            {
X              LLDnodeDataTo(iList,&sAtt);
X              iStat = 
X
XNXputattr(hfil,sAtt.name,sAtt.value,strlen(sAtt.value),DFNT_INT8);
X              if(iStat != NX_OK)
X              {
X                 /* NeXus already complained bitterly */
X                 LLDdelete(iList);
X                 return iStat;
X              }
X              iRet = LLDnodePtr2Next(iList);
X            }
X            LLDdelete(iList);
X            return NX_OK; 
X          }
X          else
X          {
X             /* this is an error */
X             sprintf(pError,"ERROR: SDS %s NOT found",pName);
X             NXIReportError(NXpData,pError);
X             LLDdelete(iList);
X             return NX_ERROR;
X          }
X       }
X       return NX_OK;
X   }
X
X#line 2199 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1417 "nxdict.w"
X
X   static int NXDIParseLink(NXhandle hfil, NXdict pDict,ParDat *pParse)
X   {
X     char pError[256];
X     int i, iRet;
X
X     /* need one word of alias */ 
X     NXDIDefToken(pParse);
X     if(pParse->iToken != DCLOSE)
X     {
X        sprintf(pError,"ERROR: expected alias , got %s",pParse->pToken);
X        NXIReportError(NXpData,pError);
X        return NX_ERROR;
X     }
X    
X     /* move back in hierarchy */
X     for(i = 0; i < pParse->iDepth; i++)
X     {
X       iRet = NXclosegroup(hfil);
X       if(iRet == NX_ERROR)
X       {
X         return NX_ERROR;
X       }
X     }
X     
X     /* open the link instead */ 
X     return NXDopenalias(hfil, pDict, pParse->pToken);
X
X   }
X
X#line 2201 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 906 "nxdict.w"
X
X    static int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat *pParse)
X    {
X       int iRet;
X       char pError[256];
X 
X       pParse->iToken = -1;
X       while(pParse->iToken != DEND)
X       {
X         NXDIDefToken(pParse); /* next token */
X         switch(pParse->iToken)
X         {
X            case DEND:
X                      break;
X            case DSLASH:
X                      iRet = NXDIParsePath(hFil, pParse);
X                      if(iRet == NX_ERROR)
X                      {
X                         return NX_ERROR;
X                      }
X                      break;
X            case DSDS:
X                      iRet = NXDIParseSDS(hFil, pParse);
X                      if(iRet == NX_ERROR)
X                      {
X                         return NX_ERROR;
X                      }
X                      pParse->iTerminal = TERMSDS;
X                      break;
X            case DLINK:
X                      iRet = NXDIParseLink(hFil,pDict, pParse);                    
  
X                      if(iRet == NX_ERROR)
X                      {
X                         return NX_ERROR;
X                      }
X                      pParse->iTerminal = TERMLINK;
X                      break;
X            case DGROUP:
X                      pParse->iTerminal = TERMVG;
X                      return NX_OK;
X            default:
X                     sprintf(pError,
X            "ERROR: Definition String parse error: %s not permitted here",
X             pParse->pToken);
X                     NXIReportError(NXpData,pError);
X                     return NX_ERROR;
X                     break;
X         }
X       }
X       return NX_OK;
X    }
X
X#line 2203 "nxdict.w"
X
X/*----------------------------------------------------------------------*/
X
X#line 1449 "nxdict.w"
X
X  static NXstatus NXDIUnwind(NXhandle hFil, int iDepth)
X  {
X     int i, iRet;
X      
X     for(i = 0; i < iDepth; i++)
X     {
X        iRet = NXclosegroup(hFil);
X        if(iRet != NX_OK)
X        {
X          return NX_ERROR;
X        }
X     }
X     return NX_OK;
X  }
X
X#line 2205 "nxdict.w"
X
X/*-------------------- The Data Transfer Functions ----------------------*/
X
X#line 1470 "nxdict.w"
X
X   NXstatus NXDopendef(NXhandle hfil, NXdict dict, char *pDef)
X   {
X     NXdict pDict;
X     ParDat pParse;
X     int iRet, i, iStat;
X
X     pDict = NXDIAssert(dict);
X     
X     /* parse and act on definition string */
X     pParse.iMayCreate = 1;
X     pParse.pPtr = pDef;
X     pParse.iDepth = 0;
X     iRet = NXDIDefParse(hfil,pDict,&pParse);
X     if(iRet == NX_ERROR)
X     {
X         /* unwind and throw up */
X         iRet = NXDIUnwind(hfil,pParse.iDepth);
X         return NX_ERROR;
X     }
X
X     
X     /* try rewinding the hierarchy */
X     if(pParse.iTerminal == TERMSDS)
X     {
X         iStat = NXDIUnwind(hfil,pParse.iDepth);
X         if(iStat != NX_OK)
X         {
X            return NX_ERROR;
X         }
X     }
X     /* do not rewind on links */
X     return iRet;
X   }
X
X#line 2207 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1510 "nxdict.w"
X
X   NXstatus NXDopenalias(NXhandle hfil, NXdict dict, char *pAlias)
X   {
X     NXdict pDict;
X     int iRet;
X     char pDefinition[1024];
X
X     pDict = NXDIAssert(dict);
X     
X     /* get Definition String  */
X     iRet = NXDget(pDict,pAlias,pDefinition,1023);
X     if(iRet != NX_OK)
X     {
X        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
X        NXIReportError(NXpData,pDefinition);
X        return NX_ERROR;
X     }
X     
X     /* call NXDopendef */
X     return NXDopendef(hfil,dict,pDefinition);
X   }
X
X#line 2209 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1537 "nxdict.w"
X
X   NXstatus NXDputdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
X   {
X     NXdict pDict;
X     ParDat pParse;
X     int iRet, i, iStat;
X
X     pDict = NXDIAssert(dict);
X     
X     /* parse and act on definition string */
X     pParse.iMayCreate = 1;
X     pParse.pPtr = pDef;
X     pParse.iDepth = 0;
X     iRet = NXDIDefParse(hFil,pDict,&pParse);
X     if(iRet == NX_ERROR)
X     {
X          NXDIUnwind(hFil,pParse.iDepth);
X          return NX_ERROR;
X     }
X
X     
X     /* only SDS can be written */
X     if(pParse.iTerminal != TERMSDS)
X     {
X        NXIReportError(NXpData,
X                     "ERROR: can only write to an SDS!");
X        iStat = NX_ERROR;
X     } 
X     else 
X     {
X       /* the SDS should be open by now, write it */
X       iStat = NXputdata(hFil, pData);
X       iRet = NXclosedata(hFil);
X     }   
X
X
X     /* rewind the hierarchy */
X     iRet = NXDIUnwind(hFil,pParse.iDepth);
X     if(iRet != NX_OK)
X     {
X       return NX_ERROR;
X     }
X     return iStat;
X   }
X
X#line 2211 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1585 "nxdict.w"
X
X  NXstatus NXDputalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
X  {
X     NXdict pDict;
X     int iRet;
X     char pDefinition[1024];
X
X     pDict = NXDIAssert(dict);
X     
X     /* get Definition String  */
X     iRet = NXDget(pDict,pAlias,pDefinition,1023);
X     if(iRet != NX_OK)
X     {
X        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
X        NXIReportError(NXpData,pDefinition);
X        return NX_ERROR;
X     }
X     
X     /* call NXDputdef */
X     return NXDputdef(hFil,dict,pDefinition,pData);
X  }
X
X#line 2213 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1610 "nxdict.w"
X
X   NXstatus NXDgetdef(NXhandle hFil, NXdict dict, char *pDef, void *pData)
X   {
X     NXdict pDict;
X     ParDat pParse;
X     int iRet, i, iStat;
X
X     pDict = NXDIAssert(dict);
X     
X     /* parse and act on definition string */
X     pParse.iMayCreate = 0;
X     pParse.pPtr = pDef;
X     pParse.iDepth = 0;
X     iRet = NXDIDefParse(hFil,pDict,&pParse);
X     if(iRet == NX_ERROR)
X     {
X         /* unwind and throw up */
X          NXDIUnwind(hFil,pParse.iDepth);
X          return NX_ERROR;
X     }
X
X
X     /* only SDS can be written */
X     if(pParse.iTerminal != TERMSDS)
X     {
X        NXIReportError(NXpData,
X                     "ERROR: can only write to an SDS!");
X        iStat = NX_ERROR;
X     } 
X     else 
X     {
X       /* the SDS should be open by now, read it */
X       iStat = NXgetdata(hFil, pData);
X       iRet = NXclosedata(hFil);
X     }   
X
X
X     /* rewind the hierarchy */
X     iRet = NXDIUnwind(hFil,pParse.iDepth);
X     if(iRet != NX_OK)
X     {
X        return NX_ERROR;
X     }
X     return iStat;
X   }
X
X#line 2215 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1659 "nxdict.w"
X
X  NXstatus NXDgetalias(NXhandle hFil, NXdict dict, char *pAlias, void *pData)
X  {
X     NXdict pDict;
X     int iRet;
X     char pDefinition[1024];
X
X     pDict = NXDIAssert(dict);
X     
X     /* get Definition String  */
X     iRet = NXDget(pDict,pAlias,pDefinition,1023);
X     if(iRet != NX_OK)
X     {
X        sprintf(pDefinition,"ERROR: alias %s not recognized",pAlias);
X        NXIReportError(NXpData,pDefinition);
X        return NX_ERROR;
X     }
X     
X     /* call NXDgetdef */
X     return NXDgetdef(hFil,dict,pDefinition,pData);
X  }
X
X#line 2217 "nxdict.w"
X
X/*------------------------------------------------------------------------*/
X
X#line 1686 "nxdict.w"
X
X  NXstatus NXDdeflink(NXhandle hFil, NXdict dict, 
X                      char *pTarget, char *pVictim)
X  {
X     NXdict pDict;
X     ParDat pParseT, pParseV;
X     int iRet, i, iStat;
X     NXlink sLink;
X
X     pDict = NXDIAssert(dict);
X     
X
X     /* parse Victim  */
X     pParseV.iMayCreate = 0;
X     pParseV.pPtr = pVictim;
X     pParseV.iDepth = 0;
X     iRet = NXDIDefParse(hFil,pDict,&pParseV);
X     if(iRet == NX_ERROR)
X     {
X         /* unwind and throw up */
X          NXDIUnwind(hFil,pParseV.iDepth);
X          return NX_ERROR;
X     }
X     /* get link data */
X     if(pParseV.iTerminal == TERMSDS)
X     {
X       NXgetdataID(hFil,&sLink);
X       iRet =  NXclosedata(hFil);
X       if(iRet != NX_OK)
X       {
X         /* unwind and throw up */
X          NXDIUnwind(hFil,pParseV.iDepth);
X          return NX_ERROR;
X       }
X     }
X     else if(pParseV.iTerminal == TERMVG)
X     {
X       NXgetgroupID(hFil,&sLink);
X     }
X     else
X     {
X        assert(0); /* serious programming error */
X     }
X     /* Unwind */
X     iRet = NXDIUnwind(hFil,pParseV.iDepth);
X     if(iRet != NX_OK)
X     {
X       return NX_ERROR;
X     }
X
X     /* parse Target */
X     pParseT.iMayCreate = 1;
X     pParseT.pPtr = pTarget;
X     pParseT.iDepth = 0;
X     iRet = NXDIDefParse(hFil,pDict,&pParseT);
X     if(iRet == NX_ERROR)
X     {
X         /* unwind and throw up */
X          NXDIUnwind(hFil,pParseT.iDepth);
X          return NX_ERROR;
X     }
X     /* check it being a vGroup! */
X     if(pParseT.iTerminal != TERMVG)
X     {
X       NXIReportError(NXpData,"ERROR: can link only into a vGroup");
X       NXDIUnwind(hFil,pParseT.iDepth);
X       return NX_ERROR;
X     }
X    
X     /* link, finally */
X     iRet = NXmakelink(hFil,&sLink);
X     /* Unwind anyway */
X     iStat = NXDIUnwind(hFil,pParseT.iDepth);
X     if(iStat != NX_OK)
X     {
X       return NX_ERROR;
X     }
X     return iStat;
X  }
X/*--------------------------------------------------------------------------*/
X  NXstatus NXDaliaslink(NXhandle hFil, NXdict dict, 
X                      char *pTarget, char *pVictim)
X  {
X    char pTargetDef[1024], pVictimDef[1024];
X    int iRet;
X    NXdict pDict;
X
X     pDict = NXDIAssert(dict);
X     
X     /* get Target Definition String  */
X     iRet = NXDget(pDict,pTarget,pTargetDef,1023);
X     if(iRet != NX_OK)
X     {
X        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
X        NXIReportError(NXpData,pTargetDef);
X        return NX_ERROR;
X     }
X   
X     /* get Victim definition string */
X     iRet = NXDget(pDict,pVictim,pVictimDef,1023);
X     if(iRet != NX_OK)
X     {
X        sprintf(pTargetDef,"ERROR: alias %s not recognized",pTarget);
X        NXIReportError(NXpData,pTargetDef);
X        return NX_ERROR;
X     }
X
X     /* call NXdeflin */
X     return NXDdeflink(hFil,pDict,pTargetDef,pVictimDef);
X  }
X
X
X#line 2219 "nxdict.w"
X
X/*-----------------------------------------------------------------------*/
X
X#line 1801 "nxdict.w"
X
X/*-------------------------------------------------------------------------*/
X  static void SNXFormatTime(char *pBuffer, int iBufLen)
X  {
X     time_t iDate;
X     struct tm *psTime;
X
X     /* make time string */
X     iDate = time(NULL);
X     psTime = localtime(&iDate);
X     memset(pBuffer,0,iBufLen);         
X     strftime(pBuffer,iBufLen,"%Y-%d-%m %H:%M:%S",psTime);
X  }  
X/*--------------------------------------------------------------------------*/
X   NXstatus NXUwriteglobals(NXhandle pFile, 
X                            char *filename,
X                            char *owner,
X                            char *adress,
X                            char *phone,
X                            char *email,
X                            char *fax,
X                            char *instrument)
X   {
X     char pBueffel[512];
X     int iStat;
X     
X     /* store global attributes */
X     iStat = NXputattr(pFile,"file_name",filename, 
X                       strlen(filename)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return NX_ERROR;
X     }
X     
X     /* write creation time */
X     SNXFormatTime(pBueffel,512);
X     iStat = NXputattr(pFile,"file_time",pBueffel,
X                       strlen(pBueffel)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return NX_ERROR;
X     }
X
X     /* instrument name */
X     iStat = NXputattr(pFile,"instrument",instrument,
X                       strlen(instrument)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return iStat;
X     }
X
X     /* owner */
X     iStat = NXputattr(pFile,"owner",owner,
X                       strlen(owner)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return iStat;
X     }
X
X     /* Adress */
X     iStat = NXputattr(pFile,"owner_adress",adress,
X                       strlen(adress)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X        return iStat;
X     }
X
X     /* phone */
X     iStat = NXputattr(pFile,"owner_telephone_number",phone,
X                       strlen(phone)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X        return iStat;
X     }
X
X     /* fax */
X     iStat = NXputattr(pFile,"owner_fax_number",fax,
X                       strlen(fax)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return iStat;
X     }
X
X     /* email */
X     iStat = NXputattr(pFile,"owner_email",email,
X                       strlen(email)+1,DFNT_INT8);
X     if(iStat == NX_ERROR)
X     {
X       return iStat;
X     }
X     return NX_OK;
X   }
X
X#line 2221 "nxdict.w"
X
X/*-----------------------------------------------------------------------*/
X
X#line 1897 "nxdict.w"
X
X   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class)
X   {
X       void (*ErrFunc)(void *pData, char *pErr); 
X       int iRet;
X
X       /* ACTION, first install dummy error handler */
X       ErrFunc = NXIReportError;
X       NXMSetError(NXpData, DummyError);
X 
X       /* try opening vGroup */
X       iRet = NXopengroup(hFil, name, class);
X       NXMSetError(NXpData,ErrFunc);
X       if(iRet == NX_OK)
X       {
X         return NX_OK;
X       } 
X       else
X       {
X          /* we need to create it */
X            iRet = NXmakegroup(hFil,name,class);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X            iRet = NXopengroup(hFil,name,class);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X       }
X       return NX_OK;
X   }
X
X#line 2223 "nxdict.w"
X
X/*-----------------------------------------------------------------------*/
X
X#line 1934 "nxdict.w"
X
X   NXstatus NXUenterdata(NXhandle hFil, char *label, int datatype,
X                         int rank, int dim[], char *pUnits)
X   {
X       void (*ErrFunc)(void *pData, char *pErr); 
X       int iRet;
X
X       /* ACTION, first install dummy error handler */
X       ErrFunc = NXIReportError;
X       NXMSetError(NXpData, DummyError);
X 
X       /* try opening SDS */
X       iRet = NXopendata(hFil, label);
X       NXMSetError(NXpData,ErrFunc);
X       if(iRet == NX_OK)
X       {
X         return NX_OK;
X       } 
X       else
X       {
X          /* we need to create it */
X            iRet = NXmakedata(hFil,label, datatype, rank,dim);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X            iRet = NXopendata(hFil,label);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X            iRet = NXputattr(hFil, "Units",pUnits,
X                             strlen(pUnits) + 1,DFNT_INT8);
X            if(iRet != NX_OK)
X            { 
X                 /* a comment on this one has already been written! */
X                 return iRet;
X            }
X       }
X       return NX_OK;
X   }
X
X#line 2225 "nxdict.w"
X
X/*-----------------------------------------------------------------------*/
X
X#line 1980 "nxdict.w"
X
X   NXstatus NXUallocSDS(NXhandle hFil, void **pData)
X   {
X      int iDIM[MAX_VAR_DIMS];
X      int iRank,iType;
X      int iRet, i;
X      long lLength;
X
X      /* get info */
X      iRet = NXgetinfo(hFil,&iRank, iDIM, &iType);
X      if(iRet != NX_OK)
X      {
X        return iRet;
X      }      
X
X      /* calculate Size */
X      lLength = iDIM[0];
X      for(i = 1; i < iRank; i++)
X      {
X        lLength *= iDIM[i];
X      }
X      switch(iType)
X      {
X        case DFNT_FLOAT32:
X             lLength *= sizeof(float32);
X             break;
X        case DFNT_FLOAT64:
X             lLength *= sizeof(float64);
X             break;
X        case DFNT_INT8:
X             lLength *= sizeof(int8);
X             break;
X        case DFNT_UINT8:
X             lLength *= sizeof(uint8);
X             break;
X        case DFNT_INT16:
X             lLength *= sizeof(int16);
X             break;
X        case DFNT_UINT16:
X             lLength *= sizeof(uint16);
X             break;
X        case DFNT_INT32:
X             lLength *= sizeof(int32);
X             break;
X        case DFNT_UINT32:
X             lLength *= sizeof(uint32);
X             break;
X        default:
X             NXIReportError(NXpData,"ERROR: Internal: number type not 
recoginized");
X             return NX_ERROR;
X      }
X
X      /* time to malloc */
X      *pData = NULL;
X      *pData = malloc(lLength);
X      if(*pData == NULL)
X      {
X        NXIReportError(NXpData,"ERROR: memory exhausted in NXUallocSDS");
X        return NX_ERROR;
X      }
X      return NX_OK;
X   }
X
X#line 2227 "nxdict.w"
X
X/*----------------------------------------------------------------------*/
X
X#line 2044 "nxdict.w"
X
X   NXstatus NXUfreeSDS(void **pData)
X   {
X      free(*pData);
X      *pData = NULL;
X      return NX_OK;
X   }
X
X#line 2229 "nxdict.w"
X
SHAR_EOF
chmod 0664 nxdict.c || echo "restore of nxdict.c fails"
echo "x - extracting nxdict.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > nxdict.h &&
X
X#line 2054 "nxdict.w"
X
X/*---------------------------------------------------------------------------
X                            NXDICT API header file
X
X   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland
X
X   No warranties of any kind taken.
X----------------------------------------------------------------------------*/
X#ifndef NXDICTAPI
X#define NXDICTAPI
X#include "napi.h" /* make sure, napi is included */
X
X/*-------------------- NXDict data types & defines ----------------------*/
X
X#line 184 "nxdict.w"
X
X   typedef struct __NXdict *NXdict;
X
X#line 2067 "nxdict.w"
X
X#define NXquiet 0
X#define NXalot  1
X/*-------------------- Dictionary Maintainance ----------------------------*/
X
X#line 190 "nxdict.w"
X
X   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);
X   NXstatus NXDclose(NXdict handle, char *filename);
X
X   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);
X   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int iBufLen);
X   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);
X
X#line 2071 "nxdict.w"
X
X/*----------------- Dictionary added data transfer -----------------------*/ 
X
X#line 223 "nxdict.w"
X
X   NXstatus NXDputalias(NXhandle file, NXdict dict, 
X                        char *alias, void *pData);
X   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
X
X   NXstatus NXDgetalias(NXhandle file, NXdict dict, 
X                        char *alias, void *pData);
X   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, void *pData);
X
X   NXstatus NXDaliaslink(NXhandle file, NXdict dict, 
X                         char *pAlias1, char *pAlias2);
X   NXstatus NXDdeflink(NXhandle file, NXdict dict, 
X                         char *pDef1, char *pDef2);
X
X   NXstatus NXDopenalias(NXhandle file, NXdict dict, 
X                        char *alias);
X   NXstatus NXDopendef(NXhandle file, NXdict dict, char *pDefString);
X
X
X#line 2073 "nxdict.w"
X
X/*-------------------- Utility Functions --------------------------------*/
X
X#line 292 "nxdict.w"
X
X        NXstatus NXUwriteglobals(NXhandle file, 
X                            char *filename,
X                            char *owner,
X                            char *adress,
X                            char *phone,
X                            char *email,
X                            char *fax,
X                            char *thing);
X
X
X   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);
X   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, 
X                          int rank, int dim[], char *pUnits);
X   
X   NXstatus NXUallocSDS(NXhandle hFil, void **pData);
X   NXstatus NXUfreeSDS(void **pData);
X
X
X#line 2075 "nxdict.w"
X
X#endif
SHAR_EOF
chmod 0664 nxdict.h || echo "restore of nxdict.h fails"
echo "x - extracting nxdict.tex (Text)"
sed 's/^X//' << 'SHAR_EOF' > nxdict.tex &&
X%
X%
X%  This software is distributed in the hope that it will be useful,
X%  but WITHOUT ANY WARRANTY; without even the implied warranty of
X%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X%  GNU General Public License for more details.
X%
X%  You may already have a copy of the GNU General Public License; if
X%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
X%  Cambridge, MA 02139, USA.
X%
X
X\documentclass[12pt]{article}
X
X\setlength{\oddsidemargin}{-.1in}
X\setlength{\evensidemargin}{0in}
X\setlength{\topmargin}{0in}
X\addtolength{\topmargin}{-\headheight}
X\addtolength{\topmargin}{-\headsep}
X\setlength{\textheight}{8.9in}
X\setlength{\textwidth}{6.2in}
X\setlength{\marginparwidth}{0.5in}
X
X\begin{document}
X\title{The NEXUS Dictionary API}
X
X\author{Mark K\"onnecke\\
X  Labor f\"ur Neutronenstreuung\\
X  Paul Scherrer Institut\\
X  CH-5232 Villigen PSI\\
X  Switzerland\\       
X  Mark.Koennecke at psi.ch \\
X}
X
X
X
X\maketitle
X
X\vskip.3in
X\centerline{\large\bf Abstract}
X\vskip.2in
X\begin{center}
X\parbox{.8\textwidth}{
X  There is a proposed portable data exchange format for neutron and
X  X-ray scattering communities, NEXUS (described in a separate
X  publication).   Another document describes an application programmers
X interface to NEXUS. This is a base level API which hides many of the
X hideous details of the HDF interface from the NeXus programmer. The
X present document   introduces a higher level application programmers
X interface sitting on top of the NeXus API. This API (the NEXDICT-API),
X reads all file structure interface from a dictionary data file and creates
X the structure automatically from that information. The NEXDICT user only
X needs to specify the data to write.
X}
X\end{center}
X
X\clearpage
X
X\section{Introduction}
X There exists a prosal for a portable data exchange format for neutron and
X X--ray scattering communities, NeXus. NeXus is fully described
X elsewhere$^{1}$. NeXus sits on top of the hierachical data format (HDF) as
X defined and specified by the National Center for Supercompter Applications, 
X NCSA, USA. HDF comes with a library of access functions. On top of the
X HDF-library an application programmers interface (API) for NeXus was
X defined which hides many of the low level details and ideosyncracies of
X the HDF interface form the NeXus programmer. However, writing NeXus files stays
X hideous even with this interface due to the amount of repetetive code
X required to  implement the NeXus structure. Now, repetetive tasks is one
X area a computer is good at. So, why not have the computer take care of all
X the structure associated with the NeXus format? In order to do this two
X components are needed:
X\begin{itemize}
X\item A language which describes the NeXus file structure to the computer.
X  This language will be called the NeXus Data Definition Language (NXDDL).
X  NXDLL might also be used as a tool for discussing and defining NeXus
X  datastructures.
X\item A application programmers interface which works with the NeXus Data 
X Definition Language.
X\end{itemize}
XBoth of the above will be detailed in this document.
X
X\section{The NeXus Data Definition Language}
XThe NeXus Data Definition Language(NXDDL) has the purpose to define the structure
Xand data items in a NeXus file in a form which can be understood by a human
Xprogrammer and which can be parsed by the computer in order to create the 
Xstructure. 
XFor this a dictionary based aproach will be used. This dictionary
Xwill contain pairs of short aliases for data items and definition strings 
Xwhich hold the structure information. This dictionary will
Xbe initialised from a data file, the NXDDL-file. Such a dictionary can be
Xused in the following way: Given an apropriate API function, a NXDICT
Xprogrammer  needs to specify only the alias and the data to write and 
Xeverything else is taken care of by the API: vGroup creation, opening,
XSDS definition etc. Another use may involve the creation of definition string
Xcompletely or partly at run time which can then be used by an API function
Xin order to create the structures defined by the definition string. The same
Xholds for writing as well.
X
X
XA NXDDL dictionary is preferably initialised from a file.
XSuch a NXDDL file has to follow these general structure guidelines:
X\begin{itemize}
X\item All input is in US--ASCII.
X\item A \verb+#+ in the first column denotes a comment and will be ignored.
X\item A \verb+\+ at the end of the line means that the current text will be 
X continued with the next non-blanck character for the next line.
X\item All other entries follow the form: alias = definition string.
X This defines \verb+alias+ as a short form for the definition string  after the
X equality sign.
X\end{itemize}         
XIt might be considered to add a special global vGroup of class NXdict to the
XNexUs API which holds the dictionary information within a NeXus file.
X
X The next thing to define is the content of the definition string. A
X definition string will have the general form: \\
X\centerline{\bf PATH/TerminalSymbol}
X This means a definition string will consist of a path specifier which
X describes the position of a data item in the vGroup hierarchy and a
X terminal symbol which describes the nature of the data item. 
X
X The path through the vGroup hierarchy to a data item will be described in a
X manner analog to a Unix directory hierarchy. However, NeXus requires two
X pieces of data in order to fully qualify a vGroup. This is it's name and
X class. Consequently, both name and classname will be given for each vGroup,
X separated by a komma. A valid path string then looks like: \\
X\begin{verbatim} 
X     /scan1,NXentry/DMC,NXinstrument/big_detector,NXdetector/TerminalSymbol
X\end{verbatim}
X This translates into: TerminalSymbol in vGroup big\_detector, class
X NXdetector, which resides in vGroup DMC of class NXinstrument, which in
X turn is situated in the vGroup scan1 of class NXentry.
X
X The terminal symbol in a definition string is used to define the data item
X at the end of the definition. NeXus currently supports only three types of
X data items at the end of the chain: these are scientific data sets (SDS),
X vGroups and links to other data items or vGroups. The terminal symbol for a link
X is specified by the keyword \verb+NXLINK+  
X followed
X by a valid alias of another data item or vGroup. For example the terminal 
X symbol: \\
X \centerline{\bf SDS counts}
X would define a SDS with name counts.
X
X A vGroup would be denoted by the keyword VGROUP. By then, the vGroup has
X already been defined by the path string. This form of alias is only useful
X for the definition of links to vGroups.
X
X A SDS is more involved. The definition of an SDS starts with the keyword
X \verb+SDS+. This keyword must then be followed by the name of the SDS.
X Following the name there are option value pairs which define the 
X  details of the SDS. The following option exist:
X \begin{itemize}
X  \item {\bf -rank} defines the rank of the SDS.
X  \item {\bf -dim \{dim0,dim1,dim2,...., dimn\} } defines the dimensions of the
X       SDS. Exactly the number of rank numbers defining the dimensions
X length is required inside the curly braces. 
X  \item {\bf -type} defines the datatype of the SDS as a string corresponding
X  to the HDF data types.
X  \item {\bf -attr \{name,value\} } defines an attribute. In the curly braces
X   there must be the name and value of the attribute separated by a komma.
X  \end{itemize}
X  If no options are given a default is used. This will be a single floating
X  point number, as this is the most frequently written data item. As an 
X  example see the definition of a 3d array of 32 bit integers:
X  \begin{verbatim}
X   PATHSTRING/SDS counts -rank 3 -dim {64,64,712} -type DFNT_INT32 \
X                  -attr {Units,Counts}      
X
X  \end{verbatim}
X
X  \section{The NXDICT--API}
X  In order to interface with the NeXus dictionary API a set of
X  API--functions is needed. All functions and data types belonging to
X  this API start with the letters: NXD. The functions belonging to this API
X  fall into three groups:
X  \begin{itemize}
X   \item Dictionary maintainance functions.
X   \item Data writing and reading functions.
X   \item Utility functions.
X  \end{itemize}
X  
X  One additional data type is needed for this API:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap1}
X$\langle$tata {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   typedef struct __NXdict *NXdict;@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNXdict will be used as a handle for the dictionary currently in use.
X
X\subsubsection{Dictionary Maintainance Function}
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap2}
X$\langle$dicman {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDinitfromfile(char *filename, NXdict *pDict);@\\
X\mbox{}\verb@   NXstatus NXDclose(NXdict handle, char *filename);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDadd(NXdict handle, char *alias, char *DefString);@\\
X\mbox{}\verb@   NXstatus NXDget(NXdict handle, char *alias, char *pBuffer, int 
iBufLen);@\\
X\mbox{}\verb@   NXstatus NXDupdate(NXdict handle, char *alias, char *pNewVal);@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X{\bf NXDinitfromfile} creates a new NeXus dictionary. If filename is NULL, this
X  is all that happens. If filename is not NULL, it will be opened and the
X  dictionary will be initialised from the file specified.  The return value
X  is either 0 for failure or non zero for success. 
X
X  {\bf NXDclose} deletes and writes a NeXus dictionary. If filename is not NULL,
X  the dictionary specified by handle is written to the file specified by
X  filename. In any case the dictionary specified by handle will be deleted.
X
X  {\bf NXDadd} adds a new alias -- Definition String pair to the dictionary
X  specified by handle.
X
X  {\bf NXDget} retrieves the definition string for the alias specified as
X  the second parameter from the dictionary handle. The definition string
X  is copied to pBuffer. Maximum iBufLen characters will be copied.
X
X  {\bf NXDupdate} replaces the definition for the alias specified as second
X parameter with the new value supplied as last parameter.
X  
X  If a special dictionary vGroup as extemsion to NeXus would be accepted,
X  two more functions need to be defined which read and write the dictionary 
X  from the NeXus file.
X
X\subsubsection{Data Handling functions}
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap3}
X$\langle$dicdata {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDputalias(NXhandle file, NXdict dict, @\\
X\mbox{}\verb@                        char *alias, void *pData);@\\
X\mbox{}\verb@   NXstatus NXDputdef(NXhandle file, NXdict dict, char *pDefString, 
void *pData);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDgetalias(NXhandle file, NXdict dict, @\\
X\mbox{}\verb@                        char *alias, void *pData);@\\
X\mbox{}\verb@   NXstatus NXDgetdef(NXhandle file, NXdict dict, char *pDefString, 
void *pData);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDaliaslink(NXhandle file, NXdict dict, @\\
X\mbox{}\verb@                         char *pAlias1, char *pAlias2);@\\
X\mbox{}\verb@   NXstatus NXDdeflink(NXhandle file, NXdict dict, @\\
X\mbox{}\verb@                         char *pDef1, char *pDef2);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDopenalias(NXhandle file, NXdict dict, @\\
X\mbox{}\verb@                        char *alias);@\\
X\mbox{}\verb@   NXstatus NXDopendef(NXhandle file, NXdict dict, char 
*pDefString);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XThe NXDICT data handling functions go in pairs. The version ending in
X alias expects an NXdict and an alias as input. These routines work
X out the pass from that. The other version ending on def acts upon 
X a definition string specified as second parameter. Using this scheme
X both full dictionary operation is possible, as well as operation with
X program generated definition strings. All routines return the
X usual NeXus status returns. All these routines start at the current vGroup
X level and return back to it.  
X
X NXDputalias, NXDputdef write the data element specified by the alias or
X the definition string to the NeXus file specified as first parameter. 
X pData is a pointer to the data to be written. These routines will check for
X the existence of all vGroups required in the path part of the definition
X string. If a vGroup  is missing it will be created. These routines step
X back to the same vGroup level from which they were called.
X
X NXDgetalias, NXDgetdef read a data item from file. pData MUST point to a
X data area large enough to hold the data read. If a vGroup is missing in
X the path for one of these routines an error is generated because it is 
X assumed that the data is present if a program wants to read it. These 
X routines step
X back to the same vGroup level from which they were called.
X 
X NXDaliaslink, NXDdeflink links the alias or definition given as fourth
X parameter to the vGroup specified by the  third parameter. pAlias1 or
X pDef1 MUST refer to a vGroup (we cannot link to a SDS, can't we?). The
X item being linked against MUST exist, otherwise the software will complain.
X The vGroup into which the link is installed will be created on the fly,
X if not present.
X Please note, that bot aliases or definition strings specified need to
X start from the same vGroup position.  These routines step
X back to the same vGroup level from which they were called. 
X
X NXDopenalias, NXDopendef open the specified data items specified by the
X alias or the definition string. Then the usual NeXus functions can be 
X used to interact with the data. These routines use the same scheme for
X creating vGroups on the fly as the put routines above. The status in the
X vGroup hierarchy after this call is dependent on the nature of the terminal
X symbol. If it is a SDS, the vGroup hierarchy will be stepped back to the
X level from which the call ocurred. The SDS will be left open. If the
X terminal symbol is a vGroup, then the this vGroup will be made the current
X vGroup. No back stepping occurs. 
X
X
X  
X  \subsection{NeXus Utility Functions}
X  This section list a couple of functions which either perform common 
X   tasks on NeXus files or relate
X  to aspects of error handling and debugging.
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap4}
X$\langle$dicutil {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@        NXstatus NXUwriteglobals(NXhandle file, @\\
X\mbox{}\verb@                            char *filename,@\\
X\mbox{}\verb@                            char *owner,@\\
X\mbox{}\verb@                            char *adress,@\\
X\mbox{}\verb@                            char *phone,@\\
X\mbox{}\verb@                            char *email,@\\
X\mbox{}\verb@                            char *fax,@\\
X\mbox{}\verb@                            char *thing);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXUentergroup(NXhandle hFil, char *name, char *class);@\\
X\mbox{}\verb@   NXstatus NXUenterdata (NXhandle fileid, char* label, int datatype, 
@\\
X\mbox{}\verb@                          int rank, int dim[], char *pUnits);@\\
X\mbox{}\verb@   @\\
X\mbox{}\verb@   NXstatus NXUallocSDS(NXhandle hFil, void **pData);@\\
X\mbox{}\verb@   NXstatus NXUfreeSDS(void **pData);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X{\bf NXUwriteglobals} writes the global attributes to a newly opened 
X NeXus file. The parameters should be self explaining. In addition 
X the file creation date is automatically written.
X
X
X {\bf NXUentergroup} tries to open the group specified by name and class.
X If it not present, it will be created and opened.
X
X {\bf NXUenterdata} tries to open the SDS specified by label.
X If it not present, it will be created and opened.
X
X  {\bf NXUallocSDS} allocates enough space for the currently open SDS. The
X  pointer created is returned in pData. 
X
X  {\bf NXUfreeSDS} returns memory allocated by NXUallocSDS to the system.
X
X
X\section{Implementation}
X\subsection{The NXDICT Data Structure}
XThe NXDICT--API is based on a dictionary which maps an alias to a definition
Xstring in NXDDL. Clearly, the first thing needed is a dictionary which maps
Xkey string to value strings. It was choosen to use an existing string
Xdictionary (developed for SICS) as the dictionary for the NXDICT--API. This
Xis realised and documented in files stringdict.*. This string dictionary is
Xbased on a linked list implementation available in the public domain (Files
Xlld.*). This is not the most efficient aproach as any search requires
Xsearching at maximum the whole linked list via strcmp. More efficient
Xdictionaries would use hash tables or binary trees. However, implementation
Xof a more efficient dictionary will be    delayed until it is proven, that
Xthe current aproach poses a serious performance problem.  
X
XThus, the NXdict data structure looks like this:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap5}
X$\langle$dicdat {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@    typedef struct __NXdict@\\
X\mbox{}\verb@                           {@\\
X\mbox{}\verb@                               int iID;@\\
X\mbox{}\verb@                               pStringDict pDictionary;@\\
X\mbox{}\verb@                           } sNXdict;@\\
X\mbox{}\verb@/*------------------ verbosity level 
-------------------------------------*/@\\
X\mbox{}\verb@   static int iVerbosity = 0 ;@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XThe first data member is a magic ID number which will be used for testing
Xpointers passed in as NXdict pointers. C permits any pointer to be passed
Xhere. But only those with the correct magic number will be accepted. The
Xnext data member is a pointer to the string dictionary used for implementing
Xthe dictionary.
X
XAnother feature is the verbosity level. This one is declared as a file
Xstatic in order to be available generally.
X
X\subsection{The Dictionary Maintainance Functions}
X\subsubsection{NXDinitfromfile}
XThis routine starts off by creating and initialising a new NXdict structure:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap6}
X$\langle$iniini {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@     /* allocate a new NXdict structure */@\\
X\mbox{}\verb@     if(iVerbosity == NXalot)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@         NXIReportError(NXpData, "Allocating new NXdict structure 
");@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@     pNew = (NXdict)malloc(sizeof(sNXdict));@\\
X\mbox{}\verb@     if(!pNew)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@         NXIReportError(NXpData, "Insufficient memory for creation of 
NXdict");@\\
X\mbox{}\verb@         return NX_ERROR;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@     @\\
X\mbox{}\verb@     /* initialise it */@\\
X\mbox{}\verb@     pNew->iID = NXDMAGIC;@\\
X\mbox{}\verb@     pNew->pDictionary = CreateStringDict();@\\
X\mbox{}\verb@     if(!pNew->pDictionary)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@         NXIReportError(NXpData, "Insufficient memory for creation of 
NXdict");@\\
X\mbox{}\verb@         free(pNew);@\\
X\mbox{}\verb@         return NX_ERROR;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XThe next step is to check for the existence of a filename. If filename is
XNULL we are done:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap7}
X$\langle$inicheck {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@     /* is there a file name argument */@\\
X\mbox{}\verb@     if(filename == NULL)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@        if(iVerbosity == NXalot)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           NXIReportError(NXpData, "NXDinitfrom file finished without 
data");@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@        *pData = pNew;@\\
X\mbox{}\verb@        return NX_OK;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XThe next step is to open the file:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap8}
X$\langle$inifil {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@      fd = fopen(filename,"rb");@\\
X\mbox{}\verb@      if(!fd)@\\
X\mbox{}\verb@      {@\\
X\mbox{}\verb@         sprintf(pError,"ERROR: file %s NOT found ",filename);@\\
X\mbox{}\verb@         NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@         NXIReportError(NXpData, "NXDinitfrom file finished without 
data");@\\
X\mbox{}\verb@         *pData = pNew;@\\
X\mbox{}\verb@         return NX_ERROR;@\\
X\mbox{}\verb@      }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNow this file needs to be parsed and the alias -- definition string pairs to
Xbe extracted. This is done in two steps: First the file contents is copied
Xin a buffer. Then this buffer is parsed. This aproach has the advantage that
Xthe parsing code can be reused if another source for the dictionary
Xdefinition shows up. For instance if it is decided to include it with the
XNeXus file in a special vGroup. 
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap9}
X$\langle$iniparse {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* read the file contents */@\\
X\mbox{}\verb@       if(iVerbosity == NXalot)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          NXIReportError(NXpData, "NXDinitfrom: reading file");@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       pBuffer = NXDIReadFile(fd);@\\
X\mbox{}\verb@       fclose(fd); /* we are done with it then */@\\
X\mbox{}\verb@       if(!pBuffer)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sprintf(pError,"ERROR: reading file %s or no 
memory",filename);@\\
X\mbox{}\verb@         NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@         NXIReportError(NXpData, "NXDinitfrom file finished without 
data");@\\
X\mbox{}\verb@         *pData = pNew;@\\
X\mbox{}\verb@         return NX_ERROR;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* parse it */@\\
X\mbox{}\verb@       if(iVerbosity == NXalot)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          NXIReportError(NXpData, "NXDinitfrom: parsing dictionary 
definitions");@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       NXDIParse(pBuffer, pNew->pDictionary);@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XOnce this has been done, the task left is to clean up and exit.  
X
X\paragraph{NXDIReadFile}
XThis is an internal function which determines the length of the file,
Xallocates a suitable buffer for it and then reads the file in the buffer.
XPlease note, that the code for determining the length of the file works
Xnicely on a Unix or DOS. On a VMS however, there might be a few rubbish
Xcharacters at the end of the buffer. This is due to the record structure of
Xfiles under VMS. 
X
X\paragraph{NXDIParse}
XNXDIParse is an internal function which parses a buffer into aliases and
Xvalues. It is one of two parsers in the nxdict system. Later on there will
Xbe a definition string parser.  This file reading parser uses a 
XTokenizer.
X
XThe Tokenizer does not need to recognize a lot of
Xtokens, so it is rather simple. NXDIfNextToken returns a pointer pointing to
Xthe character after the last token read. pPtr is the current position in
Xthe buffer. The value of the last token read will be returned in the buffer
XpToken. iToken will be set to the type of token recognized.
X  
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap10}
X$\langle$ftoken {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@#define FWORD 1@\\
X\mbox{}\verb@#define FHASH 2@\\
X\mbox{}\verb@#define FEOL  3@\\
X\mbox{}\verb@#define FEOB  4@\\
X\mbox{}\verb@#define FEQUAL 5@\\
X\mbox{}\verb@#define FSLASH 6@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   static char *NXDIfNextToken(char *pPtr, char *pToken, int 
*iToken)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@       pToken[0] = '\0';@\\
X\mbox{}\verb@       /* skip whitespace */@\\
X\mbox{}\verb@       while( (*pPtr == ' ') || (*pPtr == '\t') )@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@       } @\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* check for special characters */@\\
X\mbox{}\verb@       if(*pPtr == '#')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FHASH;@\\
X\mbox{}\verb@         pToken[0] = *pPtr;@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*pPtr == '\n')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FEOL;@\\
X\mbox{}\verb@         pToken[0] = *pPtr;@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*pPtr == '\0')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FEOB;@\\
X\mbox{}\verb@         pToken[0] = *pPtr;@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*pPtr == '=')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FEQUAL;@\\
X\mbox{}\verb@         pToken[0] = *pPtr;@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*pPtr == '\\')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FSLASH;@\\
X\mbox{}\verb@         pToken[0] = *pPtr;@\\
X\mbox{}\verb@         pPtr++;@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else @\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         *iToken = FWORD;@\\
X\mbox{}\verb@         /* copy word to pToken */@\\
X\mbox{}\verb@         while( (*pPtr != ' ') && (*pPtr != '\t') && @\\
X\mbox{}\verb@                (*pPtr != '\n') && (*pPtr != '\0') && (*pPtr != '=') 
)@\\
X\mbox{}\verb@         {@\\
X\mbox{}\verb@           *pToken = *pPtr;@\\
X\mbox{}\verb@           pPtr++;@\\
X\mbox{}\verb@           pToken++;@\\
X\mbox{}\verb@         } @\\
X\mbox{}\verb@         *pToken = '\0';@\\
X\mbox{}\verb@         return pPtr;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@      /* not reached */@\\
X\mbox{}\verb@      return pPtr;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@    @\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNXDIParse has two modes: parsing an alias  or parsing a definition string.
X 
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap11}
X$\langle$fparse {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@#define AMODE 0@\\
X\mbox{}\verb@#define DMODE 1@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@  static void  NXDIParse(char *pBuffer, pStringDict pDict)@\\
X\mbox{}\verb@  {@\\
X\mbox{}\verb@     char *pPtr;@\\
X\mbox{}\verb@     int iToken;@\\
X\mbox{}\verb@     int iMode;@\\
X\mbox{}\verb@     char pAlias[132];@\\
X\mbox{}\verb@     char pDefinition[1024]; /* this is > 10 lines of definition 
*/@\\
X\mbox{}\verb@     char pWord[132];@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     assert(pBuffer);@\\
X\mbox{}\verb@     assert(pDict);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     iMode = AMODE;@\\
X\mbox{}\verb@     pPtr = pBuffer;@\\
X\mbox{}\verb@     iToken = -1;@\\
X\mbox{}\verb@     pDefinition[0] = '\0';@\\
X\mbox{}\verb@     pAlias[0] = '\0';@\\
X\mbox{}\verb@     pWord[0] = '\0';@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     while(iToken != FEOB)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@         pPtr = NXDIfNextToken(pPtr,pWord,&iToken);@\\
X\mbox{}\verb@         switch(iToken)@\\
X\mbox{}\verb@         {@\\
X\mbox{}\verb@           case FHASH:@\\
X\mbox{}\verb@           case FSLASH: /* skip over \n to next non blank */@\\
X\mbox{}\verb@                       while(*pPtr != '\n')@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                          pPtr++;@\\
X\mbox{}\verb@                          /* check for end of file */@\\
X\mbox{}\verb@                          if(*pPtr == '\0')@\\
X\mbox{}\verb@                          {@\\
X\mbox{}\verb@                            return;@\\
X\mbox{}\verb@                          }@\\
X\mbox{}\verb@                       }@\\
X\mbox{}\verb@                       pPtr++;@\\
X\mbox{}\verb@                       break;@\\
X\mbox{}\verb@           case FEQUAL: /* do a mode change */@\\
X\mbox{}\verb@                       iMode = DMODE;@\\
X\mbox{}\verb@                       pDefinition[0] = '\0';@\\
X\mbox{}\verb@                       break;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@           case FWORD:@\\
X\mbox{}\verb@                       if(iMode == AMODE)@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                         strcpy(pAlias,pWord);@\\
X\mbox{}\verb@                       }  @\\
X\mbox{}\verb@                       else@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                         strcat(pDefinition,pWord);@\\
X\mbox{}\verb@                         strcat(pDefinition," ");@\\
X\mbox{}\verb@                       }@\\
X\mbox{}\verb@                       break;@\\
X\mbox{}\verb@           case FEOL:@\\
X\mbox{}\verb@                       if(iMode == DMODE)@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                          /* enter in dictionary */@\\
X\mbox{}\verb@                          
StringDictAddPair(pDict,pAlias,pDefinition);@\\
X\mbox{}\verb@                          iMode = AMODE;@\\
X\mbox{}\verb@                          pAlias[0] = '\0';@\\
X\mbox{}\verb@                       }@\\
X\mbox{}\verb@                       break;@\\
X\mbox{}\verb@           case FEOB:@\\
X\mbox{}\verb@                       if(iMode == AMODE) @\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                         /* empty line or a problem */@\\
X\mbox{}\verb@                       }          @\\
X\mbox{}\verb@                       else@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                          /* enter in dictionary */@\\
X\mbox{}\verb@                          
StringDictAddPair(pDict,pAlias,pDefinition);@\\
X\mbox{}\verb@                          iMode = AMODE;@\\
X\mbox{}\verb@                          pAlias[0] = '\0';@\\
X\mbox{}\verb@                       }@\\
X\mbox{}\verb@                       return;@\\
X\mbox{}\verb@           default:@\\
X\mbox{}\verb@                   assert(0); /* unrecognized token is a 
programming@\\
X\mbox{}\verb@                                 error@\\
X\mbox{}\verb@                              */@\\
X\mbox{}\verb@                   break;@\\
X\mbox{}\verb@         }@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@  }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X\subsubsection{NXDClose}
XThis routine will just write the dictionary to file if requested and clean
Xup afterwards. Prior to defining NXDClose anohter internal function is
Xneeded which checks the validity of the handle passed into the routine.
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap12}
X$\langle$dassert {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXdict NXDIAssert(NXdict handle)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@      NXdict self = NULL;@\\
X\mbox{}\verb@      assert(handle);@\\
X\mbox{}\verb@      self = (NXdict)handle;@\\
X\mbox{}\verb@      assert(self->iID == NXDMAGIC);@\\
X\mbox{}\verb@      return self;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap13}
X$\langle$dclose {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDclose(NXdict handle, char *filename)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@      NXdict self;@\\
X\mbox{}\verb@      const char *pKey = NULL;@\\
X\mbox{}\verb@      char pValue[1024];@\\
X\mbox{}\verb@      FILE *fd = NULL;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@      self = NXDIAssert(handle);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@      if(filename) /* we must write a file */@\\
X\mbox{}\verb@      {@\\
X\mbox{}\verb@        if(iVerbosity == NXalot)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           sprintf(pValue,"Writing file %s",filename);@\\
X\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@        fd = fopen(filename,"w");@\\
X\mbox{}\verb@        if(!fd)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           sprintf(pValue,"ERROR: opening file %s for 
write",filename);@\\
X\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
X\mbox{}\verb@           return NX_ERROR;@\\
X\mbox{}\verb@        }   @\\
X\mbox{}\verb@        pKey = StringDictGetNext(self->pDictionary, pValue,1023);@\\
X\mbox{}\verb@        while(pKey != NULL)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@          fprintf(fd,"%s = %s\n",pKey,pValue);@\\
X\mbox{}\verb@          pKey = StringDictGetNext(self->pDictionary,pValue,1023);@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@        fclose(fd);@\\
X\mbox{}\verb@        if(iVerbosity == NXalot)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           sprintf(pValue,"File %s written",filename);@\\
X\mbox{}\verb@           NXIReportError(NXpData, pValue);@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@      }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@      /* now we send the cleaners in */@\\
X\mbox{}\verb@      DeleteStringDict(self->pDictionary);@\\
X\mbox{}\verb@      free(self);@\\
X\mbox{}\verb@      return NX_OK;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X\subsubsection{NXDadd, NXDget, NXDupdate}
XThese are very much only wrapper function around the corresponding functions
Xfor maintaining StringDicts. Accordingly, they are fairly simple.
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap14}
X$\langle$dmaintain {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   NXstatus NXDadd(NXdict handle, char *alias, char *pDef)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@     NXdict self;@\\
X\mbox{}\verb@     int iRet;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     self = NXDIAssert(handle);@\\
X\mbox{}\verb@     iRet = StringDictAddPair(self->pDictionary,alias,pDef);@\\
X\mbox{}\verb@     if(!iRet)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@       return NX_ERROR;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@     return NX_OK;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@/*-------------------------------------------------------------------
--------*/@\\
X\mbox{}\verb@   NXstatus NXDget(NXdict handle, char *pKey, char *pBuffer, int 
iBufLen)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@     NXdict self;@\\
X\mbox{}\verb@     int iRet;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     self = NXDIAssert(handle);@\\
X\mbox{}\verb@     iRet = StringDictGet(self->pDictionary,pKey,pBuffer,iBufLen);@\\
X\mbox{}\verb@     if(!iRet)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@       return NX_ERROR;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@     return NX_OK;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@/*-------------------------------------------------------------------
------*/@\\
X\mbox{}\verb@   NXstatus NXDupdate(NXdict handle, char *pKey, char *pNewVal)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@     NXdict self;@\\
X\mbox{}\verb@     int iRet;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@     self = NXDIAssert(handle);@\\
X\mbox{}\verb@     iRet = StringDictUpdate(self->pDictionary,pKey,pNewVal);@\\
X\mbox{}\verb@     if(!iRet)@\\
X\mbox{}\verb@     {@\\
X\mbox{}\verb@       return NX_ERROR;@\\
X\mbox{}\verb@     }@\\
X\mbox{}\verb@     return NX_OK;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X\subsection{Dictionary Added Data Transfer}
XThe heart of these routines is the NXDopendef function which opens the data
Xitem specified. Most of the other routines can be defined as wrappers to
Xthis one. That is why it is discussed as the first function. Again a parser
Xis needed for parsing and interpreting the definition string. 
X
X\subsubsection{The Definition String Parser}
XThe definition string  parser is implemented as a classic recursive descent 
Xparser. And once
Xmore again a Tokenizer is needed. The Tokenizer has an own datastructure for
Xholding token information in a static array:
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap15}
X$\langle$tokdat {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@  typedef struct {@\\
X\mbox{}\verb@                  char pText[20];@\\
X\mbox{}\verb@                  int iCode;@\\
X\mbox{}\verb@                 }  TokDat;@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XIn order to do the parsing a data structure for holding parsing information
Xis necessary:
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap16}
X$\langle$padef {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@#define TERMSDS 100@\\
X\mbox{}\verb@#define TERMVG  200@\\
X\mbox{}\verb@#define TERMLINK 300@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   typedef struct {@\\
X\mbox{}\verb@                    char *pPtr;@\\
X\mbox{}\verb@                    char pToken[256];@\\
X\mbox{}\verb@                    int iToken;@\\
X\mbox{}\verb@                    int iDepth;@\\
X\mbox{}\verb@                    int iMayCreate;@\\
X\mbox{}\verb@                    int iTerminal;@\\
X\mbox{}\verb@                  } ParDat;@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XIn this structure pPtr is the current position in the buffer, iToken the ID
Xof the current token, pToken the text of the current token, iDepth gets
Xincremented whenever a vGroup is opened. This is needed in order to roll the
XvGroups back in the hierarchy after finishing operations. iMayCreate will be
Xset if the path parsing function may create new vGroups if the one requested
Xcan not be found.
X
XThis is the tokenizer:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap17}
X$\langle$deftok {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@/*---------------- Token name defines 
---------------------------*/@\\
X\mbox{}\verb@#define DSLASH 0@\\
X\mbox{}\verb@#define DKOMMA 1@\\
X\mbox{}\verb@#define DSDS   2@\\
X\mbox{}\verb@#define DLINK  3@\\
X\mbox{}\verb@#define DGROUP 4@\\
X\mbox{}\verb@#define DRANK  5@\\
X\mbox{}\verb@#define DDIM   6@\\
X\mbox{}\verb@#define DTYPE  7@\\
X\mbox{}\verb@#define DWORD  9@\\
X\mbox{}\verb@#define DOPEN  10@\\
X\mbox{}\verb@#define DCLOSE 11@\\
X\mbox{}\verb@#define DATTR  12@\\
X\mbox{}\verb@#define DEND   13@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@/*----------------- Keywords 
----------------------------------------*/@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@  static TokDat TokenList[8] = { @\\
X\mbox{}\verb@                                {"SDS",DSDS},@\\
X\mbox{}\verb@                                {"NXLINK",DLINK},@\\
X\mbox{}\verb@                                {"NXVGROUP",DGROUP},@\\
X\mbox{}\verb@                                {"-dim",DDIM},@\\
X\mbox{}\verb@                                {"-type",DTYPE},@\\
X\mbox{}\verb@                                {"-rank",DRANK},@\\
X\mbox{}\verb@                                {"-attr",DATTR},@\\
X\mbox{}\verb@                                {NULL,0} };@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@/*-------------------------------------------------------------------
----*/@\\
X\mbox{}\verb@   static void NXDIDefToken(ParDat *sStat)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@       int i;@\\
X\mbox{}\verb@       @\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       sStat->pToken[0] = '\0';@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* skip whitespace */@\\
X\mbox{}\verb@       while( (*(sStat->pPtr) == ' ') || (*(sStat->pPtr) == '\t') 
)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@       } @\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* check for special characters */@\\
X\mbox{}\verb@       if(*(sStat->pPtr) == '/')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DSLASH;@\\
X\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*(sStat->pPtr) == ',')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DKOMMA;@\\
X\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*(sStat->pPtr) == '\0')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DEND;@\\
X\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*(sStat->pPtr) == '{')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DOPEN;@\\
X\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else if(*(sStat->pPtr) == '}')@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DCLOSE;@\\
X\mbox{}\verb@         sStat->pToken[0] = *(sStat->pPtr);@\\
X\mbox{}\verb@         sStat->pPtr++;@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       else @\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         sStat->iToken = DWORD;@\\
X\mbox{}\verb@         /* copy word to pToken */@\\
X\mbox{}\verb@         i = 0;@\\
X\mbox{}\verb@         while( (*(sStat->pPtr) != ' ') && (*(sStat->pPtr) != '\t') 
&& @\\
X\mbox{}\verb@                (*(sStat->pPtr) != '/') && (*(sStat->pPtr) != '\0') 
&&@\\
X\mbox{}\verb@                (*(sStat->pPtr) != ',') && (*(sStat->pPtr) != '}') 
)@\\
X\mbox{}\verb@         {@\\
X\mbox{}\verb@           sStat->pToken[i] = *(sStat->pPtr);@\\
X\mbox{}\verb@           sStat->pPtr++;@\\
X\mbox{}\verb@           i++;@\\
X\mbox{}\verb@         } @\\
X\mbox{}\verb@         sStat->pToken[i] = '\0';@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@         /*--------- try to find word in Tokenlist */@\\
X\mbox{}\verb@         for(i = 0; i < 7; i++)@\\
X\mbox{}\verb@         {@\\
X\mbox{}\verb@           if(strcmp(sStat->pToken,TokenList[i].pText) == 0)@\\
X\mbox{}\verb@           {@\\
X\mbox{}\verb@             sStat->iToken = TokenList[i].iCode;@\\
X\mbox{}\verb@             break;@\\
X\mbox{}\verb@           }@\\
X\mbox{}\verb@         }@\\
X\mbox{}\verb@         return;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@      /* not reached */@\\
X\mbox{}\verb@      return;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNow, finally we can define the parser! This parser is universally used by
Xall the data transfer functions.  Input is the file handle of the NeXus file
Xand a pointer to an initialised ParDat structure. It is expected, that the
XpPtr field points to the start of the definition string, that iMayCreate is
Xproperly defined and that iDepth is 0. 
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap18}
X$\langle$defpar {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@    static int NXDIDefParse(NXhandle hFil, NXdict pDict, ParDat 
*pParse)@\\
X\mbox{}\verb@    {@\\
X\mbox{}\verb@       int iRet;@\\
X\mbox{}\verb@       char pError[256];@\\
X\mbox{}\verb@ @\\
X\mbox{}\verb@       pParse->iToken = -1;@\\
X\mbox{}\verb@       while(pParse->iToken != DEND)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         NXDIDefToken(pParse); /* next token */@\\
X\mbox{}\verb@         switch(pParse->iToken)@\\
X\mbox{}\verb@         {@\\
X\mbox{}\verb@            case DEND:@\\
X\mbox{}\verb@                      break;@\\
X\mbox{}\verb@            case DSLASH:@\\
X\mbox{}\verb@                      iRet = NXDIParsePath(hFil, pParse);@\\
X\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                      {@\\
X\mbox{}\verb@                         return NX_ERROR;@\\
X\mbox{}\verb@                      }@\\
X\mbox{}\verb@                      break;@\\
X\mbox{}\verb@            case DSDS:@\\
X\mbox{}\verb@                      iRet = NXDIParseSDS(hFil, pParse);@\\
X\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                      {@\\
X\mbox{}\verb@                         return NX_ERROR;@\\
X\mbox{}\verb@                      }@\\
X\mbox{}\verb@                      pParse->iTerminal = TERMSDS;@\\
X\mbox{}\verb@                      break;@\\
X\mbox{}\verb@            case DLINK:@\\
X\mbox{}\verb@                      iRet = NXDIParseLink(hFil,pDict, pParse);       
               @\\
X\mbox{}\verb@                      if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                      {@\\
X\mbox{}\verb@                         return NX_ERROR;@\\
X\mbox{}\verb@                      }@\\
X\mbox{}\verb@                      pParse->iTerminal = TERMLINK;@\\
X\mbox{}\verb@                      break;@\\
X\mbox{}\verb@            case DGROUP:@\\
X\mbox{}\verb@                      pParse->iTerminal = TERMVG;@\\
X\mbox{}\verb@                      return NX_OK;@\\
X\mbox{}\verb@            default:@\\
X\mbox{}\verb@                     sprintf(pError,@\\
X\mbox{}\verb@            "ERROR: Definition String parse error: %s not permitted 
here",@\\
X\mbox{}\verb@             pParse->pToken);@\\
X\mbox{}\verb@                     NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@                     return NX_ERROR;@\\
X\mbox{}\verb@                     break;@\\
X\mbox{}\verb@         }@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       return NX_OK;@\\
X\mbox{}\verb@    }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XThe next thing to do is to implement ParsePath. This will try to interpret a
Xpath string and initiate the apropriate actions, i.e. opening vGroups or
Xcreating them. However, there is a small problem here. The code needs to
Xknow if the vGroup exists. This can be checked by trying to open the group
Xwith NXopengroup. This will return an error if this group does not exist.
XNXopengroup will also print an error message saying so. This is not what is
Xwanted here, as we might choose to create the missing group silently.
X In order to suppress
Xthat one, it is needed to replace the current error handler by a dummy which
Xjust prints nothing anywhere and to step back to the original handler once
Xwe are done. The other option would be to use internals of the NeXus API
Ximplementation. However, the aim is to keep the original NeXus API and this
Xas independent as possible.  Consequently, here is the definition of the
Xdummy error handler:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap19}
X$\langle$dummyerr {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   static void DummyError(void *pData, char *pError)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@     return;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XWhen NXDIParsePath has been called the / has already been read.
XNXDIParsePath has to read the name and class of the vGroup separated by a
Xkomma. Then it has either to open the vGroup, and if this fails create it if
Xthe create flag in pParse is set.
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap20}
X$\langle$defpath {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   int NXDIParsePath(NXhandle hfil, ParDat *pParse)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@       int iRet, iToken;@\\
X\mbox{}\verb@       void (*ErrFunc)(void *pData, char *pErr); @\\
X\mbox{}\verb@       char pName[132], pClass[132];@\\
X\mbox{}\verb@       char pError[256];@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* get the name */@\\
X\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
X\mbox{}\verb@       if( (pParse->iToken == DSDS) || (pParse->iToken == DGROUP)@\\
X\mbox{}\verb@           || (pParse->iToken == DLINK) )@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         /* put back & OK */@\\
X\mbox{}\verb@         pParse->pPtr -= strlen(pParse->pToken);@\\
X\mbox{}\verb@         return NX_OK;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected vGroup 
name",@\\
X\mbox{}\verb@                  pParse->pToken);@\\
X\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@       }       @\\
X\mbox{}\verb@       strcpy(pName,pParse->pToken);@\\
X\mbox{}\verb@     @\\
X\mbox{}\verb@       /* now we expect a komma */@\\
X\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
X\mbox{}\verb@       if(pParse->iToken != DKOMMA)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected 
komma",@\\
X\mbox{}\verb@                  pParse->pToken);@\\
X\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@       }       @\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* next must be the class */@\\
X\mbox{}\verb@       NXDIDefToken(pParse); /* next token */@\\
X\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          sprintf(pError,"ERROR: parse error at %s, expected vGroup 
class",@\\
X\mbox{}\verb@                  pParse->pToken);@\\
X\mbox{}\verb@          NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@       }       @\\
X\mbox{}\verb@       strcpy(pClass,pParse->pToken);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* done reading, ACTION, first install dummy error handler 
*/@\\
X\mbox{}\verb@       ErrFunc = NXIReportError;@\\
X\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
X\mbox{}\verb@ @\\
X\mbox{}\verb@       /* try opening vGroup */@\\
X\mbox{}\verb@       iRet = NXopengroup(hfil, pName, pClass);@\\
X\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
X\mbox{}\verb@       if(iRet == NX_OK)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         pParse->iDepth++;@\\
X\mbox{}\verb@         return NX_OK;@\\
X\mbox{}\verb@       } @\\
X\mbox{}\verb@       else@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          /* we need to create it, if we may */@\\
X\mbox{}\verb@          if(pParse->iMayCreate)@\\
X\mbox{}\verb@          {@\\
X\mbox{}\verb@            iRet = NXmakegroup(hfil,pName,pClass);@\\
X\mbox{}\verb@            if(iRet != NX_OK)@\\
X\mbox{}\verb@            { @\\
X\mbox{}\verb@                 /* a comment on this one has already been written! 
*/@\\
X\mbox{}\verb@                 return iRet;@\\
X\mbox{}\verb@            }@\\
X\mbox{}\verb@            iRet = NXopengroup(hfil,pName,pClass);@\\
X\mbox{}\verb@            if(iRet != NX_OK)@\\
X\mbox{}\verb@            { @\\
X\mbox{}\verb@                 /* a comment on this one has already been written! 
*/@\\
X\mbox{}\verb@                 return iRet;@\\
X\mbox{}\verb@            }@\\
X\mbox{}\verb@            pParse->iDepth++;@\\
X\mbox{}\verb@            return NX_OK; @\\
X\mbox{}\verb@          }@\\
X\mbox{}\verb@          else@\\
X\mbox{}\verb@          {@\\
X\mbox{}\verb@             /* this is an error */@\\
X\mbox{}\verb@             sprintf(pError,"ERROR: vGroup %s, %s NOT found",pName, 
pClass);@\\
X\mbox{}\verb@             NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@             return NX_ERROR;@\\
X\mbox{}\verb@          }@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       /* not reached */@\\
X\mbox{}\verb@       return NX_ERROR;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNXDIParseSDS is more involved, as we have to deal with all the extras an SDS
Xcan have: dimensions, types etc. Each of these options can be present or
Xnot, and these options can go in any order. Particularly troublesome are
Xattributes which can only be written after opening or creating an SDS. this
Ximplies that attributes have to be stored in a list during parsing in order
Xto have them available after creation or opening of the SDS. This requires
Xanother private data structure for holding attribute information during
Xparsing:
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap21}
X$\langle$attitem {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@  typedef struct {@\\
X\mbox{}\verb@                   char name[256];@\\
X\mbox{}\verb@                   char value[256];@\\
X\mbox{}\verb@                  }AttItem;@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap22}
X$\langle$nxpasds {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   static int NXDIParseSDS(NXhandle hfil, ParDat *pParse)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@      int iType = DFNT_FLOAT32;@\\
X\mbox{}\verb@      int iRank = 1;@\\
X\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
X\mbox{}\verb@      int iList;@\\
X\mbox{}\verb@      int iRet, iStat;@\\
X\mbox{}\verb@      char pError[256];@\\
X\mbox{}\verb@      char pName[MAX_NC_NAME];@\\
X\mbox{}\verb@      void (*ErrFunc)(void *pData, char *pErr);@\\
X\mbox{}\verb@      AttItem sAtt; @\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       iDim[0] = 1;@\\
X\mbox{}\verb@       /* first find the name */@\\
X\mbox{}\verb@       NXDIDefToken(pParse);@\\
X\mbox{}\verb@       if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          sprintf(pError,"ERROR: parsing, expected name, got %s",@\\
X\mbox{}\verb@                  pParse->pToken);@\\
X\mbox{}\verb@          NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@        strcpy(pName,pParse->pToken);@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       /* create the attribute list */@\\
X\mbox{}\verb@       iList = LLDcreate(sizeof(AttItem));@\\
X\mbox{}\verb@       if(iList < 0)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          NXIReportError(NXpData, "ERROR: cannot create list in 
NXDIParseSDS");@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@       NXDIDefToken(pParse);@\\
X\mbox{}\verb@       while(pParse->iToken != DEND)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          switch(pParse->iToken)@\\
X\mbox{}\verb@          {@\\
X\mbox{}\verb@            case DRANK: /* rank */@\\
X\mbox{}\verb@                       NXDIDefToken(pParse); /* advance */@\\
X\mbox{}\verb@                       if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@                       {@\\
X\mbox{}\verb@                         sprintf(pError,@\\
X\mbox{}\verb@                         "ERROR: expected int, got %s", 
pParse->pToken);@\\
X\mbox{}\verb@                          NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@                          LLDdelete(iList);@\\
X\mbox{}\verb@                          return NX_ERROR; @\\
X\mbox{}\verb@                       }@\\
X\mbox{}\verb@                       iRank = atoi(pParse->pToken);@\\
X\mbox{}\verb@                       break;@\\
X\mbox{}\verb@            case DDIM:@\\
X\mbox{}\verb@                     iRet = NXDIParseDim(pParse, iDim);@\\
X\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                     {@\\
X\mbox{}\verb@                        LLDdelete(iList);@\\
X\mbox{}\verb@                        return iRet;@\\
X\mbox{}\verb@                     } @\\
X\mbox{}\verb@                     break;@\\
X\mbox{}\verb@            case DTYPE:@\\
X\mbox{}\verb@                     iRet = NXDIParseType(pParse, &iType);@\\
X\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                     {@\\
X\mbox{}\verb@                        LLDdelete(iList);@\\
X\mbox{}\verb@                        return iRet;@\\
X\mbox{}\verb@                     } @\\
X\mbox{}\verb@                     break;@\\
X\mbox{}\verb@            case DATTR:@\\
X\mbox{}\verb@                     iRet = NXDIParseAttr(pParse, iList);@\\
X\mbox{}\verb@                     if(iRet == NX_ERROR)@\\
X\mbox{}\verb@                     {@\\
X\mbox{}\verb@                        LLDdelete(iList);@\\
X\mbox{}\verb@                        return iRet;@\\
X\mbox{}\verb@                     } @\\
X\mbox{}\verb@                     break;@\\
X\mbox{}\verb@            case DEND:@\\
X\mbox{}\verb@                     break;@\\
X\mbox{}\verb@            default:@\\
X\mbox{}\verb@                     sprintf(pError,"ERROR: cannot identify token 
%s",@\\
X\mbox{}\verb@                                     pParse->pToken);@\\
X\mbox{}\verb@                     NXIReportError(NXpData, pError);@\\
X\mbox{}\verb@                     LLDdelete(iList);@\\
X\mbox{}\verb@                     return NX_ERROR;@\\
X\mbox{}\verb@                    @\\
X\mbox{}\verb@          }@\\
X\mbox{}\verb@          NXDIDefToken(pParse);@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       @\\
X\mbox{}\verb@       /* whew! got all information for doing the SDS */@\\
X\mbox{}\verb@       /* first install dummy error handler, try open it, then@\\
X\mbox{}\verb@          deinstall again and create if allowed @\\
X\mbox{}\verb@       */@\\
X\mbox{}\verb@       ErrFunc = NXIReportError;@\\
X\mbox{}\verb@       NXMSetError(NXpData, DummyError);@\\
X\mbox{}\verb@ @\\
X\mbox{}\verb@       /* try opening SDS */@\\
X\mbox{}\verb@       iRet = NXopendata(hfil, pName);@\\
X\mbox{}\verb@       NXMSetError(NXpData,ErrFunc);@\\
X\mbox{}\verb@       if(iRet == NX_OK)@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@         LLDdelete(iList);@\\
X\mbox{}\verb@         return NX_OK;@\\
X\mbox{}\verb@       } @\\
X\mbox{}\verb@       else@\\
X\mbox{}\verb@       {@\\
X\mbox{}\verb@          /* we need to create it, if we may */@\\
X\mbox{}\verb@          if(pParse->iMayCreate)@\\
X\mbox{}\verb@          {@\\
X\mbox{}\verb@            iRet = NXmakedata(hfil,pName,iType, iRank,iDim);@\\
X\mbox{}\verb@            if(iRet != NX_OK)@\\
X\mbox{}\verb@            { @\\
X\mbox{}\verb@                 /* a comment on this one has already been written! 
*/@\\
X\mbox{}\verb@                 LLDdelete(iList);@\\
X\mbox{}\verb@                 return iRet;@\\
X\mbox{}\verb@            }@\\
X\mbox{}\verb@            iRet = NXopendata(hfil,pName);@\\
X\mbox{}\verb@            if(iRet != NX_OK)@\\
X\mbox{}\verb@            { @\\
X\mbox{}\verb@                 /* a comment on this one has already been written! 
*/@\\
X\mbox{}\verb@                 LLDdelete(iList);@\\
X\mbox{}\verb@                 return iRet;@\\
X\mbox{}\verb@            }@\\
X\mbox{}\verb@            /* put attributes in */@\\
X\mbox{}\verb@            iRet = LLDnodePtr2First(iList);@\\
X\mbox{}\verb@            while(iRet != 0)@\\
X\mbox{}\verb@            {@\\
X\mbox{}\verb@              LLDnodeDataTo(iList,&sAtt);@\\
X\mbox{}\verb@              iStat = @\\
X\mbox{}\verb@@\\
X\mbox{}\verb at NXputattr(hfil,sAtt.name,sAtt.value,strlen(sAtt.value),DFNT_INT8);@\\
X\mbox{}\verb@              if(iStat != NX_OK)@\\
X\mbox{}\verb@              {@\\
X\mbox{}\verb@                 /* NeXus already complained bitterly */@\\
X\mbox{}\verb@                 LLDdelete(iList);@\\
X\mbox{}\verb@                 return iStat;@\\
X\mbox{}\verb@              }@\\
X\mbox{}\verb@              iRet = LLDnodePtr2Next(iList);@\\
X\mbox{}\verb@            }@\\
X\mbox{}\verb@            LLDdelete(iList);@\\
X\mbox{}\verb@            return NX_OK; @\\
X\mbox{}\verb@          }@\\
X\mbox{}\verb@          else@\\
X\mbox{}\verb@          {@\\
X\mbox{}\verb@             /* this is an error */@\\
X\mbox{}\verb@             sprintf(pError,"ERROR: SDS %s NOT found",pName);@\\
X\mbox{}\verb@             NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@             LLDdelete(iList);@\\
X\mbox{}\verb@             return NX_ERROR;@\\
X\mbox{}\verb@          }@\\
X\mbox{}\verb@       }@\\
X\mbox{}\verb@       return NX_OK;@\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNXDIParseType is fairly straightforward: read a word and try to interpret it 
Xas one of the standard NeXus data types.
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap23}
X$\langle$parsetype {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   static TokDat tDatType[] = {@\\
X\mbox{}\verb@                      {"DFNT_FLOAT32",DFNT_FLOAT32},   @\\
X\mbox{}\verb@                      {"DFNT_FLOAT64",DFNT_FLOAT64},    @\\
X\mbox{}\verb@                      {"DFNT_INT8",DFNT_INT8},  @\\
X\mbox{}\verb@                      {"DFNT_UINT8",DFNT_UINT8},@\\
X\mbox{}\verb@                      {"DFNT_INT16",DFNT_INT16},      @\\
X\mbox{}\verb@                      {"DFNT_UINT16",DFNT_UINT16},@\\
X\mbox{}\verb@                      {"DFNT_INT32",DFNT_INT32},@\\
X\mbox{}\verb@                      {"DFNT_UINT32",DFNT_UINT32},@\\
X\mbox{}\verb@                      {NULL,-122} };@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@   static int NXDIParseType(ParDat *pParse, int *iType)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@      char pError[256];@\\
X\mbox{}\verb@      int i = 0;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@      NXDIDefToken(pParse);@\\
X\mbox{}\verb@      if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@      { @\\
X\mbox{}\verb@        sprintf(pError,"ERROR: expected data type, got %s", 
pParse->pToken);@\\
X\mbox{}\verb@        NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@        return NX_ERROR;@\\
X\mbox{}\verb@      }@\\
X\mbox{}\verb@       @\\
X\mbox{}\verb@      /* try to interpret data type */@\\
X\mbox{}\verb@      while(tDatType[i].iCode > 0) {@\\
X\mbox{}\verb@        if(strcmp(tDatType[i].pText,pParse->pToken) == 0)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           *iType = tDatType[i].iCode;@\\
X\mbox{}\verb@            return NX_OK;@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@        i++;@\\
X\mbox{}\verb@      }@\\
X\mbox{}\verb@      /* if we are here, the data type has not been recognized. 
Reason for@\\
X\mbox{}\verb@         some boring error reporting code@\\
X\mbox{}\verb@      */@\\
X\mbox{}\verb@      sprintf(pError,"ERROR: %s not recognized as valid data 
type",@\\
X\mbox{}\verb@                      pParse->pToken);@\\
X\mbox{}\verb@      NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@      return NX_ERROR;      @\\
X\mbox{}\verb@   }@\\
X\mbox{}\verb@@$\diamond$
X\end{list}
X\vspace{-1ex}
X\footnotesize\addtolength{\baselineskip}{-1ex}
X\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}
}
X\item Macro referenced in scrap ?.
X\end{list}
X\end{minipage}\\[4ex]
X\end{flushleft}
XNXDIParseDim tries to read dimension information. This starts with a {
Xfollowed by numbers and kommas until there is a closing curly brace.
X
X\begin{flushleft} \small
X\begin{minipage}{\linewidth} \label{scrap24}
X$\langle$parsedim {\footnotesize ?}$\rangle\equiv$
X\vspace{-1ex}
X\begin{list}{}{} \item
X\mbox{}\verb@@\\
X\mbox{}\verb@   static int NXDIParseDim(ParDat *pParse, int *iDim)@\\
X\mbox{}\verb@   {@\\
X\mbox{}\verb@       char pError[256];@\\
X\mbox{}\verb@       int iRet, i;@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@        /* initialise dimensions to 0 */@\\
X\mbox{}\verb@        for(i = 0; i < MAX_VAR_DIMS; i++)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@          iDim[i] = 0;@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@        NXDIDefToken(pParse);@\\
X\mbox{}\verb@        if(pParse->iToken != DOPEN)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@          sprintf(pError,"ERROR: expected {, got 
%s",pParse->pToken);@\\
X\mbox{}\verb@          NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@          return NX_ERROR;@\\
X\mbox{}\verb@        }@\\
X\mbox{}\verb@@\\
X\mbox{}\verb@        i = 0;      @\\
X\mbox{}\verb@        while(pParse->iToken != DCLOSE)@\\
X\mbox{}\verb@        {@\\
X\mbox{}\verb@           /* get a number */@\\
X\mbox{}\verb@           NXDIDefToken(pParse);@\\
X\mbox{}\verb@           if(pParse->iToken != DWORD)@\\
X\mbox{}\verb@           {@\\
X\mbox{}\verb@              sprintf(pError,"ERROR: expected number, got 
%s",pParse->pToken);@\\
X\mbox{}\verb@              NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@              return NX_ERROR;@\\
X\mbox{}\verb@           }@\\
X\mbox{}\verb@           iDim[i] = atoi(pParse->pToken);@\\
X\mbox{}\verb@           i++;@\\
X\mbox{}\verb@           /* next must be close of komma */@\\
X\mbox{}\verb@           NXDIDefToken(pParse);@\\
X\mbox{}\verb@           if( (pParse->iToken != DKOMMA) && (pParse->iToken != 
DCLOSE) )@\\
X\mbox{}\verb@           {@\\
X\mbox{}\verb@              sprintf(pError,"ERROR: expected , or }, got 
%s",pParse->pToken);@\\
X\mbox{}\verb@              NXIReportError(NXpData,pError);@\\
X\mbox{}\verb@              return NX_ERROR;@\\



More information about the NeXus-developers mailing list