File: genchar.c

package info (click to toggle)
netcdf 1%3A4.1.3-7.2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 46,040 kB
  • ctags: 25,265
  • sloc: ansic: 169,389; fortran: 17,742; sh: 13,203; cpp: 10,960; f90: 7,903; yacc: 2,832; xml: 2,129; makefile: 2,034; lex: 1,210
file content (472 lines) | stat: -rwxr-xr-x 13,171 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*********************************************************************
 *   Copyright 2009, UCAR/Unidata
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
 *********************************************************************/
/* $Id: genchar.c,v 1.6 2010/05/24 19:59:57 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/genchar.c,v 1.6 2010/05/24 19:59:57 dmh Exp $ */

#include "includes.h"

/******************************************************/
/* Code for generating char variables etc; mostly
   language independent */
/******************************************************/

/*
Matching strings to char variables, attributes, and vlen
constants is challenging because it is desirable to mimic
the original ncgen. The "algorithms" used there have no
simple characterization (such as "abc" == {'a','b','c'}).
So, this rather ugly code is kept in this file
and a variety of heuristics are used to mimic ncgen.
*/

static void gen_chararrayr(Dimset*, Bytebuffer*, int index, Datalist*, int fillchar, size_t);

extern List* vlenconstants;


void
gen_charattr(Symbol* asym, Bytebuffer* databuf)
{
    Datasrc* src;
    Constant* con;

    if(asym->data == NULL) return;
    src = datalist2src(asym->data);
    while((con=srcnext(src))) {
	switch (con->nctype) {
	/* Following list should be consistent with isstringable */
	case NC_CHAR:
	    bbAppend(databuf,con->value.charv);
	    break;
	case NC_BYTE:
	    bbAppend(databuf,con->value.int8v);
	    break;
	case NC_UBYTE:
	    bbAppend(databuf,con->value.uint8v);
	    break;
	case NC_STRING:
	    bbCat(databuf,con->value.stringv.stringv);
	    bbNull(databuf);
	    break;
	case NC_FILL:
	    bbAppend(databuf,NC_FILL_CHAR);
	    break;
	default:
	    semerror(srcline(src),
		     "Encountered non-string constant in attribute: %s",
		     asym->name);
	    return;
	}
    }
}

#ifdef IGNORE
static void
datalistpad(Datalist* data, size_t targetlen)
{
    int i;
    /* pad this datalist to target length */
    for(i=data->length;i<targetlen;i++) {
        Constant ccon,scon;
        Datalist* sublist;
        ccon.nctype = NC_COMPOUND;
        ccon.lineno = 0;
        ccon.filled = 0;
        ccon.value.compoundv = builddatalist(1);
        scon.value.stringv.len = 0;
        scon.value.stringv.stringv = strdup("");
        scon.nctype = NC_STRING;
        scon.lineno = 0;
        scon.filled = 0;
        sublist = ccon.value.compoundv;
        dlappend(sublist,&scon);
    }
}
#endif


/*Note see comment before semantics.c:walkchararray.
  This code finishes off the processing in those comments.
  In particular, at this point, the sizes of all
  unlimited is known. Assuming the same set of 
  cases as in that comment, we do the additional actions.
  Cases:
    1. the variable's dimension set has no unlimiteds
       Action:
       1. do nothing
    2. the dimension set has one or more unlimiteds.
       This means that we have to recursively deal with
       nested compound instances.

       The last (rightmost) unlimited will correspond
       to a sequence of stringables.
       This has two special subcases
       2a. the last dimension IS NOT unlimited
	   Actions:
	   1. pad the concat to the size of the last dimension
       2b. the last dimension IS unlimited
	   Actions:
	   1. pad the concata to the actual unlimited size

    3. For each dimension to the left of the last
       unlimited, there are two cases.
       3a. dimension is NOT unlimited
	   ACTION: 
	   1. pad
       3b. dimension IS unlimited
	   ACTION: 
	   1. pad
*/



void
gen_chararray(Symbol* vsym, Bytebuffer* databuf, Datalist* fillsrc)
{
    int i,fillchar = getfillchar(fillsrc);
    Datalist* data = vsym->data;
    int lastunlimitedindex = lastunlimited(&vsym->typ.dimset);

    /* If there is no unlimited, then treat similarly to a field array */
    if(lastunlimitedindex < 0) {
        /* Semantics.c:walkchararray will have done all the hard work */
	for(i=0;i<data->length;i++) {
	    Constant* con = data->data+i;
            ASSERT(con->nctype == NC_STRING);
            bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
	}
    } else {/* dimset has at least 1 unlimited */
	/* Compute sub array size for extensions */
	size_t subsize;
        Dimset* dimset = &vsym->typ.dimset;
	for(subsize=1,i=lastunlimitedindex+1;i<dimset->ndims;i++) {
	    Symbol* dim =  dimset->dimsyms[i];
	    size_t declsize = dim->dim.declsize;
	    subsize *= (declsize == NC_UNLIMITED ? dim->dim.unlimitedsize : declsize);
        }
        gen_chararrayr(&vsym->typ.dimset, databuf, 0, data, fillchar, subsize);
    }
    bbNull(databuf);
}

