mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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 git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15795 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
91eb3d4262
commit
095c71a5f1
@ -39,6 +39,7 @@ qofincludedir = ${pkgincludedir}
|
||||
qofinclude_HEADERS = \
|
||||
deprecated.h \
|
||||
gnc-date.h \
|
||||
gnc-date-p.h \
|
||||
gnc-numeric.h \
|
||||
guid.h \
|
||||
kvp_frame.h \
|
||||
@ -86,6 +87,12 @@ EXTRA_DIST = \
|
||||
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 \
|
||||
|
45
lib/libqof/qof/gnc-date-p.h
Normal file
45
lib/libqof/qof/gnc-date-p.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* gnc-date-p.h
|
||||
*
|
||||
* Copyright (C) 2007 Andreas Koehler <andi5.py@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@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__ */
|
@ -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 @@ qof_print_date_dmy_buff (char * buff, size_t len, int day, int month, int year)
|
||||
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 @@ qof_print_date_time_buff (char * buff, size_t len, time_t secs)
|
||||
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 @@ qof_print_time_buff (char * buff, size_t len, time_t secs)
|
||||
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 @@ char dateSeparator (void)
|
||||
|
||||
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 @@ char dateSeparator (void)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************\
|
||||
\********************************************************************/
|
||||
|
||||
|
@ -328,6 +328,35 @@ gchar dateSeparator(void);
|
||||
* 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
|
||||
|
81
lib/libqof/qof/qof-win32.c
Normal file
81
lib/libqof/qof/qof-win32.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* qof-win32.c
|
||||
*
|
||||
* Copyright (C) 2007 Andreas Koehler <andi5.py@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@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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user