1 // Copyright (c) 1994 - 2010, Lawrence Livermore National Security, LLC.
2 // LLNL-CODE-425250.
3 // All rights reserved.
4 //
5 // This file is part of Silo. For details, see silo.llnl.gov.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the disclaimer below.
13 // * Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the disclaimer (as noted
15 // below) in the documentation and/or other materials provided with
16 // the distribution.
17 // * Neither the name of the LLNS/LLNL nor the names of its
18 // contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE
25 // LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR
26 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 //
34 // This work was produced at Lawrence Livermore National Laboratory under
35 // Contract No. DE-AC52-07NA27344 with the DOE. Neither the United
36 // States Government nor Lawrence Livermore National Security, LLC nor
37 // any of their employees, makes any warranty, express or implied, or
38 // assumes any liability or responsibility for the accuracy,
39 // completeness, or usefulness of any information, apparatus, product, or
40 // process disclosed, or represents that its use would not infringe
41 // privately-owned rights. Any reference herein to any specific
42 // commercial products, process, or services by trade name, trademark,
43 // manufacturer or otherwise does not necessarily constitute or imply its
44 // endorsement, recommendation, or favoring by the United States
45 // Government or Lawrence Livermore National Security, LLC. The views and
46 // opinions of authors expressed herein do not necessarily state or
47 // reflect those of the United States Government or Lawrence Livermore
48 // National Security, LLC, and shall not be used for advertising or
49 // product endorsement purposes.
50
51 #include "pydbfile.h"
52 #include "pydbtoc.h"
53 #include "pysilo.h"
54
55 #include <string>
56
57 using std::string;
58
59 #if PY_MAJOR_VERSION >= 3
60 #define PyInt_FromLong(x) (PyLong_FromLong(x))
61 #define PyInt_Check(x) (PyLong_Check(x))
62 #define PyString_Check(x) PyUnicode_Check(x)
63 #define PyInt_AS_LONG(x) PyLong_AsLong(x)
64 #define PyString_FromStringAndSize(x,y) PyUnicode_FromStringAndSize(x,y)
65 #define PyString_FromString(x) PyUnicode_FromString(x)
66 #define PyString_AsString(x) PyUnicode_AsUTF8(x)
67
68 #else
69 #define Py_RETURN_NOTIMPLEMENTED return NULL
70 #endif
71
72
73 // ****************************************************************************
74 // Method: DBfile_DBGetToc
75 //
76 // Purpose:
77 // Encapsulates DBGetToc
78 //
79 // Python Arguments:
80 // none
81 //
82 // Programmer: Jeremy Meredith
83 // Creation: July 12, 2005
84 //
85 // ****************************************************************************
DBfile_DBGetToc(PyObject * self,PyObject * args)86 static PyObject *DBfile_DBGetToc(PyObject *self, PyObject *args)
87 {
88 DBfileObject *obj = (DBfileObject*)self;
89
90 if (!obj->db)
91 {
92 SiloErrorFunc(self, "This file has been closed.");
93 return NULL;
94 }
95
96 DBtoc *toc = DBGetToc(obj->db);
97
98 DBtocObject *retval = PyObject_NEW(DBtocObject, &DBtocType);
99 if (retval)
100 {
101 retval->toc = toc;
102 }
103 return (PyObject*)retval;
104 }
105
106 // ****************************************************************************
107 // Method: DBfile_DBGetVar
108 //
109 // Purpose:
110 // Encapsulates DBGetVar
111 //
112 // Python Arguments:
113 // form 1: varname
114 //
115 // Programmer: Jeremy Meredith
116 // Creation: July 12, 2005
117 //
118 // Modifications:
119 //
120 // Mark C. Miller, Tue Aug 5 11:04:14 PDT 2008
121 // I modifed case where we're returning a string valued variable to strip
122 // off the trailing null character. The PyString_FromStringAndSize method
123 // was being given a length argument that included the trailing null and
124 // the result was a bit if an odd string in python.
125 //
126 // Mark C. Miller, Wed Nov 14 15:35:44 PST 2012
127 // Removed error return case for 'only flat variables.' This also fixes a
128 // problem with string object members on HDF5 driver where the funky "'<s>"
129 // construct is used for *both* string valued members and variable
130 // members whose value is also a string but is the name of another dataset
131 // in the file.
132 // ****************************************************************************
DBfile_DBGetVar(PyObject * self,PyObject * args)133 static PyObject *DBfile_DBGetVar(PyObject *self, PyObject *args)
134 {
135 DBfile *db = ((DBfileObject*)self)->db;
136
137 if (!db)
138 {
139 SiloErrorFunc(self, "This file has been closed.");
140 return NULL;
141 }
142
143 char *str;
144 if(!PyArg_ParseTuple(args, "s", &str))
145 return NULL;
146
147 int vartype = DBInqVarType(db, str);
148 if (vartype != DB_VARIABLE)
149 return NULL;
150
151 int len = DBGetVarLength(db,str);
152 int type = DBGetVarType(db,str);
153 void *var = DBGetVar(db,str);
154 if (len == 1 || type == DB_CHAR)
155 {
156 switch (type)
157 {
158 case DB_INT:
159 return PyInt_FromLong(*((int*)var));
160 case DB_SHORT:
161 return PyInt_FromLong(*((short*)var));
162 case DB_LONG:
163 return PyInt_FromLong(*((long*)var));
164 case DB_FLOAT:
165 return PyFloat_FromDouble(*((float*)var));
166 case DB_DOUBLE:
167 return PyFloat_FromDouble(*((double*)var));
168 case DB_CHAR:
169 if (len == 1)
170 return PyInt_FromLong(*((char*)var));
171 else
172 {
173 // strip trailing null if one exists
174 char *p = (char *) var;
175 if (p[len-1] == '\0') len--;
176 return PyString_FromStringAndSize((char*)var, len);
177 }
178 default:
179 SiloErrorFunc(self, "Unknown variable type.");
180 return NULL;
181 }
182 }
183 else
184 {
185 PyObject *retval = PyTuple_New(len);
186 for (int i=0; i<len; i++)
187 {
188 PyObject *tmp;
189 switch (type)
190 {
191 case DB_INT:
192 tmp = PyInt_FromLong(((int*)var)[i]);
193 break;
194 case DB_SHORT:
195 tmp = PyInt_FromLong(((short*)var)[i]);
196 break;
197 case DB_LONG:
198 tmp = PyInt_FromLong(((long*)var)[i]);
199 break;
200 case DB_FLOAT:
201 tmp = PyFloat_FromDouble(((float*)var)[i]);
202 break;
203 case DB_DOUBLE:
204 tmp = PyFloat_FromDouble(((double*)var)[i]);
205 break;
206 case DB_CHAR:
207 tmp = PyInt_FromLong(((char*)var)[i]);
208 break;
209 default:
210 SiloErrorFunc(self, "Unknown variable type.");
211 return NULL;
212 }
213 PyTuple_SET_ITEM(retval, i, tmp);
214 }
215 return retval;
216 }
217 }
218
219 // ****************************************************************************
220 // Method: DBfile_DBGetVarInfo
221 //
222 // Purpose: Get metadata for a variable
223 //
224 // Creation Mark C. Miller, Mon Nov 12 11:12:03 PST 2012
225 // Plagerized liberally from Silex' SiloObjectView
226 //
227 // Mark C. Miller, Tue Nov 13 17:29:29 PST 2012
228 // Added optional 1/0 flag to descend into variable components and read their
229 // data as a tuple member of the returned python dict.
230 // ****************************************************************************
DBfile_DBGetVarInfo(PyObject * self,PyObject * args)231 static PyObject *DBfile_DBGetVarInfo(PyObject *self, PyObject *args)
232 {
233 DBfile *db = ((DBfileObject*)self)->db;
234
235 if (!db)
236 {
237 SiloErrorFunc(self, "This file has been closed.");
238 return NULL;
239 }
240
241 char *str;
242 int get_data_flag = 0;
243 if (!PyArg_ParseTuple(args, "si", &str, &get_data_flag))
244 {
245 if (!PyArg_ParseTuple(args, "s", &str))
246 return NULL;
247 else
248 PyErr_Clear();
249 }
250
251 //
252 // Note that because we read the object through Silo's generic object
253 // interface, the Silo library will not be able to correctly apply
254 // object-level de-compression algorithms. We could add logic to the
255 // implementation of the GetObject method to detect the kind of object
256 // being read and, if it is a compressed mesh/var object, do the work
257 // necessary to prepare for its decompression. Too much work for now.
258 //
259 DBobject *silo_obj = DBGetObject(db, str);
260 if (!silo_obj)
261 {
262 char msg[256];
263 snprintf(msg, sizeof(msg), "Unable to get object \"%s\"", str);
264 SiloErrorFunc(self, msg);
265 return NULL;
266 }
267
268 PyObject *retval = PyDict_New();
269 PyDict_SetItemString(retval, "name", PyString_FromString(silo_obj->name));
270 PyDict_SetItemString(retval, "type", PyString_FromString(silo_obj->type));
271 for (int i=0; i<silo_obj->ncomponents; i++)
272 {
273 string compname = silo_obj->comp_names[i];
274 string pdbname = silo_obj->pdb_names[i];
275 void *comp = DBGetComponent(db, str, compname.c_str());
276 if (!comp)
277 {
278 char msg[256];
279 snprintf(msg, sizeof(msg), "Unable to get component \"%s\" for object \%s\"", compname.c_str(), str);
280 SiloErrorFunc(self, msg);
281 continue;
282 }
283 int type = DBGetComponentType(db, str, compname.c_str());
284 string typestr = "";
285 int ival = -1;
286 switch (type)
287 {
288 case DB_INT:
289 typestr = "int";
290 ival = *((int*)comp);
291 PyDict_SetItemString(retval, compname.c_str(), PyInt_FromLong((long)ival));
292 break;
293 case DB_SHORT:
294 typestr = "short";
295 ival = *((short*)comp);
296 PyDict_SetItemString(retval, compname.c_str(), PyInt_FromLong((long)ival));
297 break;
298 case DB_LONG:
299 typestr = "long";
300 ival = (int) *((long*)comp);
301 PyDict_SetItemString(retval, compname.c_str(), PyInt_FromLong((long)ival));
302 break;
303 case DB_LONG_LONG:
304 typestr = "long long";
305 ival = (int) *((long long*)comp);
306 PyDict_SetItemString(retval, compname.c_str(), PyInt_FromLong((long)ival));
307 break;
308 case DB_FLOAT:
309 typestr = "float";
310 PyDict_SetItemString(retval, compname.c_str(), PyFloat_FromDouble(*((float*)comp)));
311 break;
312 case DB_DOUBLE:
313 typestr = "double";
314 PyDict_SetItemString(retval, compname.c_str(), PyFloat_FromDouble(*((double*)comp)));
315 break;
316 case DB_CHAR:
317 typestr = "char";
318 if (*((char*)comp)== 0)
319 PyDict_SetItemString(retval, compname.c_str(), PyString_FromString(""));
320 else
321 PyDict_SetItemString(retval, compname.c_str(), PyString_FromString((char*)comp));
322 break;
323 case DB_NOTYPE:
324 typestr = "notype";
325 break;
326 default:
327 typestr = "var";
328 string valStr = std::string(pdbname.c_str());
329 if (pdbname.find("'<s>") == 0)
330 {
331 int len = pdbname.length();
332 valStr = string((const char*)(pdbname.c_str()),4,len-5);
333 }
334 if (get_data_flag)
335 {
336
337 PyObject *argTuple = PyTuple_New(1);
338 PyTuple_SetItem(argTuple, 0, PyString_FromString(valStr.c_str()));
339 PyObject *dobj = DBfile_DBGetVar(self, argTuple);
340 if (dobj)
341 PyDict_SetItemString(retval, compname.c_str(), dobj);
342 else
343 PyDict_SetItemString(retval, compname.c_str(), PyString_FromString(valStr.c_str()));
344 }
345 else
346 {
347 PyDict_SetItemString(retval, compname.c_str(), PyString_FromString(valStr.c_str()));
348 }
349 break;
350 }
351
352 // No such call as "DBFreeComponent". Maybe there should be one!
353 free(comp);
354 comp = NULL;
355
356 }
357 DBFreeObject(silo_obj);
358
359 return retval;
360 }
361
362 // ****************************************************************************
363 // Method: DBfile_DBGetVar
364 //
365 // Purpose:
366 // Encapsulates DBGetVar
367 //
368 // Python Arguments:
369 // form 1: varname, integer
370 // form 2: varname, real
371 // form 3: varname, string
372 // form 4: varname, tuple
373 //
374 // Programmer: Jeremy Meredith
375 // Creation: July 12, 2005
376 //
377 // Modifications
378 // Mark C. Miller, Thu Dec 20 00:05:41 PST 2012
379 // Adjust parsing logic to avoid deprecation warning for parsing a float into
380 // an integer variable.
381 // ****************************************************************************
DBfile_DBWrite(PyObject * self,PyObject * args)382 static PyObject *DBfile_DBWrite(PyObject *self, PyObject *args)
383 {
384 DBfile *db = ((DBfileObject*)self)->db;
385
386 if (!db)
387 {
388 SiloErrorFunc(self, "This file has been closed.");
389 return NULL;
390 }
391
392 int dims;
393 int err;
394 char *str;
395
396 int ivar;
397 double dvar;
398 char *svar;
399 PyObject *tuple;
400 if (PyArg_ParseTuple(args, "sd", &str, &dvar))
401 {
402 dims = 1;
403 if (dvar == (int) dvar)
404 {
405 ivar = (int) dvar;
406 err = DBWrite(db, str, &ivar, &dims,1, DB_INT);
407 }
408 else
409 {
410 err = DBWrite(db, str, &dvar, &dims,1, DB_DOUBLE);
411 }
412 }
413 else if (PyArg_ParseTuple(args, "ss", &str, &svar))
414 {
415 dims = strlen(svar);
416 err = DBWrite(db, str, svar, &dims,1, DB_CHAR);
417 }
418 else if (PyArg_ParseTuple(args, "sO", &str, &tuple))
419 {
420 if(!PyTuple_Check(tuple))
421 return NULL;
422
423 int len = PyTuple_Size(tuple);
424 if (len < 1)
425 {
426 PyErr_SetString(PyExc_TypeError, "Tuple must be of size > 0");
427 return NULL;
428 }
429
430 PyObject *item = PyTuple_GET_ITEM(tuple, 0);
431 if (PyInt_Check(item))
432 {
433 int *values = new int[len];
434 for (int i=0; i<len; i++)
435 {
436 item = PyTuple_GET_ITEM(tuple, i);
437 if (PyInt_Check(item))
438 values[i] = int(PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, i)));
439 else if (PyFloat_Check(item))
440 values[i] = int(PyFloat_AS_DOUBLE(PyTuple_GET_ITEM(tuple, i)));
441 else
442 {
443 PyErr_SetString(PyExc_TypeError,
444 "Only int or float tuples are supported");
445 return NULL;
446 }
447 }
448
449 dims = len;
450 err = DBWrite(db, str, values, &len,1, DB_INT);
451 }
452 else if (PyFloat_Check(item))
453 {
454 double *values = new double[len];
455 for (int i=0; i<len; i++)
456 {
457 item = PyTuple_GET_ITEM(tuple, i);
458 if (PyInt_Check(item))
459 values[i] = double(PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, i)));
460 else if (PyFloat_Check(item))
461 values[i] = double(PyFloat_AS_DOUBLE(PyTuple_GET_ITEM(tuple, i)));
462 else
463 {
464 PyErr_SetString(PyExc_TypeError,
465 "Only int or float tuples are supported");
466 return NULL;
467 }
468 }
469
470 dims = len;
471 err = DBWrite(db, str, values, &len,1, DB_DOUBLE);
472 }
473 else
474 {
475 PyErr_SetString(PyExc_TypeError,
476 "Only int or float tuples are supported");
477 return NULL;
478 }
479 }
480 else
481 {
482 PyErr_SetString(PyExc_TypeError, "Function takes 2 arguments");
483 return NULL;
484 }
485
486 if (err != 0)
487 {
488 PyErr_SetString(PyExc_TypeError, "DBWrite failed");
489 return NULL;
490 }
491
492 PyErr_Clear();
493 Py_INCREF(Py_None);
494 return Py_None;
495 }
496
497 // ****************************************************************************
498 // Method: DBfile_DBWriteObject
499 //
500 // Purpose: Generalized method for writing silo objects.
501 //
502 // Python Arguments:
503 // form 1: object name, python dictionary (with problem sized arrays as
504 // members)
505 // ****************************************************************************
DBfile_DBWriteObject(PyObject * self,PyObject * args)506 static PyObject *DBfile_DBWriteObject(PyObject *self, PyObject *args)
507 {
508 DBfile *db = ((DBfileObject*)self)->db;
509
510 if (!db)
511 {
512 SiloErrorFunc(self, "This file has been closed.");
513 return NULL;
514 }
515
516 char *objname;
517 PyDictObject *dictobj;
518 if (!PyArg_ParseTuple(args, "sO!", &objname, &PyDict_Type, &dictobj)) return NULL;
519
520 int ncomps = PyDict_Size((PyObject*)dictobj);
521 if (!ncomps) return NULL;
522 int objtype = DBGetObjtypeTag(PyString_AsString(PyDict_GetItemString((PyObject*)dictobj, "type")));
523 DBobject *siloobj = DBMakeObject(objname, objtype, ncomps);
524 printf("writing objname = \"%s\"\n", objname);
525 PyObject *key, *value;
526 #if PY_VERSION_GE(2,5,0)
527 Py_ssize_t pos = 0;
528 #else
529 int pos = 0;
530 #endif
531 while (PyDict_Next((PyObject*)dictobj, &pos, &key, &value))
532 {
533 if (PyInt_Check(value))
534 DBAddIntComponent(siloobj, PyString_AsString(key), PyInt_AS_LONG(value));
535 else if (PyFloat_Check(value))
536 DBAddDblComponent(siloobj, PyString_AsString(key), PyFloat_AS_DOUBLE(value));
537 else if (PyString_Check(value))
538 DBAddStrComponent(siloobj, PyString_AsString(key), PyString_AsString(value));
539 else if (PyTuple_Check(value))
540 {
541 long len = PyTuple_Size(value);
542 bool allint = true;
543 for (int i = 0; i < len && allint; i++)
544 {
545 if (PyFloat_Check(PyTuple_GET_ITEM(value,i)))
546 allint = false;
547 }
548 if (allint)
549 {
550 int *vals = new int[len];
551 for (int i = 0; i < len; i++)
552 {
553 if (PyFloat_Check(PyTuple_GET_ITEM(value,i)))
554 {
555 double dval = PyFloat_AS_DOUBLE(PyTuple_GET_ITEM(value,i));
556 vals[i] = (int) dval;
557 }
558 else
559 {
560 vals[i] = PyInt_AS_LONG(PyTuple_GET_ITEM(value,i));
561 }
562 }
563 DBWriteComponent(db, siloobj, PyString_AsString(key), objname, "integer", vals, 1, &len);
564 delete [] vals;
565 }
566 else
567 {
568 double *vals = new double[len];
569 for (int i = 0; i < len; i++)
570 {
571 if (PyInt_Check(PyTuple_GET_ITEM(value,i)))
572 vals[i] = (double) PyInt_AS_LONG(PyTuple_GET_ITEM(value,i));
573 else
574 vals[i] = PyFloat_AS_DOUBLE(PyTuple_GET_ITEM(value,i));
575 }
576 DBWriteComponent(db, siloobj, PyString_AsString(key), objname, "double", vals, 1, &len);
577 delete [] vals;
578 }
579 }
580 }
581 DBWriteObject(db, siloobj, 1);
582
583 PyErr_Clear();
584 Py_INCREF(Py_None);
585 return Py_None;
586
587 }
588
589 // ****************************************************************************
590 // Method: DBfile_DBMkDir
591 //
592 // Purpose:
593 // Encapsulates DBMkDir
594 //
595 // Python Arguments:
596 // form 1: dirname
597 //
598 // Programmer: Jeremy Meredith
599 // Creation: July 12, 2005
600 //
601 // ****************************************************************************
DBfile_DBMkDir(PyObject * self,PyObject * args)602 static PyObject *DBfile_DBMkDir(PyObject *self, PyObject *args)
603 {
604 DBfile *db = ((DBfileObject*)self)->db;
605
606 if (!db)
607 {
608 SiloErrorFunc(self, "This file has been closed.");
609 return NULL;
610 }
611
612 char *str;
613 if(!PyArg_ParseTuple(args, "s", &str))
614 return NULL;
615
616 if (DBMkDir(db, str))
617 {
618 SiloErrorFunc(self, "Could not make the directory.");
619 return NULL;
620 }
621 else
622 {
623 Py_INCREF(Py_None);
624 return Py_None;
625 }
626 }
627
628 // ****************************************************************************
629 // Method: DBfile_DBSetDir
630 //
631 // Purpose:
632 // Encapsulates DBSetDir
633 //
634 // Python Arguments:
635 // form 1: dirname
636 //
637 // Programmer: Jeremy Meredith
638 // Creation: July 12, 2005
639 //
640 // ****************************************************************************
DBfile_DBSetDir(PyObject * self,PyObject * args)641 static PyObject *DBfile_DBSetDir(PyObject *self, PyObject *args)
642 {
643 DBfile *db = ((DBfileObject*)self)->db;
644
645 if (!db)
646 {
647 SiloErrorFunc(self, "This file has been closed.");
648 return NULL;
649 }
650
651 char *str;
652 if(!PyArg_ParseTuple(args, "s", &str))
653 return NULL;
654
655 if (DBSetDir(db, str))
656 {
657 SiloErrorFunc(self, "Could not change directories.");
658 return NULL;
659 }
660 else
661 {
662 Py_INCREF(Py_None);
663 return Py_None;
664 }
665 }
666
667 // ****************************************************************************
668 // Method: DBfile_DBClose
669 //
670 // Purpose:
671 // Encapsulates DBClose
672 //
673 // Python Arguments:
674 // none
675 //
676 // Programmer: Jeremy Meredith
677 // Creation: July 12, 2005
678 //
679 // ****************************************************************************
DBfile_DBClose(PyObject * self,PyObject * args)680 static PyObject *DBfile_DBClose(PyObject *self, PyObject *args)
681 {
682 DBfile *db = ((DBfileObject*)self)->db;
683
684 if (!db)
685 {
686 SiloErrorFunc(self, "This file has been closed.");
687 return NULL;
688 }
689
690 if(!PyArg_ParseTuple(args, ""))
691 return NULL;
692
693 if (DBClose(db))
694 {
695 SiloErrorFunc(self, "Could not close the file.");
696 return NULL;
697 }
698 else
699 {
700 ((DBfileObject*)self)->db = NULL;
701 Py_INCREF(Py_None);
702 return Py_None;
703 }
704 }
705
706 // ****************************************************************************
707 // DBfile method definitions
708 //
709 // Programmer: Jeremy Meredith
710 // Creation: July 12, 2005
711 //
712 // ****************************************************************************
713 static struct PyMethodDef DBfile_methods[] = {
714 {"GetToc", DBfile_DBGetToc, METH_VARARGS},
715 {"GetVar", DBfile_DBGetVar, METH_VARARGS},
716 {"GetVarInfo", DBfile_DBGetVarInfo, METH_VARARGS},
717 {"Write", DBfile_DBWrite, METH_VARARGS},
718 {"WriteObject", DBfile_DBWriteObject, METH_VARARGS},
719 {"MkDir", DBfile_DBMkDir, METH_VARARGS},
720 {"SetDir", DBfile_DBSetDir, METH_VARARGS},
721 {"Close", DBfile_DBClose, METH_VARARGS},
722 {NULL, NULL}
723 };
724
725 // ****************************************************************************
726 // Method: DBfile_dealloc
727 //
728 // Purpose:
729 // Deallocate the object.
730 //
731 // Arguments:
732 // none
733 //
734 // Programmer: Jeremy Meredith
735 // Creation: July 12, 2005
736 //
737 // ****************************************************************************
DBfile_dealloc(PyObject * self)738 static void DBfile_dealloc(PyObject *self)
739 {
740 PyObject_Del(self);
741 }
742
743 // ****************************************************************************
744 // Method: DBfile_as_string
745 //
746 // Purpose:
747 // Convert the DBfileObject to a string representation.
748 //
749 // Arguments:
750 // s the target string, with space already allocated
751 //
752 // Programmer: Jeremy Meredith
753 // Creation: July 12, 2005
754 //
755 // ****************************************************************************
DBfile_as_string(PyObject * self,char * s)756 static void DBfile_as_string(PyObject *self, char *s)
757 {
758 DBfileObject *obj = (DBfileObject*)self;
759 if (obj->db)
760 sprintf(s, "<DBfile object, filename='%s'>", obj->db->pub.name);
761 else
762 sprintf(s, "<closed DBfile object>");
763 }
764
765 // ****************************************************************************
766 // Method: DBfile_str
767 //
768 // Purpose:
769 // Convert the DBfileObject to a PyString
770 //
771 // Arguments:
772 // none
773 //
774 // Programmer: Jeremy Meredith
775 // Creation: July 12, 2005
776 //
777 // ****************************************************************************
DBfile_str(PyObject * self)778 static PyObject *DBfile_str(PyObject *self)
779 {
780 char str[1000];
781 DBfile_as_string(self, str);
782 return PyString_FromString(str);
783 }
784
785 // ****************************************************************************
786 // Method: DBfile_print
787 //
788 // Purpose:
789 // Print the DBfileObject into a file as text
790 //
791 // Arguments:
792 // fp the file pointer
793 // flags (unused)
794 //
795 // Programmer: Jeremy Meredith
796 // Creation: July 12, 2005
797 //
798 // ****************************************************************************
DBfile_print(PyObject * self,FILE * fp,int flags)799 static int DBfile_print(PyObject *self, FILE *fp, int flags)
800 {
801 char str[1000];
802 DBfile_as_string(self, str);
803 fprintf(fp, str);
804 return 0;
805 }
806
807 // ****************************************************************************
808 // Method: DBfile_getattr
809 //
810 // Purpose:
811 // Return an attribute by name. There is only one attribute of a
812 // DBfile, which is its filename.
813 //
814 // Arguments:
815 // name the name of the attribute to return
816 //
817 // Programmer: Jeremy Meredith
818 // Creation: July 12, 2005
819 //
820 // ****************************************************************************
821
822 #if PY_MAJOR_VERSION < 3
DBfile_getattr(PyObject * self,char * name)823 static PyObject *DBfile_getattr(PyObject *self, char *name)
824 {
825 DBfileObject *obj = (DBfileObject*)self;
826
827 if (!obj->db)
828 {
829 SiloErrorFunc(self, "This file has been closed.");
830 return NULL;
831 }
832
833 if (!strcmp(name, "filename"))
834 {
835 if (obj->db)
836 {
837 return PyString_FromString(obj->db->pub.name);
838 }
839 else
840 {
841 return PyString_FromString("<closed file>");
842 }
843 }
844
845 return Py_FindMethod(DBfile_methods, self, name);
846 }
847 #endif
848
849 // ****************************************************************************
850 // Method: DBfile_compare
851 //
852 // Purpose:
853 // Compare two DBfileObjects.
854 //
855 // Arguments:
856 // u, v the objects to compare
857 //
858 // Programmer: Jeremy Meredith
859 // Creation: July 12, 2005
860 //
861 // ****************************************************************************
DBfile_compare(PyObject * v,PyObject * w)862 static int DBfile_compare(PyObject *v, PyObject *w)
863 {
864 DBfile *a = ((DBfileObject *)v)->db;
865 DBfile *b = ((DBfileObject *)w)->db;
866 return (a<b) ? -1 : ((a==b) ? 0 : +1);
867 }
868
869 // TODO Check this
DBfile_richcompare(PyObject * v,PyObject * w,int op)870 static PyObject* DBfile_richcompare(PyObject *v, PyObject *w, int op)
871 {
872 switch(op){
873 case Py_EQ:{
874 if(v == w) Py_RETURN_TRUE;
875 Py_RETURN_FALSE;
876 }
877 default: Py_RETURN_NOTIMPLEMENTED;
878 }
879 }
880
881 // ****************************************************************************
882 // DBfile Python Type Object
883 //
884 // Programmer: Jeremy Meredith
885 // Creation: July 12, 2005
886 //
887 // ****************************************************************************
888 PyTypeObject DBfileType =
889 {
890 //
891 // Type header
892 //
893 PyObject_HEAD_INIT(&PyType_Type)
894 #if PY_MAJOR_VERSION < 3
895 ob_size : 0,
896 #endif
897 tp_name : "DBfil",
898 tp_basicsize : sizeof(DBfileObject),
899 tp_itemsize : 0,
900 //
901 // Standard methods
902 //
903 tp_dealloc : (destructor)DBfile_dealloc,
904 #if (PY_MAJOR_VERSION <= 3) && (PY_MINOR_VERSION <= 7)
905 tp_print : (printfunc)DBfile_print,
906 #else
907 tp_vectorcall_offset : (printfunc)DBfile_print,
908 #endif
909 #if PY_MAJOR_VERSION >= 3
910 tp_getattr : 0,
911 #else
912 tp_getattr : (getattrfunc)DBfile_getattr,
913 #endif
914 tp_setattr : 0, // object is read-only
915 #if PY_MAJOR_VERSION >= 3
916 tp_as_async : (PyAsyncMethods*) NULL,
917 #else
918 tp_compare : (cmpfunc)DBfile_compare,
919 #endif
920 tp_repr : (reprfunc)0,
921 //
922 // Type categories
923 //
924 tp_as_number : 0,
925 tp_as_sequence : 0,
926 tp_as_mapping : 0,
927 //
928 // More methods
929 //
930 tp_hash : 0,
931 tp_call : 0,
932 tp_str : (reprfunc)DBfile_str,
933 tp_getattro : 0,
934 tp_setattro : 0,
935 tp_as_buffer : 0,
936 #if PY_MAJOR_VERSION >= 3
937 tp_flags : Py_TPFLAGS_DEFAULT,
938 #else
939 tp_flags : Py_TPFLAGS_CHECKTYPES,
940 #endif
941 tp_doc : "This class wraps a Silo DBfile object.",
942 tp_traverse : 0,
943 tp_clear : 0,
944 tp_richcompare : (richcmpfunc)DBfile_richcompare,
945 tp_weaklistoffset : 0,
946 };
947
948 // ****************************************************************************
949 // Method: DBfile_NEW
950 //
951 // Purpose:
952 // Allocate and initialize a DBfileObject.
953 //
954 // Arguments:
955 // init the initial value
956 //
957 // Programmer: Jeremy Meredith
958 // Creation: July 12, 2005
959 //
960 // ****************************************************************************
DBfile_NEW(DBfile * init)961 PyObject *DBfile_NEW(DBfile *init)
962 {
963 DBfileObject *obj = PyObject_NEW(DBfileObject, &DBfileType);
964 if (obj)
965 {
966 obj->db = init;
967 }
968 return (PyObject*)obj;
969 }
970
971 // ****************************************************************************
972 // Method: DBfile_NEW
973 //
974 // Purpose:
975 // Allocate and initialize a DBfileObject with default values.
976 //
977 // Python Arguments:
978 // none
979 //
980 // Programmer: Jeremy Meredith
981 // Creation: July 12, 2005
982 //
983 // ****************************************************************************
DBfile_new(PyObject * self,PyObject * args)984 PyObject *DBfile_new(PyObject *self, PyObject *args)
985 {
986 return DBfile_NEW(NULL);
987 }
988
989