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