#include "gedcom_internal.h"
#include "gedcom.h"
#include "encoding.h"
+#include "encoding_state.h"
#include "tag_data.h"
#include "buffer.h"
-#include "utf8.h"
+#include "utf8tools.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAXWRITELEN MAXGEDCLINELEN
-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 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, NULL, 0, cleanup_write_buffer };
}
int write_simple(Gedcom_write_hndl hndl,
- int level, char* xref, char* tag, char* value)
+ int level, const char* xref, const char* tag,
+ const char* value)
{
int res;
return 0;
}
+int write_encoding_value(Gedcom_write_hndl hndl,
+ int level, char* xref, char* tag, char* value)
+{
+ if (strcmp(value, write_encoding.charset))
+ gedcom_warning(_("Forcing HEAD.CHAR value to '%s'"),
+ write_encoding.charset);
+ return write_simple(hndl, level, xref, tag, write_encoding.charset);
+}
+
int supports_continuation(int elt_or_rec, int which_continuation)
{
return tag_data[elt_or_rec].options & which_continuation;
}
int write_long(Gedcom_write_hndl hndl, int elt_or_rec,
- int level, char* xref, char* tag, char* value)
+ int level, const char* xref, const char* tag, const char* value)
{
- int prefix_len, value_len, term_len;
- char* nl_pos = strchr(value, '\n');
+ int prefix_len, value_len = 0, term_len;
+ char* nl_pos = NULL;
+ if (value) nl_pos = strchr(value, '\n');
prefix_len = utf8_strlen(tag) + 3; /* for e.g. "0 INDI " */
if (level > 9) prefix_len++;
if (xref) prefix_len += utf8_strlen(xref) + 1;
- value_len = utf8_strlen(value);
+ if (value) value_len = utf8_strlen(value);
term_len = strlen(hndl->term);
if (!nl_pos && prefix_len + value_len + term_len <= MAXWRITELEN)
write_simple(hndl, level, xref, tag, value);
else {
- char* value_ptr = value;
+ const char* value_ptr = value;
int cont_supported = supports_continuation(elt_or_rec, OPT_CONT);
int cont_as_conc = supports_continuation(elt_or_rec, OPT_CONT_AS_CONC);
if (nl_pos && !cont_supported) {
- gedcom_error (_("The tag %s doesn't support newlines\n"), tag);
+ gedcom_error (_("The tag %s doesn't support newlines"), tag);
return 1;
}
else {
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
- return 1;
- }
- }
- else {
- new_encoding = get_encoding(charset, ONE_BYTE);
- if (new_encoding) {
- encoding = new_encoding;
- write_encoding_details = ONE_BYTE;
- }
- else
- return 1;
- }
- 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;
if (!hndl)
MEMORY_ERROR;
else {
+ init_write_encoding();
+ init_write_terminator();
hndl->total_conv_fails = 0;
- hndl->conv = initialize_utf8_conversion(encoding, 0);
+ hndl->conv = initialize_utf8_conversion(write_encoding.encoding, 0);
if (!hndl->conv) {
gedcom_error(_("Could not open encoding '%s' for writing: %s"),
- encoding, strerror(errno));
+ write_encoding.encoding, strerror(errno));
free(hndl);
hndl = NULL;
}
hndl = NULL;
}
else {
- hndl->term = write_terminator;
+ hndl->term = write_encoding.terminator;
hndl->ctxt_level = -1;
- if (write_encoding_details & WITH_BOM) {
- if (write_encoding_details & TWO_BYTE_HILO)
+ if (write_encoding.bom == WITH_BOM) {
+ if (write_encoding.width == TWO_BYTE_HILO)
write(hndl->filedesc, "\xFE\xFF", 2);
- else if (write_encoding_details & TWO_BYTE_LOHI)
+ else if (write_encoding.width == TWO_BYTE_LOHI)
write(hndl->filedesc, "\xFF\xFE", 2);
+ else if (!strcmp(write_encoding.encoding, "UTF-8"))
+ write(hndl->filedesc, "\xEF\xBB\xBF", 3);
else
- gedcom_warning(_("Byte order mark configured, but no Unicode"));
+ gedcom_warning(_("Byte order mark configured, but not relevant"));
}
}
}
}
}
else {
- gedcom_error(_("The element or record type '%s' requires a specific tag"
+ gedcom_error(_("The element or record type '%s' requires a specific tag "
"for writing"),
tag_data[elt_or_rec].elt_name);
return NULL;
tag_str = get_tag_string(rec_or_elt, tag);
level = get_level(hndl, rec_or_elt, parent_rec_or_elt);
if (tag_str && (level != -1)) {
- if (supports_continuation(rec_or_elt, OPT_CONT|OPT_CONC|OPT_CONT_AS_CONC))
+ if (rec_or_elt == ELT_HEAD_CHAR)
+ result = write_encoding_value(hndl, level, xrefstr, tag_str, val);
+ else if (supports_continuation(rec_or_elt, OPT_CONT|OPT_CONC))
result = write_long(hndl, rec_or_elt, level, xrefstr, tag_str, val);
else
result = write_simple(hndl, level, xrefstr, tag_str, val);
}
int gedcom_write_record_str(Gedcom_write_hndl hndl,
- Gedcom_rec rec, int tag,
- char* xrefstr, char* val)
+ Gedcom_rec rec, char* xrefstr, char* val)
{
int result = 1;
if (check_type(rec, (val ? GV_CHAR_PTR : GV_NULL)))
- result = _gedcom_write_val(hndl, rec, tag, -1, xrefstr, convert_at(val));
+ result = _gedcom_write_val(hndl, rec, 0, -1, xrefstr, convert_at(val));
return result;
}
return result;
}
-int gedcom_write_record_xref(Gedcom_write_hndl hndl,
- Gedcom_rec rec, int tag,
- char* xrefstr, struct xref_value* val)
+int gedcom_write_element_xref(Gedcom_write_hndl hndl,
+ Gedcom_elt elt, int tag, int parent_rec_or_elt,
+ struct xref_value* val)
{
int result = 1;
- if (check_type(rec, (val ? GV_XREF_PTR : GV_NULL)))
- result = _gedcom_write_val(hndl, rec, tag, -1, xrefstr, val->string);
+ if (check_type(elt, (val ? GV_XREF_PTR : GV_NULL)))
+ result = _gedcom_write_val(hndl, elt, tag, parent_rec_or_elt, NULL,
+ val->string);
return result;
}
-int gedcom_write_element_xref(Gedcom_write_hndl hndl,
+int gedcom_write_element_date(Gedcom_write_hndl hndl,
Gedcom_elt elt, int tag, int parent_rec_or_elt,
- struct xref_value* val)
+ struct date_value* val)
{
int result = 1;
- if (check_type(elt, (val ? GV_XREF_PTR : GV_NULL)))
+ if (check_type(elt, (val ? GV_DATE_VALUE : GV_NULL)))
result = _gedcom_write_val(hndl, elt, tag, parent_rec_or_elt, NULL,
- val->string);
+ gedcom_date_to_string(val));
+ return result;
+}
+
+int gedcom_write_element_age(Gedcom_write_hndl hndl,
+ Gedcom_elt elt, int tag, int parent_rec_or_elt,
+ struct age_value* val)
+{
+ int result = 1;
+ if (check_type(elt, (val ? GV_AGE_VALUE : GV_NULL)))
+ result = _gedcom_write_val(hndl, elt, tag, parent_rec_or_elt, NULL,
+ gedcom_age_to_string(val));
return result;
}