stream.c 49.8 KB
Newer Older
1
2
#ifdef  HAVE_CONFIG_H
#include "config.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
3
4
#endif

5
6
7
8
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif

9
#include <sys/stat.h> // struct stat
Uwe Schulzweida's avatar
Uwe Schulzweida committed
10
11
#include <ctype.h>

12
#include "binary.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
13
#include "cdi.h"
14
#include "cdi_int.h"
15
#include "cdi_cksum.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
16
#include "cdf.h"
17
18
#include "dmemory.h"
#include "error.h"
19
#include "stream_cgribex.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
20
#include "stream_grb.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
21
22
23
24
25
#include "stream_cdf.h"
#include "stream_srv.h"
#include "stream_ext.h"
#include "stream_ieg.h"
#include "file.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
#include "cgribex.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
#include "gribapi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
28
#include "vlist.h"
29
#include "serialize.h"
30
#include "resource_handle.h"
31
#include "resource_unpack.h"
32
33
#include "namespace.h"

34

35
static stream_t *stream_new_entry(int resH);
36
static void stream_delete_entry(stream_t *streamptr);
37
38
39
40
41
42
static int streamCompareP(void * streamptr1, void * streamptr2);
static void streamDestroyP(void * streamptr);
static void streamPrintP(void * streamptr, FILE * fp);
static int streamGetPackSize(void * streamptr, void *context);
static void streamPack(void * streamptr, void * buff, int size, int * position, void *context);
static int streamTxCode(void);
43

44
45
46
47
48
49
50
51
const resOps streamOps = {
  streamCompareP,
  streamDestroyP,
  streamPrintP,
  streamGetPackSize,
  streamPack,
  streamTxCode
};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
52
53


54

55
56
static
int getByteorder(int byteswap)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
57
58
59
{
  int byteorder = -1;

60
  switch (HOST_ENDIANNESS)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
61
    {
62
63
64
65
66
67
68
69
70
71
    case CDI_BIGENDIAN:
      byteorder = byteswap ? CDI_LITTLEENDIAN : CDI_BIGENDIAN;
      break;
    case CDI_LITTLEENDIAN:
      byteorder = byteswap ? CDI_BIGENDIAN : CDI_LITTLEENDIAN;
      break;
    /* FIXME: does not currently adjust for PDP endianness */
    case CDI_PDPENDIAN:
    default:
      Error("unhandled endianness");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
72
    }
73
  return byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
74
75
}

76
77
// used also in CDO
int cdiGetFiletype(const char *filename, int *byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
78
79
80
{
  int filetype = CDI_EUFTYPE;
  int swap = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
81
  int version;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
82
83
  long recpos;

84
  int fileID = fileOpen(filename, "r");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
85
86
87

  if ( fileID == CDI_UNDEFID )
    {
88
      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
89
	return CDI_FILETYPE_NC;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
90
      else
91
	return CDI_ESYSTEM;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
92
    }
93
  else if ( fileID == -2 ) return CDI_ETMOF;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
94

95
96
97
98
99
100
101
102
103
104
105
106
  char buffer[8];
  if ( fileRead(fileID, buffer, 8) != 8 )
    {
      struct stat buf;
      if ( stat(filename, &buf) == 0 )
        {
          if ( buf.st_size == 0 ) return CDI_EISEMPTY;
          if ( buf.st_mode&S_IFDIR ) return CDI_EISDIR;
        }

      return CDI_EUFTYPE;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
107
108
109

  fileRewind(fileID);

110
  if ( memcmp(buffer, "GRIB", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
111
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
112
113
114
      version = buffer[7];
      if ( version <= 1 )
	{
115
	  filetype = CDI_FILETYPE_GRB;
116
	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
117
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
118
119
      else if ( version == 2 )
	{
120
	  filetype = CDI_FILETYPE_GRB2;
121
	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
122
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
123
    }
124
  else if ( memcmp(buffer, "CDF\001", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
125
    {
126
      filetype = CDI_FILETYPE_NC;
127
      if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
128
    }
129
  else if ( memcmp(buffer, "CDF\002", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
130
    {
131
      filetype = CDI_FILETYPE_NC2;
132
      if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
133
    }
134
135
  else if ( memcmp(buffer, "CDF\005", 4) == 0 )
    {
136
      filetype = CDI_FILETYPE_NC5;
137
138
      if ( CDI_Debug ) Message("found CDF5 file = %s", filename);
    }
139
  else if ( memcmp(buffer+1, "HDF", 3) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
140
    {
141
      filetype = CDI_FILETYPE_NC4;
142
      if ( CDI_Debug ) Message("found HDF file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
143
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
144
#ifdef  HAVE_LIBSERVICE
Uwe Schulzweida's avatar
Uwe Schulzweida committed
145
146
  else if ( srvCheckFiletype(fileID, &swap) )
    {
147
      filetype = CDI_FILETYPE_SRV;
148
      if ( CDI_Debug ) Message("found SRV file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
149
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
150
151
#endif
#ifdef  HAVE_LIBEXTRA
Uwe Schulzweida's avatar
Uwe Schulzweida committed
152
153
  else if ( extCheckFiletype(fileID, &swap) )
    {
154
      filetype = CDI_FILETYPE_EXT;
155
      if ( CDI_Debug ) Message("found EXT file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
156
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
157
158
#endif
#ifdef  HAVE_LIBIEG
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
160
  else if ( iegCheckFiletype(fileID, &swap) )
    {
161
      filetype = CDI_FILETYPE_IEG;
162
      if ( CDI_Debug ) Message("found IEG file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
163
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
164
165
#endif
#ifdef HAVE_LIBGRIB
Uwe Schulzweida's avatar
Uwe Schulzweida committed
166
  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
167
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
168
169
      if ( version <= 1 )
	{
170
	  filetype = CDI_FILETYPE_GRB;
171
	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
172
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
173
      else if ( version == 2 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
174
	{
175
	  filetype = CDI_FILETYPE_GRB2;
176
	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
178
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
179
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
180
181
182
183
184

  fileClose(fileID);

  *byteorder = getByteorder(swap);

185
  return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
186
187
188
189
190
191
192
193
}

/*
@Function  streamInqFiletype
@Title     Get the filetype

@Prototype int streamInqFiletype(int streamID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
194
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
195
196

@Description
197
The function @func{streamInqFiletype} returns the filetype of a stream.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
198
199

@Result
200
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
one of the set of predefined CDI file format types.
202
The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC}, @func{CDI_FILETYPE_NC2},
203
@func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
204
205
206
207
208

@EndFunction
*/
int streamInqFiletype(int streamID)
{
209
  stream_t *streamptr = stream_to_pointer(streamID);
210
  return streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
211
212
213
214
215
}


int getByteswap(int byteorder)
{
216
  int byteswap = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
217

218
  switch (byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
219
    {
220
221
222
223
224
    case CDI_BIGENDIAN:
    case CDI_LITTLEENDIAN:
    case CDI_PDPENDIAN:
      byteswap = (HOST_ENDIANNESS != byteorder);
      break;
225
226
    case -1:
      break;
227
228
    default:
      Error("unexpected byteorder %d query!", byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
229
230
    }

231
  return byteswap;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
232
233
}

234
235
236
237
238
239
/*
@Function  streamDefByteorder
@Title     Define the byte order

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
240
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
241
242
243
244
245
    @Item  byteorder The byte order of a dataset, one of the CDI constants @func{CDI_BIGENDIAN} and
                     @func{CDI_LITTLEENDIAN}.

@Description
The function @func{streamDefByteorder} defines the byte order of a binary dataset
246
with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
247
248
249

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
250
251
void streamDefByteorder(int streamID, int byteorder)
{
252
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
253
  streamptr->byteorder = byteorder;
254
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
255
256
257

  switch (filetype)
    {
258
#ifdef  HAVE_LIBSERVICE
259
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
260
      {
261
	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
262
263
264
265
266
	srvp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
267
#ifdef  HAVE_LIBEXTRA
268
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
269
      {
270
	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
271
272
273
274
275
	extp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
276
#ifdef  HAVE_LIBIEG
277
    case CDI_FILETYPE_IEG:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
278
      {
279
	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
280
281
282
283
284
285
	iegp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
    }
286

287
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
288
289
}

290
291
292
293
294
295
/*
@Function  streamInqByteorder
@Title     Get the byte order

@Prototype int streamInqByteorder(int streamID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
296
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
297
298
299

@Description
The function @func{streamInqByteorder} returns the byte order of a binary dataset
300
with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
301
302
303
304
305
306
307

@Result
@func{streamInqByteorder} returns the type of the byte order.
The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDIAN}

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
308
309
int streamInqByteorder(int streamID)
{
310
  stream_t *streamptr = stream_to_pointer(streamID);
311
  return streamptr->byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
312
313
314
}


315
const char *streamFilesuffix(int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
316
{
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  static const char *noSuffix  = "";
  static const char *ncSuffix  = ".nc";
  static const char *grbSuffix = ".grb";
  static const char *srvSuffix = ".srv";
  static const char *extSuffix = ".ext";
  static const char *iegSuffix = ".ieg";

  switch (filetype)
    {
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
    case CDI_FILETYPE_NC5:   return ncSuffix;
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:  return grbSuffix;
    case CDI_FILETYPE_SRV:   return srvSuffix;
    case CDI_FILETYPE_EXT:   return extSuffix;
    case CDI_FILETYPE_IEG:   return iegSuffix;
    default:                 return noSuffix;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
339
340
}


341
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
342
{
343
  stream_t *streamptr = stream_to_pointer(streamID);
344
  return streamptr->filename;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
345
346
}

347
static
348
long cdiInqTimeSize(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
349
350
{
  int tsID = 0, nrecs;
351
  stream_t *streamptr = stream_to_pointer(streamID);
352
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
353

354
  if ( ntsteps == (long)CDI_UNDEFID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
355
    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
356
      ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357

358
  return ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
359
360
}

361
static
362
int cdiInqContents(stream_t *streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
363
364
{
  int status = 0;
Thomas Jahns's avatar
Thomas Jahns committed
365
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
366
367
368

  switch (filetype)
    {
369
#ifdef  HAVE_LIBGRIB
370
371
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
372
      {
373
        status = grbInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
374
375
376
	break;
      }
#endif
377
#ifdef  HAVE_LIBSERVICE
378
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
379
      {
380
        status = srvInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
381
382
383
	break;
      }
#endif
384
#ifdef  HAVE_LIBEXTRA
385
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
386
      {
387
        status = extInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
388
389
390
	break;
      }
#endif
391
#ifdef  HAVE_LIBIEG
392
    case CDI_FILETYPE_IEG:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
393
      {
394
        status = iegInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
395
396
397
	break;
      }
#endif
398
#ifdef  HAVE_LIBNETCDF
399
400
401
402
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
403
    case CDI_FILETYPE_NC5:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
404
      {
405
        status = cdfInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
406
407
408
409
410
411
	break;
      }
#endif
    default:
      {
	if ( CDI_Debug )
412
	  Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
413
414

	status = CDI_ELIBNAVAIL;
415
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
416
417
418
419
420
      }
    }

  if ( status == 0 )
    {
Thomas Jahns's avatar
Thomas Jahns committed
421
422
423
      int vlistID = streamptr->vlistID;
      int taxisID = vlistInqTaxis(vlistID);
      if ( taxisID != CDI_UNDEFID )
424
425
426
427
428
        {
          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
          taxis_t *taxisptr2 = taxisPtr(taxisID);
          ptaxisCopy(taxisptr2, taxisptr1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
429
430
    }

431
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
432
433
}

434
435

int cdiStreamOpenDefaultDelegate(const char *filename, char filemode, int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
436
437
{
  int fileID;
438
439
  char temp[2] = { filemode, 0 };

440
  switch (filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
441
    {
442
#if defined(HAVE_LIBGRIB) && (defined(HAVE_LIBCGRIBEX) || defined(HAVE_LIBGRIB_API))
443
    case CDI_FILETYPE_GRB:
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
      {
        fileID = gribOpen(filename, temp);
        if ( fileID < 0 ) return CDI_ESYSTEM;
        if (recordBufIsToBeCreated)
          {
            streamptr->record = (Record *) Malloc(sizeof(Record));
            streamptr->record->buffer = NULL;
#ifdef  HAVE_LIBCGRIBEX
            streamptr->record->cgribexp = cgribexNew();
#else
            streamptr->record->cgribexp = NULL;
#endif
          }
        break;
      }
459
#ifdef  HAVE_LIBGRIB_API
460
    case CDI_FILETYPE_GRB2:
461
      {
462
        fileID = gribOpen(filename, temp);
463
        if ( fileID < 0 ) return CDI_ESYSTEM;
464
465
        if (recordBufIsToBeCreated)
          {
466
            streamptr->record = (Record *) Malloc(sizeof(Record));
467
468
            streamptr->record->buffer = NULL;
          }
469
470
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
471
#endif
472
#endif
473
#ifdef  HAVE_LIBSERVICE
474
    case CDI_FILETYPE_SRV:
475
      {
476
        fileID = fileOpen(filename, temp);
477
        if ( fileID < 0 ) return CDI_ESYSTEM;
478
479
        if (recordBufIsToBeCreated)
          {
480
            streamptr->record = (Record *) Malloc(sizeof(Record));
481
            streamptr->record->buffer = NULL;
482
            streamptr->record->exsep = srvNew();
483
          }
484
485
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
486
#endif
487
#ifdef  HAVE_LIBEXTRA
488
    case CDI_FILETYPE_EXT:
489
      {
490
        fileID = fileOpen(filename, temp);
491
        if ( fileID < 0 ) return CDI_ESYSTEM;
492
493
        if (recordBufIsToBeCreated)
          {
494
            streamptr->record = (Record *) Malloc(sizeof(Record));
495
            streamptr->record->buffer = NULL;
496
            streamptr->record->exsep = extNew();
497
          }
498
499
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
500
#endif
501
#ifdef  HAVE_LIBIEG
502
    case CDI_FILETYPE_IEG:
503
      {
504
        fileID = fileOpen(filename, temp);
505
        if ( fileID < 0 ) return CDI_ESYSTEM;
506
507
        if (recordBufIsToBeCreated)
          {
508
            streamptr->record = (Record *) Malloc(sizeof(Record));
509
            streamptr->record->buffer = NULL;
510
            streamptr->record->exsep = iegNew();
511
          }
512
513
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
514
#endif
515
#ifdef  HAVE_LIBNETCDF
516
517
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
518
    case CDI_FILETYPE_NC5:
519
      {
520
        fileID = cdfOpen(filename, temp, filetype);
521
522
        break;
      }
523
524
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
525
      {
526
        fileID = cdf4Open(filename, temp, &filetype);
527
        break;
528
529
530
531
532
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
533
        return CDI_ELIBNAVAIL;
534
      }
535
    }
536
537
538

  streamptr->filetype = filetype;

539
540
541
542
  return fileID;
}


543
int streamOpenID(const char *filename, char filemode, int filetype, int resH)
544
545
{
  if ( CDI_Debug )
546
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode, filename?filename:"(NUL)");
547

548
  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
549

550
551
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
552

553
554
555
556
  int (*streamOpenDelegate)(const char *filename, char filemode,
                            int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
    = (int (*)(const char *, char, int, stream_t *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
557

558
  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
559
  if ( fileID < 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
560
561
562
563
564
    {
      streamID = fileID;
    }
  else
    {
565
566
      streamID = streamptr->self;
      if ( streamID < 0 ) return CDI_ELIMIT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
567

568
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
569
570
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
571

572
      if ( filemode == 'r' )
573
574
        {
          int vlistID = vlistCreate();
575
          if ( vlistID < 0 ) return CDI_ELIMIT;
576
577
578
579

          cdiVlistMakeInternal(vlistID);
          streamptr->vlistID = vlistID;
          /* cdiReadByteorder(streamID); */
580
          int status = cdiInqContents(streamptr);
581
582
583
584
585
586
587
588
589
590
          if ( status < 0 )
            {
              streamID = status;
            }
          else
            {
              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
              vlistptr->ntsteps = streamptr->ntsteps;
              cdiVlistMakeImmutable(vlistID);
            }
591
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
592
    }
593

594
595
596
597
598
599
600
  if ( streamID < 0 )
    {
      Free(streamptr->record);
      stream_delete_entry(streamptr);
    }

  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
601
602
}

603
604
static
int streamOpen(const char *filename, const char *filemode, int filetype)
605
{
606
607
  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
608
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
609

610
611
static
int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
612
613
{
  if ( CDI_Debug )
614
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
615
  if ( CDI_Debug ) printf("streamOpenA: %s\n", filename); // seg fault without this line on thunder/squall with "cdo cat x y"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
616

617
  if ( ! filename || ! filemode || filetype < 0 ) return CDI_EINVAL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
618

619
620
621
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
  int fileID = CDI_UNDEFID;

622
  {
623
    int (*streamOpenDelegate)(const char *filename, char filemode,
624
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
625
      = (int (*)(const char *, char, int, stream_t *, int))
626
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
627

628
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
629
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
630

631
  if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
632

633
  int streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
634

635
636
637
638
639
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
640
  cdiVlistMakeInternal(streamptr->vlistID);
641
  /* cdiReadByteorder(streamID); */
642
  int status = cdiInqContents(streamptr);
643
  if ( status < 0 ) return status;
644
  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
645
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
646
647
648
649
650

  // Needed for NetCDF4
  for ( int varID = 0; varID < vlistptr->nvars; ++varID )
    streamptr->vars[varID].defmiss = true;

651
  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
652

653
654
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
655
656
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
657

658
659
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
660
661
662

  switch (filetype)
    {
663
#if defined(HAVE_LIBGRIB) && (defined(HAVE_LIBCGRIBEX) || defined(HAVE_LIBGRIB_API))
664
    case CDI_FILETYPE_GRB:
665
#ifdef  HAVE_LIBGRIB_API
666
    case CDI_FILETYPE_GRB2:
667
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
668
669
      {
        fileID = gribOpen(filename, filemode);
670
        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
671
672
673
	break;
      }
#endif
674
#ifdef  HAVE_LIBSERVICE
675
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
676
677
678
679
680
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
681
#ifdef  HAVE_LIBEXTRA
682
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
683
684
685
686
687
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
688
#ifdef  HAVE_LIBIEG
689
    case CDI_FILETYPE_IEG:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
690
691
692
693
694
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
695
#ifdef  HAVE_LIBNETCDF
696
697
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
698
    case CDI_FILETYPE_NC5:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
699
      {
700
	fileID = cdfOpen(filename, filemode, filetype);
701
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
702
703
	break;
      }
704
705
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
706
      {
Deike Kleberg's avatar
Deike Kleberg committed
707
	fileID = cdf4Open(filename, filemode, &filetype);
708
	streamptr->ncmode = 2;
709
710
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
711
712
713
#endif
    default:
      {
714
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
715
	return CDI_ELIBNAVAIL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
717
718
719
720
721
      }
    }

  if ( fileID == CDI_UNDEFID )
    streamID = CDI_UNDEFID;
  else
722
    streamptr->fileID = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
723

724
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726
727
728
}

/*
@Function  streamOpenRead
Uwe Schulzweida's avatar
Uwe Schulzweida committed
729
@Title     Open a dataset for reading
Uwe Schulzweida's avatar
Uwe Schulzweida committed
730

Uwe Schulzweida's avatar
Uwe Schulzweida committed
731
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
733
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
734
735

@Description
736
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
737
738

@Result
739
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
740
741
742
743
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
744
745
746
747
   @Item  CDI_ESYSTEM     Operating system error.
   @Item  CDI_EINVAL      Invalid argument.
   @Item  CDI_EUFILETYPE  Unsupported file type.
   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749
750
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
Here is an example using @func{streamOpenRead} to open an existing NetCDF
752
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
753
754

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
755
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
756
757
758
759
760
761
762
763
764
   ...
int streamID;
   ...
streamID = streamOpenRead("foo.nc");
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
Thomas Jahns's avatar
Thomas Jahns committed
765
int streamOpenRead(const char *filename)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
766
{
767
768
  cdiInitialize();

769
  int byteorder = 0;
770
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
771

772
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
773

Thomas Jahns's avatar
Thomas Jahns committed
774
  int streamID = streamOpen(filename, "r", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
775

Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
777
  if ( streamID >= 0 )
    {
778
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
779
780
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781

782
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
783
784
785
786
787
}


int streamOpenAppend(const char *filename)
{
788
789
  cdiInitialize();

790
  int byteorder = 0;
791
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
792

793
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
794

795
  int streamID = streamOpenA(filename, "a", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
796

797
798
  if ( streamID >= 0 )
    {
799
      stream_t *streamptr = stream_to_pointer(streamID);
800
801
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
802

803
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
805
806
807
}

/*
@Function  streamOpenWrite
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808
@Title     Create a new dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
809

Uwe Schulzweida's avatar
Uwe Schulzweida committed
810
@Prototype int streamOpenWrite(const char *path, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
811
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
812
    @Item  path      The name of the new dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
813
    @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
814
                     The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC},
815
                     @func{CDI_FILETYPE_NC2}, @func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV},
816
                     @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
817
818

@Description
819
The function @func{streamOpenWrite} creates a new datset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
820
@Result
821
Upon successful completion @func{streamOpenWrite} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
822
823
824
825
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
826
827
828
829
   @Item  CDI_ESYSTEM     Operating system error.
   @Item  CDI_EINVAL      Invalid argument.
   @Item  CDI_EUFILETYPE  Unsupported file type.
   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
830
831
832
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
833
Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
834
835

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
836
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
837
838
839
   ...
int streamID;
   ...
840
streamID = streamOpenWrite("foo.nc", CDI_FILETYPE_NC);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
841
842
843
844
845
846
847
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
int streamOpenWrite(const char *filename, int filetype)
{
848
849
  cdiInitialize();

850
  return streamOpen(filename, "w", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
851
852
}

853
854
855
856
857
858
static
void streamDefaultValue ( stream_t * streamptr )
{
  streamptr->self              = CDI_UNDEFID;
  streamptr->accesstype        = CDI_UNDEFID;
  streamptr->accessmode        = 0;
859
  streamptr->filetype          = CDI_FILETYPE_UNDEF;
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  streamptr->byteorder         = CDI_UNDEFID;
  streamptr->fileID            = 0;
  streamptr->filemode          = 0;
  streamptr->numvals           = 0;
  streamptr->filename          = NULL;
  streamptr->record            = NULL;
  streamptr->varsAllocated     = 0;
  streamptr->nrecs             = 0;
  streamptr->nvars             = 0;
  streamptr->vars              = NULL;
  streamptr->ncmode            = 0;
  streamptr->curTsID           = CDI_UNDEFID;
  streamptr->rtsteps           = 0;
  streamptr->ntsteps           = CDI_UNDEFID;
  streamptr->tsteps            = NULL;
  streamptr->tstepsTableSize   = 0;
  streamptr->tstepsNextID      = 0;
  streamptr->historyID         = CDI_UNDEFID;
  streamptr->vlistID           = CDI_UNDEFID;
  streamptr->globalatts        = 0;
  streamptr->localatts         = 0;
  streamptr->unreduced         = cdiDataUnreduced;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
882
883
  streamptr->sortname          = cdiSortName > 0;
  streamptr->sortparam         = cdiSortParam > 0;
884
  streamptr->have_missval      = cdiHaveMissval;
885
  streamptr->comptype          = CDI_COMPRESS_NONE;
886
887
888
889
  streamptr->complevel         = 0;

  basetimeInit(&streamptr->basetime);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
890
#ifdef HAVE_LIBNETCDF
891
892
  for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
  for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
893

894
895
896
  for ( int i = 0; i < MAX_GRIDS_PS; i++ )
    {
      streamptr->ncgrid[i].gridID = CDI_UNDEFID;
897
898
      for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j)
        streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID;
899
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
900
901
902
903
904

  streamptr->vct.ilev          = 0;
  streamptr->vct.mlev          = 0;
  streamptr->vct.ilevID        = CDI_UNDEFID;
  streamptr->vct.mlevID        = CDI_UNDEFID;
905
#endif
906
907
908
909

  streamptr->gribContainers    = NULL;
}

910
911
static
stream_t *stream_new_entry(int resH)
912
913
914
{
  cdiInitialize(); /* ***************** make MT version !!! */

915
  stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));