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"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
19
#include "stream_grb.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
20
21
22
23
24
#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
25
#include "cgribex.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
#include "gribapi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
#include "vlist.h"
28
#include "serialize.h"
29
#include "resource_handle.h"
30
#include "resource_unpack.h"
31
32
#include "namespace.h"

33

34
static stream_t *stream_new_entry(int resH);
35
static void stream_delete_entry(stream_t *streamptr);
36
37
38
39
40
41
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);
42

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


53

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

59
  switch (HOST_ENDIANNESS)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
60
    {
61
62
63
64
65
66
67
68
69
70
    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
71
    }
72
  return byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
73
74
}

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

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

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

94
95
96
97
98
99
100
101
102
103
104
105
  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
106
107
108

  fileRewind(fileID);

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

  fileClose(fileID);

  *byteorder = getByteorder(swap);

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

/*
@Function  streamInqFiletype
@Title     Get the filetype

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

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

@Result
199
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
200
one of the set of predefined CDI file format types.
201
The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC}, @func{CDI_FILETYPE_NC2},
202
@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
203
204
205
206
207

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


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

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

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

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

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
239
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
240
241
242
243
244
    @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
245
with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
246
247
248

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

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

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

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

	break;
      }
#endif
    }
285
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
286
287
}

288
289
290
291
292
293
/*
@Function  streamInqByteorder
@Title     Get the byte order

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

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

@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
306
307
int streamInqByteorder(int streamID)
{
308
  stream_t *streamptr = stream_to_pointer(streamID);
309
  return streamptr->byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
310
311
312
}


313
const char *streamFilesuffix(int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
314
{
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  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
336
337
338
}


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

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

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

356
  return ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
357
358
}

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

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

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

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

429
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
430
431
}

432
int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
433
434
                                 int filetype, stream_t *streamptr,
                                 int recordBufIsToBeCreated)
435
436
437
{
  int fileID;
  switch (filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
438
    {
439
#ifdef  HAVE_LIBGRIB
440
    case CDI_FILETYPE_GRB:
441
#ifdef  HAVE_LIBGRIB_API
442
    case CDI_FILETYPE_GRB2:
443
#endif
444
      {
445
#ifndef __cplusplus
446
        fileID = gribOpen(filename, (char [2]){filemode, 0});
447
448
449
450
#else
        char temp[2] = { filemode, 0 };
        fileID = gribOpen(filename, temp);
#endif
451
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
452
453
        if (recordBufIsToBeCreated)
          {
454
            streamptr->record = (Record *) Malloc(sizeof(Record));
455
456
            streamptr->record->buffer = NULL;
          }
457
458
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
459
#endif
460
#ifdef  HAVE_LIBSERVICE
461
    case CDI_FILETYPE_SRV:
462
      {
463
#ifndef __cplusplus
464
        fileID = fileOpen(filename, (char [2]){filemode, 0});
465
466
467
468
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif
469
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
470
471
        if (recordBufIsToBeCreated)
          {
472
            streamptr->record = (Record *) Malloc(sizeof(Record));
473
            streamptr->record->buffer = NULL;
474
            streamptr->record->exsep  = srvNew();
475
          }
476
477
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
478
#endif
479
#ifdef  HAVE_LIBEXTRA
480
    case CDI_FILETYPE_EXT:
481
      {
482
#ifndef __cplusplus
483
        fileID = fileOpen(filename, (char [2]){filemode, 0});
484
485
486
487
488
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif

489
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
490
491
        if (recordBufIsToBeCreated)
          {
492
            streamptr->record = (Record *) Malloc(sizeof(Record));
493
            streamptr->record->buffer = NULL;
494
            streamptr->record->exsep  = extNew();
495
          }
496
497
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
#endif
499
#ifdef  HAVE_LIBIEG
500
    case CDI_FILETYPE_IEG:
501
      {
502
#ifndef __cplusplus
503
        fileID = fileOpen(filename, (char [2]){filemode, 0});
504
505
506
507
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif
508
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
509
510
        if (recordBufIsToBeCreated)
          {
511
            streamptr->record = (Record *) Malloc(sizeof(Record));
512
            streamptr->record->buffer = NULL;
513
            streamptr->record->exsep  = iegNew();
514
          }
515
516
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
517
#endif
518
#ifdef  HAVE_LIBNETCDF
519
520
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
521
    case CDI_FILETYPE_NC5:
522
      {
523
#ifndef __cplusplus
524
        fileID = cdfOpen(filename, (char [2]){filemode, 0}, filetype);
525
526
#else
        char temp[2] = { filemode, 0 };
527
        fileID = cdfOpen(filename, temp, filetype);
528
#endif
529
530
        break;
      }
531
532
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
533
      {
534
#ifndef __cplusplus
535
        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
536
537
538
539
#else
        char temp[2] = { filemode, 0 };
        fileID = cdf4Open(filename, temp, &filetype);
#endif
540
        break;
541
542
543
544
545
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
546
        return CDI_ELIBNAVAIL;
547
      }
548
    }
549
550
551

  streamptr->filetype = filetype;

552
553
554
555
  return fileID;
}


556
int streamOpenID(const char *filename, char filemode, int filetype, int resH)
557
558
{
  if ( CDI_Debug )
559
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
560
            filename?filename:"(NUL)");
561

562
  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
563

564
565
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
566

567
568
569
570
  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;
571

572
  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
573
  if ( fileID < 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
574
575
576
577
578
    {
      streamID = fileID;
    }
  else
    {
579
580
      streamID = streamptr->self;
      if ( streamID < 0 ) return CDI_ELIMIT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
581

582
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
583
584
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
585

586
      if ( filemode == 'r' )
587
588
        {
          int vlistID = vlistCreate();
589
          if ( vlistID < 0 ) return CDI_ELIMIT;
590
591
592
593

          cdiVlistMakeInternal(vlistID);
          streamptr->vlistID = vlistID;
          /* cdiReadByteorder(streamID); */
594
          int status = cdiInqContents(streamptr);
595
596
597
598
599
600
601
602
603
604
          if ( status < 0 )
            {
              streamID = status;
            }
          else
            {
              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
              vlistptr->ntsteps = streamptr->ntsteps;
              cdiVlistMakeImmutable(vlistID);
            }
605
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
606
    }
607

608
609
610
611
612
613
614
  if ( streamID < 0 )
    {
      Free(streamptr->record);
      stream_delete_entry(streamptr);
    }

  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
615
616
}

617
618
static
int streamOpen(const char *filename, const char *filemode, int filetype)
619
{
620
621
  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
622
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
623

624
625
static
int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
626
627
{
  if ( CDI_Debug )
628
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
629
  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
630

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

633
634
635
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
  int fileID = CDI_UNDEFID;

636
  {
637
    int (*streamOpenDelegate)(const char *filename, char filemode,
638
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
639
      = (int (*)(const char *, char, int, stream_t *, int))
640
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
641

642
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
643
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
644

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

647
  int streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
648

649
650
651
652
653
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
654
  cdiVlistMakeInternal(streamptr->vlistID);
655
  /* cdiReadByteorder(streamID); */
656
  int status = cdiInqContents(streamptr);
657
  if ( status < 0 ) return status;
658
  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
659
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
660
661
662
663
664

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

665
  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
666

667
668
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
669
670
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
671

672
673
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
674
675
676

  switch (filetype)
    {
677
#ifdef  HAVE_LIBGRIB
678
    case CDI_FILETYPE_GRB:
679
#ifdef  HAVE_LIBGRIB_API
680
    case CDI_FILETYPE_GRB2:
681
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
682
683
      {
        fileID = gribOpen(filename, filemode);
684
        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
685
686
687
	break;
      }
#endif
688
#ifdef  HAVE_LIBSERVICE
689
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
690
691
692
693
694
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
695
#ifdef  HAVE_LIBEXTRA
696
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
697
698
699
700
701
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
702
#ifdef  HAVE_LIBIEG
703
    case CDI_FILETYPE_IEG:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
704
705
706
707
708
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
709
#ifdef  HAVE_LIBNETCDF
710
711
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
712
    case CDI_FILETYPE_NC5:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
713
      {
714
	fileID = cdfOpen(filename, filemode, filetype);
715
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
717
	break;
      }
718
719
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
720
      {
Deike Kleberg's avatar
Deike Kleberg committed
721
	fileID = cdf4Open(filename, filemode, &filetype);
722
	streamptr->ncmode = 2;
723
724
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726
727
#endif
    default:
      {
728
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
729
	return CDI_ELIBNAVAIL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
730
731
732
733
734
735
      }
    }

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

738
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
739
740
741
742
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
745
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
747
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749

@Description
750
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
751
752

@Result
753
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
754
755
756
757
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
758
759
760
761
   @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
762
763
764
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
765
Here is an example using @func{streamOpenRead} to open an existing NetCDF
766
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
768

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
769
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771
772
773
774
775
776
777
778
   ...
int streamID;
   ...
streamID = streamOpenRead("foo.nc");
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
Thomas Jahns's avatar
Thomas Jahns committed
779
int streamOpenRead(const char *filename)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
780
{
781
782
  cdiInitialize();

783
  int byteorder = 0;
784
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
785

786
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
787

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
790
791
  if ( streamID >= 0 )
    {
792
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
793
794
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
795

796
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
797
798
799
800
801
}


int streamOpenAppend(const char *filename)
{
802
803
  cdiInitialize();

804
  int byteorder = 0;
805
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
806

807
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808

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

811
812
  if ( streamID >= 0 )
    {
813
      stream_t *streamptr = stream_to_pointer(streamID);
814
815
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
816

817
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
818
819
820
821
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
824
@Prototype int streamOpenWrite(const char *path, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
825
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
826
    @Item  path      The name of the new dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
827
    @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
828
                     The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC},
829
                     @func{CDI_FILETYPE_NC2}, @func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV},
830
                     @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
831
832

@Description
833
The function @func{streamOpenWrite} creates a new datset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
834
@Result
835
Upon successful completion @func{streamOpenWrite} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
836
837
838
839
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
840
841
842
843
   @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
844
845
846
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
847
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
848
849

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
850
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
851
852
853
   ...
int streamID;
   ...
854
streamID = streamOpenWrite("foo.nc", CDI_FILETYPE_NC);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
855
856
857
858
859
860
861
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
int streamOpenWrite(const char *filename, int filetype)
{
862
863
  cdiInitialize();

864
  return streamOpen(filename, "w", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
865
866
}

867
868
869
870
871
872
static
void streamDefaultValue ( stream_t * streamptr )
{
  streamptr->self              = CDI_UNDEFID;
  streamptr->accesstype        = CDI_UNDEFID;
  streamptr->accessmode        = 0;
873
  streamptr->filetype          = CDI_FILETYPE_UNDEF;
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
  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
896
897
  streamptr->sortname          = cdiSortName > 0;
  streamptr->sortparam         = cdiSortParam > 0;
898
  streamptr->have_missval      = cdiHaveMissval;
899
  streamptr->comptype          = CDI_COMPRESS_NONE;
900
901
902
903
  streamptr->complevel         = 0;

  basetimeInit(&streamptr->basetime);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
904
#ifdef HAVE_LIBNETCDF
905
906
  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;
907