static void
gen_chararrayr(Dimset* dimset, Bytebuffer* databuf, int index, Datalist* data,
               int fillchar, size_t subsize)
{
    int i;
    Symbol* dim = dimset->dimsyms[index];
    int isunlimited = dim->dim.declsize == NC_UNLIMITED;
    int lastunlimitedindex = lastunlimited(dimset);
    
    /* Split on last unlimited */
    if(index == lastunlimitedindex) {
	Constant* con;
	/* pad to the unlimited size of the dimension * subsize */
	ASSERT(data->length == 1);
	con = data->data;
	ASSERT(con->nctype == NC_STRING);
	padstring(con,dim->dim.unlimitedsize*subsize,fillchar);
	bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
    } else {/* index < lastunlimitedindex*/
	/* data should be a set of compounds */
	size_t expected = (isunlimited ? dim->dim.unlimitedsize : dim->dim.declsize );
	for(i=0;i<expected;i++) {

	    if(i >= data->length) {/* pad buffer */
		int j;
	        for(j=0;j<subsize;j++) bbAppend(databuf,fillchar);
	    } else {
	        Constant* con = data->data+i;
                if(con->nctype != NC_COMPOUND) continue;
                /* recurse */
                gen_chararrayr(dimset,databuf,index+1,con->value.compoundv,
                               fillchar,subsize);
	    }
        }
    }
}

/*
Since the field has fixed
dimensions, we can just
read N elements where N
is the product of the dimensions.
*/

void
gen_charfield(Datasrc* src, Odometer* odom, Bytebuffer* fieldbuf)
{
    Constant* con = srcnext(src);

    /* Semantics.c:walkcharfieldarray will have done all the hard work */
    ASSERT(con->nctype == NC_STRING);
    bbAppendn(fieldbuf,con->value.stringv.stringv,con->value.stringv.len);
}

void
gen_charvlen(Datasrc* vlensrc, Bytebuffer* databuf)
{
    Constant* con = srcnext(vlensrc);

    /* Semantics.c:walkcharfieldarray will have done all the hard work */
    ASSERT(con->nctype == NC_STRING);
    bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
#ifdef IGNORE
    int count;
    Bytebuffer* vlenbuf = bbNew();
    Constant* con;

    count = 0;
    while((con=srcnext(vlensrc)) != NULL) {
	if(!isstringable(con->nctype)) {
	    semerror(srcline(vlensrc),
		     "Encountered non-string constant in vlen constant");
	    goto done;
        }
	count += collectstring(con,0,vlenbuf);
    }
done:
    bbFree(vlenbuf);
#endif
}

/**************************************************/

#ifdef IGNORE
static Datalist*
dividestringlist(char* s, size_t chunksize, int lineno)
{
    size_t slen,div,rem;
    Datalist* charlist;
    Constant* chars;

    if(s == NULL) s = "";
    slen = strlen(s);
    ASSERT(chunksize > 0);
    div = slen / chunksize;
    rem = slen % chunksize;
    if(rem > 0) div++;

    charlist = builddatalist(div);
    if(!charlist) return NULL;
    charlist->readonly = 0;
    charlist->length = div;
    chars=charlist->data;
    if(slen == 0) {
	/* Special case for null string */
	charlist->length = 1;
	chars->nctype = NC_STRING;
	chars->lineno = lineno;
        chars->value.stringv.len = 0;
        chars->value.stringv.stringv = nulldup("");
    } else
    {
	int i;
	for(i=0;i<(div-1);i++,chars++) {
	    chars->nctype = NC_STRING;
	    chars->lineno = lineno;
            chars->value.stringv.len = chunksize;
	    chars->value.stringv.stringv = (char*)emalloc(chunksize+1);
	    memcpy(chars->value.stringv.stringv,s,chunksize);
	    chars->value.stringv.stringv[chunksize] = '\0';
	    s += chunksize;
	}
	/* Do last chunk */
        chars->nctype = NC_STRING;
	chars->lineno = lineno;
        chars->value.stringv.len = strlen(s);
        chars->value.stringv.stringv = nulldup(s);
    }
    return charlist;
}
#endif

#ifdef IGNORE
static int
stringexplode(Datasrc* src, size_t chunksize)
{
    Constant* con;
    Datalist* charlist;

    if(!isstring(src)) return 0;
    con = srcnext(src);
    charlist = dividestringlist(con->value.stringv.stringv,chunksize,srcline(src));
    srcpushlist(src,charlist);
    return 1;
}
#endif

