iterator_fallback.c 10.1 KB
Newer Older
1
2
3
4
5
6
7
8
#include "iterator_fallback.h"

#include "cdi.h"
#include "cdi_int.h"
#include "dmemory.h"
#include "vlist.h"      //Required for vlist_t, which we require because there is no safe function available to access a variable name.

#include <assert.h>
9
#include <limits.h>
10
11
12
#include <stdlib.h>

//For more information on the condestruct() pattern, see comment in src/iterator_grib.c
13
static CdiFallbackIterator* cdiFallbackIterator_condestruct(CdiFallbackIterator* me, const char* path, int filetype)
14
15
16
{
  if(me) goto destruct;

17
  me = (CdiFallbackIterator *)xmalloc(sizeof(*me));
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  baseIterConstruct(&me->super, filetype);

  me->streamId = streamOpenRead(path);
  if(me->streamId == CDI_UNDEFID) goto destructSuper;
  me->vlistId = streamInqVlist(me->streamId);
  if(me->vlistId == CDI_UNDEFID) goto closeStream;
  me->variableCount = vlistNvars(me->vlistId);
  if(me->variableCount <= 0) goto closeStream;
  me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()

  //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
  me->curTimestep = 0;
  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
  me->curVariable = 0;
  me->curLevel = -1;
33
  me->path = strdup(path);
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  if(!me->path) goto closeStream;

  return me;

// ^        constructor code        ^
// |                                |
// v destructor/error-cleanup code  v

destruct:
  free(me->path);
closeStream:
  streamClose(me->streamId);
destructSuper:
  baseIterDestruct(&me->super);
  free(me);
  return NULL;
}

CdiIterator* cdiFallbackIterator_new(const char* path, int filetype)
{
54
  return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
}

//Fetches the info that is published by the variables in the base class from the current field.
static void fetchSuperInfo(CdiFallbackIterator* me)
{
  me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
  me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
  me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
  int param = vlistInqVarParam(me->vlistId, me->curVariable);
  cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
}

CdiFallbackIterator* cdiFallbackIterator_clone(CdiIterator* super)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;

  //Make another stream for this file. This yields an unadvanced iterator.
72
  CdiFallbackIterator* clone = cdiFallbackIterator_condestruct(NULL, me->path, me->super.filetype);
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  if(!clone) return NULL;

  //Point the clone to the same position in the file.
  clone->variableCount = me->variableCount;
  clone->curVariable = me->curVariable;
  clone->curLevelCount = me->curLevelCount;
  clone->curLevel = me->curLevel;
  clone->curTimestep = me->curTimestep;

  clone->super.isAdvanced = super->isAdvanced;
  if(super->isAdvanced) fetchSuperInfo(clone);

  return clone;
}

char* cdiFallbackIterator_serialize(CdiIterator* super)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;

  char* escapedPath = cdiEscapeSpaces(me->path);
93
  char* result = (char *)xmalloc(strlen(escapedPath)
94
95
                         + 5 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
  sprintf(result, "%s %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curTimestep);
96
97
98
99
100
101
  free(escapedPath);
  return result;
}

CdiFallbackIterator* cdiFallbackIterator_deserialize(const char* description)
{
102
  CdiFallbackIterator* me = (CdiFallbackIterator *)xmalloc(sizeof(*me));
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  if(!me) goto fail;

  description = baseIter_constructFromString(&me->super, description);

  while(*description == ' ') description++;
  me->path = cdiUnescapeSpaces(description, &description);
  if(!me->path) goto destructSuper;

  me->streamId = streamOpenRead(me->path);
  if(me->streamId == CDI_UNDEFID) goto freePath;
  me->vlistId = streamInqVlist(me->streamId);
  if(me->vlistId == CDI_UNDEFID) goto closeStream;

  //This reads one variable from the description string, does error checking, and advances the given string pointer.
  #define decodeValue(variable, description) do \
    { \
      const char* savedStart = description; \
      long long decodedValue = strtoll(description, (char**)&description, 0);   /*The cast is a workaround for the wrong signature of strtoll().*/ \
      variable = (int)decodedValue; \
      if(savedStart == description) goto closeStream; \
      if((long long)decodedValue != (long long)variable) goto closeStream; \
    } while(0)
  decodeValue(me->variableCount, description);
  decodeValue(me->curVariable, description);
  decodeValue(me->curLevelCount, description);
  decodeValue(me->curLevel, description);
  decodeValue(me->curTimestep, description);
  #undef decodeValue

  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
  if(me->super.isAdvanced) fetchSuperInfo(me);

  return me;

closeStream:
  streamClose(me->streamId);
freePath:
  free(me->path);
destructSuper:
  baseIterDestruct(&me->super);
  free(me);
fail:
  return NULL;
}

static int advance(CdiFallbackIterator* me)
{
  me->curLevel++;
  if(me->curLevel == me->curLevelCount)
    {
      me->curLevel = 0;
      me->curVariable++;
      if(me->curVariable == me->variableCount)
        {
          me->curVariable = 0;
          me->curTimestep++;
          if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
        }
    }
  return CDI_NOERR;
}

int cdiFallbackIterator_nextField(CdiIterator* super)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int result = advance(me);
  if(result) return result;

  if(!me->curLevel)
    { //Fetch the information that may have changed (we are processing a new variable/timestep if this point is reached).
      fetchSuperInfo(me);
      me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
    }
  return CDI_NOERR;
}

