stream.c 49.6 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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  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
327
328
329
}


330
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
331
{
332
  stream_t *streamptr = stream_to_pointer(streamID);
333
  return streamptr->filename;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
335
}

336
static
337
long cdiInqTimeSize(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
339
{
  int tsID = 0, nrecs;
340
  stream_t *streamptr = stream_to_pointer(streamID);
341
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
342

343
  if ( ntsteps == (long)CDI_UNDEFID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
344
    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
345
      ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
346

347
  return ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
348
349
}

350
static
351
int cdiInqContents(stream_t *streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
352
353
{
  int status = 0;
Thomas Jahns's avatar
Thomas Jahns committed
354
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
355
356
357

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

	status = CDI_ELIBNAVAIL;
404
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
405
406
407
408
409
      }
    }

  if ( status == 0 )
    {
Thomas Jahns's avatar
Thomas Jahns committed
410
411
412
      int vlistID = streamptr->vlistID;
      int taxisID = vlistInqTaxis(vlistID);
      if ( taxisID != CDI_UNDEFID )
413
414
415
416
417
        {
          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
          taxis_t *taxisptr2 = taxisPtr(taxisID);
          ptaxisCopy(taxisptr2, taxisptr1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
418
419
    }

420
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
421
422
}

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

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

  streamptr->filetype = filetype;

543
544
545
546
  return fileID;
}


547
int streamOpenID(const char *filename, char filemode, int filetype, int resH)
548
549
{
  if ( CDI_Debug )
550
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
551
            filename?filename:"(NUL)");
552

553
  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
554

555
556
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
557

558
559
560
561
  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;
562

563
  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
564
  if ( fileID < 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
565
566
567
568
569
    {
      streamID = fileID;
    }
  else
    {
570
571
      streamID = streamptr->self;
      if ( streamID < 0 ) return CDI_ELIMIT;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
572

573
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
574
575
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
576

577
      if ( filemode == 'r' )
578
579
        {
          int vlistID = vlistCreate();
580
          if ( vlistID < 0 ) return CDI_ELIMIT;
581
582
583
584

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

599
600
601
602
603
604
605
  if ( streamID < 0 )
    {
      Free(streamptr->record);
      stream_delete_entry(streamptr);
    }

  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
606
607
}

608
609
static
int streamOpen(const char *filename, const char *filemode, int filetype)
610
{
611
612
  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
613
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
614

615
616
static
int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
617
618
{
  if ( CDI_Debug )
619
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
620
  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
621

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

624
625
626
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
  int fileID = CDI_UNDEFID;

627
  {
628
    int (*streamOpenDelegate)(const char *filename, char filemode,
629
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
630
      = (int (*)(const char *, char, int, stream_t *, int))
631
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
632

633
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
634
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
635

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

638
  int streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
639

640
641
642
643
644
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
645
  cdiVlistMakeInternal(streamptr->vlistID);
646
  /* cdiReadByteorder(streamID); */
647
  int status = cdiInqContents(streamptr);
648
  if ( status < 0 ) return status;
649
  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
650
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
651
652
653
654
655

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

656
  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
657

658
659
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
660
661
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
662

663
664
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
665
666
667

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

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

729
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
730
731
732
733
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
736
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
737
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
738
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
739
740

@Description
741
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
742
743

@Result
744
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
745
746
747
748
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
749
750
751
752
   @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
753
754
755
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
756
Here is an example using @func{streamOpenRead} to open an existing NetCDF
757
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
758
759

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

774
  int byteorder = 0;
775
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776

777
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
778

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
781
782
  if ( streamID >= 0 )
    {
783
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
784
785
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
786

787
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
788
789
790
791
792
}


int streamOpenAppend(const char *filename)
{
793
794
  cdiInitialize();

795
  int byteorder = 0;
796
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
797

798
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
799

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

802
803
  if ( streamID >= 0 )
    {
804
      stream_t *streamptr = stream_to_pointer(streamID);
805
806
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
807

808
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
809
810
811
812
}

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

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

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

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
831
832
833
834
   @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
835
836
837
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
838
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
839
840

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

855
  return streamOpen(filename, "w", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
856
857
}

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

  basetimeInit(&streamptr->basetime);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
895
#ifdef HAVE_LIBNETCDF
896
897
  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;
898

899
900
901
  for ( int i = 0; i < MAX_GRIDS_PS; i++ )
    {
      streamptr->ncgrid[i].gridID = CDI_UNDEFID;
902
903
      for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j)
        streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID;
904
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
905
906
907
908
909

  streamptr->vct.ilev          = 0;
  streamptr->vct.mlev          = 0;
  streamptr->vct.ilevID        = CDI_UNDEFID;
  streamptr->vct.mlevID        = CDI_UNDEFID;
910
#endif
911
912
913
914

  streamptr->gribContainers    = NULL;
}

Uwe Schulzweida's avatar