allow xml data to come from any source, not just files

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3397 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas
2001-01-06 05:01:46 +00:00
parent 48e964df7a
commit a2fbde40af
3 changed files with 183 additions and 67 deletions

View File

@@ -1,5 +1,8 @@
/*
* io-gncxml-r.c -- read XML-format gnucash data file
*
* Initial code by Rob l. Browning 4Q 2000
* Tuneups by James Lewis Moss Dec 2000
*/
#ifndef _GNU_SOURCE
@@ -36,9 +39,6 @@
#include "AccountP.h"
#include "TransactionP.h"
/* Hack to get going... */
#include "FileIOP.h"
#ifdef USE_GUILE_FOR_DOUBLE_CONVERSION
#include <guile/gh.h>
#endif /* USE_GUILE_FOR_DOUBLE_CONVERSION */
@@ -46,6 +46,8 @@
/* TODO
bust this file up into several. Its *way* too big to deal with.
create common funcs for repeated "types" of parsers. i.e. a common
func for handling guid, gnc_numeric, etc. parsers - just pass in
string->data and data->string funcs.
@@ -102,6 +104,8 @@
*/
static short module = MOD_IO;
typedef struct _sixtp_child_result sixtp_child_result;
typedef gboolean (*sixtp_start_handler)(GSList* sibling_data,
@@ -331,7 +335,7 @@ sixtp_sax_start_handler(void *user_data,
(gpointer) &next_parser);
if(!lookup_success) {
fprintf(stderr, "Tag <%s> not allowed in current context.\n", name);
PERR("Tag <%s> not allowed in current context.\n", name);
pdata->parsing_ok = FALSE;
return;
}
@@ -474,7 +478,7 @@ sixtp_sax_end_handler(void *user_data, const xmlChar *name) {
because this string is held by the parent parser's hash table. */
end_tag = current_frame->tag;
/*fprintf(stderr, "Finished with end of <%s>\n", end_tag);*/
PINFO("Finished with end of <%s>\n", end_tag);
/*sixtp_print_frame_stack(pdata->stack, stderr);*/
@@ -535,16 +539,15 @@ sixtp_destroy_child(gpointer key, gpointer value, gpointer user_data) {
gpointer lookup_key;
gpointer lookup_value;
/* fprintf(stderr, "Killing sixtp child under key <%s>\n", (char *) key); */
PINFO ("Killing sixtp child under key <%s>\n", (char *) key);
g_free(key);
if(!corpses) {
fprintf(stderr, "BAD: no corpses in sixtp_destroy_child <%s>\n",
(char *) key);
PERR("BAD: no corpses in sixtp_destroy_child <%s>\n", (char *) key);
return;
}
if(!child) {
fprintf(stderr, "BAD: no child in sixtp_destroy_child <%s>\n", (char *) key);
PERR("BAD: no child in sixtp_destroy_child <%s>\n", (char *) key);
return;
}
@@ -654,7 +657,7 @@ sixtp_handle_catastrophe(sixtp_sax_data *sax_data) {
GSList *lp;
GSList **stack = &(sax_data->stack);
fprintf(stderr, "sixtp: parse failed at \n");
PERR("parse failed at \n");
sixtp_print_frame_stack(sax_data->stack, stderr);
while(*stack) {
@@ -697,88 +700,141 @@ sixtp_handle_catastrophe(sixtp_sax_data *sax_data) {
}
/* ========================================================== */
static gboolean
sixtp_parse_file(sixtp *sixtp,
const char *filename,
gpointer data_for_top_level,
gpointer global_data,
gpointer *parse_result) {
xmlSAXHandler sax_handler;
sixtp_sax_data sax_data;
int sax_result;
sixtp_stack_frame *top_frame = NULL;
sixtp_setup_parser (sixtp *sixtp,
gpointer data_for_top_level,
gpointer global_data,
xmlSAXHandler *sax_handler,
sixtp_sax_data *sax_data,
sixtp_stack_frame *top_frame
)
{
memset(sax_handler, '\0', sizeof(xmlSAXHandler));
sax_handler->startElement = sixtp_sax_start_handler;
sax_handler->endElement = sixtp_sax_end_handler;
sax_handler->characters = sixtp_sax_characters_handler;
sax_handler->getEntity = sixtp_sax_get_entity_handler;
memset(&sax_handler, '\0', sizeof(sax_handler));
sax_handler.startElement = sixtp_sax_start_handler;
sax_handler.endElement = sixtp_sax_end_handler;
sax_handler.characters = sixtp_sax_characters_handler;
sax_handler.getEntity = sixtp_sax_get_entity_handler;
memset(sax_data, '\0', sizeof(sixtp_sax_data));
sax_data->parsing_ok = TRUE;
sax_data->stack = NULL;
sax_data->global_data = global_data;
memset(&sax_data, '\0', sizeof(sixtp_sax_data));
sax_data.parsing_ok = TRUE;
sax_data.stack = NULL;
sax_data.global_data = global_data;
top_frame = g_new0(sixtp_stack_frame, 1);
top_frame->parser = sixtp;
top_frame->tag = NULL;
top_frame->data_from_children = NULL;
top_frame->data_for_children = NULL;
top_frame->frame_data = NULL;
sax_data.stack = g_slist_prepend(sax_data.stack, (gpointer) top_frame);
sax_data->stack = g_slist_prepend(sax_data->stack, (gpointer) top_frame);
if(sixtp->start_handler) {
sax_data.parsing_ok =
sax_data->parsing_ok =
sixtp->start_handler(NULL,
data_for_top_level,
sax_data.global_data,
sax_data->global_data,
&top_frame->data_for_children,
&top_frame->frame_data,
NULL);
}
if(!sax_data.parsing_ok) {
sixtp_handle_catastrophe(&sax_data);
if(!sax_data->parsing_ok) {
PERR ("parsing catastrophe");
sixtp_handle_catastrophe(sax_data);
return(FALSE);
}
return (TRUE);
}
sax_result = xmlSAXUserParseFile(&sax_handler, &sax_data, filename);
/* ========================================================== */
static gboolean
sixtp_teardown_parser(sixtp *sixtp,
gpointer data_for_top_level,
gpointer global_data,
gpointer *parse_result,
sixtp_sax_data *sax_data)
{
sixtp_stack_frame *top_frame = NULL;
if(!sax_data.parsing_ok) {
sixtp_handle_catastrophe(&sax_data);
if(!sax_data->parsing_ok) {
PERR ("couldn't parse, handle catastrophe");
sixtp_handle_catastrophe(sax_data);
return(FALSE);
}
if(sixtp->end_handler) {
sax_data.parsing_ok =
sax_data->parsing_ok =
sixtp->end_handler(top_frame->data_for_children,
top_frame->data_from_children,
NULL,
data_for_top_level,
sax_data.global_data,
sax_data->global_data,
&top_frame->frame_data,
NULL);
}
if(!sax_data.parsing_ok) {
sixtp_handle_catastrophe(&sax_data);
return(FALSE);
if(!sax_data->parsing_ok) {
PERR ("couldn't call end handler, cleanup catastrophe");
sixtp_handle_catastrophe(sax_data);
return(FALSE);
}
}
/* put the result where the caller can see it */
if(top_frame->frame_data) *parse_result = top_frame->frame_data;
{
GSList *lp;
for(lp = sax_data.stack; lp; lp = lp->next)
GSList *lp = NULL;
for(lp = sax_data->stack; lp; lp = lp->next)
sixtp_stack_frame_destroy((sixtp_stack_frame *) lp->data);
}
g_slist_free(sax_data.stack);
g_slist_free(sax_data->stack);
return(TRUE);
}
/* ========================================================== */
static gboolean
sixtp_parse_file(sixtp *sixtp,
const char *filename,
gpointer data_for_top_level,
gpointer global_data,
gpointer *parse_result)
{
xmlSAXHandler sax_handler;
sixtp_sax_data sax_data;
sixtp_stack_frame *top_frame = NULL;
int rc;
/* hack alert -- XXX -- where is top_frame released?? */
/* looks like a mem leak to me ... */
top_frame = g_new0(sixtp_stack_frame, 1);
rc = sixtp_setup_parser (sixtp,
data_for_top_level,
global_data,
&sax_handler,
&sax_data,
top_frame);
if(!rc) return(FALSE);
xmlSAXUserParseFile(&sax_handler, &sax_data, filename);
rc = sixtp_teardown_parser(sixtp,
data_for_top_level,
global_data,
parse_result,
&sax_data);
return rc;
}
/* ========================================================== */
typedef enum {
GNC_PARSE_ERR_NONE,
@@ -4515,11 +4571,12 @@ gnc_parser_new() {
return(top_level);
}
/****************************************************************************/
/* ================================================================== */
gboolean
gncxml_read(const gchar *filename,
AccountGroup **result_group) {
AccountGroup **result_group)
{
/* fixme: this should be broken up into sub-functions later. */
gboolean parse_ok;

View File

@@ -1,5 +1,11 @@
/*
* io-gncxml-w.c -- write XML-format gnucash data file
*
* Initial code by Rob l. Browning 4Q 2000
* Tuneups by James Lewis Moss Dec 2000
* Generic I/O hack by Linas Vepstas January 2001
*
* Copyright (c) 2000,2001 Gnumatic Incorporated
*/
#define _GNU_SOURCE
@@ -29,14 +35,12 @@
#include "AccountP.h" /* just for kvp_data */
#include "TransactionP.h" /* just for kvp_data */
/* Hack to get going... */
#include "FileIOP.h"
#ifdef USE_GUILE_FOR_DOUBLE_CONVERSION
#include <guile/gh.h>
#endif /* USE_GUILE_FOR_DOUBLE_CONVERSION */
static short module = MOD_IO;
/* Pulled from the libxml-1.8.8 header */
#ifndef xmlChildrenNode
@@ -393,7 +397,8 @@ xml_add_binary(xmlNodePtr p,
const char *tag,
const gchar *format,
const void *data,
guint32 size) {
guint32 size)
{
xmlNodePtr value_xml;
@@ -443,7 +448,7 @@ xml_add_binary(xmlNodePtr p,
g_string_free(output, TRUE);
} else {
fprintf(stderr, "xml_add_binary: unknown output format %s.\n", format);
PERR("unknown output format %s.\n", format);
return(FALSE);
}
return(TRUE);
@@ -800,8 +805,7 @@ gncxml_append_emacs_trailer(const gchar *filename)
toappend = fopen(filename, "a+");
if(!toappend)
{
fprintf(stderr, "Unable to append emacs trailer: %s\n",
strerror(errno));
PERR("Unable to append emacs trailer: %s\n", strerror(errno));
return 0;
}
@@ -810,14 +814,15 @@ gncxml_append_emacs_trailer(const gchar *filename)
return fclose(toappend);
}
gboolean
gncxml_write(AccountGroup *group, const gchar *filename) {
/* fixme: this should be broken up into sub-functions later. */
/* =============================================================== */
/* create a new xml document and poke all account & txn data into it. */
static xmlDocPtr
gncxml_newdoc (AccountGroup *group)
{
xmlDocPtr doc;
xmlNodePtr ledger_data;
xmlNodePtr tmpnode;
int status;
doc = xmlNewDoc("1.0");
doc->xmlRootNode = xmlNewDocNode(doc, NULL, "gnc", NULL);
@@ -825,30 +830,67 @@ gncxml_write(AccountGroup *group, const gchar *filename) {
tmpnode = xmlNewTextChild(doc->xmlRootNode, NULL, "version", "1");
if(!tmpnode) {
xmlFreeDoc(doc);
return FALSE;
return 0x0;
}
ledger_data = xmlNewTextChild(doc->xmlRootNode, NULL, "ledger-data", NULL);
if(!ledger_data) {
PERR ("couldn't get ledger data");
xmlFreeDoc(doc);
return FALSE;
return 0x0;
}
if(!xml_add_commodity_restorers(ledger_data)) {
PERR ("couldn't commodity restore");
xmlFreeDoc(doc);
return FALSE;
return 0x0;
}
if(!xml_add_account_restorers(ledger_data, group)) {
PERR ("couldn't account restore");
xmlFreeDoc(doc);
return FALSE;
return 0x0;
}
if(!xml_add_txn_and_split_restorers(ledger_data, group)) {
PERR ("couldn't txn restore");
xmlFreeDoc(doc);
return FALSE;
return 0x0;
}
return doc;
}
/* =============================================================== */
void
gncxml_write_to_buf (AccountGroup *group, char **bufp, int *sz)
{
xmlDocPtr doc;
doc = gncxml_newdoc (group);
if (!doc) return;
xmlDocDumpMemory (doc, bufp, sz);
PINFO ("wrote %d bytes");
}
/* =============================================================== */
/* write the account group to a filename */
gboolean
gncxml_write(AccountGroup *group, const gchar *filename)
{
xmlDocPtr doc;
int status;
if (!group || !filename) return FALSE;
doc = gncxml_newdoc (group);
if (!doc) return FALSE;
xmlIndentTreeOutput = TRUE;
status = xmlSaveFile(filename, doc);
@@ -865,3 +907,5 @@ gncxml_write(AccountGroup *group, const gchar *filename) {
*/
return(status != -1);
}
/* ========================= END OF FILE ============================ */

View File

@@ -1,5 +1,11 @@
/*
* io-gncxml.h -- api for new XML-based file format
*
* Initial code by Rob l. Browning 4Q 2000
* Tuneups by James Lewis Moss Dec 2000
*
* Copyright (c) 2000,2001 Gnumatic Incorporated
*
*/
#ifndef __IO_GNCXML_H__
#define __IO_GNCXML_H__
@@ -8,8 +14,17 @@
#include "Group.h"
/* read in an account group from a file */
gboolean gncxml_read(const gchar *name, AccountGroup **result_group);
/* write all account info to a file */
gboolean gncxml_write(AccountGroup *group, const gchar *name);
/* The is_gncxml_file() routine checks to see if the first few
* chars of the file look like gnc-xml data.
*/
gboolean is_gncxml_file(const gchar *name);
#endif
void gncxml_write_to_buf (AccountGroup *group, char **bufp, int *sz);
#endif /* __IO_GNCXML_H__ */