stream.c 48.7 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
    }

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

  fileRewind(fileID);

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

  fileClose(fileID);

  *byteorder = getByteorder(swap);

175
  return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
176
177
178
179
180
181
182
183
}

/*
@Function  streamInqFiletype
@Title     Get the filetype

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

@Description
187
The function @func{streamInqFiletype} returns the filetype of a stream.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
188
189

@Result
190
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
one of the set of predefined CDI file format types.
192
The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC}, @func{CDI_FILETYPE_NC2},
193
@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
194
195
196
197
198

@EndFunction
*/
int streamInqFiletype(int streamID)
{
199
  stream_t *streamptr = stream_to_pointer(streamID);
200
  return streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
202
203
204
205
}


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

208
  switch (byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209
    {
210
211
212
213
214
    case CDI_BIGENDIAN:
    case CDI_LITTLEENDIAN:
    case CDI_PDPENDIAN:
      byteswap = (HOST_ENDIANNESS != byteorder);
      break;
215
216
    case -1:
      break;
217
218
    default:
      Error("unexpected byteorder %d query!", byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
219
220
    }

221
  return byteswap;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
222
223
}

224
225
226
227
228
229
/*
@Function  streamDefByteorder
@Title     Define the byte order

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
230
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
231
232
233
234
235
    @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
236
with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
237
238
239

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
240
241
void streamDefByteorder(int streamID, int byteorder)
{
242
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
243
  streamptr->byteorder = byteorder;
244
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
245
246
247

  switch (filetype)
    {
248
#ifdef  HAVE_LIBSERVICE
249
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
250
      {
251
	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
252
253
254
255
256
	srvp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
257
#ifdef  HAVE_LIBEXTRA
258
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
259
      {
260
	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
261
262
263
264
265
	extp->byteswap = getByteswap(byteorder);

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

	break;
      }
#endif
    }
276
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
277
278
}

279
280
281
282
283
284
/*
@Function  streamInqByteorder
@Title     Get the byte order

@Prototype int streamInqByteorder(int streamID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
285
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
286
287
288

@Description
The function @func{streamInqByteorder} returns the byte order of a binary dataset
289
with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
290
291
292
293
294
295
296

@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
297
298
int streamInqByteorder(int streamID)
{
299
  stream_t *streamptr = stream_to_pointer(streamID);
300
  return streamptr->byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
301
302
303
}


304
const char *streamFilesuffix(int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
305
{
306
  // static char *fileSuffix[] = {"", ".grb", ".g2", ".nc", ".nc", ".nc4", ".nc4", ".srv", ".ext", ".ieg"};
307
308
309
310
311
  /* note: the 2nd dimenstion of the fileSuffix array must be equal to or
   * larger than the length of the longest suffix (dot and \0 terminator
   * included) */
  static const char fileSuffix[][5] = {"", ".grb", ".grb", ".nc", ".nc", ".nc", ".nc", ".srv", ".ext", ".ieg"};
  int size = (int)(sizeof(fileSuffix)/sizeof(fileSuffix[0]));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
312
313

  if ( filetype > 0 && filetype < size )
314
    return fileSuffix[filetype];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
315
  else
316
    return fileSuffix[0];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
317
318
319
}


320
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
321
{
322
  stream_t *streamptr = stream_to_pointer(streamID);
323
  return streamptr->filename;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
324
325
}

326
static
327
long cdiInqTimeSize(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
328
329
{
  int tsID = 0, nrecs;
330
  stream_t *streamptr = stream_to_pointer(streamID);
331
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
332

333
  if ( ntsteps == (long)CDI_UNDEFID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
335
      ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
336

337
  return ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
339
}

340
static
341
int cdiInqContents(stream_t *streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
342
343
{
  int status = 0;
Thomas Jahns's avatar
Thomas Jahns committed
344
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
345
346
347

  switch (filetype)
    {
348
#ifdef  HAVE_LIBGRIB
349
350
    case CDI_FILETYPE_GRB:
    case CDI_FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
351
      {
352
        status = grbInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
353
354
355
	break;
      }
#endif
356
#ifdef  HAVE_LIBSERVICE
357
    case CDI_FILETYPE_SRV:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
358
      {
359
        status = srvInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360
361
362
	break;
      }
#endif
363
#ifdef  HAVE_LIBEXTRA
364
    case CDI_FILETYPE_EXT:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
365
      {
366
        status = extInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
367
368
369
	break;
      }
#endif
370
#ifdef  HAVE_LIBIEG
371
    case CDI_FILETYPE_IEG:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
372
      {
373
        status = iegInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
374
375
376
	break;
      }
#endif
377
#ifdef  HAVE_LIBNETCDF
378
379
380
381
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
382
    case CDI_FILETYPE_NC5:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
383
      {
384
        status = cdfInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
385
386
387
388
389
390
	break;
      }
#endif
    default:
      {
	if ( CDI_Debug )
391
	  Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
392
393

	status = CDI_ELIBNAVAIL;
394
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
395
396
397
398
399
      }
    }

  if ( status == 0 )
    {
Thomas Jahns's avatar
Thomas Jahns committed
400
401
402
      int vlistID = streamptr->vlistID;
      int taxisID = vlistInqTaxis(vlistID);
      if ( taxisID != CDI_UNDEFID )
403
404
405
406
407
        {
          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
          taxis_t *taxisptr2 = taxisPtr(taxisID);
          ptaxisCopy(taxisptr2, taxisptr1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
408
409
    }

410
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
411
412
}

413
int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
414
415
                                 int filetype, stream_t *streamptr,
                                 int recordBufIsToBeCreated)
416
417
418
{
  int fileID;
  switch (filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
419
    {
420
#ifdef  HAVE_LIBGRIB
421
    case CDI_FILETYPE_GRB:
422
#ifdef  HAVE_LIBGRIB_API
423
    case CDI_FILETYPE_GRB2:
424
#endif
425
      {
426
#ifndef __cplusplus
427
        fileID = gribOpen(filename, (char [2]){filemode, 0});
428
429
430
431
#else
        char temp[2] = { filemode, 0 };
        fileID = gribOpen(filename, temp);
#endif
432
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
433
434
        if (recordBufIsToBeCreated)
          {
435
            streamptr->record = (Record *) Malloc(sizeof(Record));
436
437
            streamptr->record->buffer = NULL;
          }
438
439
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
440
#endif
441
#ifdef  HAVE_LIBSERVICE
442
    case CDI_FILETYPE_SRV:
443
      {
444
#ifndef __cplusplus
445
        fileID = fileOpen(filename, (char [2]){filemode, 0});
446
447
448
449
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif
450
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
451
452
        if (recordBufIsToBeCreated)
          {
453
            streamptr->record = (Record *) Malloc(sizeof(Record));
454
            streamptr->record->buffer = NULL;
455
            streamptr->record->exsep  = srvNew();
456
          }
457
458
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
459
#endif
460
#ifdef  HAVE_LIBEXTRA
461
    case CDI_FILETYPE_EXT:
462
      {
463
#ifndef __cplusplus
464
        fileID = fileOpen(filename, (char [2]){filemode, 0});
465
466
467
468
469
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif

470
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
471
472
        if (recordBufIsToBeCreated)
          {
473
            streamptr->record = (Record *) Malloc(sizeof(Record));
474
            streamptr->record->buffer = NULL;
475
            streamptr->record->exsep  = extNew();
476
          }
477
478
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
479
#endif
480
#ifdef  HAVE_LIBIEG
481
    case CDI_FILETYPE_IEG:
482
      {
483
#ifndef __cplusplus
484
        fileID = fileOpen(filename, (char [2]){filemode, 0});
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  = iegNew();
495
          }
496
497
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
498
#endif
499
#ifdef  HAVE_LIBNETCDF
500
501
    case CDI_FILETYPE_NC:
    case CDI_FILETYPE_NC2:
502
    case CDI_FILETYPE_NC5:
503
      {
504
#ifndef __cplusplus
505
        fileID = cdfOpen(filename, (char [2]){filemode, 0}, filetype);
506
507
#else
        char temp[2] = { filemode, 0 };
508
        fileID = cdfOpen(filename, temp, filetype);
509
#endif
510
511
        break;
      }
512
513
    case CDI_FILETYPE_NC4:
    case CDI_FILETYPE_NC4C:
514
      {
515
#ifndef __cplusplus
516
        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
517
518
519
520
#else
        char temp[2] = { filemode, 0 };
        fileID = cdf4Open(filename, temp, &filetype);
#endif
521
        break;
522
523
524
525
526
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
527
        return CDI_ELIBNAVAIL;
528
      }
529
    }
530
531
532

  streamptr->filetype = filetype;

533
534
535
536
  return fileID;
}


537
int streamOpenID(const char *filename, char filemode, int filetype, int resH)
538
539
{
  if ( CDI_Debug )
540
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
541
            filename?filename:"(NUL)");
542

543
  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
544

545
546
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
547

548
549
550
551
  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;
552

553
  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
554
  if ( fileID < 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
555
556
557
558
559
    {
      streamID = fileID;
    }
  else
    {
560
561
      streamID = streamptr->self;
      if ( streamID < 0 ) return CDI_ELIMIT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
562

563
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
564
565
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
566

567
      if ( filemode == 'r' )
568
569
        {
          int vlistID = vlistCreate();
570
          if ( vlistID < 0 ) return CDI_ELIMIT;
571
572
573
574

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

589
590
591
592
593
594
595
  if ( streamID < 0 )
    {
      Free(streamptr->record);
      stream_delete_entry(streamptr);
    }

  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
596
597
}

598
599
static
int streamOpen(const char *filename, const char *filemode, int filetype)
600
{
601
602
  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
603
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
604

605
606
static
int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
607
608
{
  if ( CDI_Debug )
609
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
610
  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
611

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

614
615
616
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
  int fileID = CDI_UNDEFID;

617
  {
618
    int (*streamOpenDelegate)(const char *filename, char filemode,
619
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
620
      = (int (*)(const char *, char, int, stream_t *, int))
621
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
622

623
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
624
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
625

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

628
  int streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
629

630
631
632
633
634
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
635
  cdiVlistMakeInternal(streamptr->vlistID);
636
  /* cdiReadByteorder(streamID); */
637
  int status = cdiInqContents(streamptr);
638
  if ( status < 0 ) return status;
639
  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
640
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
641
642
643
644
645

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

646
  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
647

648
649
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
650
651
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
652

653
654
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
655
656
657

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

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

719
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
720
721
722
723
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
726
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
727
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
728
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
729
730

@Description
731
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
732
733

@Result
734
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
736
737
738
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
739
740
741
742
   @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
743
744
745
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
Here is an example using @func{streamOpenRead} to open an existing NetCDF
747
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749

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

764
  int byteorder = 0;
765
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
766

767
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
768

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
771
772
  if ( streamID >= 0 )
    {
773
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
774
775
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776

777
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
778
779
780
781
782
}


int streamOpenAppend(const char *filename)
{
783
784
  cdiInitialize();

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

788
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
789

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

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

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

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

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

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

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
821
822
823
824
   @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
825
826
827
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
828
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
829
830

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

845
  return streamOpen(filename, "w", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
846
847
}

848
849
850
851
852
853
static
void streamDefaultValue ( stream_t * streamptr )
{
  streamptr->self              = CDI_UNDEFID;
  streamptr->accesstype        = CDI_UNDEFID;
  streamptr->accessmode        = 0;
854
  streamptr->filetype          = CDI_FILETYPE_UNDEF;
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  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
877
878
  streamptr->sortname          = cdiSortName > 0;
  streamptr->sortparam         = cdiSortParam > 0;
879
  streamptr->have_missval      = cdiHaveMissval;
880
  streamptr->comptype          = CDI_COMPRESS_NONE;
881
882
883
884
  streamptr->complevel         = 0;

  basetimeInit(&streamptr->basetime);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
885
#ifdef HAVE_LIBNETCDF
886
887
  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;
888

889
890
891
  for ( int i = 0; i < MAX_GRIDS_PS; i++ )
    {
      streamptr->ncgrid[i].gridID = CDI_UNDEFID;
892
893
      for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j)
        streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID;
894
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
895
896
897
898
899

  streamptr->vct.ilev          = 0;
  streamptr->vct.mlev          = 0;
  streamptr->vct.ilevID        = CDI_UNDEFID;
  streamptr->vct.mlevID        = CDI_UNDEFID;
900
#endif
901
902
903
904

  streamptr->gribContainers    = NULL;
}