r15795 - gnucash/trunk/lib/libqof/qof - Improve printing of dates and times with non-UTF-8 locales and on Windows.
Andreas Köhler
andi5 at cvs.gnucash.org
Wed Apr 4 14:48:44 EDT 2007
Author: andi5
Date: 2007-04-04 14:48:42 -0400 (Wed, 04 Apr 2007)
New Revision: 15795
Trac: http://svn.gnucash.org/trac/changeset/15795
Added:
gnucash/trunk/lib/libqof/qof/gnc-date-p.h
gnucash/trunk/lib/libqof/qof/qof-win32.c
Modified:
gnucash/trunk/lib/libqof/qof/Makefile.am
gnucash/trunk/lib/libqof/qof/gnc-date.c
gnucash/trunk/lib/libqof/qof/gnc-date.h
Log:
Improve printing of dates and times with non-UTF-8 locales and on Windows.
* qof_time_format_from_utf8 converts an strftime format specification
from UTF-8 to the locale encoding
* qof_format_time calls strftime repeatedly with growing allocated
buffers until the result fits into one, or return NULL
* qof_formatted_time_to_utf8 converts the result back to UTF-8
* qof_strftime takes similar arguments to strftime, but in UTF-8
* the conversion functions on Windows are implemented in qof-win32.c to
allow them to use windows.h, as they need wcstombs and mbstowcs
Modified: gnucash/trunk/lib/libqof/qof/Makefile.am
===================================================================
--- gnucash/trunk/lib/libqof/qof/Makefile.am 2007-04-04 17:58:23 UTC (rev 15794)
+++ gnucash/trunk/lib/libqof/qof/Makefile.am 2007-04-04 18:48:42 UTC (rev 15795)
@@ -39,6 +39,7 @@
qofinclude_HEADERS = \
deprecated.h \
gnc-date.h \
+ gnc-date-p.h \
gnc-numeric.h \
guid.h \
kvp_frame.h \
@@ -86,6 +87,12 @@
qofla-dir.h.in \
qofmath128.c
+if OS_WIN32
+libgnc_qof_la_SOURCES += qof-win32.c
+else
+EXTRA_DIST += qof-win32.c
+endif
+
qofla-dir.h: $(srcdir)/qofla-dir.h.in Makefile
rm -f $@.tmp
sed < $< > $@.tmp \
Added: gnucash/trunk/lib/libqof/qof/gnc-date-p.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-date-p.h 2007-04-04 17:58:23 UTC (rev 15794)
+++ gnucash/trunk/lib/libqof/qof/gnc-date-p.h 2007-04-04 18:48:42 UTC (rev 15795)
@@ -0,0 +1,45 @@
+/*
+ * gnc-date-p.h
+ *
+ * Copyright (C) 2007 Andreas Koehler <andi5.py at gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation Voice: +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+ * Boston, MA 02110-1301, USA gnu at gnu.org
+ */
+
+#ifndef __GNC_DATE_P_H__
+#define __GNC_DATE_P_H__
+
+#include "gnc-date.h"
+
+/** Convert a given date/time format from UTF-8 to an encoding suitable for the
+ * strftime system call.
+ *
+ * @param utf8_format Date/time format specification in UTF-8.
+ *
+ * @return A newly allocated string on success, or NULL otherwise.
+ */
+gchar *qof_time_format_from_utf8(const gchar *utf8_format);
+
+/** Convert a result of a call to strftime back to UTF-8.
+ *
+ * @param locale_string The result of a call to strftime.
+ *
+ * @return A newly allocated string on success, or NULL otherwise.
+ */
+gchar *qof_formatted_time_to_utf8(const gchar *locale_string);
+
+#endif /* __GNC_DATE_P_H__ */
Modified: gnucash/trunk/lib/libqof/qof/gnc-date.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-date.c 2007-04-04 17:58:23 UTC (rev 15794)
+++ gnucash/trunk/lib/libqof/qof/gnc-date.c 2007-04-04 18:48:42 UTC (rev 15795)
@@ -46,7 +46,7 @@
#include <glib.h>
-#include "gnc-date.h"
+#include "gnc-date-p.h"
#include "qof.h"
#ifndef HAVE_STRPTIME
@@ -439,7 +439,7 @@
gnc_tm_set_day_start (&tm_str);
t = mktime (&tm_str);
localtime_r (&t, &tm_str);
- flen = strftime (buff, len, GNC_D_FMT, &tm_str);
+ flen = qof_strftime (buff, len, GNC_D_FMT, &tm_str);
if (flen != 0)
break;
}
@@ -618,12 +618,12 @@
case QOF_DATE_FORMAT_UTC:
{
gtm = *gmtime (&secs);
- flen = strftime (buff, len, QOF_UTC_DATE_FORMAT, >m);
+ flen = qof_strftime (buff, len, QOF_UTC_DATE_FORMAT, >m);
break;
}
case QOF_DATE_FORMAT_LOCALE:
{
- flen = strftime (buff, len, GNC_D_T_FMT, <m);
+ flen = qof_strftime (buff, len, GNC_D_T_FMT, <m);
}
break;
@@ -645,11 +645,11 @@
if(dateFormat == QOF_DATE_FORMAT_UTC)
{
gtm = *gmtime (&secs);
- flen = strftime(buff, len, QOF_UTC_DATE_FORMAT, >m);
+ flen = qof_strftime(buff, len, QOF_UTC_DATE_FORMAT, >m);
return flen;
}
ltm = *localtime (&secs);
- flen = strftime (buff, len, GNC_T_FMT, <m);
+ flen = qof_strftime (buff, len, GNC_T_FMT, <m);
return flen;
}
@@ -909,7 +909,7 @@
secs = time(NULL);
localtime_r(&secs, &tm);
- strftime(string, sizeof(string), GNC_D_FMT, &tm);
+ qof_strftime(string, sizeof(string), GNC_D_FMT, &tm);
for (s = string; s != '\0'; s++)
if (!isdigit(*s))
@@ -920,6 +920,127 @@
return '\0';
}
+
+#ifndef G_OS_WIN32
+gchar *
+qof_time_format_from_utf8(const gchar *utf8_format)
+{
+ gchar *retval;
+ GError *error = NULL;
+
+ retval = g_locale_from_utf8(utf8_format, -1, NULL, NULL, &error);
+
+ if (!retval) {
+ g_warning("Could not convert format '%s' from UTF-8: %s", utf8_format,
+ error->message);
+ g_error_free(error);
+ }
+ return retval;
+}
+
+gchar *
+qof_formatted_time_to_utf8(const gchar *locale_string)
+{
+ gchar *retval;
+ GError *error = NULL;
+
+ retval = g_locale_to_utf8(locale_string, -1, NULL, NULL, &error);
+
+ if (!retval) {
+ g_warning("Could not convert '%s' to UTF-8: %s", locale_string,
+ error->message);
+ g_error_free(error);
+ }
+ return retval;
+}
+#endif /* G_OS_WIN32 */
+
+gchar *
+qof_format_time(const gchar *format, const struct tm *tm)
+{
+ gchar *locale_format, *tmpbuf, *retval;
+ gsize tmplen, tmpbufsize;
+
+ g_return_val_if_fail(format, 0);
+ g_return_val_if_fail(tm, 0);
+
+ locale_format = qof_time_format_from_utf8(format);
+ if (!locale_format)
+ return NULL;
+
+ tmpbufsize = MAX(128, strlen(locale_format) * 2);
+ while (TRUE) {
+ tmpbuf = g_malloc(tmpbufsize);
+
+ /* Set the first byte to something other than '\0', to be able to
+ * recognize whether strftime actually failed or just returned "".
+ */
+ tmpbuf[0] = '\1';
+ tmplen = strftime(tmpbuf, tmpbufsize, locale_format, tm);
+
+ if (tmplen == 0 && tmpbuf[0] != '\0') {
+ g_free(tmpbuf);
+ tmpbufsize *= 2;
+
+ if (tmpbufsize > 65536) {
+ g_warning("Maximum buffer size for qof_format_time "
+ "exceeded: giving up");
+ g_free(locale_format);
+
+ return NULL;
+ }
+ } else {
+ break;
+ }
+ }
+ g_free(locale_format);
+
+ retval = qof_formatted_time_to_utf8(tmpbuf);
+ g_free(tmpbuf);
+
+ return retval;
+}
+
+gsize
+qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
+{
+ gsize convlen, retval;
+ gchar *convbuf;
+ GError *error = NULL;
+
+ g_return_val_if_fail(buf, 0);
+ g_return_val_if_fail(max > 0, 0);
+ g_return_val_if_fail(format, 0);
+ g_return_val_if_fail(tm, 0);
+
+ convbuf = qof_format_time(format, tm);
+ if (!convbuf) {
+ buf[0] = '\0';
+ return 0;
+ }
+
+ convlen = strlen(convbuf);
+
+ if (max <= convlen) {
+ /* Ensure only whole characters are copied into the buffer. */
+ gchar *end = g_utf8_find_prev_char(convbuf, convbuf + max);
+ g_assert(end != NULL);
+ convlen = end - convbuf;
+
+ /* Return 0 because the buffer isn't large enough. */
+ retval = 0;
+ } else {
+ retval = convlen;
+ }
+
+ memcpy(buf, convbuf, convlen);
+ buf[convlen] = '\0';
+ g_free(convbuf);
+
+ return retval;
+}
+
+
/********************************************************************\
\********************************************************************/
Modified: gnucash/trunk/lib/libqof/qof/gnc-date.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-date.h 2007-04-04 17:58:23 UTC (rev 15794)
+++ gnucash/trunk/lib/libqof/qof/gnc-date.h 2007-04-04 18:48:42 UTC (rev 15795)
@@ -328,6 +328,35 @@
* itself, instead of depending on the routines here.
*/
+/** qof_format_time takes a format specification in UTF-8 and a broken-down time,
+ * tries to call strftime with a sufficiently large buffer and, if successful,
+ * return a newly allocated string in UTF-8 for the printing result.
+ *
+ * @param format A format specification in UTF-8.
+ *
+ * @param tm A broken-down time.
+ *
+ * @return A newly allocated string on success, or NULL otherwise.
+ */
+gchar *qof_format_time(const gchar *format, const struct tm *tm);
+
+/** qof_strftime calls qof_format_time to print a given time and afterwards tries
+ * to put the result into a buffer of fixed size.
+ *
+ * @param buf A buffer.
+ *
+ * @param max The size of buf in bytes.
+ *
+ * @param format A format specification in UTF-8.
+ *
+ * @param tm A broken-down time.
+ *
+ * @return The number of characters written, not include the null byte, if the
+ * complete string, including the null byte, fits into the buffer. Otherwise 0.
+ */
+gsize qof_strftime(gchar *buf, gsize max, const gchar *format,
+ const struct tm *tm);
+
/** qof_print_date_dmy_buff
* Convert a date as day / month / year integers into a localized string
* representation
Added: gnucash/trunk/lib/libqof/qof/qof-win32.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qof-win32.c 2007-04-04 17:58:23 UTC (rev 15794)
+++ gnucash/trunk/lib/libqof/qof/qof-win32.c 2007-04-04 18:48:42 UTC (rev 15795)
@@ -0,0 +1,81 @@
+/*
+ * qof-win32.c
+ *
+ * Copyright (C) 2007 Andreas Koehler <andi5.py at gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation Voice: +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+ * Boston, MA 02110-1301, USA gnu at gnu.org
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include "gnc-date-p.h"
+#include <windows.h>
+
+gchar *
+qof_time_format_from_utf8(const gchar *utf8_format)
+{
+ gunichar2 *utf16_format;
+ gchar *retval;
+ gsize count;
+
+ utf16_format = g_utf8_to_utf16(utf8_format, -1, NULL, NULL, NULL);
+ if (!utf16_format)
+ return NULL;
+
+ /* get number of resulting wide characters */
+ count = wcstombs(NULL, utf16_format, 0);
+ if (count <= 0)
+ return NULL;
+
+ /* malloc and convert */
+ retval = g_malloc((count+1) * sizeof(gchar));
+ count = wcstombs(retval, utf16_format, count+1);
+ g_free(utf16_format);
+ if (count <= 0) {
+ g_free(retval);
+ return NULL;
+ }
+
+ return retval;
+}
+
+gchar *
+qof_formatted_time_to_utf8(const gchar *locale_string)
+{
+ gunichar2 *utf16_string;
+ gchar *retval;
+ gsize count;
+
+ /* get number of resulting wide characters */
+ count = mbstowcs(NULL, locale_string, 0);
+ if (count <= 0)
+ return NULL;
+
+ /* malloc and convert */
+ utf16_string = g_malloc((count+1) * sizeof(gunichar2));
+ count = mbstowcs(utf16_string, locale_string, count+1);
+ if (count <= 0) {
+ g_free(utf16_string);
+ return NULL;
+ }
+
+ retval = g_utf16_to_utf8(utf16_string, -1, NULL, NULL, NULL);
+ g_free(utf16_string);
+
+ return retval;
+}
More information about the gnucash-changes
mailing list