stream.c 46.4 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
#if defined (HAVE_CONFIG_H)
#  include "config.h"
#endif

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
9
10
#include <ctype.h>

11
#include "binary.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
12
#include "cdi.h"
13
#include "cdi_int.h"
14
#include "cdi_cksum.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
15
#include "cdf.h"
16
17
#include "dmemory.h"
#include "error.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
18
#include "stream_grb.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
19
20
21
22
23
#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
24
#include "cgribex.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
25
#include "gribapi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
26
#include "vlist.h"
27
#include "serialize.h"
28
#include "resource_handle.h"
29
#include "resource_unpack.h"
30
31
#include "namespace.h"

32

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

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


52

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

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

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

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 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
  if ( fileRead(fileID, buffer, 8) != 8 ) return CDI_EUFTYPE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
94
95
96

  fileRewind(fileID);

97
  if ( memcmp(buffer, "GRIB", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
98
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
99
100
101
102
      version = buffer[7];
      if ( version <= 1 )
	{
	  filetype = FILETYPE_GRB;
103
	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
104
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
105
106
107
      else if ( version == 2 )
	{
	  filetype = FILETYPE_GRB2;
108
	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
109
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
110
    }
111
  else if ( memcmp(buffer, "CDF\001", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
112
113
    {
      filetype = FILETYPE_NC;
114
      if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
115
    }
116
  else if ( memcmp(buffer, "CDF\002", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
117
118
    {
      filetype = FILETYPE_NC2;
119
      if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
120
    }
121
  else if ( memcmp(buffer+1, "HDF", 3) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
122
    {
123
      filetype = FILETYPE_NC4;
124
      if ( CDI_Debug ) Message("found HDF file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
125
126
127
128
129
    }
#if  defined  (HAVE_LIBSERVICE)
  else if ( srvCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_SRV;
130
      if ( CDI_Debug ) Message("found SRV file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
131
132
133
134
135
136
    }
#endif
#if  defined  (HAVE_LIBEXTRA)
  else if ( extCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_EXT;
137
      if ( CDI_Debug ) Message("found EXT file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
138
139
140
141
142
143
    }
#endif
#if  defined  (HAVE_LIBIEG)
  else if ( iegCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_IEG;
144
      if ( CDI_Debug ) Message("found IEG file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
145
146
    }
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
147
#if  defined  (HAVE_LIBCGRIBEX)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
148
  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
149
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
150
151
152
      if ( version <= 1 )
	{
	  filetype = FILETYPE_GRB;
153
	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
154
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
      else if ( version == 2 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
156
157
	{
	  filetype = FILETYPE_GRB2;
158
	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
160
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
161
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
162
163
164
165
166

  fileClose(fileID);

  *byteorder = getByteorder(swap);

167
  return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
168
169
170
171
172
173
174
175
}

/*
@Function  streamInqFiletype
@Title     Get the filetype

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

@Description
179
The function @func{streamInqFiletype} returns the filetype of a stream.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
180
181

@Result
182
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
183
one of the set of predefined CDI file format types.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
184
The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC}, @func{FILETYPE_NC2},
Deike Kleberg's avatar
Deike Kleberg committed
185
@func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV}, @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
186
187
188
189
190

@EndFunction
*/
int streamInqFiletype(int streamID)
{
191
  stream_t *streamptr = stream_to_pointer(streamID);
192
  return streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
193
194
195
196
197
}


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

200
  switch (byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
    {
202
203
204
205
206
    case CDI_BIGENDIAN:
    case CDI_LITTLEENDIAN:
    case CDI_PDPENDIAN:
      byteswap = (HOST_ENDIANNESS != byteorder);
      break;
207
208
    case -1:
      break;
209
210
    default:
      Error("unexpected byteorder %d query!", byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
211
212
    }

213
  return byteswap;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
214
215
}

216
217
218
219
220
221
/*
@Function  streamDefByteorder
@Title     Define the byte order

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
222
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
223
224
225
226
227
228
229
230
231
    @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
with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILETYPE_IEG}.

@EndFunction
*/
Uwe Schulzweida's avatar
Uwe Schulzweida committed
232
233
void streamDefByteorder(int streamID, int byteorder)
{
234
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
235
  streamptr->byteorder = byteorder;
236
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
237
238
239
240
241
242

  switch (filetype)
    {
#if  defined  (HAVE_LIBSERVICE)
    case FILETYPE_SRV:
      {
243
	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
244
245
246
247
248
249
250
251
	srvp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
    case FILETYPE_EXT:
      {
252
	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
253
254
255
256
257
258
259
260
	extp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
    case FILETYPE_IEG:
      {
261
	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
262
263
264
265
266
267
	iegp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
    }
268
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
269
270
}

271
272
273
274
275
276
/*
@Function  streamInqByteorder
@Title     Get the byte order

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

@Description
The function @func{streamInqByteorder} returns the byte order of a binary dataset
with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILETYPE_IEG}.

@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
289
290
int streamInqByteorder(int streamID)
{
291
  stream_t *streamptr = stream_to_pointer(streamID);
292
  return streamptr->byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
293
294
295
}


296
const char *streamFilesuffix(int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
297
{
298
  // static char *fileSuffix[] = {"", ".grb", ".g2", ".nc", ".nc", ".nc4", ".nc4", ".srv", ".ext", ".ieg"};
299
300
301
302
303
  /* 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
304
305

  if ( filetype > 0 && filetype < size )
306
    return fileSuffix[filetype];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
307
  else
308
    return fileSuffix[0];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
309
310
311
}


312
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
313
{
314
  stream_t *streamptr = stream_to_pointer(streamID);
315
  return streamptr->filename;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
316
317
}

318
static
319
long cdiInqTimeSize(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
320
321
{
  int tsID = 0, nrecs;
322
  stream_t *streamptr = stream_to_pointer(streamID);
323
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
324

325
  if ( ntsteps == (long)CDI_UNDEFID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
326
    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
327
      ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
328

329
  return ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
330
331
}

332
static
333
int cdiInqContents(stream_t *streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
334
335
336
{
  int status = 0;

Thomas Jahns's avatar
Thomas Jahns committed
337
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
339
340
341
342

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
343
344
    case FILETYPE_GRB2:
      {
345
        status = grbInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
346
347
348
	break;
      }
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
349
350
351
#if  defined  (HAVE_LIBSERVICE)
    case FILETYPE_SRV:
      {
352
        status = srvInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
353
354
355
356
357
358
	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
    case FILETYPE_EXT:
      {
359
        status = extInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
360
361
362
363
364
365
	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
    case FILETYPE_IEG:
      {
366
        status = iegInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
367
368
369
370
371
372
	break;
      }
#endif
#if  defined  (HAVE_LIBNETCDF)
    case FILETYPE_NC:
    case FILETYPE_NC2:
373
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
374
    case FILETYPE_NC4C:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
375
      {
376
        status = cdfInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
377
378
379
380
381
382
	break;
      }
#endif
    default:
      {
	if ( CDI_Debug )
383
	  Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
384
385

	status = CDI_ELIBNAVAIL;
386
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
387
388
389
390
391
      }
    }

  if ( status == 0 )
    {
Thomas Jahns's avatar
Thomas Jahns committed
392
393
394
      int vlistID = streamptr->vlistID;
      int taxisID = vlistInqTaxis(vlistID);
      if ( taxisID != CDI_UNDEFID )
395
396
397
398
399
        {
          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
          taxis_t *taxisptr2 = taxisPtr(taxisID);
          ptaxisCopy(taxisptr2, taxisptr1);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
400
401
    }

402
  return status;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
403
404
}

405
int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
406
407
                                 int filetype, stream_t *streamptr,
                                 int recordBufIsToBeCreated)
408
409
410
{
  int fileID;
  switch (filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
411
412
    {
#if  defined  (HAVE_LIBGRIB)
413
414
415
    case FILETYPE_GRB:
    case FILETYPE_GRB2:
      {
416
#ifndef __cplusplus
417
        fileID = gribOpen(filename, (char [2]){filemode, 0});
418
419
420
421
#else
        char temp[2] = { filemode, 0 };
        fileID = gribOpen(filename, temp);
#endif
422
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
423
424
        if (recordBufIsToBeCreated)
          {
425
            streamptr->record = (Record *) Malloc(sizeof(Record));
426
427
            streamptr->record->buffer = NULL;
          }
428
429
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
430
431
#endif
#if  defined  (HAVE_LIBSERVICE)
432
433
    case FILETYPE_SRV:
      {
434
#ifndef __cplusplus
435
        fileID = fileOpen(filename, (char [2]){filemode, 0});
436
437
438
439
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif
440
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
441
442
        if (recordBufIsToBeCreated)
          {
443
            streamptr->record = (Record *) Malloc(sizeof(Record));
444
            streamptr->record->buffer = NULL;
445
            streamptr->record->exsep  = srvNew();
446
          }
447
448
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
449
450
#endif
#if  defined  (HAVE_LIBEXTRA)
451
452
    case FILETYPE_EXT:
      {
453
#ifndef __cplusplus
454
        fileID = fileOpen(filename, (char [2]){filemode, 0});
455
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  = extNew();
466
          }
467
468
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
469
470
#endif
#if  defined  (HAVE_LIBIEG)
471
472
    case FILETYPE_IEG:
      {
473
#ifndef __cplusplus
474
        fileID = fileOpen(filename, (char [2]){filemode, 0});
475
476
477
478
#else
        char temp[2] = { filemode, 0 };
        fileID = fileOpen(filename, temp);
#endif
479
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
480
481
        if (recordBufIsToBeCreated)
          {
482
            streamptr->record = (Record *) Malloc(sizeof(Record));
483
            streamptr->record->buffer = NULL;
484
            streamptr->record->exsep   = iegNew();
485
          }
486
487
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488
489
#endif
#if  defined  (HAVE_LIBNETCDF)
490
491
    case FILETYPE_NC:
      {
492
#ifndef __cplusplus
493
        fileID = cdfOpen(filename, (char [2]){filemode, 0});
494
495
496
497
#else
        char temp[2] = { filemode, 0 };
        fileID = cdfOpen(filename, temp);
#endif
498
499
500
501
        break;
      }
    case FILETYPE_NC2:
      {
502
#ifndef __cplusplus
503
        fileID = cdfOpen64(filename, (char [2]){filemode, 0});
504
505
506
507
#else
        char temp[2] = { filemode, 0 };
        fileID = cdfOpen64(filename, temp);
#endif
508
509
510
511
512
        break;
      }
    case FILETYPE_NC4:
    case FILETYPE_NC4C:
      {
513
#ifndef __cplusplus
514
        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
515
516
517
518
#else
        char temp[2] = { filemode, 0 };
        fileID = cdf4Open(filename, temp, &filetype);
#endif
519
        break;
520
521
522
523
524
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
525
        return CDI_ELIBNAVAIL;
526
      }
527
    }
528
529
530

  streamptr->filetype = filetype;

531
532
533
534
  return fileID;
}


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

541
  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
542

543
544
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
545

546
547
548
549
  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;
550

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

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

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

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

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

  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
594
595
}

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

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

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

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

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

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

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

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

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

  streamptr->vlistID = vlistCreate();
634
  cdiVlistMakeInternal(streamptr->vlistID);
635
  /* cdiReadByteorder(streamID); */
636
  int status = cdiInqContents(streamptr);
637
  if ( status < 0 ) return status;
638
  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
639
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
640
  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
641

642
643
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
644
645
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
646

647
648
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
649
650
651
652
653

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
654
    case FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
655
656
      {
        fileID = gribOpen(filename, filemode);
657
        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
	break;
      }
#endif
#if  defined  (HAVE_LIBSERVICE)
    case FILETYPE_SRV:
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
    case FILETYPE_EXT:
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
    case FILETYPE_IEG:
      {
        fileID = fileOpen(filename, filemode);
	break;
      }
#endif
#if  defined  (HAVE_LIBNETCDF)
    case FILETYPE_NC:
      {
	fileID = cdfOpen(filename, filemode);
686
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
687
688
689
690
691
	break;
      }
    case FILETYPE_NC2:
      {
	fileID = cdfOpen64(filename, filemode);
692
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
693
694
	break;
      }
695
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
696
    case FILETYPE_NC4C:
697
      {
Deike Kleberg's avatar
Deike Kleberg committed
698
	fileID = cdf4Open(filename, filemode, &filetype);
699
	streamptr->ncmode = 2;
700
701
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
702
703
704
#endif
    default:
      {
705
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
706
	return CDI_ELIBNAVAIL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
707
708
709
710
711
712
      }
    }

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

715
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
716
717
718
719
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
722
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
723
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
724
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726

@Description
727
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
728
729

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

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
735
736
737
738
   @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
739
740
741
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
742
Here is an example using @func{streamOpenRead} to open an existing NetCDF
743
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
744
745

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

760
  int byteorder = 0;
761
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
762

763
  if ( filetype < 0 ) return filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
764

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
768
  if ( streamID >= 0 )
    {
769
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
772

773
  return streamID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
774
775
776
777
778
}


int streamOpenAppend(const char *filename)
{
779
780
  cdiInitialize();

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

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

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

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

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

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
801
@Prototype int streamOpenWrite(const char *path, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
802
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
803
    @Item  path      The name of the new dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
    @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
                     The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC},
Deike Kleberg's avatar
Deike Kleberg committed
806
                     @func{FILETYPE_NC2}, @func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV},
Uwe Schulzweida's avatar
Uwe Schulzweida committed
807
                     @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
808
809

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

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
817
818
819
820
   @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
821
822
823
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
824
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
825
826

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

841
  return streamOpen(filename, "w", filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
842
843
}

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

  basetimeInit(&streamptr->basetime);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
880
#ifdef HAVE_LIBNETCDF
881
  int i;
882
883
  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->xdimID[i]  = CDI_UNDEFID;
  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ydimID[i]  = CDI_UNDEFID;
884
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
885
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
886
887

  streamptr->ncgrid            = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
888
889
890
891
892

  streamptr->vct.ilev          = 0;
  streamptr->vct.mlev          = 0;
  streamptr->vct.ilevID        = CDI_UNDEFID;
  streamptr->vct.mlevID        = CDI_UNDEFID;
893
#endif
894
895
896
897

  streamptr->gribContainers    = NULL;
}

898
899
static
stream_t *stream_new_entry(int resH)
900
901
902
{
  cdiInitialize(); /* ***************** make MT version !!! */

903
  stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));
904
  streamDefaultValue ( streamptr );
905

906
907
908
909
910
911
912
  if (resH == CDI_UNDEFID)
    streamptr->self = reshPut(streamptr, &streamOps);
  else
    {
      streamptr->self = resH;
      reshReplace(resH, streamptr, &streamOps);
    }
913
914
915
916
917

  return streamptr;
}


918
void cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
919
920
921
922
923
924
925
926
927
928
929
930
931
{
  int fileID   = streamptr->fileID;
  int filetype = streamptr->filetype;
  if ( fileID == CDI_UNDEFID )
    Warning("File %s not open!", streamptr->filename);
  else
    switch (filetype)
      {
#if  defined  (HAVE_LIBGRIB)
      case FILETYPE_GRB:
      case FILETYPE_GRB2:
        {
          gribClose(fileID);
932
933
          if (recordBufIsToBeDeleted)
            gribContainersDelete(streamptr);
934
935
936
937
938
939
940
          break;
        }
#endif
#if  defined  (HAVE_LIBSERVICE)
      case FILETYPE_SRV:
        {
          fileClose(fileID);
941
          if (recordBufIsToBeDeleted)
942
            srvDelete(streamptr->record->exsep);
943
944
945
946
947
948
949
          break;
        }
#endif
#if  defined  (HAVE_LIBEXTRA)
      case FILETYPE_EXT:
        {
          fileClose(fileID);
950
          if (recordBufIsToBeDeleted)
951
            extDelete(streamptr->record->exsep);
952
953
954
955
956
957
958
          break;
        }
#endif
#if  defined  (HAVE_LIBIEG)
      case FILETYPE_IEG:
        {
          fileClose(fileID);
959
          if (recordBufIsToBeDeleted)
960
            iegDelete(streamptr->record->exsep);
961
962
963
964
965
966
967
968
969
          break;
        }
#endif
#if  defined  (HAVE_LIBNETCDF)
      case FILETYPE_NC:
      case FILETYPE_NC2:
      case FILETYPE_NC4:
      case FILETYPE_NC4C:
        {
970
          cdfClose(fileID);
971
          if ( streamptr->ncgrid ) { Free(streamptr->ncgrid); streamptr->ncgrid = NULL; }
972
973
974
975
976
          break;
        }
#endif
      default:
        {
977
          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
978
979
980
981
982
983
          break;
        }
      }
}


984
985
static
void deallocate_sleveltable_t(sleveltable_t *entry)
986
{
987
988
  if (entry->recordID) Free(entry->recordID);
  if (entry->lindex)   Free(entry->lindex);
989
990
  entry->recordID = NULL;
  entry->lindex   = NULL;
991
992
993
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
994
995
/*
@Function  streamClose
Uwe Schulzweida's avatar
Uwe Schulzweida committed
996
@Title     Close an open dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
997
998
999

@Prototype  void streamClose(int streamID)
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
1000
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1001
1002

@Description
1003
The function @func{streamClose} closes an open dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1004
1005
1006
1007
1008

@EndFunction
*/
void streamClose(int streamID)
{
1009
  stream_t *streamptr = stream_to_pointer(streamID);
1010

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1011
  if ( CDI_Debug )
Thomas Jahns's avatar
Thomas Jahns committed
1012
    Message("streamID = %d filename = %s", streamID, streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1013

Thomas Jahns's avatar
Thomas Jahns committed
1014
  int vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1015

1016
  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
1017
1018
    = (void (*)(stream_t *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
1019

1020
  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr,