GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-order-xml-v2.c
1 /********************************************************************\
2  * gnc-order-xml-v2.c -- order xml i/o implementation *
3  * *
4  * Copyright (C) 2002 Derek Atkins <[email protected]> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA [email protected] *
22  * *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <glib.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "gnc-xml-helper.h"
32 
33 #include "sixtp.h"
34 #include "sixtp-utils.h"
35 #include "sixtp-parsers.h"
36 #include "sixtp-utils.h"
37 #include "sixtp-dom-parsers.h"
38 #include "sixtp-dom-generators.h"
39 
40 #include "gnc-xml.h"
41 #include "io-gncxml-gen.h"
42 #include "io-gncxml-v2.h"
43 
44 #include "gncOrderP.h"
45 
46 #include "gnc-order-xml-v2.h"
47 #include "gnc-owner-xml-v2.h"
48 
49 #define _GNC_MOD_NAME GNC_ID_ORDER
50 
51 static QofLogModule log_module = GNC_MOD_IO;
52 
53 const gchar *order_version_string = "2.0.0";
54 
55 /* ids */
56 #define gnc_order_string "gnc:GncOrder"
57 #define order_guid_string "order:guid"
58 #define order_id_string "order:id"
59 #define order_owner_string "order:owner"
60 #define order_opened_string "order:opened"
61 #define order_closed_string "order:closed"
62 #define order_notes_string "order:notes"
63 #define order_reference_string "order:reference"
64 #define order_active_string "order:active"
65 #define order_slots_string "order:slots"
66 
67 /* EFFECTIVE FRIEND FUNCTION */
68 extern KvpFrame *qof_instance_get_slots (const QofInstance*);
69 
70 static void
71 maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
72 {
73  if (str && strlen(str) > 0)
74  xmlAddChild (ptr, text_to_dom_tree (tag, str));
75 }
76 
77 static xmlNodePtr
78 order_dom_tree_create (GncOrder *order)
79 {
80  xmlNodePtr ret;
81  Timespec ts;
82  KvpFrame *kf;
83 
84  ret = xmlNewNode(NULL, BAD_CAST gnc_order_string);
85  xmlSetProp(ret, BAD_CAST "version", BAD_CAST order_version_string);
86 
87  xmlAddChild(ret, guid_to_dom_tree(order_guid_string,
88  qof_instance_get_guid(QOF_INSTANCE (order))));
89 
90  xmlAddChild(ret, text_to_dom_tree(order_id_string,
91  gncOrderGetID (order)));
92 
93  xmlAddChild(ret, gnc_owner_to_dom_tree (order_owner_string,
94  gncOrderGetOwner (order)));
95 
96  ts = gncOrderGetDateOpened (order);
97  xmlAddChild(ret, timespec_to_dom_tree (order_opened_string, &ts));
98 
99  ts = gncOrderGetDateClosed (order);
100  if (ts.tv_sec || ts.tv_nsec)
101  xmlAddChild(ret, timespec_to_dom_tree (order_closed_string, &ts));
102 
103  maybe_add_string (ret, order_notes_string, gncOrderGetNotes (order));
104  maybe_add_string (ret, order_reference_string, gncOrderGetReference (order));
105 
106  xmlAddChild(ret, int_to_dom_tree(order_active_string,
107  gncOrderGetActive (order)));
108 
109  kf = qof_instance_get_slots (QOF_INSTANCE(order));
110  if (kf)
111  {
112  xmlNodePtr kvpnode = kvp_frame_to_dom_tree(order_slots_string, kf);
113  if (kvpnode)
114  {
115  xmlAddChild(ret, kvpnode);
116  }
117  }
118 
119  return ret;
120 }
121 
122 /***********************************************************************/
123 
125 {
126  GncOrder *order;
127  QofBook *book;
128 };
129 
130 static inline gboolean
131 set_string(xmlNodePtr node, GncOrder* order,
132  void (*func)(GncOrder *order, const char *txt))
133 {
134  char* txt = dom_tree_to_text(node);
135  g_return_val_if_fail(txt, FALSE);
136 
137  func(order, txt);
138 
139  g_free(txt);
140  return TRUE;
141 }
142 
143 static inline gboolean
144 set_timespec(xmlNodePtr node, GncOrder* order,
145  void (*func)(GncOrder *order, Timespec ts))
146 {
147  Timespec ts = dom_tree_to_timespec(node);
148  if (!dom_tree_valid_timespec(&ts, node->name)) return FALSE;
149 
150  func(order, ts);
151  return TRUE;
152 }
153 
154 static gboolean
155 order_guid_handler (xmlNodePtr node, gpointer order_pdata)
156 {
157  struct order_pdata *pdata = order_pdata;
158  GncGUID *guid;
159  GncOrder *order;
160 
161  guid = dom_tree_to_guid(node);
162  g_return_val_if_fail (guid, FALSE);
163  order = gncOrderLookup (pdata->book, guid);
164  if (order)
165  {
166  gncOrderDestroy (pdata->order);
167  pdata->order = order;
168  gncOrderBeginEdit (order);
169  }
170  else
171  {
172  gncOrderSetGUID(pdata->order, guid);
173  }
174 
175  g_free(guid);
176 
177  return TRUE;
178 }
179 
180 static gboolean
181 order_id_handler (xmlNodePtr node, gpointer order_pdata)
182 {
183  struct order_pdata *pdata = order_pdata;
184 
185  return set_string(node, pdata->order, gncOrderSetID);
186 }
187 
188 static gboolean
189 order_owner_handler (xmlNodePtr node, gpointer order_pdata)
190 {
191  struct order_pdata *pdata = order_pdata;
192  GncOwner owner;
193  gboolean ret;
194 
195  ret = gnc_dom_tree_to_owner (node, &owner, pdata->book);
196  if (ret)
197  gncOrderSetOwner (pdata->order, &owner);
198 
199  return ret;
200 }
201 
202 static gboolean
203 order_opened_handler (xmlNodePtr node, gpointer order_pdata)
204 {
205  struct order_pdata *pdata = order_pdata;
206 
207  return set_timespec (node, pdata->order, gncOrderSetDateOpened);
208 }
209 
210 static gboolean
211 order_closed_handler (xmlNodePtr node, gpointer order_pdata)
212 {
213  struct order_pdata *pdata = order_pdata;
214 
215  return set_timespec (node, pdata->order, gncOrderSetDateClosed);
216 }
217 
218 static gboolean
219 order_notes_handler (xmlNodePtr node, gpointer order_pdata)
220 {
221  struct order_pdata *pdata = order_pdata;
222 
223  return set_string(node, pdata->order, gncOrderSetNotes);
224 }
225 
226 static gboolean
227 order_reference_handler (xmlNodePtr node, gpointer order_pdata)
228 {
229  struct order_pdata *pdata = order_pdata;
230 
231  return set_string(node, pdata->order, gncOrderSetReference);
232 }
233 
234 static gboolean
235 order_active_handler (xmlNodePtr node, gpointer order_pdata)
236 {
237  struct order_pdata *pdata = order_pdata;
238  gint64 val;
239  gboolean ret;
240 
241  ret = dom_tree_to_integer(node, &val);
242  if (ret)
243  gncOrderSetActive(pdata->order, (gboolean)val);
244 
245  return ret;
246 }
247 
248 static gboolean
249 order_slots_handler (xmlNodePtr node, gpointer order_pdata)
250 {
251  struct order_pdata *pdata = order_pdata;
252 
253  return dom_tree_to_kvp_frame_given
254  (node, qof_instance_get_slots (QOF_INSTANCE (pdata->order)));
255 }
256 
257 static struct dom_tree_handler order_handlers_v2[] =
258 {
259  { order_guid_string, order_guid_handler, 1, 0 },
260  { order_id_string, order_id_handler, 1, 0 },
261  { order_owner_string, order_owner_handler, 1, 0 },
262  { order_opened_string, order_opened_handler, 1, 0 },
263  { order_closed_string, order_closed_handler, 0, 0 },
264  { order_notes_string, order_notes_handler, 0, 0 },
265  { order_reference_string, order_reference_handler, 0, 0 },
266  { order_active_string, order_active_handler, 1, 0 },
267  { order_slots_string, order_slots_handler, 0, 0 },
268  { NULL, 0, 0, 0 }
269 };
270 
271 static GncOrder*
272 dom_tree_to_order (xmlNodePtr node, QofBook *book)
273 {
274  struct order_pdata order_pdata;
275  gboolean successful;
276 
277  order_pdata.order = gncOrderCreate(book);
278  order_pdata.book = book;
279  gncOrderBeginEdit (order_pdata.order);
280 
281  successful = dom_tree_generic_parse (node, order_handlers_v2,
282  &order_pdata);
283 
284  if (successful)
285  gncOrderCommitEdit (order_pdata.order);
286  else
287  {
288  PERR ("failed to parse order tree");
289  gncOrderDestroy (order_pdata.order);
290  order_pdata.order = NULL;
291  }
292 
293  return order_pdata.order;
294 }
295 
296 static gboolean
297 gnc_order_end_handler(gpointer data_for_children,
298  GSList* data_from_children, GSList* sibling_data,
299  gpointer parent_data, gpointer global_data,
300  gpointer *result, const gchar *tag)
301 {
302  GncOrder *order;
303  xmlNodePtr tree = (xmlNodePtr)data_for_children;
304  gxpf_data *gdata = (gxpf_data*)global_data;
305  QofBook *book = gdata->bookdata;
306 
307  if (parent_data)
308  {
309  return TRUE;
310  }
311 
312  /* OK. For some messed up reason this is getting called again with a
313  NULL tag. So we ignore those cases */
314  if (!tag)
315  {
316  return TRUE;
317  }
318 
319  g_return_val_if_fail(tree, FALSE);
320 
321  order = dom_tree_to_order(tree, book);
322  if (order != NULL)
323  {
324  gdata->cb(tag, gdata->parsedata, order);
325  }
326 
327  xmlFreeNode(tree);
328 
329  return order != NULL;
330 }
331 
332 static sixtp *
333 order_sixtp_parser_create(void)
334 {
335  return sixtp_dom_parser_new(gnc_order_end_handler, NULL, NULL);
336 }
337 
338 static gboolean
339 order_should_be_saved (GncOrder *order)
340 {
341  const char *id;
342 
343  /* make sure this is a valid order before we save it -- should have an ID */
344  id = gncOrderGetID (order);
345  if (id == NULL || *id == '\0')
346  return FALSE;
347 
348  return TRUE;
349 }
350 
351 static void
352 do_count (QofInstance * order_p, gpointer count_p)
353 {
354  int *count = count_p;
355  if (order_should_be_saved ((GncOrder *) order_p))
356  (*count)++;
357 }
358 
359 static int
360 order_get_count (QofBook *book)
361 {
362  int count = 0;
363  qof_object_foreach (_GNC_MOD_NAME, book, do_count, (gpointer) &count);
364  return count;
365 }
366 
367 static void
368 xml_add_order (QofInstance * order_p, gpointer out_p)
369 {
370  xmlNodePtr node;
371  GncOrder *order = (GncOrder *) order_p;
372  FILE *out = out_p;
373 
374  if (ferror(out))
375  return;
376  if (!order_should_be_saved (order))
377  return;
378 
379  node = order_dom_tree_create (order);
380  xmlElemDump(out, NULL, node);
381  xmlFreeNode (node);
382  if (ferror(out) || fprintf(out, "\n") < 0)
383  return;
384 }
385 
386 static gboolean
387 order_write (FILE *out, QofBook *book)
388 {
389  qof_object_foreach_sorted (_GNC_MOD_NAME, book, xml_add_order, (gpointer) out);
390  return ferror(out) == 0;
391 }
392 
393 static gboolean
394 order_ns(FILE *out)
395 {
396  g_return_val_if_fail(out, FALSE);
397  return gnc_xml2_write_namespace_decl(out, "order");
398 }
399 
400 void
401 gnc_order_xml_initialize (void)
402 {
403  static GncXmlDataType_t be_data =
404  {
405  GNC_FILE_BACKEND_VERS,
406  gnc_order_string,
407  order_sixtp_parser_create,
408  NULL, /* add_item */
409  order_get_count,
410  order_write,
411  NULL, /* scrub */
412  order_ns,
413  };
414 
415  qof_object_register_backend (_GNC_MOD_NAME,
417  &be_data);
418 }
gboolean qof_object_register_backend(QofIdTypeConst type_name, const char *backend_name, gpointer be_data)
Definition: sixtp.h:93
const GncGUID * qof_instance_get_guid(gconstpointer)
#define GNC_FILE_BACKEND
Definition: io-gncxml-v2.h:99
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
#define PERR(format, args...)
Definition: qoflog.h:237
Definition: guid.h:65
void qof_object_foreach_sorted(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
api for GnuCash version 2 XML-based file format
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
gboolean gnc_xml2_write_namespace_decl(FILE *out, const char *name_space)
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
const gchar * QofLogModule
Definition: qofid.h:89