1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2   See the COPYRIGHT file for more information. */
3
4#include "config.h"
5#include <stdlib.h>
6#include <assert.h>
7#include <string.h>
8
9#include "ocinternal.h"
10#include "ocdebug.h"
11#include "ocdump.h"
12#include "oclog.h"
13#include "occlientparams.h"
14#include "occurlfunctions.h"
15#include "ochttp.h"
16
17#undef TRACK
18
19/**************************************************/
20
21/* Track legal ids */
22
23#define ocverify(o) ((o) != NULL && (((OCheader*)(o))->magic == OCMAGIC)?1:0)
24
25#define ocverifyclass(o,cl) ((o) != NULL && (((OCheader*)(o))->occlass == cl)?1:0)
26
27#define OCVERIFYX(k,x,r) if(!ocverify(x)||!ocverifyclass(x,k)) {return (r);}
28#define OCVERIFY(k,xOCVERIFYX(k,x,OCTHROW(OC_EINVAL))
29
30#define OCDEREF(T,s,x) (s)=(T)(x)
31
32/**************************************************/
33/*!\file oc.c
34*/
35
36/*!\defgroup Link Link Management
37@{*/
38
39/*!
40This procedure opens a link to some OPeNDAP
41data server to request a specific url, possibly with constraints.
42It returns an <i>OClink</i> object.
43\param[in] url The url for the OPeNDAP server to which a connection
44is created and the request is made.
45\param[out] linkp A pointer to a location into which the link
46object is to be returned.
47
48\retval OC_NOERR The link was successfully created.
49\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
50*/
51
52OCerror
53oc_open(const char* urlOCobjectlinkp)
54{
55    OCerror ocerr;
56    OCstatestate = NULL;
57    if(!ocglobalstate.initializedoc_initialize();
58    ocerr = ocopen(&state,url);
59    if(ocerr == OC_NOERR && linkp) {
60      *linkp = (OCobject)(state);
61    } else {
62      if(state) free(state);
63    }
64
65    return OCTHROW(ocerr);
66}
67
68/*!
69This procedure closes a previously opened
70link and releases all resources associated with
71that link.
72\param[in] link The link object to be closed.
73
74\retval OC_NOERR The link was successfully closed.
75\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
76*/
77
78OCerror
79oc_close(OCobject link)
80{
81    OCstatestate;
82    OCVERIFY(OC_State,link);
83    OCDEREF(OCstate*,state,link);
84    occlose(state);
85    return OCTHROW(OC_NOERR);
86}
87
88/** @} */
89
90/*!\defgroup Tree Tree Management
91@{*/
92
93/*!
94This procedure is used to send requests to the server
95to obtain either a DAS, DDS, or DATADDS response
96and produce a corresponding tree.
97It fetchs and parses a given class of DXD the server specified
98at open time, and using a specified set of constraints
99and flags.
100
101\param[in] link The link through which the server is accessed.
102\param[in] constraint The constraint to be applied to the request.
103\param[in] dxdkind The OCdxd value indicating what to fetch (i.e.
104DAS, DDS, or DataDDS).
105\param[in] flags The 'OR' of OCflags to control the fetch:
106The OCONDISK flag is defined to cause the fetched
107xdr data to be stored on disk instead of in memory.
108\param[out] rootp A pointer a location to store
109the root node of the tree associated with the the request.
110
111\retval OC_NOERR The procedure executed normally.
112\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
113*/
114
115OCerror
116oc_fetch(OCobject link, const char* constraint,
117                 OCdxd dxdkindOCflags flagsOCobjectrootp)
118{
119    OCstatestate;
120    OCerror ocerr = OC_NOERR;
121    OCnoderoot;
122    OCVERIFY(OC_State,link);
123    OCDEREF(OCstate*,state,link);
124
125    ocerr = ocfetch(state,constraint,dxdkind,flags,&root);
126    if(ocerr) return OCTHROW(ocerr);
127
128    if(rootp) *rootp = (OCobject)(root);
129    return OCTHROW(ocerr);
130}
131
132
133/*!
134This procedure reclaims all resources
135associated with a given tree of objects
136associated with a given root.
137If the root is that of a DataDDS, then the associated data tree
138will be reclaimed as well.
139
140\param[in] link The link through which the server is accessed.
141\param[in] ddsroot The root of the tree to be reclaimed.
142
143\retval OC_NOERR The procedure executed normally.
144\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
145*/
146
147OCerror
148oc_root_free(OCobject linkOCobject ddsroot)
149{
150    OCnoderoot;
151    OCVERIFY(OC_Node,ddsroot);
152    OCDEREF(OCnode*,root,ddsroot);
153
154    ocroot_free(root);
155    return OCTHROW(OC_NOERR);
156}
157
158/*!
159This procedure returns the textual part of
160a DAS, DDS, or DATADDS request exactly as sent by the server.
161
162\param[in] link The link through which the server is accessed.
163\param[in] ddsroot The root of the tree whose text is to be returned.
164
165\retval OC_NOERR The procedure executed normally.
166\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
167*/
168
169const char*
170oc_tree_text(OCobject linkOCobject ddsroot)
171{
172    OCnoderoot = NULL;
173    OCVERIFYX(OC_Node,ddsroot,NULL);
174    OCDEREF(OCnode*,root,ddsroot);
175
176    if(root == NULL) return NULL;
177    root = root->root;
178    if(root->tree == NULL) return NULL;
179    return root->tree->text;
180}
181
182/**@}*/
183
184/*!\defgroup Node Node Management
185@{*/
186
187
188/*!
189This procedure returns a variety of properties
190associated with a specific node.
191Any of the pointers may be NULL in the following procedure call;
192If the node is of type Dataset, then return # of global attributes
193If the node is of type Attribute, then return the # of values in nattrp.
194
195\param[in] link The link through which the server is accessed.
196\param[in] ddsnode The node whose properties are of interest.
197\param[out] namep Pointer for storing the node's associated name.
198The caller must free the returned name.
199\param[out] octypep Pointer for storing the node's octype.
200\param[out] atomtypep Pointer for storing the object's
201atomic type (i.e. OC_NAT .. OC_URL);only defined when
202the object's octype is OC_Atomic
203\param[out] containerp Pointer for storing the
204OCnode for which this object is a subnode. The value OCNULL
205is stored if the object is a root object.
206\param[out] rankp Pointer for storing the rank (i.e. the number
207of dimensions) for this object; zero implies a scalar.
208\param[out] nsubnodesp Pointer for storing the number
209of subnodes of this object.
210\param[out] nattrp Pointer for storing the number
211of attributes associated with this object.
212
213\retval OC_NOERR The procedure executed normally.
214\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
215*/
216
217OCerror
218oc_dds_properties(OCobject link,
219    OCobject ddsnode,
220   char** namep,
221   OCtypeoctypep,
222   OCtypeatomtypep, /* if objecttype == OC_Atomic */
223   OCobjectcontainerp,
224   size_t* rankp,
225   size_t* nsubnodesp,
226   size_t* nattrp)
227{
228    OCnodenode;
229    OCVERIFY(OC_Node,ddsnode);
230    OCDEREF(OCnode*,node,ddsnode);
231
232    if(namep) *namep = nulldup(node->name);
233    if(octypep) *octypep = node->octype;
234    if(atomtypep) *atomtypep = node->etype;
235    if(rankp) *rankp = node->array.rank;
236    if(containerp) *containerp = (OCobject)node->container;
237    if(nsubnodesp) *nsubnodesp = oclistlength(node->subnodes);
238    if(nattrp) {
239        if(node->octype == OC_Attribute) {
240            *nattrp = oclistlength(node->att.values);
241        } else {
242            *nattrp = oclistlength(node->attributes);
243 }
244    }
245    return OCTHROW(OC_NOERR);
246}
247
248/*!
249Specialized accessor function as an alternative to oc_dds_properties.
250\param[in] link The link through which the server is accessed.
251\param[in] ddsnode The node whose properties are of interest.
252\param[out] namep A pointer into which the node name is stored
253as a null terminated string. The caller must free this value
254when no longer needed.
255
256\retval OC_NOERR The procedure executed normally.
257\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
258*/
259
260OCerror
261oc_dds_name(OCobject linkOCobject ddsnode, char** namep)
262{
263    OCstatestate;
264    OCnodenode;
265    OCVERIFY(OC_State,link);
266    OCDEREF(OCstate*,state,link);
267    OCVERIFY(OC_Node,ddsnode);
268    OCDEREF(OCnode*,node,ddsnode);
269
270    if(state == NULL || node == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
271    if(namep) *namep = nulldup(node->name);
272    return OCTHROW(OC_NOERR);
273}
274
275/*!
276Specialized accessor function as an alternative to oc_dds_properties.
277\param[in] link The link through which the server is accessed.
278\param[in] ddsnode The node whose properties are of interest.
279\param[out] nsubnodesp A pointer into which the number of subnodes
280is stored.
281
282\retval OC_NOERR The procedure executed normally.
283\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
284*/
285
286OCerror
287oc_dds_nsubnodes(OCobject linkOCobject ddsnode, size_t* nsubnodesp)
288{
289    OCnodenode;
290    OCVERIFY(OC_Node,ddsnode);
291    OCDEREF(OCnode*,node,ddsnode);
292
293    if(nsubnodesp) *nsubnodesp = oclistlength(node->subnodes);
294    return OCTHROW(OC_NOERR);
295}
296
297/*!
298Specialized accessor function as an alternative to oc_dds_properties.
299\param[in] link The link through which the server is accessed.
300\param[in] ddsnode The node whose properties are of interest.
301\param[out] typep A pointer into which the atomictype is stored.
302
303\retval OC_NOERR The procedure executed normally.
304\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
305*/
306
307OCerror
308oc_dds_atomictype(OCobject linkOCobject ddsnodeOCtypetypep)
309{
310    OCnodenode;
311    OCVERIFY(OC_Node,ddsnode);
312    OCDEREF(OCnode*,node,ddsnode);
313
314    if(typep) *typep = node->etype;
315    return OCTHROW(OC_NOERR);
316}
317
318/*!
319Specialized accessor function as an alternative to oc_dds_properties.
320\param[in] link The link through which the server is accessed.
321\param[in] ddsnode The node whose properties are of interest.
322\param[out] typep A pointer into which the octype is stored.
323
324\retval OC_NOERR The procedure executed normally.
325\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
326*/
327
328OCerror
329oc_dds_class(OCobject linkOCobject ddsnodeOCtypetypep)
330{
331    OCnodenode;
332    OCVERIFY(OC_Node,ddsnode);
333    OCDEREF(OCnode*,node,ddsnode);
334
335    if(typep) *typep = node->octype;
336    return OCTHROW(OC_NOERR);
337}
338
339/*!
340Specialized accessor function as an alternative to oc_dds_properties.
341\param[in] link The link through which the server is accessed.
342\param[in] ddsnode The node whose properties are of interest.
343\param[out] rankp A pointer into which the rank is stored.
344
345\retval OC_NOERR The procedure executed normally.
346\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
347*/
348
349OCerror
350oc_dds_rank(OCobject linkOCobject ddsnode, size_t* rankp)
351{
352    OCnodenode;
353    OCVERIFY(OC_Node,ddsnode);
354    OCDEREF(OCnode*,node,ddsnode);
355
356    if(rankp) *rankp = node->array.rank;
357    return OCTHROW(OC_NOERR);
358}
359
360/*!
361Specialized accessor function as an alternative to oc_dds_properties.
362\param[in] link The link through which the server is accessed.
363\param[in] ddsnode The node whose properties are of interest.
364\param[out] nattrp A pointer into which the number of attributes is stored.
365
366\retval OC_NOERR The procedure executed normally.
367\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
368*/
369
370OCerror
371oc_dds_attr_count(OCobject linkOCobject ddsnode, size_t* nattrp)
372{
373    OCnodenode;
374    OCVERIFY(OC_Node,ddsnode);
375    OCDEREF(OCnode*,node,ddsnode);
376
377    if(nattrp) {
378        if(node->octype == OC_Attribute) {
379            *nattrp = oclistlength(node->att.values);
380        } else {
381            *nattrp = oclistlength(node->attributes);
382 }
383    }
384    return OCTHROW(OC_NOERR);
385}
386
387/*!
388Specialized accessor function as an alternative to oc_dds_properties.
389\param[in] link The link through which the server is accessed.
390\param[in] ddsnode The node whose properties are of interest.
391\param[out] rootp A pointer into which the the root of the tree containing
392the node is stored.
393
394\retval OC_NOERR The procedure executed normally.
395\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
396*/
397
398OCerror
399oc_dds_root(OCobject linkOCobject ddsnodeOCobjectrootp)
400{
401    OCnodenode;
402    OCVERIFY(OC_Node,ddsnode);
403    OCDEREF(OCnode*,node,ddsnode);
404
405    if(rootp) *rootp = (OCobject)node->root;
406    return OCTHROW(OC_NOERR);
407}
408
409/*!
410Specialized accessor function as an alternative to oc_dds_properties.
411\param[in] link The link through which the server is accessed.
412\param[in] ddsnode The node whose properties are of interest.
413\param[out] containerp A pointer into which the the immediate
414container ddsnode is stored.
415
416\retval OC_NOERR The procedure executed normally.
417\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
418*/
419
420OCerror
421oc_dds_container(OCobject linkOCobject ddsnodeOCobjectcontainerp)
422{
423    OCnodenode;
424    OCVERIFY(OC_Node,ddsnode);
425    OCDEREF(OCnode*,node,ddsnode);
426
427    if(containerp) *containerp = (OCobject)node->container;
428    return OCTHROW(OC_NOERR);
429}
430
431/*!
432Obtain the DDS node corresponding to the i'th field
433of a node that itself is a container (Dataset, Structure, Sequence, or Grid)
434
435\param[in] link The link through which the server is accessed.
436\param[in] ddsnode The container node of interest.
437\param[in] index The index (starting at zero) of the field to return.
438\param[out] fieldnodep  A pointer into which the i'th field node is stored.
439
440\retval OC_NOERR The procedure executed normally.
441\retval OC_EINDEX The index was greater than the number of fields.
442\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
443\retval OC_EBADTYPE The dds node is not a container node.
444*/
445
446OCerror
447oc_dds_ithfield(OCobject linkOCobject ddsnode, size_t indexOCobjectfieldnodep)
448{
449    OCnodenode;
450    OCnodefield;
451    OCVERIFY(OC_Node,ddsnode);
452    OCDEREF(OCnode*,node,ddsnode);
453
454    if(!ociscontainer(node->octype))
455 return OCTHROW(OC_EBADTYPE);
456
457    if(index >= oclistlength(node->subnodes))
458 return OCTHROW(OC_EINDEX);
459
460    field = (OCnode*)oclistget(node->subnodes,index);
461    if(fieldnodep) *fieldnodep = (OCobject)field;
462    return OCTHROW(OC_NOERR);
463}
464
465/*!
466Alias for oc_dds_ithfield.
467
468\param[in] link The link through which the server is accessed.
469\param[in] ddsnode The container node of interest.
470\param[in] index The index (starting at zero) of the field to return.
471\param[out] fieldnodep  A pointer into which the i'th field node is stored.
472
473\retval OC_NOERR The procedure executed normally.
474\retval OC_EINDEX The index was greater than the number of fields.
475\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
476\retval OC_EBADTYPE The dds node is not a container node.
477*/
478
479OCerror
480oc_dds_ithsubnode(OCobject linkOCobject ddsnode, size_t indexOCobjectfieldnodep)
481{
482    return OCTHROW(oc_dds_ithfield(link,ddsnode,index,fieldnodep));
483}
484
485/*!
486Obtain the DDS node corresponding to the array of a Grid container.
487Equivalent to oc_dds_ithfield(link,grid-container,0,arraynode).
488
489\param[in] link The link through which the server is accessed.
490\param[in] grid The grid container node of interest.
491\param[out] arraynodep  A pointer into which the grid array node is stored.
492
493\retval OC_NOERR The procedure executed normally.
494\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
495*/
496
497OCerror
498oc_dds_gridarray(OCobject linkOCobject gridOCobjectarraynodep)
499{
500    return OCTHROW(oc_dds_ithfield(link,grid,0,arraynodep));
501}
502
503/*!
504Obtain the DDS node corresponding to the i'th map of a Grid container.
505Equivalent to oc_dds_ithfield(link,grid-container,index+1,arraynode).
506Note the map index starts at zero.
507
508\param[in] link The link through which the server is accessed.
509\param[in] grid The grid container node of interest.
510\param[in] index The (zero-based) index of the map node to return.
511\param[out] mapnodep  A pointer into which the grid map node is stored.
512
513\retval OC_NOERR The procedure executed normally.
514\retval OC_EINDEX The map index is illegal.
515\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
516*/
517
518OCerror
519oc_dds_gridmap(OCobject linkOCobject grid, size_t indexOCobjectmapnodep)
520{
521    return OCTHROW(oc_dds_ithfield(link,grid,index+1,mapnodep));
522}
523
524
525/*!
526Obtain a dds node by name from a dds structure or dataset node.
527
528\param[in] link The link through which the server is accessed.
529\param[in] ddsnode The container node of interest.
530\param[in] name The name of the field to return.
531\param[out] fieldp  A pointer into which the name'th field node is stored.
532
533\retval OC_NOERR The procedure executed normally.
534\retval OC_EINDEX No field with the given name was found.
535\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
536*/
537
538OCerror
539oc_dds_fieldbyname(OCobject linkOCobject ddsnode, const char* nameOCobjectfieldp)
540{
541    OCerror err = OC_NOERR;
542    OCnodenode;
543    size_t count,i;
544    OCVERIFY(OC_Node,ddsnode);
545    OCDEREF(OCnode*,node,ddsnode);
546
547    if(!ociscontainer(node->octype))
548 return OCTHROW(OC_EBADTYPE);
549
550    /* Search the fields to find a name match */
551    err = oc_dds_nsubnodes(link,ddsnode,&count);
552    if(err != OC_NOERR) return err;
553    for(i=0;i<count;i++) {
554 OCobject field;
555 char* fieldname = NULL;
556 int match = 1;
557
558        err = oc_dds_ithfield(link,ddsnode,i,&field);
559        if(err != OC_NOERR) return err;
560 /* Get the field's name */
561        err = oc_dds_name(link,field,&fieldname);
562        if(err != OC_NOERR) return err;
563 if(fieldname != NULL) {
564     match = strcmp(name,fieldname);
565     free(fieldname);
566 }
567 if(match == 0) {
568     if(fieldp) *fieldp = field;
569     return OCTHROW(OC_NOERR);
570 }
571    }
572    return OCTHROW(OC_EINDEX); /* name was not found */
573}
574
575/*!
576Obtain the dimension nodes (of octype OC_Dimension)
577associated with the node of interest.
578
579\param[in] link The link through which the server is accessed.
580\param[in] ddsnode The dds node of interest.
581\param[out] dims  A vector into which the dimension nodes
582are stored. The caller must allocate based on the rank of the node.
583
584\retval OC_NOERR The procedure executed normally.
585\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
586*/
587
588OCerror
589oc_dds_dimensions(OCobject linkOCobject ddsnodeOCobjectdims)
590{
591    OCnodenode;
592    size_t i;
593
594    OCVERIFY(OC_Node,ddsnode);
595    OCDEREF(OCnode*,node,ddsnode);
596
597    if(node->array.rank == 0) return OCTHROW(OCTHROW(OC_ESCALAR));
598    if(dims != NULL) {
599        for(i=0;i<node->array.rank;i++) {
600            OCnodedim = (OCnode*)oclistget(node->array.dimensions,i);
601     dims[i] = (OCobject)dim;
602 }
603    }
604    return OCTHROW(OC_NOERR);
605}
606
607/*!
608Obtain the i'th dimension node (of octype OC_Dimension)
609associated with the node of interest.
610
611\param[in] link The link through which the server is accessed.
612\param[in] ddsnode The dds node of interest.
613\param[in] index The index of the dimension to be returned.
614\param[out] dimidp A pointer into which the index'th dimension is stored.
615
616\retval OC_NOERR The procedure executed normally.
617\retval OC_EINDEX The index is greater than the node's rank.
618\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
619*/
620
621OCerror
622oc_dds_ithdimension(OCobject linkOCobject ddsnode, size_t indexOCobjectdimidp)
623{
624    OCnodenode;
625    OCobject dimid = NULL;
626    OCVERIFY(OC_Node,ddsnode);
627    OCDEREF(OCnode*,node,ddsnode);
628
629    if(node->array.rank == 0) return OCTHROW(OCTHROW(OC_ESCALAR));
630    if(index >= node->array.rank) return OCTHROW(OCTHROW(OC_EINDEX));
631    dimid = (OCobject)oclistget(node->array.dimensions,index);
632    if(dimidp) *dimidp = dimid;
633    return OCTHROW(OC_NOERR);
634}
635
636/*!
637Obtain the properties of a dimension node.
638
639\param[in] link The link through which the server is accessed.
640\param[in] ddsnode The dimension node.
641\param[out] sizep A pointer into which to store the size of the dimension.
642\param[out] namep A pointer into which to store the name of the dimension.
643If the dimension is anonymous, then the value NULL is returned as the name.
644The caller must free the returned name.
645
646\retval OC_NOERR The procedure executed normally.
647\retval OC_BADTYPE If the node is not of type OC_Dimension.
648\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
649*/
650
651OCerror
652oc_dimension_properties(OCobject linkOCobject ddsnode, size_t* sizep, char** namep)
653{
654    OCnodedim;
655    OCVERIFY(OC_Node,ddsnode);
656    OCDEREF(OCnode*,dim,ddsnode);
657
658    if(dim->octype != OC_Dimension) return OCTHROW(OCTHROW(OC_EBADTYPE));
659    if(sizep) *sizep = dim->dim.declsize;
660    if(namep) *namep = nulldup(dim->name);
661    return OCTHROW(OC_NOERR);
662}
663
664/*!
665Obtain just the set of sizes of the dimensions
666associated with a dds node.
667
668\param[in] link The link through which the server is accessed.
669\param[in] ddsnode The node of interest
670\param[out] dimsizes A vector into which the sizes of all
671the dimensions of a node are stored. Its size is determined
672by the rank of the node and must be allocated and free'd by the caller.
673
674\retval OC_NOERR The procedure executed normally.
675\retval OC_ESCALAR If the node is a scalar.
676\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
677*/
678
679OCerror
680oc_dds_dimensionsizes(OCobject linkOCobject ddsnode, size_t* dimsizes)
681{
682    OCnodenode;
683    OCVERIFY(OC_Node,ddsnode);
684    OCDEREF(OCnode*,node,ddsnode);
685
686    if(node->array.rank == 0) return OCTHROW(OCTHROW(OC_ESCALAR));
687    if(dimsizes != NULL) {
688 size_t i;
689        for(i=0;i<node->array.rank;i++) {
690            OCnodedim = (OCnode*)oclistget(node->array.dimensions,i);
691     dimsizes[i] = dim->dim.declsize;
692 }
693    }
694    return OCTHROW(OC_NOERR);
695}
696
697/*!
698Return the name, type, length, and values associated with
699the i'th attribute of a specified node. The actual attribute
700strings are returned and the user must do any required
701conversion based on the octype.  The strings argument must
702be allocated and freed by caller.  Standard practice is to
703call twice, once with the strings argument == NULL so we get
704the number of values, then the second time with an allocated
705char** vector.  The caller should reclaim the contents of
706the returned string vector using <i>oc_reclaim_strings</i>.
707
708\param[in] link The link through which the server is accessed.
709\param[in] ddsnode The node of interest
710\param[in] index Return the information of the index'th attribute.
711\param[out] namep A pointer into which the attribute's name is stored.
712It must be freed by the caller.
713\param[out] octypep A pointer into which the attribute's atomic type is stored.
714\param[out] nvaluesp A pointer into which the number
715of attribute values is stored.
716\param[out] strings A vector into which the values of the attribute
717are stored. It must be allocated and free'd by the caller.
718
719\retval OC_NOERR The procedure executed normally.
720\retval OC_EINDEX If the index is more than the number of attributes.
721\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
722*/
723
724OCerror
725oc_dds_attr(OCobject linkOCobject ddsnode, size_t index,
726    char** namepOCtypeoctypep,
727    size_t* nvaluesp, char** strings)
728{
729    int i;
730    OCnodenode;
731    OCattributeattr;
732    size_t nattrs;
733    OCVERIFY(OC_Node,ddsnode);
734    OCDEREF(OCnode*,node,ddsnode);
735
736    nattrs = oclistlength(node->attributes);
737    if(index >= nattrs) return OCTHROW(OCTHROW(OC_EINDEX));
738    attr = (OCattribute*)oclistget(node->attributes,index);
739    if(namep) *namep = strdup(attr->name);
740    if(octypep) *octypep = attr->etype;
741    if(nvaluesp) *nvaluesp = attr->nvalues;
742    if(strings) {
743 if(attr->nvalues > 0) {
744     for(i=0;i<attr->nvalues;i++)
745         strings[i] = nulldup(attr->values[i]);
746 }
747    }
748    return OCTHROW(OC_NOERR);
749}
750
751/*!
752Given a counted vector of strings, free up all of the strings,
753BUT NOT THE VECTOR since that was allocated by the caller.
754
755\param[in] n The link through which the server is accessed.
756\param[in] svec The node of interest.
757*/
758
759void
760oc_reclaim_strings(size_t n, char** svec)
761{
762    int i;
763    for(i=0;i<n;i++) if(svec[i] != NULL) free(svec[i]);
764}
765
766/*!
767Return the count of DAS attribute values.
768
769\param[in] link The link through which the server is accessed.
770\param[in] dasnode The node of interest
771\param[out] nvaluesp A pointer into which the number of attributes
772is stored.
773
774\retval OC_NOERR The procedure executed normally.
775\retval OC_EBADTPE If the node is not of type OC_Attribute.
776\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
777*/
778
779OCerror
780oc_das_attr_count(OCobject linkOCobject dasnode, size_t* nvaluesp)
781{
782    OCnodeattr;
783    OCVERIFY(OC_Node,dasnode);
784    OCDEREF(OCnode*,attr,dasnode);
785    if(attr->octype != OC_Attribute) return OCTHROW(OCTHROW(OC_EBADTYPE));
786    if(nvaluesp) *nvaluesp = oclistlength(attr->att.values);
787    return OCTHROW(OC_NOERR);
788}
789
790/*!
791The procedure oc_das_attr returns the i'th string value
792associated with a DAS object of type <i>OC_Attribute</i>.
793Note carefully that this operation applies to DAS nodes
794and not to DDS or DATADDS nodes.
795Note also that the returned value is always a string
796and it is the caller;'s responsibility to free the returned string.
797
798\param[in] link The link through which the server is accessed.
799\param[in] dasnode The DAS node of interest.
800\param[in] index The index of the das value to return.
801\param[in] atomtypep A pointer into which is stored the atomic
802type of the attribute.
803\param[out] valuep A vector into which the attribute's string values
804are stored. Caller must allocate and free.
805
806\retval OC_NOERR The procedure executed normally.
807\retval OC_EBADTPE If the node is not of type OC_Attribute.
808\retval OC_EINDEX If the index is larger than the number of attributes.
809\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
810*/
811
812OCerror
813oc_das_attr(OCobject linkOCobject dasnode, size_t indexOCtypeatomtypep, char** valuep)
814{
815    OCnodeattr;
816    size_t nvalues;
817    OCVERIFY(OC_Node,dasnode);
818    OCDEREF(OCnode*,attr,dasnode);
819
820    if(attr->octype != OC_Attribute) return OCTHROW(OCTHROW(OC_EBADTYPE));
821    nvalues = oclistlength(attr->att.values);
822    if(index >= nvalues) return OCTHROW(OCTHROW(OC_EINDEX));
823    if(atomtypep) *atomtypep = attr->etype;
824    if(valuep) *valuep = nulldup((char*)oclistget(attr->att.values,index));
825    return OCTHROW(OC_NOERR);
826}
827
828/**@}*/
829
830/**************************************************/
831/*!\defgroup Interconnection Node Interconnection Management */
832
833/**@{*/
834
835/*!
836As a rule, the attributes of an object are accessed using
837the <i>oc_dds_attr</i> procedure rather than by traversing a
838DAS.  In order to support this, the <i>oc_merge_das</i>
839procedure annotates a DDS node with attribute values taken
840from a specified DAS node.
841
842\param[in] link The link through which the server is accessed.
843\param[in] dasroot The root object of a DAS tree.
844\param[in] ddsroot The root object of a DDS (or DataDDS) tree.
845
846\retval OC_NOERR The procedure executed normally.
847\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
848*/
849
850OCerror
851oc_merge_das(OCobject linkOCobject dasrootOCobject ddsroot)
852{
853    OCstatestate;
854    OCnodedas;
855    OCnodedds;
856    OCVERIFY(OC_State,link);
857    OCDEREF(OCstate*,state,link);
858    OCVERIFY(OC_Node,dasroot);
859    OCDEREF(OCnode*,das,dasroot);
860    OCVERIFY(OC_Node,ddsroot);
861    OCDEREF(OCnode*,dds,ddsroot);
862
863    return OCTHROW(ocddsdasmerge(state,das,dds));
864}
865
866/**@}*/
867
868/**************************************************/
869
870/*!\defgroup Data Data Management */
871/**@{*/
872
873/*!
874Obtain the datanode root associated with a DataDDS tree.
875Do not confuse this with oc_data_root.
876This procedure, given the DDS tree root, gets the data tree root.
877
878\param[in] link The link through which the server is accessed.
879\param[in] ddsroot The DataDDS tree root.
880\param[out] datarootp A pointer into which the datanode root is stored.
881
882\retval OC_NOERR The procedure executed normally.
883\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
884*/
885
886OCerror
887oc_dds_getdataroot(OCobject linkOCobject ddsrootOCobjectdatarootp)
888{
889    OCerror ocerr = OC_NOERR;
890    OCstatestate;
891    OCnoderoot;
892    OCdatadroot;
893    OCVERIFY(OC_State,link);
894    OCDEREF(OCstate*,state,link);
895    OCVERIFY(OC_Node,ddsroot);
896    OCDEREF(OCnode*,root,ddsroot);
897
898    if(datarootp == NULL)
899 return OCTHROW(OCTHROW(OC_EINVAL));
900    ocerr = ocdata_getroot(state,root,&droot);
901    if(ocerr == OC_NOERR && datarootp)
902 *datarootp = (OCobject)droot;
903    return OCTHROW(ocerr);
904}
905
906/*!
907Obtain the data instance corresponding to the i'th field
908of a data node instance that itself is a container instance.
909
910\param[in] link The link through which the server is accessed.
911\param[in] datanode The container data node instance of interest.
912\param[in] index The index (starting at zero) of the field instance to return.
913\param[out] fieldp  A pointer into which the i'th field instance is stored.
914
915\retval OC_NOERR The procedure executed normally.
916\retval OC_EINDEX The index was greater than the number of fields.
917\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
918\retval OC_EBADTYPE The data node is not a container node.
919*/
920
921OCerror
922oc_data_ithfield(OCobject linkOCobject datanode, size_t indexOCobjectfieldp)
923{
924    OCerror ocerr = OC_NOERR;
925    OCstatestate;
926    OCdatadata;
927    OCdatafield;
928    OCVERIFY(OC_State,link);
929    OCDEREF(OCstate*,state,link);
930    OCVERIFY(OC_Data,datanode);
931    OCDEREF(OCdata*,data,datanode);
932
933    if(fieldp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
934    ocerr = ocdata_ithfield(state,data,index,&field);
935    if(ocerr == OC_NOERR)
936 *fieldp = (OCobject)field;
937    return OCTHROW(ocerr);
938}
939
940/*!
941Obtain a data node by name from a container data node.
942
943\param[in] link The link through which the server is accessed.
944\param[in] datanode The container data node instance of interest.
945\param[in] name The name of the field instance to return.
946\param[out] fieldp  A pointer into which the i'th field instance is stored.
947
948\retval OC_NOERR The procedure executed normally.
949\retval OC_EINDEX No field with the given name was found.
950\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
951\retval OC_EBADTYPE The data node is not a container node.
952*/
953
954OCerror
955oc_data_fieldbyname(OCobject linkOCobject datanode, const char* nameOCobjectfieldp)
956{
957    OCerror err = OC_NOERR;
958    size_t count=0,i;
959    OCobject ddsnode;
960    OCVERIFY(OC_State,link);
961    OCVERIFY(OC_Data,datanode);
962
963    /* Get the dds node for this datanode */
964    err = oc_data_ddsnode(link,datanode,&ddsnode);
965    if(err != OC_NOERR) return err;
966
967    /* Search the fields to find a name match */
968    err = oc_dds_nsubnodes(link,ddsnode,&count);
969    if(err != OC_NOERR) return err;
970    for(i=0;i<count;i++) {
971 int match;
972 OCobject field;
973 char* fieldname = NULL;
974        err = oc_dds_ithfield(link,ddsnode,i,&field);
975        if(err != OC_NOERR) return err;
976 /* Get the field's name */
977        err = oc_dds_name(link,field,&fieldname);
978        if(err != OC_NOERR) return err;
979  if(!fieldname)
980   return OCTHROW(OC_EINVAL);
981
982 match = strcmp(name,fieldname);
983 if(fieldname != NULL) free(fieldname);
984 if(match == 0) {
985     /* Get the ith datasubnode */
986     err = oc_data_ithfield(link,datanode,i,&field);
987            if(err != OC_NOERR) return err;
988     if(fieldp) *fieldp = field;
989     return OCTHROW(OC_NOERR);
990 }
991    }
992    return OCTHROW(OC_EINDEX); /* name was not found */
993}
994
995/*!
996Obtain the data instance corresponding to the array field
997of a Grid container instance.
998Equivalent to oc_data_ithfield(link,grid,0,arraydata).
999
1000\param[in] link The link through which the server is accessed.
1001\param[in] grid The grid container instance of interest.
1002\param[out] arraydatap  A pointer into which the grid array instance is stored.
1003
1004\retval OC_NOERR The procedure executed normally.
1005\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1006*/
1007
1008OCerror
1009oc_data_gridarray(OCobject linkOCobject gridOCobjectarraydatap)
1010{
1011    return OCTHROW(oc_data_ithfield(link,grid,0,arraydatap));
1012}
1013
1014/*!
1015Obtain the data instance corresponding to the ith map field
1016of a Grid container instance.
1017Equivalent to oc_data_ithfield(link,grid-container,index+1,mapdata).
1018Note that Map indices start at zero.
1019
1020\param[in] link The link through which the server is accessed.
1021\param[in] grid The grid container instance of interest.
1022\param[in] index The map index of the map to return.
1023\param[out] mapdatap A pointer into which the grid map instance is stored.
1024
1025\retval OC_NOERR The procedure executed normally.
1026\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1027*/
1028
1029OCerror
1030oc_data_gridmap(OCobject linkOCobject grid, size_t indexOCobjectmapdatap)
1031{
1032    return OCTHROW(oc_data_ithfield(link,grid,index+1,mapdatap));
1033}
1034
1035/*!
1036Obtain the data instance corresponding to the container
1037of a specied instance object.
1038
1039\param[in] link The link through which the server is accessed.
1040\param[in] datanode The data instance of interest
1041\param[out] containerp  A pointer into which the container instance is stored.
1042
1043\retval OC_NOERR The procedure executed normally.
1044\retval OC_EINVAL The data object has no container
1045(=> it is a Dataset instance).
1046\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1047*/
1048
1049OCerror
1050oc_data_container(OCobject link,  OCobject datanodeOCobjectcontainerp)
1051{
1052    OCerror ocerr = OC_NOERR;
1053    OCstatestate;
1054    OCdatadata;
1055    OCdatacontainer;
1056    OCVERIFY(OC_State,link);
1057    OCDEREF(OCstate*,state,link);
1058    OCVERIFY(OC_Data,datanode);
1059    OCDEREF(OCdata*,data,datanode);
1060
1061    if(containerp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1062    ocerr = ocdata_container(state,data,&container);
1063    if(ocerr == OC_NOERR)
1064 *containerp = (OCobject)container;
1065    return OCTHROW(ocerr);
1066}
1067
1068/*!
1069Obtain the data instance corresponding to the root of the tree
1070of which the specified instance object is a part.
1071Do not confuse this with oc_dds_getdataroot.
1072This procedure, given any node in a data tree, get the root of that tree.
1073
1074\param[in] link The link through which the server is accessed.
1075\param[in] datanode The data instance of interest
1076\param[out] rootp  A pointer into which the root instance is stored.
1077
1078\retval OC_NOERR The procedure executed normally.
1079\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1080*/
1081
1082OCerror
1083oc_data_root(OCobject linkOCobject datanodeOCobjectrootp)
1084{
1085    OCerror ocerr = OC_NOERR;
1086    OCstatestate;
1087    OCdatadata;
1088    OCdataroot;
1089    OCVERIFY(OC_State,link);
1090    OCDEREF(OCstate*,state,link);
1091    OCVERIFY(OC_Data,datanode);
1092    OCDEREF(OCdata*,data,datanode);
1093
1094    if(rootp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1095    ocerr = ocdata_root(state,data,&root);
1096    if(ocerr == OC_NOERR)
1097 *rootp = (OCobject)root;
1098    return OCTHROW(ocerr);
1099}
1100
1101/*!
1102Return the data of a dimensioned Structure corresponding
1103to the element instance specified by the indices argument.
1104
1105\param[in] link The link through which the server is accessed.
1106\param[in] datanode The data node instance of interest.
1107\param[in] indices A vector of indices specifying the element instance
1108to return. This vector must be allocated and free'd by the caller.
1109\param[out] elementp  A pointer into which the element instance is stored.
1110
1111\retval OC_NOERR The procedure executed normally.
1112\retval OC_EBADTYPE The data instance was not of type OC_Structure
1113or was a scalar.
1114\retval OC_EINDEX The indices specified an illegal element.
1115\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1116*/
1117
1118OCerror
1119oc_data_ithelement(OCobject linkOCobject datanode, size_t* indicesOCobjectelementp)
1120{
1121    OCerror ocerr = OC_NOERR;
1122    OCstatestate;
1123    OCdatadata;
1124    OCdataelement;
1125    OCVERIFY(OC_State,link);
1126    OCDEREF(OCstate*,state,link);
1127    OCVERIFY(OC_Data,datanode);
1128    OCDEREF(OCdata*,data,datanode);
1129
1130    if(indices == NULL || elementp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1131    ocerr = ocdata_ithelement(state,data,indices,&element);
1132    if(ocerr == OC_NOERR)
1133 *elementp = (OCobject)element;
1134    return OCTHROW(ocerr);
1135}
1136
1137/*!
1138Return the i'th record instance
1139of a Sequence data instance.
1140
1141\param[in] link The link through which the server is accessed.
1142\param[in] datanode The data node instance of interest.
1143\param[in] index The record instance to return.
1144\param[out] recordp  A pointer into which the record instance is stored.
1145
1146\retval OC_NOERR The procedure executed normally.
1147\retval OC_EBADTYPE The data instance was not of type OC_Sequence
1148\retval OC_EINDEX The indices is larger than the number of records
1149of the Sequence.
1150\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1151*/
1152
1153extern OCerror oc_data_ithrecord(OCobject linkOCobject datanode, size_t indexOCobjectrecordp)
1154{
1155    OCerror ocerr = OC_NOERR;
1156    OCstatestate;
1157    OCdatadata;
1158    OCdatarecord;
1159    OCVERIFY(OC_State,link);
1160    OCDEREF(OCstate*,state,link);
1161    OCVERIFY(OC_Data,datanode);
1162    OCDEREF(OCdata*,data,datanode);
1163
1164    if(recordp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1165    ocerr = ocdata_ithrecord(state,data,index,&record);
1166    if(ocerr == OC_NOERR)
1167 *recordp = (OCobject)record;
1168    return OCTHROW(ocerr);
1169}
1170
1171/*!
1172Return the i'th record instance
1173of a Sequence data instance.
1174Return the indices for this data instance; Assumes the data
1175was obtained using oc_data_ithelement or oc_data_ithrecord.
1176
1177\param[in] link The link through which the server is accessed.
1178\param[in] datanode The data node instance of interest.
1179\param[out] indices A vector into which the indices of the
1180data instance are stored. If the data instance is a record,
1181then only indices[0] is used.
1182
1183\retval OC_NOERR The procedure executed normally.
1184\retval OC_EBADTYPE The data instance was not of type OC_Sequence
1185or it was not a dimensioned instance of OC_Structure.
1186\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1187*/
1188
1189OCerror
1190oc_data_position(OCobject linkOCobject datanode, size_t* indices)
1191{
1192    OCstatestate;
1193    OCdatadata;
1194    OCVERIFY(OC_State,link);
1195    OCDEREF(OCstate*,state,link);
1196    OCVERIFY(OC_Data,datanode);
1197    OCDEREF(OCdata*,data,datanode);
1198    if(indices == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1199    return OCTHROW(ocdata_position(state,data,indices));
1200}
1201
1202/*!
1203Return the number of records associated with a Sequence
1204data object. Be warned that applying this procedure
1205to a record data instance (as opposed to an instance
1206representing a whole Sequence) will return an error.
1207More succinctly, the data object's OCtype must be of
1208type OC_Sequence and oc_data_indexable() must be true.
1209
1210\param[in] link The link through which the server is accessed.
1211\param[in] datanode The data node instance of interest.
1212\param[out] countp A pointer into which the record count is stored.
1213
1214\retval OC_NOERR The procedure executed normally.
1215\retval OC_EBADTYPE The data instance was not of type OC_Sequence
1216or it was a record data instance.
1217\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1218*/
1219
1220OCerror
1221oc_data_recordcount(OCobject linkOCobject datanode, size_t* countp)
1222{
1223    OCstatestate;
1224    OCdatadata;
1225    OCVERIFY(OC_State,link);
1226    OCDEREF(OCstate*,state,link);
1227    OCVERIFY(OC_Data,datanode);
1228    OCDEREF(OCdata*,data,datanode);
1229    if(countp == NULL) return OCTHROW(OCTHROW(OC_EINVAL));
1230    return OCTHROW(ocdata_recordcount(state,data,countp));
1231}
1232
1233/*!
1234Return the dds node that is the "pattern"
1235for this data instance.
1236
1237\param[in] link The link through which the server is accessed.
1238\param[in] datanode The data node instance of interest.
1239\param[out] nodep A pointer into which the ddsnode is stored.
1240
1241\retval OC_NOERR The procedure executed normally.
1242\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1243*/
1244
1245OCerror
1246oc_data_ddsnode(OCobject linkOCobject datanodeOCobjectnodep)
1247{
1248    OCerror ocerr = OC_NOERR;
1249    OCdatadata;
1250    OCVERIFY(OC_Data,datanode);
1251    OCDEREF(OCdata*,data,datanode);
1252
1253    OCASSERT(data->pattern != NULL);
1254    if(nodep == NULLocerr = OC_EINVAL;
1255    else *nodep = (OCobject)data->pattern;
1256    return OCTHROW(ocerr);
1257}
1258
1259/*!
1260Return the OCtype of the ddsnode that is the "pattern"
1261for this data instance. This is a convenience function
1262since it can be obtained using a combination of other
1263API procedures.
1264
1265\param[in] link The link through which the server is accessed.
1266\param[in] datanode The data node instance of interest.
1267\param[out] typep A pointer into which the OCtype value is stored.
1268
1269\retval OC_NOERR The procedure executed normally.
1270\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1271*/
1272
1273OCerror
1274oc_data_octype(OCobject linkOCobject datanodeOCtypetypep)
1275{
1276    OCerror ocerr = OC_NOERR;
1277    OCdatadata;
1278    OCVERIFY(OC_Data,datanode);
1279    OCDEREF(OCdata*,data,datanode);
1280
1281    OCASSERT(data->pattern != NULL);
1282    if(typep == NULLocerr = OC_EINVAL;
1283    else *typep = data->pattern->octype;
1284    return OCTHROW(ocerr);
1285}
1286
1287/*!
1288Return the value one (1) if the specified data instance
1289is indexable. Indexable means that the data instance
1290is a dimensioned Structure or it is a Sequence (but not
1291a record in a Sequence).
1292
1293\param[in] link The link through which the server is accessed.
1294\param[in] datanode The data node instance of interest.
1295
1296\retval one(1) if the specified data instance is indexable.
1297\retval zero(0) otherwise.
1298*/
1299
1300int
1301oc_data_indexable(OCobject linkOCobject datanode)
1302{
1303    OCdatadata;
1304    OCVERIFY(OC_Data,datanode);
1305    OCDEREF(OCdata*,data,datanode);
1306
1307    return (fisset(data->datamode,OCDT_ARRAY)
1308     || fisset(data->datamode,OCDT_SEQUENCE)) ? 1 : 0;
1309}
1310
1311/*!
1312Return the value one (1) if the specified data instance
1313was obtained by applying either the procedure oc_data_ithelement
1314or oc_data_ithrecord. This means that the operation
1315oc_data_position() will succeed when applied to this data instance.
1316
1317\param[in] link The link through which the server is accessed.
1318\param[in] datanode The data node instance of interest.
1319
1320\retval one(1) if the specified data instance has an index.
1321\retval zero(0) otherwise.
1322*/
1323
1324int
1325oc_data_indexed(OCobject linkOCobject datanode)
1326{
1327    OCdatadata;
1328    OCVERIFY(OC_Data,datanode);
1329    OCDEREF(OCdata*,data,datanode);
1330
1331    return (fisset(data->datamode,OCDT_ELEMENT)
1332     || fisset(data->datamode,OCDT_RECORD)) ? 1 : 0;
1333}
1334
1335/**************************************************/
1336
1337/*!
1338This procedure does the work of actually extracting data
1339from a leaf instance of a data tree and storing it into
1340memory for use by the calling code.  The data instance must be
1341referencing either a scalar primitive value or an array of
1342primitive values. That is, its oc_data_octype()
1343value must be OCatomic.
1344If the variable is a scalar, then the
1345index and edge vectors will be ignored.
1346
1347\param[in] link The link through which the server is accessed.
1348\param[in] datanode The data node instance of interest.
1349\param[in] start A vector of indices specifying the starting element
1350to return.
1351\param[in] edges A vector of indices specifying the count in each dimension
1352of the number of elements to return.
1353\param[in] memsize The size (in bytes) of the memory argument.
1354\param[out] memory User allocated memory into which the extracted
1355data is to be stored. The caller is responsible for allocating and free'ing
1356this argument.
1357
1358\retval OC_NOERR The procedure executed normally.
1359\retval OC_EINVAL The memsize argument is too small to hold
1360the specified data.
1361\retval OC_EINVALCOORDS The start and/or edges argument is outside
1362the range of legal indices.
1363\retval OC_EDATADDS The data retrieved from the server was malformed
1364and the read request cannot be completed.
1365\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1366*/
1367
1368OCerror
1369oc_data_read(OCobject linkOCobject datanode,
1370                 size_t* start, size_t* edges,
1371          size_t memsize, void* memory)
1372{
1373    OCdatadata;
1374    OCnodepattern;
1375    size_t countrank;
1376
1377    OCVERIFY(OC_Data,datanode);
1378    OCDEREF(OCdata*,data,datanode);
1379
1380    if(start == NULL && edges == NULL) /* Assume it is a scalar read */
1381        return OCTHROW(oc_data_readn(link,datanode,start,0,memsize,memory));
1382
1383    if(edges == NULL)
1384 return OCTHROW(OCTHROW(OC_EINVALCOORDS));
1385
1386    /* Convert edges to a count */
1387    pattern = data->pattern;
1388    rank = pattern->array.rank;
1389    count = octotaldimsize(rank,edges);
1390
1391    return OCTHROW(oc_data_readn(link,datanode,start,count,memsize,memory));
1392}
1393
1394
1395/*!
1396This procedure is a variant of oc_data_read for reading a
1397single scalar from a leaf instance of a data tree and
1398storing it into memory for use by the calling code.  The
1399data instance must be referencing a scalar primitive value.
1400That is, its oc_data_octype() value must be OCatomic.
1401
1402\param[in] link The link through which the server is accessed.
1403\param[in] datanode The data node instance of interest.
1404\param[in] memsize The size (in bytes) of the memory argument.
1405\param[out] memory User allocated memory into which the extracted
1406data is to be stored. The caller is responsible for allocating and free'ing
1407this argument.
1408
1409\retval OC_NOERR The procedure executed normally.
1410\retval OC_EINVAL The memsize argument is too small to hold
1411the specified data.
1412\retval OC_ESCALAR The data instance is not a scalar.
1413\retval OC_EDATADDS The data retrieved from the server was malformed
1414and the read request cannot be completed.
1415\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1416*/
1417
1418OCerror
1419oc_data_readscalar(OCobject linkOCobject datanode,
1420          size_t memsize, void* memory)
1421{
1422    return OCTHROW(oc_data_readn(link,datanode,NULL,0,memsize,memory));
1423}
1424
1425/*!
1426This procedure is a variant of oc_data_read for reading
1427nelements of values starting at a given index position.
1428If the variable is a scalar, then the
1429index vector and count will be ignored.
1430
1431\param[in] link The link through which the server is accessed.
1432\param[in] datanode The data node instance of interest.
1433\param[in] start A vector of indices specifying the starting element
1434to return.
1435\param[in] N The number of elements to read. Reading is assumed
1436to use row-major order.
1437\param[in] memsize The size (in bytes) of the memory argument.
1438\param[out] memory User allocated memory into which the extracted
1439data is to be stored. The caller is responsible for allocating and free'ing
1440this argument.
1441
1442\retval OC_NOERR The procedure executed normally.
1443\retval OC_EINVAL The memsize argument is too small to hold
1444the specified data.
1445\retval OC_EINVALCOORDS The start and/or count argument is outside
1446the range of legal indices.
1447\retval OC_EDATADDS The data retrieved from the server was malformed
1448and the read request cannot be completed.
1449\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1450*/
1451
1452OCerror
1453oc_data_readn(OCobject linkOCobject datanode,
1454                 size_t* start, size_t N,
1455          size_t memsize, void* memory)
1456{
1457    OCerror ocerr = OC_NOERR;
1458    OCstatestate;
1459    OCdatadata;
1460    OCnodepattern;
1461    size_t rank,startpoint;
1462
1463    OCVERIFY(OC_State,link);
1464    OCDEREF(OCstate*,state,link);
1465    OCVERIFY(OC_Data,datanode);
1466    OCDEREF(OCdata*,data,datanode);
1467
1468    /* Do argument validation */
1469
1470    if(memory == NULL || memsize == 0)
1471 return OCTHROW(OC_EINVAL);
1472
1473    pattern = data->pattern;
1474    rank = pattern->array.rank;
1475
1476    if(rank == 0) {
1477 startpoint = 0;
1478 N = 1;
1479    } else if(start == NULL) {
1480        return OCTHROW(OCTHROW(OC_EINVALCOORDS));
1481    } else {/* not scalar */
1482 startpoint = ocarrayoffset(rank,pattern->array.sizes,start);
1483    }
1484    if(N > 0)
1485        ocerr = ocdata_read(state,data,startpoint,N,memory,memsize);
1486    if(ocerr == OC_EDATADDS)
1487 ocdataddsmsg(state,pattern->tree);
1488    return OCTHROW(OCTHROW(ocerr));
1489}
1490
1491
1492
1493/*!
1494This procedure has the same semantics as oc_data_read.
1495However, it takes an OCddsnode as argument.
1496The limitation is that the DDS node must be a top-level,
1497atomic variable.
1498Top-level means that it is not nested in a Sequence or a
1499dimensioned Structure; being in a Grid is ok as is being in
1500a scalar structure.
1501
1502\param[in] link The link through which the server is accessed.
1503\param[in] ddsnode The dds node instance of interest.
1504\param[in] start A vector of indices specifying the starting element
1505to return.
1506\param[in] edges A vector of indices specifying the count in each dimension
1507of the number of elements to return.
1508\param[in] memsize The size (in bytes) of the memory argument.
1509\param[out] memory User allocated memory into which the extracted
1510data is to be stored. The caller is responsible for allocating and free'ing
1511this argument.
1512
1513\retval OC_NOERR The procedure executed normally.
1514\retval OC_EINVAL The memsize argument is too small to hold
1515the specified data.
1516\retval OC_EINVALCOORDS The start and/or edges argument is outside
1517the range of legal indices.
1518\retval OC_EDATADDS The data retrieved from the server was malformed
1519and the read request cannot be completed.
1520
1521*/
1522
1523OCerror
1524oc_dds_read(OCobject linkOCobject ddsnode,
1525                 size_t* start, size_t* edges,
1526          size_t memsize, void* memory)
1527{
1528    OCdatadata;
1529    OCnodedds;
1530
1531    OCVERIFY(OC_Node,ddsnode);
1532    OCDEREF(OCnode*,dds,ddsnode);
1533
1534    /* Get the data associated with this top-level node */
1535    data = dds->data;
1536    if(data == NULL) return OCTHROW(OC_EINVAL);
1537    return OCTHROW(oc_data_read(link,data,start,edges,memsize,memory));
1538}
1539
1540
1541/*!
1542This procedure is a variant of oc_data_read for reading a single scalar.
1543This procedure has the same semantics as oc_data_readscalar.
1544However, it takes an OCddsnode as argument.
1545The limitation is that the DDS node must be a top-level, atomic variable.
1546Top-level means that it is not nested in a Sequence or a
1547dimensioned Structure; being in a Grid is ok as is being in
1548a scalar structure.
1549
1550\param[in] link The link through which the server is accessed.
1551\param[in] ddsnode The dds node instance of interest.
1552\param[in] memsize The size (in bytes) of the memory argument.
1553\param[out] memory User allocated memory into which the extracted
1554data is to be stored. The caller is responsible for allocating and free'ing
1555this argument.
1556
1557\retval OC_NOERR The procedure executed normally.
1558\retval OC_EINVAL The memsize argument is too small to hold
1559the specified data.
1560\retval OC_ESCALAR The data instance is not a scalar.
1561\retval OC_EDATADDS The data retrieved from the server was malformed
1562and the read request cannot be completed.
1563\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1564*/
1565
1566OCerror
1567oc_dds_readscalar(OCobject linkOCobject ddsnode,
1568          size_t memsize, void* memory)
1569{
1570    return OCTHROW(oc_dds_readn(link,ddsnode,NULL,0,memsize,memory));
1571}
1572
1573/*!
1574This procedure is a variant of oc_dds_read for reading
1575nelements of values starting at a given index position.
1576If the variable is a scalar, then the
1577index vector and count will be ignored.
1578This procedure has the same semantics as oc_data_readn.
1579However, it takes an OCddsnode as argument.
1580The limitation is that the DDS node must be a top-level, atomic variable.
1581Top-level means that it is not nested in a Sequence or a
1582dimensioned Structure; being in a Grid is ok as is being in
1583a scalar structure.
1584
1585\param[in] link The link through which the server is accessed.
1586\param[in] ddsnode The dds node instance of interest.
1587\param[in] start A vector of indices specifying the starting element
1588to return.
1589\param[in] N The number of elements to read. Reading is assumed
1590to use row-major order.
1591\param[in] memsize The size (in bytes) of the memory argument.
1592\param[out] memory User allocated memory into which the extracted
1593data is to be stored. The caller is responsible for allocating and free'ing
1594this argument.
1595
1596\retval OC_NOERR The procedure executed normally.
1597\retval OC_EINVAL The memsize argument is too small to hold
1598the specified data.
1599\retval OC_EINVALCOORDS The start and/or count argument is outside
1600the range of legal indices.
1601\retval OC_EDATADDS The data retrieved from the server was malformed
1602and the read request cannot be completed.
1603\retval OC_EINVAL  One of the arguments (link, etc.) was invalid.
1604*/
1605
1606OCerror
1607oc_dds_readn(OCobject linkOCobject ddsnode,
1608                 size_t* start, size_t N,
1609          size_t memsize, void* memory)
1610{
1611    OCdatadata;
1612    OCnodedds;
1613
1614    OCVERIFY(OC_Node,ddsnode);
1615    OCDEREF(OCnode*,dds,ddsnode);
1616
1617    /* Get the data associated with this top-level node */
1618    data = dds->data;
1619    if(data == NULL) return OCTHROW(OC_EINVAL);
1620    return OCTHROW(oc_data_readn(link,data,start,N,memsize,memory));
1621}
1622
1623/**@}*/
1624
1625/**************************************************/
1626/*!\defgroup OCtype OCtype Management
1627@{*/
1628
1629/*!
1630Return the size of the C data structure corresponding
1631to a given atomic type.
1632For example,
1633oc_typesize(OC_Int32) == sizeof(int), and
1634oc_typesize(OC_String) == sizeof(char*).
1635Non-atomic types (e.g. OC_Structure) return zero.
1636
1637\param[in] etype The atomic type.
1638
1639\return The C size of the atomic type.
1640*/
1641
1642size_t
1643oc_typesize(OCtype etype)
1644{
1645    return octypesize(etype);
1646}
1647
1648/*!
1649Return a string corresponding to the
1650to a given OCtype.
1651For example,
1652oc_typetostring(OC_Int32) == "Int32" and
1653oc_typesize(OC_Structure) == "Structure".
1654The caller MUST NOT free the returned string.
1655
1656\param[in] octype The OCtype value.
1657
1658\return The name, as a string, of that OCtype value.
1659*/
1660
1661const char*
1662oc_typetostring(OCtype octype)
1663{
1664    return octypetoddsstring(octype);
1665}
1666
1667/*!
1668Print a value of an atomic type instance.
1669This is primarily for debugging and provides
1670a simple way to convert a value to a printable string.
1671
1672\param[in] etype The OCtype atomic type.
1673\param[in] value A pointer to the value to be printed.
1674\param[in] bufsize The size of the buffer argument
1675\param[in] buffer The buffer into which to store the printable
1676value as a NULL terminated string.
1677
1678\retval OC_NOERR if the procedure succeeded
1679\retval OC_EINVAL  if one of the arguments is illegal.
1680*/
1681
1682OCerror
1683oc_typeprint(OCtype etype, void* value, size_t bufsize, char* buffer)
1684{
1685    return OCTHROW(octypeprint(etype,value,bufsize,buffer));
1686}
1687
1688/**@}*/
1689
1690/**************************************************/
1691/* The oc_logXXX procedures are defined in oclog.c */
1692
1693/**************************************************/
1694/* Miscellaneous */
1695
1696/*!\defgroup Miscellaneous Miscellaneous Procedures
1697@{*/
1698
1699/*!
1700Return a user-readable error message corresponding
1701to a given OCerror value.
1702
1703\param[in] err The OCerror value.
1704
1705\return The error message
1706*/
1707
1708const char*
1709oc_errstring(OCerror err)
1710{
1711    return ocerrstring(err);
1712}
1713
1714/*!
1715Each OClink object maintains a table of
1716(name,value) pairs, called client parameters.
1717It is initialized from any such parameters
1718specified in the URL given as argument to
1719oc_open().
1720
1721\param[in] link The link through which the server is accessed.
1722\param[in] param The name of the parameter whose value is desired.
1723
1724\return The corresponding value, or NULL if parameter name is not in the table.
1725*/
1726
1727const char*
1728oc_clientparam_get(OCobject link, const char* param)
1729{
1730    OCstatestate;
1731    OCVERIFYX(OC_State,link,NULL);
1732    OCDEREF(OCstate*,state,link);
1733
1734    return ocparamlookup(state,param);
1735}
1736
1737#ifdef OCIGNORE
1738/* Delete client parameter
1739   return value:
1740 OC_NOERR => defined; deletion performed
1741 OC_EINVAL => not already defined
1742*/
1743OCerror
1744oc_clientparam_delete(OCobject link, const char* param)
1745{
1746    OCstatestate;
1747    OCVERIFY(OC_State,link);
1748    OCDEREF(OCstate*,state,link);
1749
1750    return OCTHROW(ocparamdelete(state->clientparams,param));
1751}
1752
1753/* Insert client parameter
1754   return value:
1755 OC_NOERR => not already define; insertion performed
1756 OC_EINVAL => already defined
1757*/
1758OCerror
1759oc_clientparam_insert(OCobject link, const char* param, const char* value)
1760{
1761    OCstatestate;
1762    OCVERIFY(OC_State,link);
1763    OCDEREF(OCstate*,state,link);
1764
1765    state->clientparams = dapparaminsert(state->clientparams,param,value);
1766    return OCTHROW(OC_NOERR);
1767}
1768
1769/* Replace client parameter
1770   return value:
1771 OC_NOERR => already define; replacement performed
1772 OC_EINVAL => not already defined
1773*/
1774OCerror
1775oc_clientparam_replace(OCobject link, const char* param, const char* value)
1776{
1777    OCstatestate;
1778    OCVERIFY(OC_State,link);
1779    OCDEREF(OCstate*,state,link);
1780
1781    return dapparamreplace(state->clientparams,param,value);
1782}
1783#endif
1784
1785/**************************************************/
1786
1787/*!
1788Sometimes, when a fetch request fails, there will be
1789error information in the reply from the server.
1790Typically this only occurs if an API operation
1791returns OC_EDAS, OC_EDDS, OC_EDATADDS, or OC_EDAPSVC.
1792This procedure will attempt to locate and return information
1793from such an error reply.
1794
1795The error reply contains three pieces of information.
1796<ol>
1797<li> code - a string representing a numeric error code.
1798<li> msg - a string representing an extended error message.
1799<li> http - an integer representing an HTTP error return (e.g. 404).
1800</ol>
1801
1802\param[in] link The link through which the server is accessed.
1803\param[in] codep A pointer for returning the error code.
1804\param[in] msgp A pointer for returning the error message.
1805\param[in] httpp A pointer for returning the HTTP error number.
1806
1807\retval OC_NOERR if an error was found and the return values are defined.
1808\retval OC_EINVAL  if no error reply could be found, so the return
1809values are meaningless.
1810*/
1811
1812OCerror
1813oc_svcerrordata(OCobject link, char** codep,
1814                               char** msgp, long* httpp)
1815{
1816    OCstatestate;
1817    OCVERIFY(OC_State,link);
1818    OCDEREF(OCstate*,state,link);
1819    return OCTHROW(ocsvcerrordata(state,codep,msgp,httpp));
1820}
1821
1822/*!
1823Obtain the HTTP code (e.g. 200, 404, etc) from the last
1824fetch command.
1825
1826\param[in] link The link through which the server is accessed.
1827
1828\retval the HTTP code
1829*/
1830
1831OCerror
1832oc_httpcode(OCobject link)
1833{
1834    OCstatestate;
1835    OCVERIFY(OC_State,link);
1836    OCDEREF(OCstate*,state,link);
1837    return state->error.httpcode;
1838}
1839
1840/**************************************************/
1841/* New 10/31/2009: return the size(in bytes)
1842   of the fetched datadds.
1843*/
1844
1845/*!
1846Return the size of the in-memory or on-disk
1847data chunk returned by the server.
1848
1849\param[in] link The link through which the server is accessed.
1850\param[in] ddsroot The root dds node of the tree whose xdr size is desired.
1851\param[out] xdrsizep The size in bytes of the returned packet.
1852
1853\retval OC_NOERR if the procedure succeeded
1854\retval OC_EINVAL if an argument was invalid
1855*/
1856
1857OCerror
1858oc_raw_xdrsize(OCobject linkOCobject ddsrootoff_txdrsizep)
1859{
1860    OCnoderoot;
1861    OCVERIFY(OC_Node,ddsroot);
1862    OCDEREF(OCnode*,root,ddsroot);
1863
1864    if(root->root == NULL || root->root->tree == NULL
1865 || root->root->tree->dxdclass != OCDATADDS)
1866     return OCTHROW(OCTHROW(OC_EINVAL));
1867    if(xdrsizep) *xdrsizep = root->root->tree->data.datasize;
1868    return OCTHROW(OC_NOERR);
1869}
1870
1871/* Resend a url as a head request to check the Last-Modified time */
1872OCerror
1873oc_update_lastmodified_data(OCobject link)
1874{
1875    OCstatestate;
1876    OCVERIFY(OC_State,link);
1877    OCDEREF(OCstate*,state,link);
1878    return OCTHROW(ocupdatelastmodifieddata(state));
1879}
1880
1881long
1882oc_get_lastmodified_data(OCobject link)
1883{
1884    OCstatestate;
1885    OCVERIFY(OC_State,link);
1886    OCDEREF(OCstate*,state,link);
1887    return state->datalastmodified;
1888}
1889
1890/* Given an arbitrary OCnode, return the connection of which it is a part */
1891OCerror
1892oc_get_connection(OCobject ddsnodeOCobjectlinkp)
1893{
1894    OCnodenode;
1895    OCVERIFY(OC_Node,ddsnode);
1896    OCDEREF(OCnode*,node,ddsnode);
1897    if(linkp) *linkp = node->root->tree->state;
1898    return OCTHROW(OC_NOERR);
1899}
1900
1901
1902/*!
1903Attempt to retrieve a dataset using a specified URL
1904and using the DAP protocol.
1905
1906\param[in] url The url to use for the request.
1907
1908\retval OC_NOERR if the request succeeded.
1909\retval OC_EINVAL if the request failed.
1910*/
1911
1912OCerror
1913oc_ping(const char* url)
1914{
1915    return OCTHROW(ocping(url));
1916}
1917/**@}*/
1918
1919/**************************************************/
1920
1921int
1922oc_dumpnode(OCobject linkOCobject ddsroot)
1923{
1924    OCnoderoot;
1925    OCerror ocerr = OC_NOERR;
1926    OCVERIFY(OC_Node,ddsroot);
1927    OCDEREF(OCnode*,root,ddsroot);
1928    ocdumpnode(root);
1929    return OCTHROW(ocerr);
1930}
1931
1932/**************************************************/
1933/* ocx.h interface */
1934/* Following procedures are in API, but are not
1935   externally documented.
1936*/
1937
1938
1939OCerror
1940oc_dds_dd(OCobject linkOCobject ddsroot, int level)
1941{
1942    OCstatestate;
1943    OCnoderoot;
1944    OCVERIFY(OC_State,link);
1945    OCDEREF(OCstate*,state,link);
1946    OCVERIFY(OC_Node,ddsroot);
1947    OCDEREF(OCnode*,root,ddsroot);
1948
1949    ocdd(state,root,1,level);
1950    return OCTHROW(OC_NOERR);
1951}
1952
1953OCerror
1954oc_dds_ddnode(OCobject linkOCobject ddsroot)
1955{
1956    OCnoderoot;
1957    OCVERIFY(OC_Node,ddsroot);
1958    OCDEREF(OCnode*,root,ddsroot);
1959
1960    ocdumpnode(root);
1961    return OCTHROW(OC_NOERR);
1962}
1963
1964OCerror
1965oc_data_ddpath(OCobject linkOCobject datanode, char** resultp)
1966{
1967    OCstatestate;
1968    OCdatadata;
1969    OCbytesbuffer;
1970
1971    OCVERIFY(OC_State,link);
1972    OCDEREF(OCstate*,state,link);
1973    OCVERIFY(OC_Data,datanode);
1974    OCDEREF(OCdata*,data,datanode);
1975
1976    buffer = ocbytesnew();
1977    ocdumpdatapath(state,data,buffer);
1978    if(resultp) *resultp = ocbytesdup(buffer);
1979    ocbytesfree(buffer);
1980    return OCTHROW(OC_NOERR);
1981}
1982
1983OCerror
1984oc_data_ddtree(OCobject linkOCobject ddsroot)
1985{
1986    OCstatestate;
1987    OCdatadata;
1988    OCbytesbuffer;
1989    OCVERIFY(OC_State,link);
1990    OCDEREF(OCstate*,state,link);
1991    OCVERIFY(OC_Data,ddsroot);
1992    OCDEREF(OCdata*,data,ddsroot);
1993
1994    buffer = ocbytesnew();
1995    ocdumpdatatree(state,data,buffer,0);
1996    fprintf(stderr,"%s\n",ocbytescontents(buffer));
1997    ocbytesfree(buffer);
1998    return OCTHROW(OC_NOERR);
1999}
2000
2001OCDT
2002oc_data_mode(OCobject linkOCobject datanode)
2003{
2004    OCdatadata;
2005    OCVERIFY(OC_Data,datanode);
2006    OCDEREF(OCdata*,data,datanode);
2007
2008    return data->datamode;
2009}
2010
2011/* Free up a datanode that is no longer being used;
2012   Currently does nothing
2013*/
2014OCerror
2015oc_data_free(OCobject linkOCobject datanode)
2016{
2017    return OCTHROW(OC_NOERR);
2018}
2019
2020/* Free up a ddsnode that is no longer being used;
2021   Currently does nothing
2022*/
2023OCerror
2024oc_dds_free(OCobject linkOCobject dds0)
2025{
2026    return OCTHROW(OC_NOERR);
2027}
2028
2029
2030/**************************************************/
2031/* Curl specific  options */
2032
2033/*!\defgroup Curl Curl-specifi Procedures
2034@{*/
2035
2036/*!
2037Set an arbitrary curl option. Option
2038must be one of the ones supported by oc.
2039
2040\param[in] link The link through which the server is accessed.
2041\param[in] option The name of the option to set;
2042                  See occurlfunction.c for
2043                  the set of supported flags and names.
2044\param[in] value The option value.
2045
2046\retval OC_NOERR if the request succeeded.
2047\retval OC_ECURL if the request failed.
2048*/
2049
2050OCerror
2051oc_set_curlopt(OClink link, const char* option, void* value)
2052{
2053    OCstatestate;
2054    struct OCCURLFLAGf;
2055
2056    OCVERIFY(OC_State,link);
2057    OCDEREF(OCstate*,state,link);
2058    f = occurlflagbyname(option);
2059    if(f == NULL)
2060 return OCTHROW(OC_ECURL);
2061    return OCTHROW(ocset_curlopt(state,f->flag,value));
2062}
2063
2064/*!
2065Set the absolute path to use for the .netrc file
2066
2067\param[in] link The link through which the server is accessed.
2068\param[in] netrc The path to use.
2069
2070\retval OC_NOERR if the request succeeded.
2071\retval OC_EINVAL if the request failed, typically
2072                  because the path string is null or zero-length.
2073*/
2074
2075OCerror
2076oc_set_netrc(OClinklink, const char* file)
2077{
2078    OCstatestate;
2079    FILEf;
2080    OCVERIFY(OC_State,link);
2081    OCDEREF(OCstate*,state,link);
2082
2083
2084    if(file == NULL || strlen(file) == 0)
2085 return OC_EINVAL;
2086    oclog(OCLOGDBG,"OC: using netrc file: %s",file);
2087    /* See if it exists and is readable; complain if not */
2088    f = fopen(file,"r");
2089    if(f == NULL)
2090 oclog(OCLOGWARN,"OC: netrc file is not readable; continuing");
2091    else {
2092 fclose(f);
2093    }
2094    return OCTHROW(ocset_netrc(state,file));
2095}
2096
2097/*!
2098Set the user agent field.
2099
2100\param[in] link The link through which the server is accessed.
2101\param[in] agent The user agent string
2102
2103\retval OC_NOERR if the request succeeded.
2104\retval OC_EINVAL if the request failed, typically
2105                  because the agent string is null or zero-length.
2106*/
2107
2108OCerror
2109oc_set_useragent(OCobject link, const char* agent)
2110{
2111    OCstatestate;
2112    OCVERIFY(OC_State,link);
2113    OCDEREF(OCstate*,state,link);
2114
2115    if(agent == NULL || strlen(agent) == 0)
2116 return OC_EINVAL;
2117    return OCTHROW(ocset_useragent(state,agent));
2118}
2119
2120/*!
2121Set the absolute path to use for the rc file.
2122WARNING: this MUST be called before any other
2123call in order for this to take effect.
2124
2125\param[in] rcfile The path to use. If NULL, or "",
2126                  then do not use any rcfile.
2127
2128\retval OC_NOERR if the request succeeded.
2129\retval OC_ERCFILE if the file failed to load
2130*/
2131
2132OCerror
2133oc_set_rcfile(const char* rcfile)
2134{
2135    OCerror stat = OC_NOERR;
2136    if(rcfile != NULL && strlen(rcfile) == 0)
2137 rcfile = NULL;
2138
2139    if(!ocglobalstate.initialized)
2140 ocinternalinitialize(); /* so ocglobalstate is defined, but not triplestore */
2141    if(rcfile == NULL) {
2142 ocglobalstate.rc.ignore = 1;
2143    } else {
2144        FILEf = fopen(rcfile,"r");
2145        if(f == NULL) {
2146     stat = (OC_ERCFILE);
2147     goto done;
2148        }
2149        fclose(f);
2150        ocglobalstate.rc.rcfile = strdup(rcfile);
2151        /* (re) load the rcfile and esp the triplestore*/
2152        stat = ocrc_load();
2153    }
2154done:
2155    return OCTHROW(stat);
2156}
2157
2158/*!
2159Force the curl library to trace its actions.
2160
2161\param[in] link The link through which the server is accessed.
2162
2163\retval OC_NOERR if the request succeeded.
2164*/
2165
2166OCerror
2167oc_trace_curl(OCobject link)
2168{
2169    OCstatestate;
2170    OCVERIFY(OC_State,link);
2171    OCDEREF(OCstate*,state,link);
2172    oc_curl_debug(state);
2173    return OCTHROW(OC_NOERR);
2174}
2175
2176OCerror
2177oc_initialize(void)
2178{
2179    OCerror status = OC_NOERR;
2180    if(!ocglobalstate.initialized) {
2181        /* Clean up before re-initializing */
2182 if(ocglobalstate.tempdir != NULL) free(ocglobalstate.tempdir);
2183 if(ocglobalstate.home != NULL) free(ocglobalstate.home);
2184 if(ocglobalstate.rc.rcfile != NULL) free(ocglobalstate.rc.rcfile);
2185    }
2186    ocglobalstate.initialized = 0;
2187    status = ocinternalinitialize();
2188    /* (re) load the rcfile */
2189    status =  ocrc_load();
2190    return OCTHROW(status);
2191}
2192
2193/**@}*/


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed