stream.c 64.7 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
#include <ctype.h>
10
11
#include <stdio.h>
#include <string.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
12
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
28
29
30
31
#include "cdf.h"
#include "service.h"
#include "extra.h"
#include "ieg.h"
#include "vlist.h"
32
#include "serialize.h"
33
#include "resource_handle.h"
34
#include "resource_unpack.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
35

36
37
#include "namespace.h"

38

39
static stream_t *stream_new_entry(int resH);
40
static void stream_delete_entry(stream_t *streamptr);
41
42
43
44
45
46
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);
47

48
49
50
51
52
53
54
55
const resOps streamOps = {
  streamCompareP,
  streamDestroyP,
  streamPrintP,
  streamGetPackSize,
  streamPack,
  streamTxCode
};
Uwe Schulzweida's avatar
Uwe Schulzweida committed
56
57


58
59


Uwe Schulzweida's avatar
Uwe Schulzweida committed
60
61
62
63
#undef  IsBigendian
#define IsBigendian()  ( u_byteorder.c[sizeof(long) - 1] )


64
65
static
int getByteorder(int byteswap)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{
  static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1};
  int byteorder = -1;

  if ( IsBigendian() )
    {
      if ( byteswap ) byteorder = CDI_LITTLEENDIAN;
      else            byteorder = CDI_BIGENDIAN;
    }
  else
    {
      if ( byteswap ) byteorder = CDI_BIGENDIAN;
      else            byteorder = CDI_LITTLEENDIAN;
    }

  return (byteorder);
}

