Mail Archives: djgpp-workers/2005/01/07/18:27:15
On Fri, 07 Jan 2005 19:09:03 +0100 (CET), ams AT ludd DOT ltu DOT se wrote:
>Hello Brian.
>
>Can you send me a link or the patch of the changes or the code to the
>documentation of setlocale (i.e. setlocal.txh), please? I'm sorry but
>I can't find them.
Appended the changes to setlocal and its version of strftime which will
then be identical to the updated version of libc strftime which I changed.
As these are not under CVS control, I generated diffs between the DJGPP
contrib/liblocal.02 directory and my development directory then edited
the new file path to match the old file path, and hope this works okay.
>The changes to strftime.c and friends are dependand of the setlocale
>patch, right?
AIUI the only interface is the __dj_date_format and __dj_time_format
global variables which are defaulted in strftime but can be set by
calling setlocale().
Some of the time test programs call setlocale() and change the TZ
env var to check out handling these variations.
>I want to apply your setlocal patch because my cvs copy has so many
>changes that I'm having problems knowing what is what. But to do that
>I want to have the documentation up-to-date too.
>
>Are you planning to recode setlocal.c so it uses other functions
>instead of stpcpy() and itoa()? If you are, it's counterproductive to
>add those as stubs as they'll disappear again rather quickly; or not
>which can be the real problem.
On Thu, 30 Dec 2004 09:24:08 +0300 (MSK), in Re: setlocale patch,
Alexander Aganichev said he would review my fixes and incorporate
them, and deal with those other issues.
If the updated version of strftime is incorporated into libc,
then he can eliminate the version he provided with liblocal.02,
which the appended patch makes identical.
>That change itself is in no great hurry. Actually I'd prefer if that
>change came later as I had to make some minor adjustment to the code I
>got from you to make it compile and I really want to commit that new
>setlocal.c after which you can submit a small patch.
If he doesn't have time, I can deal with them right now.
>It would be great if you could whip up two small texinfo entries for
>wc204.txi too, as I'm not sure what the changes means exactly. (There
>is some text about strftime() there already:
>@findex strftime AT r{, and z format}
>Corrected problem with negative gmt offsets with z format in @code{strftime}.
>...
>@findex strftime AT r{, and the x type conversion}
>@findex strftime AT r{, and the X type conversion}
>@code{strftime} now uses the date format (for @code{%x})
>and time format (for @code{%X}) from the current locale.
>This means that @code{%T} and @code{%X} are no longer equivalent.
>
>which perhaps should be changed. Don't forget setlocale() too.)
I'll pull my patch summaries and edit those into new patches to wc204.
The setlocale() patch contains only minor bug fixes for resetting
the locale and returning the correct name.
Thanks. Take care, Brian Inglis
diff -put contrib/liblocal.02/src/ansi/locale/setlocal.c contrib/liblocal.02/src/ansi/locale/setlocal.c
--- contrib/liblocal.02/src/ansi/locale/setlocal.c 2002-07-17 02:16:36.000000000 -0600
+++ contrib/liblocal.02/src/ansi/locale/setlocal.c 2004-02-24 01:57:18.000000000 -0700
@@ -465,15 +465,17 @@ setlocale(int category, const char *loca
if (locale[0] == '\0')
{
const char *env;
- if ((env = getenv ("LANG")) != NULL)
+ if ((env = getenv (cat[i].env)) != NULL)
{
locale = env;
}
- if ((env = getenv (cat[i].env)) != NULL)
+ else
+ if ((env = getenv ("LC_ALL")) != NULL)
{
locale = env;
}
- if ((env = getenv ("LC_ALL")) != NULL)
+ else
+ if ((env = getenv ("LANG")) != NULL)
{
locale = env;
}
@@ -481,7 +483,10 @@ setlocale(int category, const char *loca
if ((stricmp(locale, "C") == 0) || (stricmp(locale, "POSIX") == 0))
{
if (cat[i].reset() == 0)
+ {
honored = 0;
+ continue;
+ }
}
else
{
@@ -559,10 +564,10 @@ setlocale(int category, const char *loca
honored = 0;
continue;
}
-
- strncpy(lc_current[i], locale, LC_MAXNAMESIZE);
- lc_current[i][LC_MAXNAMESIZE - 1] = '\0';
}
+
+ strncpy(lc_current[i], locale, LC_MAXNAMESIZE);
+ lc_current[i][LC_MAXNAMESIZE - 1] = '\0';
}
}
if (segment != -1)
@@ -607,8 +612,8 @@ setlocale(int category, const char *loca
#include <stdio.h>
unsigned char __dj_collate_table[256];
-char __dj_date_format[10] = "%m/%d/%y";
-char __dj_time_format[16] = "%H:%M:%S";
+extern char __dj_date_format[10];
+extern char __dj_time_format[16];
int
main(int ac, char *av[])
diff -put contrib/liblocal.02/src/ansi/time/strftime.c contrib/liblocal.02/src/ansi/time/strftime.c
--- contrib/liblocal.02/src/ansi/time/strftime.c 2002-06-08 04:18:06.000000000 -0600
+++ contrib/liblocal.02/src/ansi/time/strftime.c 2004-02-29 00:04:48.000000000 -0700
@@ -1,13 +1,57 @@
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
-
#include <string.h>
#include <time.h>
#include <ctype.h>
+#include <stdlib.h>
+#if 0 /* DEBUG */
+#include <stdio.h>
+#endif /* 0 */
+
+
+
+#define TM_YEAR_BASE 1900 /* tm year epoch base */
+#define LEAP_CENTURIES 4 /* centuries between leap centuries */
+#define CENTURY_YEARS 100 /* years per century */
+#define LEAP_CENTURY_YEARS (LEAP_CENTURIES * CENTURY_YEARS) /* years */
+#define LEAP_YEARS 4 /* years between leap years */
+#define YEAR_DAYS 365 /* days in common year */
+#define HOUR_MINS 60 /* minutes per hour */
+#define MIN_SECS 60 /* seconds per minute */
+
+
+#define FMT_DATE_ISO "%Y-%m-%d" /* ISO date format */
+
+
+/* convert tm year to Gregorian year */
+#define YEAR(tm_y) ((tm_y) + TM_YEAR_BASE)
+/* test if Gregorian year is a leap year */
+#define IS_LEAP_YEAR(y) (!((y) % LEAP_YEARS) && (((y) % CENTURY_YEARS) \
+ || !((y) % LEAP_CENTURY_YEARS)))
+
-#define TM_YEAR_BASE 1900
+
+/* tm wday values */
+typedef enum weekday
+{
+ SUNDAY,
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY,
+ WEEK_DAYS
+
+} weekday; /* enum */
+
+
+
+
+/* locale dependent strings */
static const char *afmt[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
@@ -24,11 +68,92 @@ static const char *Bfmt[] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December",
};
+
+
+/* locale dependent formats */
+
char __dj_date_format[10] = "%m/%d/%y";
char __dj_time_format[16] = "%H:%M:%S";
-static size_t gsize;
-static char *pt;
+
+/* internal global variables */
+
+static size_t gsize; /* user buffer space left */
+static char *pt; /* next char to use in buffer */
+
+
+
+/* calculate ISO year from Gregorian year and days of year and week */
+static int
+iso_year( int year, int doy, int dow)
+{
+ int ISOyear = year; /* ISO year may not be same as Gregorian */
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date */
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d max %d \n",
+ year, doy, dow, THURSDAY, near_thu, YEAR_DAYS + IS_LEAP_YEAR( year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+ --ISOyear;
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+ ++ISOyear;
+ }
+
+ return ISOyear;
+
+} /* iso_year() */
+
+
+
+/* calculate ISO week from Gregorian year and days of year and week */
+static int
+iso_week( int year, int doy, int dow)
+{
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date */
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d"
+ " max prev %d this %d \n",
+ year, doy, dow, THURSDAY, near_thu,
+ YEAR_DAYS + IS_LEAP_YEAR( year - 1 ),
+ YEAR_DAYS + IS_LEAP_YEAR( year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+/* adjust day to make it part of last year */
+ near_thu += YEAR_DAYS + IS_LEAP_YEAR( year - 1 );
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+/* adjust day to make it part of next year */
+ near_thu -= YEAR_DAYS + IS_LEAP_YEAR( year );
+ }
+
+#if 0 /* DEBUG */
+ printf( "near thu %d week %d \n", near_thu, near_thu / WEEK_DAYS + 1);
+#endif /* 0 */
+
+ return near_thu / WEEK_DAYS + 1; /* 0-365 -> 0-52 -> 1-53 */
+
+} /* iso_week() */
+
+
static int
_add(const char *str, int upcase)
@@ -47,7 +172,7 @@ _add(const char *str, int upcase)
static int
_conv(int n, int digits, char pad)
{
- static char buf[10];
+ static char buf[12];
char *p = buf + sizeof(buf) - 2;
do {
@@ -70,6 +195,10 @@ _fmt(const char *format, const struct tm
if (*format == '%')
{
int pad = '0', space=' ';
+ int era = 0; /* locale era modifier */
+ int ordinal = 0; /* locale ordinal modifier */
+
+
if (format[1] == '_')
pad = space = ' ', format++;
if (format[1] == '-')
@@ -78,6 +207,10 @@ _fmt(const char *format, const struct tm
pad = space = '0', format++;
if (format[1] == '^')
upcase = 1, format++;
+ if (format[1] == 'E') /* if locale era modifier */
+ era = 1, format++;
+ if (format[1] == 'O') /* if locale ordinal modifier */
+ ordinal = 1, format++;
switch(*++format)
{
@@ -129,6 +262,16 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_mday, 2, pad))
return 0;
continue;
+
+/*
+ * %F is equivalent to ``%Y-%m-%d'' (the ISO 8601 date format).
+ * [tm_year, tm_mon, tm_mday]
+ */
+ case 'F':
+ if (!_fmt( FMT_DATE_ISO, t, upcase))
+ return 0;
+ continue;
+
case 'H':
if (!_conv(t->tm_hour, 2, pad))
return 0;
@@ -179,6 +322,29 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_sec, 2, pad))
return 0;
continue;
+
+/*
+ * + %s is replaced by the number of seconds since the epoch
+ * 1970-01-01 00:00:00 as a decimal number. [all]
+ */
+ case 's':
+ {
+/* copy user tm in case modified */
+ struct tm tm = *t;
+/* convert to seconds since epoch */
+ time_t secs = mktime( &tm );
+
+#if 0 /* DEBUG */
+ printf( "\n %u s \n", secs);
+#endif /* 0 */
+
+ if (secs == (time_t)-1) /* if invalid time, quit */
+ return 0;
+ if (!_conv( secs, 10, '\0')) /* if conversion failed, quit */
+ return 0;
+ continue;
+ }
+
case 'T':
if (!_fmt("%H:%M:%S", t, upcase))
return 0;
@@ -196,6 +362,37 @@ _fmt(const char *format, const struct tm
2, pad))
return 0;
continue;
+
+/*
+ * %V is replaced by the ISO 8601 week number (see above)
+ * as a decimal number (01-53). [tm_year, tm_wday, tm_yday]
+ */
+ case 'V':
+ if (!_conv( iso_week( YEAR( t->tm_year ), t->tm_yday, t->tm_wday),
+ 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %g is replaced by the last 2 digits of the week-based year (see above)
+ * as a decimal number (00-99). [tm_year, tm_wday, tm_yday]
+ */
+ case 'g':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday, t->tm_wday)
+ % CENTURY_YEARS, 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %G is replaced by the week-based year (see above) as a
+ * decimal number (e.g., 1997). [tm_year, tm_wday, tm_yday]
+ */
+ case 'G':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday, t->tm_wday),
+ 4, pad))
+ return 0;
+ continue;
+
case 'W':
if (!_conv((t->tm_yday + 7 -
(t->tm_wday ? (t->tm_wday - 1) : 6))
@@ -215,24 +412,31 @@ _fmt(const char *format, const struct tm
return 0;
continue;
case 'y':
- case 'g':
if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, 2, pad))
return 0;
continue;
case 'Y':
- case 'G':
if (!_conv(t->tm_year + TM_YEAR_BASE, 4, pad))
return 0;
continue;
case 'z':
- if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
- return 0;
- if (!_conv(t->__tm_gmtoff<0 ? -t->__tm_gmtoff : t->__tm_gmtoff, 4, pad))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ {
+ int offset = abs( t->__tm_gmtoff ) / MIN_SECS;
+
+ if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
+ return 0;
+ if (!_conv( offset / HOUR_MINS * 100 + offset % HOUR_MINS,
+ 4, pad))
+ return 0;
+ }
continue;
case 'Z':
- if (!t->tm_zone || !_add(t->tm_zone, upcase))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ if (!_add(t->__tm_zone, upcase))
+ return 0;
continue;
case '%':
/*
- Raw text -