1 /**
2  * @file fctxml.cpp
3  *
4  */
5 
6 // This file is part of Cantera. See License.txt in the top-level directory or
7 // at https://cantera.org/license.txt for license and copyright information.
8 
9 #include "clib/clib_utils.h"
10 #include "cantera/base/ctml.h"
11 #include "cantera/base/global.h"
12 
13 #include <cstring>
14 #include <fstream>
15 
16 using namespace std;
17 using Cantera::XML_Node;
18 using Cantera::CanteraError;
19 using Cantera::handleAllExceptions;
20 
21 #include "clib/Cabinet.h"
22 
23 typedef Cabinet<XML_Node, false> XmlCabinet;
24 template<> XmlCabinet* XmlCabinet::s_storage = 0;
25 
26 typedef integer status_t;
27 
28 namespace {
29 
_xml(const integer * i)30 XML_Node* _xml(const integer* i)
31 {
32     return &XmlCabinet::item(*i);
33 }
34 
35 } // unnamed namespace
36 
37 std::string f2string(const char* s, ftnlen n);
38 
39 extern "C" {
40 
fxml_new_(const char * name,ftnlen namelen)41     integer fxml_new_(const char* name, ftnlen namelen)
42     {
43         try {
44             XML_Node* x;
45             if (!name) {
46                 x = new XML_Node;
47             } else {
48                 x = new XML_Node(f2string(name, namelen), 0);
49             }
50             return XmlCabinet::add(x);
51         } catch (...) {
52             return handleAllExceptions(-1, ERR);
53         }
54     }
55 
fxml_get_xml_file_(const char * file,ftnlen filelen)56     status_t fxml_get_xml_file_(const char* file, ftnlen filelen)
57     {
58         try {
59             XML_Node* x = Cantera::get_XML_File(f2string(file, filelen));
60             return XmlCabinet::add(x);
61         } catch (...) {
62             return handleAllExceptions(-1, ERR);
63         }
64     }
65 
fxml_clear_()66     status_t fxml_clear_()
67     {
68         try {
69             XmlCabinet::clear();
70             Cantera::close_XML_File("all");
71             return 0;
72         } catch (...) {
73             return handleAllExceptions(-1, ERR);
74         }
75     }
76 
fxml_del_(const integer * i)77     status_t fxml_del_(const integer* i)
78     {
79         try {
80             XmlCabinet::del(*i);
81             return 0;
82         } catch (...) {
83             return handleAllExceptions(-1, ERR);
84         }
85     }
86 
fxml_removechild_(const integer * i,const integer * j)87     status_t fxml_removechild_(const integer* i, const integer* j)
88     {
89         try {
90             _xml(i)->removeChild(_xml(j));
91             return 0;
92         } catch (...) {
93             return handleAllExceptions(-1, ERR);
94         }
95     }
96 
fxml_copy_(const integer * i)97     status_t fxml_copy_(const integer* i)
98     {
99         try {
100             return XmlCabinet::newCopy(*i);
101         } catch (...) {
102             return handleAllExceptions(-1, ERR);
103         }
104     }
105 
fxml_attrib_(const integer * i,const char * key,char * value,ftnlen keylen,ftnlen valuelen)106     status_t fxml_attrib_(const integer* i, const char* key, char* value,
107                           ftnlen keylen, ftnlen valuelen)
108     {
109         try {
110             std::string ky = f2string(key, keylen);
111             XML_Node& node = *_xml(i);
112             if (node.hasAttrib(ky)) {
113                 std::string v = node[ky];
114                 strncpy(value, v.c_str(), valuelen);
115             } else {
116                 throw CanteraError("fxml_attrib","node "
117                                    " has no attribute '"+ky+"'");
118             }
119         } catch (...) {
120             return handleAllExceptions(-1, ERR);
121         }
122         return 0;
123     }
124 
fxml_addattrib_(const integer * i,const char * key,const char * value,ftnlen keylen,ftnlen valuelen)125     status_t fxml_addattrib_(const integer* i, const char* key,
126                              const char* value, ftnlen keylen, ftnlen valuelen)
127     {
128         try {
129             std::string ky = f2string(key, keylen);
130             std::string val = f2string(value, valuelen);
131             XML_Node& node = *_xml(i);
132             node.addAttribute(ky, val);
133         } catch (...) {
134             return handleAllExceptions(-1, ERR);
135         }
136         return 0;
137     }
138 
fxml_addcomment_(const integer * i,const char * comment,ftnlen commentlen)139     status_t fxml_addcomment_(const integer* i, const char* comment,
140                               ftnlen commentlen)
141     {
142         try {
143             std::string c = f2string(comment, commentlen);
144             XML_Node& node = *_xml(i);
145             node.addComment(c);
146         } catch (...) {
147             return handleAllExceptions(-1, ERR);
148         }
149         return 0;
150     }
151 
fxml_tag_(const integer * i,char * tag,ftnlen taglen)152     status_t fxml_tag_(const integer* i, char* tag, ftnlen taglen)
153     {
154         try {
155             XML_Node& node = *_xml(i);
156             const std::string v = node.name();
157             strncpy(tag, v.c_str(), taglen);
158         } catch (...) {
159             return handleAllExceptions(-1, ERR);
160         }
161         return 0;
162     }
163 
fxml_value_(const integer * i,char * value,ftnlen valuelen)164     status_t fxml_value_(const integer* i, char* value, ftnlen valuelen)
165     {
166         try {
167             XML_Node& node = *_xml(i);
168             const std::string v = node.value();
169             strncpy(value, v.c_str(), valuelen);
170         } catch (...) {
171             return handleAllExceptions(-1, ERR);
172         }
173         return 0;
174     }
175 
fxml_child_(const integer * i,const char * loc,ftnlen loclen)176     status_t fxml_child_(const integer* i, const char* loc, ftnlen loclen)
177     {
178         try {
179             XML_Node& node = *_xml(i);
180             XML_Node& c = node.child(f2string(loc, loclen));
181             return XmlCabinet::add(&c);
182         } catch (...) {
183             return handleAllExceptions(-1, ERR);
184         }
185     }
186 
fxml_child_bynumber_(const integer * i,const integer * m)187     status_t fxml_child_bynumber_(const integer* i, const integer* m)
188     {
189         try {
190             XML_Node& node = *_xml(i);
191             XML_Node& c = node.child(*m);
192             return XmlCabinet::add(&c);
193         } catch (...) {
194             return handleAllExceptions(-1, ERR);
195         }
196         return 0;
197     }
198 
fxml_findid_(const integer * i,const char * id,ftnlen idlen)199     status_t fxml_findid_(const integer* i, const char* id, ftnlen idlen)
200     {
201         try {
202             XML_Node& node = *_xml(i);
203             XML_Node* c = node.findID(f2string(id, idlen));
204             if (c) {
205                 return XmlCabinet::add(c);
206             } else {
207                 throw CanteraError("fxml_findid", "id not found: '{}'",
208                                    f2string(id, idlen));
209             }
210         } catch (...) {
211             return handleAllExceptions(-1, ERR);
212         }
213         return 0;
214     }
215 
fxml_findbyname_(const integer * i,const char * nm,ftnlen nmlen)216     status_t fxml_findbyname_(const integer* i, const char* nm, ftnlen nmlen)
217     {
218         try {
219             XML_Node& node = *_xml(i);
220             XML_Node* c = node.findByName(f2string(nm, nmlen));
221             if (c) {
222                 return XmlCabinet::add(c);
223             } else {
224                 throw CanteraError("fxml_findByName", "name '{}' not found",
225                                    f2string(nm, nmlen));
226             }
227         } catch (...) {
228             return handleAllExceptions(-1, ERR);
229         }
230         return 0;
231     }
232 
fxml_nchildren_(const integer * i)233     integer fxml_nchildren_(const integer* i)
234     {
235         try {
236             XML_Node& node = *_xml(i);
237             return node.nChildren();
238         } catch (...) {
239             return handleAllExceptions(-1, ERR);
240         }
241         return 0;
242     }
243 
fxml_addchild_(const integer * i,const char * name,const char * value,ftnlen namelen,ftnlen valuelen)244     status_t fxml_addchild_(const integer* i, const char* name,
245                             const char* value, ftnlen namelen, ftnlen valuelen)
246     {
247         try {
248             XML_Node& node = *_xml(i);
249             XML_Node& c = node.addChild(f2string(name, namelen),
250                                         f2string(value,valuelen));
251             return XmlCabinet::add(&c);
252         } catch (...) {
253             return handleAllExceptions(-1, ERR);
254         }
255         return 0;
256     }
257 
fxml_addchildnode_(const integer * i,const integer * j)258     status_t fxml_addchildnode_(const integer* i, const integer* j)
259     {
260         try {
261             XML_Node& node = *_xml(i);
262             XML_Node& chld = *_xml(j);
263             XML_Node& c = node.addChild(chld);
264             return XmlCabinet::add(&c);
265         } catch (...) {
266             return handleAllExceptions(-1, ERR);
267         }
268         return 0;
269     }
270 
fxml_write_(const integer * i,const char * file,ftnlen filelen)271     status_t fxml_write_(const integer* i, const char* file, ftnlen filelen)
272     {
273         try {
274             std::string ff(file, filelen);
275             ofstream f(ff.c_str());
276             if (f) {
277                 XML_Node& node = *_xml(i);
278                 node.write(f);
279             } else {
280                 throw CanteraError("fxml_write",
281                                    "file "+f2string(file, filelen)+" not found.");
282             }
283             return 0;
284         } catch (...) {
285             return handleAllExceptions(-1, ERR);
286         }
287         return 0;
288     }
289 
ctml_getfloatarray_(const integer * i,const integer * n,doublereal * data,const integer * iconvert)290     status_t ctml_getfloatarray_(const integer* i, const integer* n,
291                                  doublereal* data, const integer* iconvert)
292     {
293         try {
294             XML_Node& node = *_xml(i);
295             Cantera::vector_fp v;
296             bool conv = false;
297             if (*iconvert > 0) {
298                 conv = true;
299             }
300             getFloatArray(node, v, conv);
301             int nv = v.size();
302 
303             // array not big enough
304             if (*n < nv) {
305                 throw CanteraError("ctml_getfloatarray",
306                                    "array must be dimensioned at least {}", nv);
307             }
308 
309             for (int i = 0; i < nv; i++) {
310                 data[i] = v[i];
311             }
312         } catch (...) {
313             return handleAllExceptions(-1, ERR);
314         }
315         return 0;
316     }
317 
318 }
319