stream.c 49.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
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
142
#ifdef  HAVE_LIBSERVICE
Uwe Schulzweida's avatar
Uwe Schulzweida committed
143
144
  else if ( srvCheckFiletype(fileID, &swap) )
    {
145
      filetype = CDI_FILETYPE_SRV;
146
      if ( CDI_Debug ) Message("found SRV file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
148
149
#endif
#ifdef  HAVE_LIBEXTRA
Uwe Schulzweida's avatar
Uwe Schulzweida committed
150
151
  else if ( extCheckFiletype(fileID, &swap) )
    {
152
      filetype = CDI_FILETYPE_EXT;
153
      if ( CDI_Debug ) Message("found EXT file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
154
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
156
#endif
#ifdef  HAVE_LIBIEG
Uwe Schulzweida's avatar
Uwe Schulzweida committed
157
158
  else if ( iegCheckFiletype(fileID, &swap) )
    {
159
      filetype = CDI_FILETYPE_IEG;
160
      if ( CDI_Debug ) Message("found IEG file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
161
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
163
#endif
#ifdef HAVE_LIBGRIB
Uwe Schulzweida's avatar
Uwe Schulzweida committed
164
  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
165
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
166
167
      if ( version <= 1 )
	{
168
	  filetype = CDI_FILETYPE_GRB;
169
	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
170
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
171
      else if ( version == 2 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
172
	{
173
	  filetype = CDI_FILETYPE_GRB2;
174
	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
175
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
176
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
177
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
178
179
180
181
182

  fileClose(fileID);

  *byteorder = getByteorder(swap);

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

/*
@Function  streamInqFiletype
@Title     Get the filetype

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

  streamptr->filetype = filetype;

551
552
553
554
  return fileID;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

  basetimeInit(&streamptr->basetime);

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