stream.c 45.1 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
  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
148
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
149
150
151
      if ( version <= 1 )
	{
	  filetype = FILETYPE_GRB;
152
	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
153
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
154
      else if ( version == 2 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
155
156
	{
	  filetype = FILETYPE_GRB2;
157
	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
158
	}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    }

  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
174
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
175
176

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

@Result
180
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
181
one of the set of predefined CDI file format types.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
182
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
183
@func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV}, @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
184
185
186
187
188

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


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

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

  return (byteswap);
}

214
215
216
217
218
219
/*
@Function  streamDefByteorder
@Title     Define the byte order

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
220
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
221
222
223
224
225
226
227
228
229
    @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
230
231
void streamDefByteorder(int streamID, int byteorder)
{
232
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
233
  streamptr->byteorder = byteorder;
234
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
235
236
237
238
239
240

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

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

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

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

269
270
271
272
273
274
/*
@Function  streamInqByteorder
@Title     Get the byte order

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

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


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

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


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

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

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

  return (ntsteps);
}

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

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

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

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

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

  return (status);
}

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

  streamptr->filetype = filetype;

493
494
495
496
  return fileID;
}


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

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

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

510
511
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
512

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

519
    fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
520
521
522
  }

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

532
      if ( streamID < 0 ) return (CDI_ELIMIT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
533

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

538
      if ( filemode == 'r' )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
539
	{
540
	  int vlistID = vlistCreate();
541
542
543
	  if ( vlistID < 0 ) return(CDI_ELIMIT);

	  streamptr->vlistID = vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
544
	  /* cdiReadByteorder(streamID); */
545
	  status = cdiInqContents(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546
	  if ( status < 0 ) return (status);
547
	  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
548
	  vlistptr->ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
549
550
	}
    }
551

Uwe Schulzweida's avatar
Uwe Schulzweida committed
552
553
554
  return (streamID);
}

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

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

  if ( CDI_Debug )
571
    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
572
  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
573
574
575

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

576
  {
577
    int (*streamOpenDelegate)(const char *filename, char filemode,
578
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
Thomas Jahns's avatar
Thomas Jahns committed
579
      = (int (*)(const char *, char, int, stream_t *, int))
580
      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
581

582
    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
583
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
584

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

587
  streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
588

589
590
591
592
593
594
595
596
597
  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);
598
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
599

600
601
  {
    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
602
603
      = (void (*)(stream_t *, int))
      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
604

605
606
    streamCloseDelegate(streamptr, 0);
  }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
607
608
609
610
611

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

  if ( fileID == CDI_UNDEFID )
    streamID = CDI_UNDEFID;
  else
670
    streamptr->fileID = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
671
672
673
674
675
676

  return (streamID);
}

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
679
@Prototype int streamOpenRead(const char *path)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
680
@Parameter
Deike Kleberg's avatar
Deike Kleberg committed
681
    @Item  path  The name of the dataset to be read.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
682
683

@Description
684
The function @func{streamOpenRead} opens an existing dataset for reading.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
685
686

@Result
687
Upon successful completion @func{streamOpenRead} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
688
689
690
691
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
692
693
694
695
   @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
696
697
698
@EndList

@Example
699
700
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
701
702

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
703
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
704
705
706
707
708
709
710
711
712
   ...
int streamID;
   ...
streamID = streamOpenRead("foo.nc");
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
Thomas Jahns's avatar
Thomas Jahns committed
713
int streamOpenRead(const char *filename)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
714
{
715
716
  cdiInitialize();

717
  int byteorder = 0;
718
  int filetype = cdiGetFiletype(filename, &byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
719
720
721

  if ( filetype < 0 ) return (filetype);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
724
725
  if ( streamID >= 0 )
    {
726
      stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
727
728
      streamptr->byteorder = byteorder;
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
729
730
731
732
733
734
735

  return (streamID);
}


int streamOpenAppend(const char *filename)
{
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);

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

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

  return (streamID);
}

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

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

@Description
767
The function @func{streamOpenWrite} creates a new datset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
768
@Result
769
Upon successful completion @func{streamOpenWrite} returns an identifier to the
Uwe Schulzweida's avatar
Uwe Schulzweida committed
770
771
772
773
open stream. Otherwise, a negative number with the error status is returned.

@Errors
@List
Deike Kleberg's avatar
Deike Kleberg committed
774
775
776
777
   @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
778
779
780
@EndList

@Example
Uwe Schulzweida's avatar
Uwe Schulzweida committed
781
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
782
783

@Source
Uwe Schulzweida's avatar
Uwe Schulzweida committed
784
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
785
786
787
788
789
790
791
792
793
794
795
   ...
int streamID;
   ...
streamID = streamOpenWrite("foo.nc", FILETYPE_NC);
if ( streamID < 0 ) handle_error(streamID);
   ...
@EndSource
@EndFunction
*/
int streamOpenWrite(const char *filename, int filetype)
{
796
797
  cdiInitialize();

Uwe Schulzweida's avatar
Uwe Schulzweida committed
798
799
800
  return (streamOpen(filename, "w", filetype));
}

801
802
803
804
805
806
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
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);

841
  int i;
842
843
844
  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;
845
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
846
847
848
849
850
851
852
853
  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;
}


854
static stream_t *stream_new_entry(int resH)
855
856
857
858
859
{
  stream_t *streamptr;

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

860
  streamptr = (stream_t *) Malloc(sizeof(stream_t));
861
  streamDefaultValue ( streamptr );
862
863
864
865
866
867
868
  if (resH == CDI_UNDEFID)
    streamptr->self = reshPut(streamptr, &streamOps);
  else
    {
      streamptr->self = resH;
      reshReplace(resH, streamptr, &streamOps);
    }
869
870
871
872
873

  return streamptr;
}


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


940
static void deallocate_sleveltable_t(sleveltable_t *entry)
941
{
942
943
  if (entry->recordID) Free(entry->recordID);
  if (entry->lindex)   Free(entry->lindex);
944
945
  entry->recordID = NULL;
  entry->lindex   = NULL;
946
947
948
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
949
950
/*
@Function  streamClose
Uwe Schulzweida's avatar
Uwe Schulzweida committed
951
@Title     Close an open dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
952
953
954

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

@Description
958
The function @func{streamClose} closes an open dataset.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
959
960
961
962
963
964

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

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

Thomas Jahns's avatar
Thomas Jahns committed
970
  int vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
971

972
  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
973
974
    = (void (*)(stream_t *, int))
    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
975

976
  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
977

978
  if ( streamptr->record )
979
980
    {
      if ( streamptr->record->buffer )
981
        Free(streamptr->record->buffer);
982

983
      Free(streamptr->record);
984
    }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
985

Uwe Schulzweida's avatar
Uwe Schulzweida committed
986
  streamptr->filetype = 0;
987
  if ( streamptr->filename ) Free(streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
988

Uwe Schulzweida's avatar
Uwe Schulzweida committed
989
  for ( index = 0; index < streamptr->nvars; index++ )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
990
    {
991
992
993
994
      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++)
995
        {
996
          deallocate_sleveltable_t(pslev + isub);
997
        }
998
      if (pslev) Free(pslev);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
999
    }
1000
  Free(streamptr->vars);
For faster browsing, not all history is shown. View entire blame