#ifdef IGNORE
static Datalist*
padstringlist(char* s, size_t chunksize, int lineno)
{
    size_t slen;
    Datalist* charlist;
    Constant* chars;

    if(s == NULL) s = "";
    slen = strlen(s);
    ASSERT(chunksize > 0);
    ASSERT(chunksize >= slen);

    charlist = builddatalist(1);
    if(!charlist) return NULL;
    charlist->readonly = 0;
    charlist->length = 1;
    chars=charlist->data;
    chars->nctype = NC_STRING;
    chars->lineno = lineno;
    chars->value.stringv.len = chunksize;
    chars->value.stringv.stringv = emalloc(chunksize+1);
    if(chars->value.stringv.stringv == NULL) return NULL;
    memset((void*)chars->value.stringv.stringv,0,chunksize+1);
    strcpy(chars->value.stringv.stringv,s);
    return charlist;
}
#endif

#ifdef IGNORE
static int
stringpad(Datasrc* src, size_t chunksize)
{
    Constant* con;
    Datalist* charlist;

    if(!isstring(src)) return 0;
    con = srcnext(src);
    charlist = padstringlist(con->value.stringv.stringv,chunksize,srcline(src));
    srcpushlist(src,charlist);
    return 1;
}
#endif

#ifdef IGNORE
/* Fill */
static int
fillstring(size_t declsize, int len, Bytebuffer* databuf, int fillchar)
{
    for(;len<declsize;len++)
        bbAppend(databuf,fillchar);
    return len;
}
#endif

int
getfillchar(Datalist* fillsrc)
{
    /* Determine the fill char */
    int fillchar = 0;
    if(fillsrc != NULL && fillsrc->length > 0) {
	Constant* ccon = fillsrc->data;
	if(ccon->nctype == NC_CHAR) {
	    fillchar = ccon->value.charv;
	} else if(ccon->nctype == NC_STRING) {	    
	    if(ccon->value.stringv.len > 0) {
	        fillchar = ccon->value.stringv.stringv[0];
	    }
	}
    }
    if(fillchar == 0) fillchar = NC_FILL_CHAR; /* default */
    return fillchar;
}


/*
Take constant, and if stringable, append to databuf as characters.
If the constant, as a string, is not a multiple in length of dimsize,
then pad using fillchar
*/

int
collectstring(Constant* con, size_t dimsize, Bytebuffer* databuf, int fillchar)
{
    size_t padding = 0;

    if(dimsize == 0) dimsize = 1;
    if(con == NULL) con = &fillconstant;
    switch (con->nctype) {
    case NC_STRING: {
        char* s = con->value.stringv.stringv;
        size_t slen = con->value.stringv.len;
        padding = (slen % dimsize == 0 ? 0 : dimsize - (slen % dimsize));
        if(slen > 0) bbAppendn(databuf,s,slen);
        } break;
    case NC_FILLVALUE:
        padding = dimsize;
        break;
    case NC_CHAR:
    case NC_BYTE:
    case NC_UBYTE:
        /* Append */
        bbAppend(databuf,con->value.charv);
        break;
    default:
        semerror(con->lineno,"Non string or character constant encountered");
        return 0;
    }
    while(padding-- > 0) bbAppend(databuf,fillchar);
    bbNull(databuf);
    return 1;
}

/* Given a list of stringables (e.g. strings),
   make each be a multiple in size of size.
   Then concat them all together and create
   and return a new Constant containg that string.
*/   
int
buildcanonicalcharlist(Datalist* list, size_t size, int fillchar, Constant* conp)
{
    int i;
    Bytebuffer* buf = bbNew();
    Constant* con = NULL;
    Constant newcon = nullconstant;

    if(list->length == 0) {
      /* If an empty list, then produce a string of size size using fillchar*/
      for(i=0;i<size;i++) bbAppend(buf,fillchar);
    } else for(i=0;i<list->length;i++) {
	con = list->data+i;
	if(!collectstring(con,size,buf,fillchar)) return 0;
    }
    bbNull(buf);
    /* Construct the new string constant */ 
    newcon.nctype = NC_STRING;
    newcon.lineno = (list->length == 0 ? 0: list->data[0].lineno);
    newcon.value.stringv.len = bbLength(buf);
    newcon.value.stringv.stringv = bbDup(buf);
    bbFree(buf);
    if(conp) *conp = newcon;
    return 1;
}

void
padstring(Constant* con, size_t desiredlength, int fillchar)
{
    size_t len = con->value.stringv.len;
    char* s = con->value.stringv.stringv;
    ASSERT(con->nctype == NC_STRING);
    if(len > desiredlength) {
	semerror(con->lineno,"String constant too long");
	con->value.stringv.len = desiredlength;
    } else if(len < desiredlength) {
	s = realloc(s,desiredlength+1);
	memset(s+len,fillchar,(desiredlength - len));
        s[desiredlength] = '\0';		
        con->value.stringv.stringv = s;
        con->value.stringv.len = desiredlength;
    }
}
#ifdef IGNORE
static size_t
padround(size_t udimsize, Constant* con)
{
    size_t r;
    ASSERT(con->nctype == NC_STRING);
    r = (con->value.stringv.len + (udimsize-1))/udimsize;
    r = r * udimsize;
    return r;
}
#endif