84
85
// used also in CDO
int cdiGetFiletype(const char *filename, int *byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
86
87
88
{
  int filetype = CDI_EUFTYPE;
  int swap = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
89
  int version;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
90
  long recpos;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
91
  char buffer[8];
Uwe Schulzweida's avatar
Uwe Schulzweida committed
92

93
  int fileID = fileOpen(filename, "r");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
94
95
96

  if ( fileID == CDI_UNDEFID )
    {
97
      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
98
99
100
101
102
	return (FILETYPE_NC);
      else
	return (CDI_ESYSTEM);
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
103
  if ( fileRead(fileID, buffer, 8) != 8 ) return (CDI_EUFTYPE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
104
105
106

  fileRewind(fileID);

107
  if ( memcmp(buffer, "GRIB", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
108
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
109
110
111
112
      version = buffer[7];
      if ( version <= 1 )
	{
	  filetype = FILETYPE_GRB;
113
	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
114
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
115
116
117
      else if ( version == 2 )
	{
	  filetype = FILETYPE_GRB2;
118
	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
119
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
120
    }
121
  else if ( memcmp(buffer, "CDF\001", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
122
123
    {
      filetype = FILETYPE_NC;
124
      if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
125
    }
126
  else if ( memcmp(buffer, "CDF\002", 4) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
127
128
    {
      filetype = FILETYPE_NC2;
129
      if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
130
    }
131
  else if ( memcmp(buffer+1, "HDF", 3) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
132
    {
133
      filetype = FILETYPE_NC4;
134
      if ( CDI_Debug ) Message("found HDF file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
135
136
137
138
139
    }
#if  defined  (HAVE_LIBSERVICE)
  else if ( srvCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_SRV;
140
      if ( CDI_Debug ) Message("found SRV file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
141
142
143
144
145
146
    }
#endif
#if  defined  (HAVE_LIBEXTRA)
  else if ( extCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_EXT;
147
      if ( CDI_Debug ) Message("found EXT file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
148
149
150
151
152
153
    }
#endif
#if  defined  (HAVE_LIBIEG)
  else if ( iegCheckFiletype(fileID, &swap) )
    {
      filetype = FILETYPE_IEG;
154
      if ( CDI_Debug ) Message("found IEG file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
156
    }
#endif
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
161
      if ( version <= 1 )
	{
	  filetype = 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 = 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
175
176
177
178
179
180
181
182
183
    }

  fileClose(fileID);

  *byteorder = getByteorder(swap);

  return (filetype);
}

/*
@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.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
192
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
193
@func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV}, @func{FILETYPE_EXT} and @func{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);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
200

201
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
202

Uwe Schulzweida's avatar
Uwe Schulzweida committed
203
  return (streamptr->filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
}


int getByteswap(int byteorder)
{
  static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1};
  int byteswap = 0;

  if ( IsBigendian() )
    {
      if ( byteorder == CDI_LITTLEENDIAN ) byteswap = TRUE;
    }
  else
    {
      if ( byteorder == CDI_BIGENDIAN ) byteswap = TRUE;
    }

  return (byteswap);
}

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
236
237
238
239
    @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
240
241
void streamDefByteorder(int streamID, int byteorder)
{
Thomas Jahns's avatar
Thomas Jahns committed
242
  int filetype;
243
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
244

245
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
246
247
248

  streamptr->byteorder = byteorder;
  filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
249
250
251
252
253
254

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

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

	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
    case FILETYPE_IEG:
      {
273
	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
274
275
276
277
278
279
	iegp->byteswap = getByteswap(byteorder);

	break;
      }
#endif
    }
280
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
281
282
}

283
284
285
286
287
288
/*
@Function  streamInqByteorder
@Title     Get the byte order

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

@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
301
302
int streamInqByteorder(int streamID)
{
303
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
304

305
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
306

Uwe Schulzweida's avatar
Uwe Schulzweida committed
307
  return (streamptr->byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
308
309
310
}


311
const char *streamFilesuffix(int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
312
{
313
  // static char *fileSuffix[] = {"", ".grb", ".g2", ".nc", ".nc", ".nc4", ".nc4", ".srv", ".ext", ".ieg"};
314
315
316
317
318
  /* 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
319
320
321
322
323
324
325
326

  if ( filetype > 0 && filetype < size )
    return (fileSuffix[filetype]);
  else
    return (fileSuffix[0]);
}


327
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
328
{
329
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
330

331
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
332
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);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
341

342
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
343

344
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
345

346
  if ( ntsteps == (long)CDI_UNDEFID )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
347
    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
348
      ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
349
350
351
352

  return (ntsteps);
}

353
354
static
int cdiInqContents(stream_t * streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
355
356
357
{
  int status = 0;

Thomas Jahns's avatar
Thomas Jahns committed
358
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
359
360
361
362
363

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
364
365
    case FILETYPE_GRB2:
      {
366
        status = grbInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
367
368
369
	break;
      }
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
370
371
372
#if  defined  (HAVE_LIBSERVICE)
    case FILETYPE_SRV:
      {
373
        status = srvInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
374
375
376
377
378
379
	break;
      }
#endif
#if  defined  (HAVE_LIBEXTRA)
    case FILETYPE_EXT:
      {
380
        status = extInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
381
382
383
384
385
386
	break;
      }
#endif
#if  defined  (HAVE_LIBIEG)
    case FILETYPE_IEG:
      {
387
        status = iegInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
388
389
390
391
392
393
	break;
      }
#endif
#if  defined  (HAVE_LIBNETCDF)
    case FILETYPE_NC:
    case FILETYPE_NC2:
394
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
395
    case FILETYPE_NC4C:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
396
      {
397
        status = cdfInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
398
399
400
401
402
403
	break;
      }
#endif
    default:
      {
	if ( CDI_Debug )
404
	  Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
405
406

	status = CDI_ELIBNAVAIL;
407
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
408
409
410
411
412
      }
    }

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

  return (status);
}

426
int cdiStreamOpenDefaultDelegate(const char *filename, const char *filemode,
427
428
                                 int filetype, stream_t *streamptr,
                                 int recordBufIsToBeCreated)
429
430
431
{
  int fileID;
  switch (filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
432
433
    {
#if  defined  (HAVE_LIBGRIB)
434
435
436
437
438
    case FILETYPE_GRB:
    case FILETYPE_GRB2:
      {
        fileID = gribOpen(filename, filemode);
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
439
440
441
442
443
        if (recordBufIsToBeCreated)
          {
            streamptr->record = (Record *) malloc(sizeof(Record));
            streamptr->record->buffer = NULL;
          }
444
445
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
446
447
#endif
#if  defined  (HAVE_LIBSERVICE)
448
449
450
451
    case FILETYPE_SRV:
      {
        fileID = fileOpen(filename, filemode);
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
452
453
454
455
        if (recordBufIsToBeCreated)
          {
            streamptr->record = (Record *) malloc(sizeof(Record));
            streamptr->record->buffer = NULL;
456
            streamptr->record->exsep  = srvNew();
457
          }
458
459
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
460
461
#endif
#if  defined  (HAVE_LIBEXTRA)
462
463
464
465
    case FILETYPE_EXT:
      {
        fileID = fileOpen(filename, filemode);
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
466
467
468
469
        if (recordBufIsToBeCreated)
          {
            streamptr->record = (Record *) malloc(sizeof(Record));
            streamptr->record->buffer = NULL;
470
            streamptr->record->exsep  = extNew();
471
          }
472
473
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
474
475
#endif
#if  defined  (HAVE_LIBIEG)
476
477
478
479
    case FILETYPE_IEG:
      {
        fileID = fileOpen(filename, filemode);
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
480
481
482
483
        if (recordBufIsToBeCreated)
          {
            streamptr->record = (Record *) malloc(sizeof(Record));
            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
492
493
494
495
496
497
498
499
500
501
502
    case FILETYPE_NC:
      {
        fileID = cdfOpen(filename, filemode);
        break;
      }
    case FILETYPE_NC2:
      {
        fileID = cdfOpen64(filename, filemode);
        break;
      }
    case FILETYPE_NC4:
    case FILETYPE_NC4C:
      {
503
        fileID = cdf4Open(filename, filemode, &filetype);
504
        break;
505
506
507
508
509
510
511
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
        return (CDI_ELIBNAVAIL);
      }
512
    }
513
514
515

  streamptr->filetype = filetype;

516
517
518
519
  return fileID;
}


520
521
522
static int
streamOpenID(const char *filename, const char *filemode, int filetype,
             int resH)
523
524
525
{
  int fileID = CDI_UNDEFID;
  int status;
526

527
  if ( CDI_Debug )
528
529
    Message("Open %s mode %c file %s", strfiletype(filetype), (int) *filemode,
            filename?filename:"(NUL)");
530
531
532

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

533
534
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
535

536
537
  {
    int (*streamOpenDelegate)(const char *filename, const char *filemode,
538
539
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
      = (int (*)(const char *, const char *, int, stream_t *, int))
540
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
541

542
    fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
543
544
545
  }

  if (fileID < 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546
    {
547
548
      free(streamptr->record);
      stream_delete_entry(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
549
550
551
552
      streamID = fileID;
    }
  else
    {
553
554
      streamID  = streamptr->self;

555
      if ( streamID < 0 ) return (CDI_ELIMIT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
556

Uwe Schulzweida's avatar
Uwe Schulzweida committed
557
558
559
      streamptr->filemode = tolower(*filemode);
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
560

Uwe Schulzweida's avatar
Uwe Schulzweida committed
561
      if ( streamptr->filemode == 'r' )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
562
	{
563
	  int vlistID = vlistCreate();
564
565
566
	  if ( vlistID < 0 ) return(CDI_ELIMIT);

	  streamptr->vlistID = vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
567
	  /* cdiReadByteorder(streamID); */
568
	  status = cdiInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
569
	  if ( status < 0 ) return (status);
570
	  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
571
	  vlistptr->ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
572
573
	}
    }
574

Uwe Schulzweida's avatar
Uwe Schulzweida committed
575
576
577
  return (streamID);
}

578
579
580
581
int streamOpen(const char *filename, const char *filemode, int filetype)
{
  return streamOpenID(filename, filemode, filetype, CDI_UNDEFID);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
582

583
static int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
584
585
586
587
{
  int fileID = CDI_UNDEFID;
  int streamID = CDI_ESYSTEM;
  int status;
588
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
589
  vlist_t *vlistptr;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
590
591

  if ( CDI_Debug )
592
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
593
  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
594
595
596

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

597
598
  {
    int (*streamOpenDelegate)(const char *filename, const char *filemode,
599
600
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
      = (int (*)(const char *, const char *, int, stream_t *, int))
601
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
602

603
    fileID = streamOpenDelegate(filename, "r", filetype, streamptr, 1);
604
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
605

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

608
  streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
609

610
611
612
613
614
615
616
617
618
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
  /* cdiReadByteorder(streamID); */
  status = cdiInqContents(streamptr);
  if ( status < 0 ) return (status);
  vlistptr = vlist_to_pointer(streamptr->vlistID);
619
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
620

621
622
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
623
624
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
625

626
627
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
628
629
630
631
632

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
633
    case FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
      {
        fileID = gribOpen(filename, filemode);
	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);
664
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
665
666
667
668
669
	break;
      }
    case FILETYPE_NC2:
      {
	fileID = cdfOpen64(filename, filemode);
670
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
671
672
	break;
      }
673
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
674
    case FILETYPE_NC4C:
675
      {
Deike Kleberg's avatar
Deike Kleberg committed
676
	fileID = cdf4Open(filename, filemode, &filetype);
677
	streamptr->ncmode = 2;
678
679
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
680
681
682
#endif
    default:
      {
683
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
684
685
686
687
688
689
690
	return (CDI_ELIBNAVAIL);
      }
    }

  if ( fileID == CDI_UNDEFID )
    streamID = CDI_UNDEFID;
  else
691
    streamptr->fileID = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
692
693
694
695
696
697

  return (streamID);
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
700
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
701
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
702
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
703
704

@Description
705
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
706
707

@Result
708
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
709
710
711
712
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
713
714
715
716
   @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
717
718
719
@EndList

@Example
720
721
Here is an example using @func{streamOpenRead} to open an existing netCDF
file named @func{foo.nc} for reading:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
722
723

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
724
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726
727
728
729
730
731
732
733
   ...
int streamID;
   ...
streamID = streamOpenRead("foo.nc");
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
Thomas Jahns's avatar
Thomas Jahns committed
734
int streamOpenRead(const char *filename)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
{
736
737
  cdiInitialize();

738
  int byteorder = 0;
739
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
740
741
742

  if ( filetype < 0 ) return (filetype);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
745
746
  if ( streamID >= 0 )
    {
747
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
748
749
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
750
751
752
753
754
755
756

  return (streamID);
}


int streamOpenAppend(const char *filename)
{
757
758
  cdiInitialize();

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

  if ( filetype < 0 ) return (filetype);

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

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

  return (streamID);
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
779
@Prototype int streamOpenWrite(const char *path, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
780
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
781
    @Item  path      The name of the new dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
782
    @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
783
                     The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC},
Deike Kleberg's avatar
Deike Kleberg committed
784
                     @func{FILETYPE_NC2}, @func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV},
Uwe Schulzweida's avatar
Uwe Schulzweida committed
785
                     @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
786
787

@Description
788
The function @func{streamOpenWrite} creates a new datset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
789
@Result
790
Upon successful completion @func{streamOpenWrite} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
791
792
793
794
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
795
796
797
798
   @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
799
800
801
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
802
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
803
804

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
805
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
806
807
808
809
810
811
812
813
814
815
816
   ...
int streamID;
   ...
streamID = streamOpenWrite("foo.nc", FILETYPE_NC);
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
int streamOpenWrite(const char *filename, int filetype)
{
817
818
  cdiInitialize();

Uwe Schulzweida's avatar
Uwe Schulzweida committed
819
820
821
  return (streamOpen(filename, "w", filetype));
}

822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
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
static
void streamDefaultValue ( stream_t * streamptr )
{
  int i;

  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->vct.ilev          = 0;
  streamptr->vct.mlev          = 0;
  streamptr->vct.ilevID        = CDI_UNDEFID;
  streamptr->vct.mlevID        = CDI_UNDEFID;
  streamptr->unreduced         = cdiDataUnreduced;
  streamptr->sortname          = cdiSortName;
  streamptr->have_missval      = cdiHaveMissval;
  streamptr->comptype          = COMPRESS_NONE;
  streamptr->complevel         = 0;

  basetimeInit(&streamptr->basetime);

  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;
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncxvarID[i] = CDI_UNDEFID;
  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncyvarID[i] = CDI_UNDEFID;
  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncavarID[i] = CDI_UNDEFID;

  streamptr->gribContainers    = NULL;
  streamptr->vlistIDorig       = CDI_UNDEFID;
}


876
static stream_t *stream_new_entry(int resH)
877
878
879
880
881
882
883
{
  stream_t *streamptr;

  cdiInitialize(); /* ***************** make MT version !!! */

  streamptr = (stream_t *) xmalloc(sizeof(stream_t));
  streamDefaultValue ( streamptr );
884
885
886
887
888
889
890
  if (resH == CDI_UNDEFID)
    streamptr->self = reshPut(streamptr, &streamOps);
  else
    {
      streamptr->self = resH;
      reshReplace(resH, streamptr, &streamOps);
    }
891
892
893
894
895

  return streamptr;
}


896
void
897
cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
898
899
900
901
902
903
904
905
906
907
908
909
910
{
  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);
911
912
          if (recordBufIsToBeDeleted)
            gribContainersDelete(streamptr);
913
914
915
916
917
918
919
          break;
        }
#endif
#if  defined  (HAVE_LIBSERVICE)
      case FILETYPE_SRV:
        {
          fileClose(fileID);
920
          if (recordBufIsToBeDeleted)
921
            srvDelete((srvrec_t *)streamptr->record->exsep);
922
923
924
925
926
927
928
          break;
        }
#endif
#if  defined  (HAVE_LIBEXTRA)
      case FILETYPE_EXT:
        {
          fileClose(fileID);
929
          if (recordBufIsToBeDeleted)
930
            extDelete(streamptr->record->exsep);
931
932
933
934
935
936
937
          break;
        }
#endif
#if  defined  (HAVE_LIBIEG)
      case FILETYPE_IEG:
        {
          fileClose(fileID);
938
          if (recordBufIsToBeDeleted)
939
            iegDelete((iegrec_t *)streamptr->record->exsep);
940
941
942
943
944
945
946
947
948
          break;
        }
#endif
#if  defined  (HAVE_LIBNETCDF)
      case FILETYPE_NC:
      case FILETYPE_NC2:
      case FILETYPE_NC4:
      case FILETYPE_NC4C:
        {
949
          cdfClose(fileID);
950
951
952
953
954
          break;
        }
#endif
      default:
        {
955
          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
956
957
958
959
960
961
          break;
        }
      }
}


962
963
964
965
966
void deallocate_sleveltable_t(sleveltable_t *entry)
{
  if (entry == NULL) return;
  if (entry->recordID) free(entry->recordID);
  if (entry->lindex)   free(entry->lindex);
967
968
  entry->recordID = NULL;
  entry->lindex   = NULL;
969
970
971
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
972
973
/*
@Function  streamClose
Uwe Schulzweida's avatar
Uwe Schulzweida committed
974
@Title     Close an open dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
975
976
977

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

@Description
981
The function @func{streamClose} closes an open dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
982
983
984
985
986
987
988

@EndFunction
*/
void streamClose(int streamID)
{
  int index;
  int vlistID;
989
  stream_t *streamptr = stream_to_pointer(streamID);
990

991
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
992
993

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

996
  vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
997

998
  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
999
1000
    = (void (*)(stream_t *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
1001

1002
  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
1003

1004
  if ( streamptr->record )
1005
1006
1007
    {
      if ( streamptr->record->buffer )
        free(streamptr->record->buffer);
1008

1009
1010
      free(streamptr->record);
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1011

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1012
1013
  streamptr->filetype = 0;
  if ( streamptr->filename ) free(streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1014

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1015
  for ( index = 0; index < streamptr->nvars; index++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1016
    {
1017
1018
1019
1020
1021
1022
1023
      for (int isub=0; isub<streamptr->vars[index].subtypeSize; isub++)
        {
          /* fprintf(stderr, "deallocate subtype %d / %d\n",      */
          /*         isub+1, streamptr->vars[index].subtypeSize); */
          deallocate_sleveltable_t(&streamptr->vars[index].recordTable[isub]);
        }
      if (streamptr->vars[index].recordTable)  free(streamptr->vars[index].recordTable);
1024
      streamptr->vars[index].recordTable = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1025
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1026
  free(streamptr->vars);
1027
  streamptr->vars = NULL;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1028

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1029
  for ( index = 0; index < streamptr->ntsteps; ++index )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1030
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1031
1032
1033
1034
      if ( streamptr->tsteps[index].records )
	free(streamptr->tsteps[index].records);
      if ( streamptr->tsteps[index].recIDs )
	free(streamptr->tsteps[index].recIDs);
1035
      taxisDestroyKernel(&streamptr->tsteps[index].taxis);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1036
    }
1037

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1038
  if ( streamptr->tsteps ) free(streamptr->tsteps);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1039

1040
1041
  if ( streamptr->basetime.timevar_cache ) free(streamptr->basetime.timevar_cache);

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1042
1043
  if ( vlistID != -1 )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1044
1045
1046
1047
1048
1049
      if ( streamptr->filemode != 'w' )
	if ( vlistInqTaxis(vlistID) != -1 )
	  {
	    taxisDestroy(vlistInqTaxis(vlistID));
	  }

1050
      vlistDestroy(vlistID);
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
      /* decrease lock counter of the original vlist by 1 */
      if ( streamptr->vlistIDorig != CDI_UNDEFID ) {
        /* Note: Here we have to check if the original vlist still
         * exists. If, for example, the garbage collection routine
         * reshListDestruct takes care of the destruction of objects,
         * then the original vlist might have been destroyed
         * beforehand. */
        if (reshExists(streamptr->vlistIDorig, &vlistOps) != 0)
          vlist_unlock(streamptr->vlistIDorig);
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1061
    }
Uwe Schulzweida's avatar
bug fix    
Uwe Schulzweida committed
1062
1063

  stream_delete_entry(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1064
1065
}

1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
static void stream_delete_entry(stream_t *streamptr)
{
  int idx;

  xassert ( streamptr );

  idx = streamptr->self;
  free ( streamptr );
  reshRemove ( idx, &streamOps );

1076
  if ( CDI_Debug )
1077
1078
1079
1080
    Message("Removed idx %d from stream list", idx);
}


Thomas Jahns's avatar
Thomas Jahns committed
1081
void cdiStreamSync_(stream_t *streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1082
{
Thomas Jahns's avatar
Thomas Jahns committed
1083
1084
1085
1086
  int fileID   = streamptr->fileID;
  int filetype = streamptr->filetype;
  int vlistID  = streamptr->vlistID;
  int nvars    = vlistNvars(vlistID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1087
1088

  if ( fileID == CDI_UNDEFID )
1089
    Warning("File %s not open!", streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1090
  else if ( vlistID == CDI_UNDEFID )
1091
    Warning("Vlist undefined for file %s!", streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1092
  else if ( nvars == 0 )
1093
    Warning("No variables defined!");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  else
    {
      if ( streamptr->filemode == 'w' || streamptr->filemode == 'a' )
	{
	  switch (filetype)
	    {
#if  defined  (HAVE_LIBNETCDF)
	    case FILETYPE_NC:
	    case FILETYPE_NC2:
	    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
1104
	    case FILETYPE_NC4C:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1105
	      {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1106
1107
		void cdf_sync(int ncid);
		if ( streamptr->ncmode == 2 ) cdf_sync(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1108
1109
1110
1111
1112
		break;
	      }
#endif
	    default:
	      {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1113
		fileFlush(fileID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1114
1115
1116
1117
1118
1119
1120
		break;
	      }
	    }
	}
    }
}

Thomas Jahns's avatar
Thomas Jahns committed
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
/*
@Function  streamSync
@Title     Synchronize an Open Dataset to Disk

@Prototype  void streamSync(int streamID)
@Parameter
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.

@Description
The function @func{streamSync} offers a way to synchronize the disk copy of a dataset with in-memory buffers.

@EndFunction
*/
void streamSync(int streamID)
{
1136
  stream_t *streamptr = stream_to_pointer(streamID);
Thomas Jahns's avatar
Thomas Jahns committed
1137
1138
1139
1140

  stream_check_ptr(__func__, streamptr);

  void (*myStreamSync_)(stream_t *streamptr)
1141
    = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
Thomas Jahns's avatar
Thomas Jahns committed
1142
1143
1144
  myStreamSync_(streamptr);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1145

Thomas Jahns's avatar
Thomas Jahns committed
1146
int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1147
1148
{
  int taxisID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1149

Uwe Schulzweida's avatar
Uwe Schulzweida committed
1150
  if ( CDI_Debug )