source: XIOS3/trunk/extern/src_netcdf4/dapparse.c @ 2537

Last change on this file since 2537 was 409, checked in by ymipsl, 12 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2   See the COPYRIGHT file for more information. */
3
4#include "config.h"
5#include "dapparselex.h"
6
7/* Forward */
8
9static void addedges(OCnode* node);
10static void setroot(OCnode*,OClist*);
11static int isglobalname(char* name);
12static OCnode* newocnode(char* name, OCtype octype, DAPparsestate* state);
13static OCtype octypefor(Object etype);
14static char* scopeduplicates(OClist* list);
15static int check_int32(char* val, long* value);
16
17
18/****************************************************/
19
20/* Switch to DAS parsing SCAN_WORD definition */
21
22/* Use the initial keyword to indicate what we are parsing */
23void
24dap_tagparse(DAPparsestate* state, int kind)
25{
26    switch (kind) {
27    case SCAN_DATASET:
28    case SCAN_ERROR:
29        break;
30    case SCAN_ATTR:
31        dapsetwordchars(state->lexstate,1);
32        break;
33    default:
34        fprintf(stderr,"tagparse: Unknown tag argument: %d\n",kind);
35    }
36}
37
38
39Object
40dap_datasetbody(DAPparsestate* state, Object name, Object decls)
41{
42    OCnode* root = newocnode((char*)name,OC_Dataset,state);
43    root->subnodes = (OClist*)decls;
44    OCASSERT((state->root == NULL));
45    state->root = root;
46    state->root->root = state->root; /* make sure to cross link */
47    addedges(root);
48    setroot(root,state->ocnodes);
49    return NULL;
50}
51
52Object
53dap_attributebody(DAPparsestate* state, Object attrlist)
54{
55    OCnode* node = newocnode(NULL,OC_Attributeset,state);
56    OCASSERT((state->root == NULL));
57    state->root = node;
58    /* make sure to cross link */
59    state->root->root = state->root;
60    node->subnodes = (OClist*)attrlist;
61    addedges(node);
62    return NULL;
63}
64
65void
66dap_errorbody(DAPparsestate* state,
67          Object code, Object msg, Object ptype, Object prog)
68{
69    state->svcerror = 1;
70    state->code     = nulldup((char*)code);
71    state->message  = nulldup((char*)msg);
72    /* Ignore ptype and prog for now */
73}
74
75void
76dap_unrecognizedresponse(DAPparsestate* state)
77{
78    /* see if this is an HTTP error */
79    unsigned int httperr = 0;
80    int i;
81    char iv[32];
82    sscanf(state->lexstate->input,"%u ",&httperr);
83    sprintf(iv,"%u",httperr);
84    state->lexstate->next = state->lexstate->input;
85    /* Limit the amount of input to prevent runaway */
86    for(i=0;i<4096;i++) {if(state->lexstate->input[i] == '\0') break;}
87    state->lexstate->input[i] = '\0';
88    dap_errorbody(state,iv,state->lexstate->input,NULL,NULL);
89}
90
91Object
92dap_declarations(DAPparsestate* state, Object decls, Object decl)
93{
94    OClist* alist = (OClist*)decls;
95    if(alist == NULL)
96         alist = oclistnew();
97    else
98        oclistpush(alist,(ocelem)decl);
99    return alist;
100}
101
102Object
103dap_arraydecls(DAPparsestate* state, Object arraydecls, Object arraydecl)
104{
105    OClist* alist = (OClist*)arraydecls;
106    if(alist == NULL)
107        alist = oclistnew();
108    else
109        oclistpush(alist,(ocelem)arraydecl);
110    return alist;
111}
112
113Object
114dap_arraydecl(DAPparsestate* state, Object name, Object size)
115{
116    long value;
117    OCnode* dim;
118    if(!check_int32(size,&value))
119        dap_parse_error(state,"Dimension not an integer");
120    if(name != NULL)
121        dim = newocnode((char*)name,OC_Dimension,state);
122    else
123        dim = newocnode(NULL,OC_Dimension,state);
124    dim->dim.declsize = value;
125    return dim;
126}
127
128Object
129dap_attrlist(DAPparsestate* state, Object attrlist, Object attrtuple)
130{
131    OClist* alist = (OClist*)attrlist;
132    if(alist == NULL)
133        alist = oclistnew();
134    else {
135        char* dupname;
136        if(attrtuple != NULL) {/* NULL=>alias encountered, ignore */
137            oclistpush(alist,(ocelem)attrtuple);
138            if((dupname=scopeduplicates(alist))!=NULL) {
139                dap_parse_error(state,"Duplicate attribute names in same scope: %s",dupname);
140                /* Remove this attribute */
141                oclistpop(alist);
142            }
143        }
144    }
145    return alist;
146}
147
148Object
149dap_attrvalue(DAPparsestate* state, Object valuelist, Object value, Object etype)
150{
151    OClist* alist = (OClist*)valuelist;
152    if(alist == NULL) alist = oclistnew();
153    /* Watch out for null values */
154    if(value == NULL) value = "";
155    oclistpush(alist,(ocelem)strdup(value));
156    return alist;
157}
158
159Object
160dap_attribute(DAPparsestate* state, Object name, Object values, Object etype)
161{
162    OCnode* att;
163    att = newocnode((char*)name,OC_Attribute,state);
164    att->etype = octypefor(etype);
165    att->att.values = (OClist*)values;
166    return att;
167}
168
169Object
170dap_attrset(DAPparsestate* state, Object name, Object attributes)
171{
172    OCnode* attset;
173    attset = newocnode((char*)name,OC_Attributeset,state);
174    /* Check var set vs global set */
175    attset->att.isglobal = isglobalname(name);
176    attset->subnodes = (OClist*)attributes;
177    addedges(attset);
178    return attset;
179}
180
181static int
182isglobalname(char* name)
183{
184    int len = strlen(name);
185    int glen = strlen("global");
186    char* p;
187    if(len < glen) return 0;
188    p = name + (len - glen);
189    if(strcasecmp(p,"global") != 0)
190        return 0;
191    return 1;
192}
193
194#if 0
195static int
196isnumber(const char* text)
197{
198    for(;*text;text++) {if(!isdigit(*text)) return 0;}
199    return 1;
200}
201#endif
202
203static void
204dimension(OCnode* node, OClist* dimensions)
205{
206    unsigned int i;
207    unsigned int rank = oclistlength(dimensions);
208    node->array.dimensions = (OClist*)dimensions;
209    node->array.rank = rank;
210    for(i=0;i<rank;i++) {
211        OCnode* dim = (OCnode*)oclistget(node->array.dimensions,i);
212        dim->dim.array = node;
213        dim->dim.arrayindex = i;
214#if 0
215        if(dim->name == NULL) {
216            dim->dim.anonymous = 1;
217            dim->name = dimnameanon(node->name,i);
218        }
219#endif
220    }
221}
222
223char*
224dimnameanon(char* basename, unsigned int index)
225{
226    char name[64];
227    sprintf(name,"%s_%d",basename,index);
228    return strdup(name);
229}
230
231Object
232dap_makebase(DAPparsestate* state, Object name, Object etype, Object dimensions)
233{
234    OCnode* node;
235    node = newocnode((char*)name,OC_Primitive,state);
236    node->etype = octypefor(etype);
237    dimension(node,(OClist*)dimensions);
238    return node;
239}
240
241Object
242dap_makestructure(DAPparsestate* state, Object name, Object dimensions, Object fields)
243{
244    OCnode* node;
245    char* dupname;   
246    if((dupname=scopeduplicates((OClist*)fields))!= NULL) {
247        dap_parse_error(state,"Duplicate structure field names in same scope: %s.%s",(char*)name,dupname);
248        return (Object)NULL;
249    }
250    node = newocnode(name,OC_Structure,state);
251    node->subnodes = fields;
252    dimension(node,(OClist*)dimensions);
253    addedges(node);
254    return node;
255}
256
257Object
258dap_makesequence(DAPparsestate* state, Object name, Object members)
259{
260    OCnode* node;
261    char* dupname;   
262    if((dupname=scopeduplicates((OClist*)members)) != NULL) {
263        dap_parse_error(state,"Duplicate sequence member names in same scope: %s.%s",(char*)name,dupname);
264        return (Object)NULL;
265    }
266    node = newocnode(name,OC_Sequence,state);
267    node->subnodes = members;
268    addedges(node);
269    return node;
270}
271
272Object
273dap_makegrid(DAPparsestate* state, Object name, Object arraydecl, Object mapdecls)
274{
275    OCnode* node;
276    /* Check for duplicate map names */
277    char* dupname;   
278    if((dupname=scopeduplicates((OClist*)mapdecls)) != NULL) {
279        dap_parse_error(state,"Duplicate grid map names in same scope: %s.%s",(char*)name,dupname);
280        return (Object)NULL;
281    }
282    node = newocnode(name,OC_Grid,state);
283    node->subnodes = (OClist*)mapdecls;
284    oclistinsert(node->subnodes,0,(ocelem)arraydecl);
285    addedges(node);
286    return node;
287}
288
289static void
290addedges(OCnode* node)
291{
292    unsigned int i;
293    if(node->subnodes == NULL) return;
294    for(i=0;i<oclistlength(node->subnodes);i++) {
295        OCnode* subnode = (OCnode*)oclistget(node->subnodes,i);
296        subnode->container = node;
297    }
298}
299
300static void
301setroot(OCnode* root, OClist* ocnodes)
302{
303    int i;
304    for(i=0;i<oclistlength(ocnodes);i++) {
305        OCnode* node = (OCnode*)oclistget(ocnodes,i);
306        node->root = root;
307    }
308}
309
310int
311daperror(DAPparsestate* state, const char* msg)
312{
313    dap_parse_error(state,msg);
314    return 0;
315}
316
317static char*
318flatten(char* s, char* tmp, int tlen)
319{
320    int c;
321    char* p,*q;
322    strncpy(tmp,s,tlen);
323    tmp[tlen] = '\0';
324    p = (q = tmp);
325    while((c=*p++)) {
326        switch (c) {
327        case '\r': case '\n': break;
328        case '\t': *q++ = ' '; break;
329        case ' ': if(*p != ' ') *q++ = c; break;
330        default: *q++ = c;
331        }
332    }
333    *q = '\0';
334    return tmp;
335}
336
337/* Create an ocnode and capture in the state->ocnode list */
338static OCnode*
339newocnode(char* name, OCtype octype, DAPparsestate* state)
340{
341    OCnode* node = ocmakenode(name,octype,state->root);
342    oclistpush(state->ocnodes,(ocelem)node);
343    return node;
344}
345
346static int
347check_int32(char* val, long* value)
348{
349    char* ptr;
350    int ok = 1;
351    long iv = strtol(val,&ptr,0); /* 0=>auto determine base */
352    if((iv == 0 && val == ptr) || *ptr != '\0') {ok=0; iv=1;}
353    else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) ok=0;
354    if(value != NULL) *value = iv;
355    return ok;
356}
357
358static char*
359scopeduplicates(OClist* list)
360{
361    unsigned int i,j;
362    for(i=0;i<oclistlength(list);i++) {
363        OCnode* io = (OCnode*)oclistget(list,i);
364        for(j=i+1;j<oclistlength(list);j++) {
365            OCnode* jo = (OCnode*)oclistget(list,j);
366            if(strcmp(io->name,jo->name)==0)
367                return io->name;
368        }
369    }
370    return NULL;
371}
372
373static OCtype
374octypefor(Object etype)
375{
376    switch ((long)etype) {
377    case SCAN_BYTE: return OC_Byte;
378    case SCAN_INT16: return OC_Int16;
379    case SCAN_UINT16: return OC_UInt16;
380    case SCAN_INT32: return OC_Int32;
381    case SCAN_UINT32: return OC_UInt32;
382    case SCAN_FLOAT32: return OC_Float32;
383    case SCAN_FLOAT64: return OC_Float64;
384    case SCAN_URL: return OC_URL;
385    case SCAN_STRING: return OC_String;
386    default: abort();
387    }
388    return OC_NAT;
389}
390
391void
392dap_parse_error(DAPparsestate* state, const char *fmt, ...)
393{
394    size_t len, suffixlen, prefixlen;
395    va_list argv;
396    char* tmp = NULL;
397    va_start(argv,fmt);
398    (void) vfprintf(stderr,fmt,argv) ;
399    (void) fputc('\n',stderr) ;
400    len = strlen(state->lexstate->input);
401    suffixlen = strlen(state->lexstate->next);
402    prefixlen = (len - suffixlen);
403    tmp = (char*)ocmalloc(len+1);
404    flatten(state->lexstate->input,tmp,prefixlen);
405    (void) fprintf(stderr,"context: %s",tmp);
406    flatten(state->lexstate->next,tmp,suffixlen);
407    (void) fprintf(stderr,"^%s\n",tmp);
408    (void) fflush(stderr);      /* to ensure log files are current */
409    ocfree(tmp);
410}
411
412static void
413dap_parse_cleanup(DAPparsestate* state)
414{
415    daplexcleanup(&state->lexstate);
416    if(state->ocnodes != NULL) ocfreenodes(state->ocnodes);
417    state->ocnodes = NULL;
418    free(state);
419}
420
421static DAPparsestate*
422dap_parse_init(char* buf)
423{
424    DAPparsestate* state = (DAPparsestate*)ocmalloc(sizeof(DAPparsestate)); /*ocmalloc zeros*/
425    MEMCHECK(state,(DAPparsestate*)NULL);
426    if(buf==NULL) {
427        dap_parse_error(state,"dap_parse_init: no input buffer");
428        dap_parse_cleanup(state);
429        return NULL;
430    }
431    daplexinit(buf,&state->lexstate);
432    return state;
433}
434
435/* Wrapper for dapparse */
436OCerror
437DAPparse(OCstate* conn, OCtree* tree, char* parsestring)
438{
439    DAPparsestate* state = dap_parse_init(parsestring);
440    int parseresult;
441    OCerror ocerr = OC_NOERR;
442    state->ocnodes = oclistnew();
443    state->conn = conn;
444    if(ocdebug >= 2)
445        dapdebug = 1;
446    parseresult = dapparse(state);
447    if(parseresult == 0) {/* 0 => parse ok */
448        /* Check to see if we ended up parsing an error message */
449        if(state->svcerror) {
450            conn->error.code = nulldup(state->code);
451            conn->error.message = nulldup(state->message);
452            tree->root = NULL;
453            /* Attempt to further decipher the error code */
454            if(state->code != NULL
455                && (strcmp(state->code,"404") == 0 /* tds returns 404 */
456                    || strcmp(state->code,"5") == 0)) /* hyrax returns 5 */
457                ocerr = OC_ENOFILE;
458            else
459                ocerr = OC_EDAPSVC;
460        } else {
461            OCASSERT((state->root != NULL));   
462            tree->root = state->root;
463            state->root = NULL; /* avoid reclaim */
464            tree->nodes = state->ocnodes;
465            state->ocnodes = NULL; /* avoid reclaim */
466            tree->root->tree = tree;
467            ocerr = OC_NOERR;
468        }
469    } else { /* Parse failed */
470        switch (tree->dxdclass) {
471        case OCDAS: ocerr = OC_EDAS; break;
472        case OCDDS: ocerr = OC_EDDS; break;
473        case OCDATADDS: ocerr = OC_EDATADDS; break;
474        default: ocerr = OC_EDAPSVC;
475        }               
476    }
477    dap_parse_cleanup(state);
478    return ocerr;
479}
480
Note: See TracBrowser for help on using the repository browser.