stream.c 63 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 "binary.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
14
#include "cdi.h"
15
#include "cdi_int.h"
16
#include "cdi_cksum.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
17
#include "cdf.h"
18
19
#include "dmemory.h"
#include "error.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
20
#include "stream_grb.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
21
22
23
24
25
#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
26
#include "cgribex.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
27
#include "gribapi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
28
29
30
31
32
#include "cdf.h"
#include "service.h"
#include "extra.h"
#include "ieg.h"
#include "vlist.h"
33
#include "serialize.h"
34
#include "resource_handle.h"
35
#include "resource_unpack.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
36

37
38
#include "namespace.h"

39

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

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


59

60
61
static
int getByteorder(int byteswap)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
62
63
64
{
  int byteorder = -1;

65
  switch (HOST_ENDIANNESS)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
66
    {
67
68
69
70
71
72
73
74
75
76
    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
77
    }
78
  return byteorder;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
79
80
}

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

90
  int fileID = fileOpen(filename, "r");
Uwe Schulzweida's avatar
Uwe Schulzweida committed
91
92
93

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
100
  if ( fileRead(fileID, buffer, 8) != 8 ) return (CDI_EUFTYPE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
101
102
103

  fileRewind(fileID);

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

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

@Description
184
The function @func{streamInqFiletype} returns the filetype of a stream.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
185
186

@Result
187
@func{streamInqFiletype} returns the type of the file format,
Uwe Schulzweida's avatar
Uwe Schulzweida committed
188
one of the set of predefined CDI file format types.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
189
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
190
@func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV}, @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
192
193
194
195

@EndFunction
*/
int streamInqFiletype(int streamID)
{
196
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
197

198
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
199

Uwe Schulzweida's avatar
Uwe Schulzweida committed
200
  return (streamptr->filetype);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
201
202
203
204
205
}


int getByteswap(int byteorder)
{
206
  int byteswap;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
207

208
  switch (byteorder)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209
    {
210
211
212
213
214
    case CDI_BIGENDIAN:
    case CDI_LITTLEENDIAN:
    case CDI_PDPENDIAN:
      byteswap = (HOST_ENDIANNESS != byteorder);
      break;
215
216
217
    case -1:
      byteswap = -1;
      break;
218
219
    default:
      Error("unexpected byteorder %d query!", byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
220
221
222
223
224
    }

  return (byteswap);
}

225
226
227
228
229
230
/*
@Function  streamDefByteorder
@Title     Define the byte order

@Prototype void streamDefByteorder(int streamID, int byteorder)
@Parameter
231
    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
232
233
234
235
236
237
238
239
240
    @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
241
242
void streamDefByteorder(int streamID, int byteorder)
{
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

  streamptr->byteorder = byteorder;
248
  int 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
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
  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;
}


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

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

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

  return streamptr;
}


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


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


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

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

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

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

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

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

Thomas Jahns's avatar
Thomas Jahns committed
995
  int vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
996

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

For faster browsing, not all history is shown. View entire blame