%  Copyleft (c) 1997 by Mark Koennecke at PSI, Switzerland.
%
%
%  This software is distributed in the hope that it will be useful,
%  but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%  GNU General Public License for more details.
%
%  You may already have a copy of the GNU General Public License; if
%  not, write to the Free Software Foundation, Inc., 675 Mass Ave,
%  Cambridge, MA 02139, USA.
%

\documentclass[12pt]{article}
\usepackage[dvips]

\setlength{\oddsidemargin}{-.1in}
\setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in}
\addtolength{\topmargin}{-\headheight}
\addtolength{\topmargin}{-\headsep}
\setlength{\textheight}{8.9in}
\setlength{\textwidth}{6.2in}
\setlength{\marginparwidth}{0.5in}

\begin{document}
\title{The NeXus Application Programmer's Interface}

\author{Mark K\"onnecke\\
  Labor f\"ur Neutronenstreuung\\
  Paul Scherrer Institut\\
  CH-5232 Villigen PSI\\
  Switzerland\\       
  Mark.Koennecke@psi.ch \\
  Przemek K\l{}osowski\\
  U. of Maryland \& NIST \\       
  przemek.klosowski@nist.gov 
}

}

\maketitle
\tableofcontents

\vskip.3in
\centerline{\large\bf Abstract}
\vskip.2in
\begin{center}
\parbox{.8\textwidth}{
  There is a proposed portable data exchange format for neutron and
  X-ray scattering communities, NeXus (described in a separate
  publication).  The present document supplements the NeXus proposal,
  by defining a simplified, NeXus-compliant programming interface for
  reading and writing NeXus files.
}
\end{center}

\section{Introduction}
\label{chap:intro}

This file defines an Application Programmer's Interface (API) to HDF
library as used for the NeXus data format. It encapsulates a subset of
HDF and provides some helper routines to simplify creating and reading
NeXus data files.

The API is designed to be modal; there is a hidden state that
determines which groups and datasets (Vgroups and SDSes) are open at
any given moment, and subsequent operations are implicitly performed
on these entities. This cuts down the number of parameters to pass
around in API calls, at the cost of forcing certain pre-approved {\em
mode d'emploi}. This mode d'emploi will be familiar to most: it is very
similar to navigating a directory hierarchy. In our case HDF--VGroups are
the directories, which can hold other directories and data items which are
restricted to being HDF--scientific data sets (SDS).

The API comprises the following functional groups:

\begin{enumerate}
\item General initialization and shutdown: opening and closing the file,
      creating or opening an existing group or dataset,  and closing them.
\item Reading and writing data and attributes to previously opened datasets.
\item Routines to obtain meta-data and to iterate over component datasets and attributes.
\item Handling of linking and group hierarchy.
\end{enumerate}



\section{Implementation}

\subsection{Data Structures}
The approach used in this version is to maintain a datastructure for each
open file. This datastructure will hold a stack of Vgroups traversed and
will thus allow stepping back and forth in the NeXus file structure. The
stack is implemented using an array. The datastructure looks like this: 
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@    typedef struct __NexusFile {@\\
\mbox{}\verb@                                 int   iNXID;@\\
\mbox{}\verb@                                 int32 iVID;@\\
\mbox{}\verb@                                 int32 iSID;@\\
\mbox{}\verb@                                 int32 iCurrentVG;@\\
\mbox{}\verb@                                 int32 iCurrentSDS;@\\
\mbox{}\verb@                                 int32 iStack[NXMAXSTACK];@\\
\mbox{}\verb@                                 int   iStackPtr; @\\
\mbox{}\verb@                                 int iNDir;@\\
\mbox{}\verb@                                 int iCurDir;@\\
\mbox{}\verb@                                 int *iRefDir;@\\
\mbox{}\verb@                                 int *iTagDir;@\\
\mbox{}\verb@                                } NexusFile, *pNexusFile;@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
The fields in more detail: \begin{itemize}
\item iNXID is a test value against memory corruption.
\item iVID is the file ID to use for the Vgroup interface.
\item iSID is the file ID to use for the SDS interface.
\item iCurrentVG is the ID of the current open Vgroup. Is 0, if there is 
 no Vgroup open.
\item iCurrentSDS is the ID of the current open SDS. Is 0, if there is 
 no SDS open.
\item iStack is the stack array.
\item iStackPtr is the pointer to the current Vgroup in iStack.
\item iNDir, iCurDir, iRefDir, iTagDir are data fields used during an
directory search with NXgetnextentry. They are:
\begin{itemize}
\item iNDir: number of directory entries.
\item iCurDir current directory entry.
\item iRefDir array of reference numbers.
\item iTagDir array of tag numbers.

\end{itemize}
\end{itemize} 

The other datastructure used is NXlink. It encapsulates all information
necessary to do a link between Vgroups and SDS's. This is easy:

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@    typedef struct {@\\
\mbox{}\verb@                    int32 iTag;@\\
\mbox{}\verb@                    int32 iRef;@\\
\mbox{}\verb@                   } NXlink;@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
Before diving into code, it may be helpful to highlight a few pecularities
of the HDF interface which help confuse the code. The first is, that there
is no single ID to refer to a given file. The Vgroup interface and the SDS
interface use two different ID's which have to be initialised at file
opening and used apropriatetly.

The other feature is the plethora of integer ID's associated with each
HDF--object. First there is something called a reference ID which seems to
be an ID which identifies an object within an HDF file. Coming with it there
is a tag, which denotes the type of the object. When things need to be done
to an object, HDF requires to attach or open the object. These calls usually
return another ID which can than be used furtheron. This becomes invalid
once you close the object again. So much bookeeping is needed to keep track
of all these ID's. \label{ididid}



\subsection{General initialization and shutdown}
\label{ss:gen}


The routines in this group are for opening and closing the NeXus/HDF file,
creating or opening an existing group or dataset,  and closing them.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@NXhandle  NXopen(char * filename, NXaccess access_method);@\\
\mbox{}\verb@NXstatus  NXclose(NXhandle fileid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@NXstatus  NXmakegroup (NXhandle fileid, char* Vgroup, char* NXclass);@\\
\mbox{}\verb@NXstatus  NXopengroup (NXhandle fileid, char* Vgroup, char* NXclass);@\\
\mbox{}\verb@NXstatus  NXclosegroup(NXhandle fileid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@NXstatus  NXmakedata (NXhandle fileid, char* label, int datatype, int rank, int dim[]);@\\
\mbox{}\verb@NXstatus  NXopendata (NXhandle fileid, char* label);@\\
\mbox{}\verb@NXstatus  NXclosedata(NXhandle fileid);@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXopen}
NXopen opens the HDF--file filename and creates and initialises a NexusFile
structure. The returned handle is actually the pointer to this structure.
This danger of this aproach is, that somebody might try arithemetic on the
handle and thereby  corrupt the system. In order to test for this the
NexusFile structure contains the NXID field which can be checked against a
predefined value. 

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@  NXhandle NXopen(char *filename, NXaccess am)@\\
\mbox{}\verb@  {@\\
\mbox{}\verb@     pNexusFile pNew = NULL;@\\
\mbox{}\verb@     char pBuffer[512];@\\
\mbox{}\verb@     int iRet;@\\
\mbox{}\verb@@\\
\mbox{}\verb@     /* get memory */@\\
\mbox{}\verb@     pNew = (pNexusFile)malloc(sizeof(NexusFile));@\\
\mbox{}\verb@     if(!pNew)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIReportError(NXpData, "ERROR: no memory to create File datastructure");@\\
\mbox{}\verb@        return NULL;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     memset(pNew,0,sizeof(NexusFile));@\\
\mbox{}\verb@@\\
\mbox{}\verb@     /* start SDS interface */@\\
\mbox{}\verb@     pNew->iSID = SDstart(filename,am);@\\
\mbox{}\verb@     if(pNew->iSID <= 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@       sprintf(pBuffer,"ERROR: cannot open file: %s",filename);@\\
\mbox{}\verb@       NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@       free(pNew);@\\
\mbox{}\verb@       return NULL;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     @\\
\mbox{}\verb@     /* otherwise we try to create the file two times which makes HDF@\\
\mbox{}\verb@        Trow up on us.@\\
\mbox{}\verb@     */@\\
\mbox{}\verb@     if(am == NXACC_CREATE)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        am = NXACC_RDWR;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@@\\
\mbox{}\verb@     /* start Vgroup API */@\\
\mbox{}\verb@     pNew->iVID = Hopen(filename,am,100);@\\
\mbox{}\verb@     if(pNew->iVID <= 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@       sprintf(pBuffer,"ERROR: cannot open file: %s",filename);@\\
\mbox{}\verb@       NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@       free(pNew);@\\
\mbox{}\verb@       return NULL;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     iRet = Vstart(pNew->iVID);@\\
\mbox{}\verb@     if(iRet < 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot initalise Vgroup interface");@\\
\mbox{}\verb@@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     pNew->iNXID = NXSIGNATURE;@\\
\mbox{}\verb@     pNew->iStack[0] = 0; /* root! */@\\
\mbox{}\verb@@\\
\mbox{}\verb@     return (NXhandle)pNew;   @\\
\mbox{}\verb@  }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXclose}
NXclose closes an Nexus file and deletes all associated datastructures from
memory. The handle fileid will no longer be valid after this.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@  NXstatus NXclose(NXhandle fid)@\\
\mbox{}\verb@  {@\\
\mbox{}\verb@      pNexusFile pFile = NULL;@\\
\mbox{}\verb@      int iRet; @\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* close links into vGroups or SDS */@\\
\mbox{}\verb@      if(pFile->iCurrentVG != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         Vdetach(pFile->iCurrentVG);@\\
\mbox{}\verb@      }    @\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = SDendaccess(pFile->iCurrentSDS);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          NXIReportError(NXpData,"ERROR: ending access to SDS");@\\
\mbox{}\verb@      }    @\\
\mbox{}\verb@@\\
\mbox{}\verb@  @\\
\mbox{}\verb@      /* close the SDS and Vgroup API's */@\\
\mbox{}\verb@      Vend(pFile->iVID);@\\
\mbox{}\verb@      iRet = SDend(pFile->iSID);@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          NXIReportError(NXpData,"ERROR: HDF cannot close SDS interface");@\\
\mbox{}\verb@      }    @\\
\mbox{}\verb@@\\
\mbox{}\verb@      iRet = Hclose(pFile->iVID);@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          NXIReportError(NXpData,"ERROR: HDF cannot close HDF file");@\\
\mbox{}\verb@      }    @\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* release memory */@\\
\mbox{}\verb@      NXIKillDir(pFile);@\\
\mbox{}\verb@      free(pFile);@\\
\mbox{}\verb@      return NX_OK; @\\
\mbox{}\verb@  }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXmakegroup}
NXmakegroup creates a new Vgroup at the current level in the Vgroup
hierarchy. The new Vgroup will have the name Vgroup and have the class
descriptor NXclass. This call does not open the new group automatically.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXmakegroup(NXhandle fid, char *name, char *class)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@     pNexusFile pFile;@\\
\mbox{}\verb@     int32 iNew, iRet;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@     pFile = NXIassert(fid);     @\\
\mbox{}\verb@@\\
\mbox{}\verb@     /* create and configure the group */@\\
\mbox{}\verb@     iNew = Vattach(pFile->iVID,-1,"w");     @\\
\mbox{}\verb@     if(iNew < 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF could not create Vgroup");@\\
\mbox{}\verb@        return NX_ERROR;       @\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     Vsetname(iNew,name);@\\
\mbox{}\verb@     Vsetclass(iNew,class);@\\
\mbox{}\verb@   @\\
\mbox{}\verb@     /* insert it into the hierarchy, when apropriate */@\\
\mbox{}\verb@     if(pFile->iCurrentVG != 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@       iRet = Vinsert(pFile->iCurrentVG,iNew);@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     Vdetach(iNew);@\\
\mbox{}\verb@     if(iRet < 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF failed to insert Vgroup");@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXopengroup}
NXopengroup opens an existing Vgroup for writing and reading data to it.
This routine maintains the Vgroup stack. There are several possible
situations. The first is that we are at root level (iCurrentVG = 0). The
vGroup must be found and attatched to. Than the Stack has to be incremented.
The next situation is, that we are already in a Vgroup. Than we have to find
the new Vgroup, detach the current Vgroup and attach to the new one, thereby
incrementing the stack.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@   NXstatus NXopengroup(NXhandle fid, char *name, char *class)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int32 iNew, iRef;@\\
\mbox{}\verb@      char pBuffer[256];@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      iRef = NXIFindVgroup(pFile,name,class);@\\
\mbox{}\verb@      if(iRef < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sprintf(pBuffer,"ERROR: Vgroup %s, class %s NOT found",name,class);@\\
\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      } @\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* are we at root level ? */@\\
\mbox{}\verb@      if(pFile->iCurrentVG == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          pFile->iCurrentVG = Vattach(pFile->iVID,iRef,"w");@\\
\mbox{}\verb@          if(pFile->iCurrentVG < 0)@\\
\mbox{}\verb@          {@\\
\mbox{}\verb@            sprintf(pBuffer,"ERROR: cannot attach to vGroup %s",name);@\\
\mbox{}\verb@            NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@            return NX_ERROR;@\\
\mbox{}\verb@          }@\\
\mbox{}\verb@          pFile->iStackPtr++;@\\
\mbox{}\verb@          pFile->iStack[pFile->iStackPtr] = iRef;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          Vdetach(pFile->iCurrentVG);@\\
\mbox{}\verb@          pFile->iStackPtr++;@\\
\mbox{}\verb@          pFile->iStack[pFile->iStackPtr] = iRef;@\\
\mbox{}\verb@          pFile->iCurrentVG = Vattach(pFile->iVID,@\\
\mbox{}\verb@                                      pFile->iStack[pFile->iStackPtr],@\\
\mbox{}\verb@                                      "w");@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      NXIKillDir(pFile);@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@ }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXclosegroup}
NXclosegroup closes an open Vgroup and travels one back in the Vgroup
hierarchy. The usual hassle with the tons of different indices again.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap8}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXclosegroup(NXhandle fid)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* first catch the trivial case: we are at root and cannot get @\\
\mbox{}\verb@         deeper into a negative directory hierarchy (anti-directory)@\\
\mbox{}\verb@      */@\\
\mbox{}\verb@      if(pFile->iCurrentVG = 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIKillDir(pFile);@\\
\mbox{}\verb@         return NX_OK;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else  /* Sighhh. Some work to do */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         /* close the current VG and decrement stack */@\\
\mbox{}\verb@         Vdetach(pFile->iCurrentVG);@\\
\mbox{}\verb@         pFile->iStackPtr--;@\\
\mbox{}\verb@         if(pFile->iStackPtr <= 0) /* we hit root */@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            pFile->iStackPtr = 0;@\\
\mbox{}\verb@            pFile->iCurrentVG = 0;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         else@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            /* attach to the lower Vgroup */@\\
\mbox{}\verb@            pFile->iCurrentVG = Vattach(pFile->iVID,@\\
\mbox{}\verb@                                        pFile->iStack[pFile->iStackPtr],@\\
\mbox{}\verb@                                        "w");@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      NXIKillDir(pFile);@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXmakedata}
NXmakedata creates a new scientific datset. As argument it takes the usual filehandle,
Than there is an integer denoting the datatype. This needs to be one of the
HDF defined type identifiers. Commonly used types are: DFNT\_FLOAT for 32 bit
floats, DFNT\_INT32 for 32-bit integers, DFNT\_UINT8 for unsigned bytes (or
characters). rank is the dimensionality of the data. The parameter dims is
an integer array which has rank values. Each value denotes the length of the
data in the dimensions. Note that this function does not open a dataset.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap9}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXmakedata(NXhandle fid, char *name, int datatype, int rank, @\\
\mbox{}\verb@                       int dimensions[])@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int32 iNew;@\\
\mbox{}\verb@      char pBuffer[256];@\\
\mbox{}\verb@      int i, iRet;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* do some argument checking */@\\
\mbox{}\verb@      if( (datatype != DFNT_FLOAT32) && (datatype != DFNT_FLOAT64) &&@\\
\mbox{}\verb@          (datatype != DFNT_INT8)    && (datatype != DFNT_UINT8)  &&@\\
\mbox{}\verb@          (datatype != DFNT_INT16)    && (datatype != DFNT_UINT16)  &&@\\
\mbox{}\verb@          (datatype != DFNT_INT32)    && (datatype != DFNT_UINT32))@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sprintf(pBuffer,"ERROR: unknown datatype specified for SDS %s",@\\
\mbox{}\verb@                name);@\\
\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(rank <= 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sprintf(pBuffer,"ERROR: invalid rank specified for SDS %s",@\\
\mbox{}\verb@                name);@\\
\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      for(i = 0; i < rank; i++)@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@          if(dimensions[i] <= 0 )@\\
\mbox{}\verb@          {@\\
\mbox{}\verb@              sprintf(pBuffer,@\\
\mbox{}\verb@              "ERROR: invalid dimension %d, value %d given for SDS %s",@\\
\mbox{}\verb@               i,dimensions[i], name);@\\
\mbox{}\verb@              NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@              return NX_ERROR;@\\
\mbox{}\verb@          }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* behave nicely, if there is still an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         SDendaccess(pFile->iCurrentSDS);@\\
\mbox{}\verb@         pFile->iCurrentSDS = 0;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* dataset creation */@\\
\mbox{}\verb@      iNew = SDcreate(pFile->iSID,name,datatype,rank,dimensions);@\\
\mbox{}\verb@      if(iNew < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sprintf(pBuffer,"ERROR: cannot create SDS %s, check argumenst",@\\
\mbox{}\verb@                 name);@\\
\mbox{}\verb@         NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@         return NX_ERROR; @\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      /* link into Vgroup, if in one */@\\
\mbox{}\verb@      if(pFile->iCurrentVG != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = Vaddtagref(pFile->iCurrentVG,DFTAG_SDG,SDidtoref(iNew));@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      iRet = SDendaccess(iNew);@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXopendata}
NXopendata opens a scientific data set for further manipulation, i.e. reading
and writing of data or getting information about it. The scientific dataset
must exist. 
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap10}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@    NXstatus NXopendata(NXhandle fid, char *name)@\\
\mbox{}\verb@    {@\\
\mbox{}\verb@        pNexusFile pFile;@\\
\mbox{}\verb@        int32 iNew;  @\\
\mbox{}\verb@        char pBuffer[256];@\\
\mbox{}\verb@        int iRet;@\\
\mbox{}\verb@@\\
\mbox{}\verb@        pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@        /* first find the reference number of the SDS */@\\
\mbox{}\verb@        iNew = NXIFindSDS(fid,name);@\\
\mbox{}\verb@        if(iNew < 0) @\\
\mbox{}\verb@        {@\\
\mbox{}\verb@          sprintf(pBuffer,"ERROR: SDS %s not found at this level",name);@\\
\mbox{}\verb@          NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@          return NX_ERROR;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@@\\
\mbox{}\verb@        /* be nice: properly close the old open SDS silently if there is@\\
\mbox{}\verb@           still an SDS open.@\\
\mbox{}\verb@        */@\\
\mbox{}\verb@        if(pFile->iCurrentSDS)@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           iRet = SDendaccess(pFile->iCurrentSDS);@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        else@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           iRet = 1;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        if(iRet < 0)@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@@\\
\mbox{}\verb@       /* clear pending attribute directories first */@\\
\mbox{}\verb@        NXIKillDir(pFile);@\\
\mbox{}\verb@@\\
\mbox{}\verb@        /* open the SDS */@\\
\mbox{}\verb@        iNew = SDreftoindex(pFile->iSID, iNew);@\\
\mbox{}\verb@        pFile->iCurrentSDS = SDselect(pFile->iSID,iNew);@\\
\mbox{}\verb@        if(pFile->iCurrentSDS < 0)@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF error opening SDS");@\\
\mbox{}\verb@           pFile->iCurrentSDS = 0;@\\
\mbox{}\verb@           return NX_ERROR;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        return NX_OK;@\\
\mbox{}\verb@    }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXclosedata}
NXclosedata ends the access to the currently active scientific dataset.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap11}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXclosedata(NXhandle fid)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@       pNexusFile pFile;@\\
\mbox{}\verb@       int iRet;@\\
\mbox{}\verb@@\\
\mbox{}\verb@       pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@       if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@           iRet = SDendaccess(pFile->iCurrentSDS);@\\
\mbox{}\verb@           pFile->iCurrentSDS = 0;@\\
\mbox{}\verb@           if(iRet < 0)@\\
\mbox{}\verb@           {@\\
\mbox{}\verb@              NXIReportError(NXpData,"ERROR: HDF cannot end access to SDS");@\\
\mbox{}\verb@              return NX_ERROR;@\\
\mbox{}\verb@            }@\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       else@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@             NXIReportError(NXpData,"ERROR: no SDS open --> nothing to do");@\\
\mbox{}\verb@             return NX_ERROR;@\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       NXIKillDir(pFile); /* for attribute data */@\\
\mbox{}\verb@       return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsection{Reading and writing}
\label{ss:rw}

