stream.c 45.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
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 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
88
89
90
91
92
	return (FILETYPE_NC);
      else
	return (CDI_ESYSTEM);
    }

Uwe Schulzweida's avatar
Uwe Schulzweida committed
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
167
168
169
170
171
172
173
174
175

  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
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);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
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
214
215
    }

  return (byteswap);
}

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);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
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
306
307
308
309
310
311

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


312
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
313
{
314
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
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
330
331

  return (ntsteps);
}

332
333
static
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
403
404
    }

  return (status);
}

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
        fileID = gribOpen(filename, (char [2]){filemode, 0});
417
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
418
419
        if (recordBufIsToBeCreated)
          {
420
            streamptr->record = (Record *) Malloc(sizeof(Record));
421
422
            streamptr->record->buffer = NULL;
          }
423
424
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
425
426
#endif
#if  defined  (HAVE_LIBSERVICE)
427
428
    case FILETYPE_SRV:
      {
429
        fileID = fileOpen(filename, (char [2]){filemode, 0});
430
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
431
432
        if (recordBufIsToBeCreated)
          {
433
            streamptr->record = (Record *) Malloc(sizeof(Record));
434
            streamptr->record->buffer = NULL;
435
            streamptr->record->exsep  = srvNew();
436
          }
437
438
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
439
440
#endif
#if  defined  (HAVE_LIBEXTRA)
441
442
    case FILETYPE_EXT:
      {
443
        fileID = fileOpen(filename, (char [2]){filemode, 0});
444
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
445
446
        if (recordBufIsToBeCreated)
          {
447
            streamptr->record = (Record *) Malloc(sizeof(Record));
448
            streamptr->record->buffer = NULL;
449
            streamptr->record->exsep  = extNew();
450
          }
451
452
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
453
454
#endif
#if  defined  (HAVE_LIBIEG)
455
456
    case FILETYPE_IEG:
      {
457
        fileID = fileOpen(filename, (char [2]){filemode, 0});
458
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
459
460
        if (recordBufIsToBeCreated)
          {
461
            streamptr->record = (Record *) Malloc(sizeof(Record));
462
            streamptr->record->buffer = NULL;
463
            streamptr->record->exsep   = iegNew();
464
          }
465
466
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
467
468
#endif
#if  defined  (HAVE_LIBNETCDF)
469
470
    case FILETYPE_NC:
      {
471
        fileID = cdfOpen(filename, (char [2]){filemode, 0});
472
473
474
475
        break;
      }
    case FILETYPE_NC2:
      {
476
        fileID = cdfOpen64(filename, (char [2]){filemode, 0});
477
478
479
480
481
        break;
      }
    case FILETYPE_NC4:
    case FILETYPE_NC4C:
      {
482
        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
483
        break;
484
485
486
487
488
489
490
      }
#endif
    default:
      {
        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
        return (CDI_ELIBNAVAIL);
      }
491
    }
492
493
494

  streamptr->filetype = filetype;

495
496
497
498
  return fileID;
}


499
int
500
streamOpenID(const char *filename, char filemode, int filetype,
501
             int resH)
502
503
504
{
  int fileID = CDI_UNDEFID;
  int status;
505

506
  if ( CDI_Debug )
507
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
508
            filename?filename:"(NUL)");
509

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

512
513
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
514

515
  {
516
    int (*streamOpenDelegate)(const char *filename, char filemode,
517
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
518
      = (int (*)(const char *, char, int, stream_t *, int))
519
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
520

521
    fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
522
523
524
  }

  if (fileID < 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
525
    {
526
      Free(streamptr->record);
527
      stream_delete_entry(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
528
529
530
531
      streamID = fileID;
    }
  else
    {
532
533
      streamID  = streamptr->self;

534
      if ( streamID < 0 ) return (CDI_ELIMIT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
535

536
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
537
538
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
539

540
      if ( filemode == 'r' )
541
542
543
544
545
546
547
548
549
550
551
552
553
        {
          int vlistID = vlistCreate();
          if ( vlistID < 0 ) return(CDI_ELIMIT);

          cdiVlistMakeInternal(vlistID);
          streamptr->vlistID = vlistID;
          /* cdiReadByteorder(streamID); */
          status = cdiInqContents(streamptr);
          if ( status < 0 ) return (status);
          vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
          vlistptr->ntsteps = streamptr->ntsteps;
          cdiVlistMakeImmutable(vlistID);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
554
    }
555

Uwe Schulzweida's avatar
Uwe Schulzweida committed
556
557
558
  return (streamID);
}

Thomas Jahns's avatar
Thomas Jahns committed
559
static int streamOpen(const char *filename, const char *filemode, int filetype)
560
{
561
562
563
  if (!filemode || strlen(filemode) != 1) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]),
                      filetype, CDI_UNDEFID);
564
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
565

566
static int streamOpenA(const char *filename, const char *filemode, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
567
568
569
570
{
  int fileID = CDI_UNDEFID;
  int streamID = CDI_ESYSTEM;
  int status;
571
  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
572
  vlist_t *vlistptr;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
573
574

  if ( CDI_Debug )
575
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
576
  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
577
578
579

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

580
  {
581
    int (*streamOpenDelegate)(const char *filename, char filemode,
582
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
583
      = (int (*)(const char *, char, int, stream_t *, int))
584
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
585

586
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
587
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
588

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

591
  streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
592

593
594
595
596
597
  streamptr->filemode = tolower(*filemode);
  streamptr->filename = strdupx(filename);
  streamptr->fileID   = fileID;

  streamptr->vlistID = vlistCreate();
598
  cdiVlistMakeInternal(streamptr->vlistID);
599
600
601
602
  /* cdiReadByteorder(streamID); */
  status = cdiInqContents(streamptr);
  if ( status < 0 ) return (status);
  vlistptr = vlist_to_pointer(streamptr->vlistID);
603
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
604
  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
605

606
607
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
608
609
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
610

611
612
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
613
614
615
616
617

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
618
    case FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
      {
        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);
649
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
650
651
652
653
654
	break;
      }
    case FILETYPE_NC2:
      {
	fileID = cdfOpen64(filename, filemode);
655
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
656
657
	break;
      }
658
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
659
    case FILETYPE_NC4C:
660
      {
Deike Kleberg's avatar
Deike Kleberg committed
661
	fileID = cdf4Open(filename, filemode, &filetype);
662
	streamptr->ncmode = 2;
663
664
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
665
666
667
#endif
    default:
      {
668
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
669
670
671
672
673
674
675
	return (CDI_ELIBNAVAIL);
      }
    }

  if ( fileID == CDI_UNDEFID )
    streamID = CDI_UNDEFID;
  else
676
    streamptr->fileID = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
677
678
679
680
681
682

  return (streamID);
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
685
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
686
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
687
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
688
689

@Description
690
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
691
692

@Result
693
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
694
695
696
697
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
698
699
700
701
   @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
702
703
704
@EndList

@Example
705
706
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
707
708

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
709
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
710
711
712
713
714
715
716
717
718
   ...
int streamID;
   ...
streamID = streamOpenRead("foo.nc");
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
Thomas Jahns's avatar
Thomas Jahns committed
719
int streamOpenRead(const char *filename)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
720
{
721
722
  cdiInitialize();

723
  int byteorder = 0;
724
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
725
726
727

  if ( filetype < 0 ) return (filetype);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
730
731
  if ( streamID >= 0 )
    {
732
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
733
734
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
735
736
737
738
739
740
741

  return (streamID);
}


int streamOpenAppend(const char *filename)
{
742
743
  cdiInitialize();

744
  int byteorder = 0;
745
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
746
747
748

  if ( filetype < 0 ) return (filetype);

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

751
752
  if ( streamID >= 0 )
    {
753
      stream_t *streamptr = stream_to_pointer(streamID);
754
755
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
756
757
758
759
760
761

  return (streamID);
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
764
@Prototype int streamOpenWrite(const char *path, int filetype)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
765
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
766
    @Item  path      The name of the new dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
767
    @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
768
                     The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC},
Deike Kleberg's avatar
Deike Kleberg committed
769
                     @func{FILETYPE_NC2}, @func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV},
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
                     @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
771
772

@Description
773
The function @func{streamOpenWrite} creates a new datset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
774
@Result
775
Upon successful completion @func{streamOpenWrite} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
776
777
778
779
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
780
781
782
783
   @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
784
785
786
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
787
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
788
789

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
790
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
791
792
793
794
795
796
797
798
799
800
801
   ...
int streamID;
   ...
streamID = streamOpenWrite("foo.nc", FILETYPE_NC);
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
int streamOpenWrite(const char *filename, int filetype)
{
802
803
  cdiInitialize();

Uwe Schulzweida's avatar
Uwe Schulzweida committed
804
805
806
  return (streamOpen(filename, "w", filetype));
}

807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
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
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->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);

847
  int i;
848
849
850
  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;
851
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
852
853
854
855
856
857
858
859
  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;
}


860
static stream_t *stream_new_entry(int resH)
861
862
863
864
865
{
  stream_t *streamptr;

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

866
  streamptr = (stream_t *) Malloc(sizeof(stream_t));
867
  streamDefaultValue ( streamptr );
868
869
870
871
872
873
874
  if (resH == CDI_UNDEFID)
    streamptr->self = reshPut(streamptr, &streamOps);
  else
    {
      streamptr->self = resH;
      reshReplace(resH, streamptr, &streamOps);
    }
875
876
877
878
879

  return streamptr;
}


880
void
881
cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
882
883
884
885
886
887
888
889
890
891
892
893
894
{
  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);
895
896
          if (recordBufIsToBeDeleted)
            gribContainersDelete(streamptr);
897
898
899
900
901
902
903
          break;
        }
#endif
#if  defined  (HAVE_LIBSERVICE)
      case FILETYPE_SRV:
        {
          fileClose(fileID);
904
          if (recordBufIsToBeDeleted)
905
            srvDelete(streamptr->record->exsep);
906
907
908
909
910
911
912
          break;
        }
#endif
#if  defined  (HAVE_LIBEXTRA)
      case FILETYPE_EXT:
        {
          fileClose(fileID);
913
          if (recordBufIsToBeDeleted)
914
            extDelete(streamptr->record->exsep);
915
916
917
918
919
920
921
          break;
        }
#endif
#if  defined  (HAVE_LIBIEG)
      case FILETYPE_IEG:
        {
          fileClose(fileID);
922
          if (recordBufIsToBeDeleted)
923
            iegDelete(streamptr->record->exsep);
924
925
926
927
928
929
930
931
932
          break;
        }
#endif
#if  defined  (HAVE_LIBNETCDF)
      case FILETYPE_NC:
      case FILETYPE_NC2:
      case FILETYPE_NC4:
      case FILETYPE_NC4C:
        {
933
          cdfClose(fileID);
934
935
936
937
938
          break;
        }
#endif
      default:
        {
939
          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
940
941
942
943
944
945
          break;
        }
      }
}


946
static void deallocate_sleveltable_t(sleveltable_t *entry)
947
{
948
949
  if (entry->recordID) Free(entry->recordID);
  if (entry->lindex)   Free(entry->lindex);
950
951
  entry->recordID = NULL;
  entry->lindex   = NULL;
952
953
954
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
955
956
/*
@Function  streamClose
Uwe Schulzweida's avatar
Uwe Schulzweida committed
957
@Title     Close an open dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
958
959
960

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

@Description
964
The function @func{streamClose} closes an open dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
965
966
967
968
969
970

@EndFunction
*/
void streamClose(int streamID)
{
  int index;
971
  stream_t *streamptr = stream_to_pointer(streamID);
972

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

Thomas Jahns's avatar
Thomas Jahns committed
976
  int vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
977

978
  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
979
980
    = (void (*)(stream_t *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
981

982
  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
983

984
  if ( streamptr->record )
985
986
    {
      if ( streamptr->record->buffer )
987
        Free(streamptr->record->buffer);
988

989
      Free(streamptr->record);
990
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
991

Uwe Schulzweida's avatar
Uwe Schulzweida committed
992
  streamptr->filetype = 0;
993
  if ( streamptr->filename ) Free(streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
994

Uwe Schulzweida's avatar
Uwe Schulzweida committed
995
  for ( index = 0; index < streamptr->nvars; index++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
996
    {
997
998
999
1000
      sleveltable_t *pslev = streamptr->vars[index].recordTable;
      unsigned nsub = streamptr->vars[index].subtypeSize >= 0
        ? (unsigned)streamptr->vars[index].subtypeSize : 0U;
      for (size_t isub=0; isub < nsub; isub++)
For faster browsing, not all history is shown. View entire blame