This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH]: Enable LC_TIME handling


On Jan 18 13:48, Howland Craig D (Craig) wrote:
> The strftime.c documentation edits should be done consistently
> in the manner that %r, %x, etc., were edited, which is to keep the
> default locale information, but simply changing the words around them.
> (Since many users likely know nothing about locale (and are better off
> continuing to know nothing about it), keeping the info that is there is
> better than deleting it; I can't, offhand, think of another place in
> Newlib documentation where a user could go to get the information that
> would be deleted.)
>  
> For example:
>  
> Extract from the patch:
>  o %B
> -The full name of the month, one of `<<January>>', `<<February>>',
> -`<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
> -`<<August>>', `<<September>>', `<<October>>', `<<November>>',
> -`<<December>>'. [tm_mon]
> +The full month name according to the current locale. [tm_mon]
> ...
>  o %r
> -The 12-hour time, to the second.  Equivalent to "%I:%M:%S %p". [tm_sec,
> -tm_min, tm_hour]
> +Replaced by the time in a.m. and p.m. notation.  In the POSIX locale
> this
> +is equivalent to "%I:%M:%S %p".  In locales which don't define
> a.m./p.m.
> +notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
>  
> A possible alternative for %B, using the same paradigm as was used for
> %r:
>  o %B
> +The full month name according to the current locale. [tm_mon]
> -The full name of the month, one of `<<January>>', `<<February>>',
> +In the default "C" locale, one of `<<January>>', `<<February>>',
>  `<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
>  `<<August>>', `<<September>>', `<<October>>', `<<November>>',
>  `<<December>>'. [tm_mon]

Ok.

> Another alternative is to put the information in another place, and
> refer to it so that users can find it--but the first alternative is
> the least amount of work.
>  
> And a secondary comment:  when referring to locale, the patch generally
> uses "POSIX".  Again, because many people likely don't know, it might
> be better to talk about "C" locale or "'C' and POSIX" (or "'C'/POSIX,
> etc.) locales.

The original documentation already refers to POSIX, for instance:

  o %k
  The hour (on a 24-hour clock), formatted with leading space if single
  digit (from `<<0>>' to `<<23>>'). Non-POSIX extension (c.p. %I). [tm_hour]

strftime is a POSIX function and newlib is a POSIX C library.  Anybody
developing locale-specific stuff should know what that means.  Per POSIX,
the strings "C" and "POSIX" are reserved identifiers for the POSIX locale.

But I don't care much.  I changed that to "C" in the below patch.

> +     *len_ret = mbstowcs (buf, elem, 256);
> ...
> +#ifdef MAKE_WCSFTIME
> +  CHAR ctlocbuf[256];
> +#endif
> Are these two occurrences of the number 256 independent of each other?
> If they are dependent, #define CTLOCBUFLEN 256 (or the like) should be
> introduced.

You're ight.  They depend on each other.  256 is just a big buffer which
is always big enough.  None of the localized strings is that big in wide
char representation.  However, I tweaked the wide char version of _ctloc
to make sure the buffer is always 0-terminated.

Below's the new version of the strftime.c part of the patch.


Corinna



Index: libc/time/strftime.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/time/strftime.c,v
retrieving revision 1.12
diff -u -p -r1.12 strftime.c
--- libc/time/strftime.c	12 Mar 2009 10:27:10 -0000	1.12
+++ libc/time/strftime.c	18 Jan 2010 20:10:50 -0000
@@ -52,26 +52,26 @@ following ways:
 
 o+
 o %a
-A three-letter abbreviation for the day of the week. [tm_wday]
+The abbreviated weekday name according to the current locale. [tm_wday]
 
 o %A
-The full name for the day of the week, one of `<<Sunday>>',
-`<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>',
-`<<Friday>>', or `<<Saturday>>'. [tm_wday]
+The full weekday name according to the current locale.
+In the default "C" locale, one of `<<Sunday>>', `<<Monday>>', `<<Tuesday>>',
+`<<Wednesday>>', `<Thursday>>', `<<Friday>>', `<<Saturday>>'. [tm_wday]
 
 o %b
-A three-letter abbreviation for the month name. [tm_mon]
+The abbreviated month name according to the current locale. [tm_mon]
 
 o %B
-The full name of the month, one of `<<January>>', `<<February>>',
+The full month name according to the current locale.
+In the default "C" locale, one of `<<January>>', `<<February>>',
 `<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
 `<<August>>', `<<September>>', `<<October>>', `<<November>>',
 `<<December>>'. [tm_mon]
 
 o %c
-A string representing the complete date and time, in the form
-`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13
-1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
+The preferred date and time representation for the current locale.
+[tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
 
 o %C
 The century, that is, the year divided by 100 then truncated.  For
@@ -93,8 +93,7 @@ The day of the month, formatted with lea
 
 o %E<<x>>
 In some locales, the E modifier selects alternative representations of
-certain modifiers <<x>>.  But in the "C" locale supported by newlib,
-it is ignored, and treated as %<<x>>.
+certain modifiers <<x>>.  In newlib, it is ignored, and treated as %<<x>>.
 
 o %F
 A string representing the ISO 8601:2000 date format, in the form
@@ -115,8 +114,7 @@ Example: "%G" for Saturday 2nd January 1
 Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
 
 o %h
-A three-letter abbreviation for the month name (synonym for
-"%b"). [tm_mon]
+Synonym for "%b". [tm_mon]
 
 o %H
 The hour (on a 24-hour clock), formatted with two digits (from
@@ -150,15 +148,19 @@ A newline character (`<<\n>>').
 
 o %O<<x>>
 In some locales, the O modifier selects alternative digit characters
-for certain modifiers <<x>>.  But in the "C" locale supported by newlib, it
-is ignored, and treated as %<<x>>.
+for certain modifiers <<x>>.  In newlib, it is ignored, and treated as %<<x>>.
 
 o %p
-Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour]
+Either `<<AM>>' or `<<PM>>' as appropriate, or the corresponding strings for
+the current locale. [tm_hour]
+
+o %P
+Same as '<<%p>>', but in lowercase.  This is a GNU extension. [tm_hour]
 
 o %r
-The 12-hour time, to the second.  Equivalent to "%I:%M:%S %p". [tm_sec,
-tm_min, tm_hour]
+Replaced by the time in a.m. and p.m. notation.  In the "C" locale this
+is equivalent to "%I:%M:%S %p".  In locales which don't define a.m./p.m.
+notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
 
 o %R
 The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
@@ -198,12 +200,13 @@ Monday in a year, and earlier days are i
 digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
 
 o %x
-A string representing the complete date, equivalent to "%m/%d/%y".
+Replaced by the preferred date representation in the current locale.
+In the "C" locale this is equivalent to "%m/%d/%y".
 [tm_mon, tm_mday, tm_year]
 
 o %X
-A string representing the full time of day (hours, minutes, and
-seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
+Replaced by the preferred time representation in the current locale.
+In the "C" locale this is equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
 
 o %y
 The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
@@ -263,7 +266,10 @@ the "C" locale settings.
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <ctype.h>
+#include <wctype.h>
 #include "local.h"
+#include "../locale/timelocal.h"
  
 /* Defines to make the file dual use for either strftime() or wcsftime().
  * To get wcsftime, define MAKE_WCSFTIME.
@@ -276,13 +282,28 @@ the "C" locale settings.
 #  define CHAR		char		/* string type basis */
 #  define CQ(a)		a		/* character constant qualifier */
 #  define SFLG				/* %s flag (null for normal char) */
+#  define _ctloc(x) (ctloclen = strlen (ctloc = _CurrentTimeLocale->x), ctloc)
+#  define TOLOWER(c)	tolower((int)(unsigned char)(c))
 # else
 #  define strftime	wcsftime	/* Alternate function name */
 #  define CHAR		wchar_t		/* string type basis */
 #  define CQ(a)		L##a		/* character constant qualifier */
 #  define snprintf	swprintf	/* wide-char equivalent function name */
 #  define strncmp	wcsncmp		/* wide-char equivalent function name */
+#  define TOLOWER(c)	towlower((wint_t)(c))
 #  define SFLG		"l"		/* %s flag (l for wide char) */
+#  define CTLOCBUFLEN   256		/* Arbitrary big buffer size */
+   const wchar_t *
+   __ctloc (wchar_t *buf, const char *elem, size_t *len_ret)
+   {
+     buf[CTLOCBUFLEN - 1] = L'\0';
+     *len_ret = mbstowcs (buf, elem, CTLOCBUFLEN - 1);
+     if (*len_ret == (size_t) -1 )
+       *len_ret = 0;
+     return buf;
+   }
+#  define _ctloc(x) (ctloc = __ctloc (ctlocbuf, _CurrentTimeLocale->x, \
+		     &ctloclen))
 #endif  /* MAKE_WCSFTIME */
 
 /* Enforce the coding assumptions that YEAR_BASE is positive.  (%C, %Y, etc.) */
@@ -293,18 +314,6 @@ the "C" locale settings.
 static _CONST int dname_len[7] =
 {6, 6, 7, 9, 8, 6, 8};
 
-static _CONST CHAR *_CONST dname[7] =
-{CQ("Sunday"), CQ("Monday"), CQ("Tuesday"), CQ("Wednesday"),
- CQ("Thursday"), CQ("Friday"), CQ("Saturday")};
-
-static _CONST int mname_len[12] =
-{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8};
-
-static _CONST CHAR *_CONST mname[12] =
-{CQ("January"), CQ("February"), CQ("March"), CQ("April"),
- CQ("May"), CQ("June"), CQ("July"), CQ("August"),
- CQ("September"), CQ("October"), CQ("November"), CQ("December")};
-
 /* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
    -1, 0, or 1 as the adjustment to add to the year for the ISO week
    numbering used in "%g%G%V", avoiding overflow.  */
@@ -361,7 +370,13 @@ _DEFUN (strftime, (s, maxsize, format, t
 {
   size_t count = 0;
   int i, len;
+  const CHAR *ctloc;
+#ifdef MAKE_WCSFTIME
+  CHAR ctlocbuf[CTLOCBUFLEN];
+#endif
+  size_t ctloclen;
 
+  struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale ();
   for (;;)
     {
       while (*format && *format != CQ('%'))
@@ -382,56 +397,68 @@ _DEFUN (strftime, (s, maxsize, format, t
       switch (*format)
 	{
 	case CQ('a'):
-	  for (i = 0; i < 3; i++)
+	  _ctloc (wday[tim_p->tm_wday]);
+	  for (i = 0; i < ctloclen; i++)
 	    {
 	      if (count < maxsize - 1)
-		s[count++] =
-		  dname[tim_p->tm_wday][i];
+		s[count++] = ctloc[i];
 	      else
 		return 0;
 	    }
 	  break;
 	case CQ('A'):
-	  for (i = 0; i < dname_len[tim_p->tm_wday]; i++)
+	  _ctloc (weekday[tim_p->tm_wday]);
+	  for (i = 0; i < ctloclen; i++)
 	    {
 	      if (count < maxsize - 1)
-		s[count++] =
-		  dname[tim_p->tm_wday][i];
+		s[count++] = ctloc[i];
 	      else
 		return 0;
 	    }
 	  break;
 	case CQ('b'):
 	case CQ('h'):
-	  for (i = 0; i < 3; i++)
+	  _ctloc (mon[tim_p->tm_mon]);
+	  for (i = 0; i < ctloclen; i++)
 	    {
 	      if (count < maxsize - 1)
-		s[count++] =
-		  mname[tim_p->tm_mon][i];
+		s[count++] = ctloc[i];
 	      else
 		return 0;
 	    }
 	  break;
 	case CQ('B'):
-	  for (i = 0; i < mname_len[tim_p->tm_mon]; i++)
+	  _ctloc (month[tim_p->tm_mon]);
+	  for (i = 0; i < ctloclen; i++)
 	    {
 	      if (count < maxsize - 1)
-		s[count++] =
-		  mname[tim_p->tm_mon][i];
+		s[count++] = ctloc[i];
 	      else
 		return 0;
 	    }
 	  break;
 	case CQ('c'):
-	  {
-	    /* Recurse to avoid need to replicate %Y formation. */
-	    size_t adjust = strftime (&s[count], maxsize - count,
-				      CQ("%a %b %e %H:%M:%S %Y"), tim_p);
-	    if (adjust > 0)
-	      count += adjust;
-	    else
-	      return 0;
-	  }
+	  _ctloc (c_fmt);
+	  goto recurse;
+	case CQ('r'):
+	  _ctloc (ampm_fmt);
+	  goto recurse;
+	case CQ('x'):
+	  _ctloc (x_fmt);
+	  goto recurse;
+	case CQ('X'):
+	  _ctloc (X_fmt);
+recurse:
+	  if (*ctloc)
+	    {
+	      /* Recurse to avoid need to replicate %Y formation. */
+	      size_t adjust = strftime (&s[count], maxsize - count, ctloc,
+					tim_p);
+	      if (adjust > 0)
+		count += adjust;
+	      else
+		return 0;
+	    }
 	  break;
 	case CQ('C'):
 	  {
@@ -472,7 +499,6 @@ _DEFUN (strftime, (s, maxsize, format, t
 	  if (len < 0  ||  (count+=len) >= maxsize)  return 0;
 	  break;
 	case CQ('D'):
-	case CQ('x'):
 	  /* %m/%d/%y */
 	  len = snprintf (&s[count], maxsize - count,
 			CQ("%.2d/%.2d/%.2d"),
@@ -582,33 +608,16 @@ _DEFUN (strftime, (s, maxsize, format, t
 	    return 0;
 	  break;
 	case CQ('p'):
-	  if (count < maxsize - 1)
+	case CQ('P'):
+	  _ctloc (am_pm[tim_p->tm_hour < 12 ? 0 : 1]);
+	  for (i = 0; i < ctloclen; i++)
 	    {
-	      if (tim_p->tm_hour < 12)
-		s[count++] = CQ('A');
+	      if (count < maxsize - 1)
+		s[count++] = (*format == CQ('P') ? TOLOWER (ctloc[i])
+						 : ctloc[i]);
 	      else
-		s[count++] = CQ('P');
-	    }
-	  if (count < maxsize - 1)
-	    {
-	      s[count++] = CQ('M');
+		return 0;
 	    }
-	  else
-	    return 0;
-	  break;
-	case CQ('r'):
-	  {
-	    register int  h12;
-	    h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12)  ?
-						12  :  tim_p->tm_hour % 12;
-	    len = snprintf (&s[count], maxsize - count,
-			CQ("%.2d:%.2d:%.2d %cM"),
-			h12, 
-			tim_p->tm_min,
-			tim_p->tm_sec,
-			(tim_p->tm_hour < 12)  ?  CQ('A') :  CQ('P'));
-	    if (len < 0  ||  (count+=len) >= maxsize)  return 0;
-	  }
 	  break;
 	case CQ('R'):
           len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
@@ -627,7 +636,6 @@ _DEFUN (strftime, (s, maxsize, format, t
 	    return 0;
 	  break;
 	case CQ('T'):
-	case CQ('X'):
           len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
 			tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
           if (len < 0  ||  (count+=len) >= maxsize)  return 0;


-- 
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]