Routines to read and write data and attributes to previously opened datasets:

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap12}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@NXstatus  NXgetdata(NXhandle fileid, void* data);@\\
\mbox{}\verb@NXstatus  NXgetslab(NXhandle fileid, void* data, int start[], int size[]);@\\
\mbox{}\verb@NXstatus  NXgetattr(NXhandle fileid, char* name, char* data, int datalen);@\\
\mbox{}\verb@@\\
\mbox{}\verb@NXstatus  NXputdata(NXhandle fileid, void* data);@\\
\mbox{}\verb@NXstatus  NXputslab(NXhandle fileid, void* data, int start[], int size[]);@\\
\mbox{}\verb@NXstatus  NXputattr(NXhandle fileid, char* name, char* data, int datalen);@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
Please note, that all data reading and writing routines require that the
scientific dataset has been opened beforehand with NXopenadata. 

\subsubsection{NXgetdata}
NXgetdata reads data from the currently open scientific data set into
data. Please note, that memory overwrite occurs if the caller has not
allocated enough memory to hold all the data available. There are functions
in the section \ref{ss:meta} which allow to inquire the data size first.

Note as well that the scientific dataset must have been opened with
NXopendata before this function can succeed. Before it can do its job,
NXgetdata has to get dimension information first.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap13}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXgetdata(NXhandle fid, void *data)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int32 iStart[MAX_VAR_DIMS], iEnd[MAX_VAR_DIMS];@\\
\mbox{}\verb@      NXname pBuffer;@\\
\mbox{}\verb@      int32 iRank, iAtt, iType;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* check if there is an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* first read dimension information */@\\
\mbox{}\verb@      memset(iStart,0,MAX_VAR_DIMS*sizeof(int32));@\\
\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,&iRank,iEnd,&iType,&iAtt);@\\
\mbox{}\verb@      /* actually read */@\\
\mbox{}\verb@      SDreaddata(pFile->iCurrentSDS,iStart,NULL,iEnd,data);@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetslab}
NXgetslab reads a subset of the data in the current scientific data set.
The start dimensions to read from are specified in iStart, the end in iEnd.
The caller is responsable for allocation enough memory for data.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap14}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXgetslab(NXhandle fid, void *data, int iStart[], int iEnd[])@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* check if there is an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* actually read */@\\
\mbox{}\verb@      SDreaddata(pFile->iCurrentSDS,iStart,NULL,iEnd,data);@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetattr}
HDF has the concept of attributes. This is additional data which goes with
usually an SDS. Such attributes are used to denotes axis, units etc. The
other class of attributes are global attributes. This function reads such
attributes. If an SDS is open, it reads the attributes associated with the SDS, else
the it tries to find a global attribute. The data read is transfered to
data, but maximum datalen bytes. The caller is responsible for allocating at
least datalen bytes for data. In order to enable this scheme, NXgetattr
has to read the first into an internal temporary buffer before it copies the
data to the datat buffer provided. And discards with the temporary buffer.
Note that searching for attributes is handled differently if attributes at
global level are searched compared to searching attributes in an SDS.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap15}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXgetattr(NXhandle fid, char *name, char *data, int datalen)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int32 iNew;@\\
\mbox{}\verb@      void *pData = NULL;@\\
\mbox{}\verb@      int32 iLen, iType, iRet;@\\
\mbox{}\verb@      char pBuffer[256];@\\
\mbox{}\verb@      NXname pNam;      @\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* find attribute */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        /* SDS attribute */@\\
\mbox{}\verb@        iNew = SDfindattr(pFile->iCurrentSDS,name);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        /* global attribute */@\\
\mbox{}\verb@        iNew = SDfindattr(pFile->iSID,name);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(iNew < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        sprintf(pBuffer,"ERROR: attribute %s not found",name);@\\
\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }  @\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* get more info, allocate temporary data space */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = SDattrinfo(pFile->iCurrentSDS,iNew,pNam,&iType,&iLen);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = SDattrinfo(pFile->iSID,iNew,pNam,&iType,&iLen);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        sprintf(pBuffer,"ERROR: HDF could not read attribute info");@\\
\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      iLen = iLen*DFKNTsize(iType);  @\\
\mbox{}\verb@      pData = (void *)malloc(iLen);@\\
\mbox{}\verb@      if(!pData)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: allocating memory in NXgetattr");@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      memset(pData,0,iLen);@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* finally read the data */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = SDreadattr(pFile->iCurrentSDS,iNew,pData);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = SDreadattr(pFile->iSID,iNew,pData);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        sprintf(pBuffer,"ERROR: HDF could not read attribute data");@\\
\mbox{}\verb@        NXIReportError(NXpData,pBuffer);@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* copy data to caller */@\\
\mbox{}\verb@      memset(data,0,datalen);@\\
\mbox{}\verb@      if(datalen < iLen)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        iLen = datalen - 1;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      memcpy(data,pData,iLen);@\\
\mbox{}\verb@      free(pData);@\\
\mbox{}\verb@      return NX_OK; @\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXputdata}
NXputdata copies  data into the currently open scientific data set in the
HDF file. 

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap16}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXputdata(NXhandle fid, void *data)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int32 iStart[MAX_VAR_DIMS], iEnd[MAX_VAR_DIMS], iStride[MAX_VAR_DIMS];@\\
\mbox{}\verb@      NXname pBuffer;@\\
\mbox{}\verb@      int32 iRank, iAtt, iType, iRet, i;@\\
\mbox{}\verb@      char pError[512];@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* check if there is an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@     @\\
\mbox{}\verb@           @\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* first read dimension information */@\\
\mbox{}\verb@      memset(iStart,0,MAX_VAR_DIMS*sizeof(int32));@\\
\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,&iRank,iEnd,&iType,&iAtt);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* initialise stride to 1 */@\\
\mbox{}\verb@      for(i = 0; i < iRank; i++)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        iStride[i] = 1;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* actually write */@\\
\mbox{}\verb@      iRet = SDwritedata(pFile->iCurrentSDS,iStart,iStride,iEnd,data);@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sprintf(pError,"ERROR: failure to write data to %s",pBuffer);@\\
\mbox{}\verb@         NXIReportError(NXpData,pError);@\\
\mbox{}\verb@         return NX_ERROR; @\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXputslab}
NXputslab writes an subset of data as specified by iStart to iEnd into the
currently open SDS.
 
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap17}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXputslab(NXhandle fid, void *data, int iStart[], int iEnd[])@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int iRet;@\\
\mbox{}\verb@      int iStride[MAX_VAR_DIMS], i;@\\
\mbox{}\verb@     @\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* check if there is an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* initialise stride to 1 */@\\
\mbox{}\verb@      for(i = 0; i < MAX_VAR_DIMS; i++)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iStride[i] = 1;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* actually write */@\\
\mbox{}\verb@      iRet = SDwritedata(pFile->iCurrentSDS,iStart,iStride,iEnd,data);@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: writing slab failed");@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXputattr}
Nxputattr puts an attribute into an Nexus file.If an SDS is open, the SDS
will get the attribute. If not, a global attribute will be generated.
Attributes are name = value pairs. 

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap18}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXputattr(NXhandle fid, char *name, char *data, int datalen)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int iRet;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      if(pFile->iCurrentSDS != 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         /* SDS attribute */@\\
\mbox{}\verb@         iRet = SDsetattr(pFile->iCurrentSDS,name,DFNT_UINT8,@\\
\mbox{}\verb@                          datalen,data);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         /* global attribute */@\\
\mbox{}\verb@         iRet = SDsetattr(pFile->iSID,name,DFNT_UINT8,@\\
\mbox{}\verb@                          datalen, data);@\\
\mbox{}\verb@   @\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(iRet < 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDf failed to store attribute ");@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsection{Meta-data} 
\label{ss:meta}

Routines to obtain meta-data and to iterate over component datasets and attributes.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap19}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@NXstatus  NXgetinfo     (NXhandle fileid, int* rank, int dimension[], int* datatype);@\\
\mbox{}\verb@NXstatus  NXgetnextentry     (NXhandle fileid, NXname name, NXname class, int* datatype);@\\
\mbox{}\verb@NXstatus  NXgetnextattr(NXhandle fileid, NXname pName, int *iLength, int *iType);@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetinfo}
NXgetinfo gets information about an SDS. rank is the dimesionality of the
data, dimension will contain the size of the data in each dimension and
datatype results to one of the HDF--datatypes. The SDS has to be open in
order for this routine to work.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap20}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXgetinfo(NXhandle fid, int *rank,int dimension[], int *iType)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      NXname pBuffer;@\\
\mbox{}\verb@      int32  iAtt;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* check if there is an SDS open */@\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: no SDS open");@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      /* read information */@\\
\mbox{}\verb@      SDgetinfo(pFile->iCurrentSDS,pBuffer,rank,dimension,iType,&iAtt);@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetnextentry}
NXgetnextentry  implements a directory search facility on the current Vgroup
level. The first call will initialize Vgroup searching facilities and return
information on the first data item in the list. Subsequent calls will yield
information about the next item in the Vgroup. If the end of the list is
reached, NXgetentry will return NX\_EOD. Before, the usual NX\_ERROR or NX\_OK
are returned. Information returned is different for each type of data. For
Vgroups the name and class of the Vgroup will be returned, iType will be 0.
For scientific data sets, the name field will be the name, class will be SDS
and iType will denote the number type of the scientific data set. For types
not known to Nexus (but to HDF) both name and class will be set to
"UNKNOWN". 

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap21}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   int NXgetnextentry(NXhandle fid, NXname name, NXname class, int *datatype)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      int iRet;   @\\
\mbox{}\verb@      int32 iTemp, iD1, iD2, iA;@\\
\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* first case to check for: no directory entry */@\\
\mbox{}\verb@      if(pFile->iRefDir == NULL)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iRet = NXIInitDir(pFile);@\\
\mbox{}\verb@         if(iRet < 0)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@           NXIReportError(NXpData, @\\
\mbox{}\verb@            "ERROR: no memory to store directory info");@\\
\mbox{}\verb@           return -1;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* next case: end of directory */@\\
\mbox{}\verb@      if(pFile->iCurDir >= pFile->iNDir)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         NXIKillDir(pFile);@\\
\mbox{}\verb@         return NX_EOD;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* next case: we have data! suppy it and increment counter */@\\
\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        iTemp = Vattach(pFile->iVID,pFile->iRefDir[pFile->iCurDir],@\\
\mbox{}\verb@                        "r");@\\
\mbox{}\verb@        if(iTemp < 0)@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           NXIReportError(NXpData,"ERROR: HDF cannot attach to Vgroup");@\\
\mbox{}\verb@           return NX_ERROR;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        Vgetname(iTemp,name);@\\
\mbox{}\verb@        Vgetclass(iTemp,class);@\\
\mbox{}\verb@        *datatype = DFTAG_VG;@\\
\mbox{}\verb@        pFile->iCurDir++;@\\
\mbox{}\verb@        Vdetach(iTemp);@\\
\mbox{}\verb@        return NX_OK;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else /* in Vgroup */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        if(pFile->iTagDir[pFile->iCurDir] == DFTAG_VG) /* Vgroup */@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           iTemp = Vattach(pFile->iVID,pFile->iRefDir[pFile->iCurDir],@\\
\mbox{}\verb@                           "r");@\\
\mbox{}\verb@           if(iTemp < 0)@\\
\mbox{}\verb@           {@\\
\mbox{}\verb@              NXIReportError(NXpData,"ERROR: HDF cannot attach to Vgroup");@\\
\mbox{}\verb@              return NX_ERROR;@\\
\mbox{}\verb@           }@\\
\mbox{}\verb@           Vgetname(iTemp,name);@\\
\mbox{}\verb@           Vgetclass(iTemp,class);@\\
\mbox{}\verb@           *datatype = DFTAG_VG;@\\
\mbox{}\verb@           pFile->iCurDir++;@\\
\mbox{}\verb@           Vdetach(iTemp);@\\
\mbox{}\verb@           return NX_OK;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        else if( (pFile->iTagDir[pFile->iCurDir] == DFTAG_SDG) ||@\\
\mbox{}\verb@                 (pFile->iTagDir[pFile->iCurDir] == DFTAG_NDG) )@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@            iTemp = SDreftoindex(pFile->iSID, @\\
\mbox{}\verb@                                pFile->iRefDir[pFile->iCurDir]);@\\
\mbox{}\verb@            iTemp = SDselect(pFile->iSID,iTemp);@\\
\mbox{}\verb@            SDgetinfo(iTemp,name,&iA,iDim,&iD1, &iD2);@\\
\mbox{}\verb@            strcpy(class,"SDS");@\\
\mbox{}\verb@            *datatype = iD1;@\\
\mbox{}\verb@            SDendaccess(iTemp);@\\
\mbox{}\verb@            pFile->iCurDir++;@\\
\mbox{}\verb@            return NX_OK;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@        else /* unidentified */@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@          strcpy(name,"UNKNOWN");@\\
\mbox{}\verb@          strcpy(class,"UNKNOWN");@\\
\mbox{}\verb@          pFile->iCurDir++;@\\
\mbox{}\verb@          return NX_OK;@\\
\mbox{}\verb@        }      @\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_ERROR; /* not reached */@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetnextattr}
NXgetnextattr works very much like NXgetnextentry except, that it works on
SDS attributes and not on Vgroup entries. This function allows to scan the
names of attributes available. iLength will be filled with the length of the
attributes data in byte. iType will be filled with the HDF type of the
attribute. Be warned: this routine returns global attributes when no SDS is
currently open.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap22}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@  NXstatus  NXgetnextattr(NXhandle fileid, NXname pName, @\\
\mbox{}\verb@                          int *iLength, int *iType)@\\
\mbox{}\verb@  {@\\
\mbox{}\verb@     pNexusFile pFile;@\\
\mbox{}\verb@     int iRet;@\\
\mbox{}\verb@     int32 iPType, iCount;@\\
\mbox{}\verb@@\\
\mbox{}\verb@     pFile = NXIassert(fileid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@     /* first check if we have to start a new attribute search */@\\
\mbox{}\verb@     if(pFile->iNDir == 0) @\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        iRet = NXIInitAttDir(pFile);@\\
\mbox{}\verb@        if(iRet == NX_ERROR)@\\
\mbox{}\verb@        {@\\
\mbox{}\verb@           return NX_ERROR;@\\
\mbox{}\verb@        }@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     @\\
\mbox{}\verb@     /* are we done ? */@\\
\mbox{}\verb@     if(pFile->iCurDir >= pFile->iNDir)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIKillDir(pFile);@\\
\mbox{}\verb@        return NX_EOD;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     @\\
\mbox{}\verb@     /* well, there must be data to copy */@\\
\mbox{}\verb@     if(pFile->iCurrentSDS == 0) /* global attribute */@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        iRet = SDattrinfo(pFile->iSID,pFile->iCurDir, pName, &iPType,&iCount); @\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     else@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        iRet = SDattrinfo(pFile->iCurrentSDS,pFile->iCurDir,@\\
\mbox{}\verb@                          pName, &iPType,&iCount);@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     if(iRet < 0)@\\
\mbox{}\verb@     {@\\
\mbox{}\verb@        NXIReportError(NXpData,"ERROR: HDF cannot read attribute info");@\\
\mbox{}\verb@        return NX_ERROR;@\\
\mbox{}\verb@     }@\\
\mbox{}\verb@     *iLength = iCount*DFKNTsize(iPType);@\\
\mbox{}\verb@     *iType =   iPType;@\\
\mbox{}\verb@     pFile->iCurDir++;@\\
\mbox{}\verb@     return NX_OK;@\\
\mbox{}\verb@  }@\\
\mbox{}\verb@@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsection{ Handling of linking and group hierarchy}
\label{ss:link}

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap23}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@NXlink      NXgetgroupID(NXhandle fileid);@\\
\mbox{}\verb@NXlink      NXgetdataID(NXhandle fileid);@\\
\mbox{}\verb@NXstatus    NXmakelink(NXhandle fileid, NXlink link);@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{  NXgetgroupID}
NXgetgroupID retrieves the ID and tag of the currently open
Vgroup in an NXlink strcuture. In case of an error the iTag field of this
structure will contain NX\_ERROR.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap24}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXlink NXgetgroupID(NXhandle fileid)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      NXlink sRes;@\\
\mbox{}\verb@      @\\
\mbox{}\verb@      pFile = NXIassert(fileid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      if(pFile->iCurrentVG == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        sRes.iTag = NX_ERROR;@\\
\mbox{}\verb@        return sRes;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@        sRes.iTag = DFTAG_VG;@\\
\mbox{}\verb@        sRes.iRef = pFile->iCurrentVG;@\\
\mbox{}\verb@        return  sRes;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      /* not reached */@\\
\mbox{}\verb@      sRes.iTag = NX_ERROR;@\\
\mbox{}\verb@      return sRes;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{NXgetdataID}
NXgetdataID retrieves the tag and reference number of the current data
object. Returns NX\_ERROR if none is open.
 
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap25}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXlink NXgetdataID(NXhandle fid)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@      NXlink sRes;@\\
\mbox{}\verb@   @\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@     @\\
\mbox{}\verb@      if(pFile->iCurrentSDS == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         sRes.iTag = NX_ERROR;@\\
\mbox{}\verb@         return sRes;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@          sRes.iTag = DFTAG_SDS;@\\
\mbox{}\verb@          sRes.iRef = SDidtoref(pFile->iCurrentSDS);@\\
\mbox{}\verb@          return sRes;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      sRes.iTag = NX_ERROR;@\\
\mbox{}\verb@      return sRes; /* not reached */@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{ NXlink}
NXlink links a Vgroup or SDS into a Vgroup.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap26}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   NXstatus NXmakelink(NXhandle fid, NXlink sLink)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pFile;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      pFile = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level, can not link here */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@@\\
\mbox{}\verb@      if(sLink.iTag == DFTAG_VG)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         Vinsert(pFile->iCurrentVG,sLink.iRef);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      else @\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         Vaddtagref(pFile->iCurrentVG, sLink.iTag,sLink.iRef);@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsection{Internal routines}
There are a couple of internal Nexus API routines which are declared
static and are not visible outside of the module. First a few
defines.


\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap27}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@#include <stdlib.h>@\\
\mbox{}\verb@#include <assert.h>@\\
\mbox{}\verb@#include <string.h>@\\
\mbox{}\verb@#include "fortify.h"@\\
\mbox{}\verb@#include "napi.h"@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define NXMAXSTACK 50@\\
\mbox{}\verb@#define NXSIGNATURE 959697@\\
\mbox{}\verb@@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
MAXSTACK denotes the maximum depth of Vgroup stacking permissible. If there
are problems, feel free to increase this value and recompile. 50 is probably
fairly generous.

NXSIGNATURE is just the signature which the Nexus API will check for on
handles in order to prevent against tampering with the handles.

NXMAXNAME is the number of characters permitted for names and Vgroup names.

The internal function NXIassert will convert a filehandle to a pointer
to a NexusFile datastructure. Furthermore, it will check the signature and
throw an assertion, when the signature does not match.


\subsubsection{NX error handling}

As each piece of non trivial software the Nexus API needs a error handling
policy. The policy implemented is as follows: The NX routines terminate when
an invalid NXhandle has been specified. This is a serious programmer error.
In any other case the NX routines are meant to complain, recover and present
an NX-ERROR return to the higher level code. That code is than responsible
to deal with the problem. The problem left is error reporting. This is done
througout the code by a call to NXIReportError. This function takes as first
parameter a pointer to void and as next parameter the string with the
complaint. The default implementation of NXIReportError will print to
stdout. However, there are environments where this strategy is not feasible
because stdout is supported only in a very  strange way. Think about
operating system like MS-Windows, MAC-OS (going to die anyway) or other
windowing systems. In order to cater for this there is an inofficial support
function which allows to set both a pointer to a datastructure and a new
function for error reporting. This is called NXMSetError.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap28}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@   static void NXNXNXReportError(void *pData, char *string)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@       printf("%s \n",string);@\\
\mbox{}\verb@   }@\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@   static void *NXpData = NULL;@\\
\mbox{}\verb@   static void (*NXIReportError)(void *pData, char *string) =@\\
\mbox{}\verb@                NXNXNXReportError;@\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@   void NXMSetError(void *pData, void (*NewError)(void *pD, char *text))@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      NXpData = pData;@\\
\mbox{}\verb@      NXIReportError = NewError;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap29}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------*/@\\
\mbox{}\verb@   static pNexusFile NXIassert(NXhandle fid)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile pRes;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      assert(fid);@\\
\mbox{}\verb@      pRes = (pNexusFile)fid;@\\
\mbox{}\verb@      assert(pRes->iNXID == NXSIGNATURE);@\\
\mbox{}\verb@      return pRes;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{ Object finding dunctions}

Routines for finding objects in an HDF file have to cope with two quirks in
the HDF interface. The first is that the root level is no Vgroup. This
implies that the root level is searched for objects using different routines
than searching for objects in a Vgroup. The last one uses, of course, Vgroup
interface routines.

Finding routines have  to cope with the plethora of different integer
ID's for any given HDF object. See \ref{ididid} for more details. 


NXIFindVgroup searches the current Vgroup level in the file for the
occurence of a Vgroup with a specified name and of a specified class. If no
suitable Vgroup can be found NIXFinfVgroup returns -1, else the ID of the
Vgroup. 
NXIFindVgroup has to cope with the plethora of different integer
ID's for any give Vgroup. There is the Vgroup ID, than there is the
reference number which can be obtained by Vgettagref and which can refer to
any object in the HDF file. Additionally there is a Tag which denotes the
type of the object.  


\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap30}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@  static int32 NXIFindVgroup(pNexusFile pFile, char *name, char *class)@\\
\mbox{}\verb@  {@\\
\mbox{}\verb@      int32 iNew, iRef, iTag;@\\
\mbox{}\verb@      int iN, i;@\\
\mbox{}\verb@      int32 *pArray = NULL;@\\
\mbox{}\verb@      NXname pText;@\\
\mbox{}\verb@@\\
\mbox{}\verb@      assert(pFile);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      if(pFile->iCurrentVG == 0) /* root level */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         /* get the number and ID's of all lone Vgroups in the file */@\\
\mbox{}\verb@         iN = Vlone(pFile->iVID,NULL,0);@\\
\mbox{}\verb@         pArray = (int32 *)malloc(iN*sizeof(int32));@\\
\mbox{}\verb@         if(!pArray)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIFindVgroup");@\\
\mbox{}\verb@            return -1;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         Vlone(pFile->iVID,pArray,iN);@\\
\mbox{}\verb@      @\\
\mbox{}\verb@         /* loop and check */@\\
\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            iNew = Vattach(pFile->iVID,pArray[i],"r");@\\
\mbox{}\verb@            Vgetname(iNew, pText);@\\
\mbox{}\verb@            if(strcmp(pText,name) == 0)@\\
\mbox{}\verb@            {@\\
\mbox{}\verb@               Vgetclass(iNew,pText);@\\
\mbox{}\verb@               if(strcmp(pText,class) == 0)@\\
\mbox{}\verb@               {@\\
\mbox{}\verb@                  /* found !*/@\\
\mbox{}\verb@                  Vdetach(iNew);@\\
\mbox{}\verb@                  iNew = pArray[i];@\\
\mbox{}\verb@                  free(pArray);@\\
\mbox{}\verb@                  return iNew;@\\
\mbox{}\verb@               }@\\
\mbox{}\verb@            }@\\
\mbox{}\verb@            Vdetach(iNew);@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         /* nothing found */@\\
\mbox{}\verb@         free(pArray); @\\
\mbox{}\verb@         return -1;        @\\
\mbox{}\verb@      } @\\
\mbox{}\verb@      else /* case in Vgroup */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iN = Vntagrefs(pFile->iCurrentVG);@\\
\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            Vgettagref(pFile->iCurrentVG,i,&iTag, &iRef);@\\
\mbox{}\verb@            if(iTag == DFTAG_VG)@\\
\mbox{}\verb@            {@\\
\mbox{}\verb@               iNew = Vattach(pFile->iVID,iRef,"r");@\\
\mbox{}\verb@               Vgetname(iNew, pText);@\\
\mbox{}\verb@               if(strcmp(pText,name) == 0)@\\
\mbox{}\verb@               {@\\
\mbox{}\verb@                  Vgetclass(iNew,pText);@\\
\mbox{}\verb@                  if(strcmp(pText,class) == 0)@\\
\mbox{}\verb@                  {@\\
\mbox{}\verb@                     /* found !*/@\\
\mbox{}\verb@                     Vdetach(iNew);@\\
\mbox{}\verb@                     return iRef;@\\
\mbox{}\verb@                   }@\\
\mbox{}\verb@                }@\\
\mbox{}\verb@                Vdetach(iNew);@\\
\mbox{}\verb@            }@\\
\mbox{}\verb@         } /* end for */ @\\
\mbox{}\verb@      } /* end else */    @\\
\mbox{}\verb@      /* not found */@\\
\mbox{}\verb@      return -1;@\\
\mbox{}\verb@  }  @\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
NXIFindSDS searches the current Vgroup level for an SDS  name. It returns
the reference ID of the SDS when found and -1 when no SDS of this name can 
be found on this level.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap31}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   static int32 NXIFindSDS(NXhandle fid, char *name)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      pNexusFile self;@\\
\mbox{}\verb@      int32 iNew, iRet, iTag, iRef;@\\
\mbox{}\verb@      int32 i, iN, iA, iD1, iD2;@\\
\mbox{}\verb@      NXname pNam;@\\
\mbox{}\verb@      int32 iDim[MAX_VAR_DIMS];@\\
\mbox{}\verb@@\\
\mbox{}\verb@      self = NXIassert(fid);@\\
\mbox{}\verb@@\\
\mbox{}\verb@      /* root level search */@\\
\mbox{}\verb@      if(self->iCurrentVG == 0)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         i = SDfileinfo(self->iSID,&iN,&iA);@\\
\mbox{}\verb@         if(i < 0)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            NXIReportError(NXpData, "ERROR: failure to read file information");@\\
\mbox{}\verb@            return -1;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@           iNew = SDselect(self->iSID,i);@\\
\mbox{}\verb@           SDgetinfo(iNew,pNam,&iA,iDim,&iD2, &iD2);@\\
\mbox{}\verb@           if(strcmp(pNam,name) == 0)@\\
\mbox{}\verb@           {@\\
\mbox{}\verb@              iRet = SDidtoref(iNew);@\\
\mbox{}\verb@              SDendaccess(iNew);@\\
\mbox{}\verb@              return iRet;@\\
\mbox{}\verb@           } @\\
\mbox{}\verb@           else@\\
\mbox{}\verb@           {@\\
\mbox{}\verb@               SDendaccess(iNew);@\\
\mbox{}\verb@           }@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         /* not found */@\\
\mbox{}\verb@         return -1;@\\
\mbox{}\verb@      }/* end root level */@\\
\mbox{}\verb@      else /* search in a Vgroup */@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         iN = Vntagrefs(self->iCurrentVG);@\\
\mbox{}\verb@         for(i = 0; i < iN; i++)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            Vgettagref(self->iCurrentVG,i,&iTag, &iRef);@\\
\mbox{}\verb@            if( (iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || @\\
\mbox{}\verb@                (iTag == DFTAG_SDS) )@\\
\mbox{}\verb@            {@\\
\mbox{}\verb@               iNew = SDreftoindex(self->iSID, iRef);@\\
\mbox{}\verb@               iNew = SDselect(self->iSID,iNew);@\\
\mbox{}\verb@               SDgetinfo(iNew,pNam,&iA,iDim,&iD2, &iD2);@\\
\mbox{}\verb@               if(strcmp(pNam,name) == 0)@\\
\mbox{}\verb@               {@\\
\mbox{}\verb@                  SDendaccess(iNew);@\\
\mbox{}\verb@                  return iRef;@\\
\mbox{}\verb@               }@\\
\mbox{}\verb@               SDendaccess(iNew);@\\
\mbox{}\verb@            }@\\
\mbox{}\verb@         } /* end for */ @\\
\mbox{}\verb@      }   /* end Vgroup */@\\
\mbox{}\verb@      /* we get here, only if nothing found */@\\
\mbox{}\verb@      return -1;      @\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{Helper routines for directory search}
NXIInitDir initialises the directory data fields in the Nexus File structure
for a subsequent directory request. Please note, that at root level only
Vgroups will be searched. When searching SDS's at root level, all SDS's in 
the whole
file seem to be returned.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap32}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   static int NXIInitDir(pNexusFile self)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@       int i;@\\
\mbox{}\verb@       int32 iTag, iRef;@\\
\mbox{}\verb@@\\
\mbox{}\verb@       if(self->iCurrentVG == 0) /* root level */@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@         /* get the number and ID's of all lone Vgroups in the file */@\\
\mbox{}\verb@         self->iNDir = Vlone(self->iVID,NULL,0);@\\
\mbox{}\verb@         self->iRefDir  = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
\mbox{}\verb@         if(!self->iRefDir)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIInitDir");@\\
\mbox{}\verb@            return -1;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         Vlone(self->iVID,self->iRefDir,self->iNDir);@\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       else@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@          /* Vgroup level */@\\
\mbox{}\verb@         self->iNDir  = Vntagrefs(self->iCurrentVG);@\\
\mbox{}\verb@         self->iRefDir = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
\mbox{}\verb@         self->iTagDir = (int32 *)malloc(self->iNDir*sizeof(int32));@\\
\mbox{}\verb@         if( (!self->iRefDir) || (!self->iTagDir))@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            NXIReportError(NXpData,"ERROR: out of memory in NXIInitDir");@\\
\mbox{}\verb@            return -1;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@         for(i = 0; i < self->iNDir; i++)@\\
\mbox{}\verb@         {@\\
\mbox{}\verb@            Vgettagref(self->iCurrentVG,i,&iTag, &iRef);@\\
\mbox{}\verb@            self->iRefDir[i] = iRef;@\\
\mbox{}\verb@            self->iTagDir[i] = iTag;@\\
\mbox{}\verb@         }@\\
\mbox{}\verb@       }       @\\
\mbox{}\verb@       self->iCurDir = 0;@\\
\mbox{}\verb@       return 1;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
NXIKillDir removes all data associated with a directory search from 
 memory.

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap33}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@   static void NXIKillDir(pNexusFile self)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@      if(self->iRefDir)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         free(self->iRefDir);@\\
\mbox{}\verb@         self->iRefDir = NULL;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      if(self->iTagDir)@\\
\mbox{}\verb@      {@\\
\mbox{}\verb@         free(self->iTagDir);@\\
\mbox{}\verb@         self->iTagDir = NULL;@\\
\mbox{}\verb@      }@\\
\mbox{}\verb@      self->iCurDir = 0;@\\
\mbox{}\verb@      self->iNDir = 0;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
NXIInitAttDir will initialise the counters for reading either SDS or global 
attribute data. 

\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap34}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@   static int NXIInitAttDir(pNexusFile pFile)@\\
\mbox{}\verb@   {@\\
\mbox{}\verb@       int iRet;@\\
\mbox{}\verb@       int32 iData, iAtt, iRank, iType;@\\
\mbox{}\verb@       int32 iDim[MAX_VAR_DIMS];@\\
\mbox{}\verb@       NXname pNam;@\\
\mbox{}\verb@@\\
\mbox{}\verb@       pFile->iCurDir = 0;@\\
\mbox{}\verb@       if(pFile->iCurrentSDS != 0) /* SDS level */@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@         iRet = SDgetinfo(pFile->iCurrentSDS,pNam, &iRank, iDim,&iType, @\\
\mbox{}\verb@                          &iAtt); @\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       else /* global level */@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@         iRet = SDfileinfo(pFile->iSID,&iData,&iAtt);  @\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       if(iRet < 0)@\\
\mbox{}\verb@       {@\\
\mbox{}\verb@         NXIReportError(NXpData,"ERROR: HDF cannot read attribute numbers");@\\
\mbox{}\verb@         pFile->iNDir = 0;@\\
\mbox{}\verb@         return NX_ERROR;@\\
\mbox{}\verb@       }@\\
\mbox{}\verb@       pFile->iNDir = iAtt;@\\
\mbox{}\verb@       return NX_OK;@\\
\mbox{}\verb@   }@\\
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap35}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@                            Nexus API header file@\\
\mbox{}\verb@@\\
\mbox{}\verb@   copyleft: Mark Koennecke, March 1997 at LNS,PSI, Switzerland@\\
\mbox{}\verb@             Przemek Klosowski, U. of Maryland & NIST, USA       @\\
\mbox{}\verb@@\\
\mbox{}\verb@   No warranties of any kind taken.@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef NEXUSAPI@\\
\mbox{}\verb@#define NEXUSAPI@\\
\mbox{}\verb@@\\
\mbox{}\verb@#include <mfhdf.h>@\\
\mbox{}\verb@@\\
\mbox{}\verb@typedef enum {NXACC_READ = DFACC_READ, @\\
\mbox{}\verb@              NXACC_RDWR = DFACC_RDWR, @\\
\mbox{}\verb@              NXACC_CREATE = DFACC_CREATE } NXaccess;@\\
\mbox{}\verb@typedef void *  NXhandle;@\\
\mbox{}\verb@typedef int  NXstatus;@\\
\mbox{}\verb@typedef char NXname[VGNAMELENMAX];@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define NX_OK 1@\\
\mbox{}\verb@#define NX_ERROR 0@\\
\mbox{}\verb@#define NX_EOD -1@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@                HDF Datatype values for datatype parameters @\\
\mbox{}\verb@                       in the Nexus API@\\
\mbox{}\verb@@\\
\mbox{}\verb@  DFNT_FLOAT32     32 bit float@\\
\mbox{}\verb@  DFNT_FLOAT64     64 nit float == double@\\
\mbox{}\verb@  DFNT_INT8        8 bit integer ==char, byte@\\
\mbox{}\verb@  DFNT_UINT8       8 bit unsigned integer@\\
\mbox{}\verb@  DFNT_INT16       16 bit integer@\\
\mbox{}\verb@  DFNT_UINT16      16 bit unsigned integer@\\
\mbox{}\verb@  DFNT_INT32       32 bit integer@\\
\mbox{}\verb@  DFNT_UINT32      32 bit unsigned integer@\\
\mbox{}\verb@@\\
\mbox{}\verb@  This list is a edited version of the one found in the HDF header file@\\
\mbox{}\verb@  htndefs.h. That source will always be the real reference, this is@\\
\mbox{}\verb@  documented here for your convenience.@\\
\mbox{}\verb@--------------------------------------------------------------------------*/ @\\
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@    A non Nexus standars function to set an error handler @\\
\mbox{}\verb@*/@\\
\mbox{}\verb@  void NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text));@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap36}
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@                         Nexus API implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@  For documentation see the Napi.tex file which comes with this @\\
\mbox{}\verb@  distribution.@\\
\mbox{}\verb@@\\
\mbox{}\verb@  copyleft: Mark Koennecke@\\
\mbox{}\verb@            Labor fuer Neutronenstreuung@\\
\mbox{}\verb@            Paul Scherrer Institut@\\
\mbox{}\verb@            CH-5232 Villigen-PSI@\\
\mbox{}\verb@            Switzerland@\\
\mbox{}\verb@            Mark.Koenencke@{\tt @}\verb@psi.ch@\\
\mbox{}\verb@            Przemek Klosowski@\\
\mbox{}\verb@            U. of Maryland & NIST        @\\
\mbox{}\verb@            przemek.klosowski@{\tt @}\verb@nist.gov @\\
\mbox{}\verb@@\\
\mbox{}\verb@  no warranties of any kind, whether explicit or implied, taken.@\\
\mbox{}\verb@  Distributed under the GNU copyleft license as documented elsewhere.@\\
\mbox{}\verb@@\\
\mbox{}\verb@  March 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@  Version: 1.0@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\end{document}
