- Fixed a bug fix with Fixed motor in TAS code

- Made AMOR write HDF-5 data in chunks
- Added  driver for a PSI-DSP magnet controller as used at SLS
- Added code for directly accessing RS232 controllers connected to a
  terminal server, thereby bypassing the SerPortServer
- A rounding problem in the PSD histogram memory was resolved.
This commit is contained in:
cvs
2001-10-25 13:57:59 +00:00
parent 22688ac0fc
commit 3c916c9a7d
32 changed files with 2247 additions and 758 deletions

302
napi.c
View File

@@ -35,7 +35,7 @@
----------------------------------------------------------------------------*/
static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /* Revision interted by CVS */
static const char* rscid = "$Id: napi.c,v 1.5 2001/10/25 13:58:00 cvs Exp $"; /* Revision interted by CVS */
#include <stdlib.h>
#include <assert.h>
@@ -70,13 +70,24 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*---------------------------------------------------------------------*/
static void NXNXNXReportError(void *pData, char *string)
{
printf("%s \n",string);
#if defined(_WIN32) && ( defined(_DLL) || defined(_HDFDLL_) ) && !defined(_CONSOLE) && !defined(JNEXUS)
/*
* printf() output may get lost in Windows applications without a console ... this code
* makes them appear in Dialog boxes. To use printf(), you would probably have to create
* a console window with AllocConsole(), or get hold of "stdout" from the main program
* and then use fprintf(main_program_stdout, ... ) rather then printf(...)
*/
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(NULL, string, "NeXus Error", MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
#else
printf("%s \n",string);
#endif /* _WIN32 */
}
/*---------------------------------------------------------------------*/
void *NXpData = NULL;
void (*NXIReportError)(void *pData, char *string) = NXNXNXReportError;
/*---------------------------------------------------------------------*/
void NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
{
NXpData = pData;
NXIReportError = NewError;
@@ -321,7 +332,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
* NXhandle. We could store the NXhandle value in the FORTRAN array
* instead, but that would mean writing far more wrappers
*/
NXstatus NXfopen(char * filename, NXaccess* am, NexusFile* pHandle)
NXstatus CALLING_STYLE NXfopen(char * filename, NXaccess* am, NexusFile* pHandle)
{
NXstatus ret;
NXhandle fileid = NULL;
@@ -341,24 +352,17 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return ret;
}
/*
* the following deals with how we do our timezone calculation.
* Not all systems have a timezone field as part of "struct tm"
* that is passed to localtime(), so we need to look elsewhere
*
* If you encounter problems, try defining USE_FTIME first, with
* NEED_TZSET is your system provides the tzset() function
/*
* On Open VMS prior to version 7.0 timezone support wasn't complete and gmtime() always returned NULL
*/
#if defined(_WIN32)
# define NEED_TZSET /* call tzset() to initialise time variables */
# define USE_TIMEZONE /* use timezone and daylight variables */
#elif (defined(__VMS) && (__VMS_VER < 70000000))
#if (defined(__VMS) && (__VMS_VER < 70000000))
# define USE_FTIME /* use ftime() function */
# include <sys/timeb.h>
#endif /* __VMS && __VMS_VER < 70000000 */
NXstatus NXopen(CONSTCHAR * filename, NXaccess am, NXhandle* pHandle)
/* #define NEED_TZSET /* probably not needed now as we do not use the "timezone" external variable */
NXstatus CALLING_STYLE NXopen(CONSTCHAR * filename, NXaccess am, NXhandle* pHandle)
{
pNexusFile pNew = NULL;
char pBuffer[512], time_buffer[64];
@@ -387,21 +391,26 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
tzset();
#endif /* NEED_TZSET */
time(&timer);
time_info = localtime(&timer);
#if defined(USE_TIMEZONE)
gmt_offset = -timezone + ( (daylight != 0) ? 3600 : 0 );
#elif defined(USE_FTIME)
#ifdef USE_FTIME
ftime(&timeb_struct);
gmt_offset = -timeb_struct.timezone * 60;
if (timeb_struct.dstflag != 0)
{
gmt_offset += 3600;
}
#elif defined(__MWERKS__)
gmt_offset = difftime (timer, mktime(gmtime(&timer)));
#else
gmt_offset = time_info->tm_gmtoff;
#endif
time_info = gmtime(&timer);
if (time_info != NULL)
{
gmt_offset = difftime(timer, mktime(time_info));
}
else
{
NXIReportError(NXpData, "Your gmtime() function does not work ... timezone information will be incorrect\n");
gmt_offset = 0;
}
#endif /* USE_FTIME */
time_info = localtime(&timer);
if (time_info != NULL)
{
if (gmt_offset < 0)
@@ -507,7 +516,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
/* start Vgroup API */
pNew->iVID = Hopen (filename, am, 5000);
pNew->iVID = Hopen (filename, am, 100);
if (pNew->iVID <= 0) {
sprintf (pBuffer, "ERROR: cannot open file: %s", filename);
NXIReportError (NXpData, pBuffer);
@@ -528,8 +537,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
* array holding the NexusFile structure. We need to malloc()
* a temporary copy as NXclose will try to free() this
*/
NXstatus
NXfclose (NexusFile* pHandle)
NXstatus CALLING_STYLE NXfclose (NexusFile* pHandle)
{
NXhandle h;
NXstatus ret;
@@ -540,8 +548,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return ret;
}
NXstatus
NXclose (NXhandle* fid)
NXstatus CALLING_STYLE NXclose (NXhandle* fid)
{
pNexusFile pFile = NULL;
int iRet;
@@ -574,9 +581,102 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
*fid = NULL;
return NX_OK;
}
/*---------------------------------------------------------------------------
For the same reasons as stated above we need a wrapper for the fortran
version of NXFlush
---------------------------------------------------------------------------*/
NXstatus CALLING_STYLE NXfflush(NexusFile* pHandle)
{
NXhandle h;
NXstatus ret;
h = (NXhandle)malloc(sizeof(NexusFile));
memcpy(h, pHandle, sizeof(NexusFile));
ret = NXflush(&h); /* modifies and reallocates h */
memcpy(pHandle, h, sizeof(NexusFile));
return ret;
}
/*----------------------------------------------------------------------*/
NXstatus CALLING_STYLE NXflush(NXhandle *pHandle)
{
char *pFileName, *pCopy = NULL;
int access, dummy, iRet, i, iStack;
pNexusFile pFile = NULL;
NXaccess ac;
int *iRefs = NULL;
pFile = NXIassert(*pHandle);
/*
The HDF4-API does not support a flush. We help ourselves with
inquiring the name and access type of the file, closing it and
opening it again. This is also the reason why this needs a pointer
to the handle structure as the handle changes. The other thing we
do is to store the refs of all open vGroups in a temporary array
in order to recover the position in the vGroup hierarchy before the
flush.
*/
iRet = Hfidinquire(pFile->iVID,&pFileName,&access,&dummy);
if (iRet < 0) {
NXIReportError (NXpData,
"ERROR: Failed to inquire file name for HDF file");
return NX_ERROR;
}
if(pFile->iAccess[0] == 'r') {
ac = NXACC_READ;
}else if(pFile->iAccess[0] == 'w') {
ac = NXACC_RDWR;
}
pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
if(!pCopy) {
NXIReportError (NXpData,
"ERROR: Failed to allocate data for filename copy");
return NX_ERROR;
}
memset(pCopy,0,strlen(pFileName)+10);
strcpy(pCopy,pFileName);
/* get refs for recovering vGroup position */
iStack = 0;
if(pFile->iStackPtr > 0) {
iStack = pFile->iStackPtr + 1;
iRefs = (int *)malloc(iStack*sizeof(int));
if(!iRefs){
NXIReportError (NXpData,
"ERROR: Failed to allocate data for hierarchy copy");
return NX_ERROR;
}
for(i = 0; i < iStack; i++){
iRefs[i] = pFile->iStack[i].iVref;
}
}
iRet = NXclose(pHandle);
if(iRet != NX_OK) {
return iRet;
}
iRet = NXopen(pCopy, ac, pHandle);
free(pCopy);
NXstatus NXmakegroup (NXhandle fid, CONSTCHAR *name, char *nxclass) {
/* return to position in vGroup hierarchy */
pFile = NXIassert(*pHandle);
if(iStack > 0){
pFile->iStackPtr = iStack - 1;
for(i = 0; i < iStack; i++){
pFile->iStack[i].iVref = iRefs[i];
}
free(iRefs);
pFile->iCurrentVG = Vattach(pFile->iVID,
pFile->iStack[pFile->iStackPtr].iVref,
pFile->iAccess);
}
return iRet;
}
/*-----------------------------------------------------------------------*/
NXstatus CALLING_STYLE NXmakegroup (NXhandle fid, CONSTCHAR *name, char *nxclass)
{
pNexusFile pFile;
int32 iNew, iRet;
char pBuffer[256];
@@ -617,8 +717,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*------------------------------------------------------------------------*/
NXstatus
NXopengroup (NXhandle fid, CONSTCHAR *name, char *nxclass)
NXstatus CALLING_STYLE NXopengroup (NXhandle fid, CONSTCHAR *name, char *nxclass)
{
pNexusFile pFile;
int32 iNew, iRef;
@@ -650,8 +749,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXclosegroup (NXhandle fid)
NXstatus CALLING_STYLE NXclosegroup (NXhandle fid)
{
pNexusFile pFile;
@@ -681,7 +779,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_OK;
}
NXstatus NXfmakedata(NXhandle fid, char *name, int *pDatatype,
NXstatus CALLING_STYLE NXfmakedata(NXhandle fid, char *name, int *pDatatype,
int *pRank, int dimensions[])
{
NXstatus ret;
@@ -706,7 +804,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return ret;
}
NXstatus NXmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
NXstatus CALLING_STYLE NXmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
int dimensions[])
{
pNexusFile pFile;
@@ -750,7 +848,12 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
NXIReportError (NXpData, pBuffer);
return NX_ERROR;
}
for (i = 0; i < rank; i++) {
/*
Check dimensions for consistency. The first dimension may be 0
thus denoting an unlimited dimension.
*/
for (i = 1; i < rank; i++) {
if (dimensions[i] <= 0) {
sprintf (pBuffer,
"ERROR: invalid dimension %d, value %d given for SDS %s",
@@ -802,8 +905,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXopendata (NXhandle fid, CONSTCHAR *name)
NXstatus CALLING_STYLE NXopendata (NXhandle fid, CONSTCHAR *name)
{
pNexusFile pFile;
int32 iNew;
@@ -843,13 +945,12 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus NXfcompress(NXhandle fid, int *compr_type)
NXstatus CALLING_STYLE NXfcompress(NXhandle fid, int *compr_type)
{
return NXcompress(fid,*compr_type);
}
NXstatus
NXcompress (NXhandle fid, int compress_type)
NXstatus CALLING_STYLE NXcompress (NXhandle fid, int compress_type)
{
pNexusFile pFile;
int32 iRank, iAtt, iType, iRet, i, e;
@@ -892,8 +993,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_OK;
}
NXstatus
NXclosedata (NXhandle fid)
NXstatus CALLING_STYLE NXclosedata (NXhandle fid)
{
pNexusFile pFile;
int iRet;
@@ -916,8 +1016,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXgetdata (NXhandle fid, void *data)
NXstatus CALLING_STYLE NXgetdata (NXhandle fid, void *data)
{
pNexusFile pFile;
int32 iStart[MAX_VAR_DIMS], iSize[MAX_VAR_DIMS];
@@ -940,8 +1039,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXgetslab (NXhandle fid, void *data, int iStart[], int iSize[])
NXstatus CALLING_STYLE NXgetslab (NXhandle fid, void *data, int iStart[], int iSize[])
{
pNexusFile pFile;
int32 myStart[MAX_VAR_DIMS], mySize[MAX_VAR_DIMS];
@@ -983,11 +1081,10 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXgetattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
NXstatus CALLING_STYLE NXgetattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
{
pNexusFile pFile;
int32 iNew;
int32 iNew, iType32;
void *pData = NULL;
int32 iLen, iRet;
char pBuffer[256];
@@ -1010,11 +1107,13 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_ERROR;
}
/* get more info, allocate temporary data space */
iType32 = (int32)*iType;
if (pFile->iCurrentSDS != 0) {
iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, (int32*)iType, &iLen);
iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen);
} else {
iRet = SDattrinfo (pFile->iSID, iNew, pNam, (int32*)iType, &iLen);
iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
}
*iType = (int)iType32;
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute info");
NXIReportError (NXpData, pBuffer);
@@ -1050,46 +1149,8 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_OK;
}
NXstatus
NXsetdimname(NXhandle fid, int iDim, CONSTCHAR *name)
{
pNexusFile pFile;
int32 dim_id, iRet;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXIReportError (NXpData, "ERROR: no SDS open");
return NX_ERROR;
}
/*
get dimension ID
*/
dim_id = SDgetdimid(pFile->iCurrentSDS,iDim);
if(dim_id < 0){
NXIReportError(NXpData,
"ERROR: trying to set dimension name for non existent dimension");
return NX_ERROR;
}
/*
set name
*/
iRet = SDsetdimname(dim_id,name);
if(iRet < 0){
NXIReportError(NXpData,
"ERROR: failed to set dimension name");
return NX_ERROR;
}
return NX_OK;
}
NXstatus
NXputdata (NXhandle fid, void *data)
NXstatus CALLING_STYLE NXputdata (NXhandle fid, void *data)
{
pNexusFile pFile;
int32 iStart[MAX_VAR_DIMS], iSize[MAX_VAR_DIMS], iStride[MAX_VAR_DIMS];
@@ -1124,8 +1185,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_OK;
}
NXstatus
NXputslab (NXhandle fid, void *data, int iStart[], int iSize[])
NXstatus CALLING_STYLE NXputslab (NXhandle fid, void *data, int iStart[], int iSize[])
{
pNexusFile pFile;
int iRet;
@@ -1167,8 +1227,8 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
else
{
/* write directly */
iRet = SDwritedata (pFile->iCurrentSDS, (int32 *) iStart,
iStride, (int32 *) iSize, data);
iRet = SDwritedata (pFile->iCurrentSDS,(int32*)iStart,
iStride, (int32*)iSize, data);
}
/* deal with HDF errors */
@@ -1179,14 +1239,13 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_OK;
}
NXstatus
NXfputattr(NXhandle fid, char *name, void *data, int *pDatalen, int *pIType)
NXstatus CALLING_STYLE NXfputattr(NXhandle fid, char *name, void *data, int *pDatalen, int *pIType)
{
return NXputattr(fid, name, data, *pDatalen, *pIType);
}
NXstatus
NXputattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType)
CALLING_STYLE NXputattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType)
{
pNexusFile pFile;
int iRet;
@@ -1212,7 +1271,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
NXstatus
NXgetinfo (NXhandle fid, int *rank, int dimension[], int *iType)
CALLING_STYLE NXgetinfo (NXhandle fid, int *rank, int dimension[], int *iType)
{
pNexusFile pFile;
NXname pBuffer;
@@ -1241,7 +1300,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*-------------------------------------------------------------------------*/
NXstatus
NXgetgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
CALLING_STYLE NXgetgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
{
pNexusFile pFile;
@@ -1262,7 +1321,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*-------------------------------------------------------------------------*/
NXstatus
NXgetattrinfo (NXhandle fid, int *iN)
CALLING_STYLE NXgetattrinfo (NXhandle fid, int *iN)
{
pNexusFile pFile;
int iRet;
@@ -1287,7 +1346,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
NXstatus
NXinitgroupdir (NXhandle fid)
CALLING_STYLE NXinitgroupdir (NXhandle fid)
{
pNexusFile pFile;
int iRet;
@@ -1305,7 +1364,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*-------------------------------------------------------------------------*/
NXstatus
NXgetnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
CALLING_STYLE NXgetnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
{
pNexusFile pFile;
int iRet, iStackPtr, iCurDir;
@@ -1385,7 +1444,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*-------------------------------------------------------------------------*/
NXstatus
NXinitattrdir (NXhandle fid)
CALLING_STYLE NXinitattrdir (NXhandle fid)
{
pNexusFile pFile;
int iRet;
@@ -1400,7 +1459,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
/*-------------------------------------------------------------------------*/
NXstatus
NXgetnextattr (NXhandle fileid, NXname pName,
CALLING_STYLE NXgetnextattr (NXhandle fileid, NXname pName,
int *iLength, int *iType)
{
pNexusFile pFile;
@@ -1441,7 +1500,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
NXstatus
NXgetgroupID (NXhandle fileid, NXlink* sRes)
CALLING_STYLE NXgetgroupID (NXhandle fileid, NXlink* sRes)
{
pNexusFile pFile;
@@ -1452,7 +1511,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_ERROR;
} else {
sRes->iTag = DFTAG_VG;
sRes->iRef = VQueryref(pFile->iCurrentVG);
sRes->iRef = pFile->iStack[pFile->iStackPtr].iVref;
return NX_OK;
}
/* not reached */
@@ -1462,7 +1521,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
NXstatus
NXgetdataID (NXhandle fid, NXlink* sRes)
CALLING_STYLE NXgetdataID (NXhandle fid, NXlink* sRes)
{
pNexusFile pFile;
@@ -1480,23 +1539,31 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
return NX_ERROR; /* not reached */
}
NXstatus
NXmakelink (NXhandle fid, NXlink* sLink)
NXstatus CALLING_STYLE NXmakelink (NXhandle fid, NXlink* sLink)
{
pNexusFile pFile;
int32 iVG, iRet;
pFile = NXIassert (fid);
if (pFile->iCurrentVG == 0) { /* root level, can not link here */
return NX_ERROR;
}
Vaddtagref (pFile->iCurrentVG, sLink->iTag, sLink->iRef);
if(sLink->iTag == DFTAG_VG)
{
iVG = Vattach (pFile->iVID, sLink->iRef,pFile->iAccess);
iRet = Vinsert(pFile->iCurrentVG,iVG);
iRet = Vdetach(iVG);
}
else
{
Vaddtagref (pFile->iCurrentVG, sLink->iTag, sLink->iRef);
}
return NX_OK;
}
/* allocate space for an array of given dimensions and type */
NXstatus
NXmalloc (void** data, int rank, int dimensions[], int datatype)
NXstatus CALLING_STYLE NXmalloc (void** data, int rank, int dimensions[], int datatype)
{
int i;
size_t size = 1;
@@ -1536,8 +1603,7 @@ static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /*
}
/* free space allocated by NXmalloc */
NXstatus
NXfree (void** data)
NXstatus CALLING_STYLE NXfree (void** data)
{
if (data == NULL)
{