1 /* Write functions for Gedcom.
2 Copyright (C) 2001,2002 The Genes Development Team
3 This file is part of the Gedcom parser library.
4 Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
6 The Gedcom parser library is free software; you can redistribute it
7 and/or modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The Gedcom parser library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the Gedcom parser library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 #include "gedcom_internal.h"
31 #include <sys/types.h>
35 const char* encoding = "ASCII";
36 int write_encoding_details = ONE_BYTE;
37 /* SYS_NEWLINE is defined in config.h */
38 const char* write_terminator = SYS_NEWLINE;
40 struct Gedcom_write_struct {
45 int ctxt_stack[MAXGEDCLEVEL+1];
49 const char* default_encoding[] = {
50 /* ONE_BYTE */ "ASCII",
51 /* TWO_BYTE_HILO */ "UCS-2BE",
52 /* TWO_BYTE_LOHI */ "UCS-2LE"
55 const char* terminator[] = {
58 /* END_CR_LF */ "\x0D\x0A",
59 /* END_LF_CR */ "\x0A\x0D"
62 void cleanup_write_buffer();
64 struct safe_buffer write_buffer = { NULL, 0, cleanup_write_buffer };
66 void cleanup_write_buffer()
68 cleanup_buffer(&write_buffer);
71 int write_simple(Gedcom_write_hndl hndl,
72 int level, char* xref, char* tag, char* value)
81 reset_buffer(&write_buffer);
82 res = safe_buf_append(&write_buffer, "%d", level);
84 res += safe_buf_append(&write_buffer, " %s", xref);
85 res += safe_buf_append(&write_buffer, " %s", tag);
87 res += safe_buf_append(&write_buffer, " %s", value);
88 res += safe_buf_append(&write_buffer, hndl->term);
90 converted = convert_from_utf8(hndl->conv, get_buf_string(&write_buffer),
91 &conv_fails, &outlen);
93 if (converted && (conv_fails == 0))
94 write(hndl->filedesc, converted, outlen);
96 hndl->total_conv_fails += conv_fails;
98 (_("Error converting output string: %s (%d conversion failures)"),
99 strerror(errno), conv_fails);
105 int gedcom_write_set_encoding(const char* charset,
106 Encoding width, Enc_bom bom)
108 char* new_encoding = NULL;
109 if (!strcmp(charset, "UNICODE")) {
110 if (width == ONE_BYTE) {
111 gedcom_error(_("Unicode cannot be encoded into one byte"));
115 new_encoding = get_encoding(charset, width);
117 encoding = new_encoding;
118 write_encoding_details = width | bom;
123 new_encoding = get_encoding(charset, ONE_BYTE);
125 encoding = new_encoding;
126 write_encoding_details = ONE_BYTE;
132 int gedcom_write_set_line_terminator(Enc_line_end end)
134 write_terminator = terminator[end];
138 Gedcom_write_hndl gedcom_write_open(const char *filename)
140 Gedcom_write_hndl hndl;
142 hndl = (Gedcom_write_hndl)malloc(sizeof(struct Gedcom_write_struct));
147 hndl->total_conv_fails = 0;
148 hndl->conv = initialize_utf8_conversion(encoding, 0);
150 gedcom_error(_("Could not open encoding '%s' for writing: %s"),
151 encoding, strerror(errno));
156 hndl->filedesc = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
157 if (!hndl->filedesc) {
158 gedcom_error(_("Could not open file '%s' for writing: %s"),
159 filename, strerror(errno));
160 cleanup_utf8_conversion(hndl->conv);
165 hndl->term = write_terminator;
166 hndl->ctxt_level = -1;
167 if (write_encoding_details & WITH_BOM) {
168 if (write_encoding_details & TWO_BYTE_HILO)
169 write(hndl->filedesc, "\xFE\xFF", 2);
170 else if (write_encoding_details & TWO_BYTE_LOHI)
171 write(hndl->filedesc, "\xFF\xFE", 2);
173 gedcom_warning(_("Byte order mark configured, but no Unicode"));
182 int gedcom_write_close(Gedcom_write_hndl hndl, int* total_conv_fails)
186 write_simple(hndl, 0, NULL, "TRLR", NULL);
187 if (total_conv_fails) *total_conv_fails = hndl->total_conv_fails;
188 result = close(hndl->filedesc);
189 cleanup_utf8_conversion(hndl->conv);
195 char* get_tag_string(int elt_or_rec, char* tag)
197 char* result = tag_data[elt_or_rec].tag_name;
204 gedcom_error(_("The element or record type '%s' requires a specific tag"
206 tag_data[elt_or_rec].elt_name);
211 int check_type(int elt_or_rec, Gedcom_val_type type)
213 int allowed = tag_data[elt_or_rec].allowed_types;
217 gedcom_error(_("Wrong data type for writing element or record type '%s'"),
218 tag_data[elt_or_rec].elt_name);
223 int get_level(Gedcom_write_hndl hndl, int elt_or_rec, int parent)
226 hndl->ctxt_level = 0;
229 while (hndl->ctxt_level && hndl->ctxt_stack[hndl->ctxt_level] != parent)
231 if (hndl->ctxt_stack[hndl->ctxt_level] == parent) {
235 gedcom_error(_("Parent %d not found during write of %d"),
240 hndl->ctxt_stack[hndl->ctxt_level] = elt_or_rec;
241 return hndl->ctxt_level;
244 int gedcom_write_record_str(Gedcom_write_hndl hndl,
245 Gedcom_rec rec, char* tag,
246 struct xref_value* xref, char* val)
250 char* tag_str = NULL;
251 char* xref_str = NULL;
253 tag_str = get_tag_string(rec, tag);
254 level = get_level(hndl, rec, -1);
255 if (tag_str && check_type(rec, (val ? GV_CHAR_PTR : GV_NULL))) {
257 xref_str = xref->string;
258 result = write_simple(hndl, level, xref_str, tag_str, val);
264 int gedcom_write_element_str(Gedcom_write_hndl hndl,
265 Gedcom_elt elt, char* tag, int parent_rec_or_elt,
270 char* tag_str = NULL;
272 tag_str = get_tag_string(elt, tag);
273 level = get_level(hndl, elt, parent_rec_or_elt);
274 if (tag_str && (level != -1)
275 && check_type(elt, (val ? GV_CHAR_PTR : GV_NULL))) {
276 result = write_simple(hndl, level, NULL, tag_str, val);