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 = -1;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
207

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

  return (byteswap);
}

222
223
224
225
226
227
/*
@Function  streamDefByteorder
@Title     Define the byte order

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

242
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
243
244

  streamptr->byteorder = byteorder;
245
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
246
247
248
249
250
251

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

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

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

	break;
      }
#endif
    }
277
  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
278
279
}

280
281
282
283
284
285
/*
@Function  streamInqByteorder
@Title     Get the byte order

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

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

302
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
303

Uwe Schulzweida's avatar
Uwe Schulzweida committed
304
  return (streamptr->byteorder);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
305
306
307
}


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

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


324
const char *streamFilename(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
325
{
326
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
327

328
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
329
330

  return (streamptr->filename);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
331
332
}

333
static
334
long cdiInqTimeSize(int streamID)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
335
336
{
  int tsID = 0, nrecs;
337
  stream_t *streamptr = stream_to_pointer(streamID);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
338

339
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
340

341
  long ntsteps = streamptr->ntsteps;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
342

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

  return (ntsteps);
}

350
351
static
int cdiInqContents(stream_t * streamptr)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
352
353
354
{
  int status = 0;

Thomas Jahns's avatar
Thomas Jahns committed
355
  int filetype = streamptr->filetype;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
356
357
358
359
360

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

	status = CDI_ELIBNAVAIL;
404
        break;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
405
406
407
408
409
      }
    }

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

  return (status);
}

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

  streamptr->filetype = filetype;

513
514
515
516
  return fileID;
}


517
int
518
streamOpenID(const char *filename, char filemode, int filetype,
519
             int resH)
520
521
522
{
  int fileID = CDI_UNDEFID;
  int status;
523

524
  if ( CDI_Debug )
525
    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
526
            filename?filename:"(NUL)");
527

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

530
531
  stream_t *streamptr = stream_new_entry(resH);
  int streamID = CDI_ESYSTEM;
532

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

539
    fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
540
541
542
  }

  if (fileID < 0)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
543
    {
544
      Free(streamptr->record);
545
      stream_delete_entry(streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546
547
548
549
      streamID = fileID;
    }
  else
    {
550
551
      streamID  = streamptr->self;

552
      if ( streamID < 0 ) return (CDI_ELIMIT);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
553

554
      streamptr->filemode = filemode;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
555
556
      streamptr->filename = strdupx(filename);
      streamptr->fileID   = fileID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
557

558
      if ( filemode == 'r' )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
559
	{
560
	  int vlistID = vlistCreate();
561
562
563
	  if ( vlistID < 0 ) return(CDI_ELIMIT);

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

Uwe Schulzweida's avatar
Uwe Schulzweida committed
572
573
574
  return (streamID);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

  return (streamID);
}

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

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

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

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

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

@Example
719
720
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
721
722

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

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

  if ( filetype < 0 ) return (filetype);

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

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

  return (streamID);
}


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

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

  if ( filetype < 0 ) return (filetype);

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

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

  return (streamID);
}

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

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

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

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

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

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

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

821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
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);

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


874
static stream_t *stream_new_entry(int resH)
875
876
877
878
879
{
  stream_t *streamptr;

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

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

  return streamptr;
}


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


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


Uwe Schulzweida's avatar
Uwe Schulzweida committed
969
970
/*
@Function  streamClose
Uwe Schulzweida's avatar
Uwe Schulzweida committed
971
@Title     Close an open dataset
Uwe Schulzweida's avatar
Uwe Schulzweida committed
972
973
974

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

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

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

988
  stream_check_ptr(__func__, streamptr);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
989
990

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

993
  vlistID  = streamptr->vlistID;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
994

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

999
  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
1000

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