char* cdiFallbackIterator_inqTime(CdiIterator* super, bool getEndTime)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  if(getEndTime) return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
  int taxisId = vlistInqTaxis(me->vlistId);
  int date = taxisInqVdate(taxisId);
  int time = taxisInqVtime(taxisId);
  int year, month, day, hour, minute, second;
  cdiDecodeDate(date, &year, &month, &day);
  cdiDecodeTime(time, &hour, &minute, &second);
189
  char *result = (char *)xmalloc(   4+1 +2+1 +2+1 +2+1 +2+1 +2+4+1);
190
191
  sprintf(result, "%04d-%02d-%02dT%02d:%02d:%02d.000", year, month, day, hour, minute, second);
  return result;
192
193
194
195
196
197
}

int cdiFallbackIterator_levelType(CdiIterator* super, int levelSelector, char** outName, char** outLongName, char** outStdName, char** outUnit)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
Thomas Jahns's avatar
Thomas Jahns committed
198
  (void)levelSelector;
199
200
201
202
203
204
  #define copyString(outPointer, function) do \
    { \
      if(outPointer) \
        { \
          char tempBuffer[CDI_MAX_NAME]; \
          function(zaxisId, tempBuffer); \
205
          *outPointer = strdup(tempBuffer); \
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
        } \
    } \
  while(0)
  copyString(outName, zaxisInqName);    //FIXME: zaxisInqName is unsafe.
  copyString(outLongName, zaxisInqLongname);    //FIXME: zaxisInqLongname is unsafe.
  copyString(outStdName, zaxisInqStdname);    //FIXME: zaxisInqStdname is unsafe.
  copyString(outUnit, zaxisInqUnits);    //FIXME: zaxisInqUnits is unsafe.
  #undef copyString
  return zaxisInqLtype(zaxisId);
}

int cdiFallbackIterator_level(CdiIterator* super, int levelSelector, double* outValue1, double* outValue2)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);

  //handle NULL pointers once and for all
  double trash;
  if(!outValue1) outValue1 = &trash;
  if(!outValue2) outValue2 = &trash;

  //get the level value
  if(levelSelector)
    {
      *outValue1 = (zaxisInqLbounds(zaxisId, NULL))
                 ? zaxisInqLbound(zaxisId, me->curLevel)
                 : zaxisInqLevel(zaxisId, me->curLevel);
    }
  else
    {
      *outValue1 = (zaxisInqUbounds(zaxisId, NULL))
                 ? zaxisInqUbound(zaxisId, me->curLevel)
                 : zaxisInqLevel(zaxisId, me->curLevel);
    }
  *outValue2 = 0.0;

  //if this is a hybrid zaxis, lookup the coordinates in the vertical coordinate table
  ssize_t intLevel = (ssize_t)(2**outValue1);
  if(0 <= intLevel && intLevel < zaxisInqVctSize(zaxisId) - 1)
    {
      const double* coordinateTable = zaxisInqVctPtr(zaxisId);
      *outValue1 = coordinateTable[intLevel];
      *outValue2 = coordinateTable[intLevel + 1];
    }
  return CDI_NOERR;
}

int cdiFallbackIterator_zaxisUuid(CdiIterator* super, int* outVgridNumber, int* outLevelCount, unsigned char (*outUuid)[16])
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
  if(zaxisInqLtype(zaxisId) != ZAXIS_HYBRID) return CDI_EINVAL;
  if(outVgridNumber) *outVgridNumber = zaxisInqNumber(zaxisId);
  if(outLevelCount) *outLevelCount = zaxisInqNlevRef(zaxisId);
  if(outUuid) zaxisInqUUID(zaxisId, *outUuid);
  return CDI_NOERR;
}

char* cdiFallbackIterator_copyVariableName(CdiIterator* super)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  return vlistCopyVarName(me->vlistId, me->curVariable);
}

void cdiFallbackIterator_readField(CdiIterator* super, double* buffer, size_t* nmiss)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int missingValues = 0;
  streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
275
  if(nmiss) *nmiss = (size_t)missingValues;
276
277
278
279
280
281
282
}

void cdiFallbackIterator_readFieldF(CdiIterator* super, float* buffer, size_t* nmiss)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
  int missingValues = 0;
  streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
283
  if(nmiss) *nmiss = (size_t)missingValues;
284
285
286
287
288
}

void cdiFallbackIterator_delete(CdiIterator* super)
{
  CdiFallbackIterator* me = (CdiFallbackIterator*)super;
289
  cdiFallbackIterator_condestruct(me, NULL, 0);
290
}