stream.c 65 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, 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
    case FILETYPE_GRB:
    case FILETYPE_GRB2:
      {
437
        fileID = gribOpen(filename, (char [2]){filemode, 0});
438
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
439
440
        if (recordBufIsToBeCreated)
          {
441
            streamptr->record = (Record *) Malloc(sizeof(Record));
442
443
            streamptr->record->buffer = NULL;
          }
444
445
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
446
447
#endif
#if  defined  (HAVE_LIBSERVICE)
448
449
    case FILETYPE_SRV:
      {
450
        fileID = fileOpen(filename, (char [2]){filemode, 0});
451
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
452
453
        if (recordBufIsToBeCreated)
          {
454
            streamptr->record = (Record *) Malloc(sizeof(Record));
455
            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
    case FILETYPE_EXT:
      {
464
        fileID = fileOpen(filename, (char [2]){filemode, 0});
465
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
466
467
        if (recordBufIsToBeCreated)
          {
468
            streamptr->record = (Record *) Malloc(sizeof(Record));
469
            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
    case FILETYPE_IEG:
      {
478
        fileID = fileOpen(filename, (char [2]){filemode, 0});
479
        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
480
481
        if (recordBufIsToBeCreated)
          {
482
            streamptr->record = (Record *) Malloc(sizeof(Record));
483
            streamptr->record->buffer = NULL;
484
            streamptr->record->exsep   = iegNew();
485
          }
486
487
        break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
488
489
#endif
#if  defined  (HAVE_LIBNETCDF)
490
491
    case FILETYPE_NC:
      {
492
        fileID = cdfOpen(filename, (char [2]){filemode, 0});
493
494
495
496
        break;
      }
    case FILETYPE_NC2:
      {
497
        fileID = cdfOpen64(filename, (char [2]){filemode, 0});
498
499
500
501
502
        break;
      }
    case FILETYPE_NC4:
    case FILETYPE_NC4C:
      {
503
        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &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
static int
521
streamOpenID(const char *filename, char filemode, int filetype,
522
             int resH)
523
524
525
{
  int fileID = CDI_UNDEFID;
  int status;
526

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

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

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

536
  {
537
    int (*streamOpenDelegate)(const char *filename, char filemode,
538
                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
539
      = (int (*)(const char *, 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
      Free(streamptr->record);
548
      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

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

561
      if ( 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);
}

Thomas Jahns's avatar
Thomas Jahns committed
578
static int streamOpen(const char *filename, const char *filemode, int filetype)
579
{
580
581
582
  if (!filemode || strlen(filemode) != 1) return CDI_EINVAL;
  return streamOpenID(filename, (char)tolower(filemode[0]),
                      filetype, CDI_UNDEFID);
583
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
584

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

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

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

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

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

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

610
  streamID = streamptr->self;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
611

612
613
614
615
616
617
618
619
620
  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);
621
  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
622

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

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

  switch (filetype)
    {
#if  defined  (HAVE_LIBGRIB)
    case FILETYPE_GRB:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
635
    case FILETYPE_GRB2:
Uwe Schulzweida's avatar
Uwe Schulzweida committed
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
664
665
      {
        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);
666
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
667
668
669
670
671
	break;
      }
    case FILETYPE_NC2:
      {
	fileID = cdfOpen64(filename, filemode);
672
	streamptr->ncmode = 2;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
673
674
	break;
      }
675
    case FILETYPE_NC4:
Deike Kleberg's avatar
Deike Kleberg committed
676
    case FILETYPE_NC4C:
677
      {
Deike Kleberg's avatar
Deike Kleberg committed
678
	fileID = cdf4Open(filename, filemode, &filetype);
679
	streamptr->ncmode = 2;
680
681
	break;
      }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
682
683
684
#endif
    default:
      {
685
	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
686
687
688
689
690
691
692
	return (CDI_ELIBNAVAIL);
      }
    }

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

  return (streamID);
}

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

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

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

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

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

@Example
722
723
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
724
725

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

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

  if ( filetype < 0 ) return (filetype);

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

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

  return (streamID);
}


int streamOpenAppend(const char *filename)
{
759
760
  cdiInitialize();

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

  if ( filetype < 0 ) return (filetype);

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

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

  return (streamID);
}

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

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

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

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

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

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

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

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
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);

864
  int i;
865
866
867
  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;
868
  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
869
870
871
872
873
874
875
876
877
  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;
}


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

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

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

  return streamptr;
}


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


964
static void deallocate_sleveltable_t(sleveltable_t *entry)
965
{
966
967
  if (entry->recordID) Free(entry->recordID);
  if (entry->lindex)   Free(entry->lindex);
968
969
  entry->recordID = NULL;
  entry->lindex   = NULL;
970
971
972
}


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

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

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

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

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

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

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

999
  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
1000
    = (void (*)(stream_t *, int))
For faster browsing, not all history is shown. View entire blame