From 4c78192cf17bde2f3c6bff7bb90757c21d1e3792 Mon Sep 17 00:00:00 2001 From: Peter Verthez Date: Wed, 4 Dec 2002 18:45:12 +0000 Subject: [PATCH] Beginnings of write support. --- gedcom/Makefile.am | 8 +- gedcom/encoding.c | 15 +-- gedcom/encoding.h | 10 +- gedcom/tag_data.h | 138 ++++++++++++++++++++++ gedcom/write.c | 280 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 434 insertions(+), 17 deletions(-) create mode 100644 gedcom/tag_data.h create mode 100644 gedcom/write.c diff --git a/gedcom/Makefile.am b/gedcom/Makefile.am index 661c7f6..f219f9a 100644 --- a/gedcom/Makefile.am +++ b/gedcom/Makefile.am @@ -28,8 +28,9 @@ libgedcom_la_SOURCES = lex.gedcom_1byte_.c \ xref.c \ age.c \ compat.c \ - buffer.c -libgedcom_la_LDFLAGS = -export-dynamic -version-info $(LIBVERSION) $(LIBICONV) + buffer.c \ + write.c +libgedcom_la_LDFLAGS = -export-dynamic -version-info $(LIBVERSION) libgedcom_la_LIBADD = calendar/libcalendar.la ../utf8/libutf8.la @INTLLIBS@ BUILT_SOURCES = lex.gedcom_1byte_.c \ lex.gedcom_hilo_.c \ @@ -50,7 +51,8 @@ noinst_HEADERS = encoding.h \ xref.h \ age.h \ compat.h \ - buffer.h + buffer.h \ + tag_data.h EXTRA_DIST = gedcom.y \ gedcom_date.y \ gedcom_1byte.lex \ diff --git a/gedcom/encoding.c b/gedcom/encoding.c index 469854b..e0140b2 100644 --- a/gedcom/encoding.c +++ b/gedcom/encoding.c @@ -22,7 +22,6 @@ /* $Name$ */ #include -#include #include #include #include @@ -36,10 +35,7 @@ #define GCONV_SEARCH_PATH "GCONV_PATH" #define MAXBUF 255 -/* -static iconv_t cd_to_internal = (iconv_t) -1; -*/ -static ENCODING the_enc = ONE_BYTE; +static Encoding the_enc = ONE_BYTE; static hash_t *encodings = NULL; const char* charwidth_string[] = { "1", "2_HILO", "2_LOHI" }; @@ -83,10 +79,12 @@ void add_encoding(const char *gedcom_n, const char* charwidth, MEMORY_ERROR; } -char* get_encoding(const char* gedcom_n, ENCODING enc) +char* get_encoding(const char* gedcom_n, Encoding enc) { char *key; hnode_t *node; + + if (encodings == NULL) return NULL; key = (char*)malloc(strlen(gedcom_n) + strlen(charwidth_string[enc]) + 3); @@ -222,6 +220,7 @@ void init_encodings() if (buffer[strlen(buffer) - 1] != '\n') { gedcom_error(_("Line too long in encoding configuration file '%s'"), ENCODING_CONF_FILE); + line_no = 0; return; } else if ((buffer[0] != '#') && (strcmp(buffer, "\n") != 0)) { @@ -231,10 +230,12 @@ void init_encodings() else { gedcom_error(_("Missing data in encoding configuration file '%s'"), ENCODING_CONF_FILE); + line_no = 0; return; } } } + line_no = 0; if (fclose(in) != 0) { gedcom_warning(_("Error closing file '%s': %s"), ENCODING_CONF_FILE, strerror(errno)); @@ -243,7 +244,7 @@ void init_encodings() } } -void set_encoding_width(ENCODING enc) +void set_encoding_width(Encoding enc) { the_enc = enc; } diff --git a/gedcom/encoding.h b/gedcom/encoding.h index e80616f..a44ed0b 100644 --- a/gedcom/encoding.h +++ b/gedcom/encoding.h @@ -25,19 +25,15 @@ #ifndef __ENCODING_H #define __ENCODING_H +#include "gedcom.h" #include "utf8.h" -typedef enum _ENC { - ONE_BYTE = 0, - TWO_BYTE_HILO = 1, - TWO_BYTE_LOHI = 2 -} ENCODING; - int open_conv_to_internal(const char* fromcode); void close_conv_to_internal(); char* to_internal(const char* str, size_t len, struct conv_buffer *output_buf); void init_encodings(); -void set_encoding_width(ENCODING enc); +char* get_encoding(const char* gedcom_n, Encoding enc); +void set_encoding_width(Encoding enc); void update_gconv_search_path(); #endif /* __ENCODING_H */ diff --git a/gedcom/tag_data.h b/gedcom/tag_data.h new file mode 100644 index 0000000..052a226 --- /dev/null +++ b/gedcom/tag_data.h @@ -0,0 +1,138 @@ +/* Tag data header + Copyright (C) 2001,2002 The Genes Development Team + This file is part of the Gedcom parser library. + Contributed by Peter Verthez , 2001. + + The Gedcom parser library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The Gedcom parser library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Gedcom parser library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* $Id$ */ +/* $Name$ */ + +#include "gedcom.h" + +typedef enum _OPT { + OPT_CONC = 0x01, + OPT_CONT = 0x02 +} Opt; + +struct tag_data { + char *elt_name; + char *tag_name; + int allowed_types; + Opt options; +}; + +struct tag_data tag_data[NR_OF_ELTS] = +{ + /* REC_HEAD */ + { "REC_HEAD", "HEAD", GV_NULL, 0 }, + + /* REC_FAM */ + { "REC_FAM", "FAM", GV_NULL, 0 }, + + /* REC_INDI */ + { "REC_INDI", "INDI", GV_NULL, 0 }, + + /* REC_OBJE */ + { "REC_OBJE", "OBJE", GV_NULL, 0 }, + + /* REC_NOTE */ + { "REC_NOTE", "NOTE", GV_CHAR_PTR, 0 }, + + /* REC_REPO */ + { "REC_REPO", "REPO", GV_NULL, 0 }, + + /* REC_SOUR */ + { "REC_SOUR", "SOUR", GV_NULL, 0 }, + + /* REC_SUBN */ + { "REC_SUBN", "SUBN", GV_NULL, 0 }, + + /* REC_SUBM */ + { "REC_SUBM", "SUBM", GV_NULL, 0 }, + + /* REC_USER */ + { "REC_USER", NULL, GV_NULL | GV_CHAR_PTR | GV_XREF_PTR, 0 }, + + /* ELT_HEAD_SOUR */ + { "ELT_HEAD_SOUR", "SOUR", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SOUR_VERS */ + { "ELT_HEAD_SOUR_VERS", "VERS", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SOUR_NAME */ + { "ELT_HEAD_SOUR_NAME", "NAME", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SOUR_CORP */ + { "ELT_HEAD_SOUR_CORP", "CORP", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SOUR_DATA */ + { "ELT_HEAD_SOUR_DATA", "DATA", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SOUR_DATA_DATE */ + { "ELT_HEAD_SOUR_DATA_DATE", "DATE", GV_DATE_VALUE, 0 }, + + /* ELT_HEAD_SOUR_DATA_COPR */ + { "ELT_HEAD_SOUR_DATA_COPR", "COPR", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_DEST */ + { "ELT_HEAD_DEST", "DEST", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_DATE */ + { "ELT_HEAD_DATE", "DATE", GV_DATE_VALUE, 0 }, + + /* ELT_HEAD_DATE_TIME */ + { "ELT_HEAD_DATE_TIME", "TIME", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_SUBM */ + { "ELT_HEAD_SUBM", "SUBM", GV_XREF_PTR, 0 }, + + /* ELT_HEAD_SUBN */ + { "ELT_HEAD_SUBN", "SUBN", GV_XREF_PTR, 0 }, + + /* ELT_HEAD_FILE */ + { "ELT_HEAD_FILE", "FILE", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_COPR */ + { "ELT_HEAD_COPR", "COPR", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_GEDC */ + { "ELT_HEAD_GEDC", "GEDC", GV_NULL, 0 }, + + /* ELT_HEAD_GEDC_VERS */ + { "ELT_HEAD_GEDC_VERS", "VERS", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_GEDC_FORM */ + { "ELT_HEAD_GEDC_FORM", "FORM", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_CHAR */ + { "ELT_HEAD_CHAR", "CHAR", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_CHAR_VERS */ + { "ELT_HEAD_CHAR_VERS", "VERS", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_LANG */ + { "ELT_HEAD_LANG", "LANG", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_PLAC */ + { "ELT_HEAD_PLAC", "PLAC", GV_NULL, 0 }, + + /* ELT_HEAD_PLAC_FORM */ + { "ELT_HEAD_PLAC_FORM", "FORM", GV_CHAR_PTR, 0 }, + + /* ELT_HEAD_NOTE */ + { "ELT_HEAD_NOTE", "NOTE", GV_CHAR_PTR, OPT_CONC | OPT_CONT } +}; diff --git a/gedcom/write.c b/gedcom/write.c new file mode 100644 index 0000000..e74a571 --- /dev/null +++ b/gedcom/write.c @@ -0,0 +1,280 @@ +/* Write functions for Gedcom. + Copyright (C) 2001,2002 The Genes Development Team + This file is part of the Gedcom parser library. + Contributed by Peter Verthez , 2001. + + The Gedcom parser library is free software; you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The Gedcom parser library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the Gedcom parser library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* $Id$ */ +/* $Name$ */ + +#include "gedcom_internal.h" +#include "gedcom.h" +#include "encoding.h" +#include "tag_data.h" +#include "buffer.h" +#include "utf8.h" +#include +#include +#include +#include + +const char* encoding = "ASCII"; +int write_encoding_details = ONE_BYTE; +/* SYS_NEWLINE is defined in config.h */ +const char* write_terminator = SYS_NEWLINE; + +struct Gedcom_write_struct { + int filedesc; + convert_t conv; + int total_conv_fails; + const char* term; + int ctxt_stack[MAXGEDCLEVEL+1]; + int ctxt_level; +}; + +const char* default_encoding[] = { + /* ONE_BYTE */ "ASCII", + /* TWO_BYTE_HILO */ "UCS-2BE", + /* TWO_BYTE_LOHI */ "UCS-2LE" +}; + +const char* terminator[] = { + /* END_CR */ "\x0D", + /* END_LF */ "\x0A", + /* END_CR_LF */ "\x0D\x0A", + /* END_LF_CR */ "\x0A\x0D" +}; + +void cleanup_write_buffer(); + +struct safe_buffer write_buffer = { NULL, 0, cleanup_write_buffer }; + +void cleanup_write_buffer() +{ + cleanup_buffer(&write_buffer); +} + +int write_simple(Gedcom_write_hndl hndl, + int level, char* xref, char* tag, char* value) +{ + int res; + + if (hndl) { + char* converted; + int conv_fails; + size_t outlen; + + reset_buffer(&write_buffer); + res = safe_buf_append(&write_buffer, "%d", level); + if (xref) + res += safe_buf_append(&write_buffer, " %s", xref); + res += safe_buf_append(&write_buffer, " %s", tag); + if (value) + res += safe_buf_append(&write_buffer, " %s", value); + res += safe_buf_append(&write_buffer, hndl->term); + + converted = convert_from_utf8(hndl->conv, get_buf_string(&write_buffer), + &conv_fails, &outlen); + + if (converted && (conv_fails == 0)) + write(hndl->filedesc, converted, outlen); + else { + hndl->total_conv_fails += conv_fails; + gedcom_error + (_("Error converting output string: %s (%d conversion failures)"), + strerror(errno), conv_fails); + } + } + return 0; +} + +int gedcom_write_set_encoding(const char* charset, + Encoding width, Enc_bom bom) +{ + char* new_encoding = NULL; + if (!strcmp(charset, "UNICODE")) { + if (width == ONE_BYTE) { + gedcom_error(_("Unicode cannot be encoded into one byte")); + return 1; + } + else { + new_encoding = get_encoding(charset, width); + if (new_encoding) { + encoding = new_encoding; + write_encoding_details = width | bom; + } + } + } + else { + new_encoding = get_encoding(charset, ONE_BYTE); + if (new_encoding) { + encoding = new_encoding; + write_encoding_details = ONE_BYTE; + } + } + return 0; +} + +int gedcom_write_set_line_terminator(Enc_line_end end) +{ + write_terminator = terminator[end]; + return 0; +} + +Gedcom_write_hndl gedcom_write_open(const char *filename) +{ + Gedcom_write_hndl hndl; + + hndl = (Gedcom_write_hndl)malloc(sizeof(struct Gedcom_write_struct)); + + if (!hndl) + MEMORY_ERROR; + else { + hndl->total_conv_fails = 0; + hndl->conv = initialize_utf8_conversion(encoding, 0); + if (!hndl->conv) { + gedcom_error(_("Could not open encoding '%s' for writing: %s"), + encoding, strerror(errno)); + free(hndl); + hndl = NULL; + } + else { + hndl->filedesc = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (!hndl->filedesc) { + gedcom_error(_("Could not open file '%s' for writing: %s"), + filename, strerror(errno)); + cleanup_utf8_conversion(hndl->conv); + free(hndl); + hndl = NULL; + } + else { + hndl->term = write_terminator; + hndl->ctxt_level = -1; + if (write_encoding_details & WITH_BOM) { + if (write_encoding_details & TWO_BYTE_HILO) + write(hndl->filedesc, "\xFE\xFF", 2); + else if (write_encoding_details & TWO_BYTE_LOHI) + write(hndl->filedesc, "\xFF\xFE", 2); + else + gedcom_warning(_("Byte order mark configured, but no Unicode")); + } + } + } + } + + return hndl; +} + +int gedcom_write_close(Gedcom_write_hndl hndl, int* total_conv_fails) +{ + int result = 0; + if (hndl) { + write_simple(hndl, 0, NULL, "TRLR", NULL); + if (total_conv_fails) *total_conv_fails = hndl->total_conv_fails; + result = close(hndl->filedesc); + cleanup_utf8_conversion(hndl->conv); + free(hndl); + } + return result; +} + +char* get_tag_string(int elt_or_rec, char* tag) +{ + char* result = tag_data[elt_or_rec].tag_name; + + if (result) + return result; + else if (tag) + return tag; + else { + gedcom_error(_("The element or record type '%s' requires a specific tag" + "for writing"), + tag_data[elt_or_rec].elt_name); + return NULL; + } +} + +int check_type(int elt_or_rec, Gedcom_val_type type) +{ + int allowed = tag_data[elt_or_rec].allowed_types; + if (allowed & type) + return 1; + else { + gedcom_error(_("Wrong data type for writing element or record type '%s'"), + tag_data[elt_or_rec].elt_name); + return 0; + } +} + +int get_level(Gedcom_write_hndl hndl, int elt_or_rec, int parent) +{ + if (parent == -1) { + hndl->ctxt_level = 0; + } + else { + while (hndl->ctxt_level && hndl->ctxt_stack[hndl->ctxt_level] != parent) + hndl->ctxt_level--; + if (hndl->ctxt_stack[hndl->ctxt_level] == parent) { + hndl->ctxt_level++; + } + else { + gedcom_error(_("Parent %d not found during write of %d"), + parent, elt_or_rec); + return -1; + } + } + hndl->ctxt_stack[hndl->ctxt_level] = elt_or_rec; + return hndl->ctxt_level; +} + +int gedcom_write_record_str(Gedcom_write_hndl hndl, + Gedcom_rec rec, char* tag, + struct xref_value* xref, char* val) +{ + int result = 1; + int level = 0; + char* tag_str = NULL; + char* xref_str = NULL; + + tag_str = get_tag_string(rec, tag); + level = get_level(hndl, rec, -1); + if (tag_str && check_type(rec, (val ? GV_CHAR_PTR : GV_NULL))) { + if (xref) + xref_str = xref->string; + result = write_simple(hndl, level, xref_str, tag_str, val); + } + + return result; +} + +int gedcom_write_element_str(Gedcom_write_hndl hndl, + Gedcom_elt elt, char* tag, int parent_rec_or_elt, + char* val) +{ + int result = 1; + int level = -1; + char* tag_str = NULL; + + tag_str = get_tag_string(elt, tag); + level = get_level(hndl, elt, parent_rec_or_elt); + if (tag_str && (level != -1) + && check_type(elt, (val ? GV_CHAR_PTR : GV_NULL))) { + result = write_simple(hndl, level, NULL, tag_str, val); + } + + return result; +} -- 2.30.2