summaryrefslogtreecommitdiff
path: root/missing_d
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2010-07-16 13:14:38 +0300
committerArnold D. Robbins <arnold@skeeve.com>2010-07-16 13:14:38 +0300
commitfae4762eba9ff7bb466a600130e9c90eaac6b0bc (patch)
tree62711fe7cd511824b5f8a90ba1ba7b523d42e127 /missing_d
parentbc70de7b3302d5a81515b901cae376b8b51d2004 (diff)
downloadgawk-fae4762eba9ff7bb466a600130e9c90eaac6b0bc.tar.gz
Move to gawk-3.1.1.gawk-3.1.1
Diffstat (limited to 'missing_d')
-rw-r--r--missing_d/ChangeLog15
-rw-r--r--missing_d/strftime.3359
-rw-r--r--missing_d/strftime.c2123
-rw-r--r--missing_d/strtod.c9
4 files changed, 1363 insertions, 1143 deletions
diff --git a/missing_d/ChangeLog b/missing_d/ChangeLog
new file mode 100644
index 00000000..7220065c
--- /dev/null
+++ b/missing_d/ChangeLog
@@ -0,0 +1,15 @@
+Wed May 1 16:41:32 2002 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Release 3.1.1: Release tar file made.
+
+Tue Dec 4 17:56:46 2001 Arnold D. Robbins <arnold@skeeve.com>
+
+ * strftime.c: Replaced with glibc version.
+ * strftime.3: Removed
+
+Fri Aug 3 09:01:19 2001 Arnold D. Robbins <arnold@skeeve.com>
+
+ ChangeLog created.
+
+ * strtod.c (strtod): Fixed test at end for failure to
+ be a little smarter.
diff --git a/missing_d/strftime.3 b/missing_d/strftime.3
deleted file mode 100644
index b017bf45..00000000
--- a/missing_d/strftime.3
+++ /dev/null
@@ -1,359 +0,0 @@
-.TH STRFTIME 3
-.SH NAME
-strftime \- generate formatted time information
-.SH SYNOPSIS
-.ft B
-.nf
-#include <sys/types.h>
-#include <time.h>
-.sp
-size_t strftime(char *s, size_t maxsize, const char *format,
- const struct tm *timeptr);
-.fi
-.SH DESCRIPTION
-The following description is transcribed verbatim from the January 18, 1999
-draft standard for ISO C.
-This draft is essentially identical in technical content
-to the final version of the standard.
-.LP
-``The
-.B strftime
-function places characters into the array pointed to by
-.B s
-as controlled by the string pointed to by
-.BR format .
-The format shall be a multibyte character sequence, beginning and ending in
-its initial shift state.
-The
-.B format
-string consists of zero or more conversion specifiers and ordinary
-multibyte characters. A conversion specifier consists of a
-.B %
-character, possibly followed by an
-.B E
-or
-.B O
-modifier character (described below),
-followed by a character that determines the behavior of the
-conversion specifier.
-All ordinary multibyte characters (including the terminating null
-character) are copied unchanged into the array.
-If copying takes place between objects that overlap the behavior is undefined.
-No more than
-.B maxsize
-characters are placed into the array.
-.PP
-``Each conversion specifier is replaced by appropriate characters as described
-in the following list.
-The appropriate characters are determined by the
-.B LC_TIME
-category of the current locale and by the values
-of zero or more members of the broken-down time
-structure pointed to by
-.BR timeptr ,
-as specified by brackets in the description.
-If any of the specified values is outside the normal range, the characters
-stored are unspecified.''
-.TP
-.B %a
-is replaced by the locale's abbreviated weekday name.
-.TP
-.B %A
-is replaced by the locale's full weekday name.
-.TP
-.B %b
-is replaced by the locale's abbreviated month name.
-.TP
-.B %B
-is replaced by the locale's full month name.
-.TP
-.B %c
-is replaced by the locale's appropriate date and time representation.
-(This is
-.B "%A %B %d %T %Y"
-in the \fB"C"\fR
-locale.)
-.TP
-.B %C
-is replaced by the year divided by 100 and truncated to an integer,
-as a decimal number
-.RB ( 00 - 99 ).
-.TP
-.B %d
-is replaced by the day of the month as a decimal number
-.RB ( 01 - 31 ).
-.TP
-.B %D
-is equivalent to
-.BR %m/%d/%y .
-.TP
-.B %e
-is replaced by the day of the month as a decimal number
-.RB ( 1 - 31 );
-a single digit is preceded by a space.
-.TP
-.B %F
-is equivalent to
-.B %Y\-%m\-%d
-(the ISO 8601 date format).
-.TP
-.B %g
-is replaced by the year without century of the ISO week number
-as a decimal number
-.RB ( 00 - 99 ).
-.TP
-.B %G
-is replaced by the year with century of the ISO week number
-as a decimal number.
-.TP
-.B %h
-is equivalent to
-.BR %b .
-.TP
-.B %H
-is replaced by the hour (24-hour clock) as a decimal number
-.RB ( 00 - 23 ).
-.TP
-.B %I
-is replaced by the hour (12-hour clock) as a decimal number
-.RB ( 01 - 12 ).
-.TP
-.B %j
-is replaced by the day of the year as a decimal number
-.RB ( 001 - 366 ).
-.TP
-.B %m
-is replaced by the month as a decimal number
-.RB ( 01 - 12 ).
-.TP
-.B %M
-is replaced by the minute as a decimal number
-.RB ( 00 - 59 ).
-.TP
-.B %n
-is replaced with a newline character (\s-1ASCII LF\s+1).
-.TP
-.B %p
-is replaced by the locale's equivalent of the AM/PM designations associated
-with a 12-hour clock.
-.TP
-.B %r
-is replaced by the locale's 12-hour clock time.
-(This is
-.B "%I:%M:%S %p"
-in the \fB"C"\fR
-locale.)
-.TP
-.B %R
-is equivalent to
-.BR %H:%M .
-.TP
-.B %S
-is replaced by the second as a decimal number
-.RB ( 00 - 60 ).
-.TP
-.B %t
-is replaced with a \s-1TAB\s+1 character.
-.TP
-.B %T
-is equivalent to
-.BR %H:%M:%S .
-.TP
-.B %u
-is replaced by the ISO 8601 weekday as a decimal number
-.RB [ "1 " (Monday)- 7 ].
-.TP
-.B %U
-is replaced by the week number of the year (the first Sunday as the first
-day of week 1) as a decimal number
-.RB ( 00 - 53 ).
-.TP
-.B %V
-is replaced by the ISO 8601 week number of the year (the first Monday as the first
-day of week 1) as a decimal number
-.RB ( 01 - 53 ).
-.TP
-.B %w
-is replaced by the weekday as a decimal number
-.RB [ "0 " (Sunday)- 6 ].
-.TP
-.B %W
-is replaced by the week number of the year (the first Monday as the first
-day of week 1) as a decimal number
-.RB ( 00 - 53 ).
-.TP
-.B %x
-is replaced by the locale's appropriate date representation.
-(This is
-.B "%A %B %d %Y"
-in the \fB"C"\fR
-locale.)
-.TP
-.B %X
-is replaced by the locale's appropriate time representation.
-(This is
-.B "%T"
-in the \fB"C"\fR
-locale.)
-.TP
-.B %y
-is replaced by the year without century as a decimal number
-.RB ( 00 - 99 ).
-.TP
-.B %Y
-is replaced by the year with century as a decimal number.
-.TP
-.B %z
-The timezone offset in a +HHMM format (e.g. the format necessary to
-produce RFC-822/RFC-1036 date headers).
-.TP
-.B %Z
-is replaced by the time zone name or abbreviation, or by no characters if
-no time zone is determinable.
-.TP
-.B %%
-is replaced by
-.BR % .
-.LP
-If a conversion specifier is not one of the above, the behavior is
-undefined.
-.SH RETURNS
-If the total number of resulting characters including the terminating null
-character is not more than
-.BR maxsize ,
-the
-.B strftime
-function returns the number of characters placed into the array pointed to
-by
-.B s
-not including the terminating null character.
-Otherwise, zero is returned and the contents of the array are indeterminate.
-.SH ISO 8601
-The method for determining the week number as specified by ISO 8601 is:
-if the week containing January 1 has four or more days in the
-new year, then it is week 1, otherwise it is the highest numbered
-week of the previous year (52 or 53)
-and the next week is week 1.
-All days in a new year preceding the first Monday are considered to be
-in week 0.
-.PP
-For example, January 1, 1993, is in week 53 of 1992. Thus, the year
-of its ISO week number is 1992, even though its year is 1993.
-Similarly, December 31, 1973, is in week 1 of 1974. Thus, the year
-of its ISO week number is 1974, even though its year is 1973.
-.SH ALTERNATE REPRESENTATIONS
-The alternate representations
-.BR %Ec ,
-.BR %EC ,
-.BR %Ex ,
-.BR %EX ,
-.BR %Ey ,
-.BR %EY ,
-.BR %Od ,
-.BR %Oe ,
-.BR %OH ,
-.BR %OI ,
-.BR %Om ,
-.BR %OM ,
-.BR %OS ,
-.BR %Ou ,
-.BR %OU ,
-.BR %OV ,
-.BR %Ow ,
-.BR %OW ,
-and
-.B %Oy
-are recognized, but their normal representations are used.
-.SH NON-ISO EXTENSIONS
-.SS SunOS Extensions
-If
-.B SUNOS_EXT
-is defined when the routine is compiled, then the following additional
-conversions will be available.
-These are borrowed from the SunOS version of
-.IR strftime .
-.TP
-.B %k
-is replaced by the hour (24-hour clock) as a decimal number
-.RB ( 0 - 23 ).
-Single digit numbers are padded with a blank.
-.TP
-.B %l
-is replaced by the hour (12-hour clock) as a decimal number
-.RB ( 1 - 12 ).
-Single digit numbers are padded with a blank.
-.SS HP/UX Extensions
-If
-.B HPUX_EXT
-is defined when the routine is compiled, then the following additional
-conversions will be available.
-These are borrowed from the HP-UX version of
-.IR date .
-.TP
-.B %N
-The ``Emporer/Era'' name.
-Typically, this is equivalent to the century
-(same as
-.B %C ).
-.TP
-.B %o
-The ``Emporer/Era'' year.
-Typically, this is equivalent to the year
-(same as
-.B %y ).
-.SS VMS Extensions
-If
-.B VMS_EXT
-is defined, then the following additional conversion is available:
-.TP
-.B %v
-The date in VMS format (e.g. 20-JUN-1991).
-.SS Other Extensions
-If
-.B HAVE_MKTIME
-is defined, then this conversion is available:
-.TP
-.B %s
-The time in ``seconds since the Epoch,''
-usually Midnight January 1, 1970, UTC.
-.SH SEE ALSO
-.IR time (2),
-.IR ctime (3),
-.IR localtime (3),
-.IR mktime (3),
-.IR tzset (3)
-.SH BUGS
-This version does not handle multibyte characters or pay attention to the
-setting of the
-.B LC_TIME
-environment variable.
-.LP
-The ``appropriate'' values used for
-.BR %c ,
-.BR %x ,
-are
-.B %X
-are always those specified by the 1999 ISO C standard for the \fB"C"\fR locale.
-.SH CAVEATS
-The pre-processor symbol
-.B POSIX_SEMANTICS
-is automatically defined, which forces the code to call
-.IR tzset (3)
-whenever the
-.B TZ
-environment variable has changed.
-If this routine will be used in an application that will not be changing
-.BR TZ ,
-then there may be some performance improvements by not defining
-.BR POSIX_SEMANTICS .
-.SH AUTHOR
-Arnold Robbins <arnold@skeeve.com>
-.SH ACKNOWLEDGEMENTS
-Thanks to Geoff Clare <gwc@root.co.uk> for helping debug earlier
-versions of this routine, and for advice about POSIX semantics.
-Additional thanks to Arthur David Olsen <ado@elsie.nci.nih.gov>
-for some code improvements.
-Thanks also to Tor Lillqvist <tml@tik.vtt.fi>
-for code fixes to the ISO 8601 code.
-Thanks to Hume Smith for pointing out a problem with the ISO 8601 code
-and to Arthur David Olsen for further discussions.
diff --git a/missing_d/strftime.c b/missing_d/strftime.c
index d291e8fd..18350461 100644
--- a/missing_d/strftime.c
+++ b/missing_d/strftime.c
@@ -1,850 +1,1411 @@
-/*
- * strftime.c
- *
- * Public-domain implementation of ISO C library routine.
- *
- * If you can't do prototypes, get GCC.
- *
- * The C99 standard now specifies just about all of the formats
- * that were additional in the earlier versions of this file.
- *
- * For extensions from SunOS, add SUNOS_EXT.
- * For extensions from HP/UX, add HPUX_EXT.
- * For VMS dates, add VMS_EXT.
- * For complete POSIX semantics, add POSIX_SEMANTICS.
- *
- * The code for %c, %x, and %X follows the C99 specification for
- * the "C" locale.
- *
- * This version ignores LOCALE information.
- * It also doesn't worry about multi-byte characters.
- * So there.
- *
- * This file is also shipped with GAWK (GNU Awk), gawk specific bits of
- * code are included if GAWK is defined.
- *
- * Arnold Robbins
- * January, February, March, 1991
- * Updated March, April 1992
- * Updated April, 1993
- * Updated February, 1994
- * Updated May, 1994
- * Updated January, 1995
- * Updated September, 1995
- * Updated January, 1996
- * Updated July, 1997
- * Updated October, 1999
- * Updated September, 2000
- *
- * Fixes from ado@elsie.nci.nih.gov,
- * February 1991, May 1992
- * Fixes from Tor Lillqvist tml@tik.vtt.fi,
- * May 1993
- * Further fixes from ado@elsie.nci.nih.gov,
- * February 1994
- * %z code from chip@chinacat.unicom.com,
- * Applied September 1995
- * %V code fixed (again) and %G, %g added,
- * January 1996
- * %v code fixed, better configuration,
- * July 1997
- * Moved to C99 specification.
- * September 2000
- */
-
-#ifndef GAWK
-#include <stdio.h>
+/* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define HAVE_LIMITS_H 1
+# define HAVE_MBLEN 1
+# define HAVE_MBRLEN 1
+# define HAVE_STRUCT_ERA_ENTRY 1
+# define HAVE_TM_GMTOFF 1
+# define HAVE_TM_ZONE 1
+# define HAVE_TZNAME 1
+# define HAVE_TZSET 1
+# define MULTIBYTE_IS_FORMAT_SAFE 1
+# define STDC_HEADERS 1
+# include "../locale/localeinfo.h"
+#endif
+
+#if defined emacs && !defined HAVE_BCOPY
+# define HAVE_MEMCPY 1
+#endif
+
#include <ctype.h>
-#include <time.h>
+#ifdef TIME_T_IN_SYS_TYPES_H
+#include <sys/types.h> /* Some systems define `time_t' here. */
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
#endif
-#if defined(TM_IN_SYS_TIME) || ! defined(GAWK)
-#include <sys/types.h>
-#include <sys/time.h>
+#if HAVE_TZNAME
+extern char *tzname[];
#endif
-#include <stdlib.h>
-#include <string.h>
+/* Do multibyte processing if multibytes are supported, unless
+ multibyte sequences are safe in formats. Multibyte sequences are
+ safe if they cannot contain byte sequences that look like format
+ conversion specifications. The GNU C Library uses UTF8 multibyte
+ encoding, which is safe for formats, but strftime.c can be used
+ with other C libraries that use unsafe encodings. */
+#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
+
+#if DO_MULTIBYTE
+# if HAVE_MBRLEN
+# include <wchar.h>
+# else
+ /* Simulate mbrlen with mblen as best we can. */
+# define mbstate_t int
+# define mbrlen(s, n, ps) mblen (s, n)
+# define mbsinit(ps) (*(ps) == 0)
+# endif
+ static const mbstate_t mbstate_zero;
+#endif
-/* defaults: season to taste */
-#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */
-#define VMS_EXT 1 /* include %v for VMS date format */
-#define HPUX_EXT 1 /* non-conflicting stuff in HP-UX date */
-#ifndef GAWK
-#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */
+#if HAVE_LIMITS_H
+# include <limits.h>
#endif
-#undef strchr /* avoid AIX weirdness */
+#if STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
-extern void tzset(void);
-static int weeknumber(const struct tm *timeptr, int firstweekday);
-static int iso8601wknum(const struct tm *timeptr);
+#undef TOUPPER
+#undef TOLOWER
+#undef ISDIGIT
+#ifdef COMPILE_WIDE
+# include <endian.h>
+# define CHAR_T wchar_t
+# define UCHAR_T unsigned int
+# define L_(Str) L##Str
+# define NLW(Sym) _NL_W##Sym
+
+# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
+# define STRLEN(s) __wcslen (s)
-#ifdef __GNUC__
-#define inline __inline__
#else
-#define inline /**/
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define L_(Str) Str
+# define NLW(Sym) Sym
+
+# if !defined STDC_HEADERS && !defined HAVE_MEMCPY
+# define MEMCPY(d, s, n) bcopy ((s), (d), (n))
+# else
+# define MEMCPY(d, s, n) memcpy ((d), (s), (n))
+# endif
+# define STRLEN(s) strlen (s)
+
+# ifdef _LIBC
+# define MEMPCPY(d, s, n) __mempcpy (d, s, n)
+# else
+# ifndef HAVE_MEMPCPY
+# define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
+# endif
+# endif
+#endif
+
+#ifndef __P
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+#ifndef PTR
+# ifdef __STDC__
+# define PTR void *
+# else
+# define PTR char *
+# endif
+#endif
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#ifndef NULL
+# define NULL 0
#endif
-#define range(low, item, hi) max(low, min(item, hi))
+#define TYPE_SIGNED(t) ((t) -1 < 0)
+
+/* Bound on length of the string representing an integer value of type t.
+ Subtract one for the sign bit if t is signed;
+ 302 / 1000 is log10 (2) rounded up;
+ add one for integer division truncation;
+ add one more for a minus sign if t is signed. */
+#define INT_STRLEN_BOUND(t) \
+ ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
+
+#define TM_YEAR_BASE 1900
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+
+#ifdef _LIBC
+# define my_strftime_gmtime_r __gmtime_r
+# define my_strftime_localtime_r __localtime_r
+# define tzname __tzname
+# define tzset __tzset
+#else
+
+/* If we're a strftime substitute in a GNU program, then prefer gmtime
+ to gmtime_r, since many gmtime_r implementations are buggy.
+ Similarly for localtime_r. */
+
+# if ! HAVE_TM_GMTOFF
+static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+my_strftime_gmtime_r (t, tp)
+ const time_t *t;
+ struct tm *tp;
+{
+ struct tm *l = gmtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+# endif /* ! HAVE_TM_GMTOFF */
+
+static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+my_strftime_localtime_r (t, tp)
+ const time_t *t;
+ struct tm *tp;
+{
+ struct tm *l = localtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+#endif /* ! defined _LIBC */
+
+
+#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
+/* Some systems lack the `memset' function and we don't want to
+ introduce additional dependencies. */
+/* The SGI compiler reportedly barfs on the trailing null
+ if we use a string constant as the initializer. 28 June 1997, rms. */
+static const CHAR_T spaces[16] = /* " " */
+{
+ L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
+ L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
+};
+static const CHAR_T zeroes[16] = /* "0000000000000000" */
+{
+ L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
+ L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
+};
-#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME)
-extern char *tzname[2];
-extern int daylight;
-#if defined(SOLARIS) || defined(mips)
-extern long int timezone, altzone;
+# define memset_space(P, Len) \
+ do { \
+ int _len = (Len); \
+ \
+ do \
+ { \
+ int _this = _len > 16 ? 16 : _len; \
+ (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
+ _len -= _this; \
+ } \
+ while (_len > 0); \
+ } while (0)
+
+# define memset_zero(P, Len) \
+ do { \
+ int _len = (Len); \
+ \
+ do \
+ { \
+ int _this = _len > 16 ? 16 : _len; \
+ (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
+ _len -= _this; \
+ } \
+ while (_len > 0); \
+ } while (0)
#else
-extern int timezone, altzone;
+# ifdef COMPILE_WIDE
+# define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
+# define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
+# else
+# define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
+# define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
+# endif
#endif
+
+#define add(n, f) \
+ do \
+ { \
+ int _n = (n); \
+ int _delta = width - _n; \
+ int _incr = _n + (_delta > 0 ? _delta : 0); \
+ if (i + _incr >= maxsize) \
+ return 0; \
+ if (p) \
+ { \
+ if (_delta > 0) \
+ { \
+ if (pad == L_('0')) \
+ memset_zero (p, _delta); \
+ else \
+ memset_space (p, _delta); \
+ } \
+ f; \
+ p += _n; \
+ } \
+ i += _incr; \
+ } while (0)
+
+#define cpy(n, s) \
+ add ((n), \
+ if (to_lowcase) \
+ memcpy_lowcase (p, (s), _n); \
+ else if (to_uppcase) \
+ memcpy_uppcase (p, (s), _n); \
+ else \
+ MEMCPY ((PTR) p, (const PTR) (s), _n))
+
+#ifdef COMPILE_WIDE
+# define widen(os, ws, l) \
+ { \
+ mbstate_t __st; \
+ const char *__s = os; \
+ memset (&__st, '\0', sizeof (__st)); \
+ l = __mbsrtowcs (NULL, &__s, 0, &__st); \
+ ws = alloca ((l + 1) * sizeof (wchar_t)); \
+ (void) __mbsrtowcs (ws, &__s, l, &__st); \
+ }
#endif
-#undef min /* just in case */
-/* min --- return minimum of two numbers */
+#ifdef COMPILE_WIDE
+# define TOUPPER(Ch) towupper (Ch)
+# define TOLOWER(Ch) towlower (Ch)
+#else
+# ifdef _LIBC
+# define TOUPPER(Ch) toupper (Ch)
+# define TOLOWER(Ch) tolower (Ch)
+# else
+# define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
+# define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
+# endif
+#endif
+/* We don't use `isdigit' here since the locale dependent
+ interpretation is not what we want here. We only need to accept
+ the arabic digits in the ASCII range. One day there is perhaps a
+ more reliable way to accept other sets of digits. */
+#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
+
+static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
+ size_t len));
+
+static CHAR_T *
+memcpy_lowcase (dest, src, len)
+ CHAR_T *dest;
+ const CHAR_T *src;
+ size_t len;
+{
+ while (len-- > 0)
+ dest[len] = TOLOWER ((UCHAR_T) src[len]);
+ return dest;
+}
+
+static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
+ size_t len));
+
+static CHAR_T *
+memcpy_uppcase (dest, src, len)
+ CHAR_T *dest;
+ const CHAR_T *src;
+ size_t len;
+{
+ while (len-- > 0)
+ dest[len] = TOUPPER ((UCHAR_T) src[len]);
+ return dest;
+}
+
-static inline int
-min(int a, int b)
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds. */
+# define tm_diff ftime_tm_diff
+static int tm_diff __P ((const struct tm *, const struct tm *));
+static int
+tm_diff (a, b)
+ const struct tm *a;
+ const struct tm *b;
{
- return (a < b ? a : b);
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+ int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
}
+#endif /* ! HAVE_TM_GMTOFF */
-#undef max /* also, just in case */
-/* max --- return maximum of two numbers */
-static inline int
-max(int a, int b)
+/* The number of days from the first day of the first ISO week of this
+ year to the year day YDAY with week day WDAY. ISO weeks start on
+ Monday; the first ISO week has the year's first Thursday. YDAY may
+ be as small as YDAY_MINIMUM. */
+#define ISO_WEEK_START_WDAY 1 /* Monday */
+#define ISO_WEEK1_WDAY 4 /* Thursday */
+#define YDAY_MINIMUM (-366)
+static int iso_week_days __P ((int, int));
+#ifdef __GNUC__
+__inline__
+#endif
+static int
+iso_week_days (yday, wday)
+ int yday;
+ int wday;
{
- return (a > b ? a : b);
+ /* Add enough to the first operand of % to make it nonnegative. */
+ int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
+ return (yday
+ - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
+ + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
}
-/* strftime --- produce formatted time */
+#if !(defined _NL_CURRENT || HAVE_STRFTIME)
+static CHAR_T const weekday_name[][10] =
+ {
+ L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
+ L_("Thursday"), L_("Friday"), L_("Saturday")
+ };
+static CHAR_T const month_name[][10] =
+ {
+ L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
+ L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
+ L_("November"), L_("December")
+ };
+#endif
+
+
+/* When compiling this file, GNU applications can #define my_strftime
+ to a symbol (typically nstrftime) to get an extended strftime with
+ extra arguments UT and NS. Emacs is a special case for now, but
+ this Emacs-specific code can be removed once Emacs's config.h
+ defines my_strftime. */
+#if defined emacs && !defined my_strftime
+# define my_strftime nstrftime
+#endif
+
+#ifdef my_strftime
+# define extra_args , ut, ns
+# define extra_args_spec int ut; int ns;
+# define extra_args_spec_iso , int ut, int ns
+#else
+# ifdef COMPILE_WIDE
+# define my_strftime wcsftime
+# else
+# define my_strftime strftime
+# endif
+# define extra_args
+# define extra_args_spec
+# define extra_args_spec_iso
+/* We don't have this information in general. */
+# define ut 0
+# define ns 0
+#endif
+
+#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
+ /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
+ Work around this bug by copying *tp before it might be munged. */
+ size_t _strftime_copytm __P ((char *, size_t, const char *,
+ const struct tm * extra_args_spec_iso));
+ size_t
+ my_strftime (s, maxsize, format, tp extra_args)
+ CHAR_T *s;
+ size_t maxsize;
+ const CHAR_T *format;
+ const struct tm *tp;
+ extra_args_spec
+ {
+ struct tm tmcopy;
+ tmcopy = *tp;
+ return _strftime_copytm (s, maxsize, format, &tmcopy extra_args);
+ }
+# undef my_strftime
+# define my_strftime _strftime_copytm
+#endif
+
+
+/* Write information from TP into S according to the format
+ string FORMAT, writing no more that MAXSIZE characters
+ (including the terminating '\0') and returning number of
+ characters written. If S is NULL, nothing will be written
+ anywhere, so to determine how many characters would be
+ written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
size_t
-strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
+my_strftime (s, maxsize, format, tp extra_args)
+ CHAR_T *s;
+ size_t maxsize;
+ const CHAR_T *format;
+ const struct tm *tp;
+ extra_args_spec
{
- char *endp = s + maxsize;
- char *start = s;
- auto char tbuf[100];
- long off;
- int i, w, y;
- static short first = 1;
-#ifdef POSIX_SEMANTICS
- static char *savetz = NULL;
- static int savetzlen = 0;
- char *tz;
-#endif /* POSIX_SEMANTICS */
-#ifndef HAVE_TM_ZONE
-#ifndef HAVE_TM_NAME
-#ifndef HAVE_TZNAME
- extern char *timezone();
- struct timeval tv;
- struct timezone zone;
-#endif /* HAVE_TZNAME */
-#endif /* HAVE_TM_NAME */
-#endif /* HAVE_TM_ZONE */
-
- /* various tables, useful in North America */
- static const char *days_a[] = {
- "Sun", "Mon", "Tue", "Wed",
- "Thu", "Fri", "Sat",
- };
- static const char *days_l[] = {
- "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday",
- };
- static const char *months_a[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- };
- static const char *months_l[] = {
- "January", "February", "March", "April",
- "May", "June", "July", "August", "September",
- "October", "November", "December",
- };
- static const char *ampm[] = { "AM", "PM", };
-
- if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
- return 0;
-
- /* quick check if we even need to bother */
- if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize)
- return 0;
-
-#ifndef POSIX_SEMANTICS
- if (first) {
- tzset();
- first = 0;
+ int hour12 = tp->tm_hour;
+#ifdef _NL_CURRENT
+ /* We cannot make the following values variables since we must delay
+ the evaluation of these values until really needed since some
+ expressions might not be valid in every situation. The `struct tm'
+ might be generated by a strptime() call that initialized
+ only a few elements. Dereference the pointers only if the format
+ requires this. Then it is ok to fail if the pointers are invalid. */
+# define a_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
+# define f_wkday \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
+# define a_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
+# define f_month \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
+# define ampm \
+ ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
+ ? NLW(PM_STR) : NLW(AM_STR)))
+
+# define aw_len STRLEN (a_wkday)
+# define am_len STRLEN (a_month)
+# define ap_len STRLEN (ampm)
+#else
+# if !HAVE_STRFTIME
+# define f_wkday (weekday_name[tp->tm_wday])
+# define f_month (month_name[tp->tm_mon])
+# define a_wkday f_wkday
+# define a_month f_month
+# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
+
+ size_t aw_len = 3;
+ size_t am_len = 3;
+ size_t ap_len = 2;
+# endif
+#endif
+ const char *zone;
+ size_t i = 0;
+ CHAR_T *p = s;
+ const CHAR_T *f;
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ const char *format_end = NULL;
+#endif
+
+ zone = NULL;
+#if HAVE_TM_ZONE
+ /* The POSIX test suite assumes that setting
+ the environment variable TZ to a new value before calling strftime()
+ will influence the result (the %Z format) even if the information in
+ TP is computed with a totally different time zone.
+ This is bogus: though POSIX allows bad behavior like this,
+ POSIX does not require it. Do the right thing instead. */
+ zone = (const char *) tp->tm_zone;
+#endif
+#if HAVE_TZNAME
+ if (ut)
+ {
+ if (! (zone && *zone))
+ zone = "GMT";
+ }
+ else
+ {
+ /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
+ time zone names contained in the external variable `tzname' shall
+ be set as if the tzset() function had been called. */
+# if HAVE_TZSET
+ tzset ();
+# endif
+ }
+#endif
+
+ if (hour12 > 12)
+ hour12 -= 12;
+ else
+ if (hour12 == 0)
+ hour12 = 12;
+
+ for (f = format; *f != '\0'; ++f)
+ {
+ int pad = 0; /* Padding for number ('-', '_', or 0). */
+ int modifier; /* Field modifier ('E', 'O', or 0). */
+ int digits; /* Max digits for numeric format. */
+ int number_value; /* Numeric value to be printed. */
+ int negative_number; /* 1 if the number is negative. */
+ const CHAR_T *subfmt;
+ CHAR_T *bufp;
+ CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
+ ? INT_STRLEN_BOUND (time_t)
+ : INT_STRLEN_BOUND (int))];
+ int width = -1;
+ int to_lowcase = 0;
+ int to_uppcase = 0;
+ int change_case = 0;
+ int format_char;
+
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+ switch (*f)
+ {
+ case L_('%'):
+ break;
+
+ case L_('\b'): case L_('\t'): case L_('\n'):
+ case L_('\v'): case L_('\f'): case L_('\r'):
+ case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
+ case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
+ case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
+ case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
+ case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
+ case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
+ case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
+ case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
+ case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
+ case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
+ case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
+ case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
+ case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
+ case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
+ case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
+ case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
+ case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
+ case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
+ case L_('~'):
+ /* The C Standard requires these 98 characters (plus '%') to
+ be in the basic execution character set. None of these
+ characters can start a multibyte sequence, so they need
+ not be analyzed further. */
+ add (1, *p = *f);
+ continue;
+
+ default:
+ /* Copy this multibyte sequence until we reach its end, find
+ an error, or come back to the initial shift state. */
+ {
+ mbstate_t mbstate = mbstate_zero;
+ size_t len = 0;
+ size_t fsize;
+
+ if (! format_end)
+ format_end = f + strlen (f) + 1;
+ fsize = format_end - f;
+
+ do
+ {
+ size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
+
+ if (bytes == 0)
+ break;
+
+ if (bytes == (size_t) -2)
+ {
+ len += strlen (f + len);
+ break;
+ }
+
+ if (bytes == (size_t) -1)
+ {
+ len++;
+ break;
+ }
+
+ len += bytes;
+ }
+ while (! mbsinit (&mbstate));
+
+ cpy (len, f);
+ f += len - 1;
+ continue;
+ }
}
-#else /* POSIX_SEMANTICS */
- tz = getenv("TZ");
- if (first) {
- if (tz != NULL) {
- int tzlen = strlen(tz);
-
- savetz = (char *) malloc(tzlen + 1);
- if (savetz != NULL) {
- savetzlen = tzlen + 1;
- strcpy(savetz, tz);
- }
- }
- tzset();
- first = 0;
+
+#else /* ! DO_MULTIBYTE */
+
+ /* Either multibyte encodings are not supported, they are
+ safe for formats, so any non-'%' byte can be copied through,
+ or this is the wide character version. */
+ if (*f != L_('%'))
+ {
+ add (1, *p = *f);
+ continue;
}
- /* if we have a saved TZ, and it is different, recapture and reset */
- if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) {
- i = strlen(tz) + 1;
- if (i > savetzlen) {
- savetz = (char *) realloc(savetz, i);
- if (savetz) {
- savetzlen = i;
- strcpy(savetz, tz);
- }
- } else
- strcpy(savetz, tz);
- tzset();
+
+#endif /* ! DO_MULTIBYTE */
+
+ /* Check for flags that can modify a format. */
+ while (1)
+ {
+ switch (*++f)
+ {
+ /* This influences the number formats. */
+ case L_('_'):
+ case L_('-'):
+ case L_('0'):
+ pad = *f;
+ continue;
+
+ /* This changes textual output. */
+ case L_('^'):
+ to_uppcase = 1;
+ continue;
+ case L_('#'):
+ change_case = 1;
+ continue;
+
+ default:
+ break;
+ }
+ break;
}
-#endif /* POSIX_SEMANTICS */
- for (; *format && s < endp - 1; format++) {
- tbuf[0] = '\0';
- if (*format != '%') {
- *s++ = *format;
- continue;
- }
- again:
- switch (*++format) {
- case '\0':
- *s++ = '%';
- goto out;
-
- case '%':
- *s++ = '%';
- continue;
-
- case 'a': /* abbreviated weekday name */
- if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
- strcpy(tbuf, "?");
- else
- strcpy(tbuf, days_a[timeptr->tm_wday]);
- break;
-
- case 'A': /* full weekday name */
- if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
- strcpy(tbuf, "?");
- else
- strcpy(tbuf, days_l[timeptr->tm_wday]);
- break;
-
- case 'b': /* abbreviated month name */
- short_month:
- if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
- strcpy(tbuf, "?");
- else
- strcpy(tbuf, months_a[timeptr->tm_mon]);
- break;
-
- case 'B': /* full month name */
- if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
- strcpy(tbuf, "?");
- else
- strcpy(tbuf, months_l[timeptr->tm_mon]);
- break;
-
- case 'c': /* appropriate date and time representation */
- /*
- * This used to be:
- *
- * strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr);
- *
- * Now, per the ISO 1999 C standard, it this:
- */
- strftime(tbuf, sizeof tbuf, "%A %B %d %T %Y", timeptr);
- break;
-
- case 'C':
- century:
- sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
- break;
-
- case 'd': /* day of the month, 01 - 31 */
- i = range(1, timeptr->tm_mday, 31);
- sprintf(tbuf, "%02d", i);
- break;
-
- case 'D': /* date as %m/%d/%y */
- strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
- break;
-
- case 'e': /* day of month, blank padded */
- sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
- break;
-
- case 'E':
- /* POSIX (now C99) locale extensions, ignored for now */
- goto again;
-
- case 'F': /* ISO 8601 date representation */
- strftime(tbuf, sizeof tbuf, "%Y-%m-%d", timeptr);
- break;
-
- case 'g':
- case 'G':
- /*
- * Year of ISO week.
- *
- * If it's December but the ISO week number is one,
- * that week is in next year.
- * If it's January but the ISO week number is 52 or
- * 53, that week is in last year.
- * Otherwise, it's this year.
- */
- w = iso8601wknum(timeptr);
- if (timeptr->tm_mon == 11 && w == 1)
- y = 1900 + timeptr->tm_year + 1;
- else if (timeptr->tm_mon == 0 && w >= 52)
- y = 1900 + timeptr->tm_year - 1;
- else
- y = 1900 + timeptr->tm_year;
-
- if (*format == 'G')
- sprintf(tbuf, "%d", y);
- else
- sprintf(tbuf, "%02d", y % 100);
- break;
-
- case 'h': /* abbreviated month name */
- goto short_month;
-
- case 'H': /* hour, 24-hour clock, 00 - 23 */
- i = range(0, timeptr->tm_hour, 23);
- sprintf(tbuf, "%02d", i);
- break;
-
- case 'I': /* hour, 12-hour clock, 01 - 12 */
- i = range(0, timeptr->tm_hour, 23);
- if (i == 0)
- i = 12;
- else if (i > 12)
- i -= 12;
- sprintf(tbuf, "%02d", i);
- break;
-
- case 'j': /* day of the year, 001 - 366 */
- sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
- break;
-
- case 'm': /* month, 01 - 12 */
- i = range(0, timeptr->tm_mon, 11);
- sprintf(tbuf, "%02d", i + 1);
- break;
-
- case 'M': /* minute, 00 - 59 */
- i = range(0, timeptr->tm_min, 59);
- sprintf(tbuf, "%02d", i);
- break;
-
- case 'n': /* same as \n */
- tbuf[0] = '\n';
- tbuf[1] = '\0';
- break;
-
- case 'O':
- /* POSIX (now C99) locale extensions, ignored for now */
- goto again;
-
- case 'p': /* am or pm based on 12-hour clock */
- i = range(0, timeptr->tm_hour, 23);
- if (i < 12)
- strcpy(tbuf, ampm[0]);
- else
- strcpy(tbuf, ampm[1]);
- break;
-
- case 'r': /* time as %I:%M:%S %p */
- strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
- break;
-
- case 'R': /* time as %H:%M */
- strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
- break;
-
-#if defined(HAVE_MKTIME) || defined(GAWK)
- case 's': /* time as seconds since the Epoch */
+ /* As a GNU extension we allow to specify the field width. */
+ if (ISDIGIT (*f))
+ {
+ width = 0;
+ do
+ {
+ width *= 10;
+ width += *f - L_('0');
+ ++f;
+ }
+ while (ISDIGIT (*f));
+ }
+
+ /* Check for modifiers. */
+ switch (*f)
+ {
+ case L_('E'):
+ case L_('O'):
+ modifier = *f++;
+ break;
+
+ default:
+ modifier = 0;
+ break;
+ }
+
+ /* Now do the specified format. */
+ format_char = *f;
+ switch (format_char)
+ {
+#define DO_NUMBER(d, v) \
+ digits = width == -1 ? d : width; \
+ number_value = v; goto do_number
+#define DO_NUMBER_SPACEPAD(d, v) \
+ digits = width == -1 ? d : width; \
+ number_value = v; goto do_number_spacepad
+
+ case L_('%'):
+ if (modifier != 0)
+ goto bad_format;
+ add (1, *p = *f);
+ break;
+
+ case L_('a'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (aw_len, a_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case 'A':
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_wkday), f_wkday);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('b'):
+ case L_('h'): /* POSIX.2 extension. */
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+ if (modifier != 0)
+ goto bad_format;
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (am_len, a_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('B'):
+ if (modifier != 0)
+ goto bad_format;
+ if (change_case)
+ {
+ to_uppcase = 1;
+ to_lowcase = 0;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (STRLEN (f_month), f_month);
+ break;
+#else
+ goto underlying_strftime;
+#endif
+
+ case L_('c'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == 'E'
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(ERA_D_T_FMT)))
+ != '\0')))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ subfmt = L_("%a %b %e %H:%M:%S %Y");
+# endif
+#endif
+
+ subformat:
+ {
+ CHAR_T *old_start = p;
+ size_t len = my_strftime (NULL, (size_t) -1, subfmt,
+ tp extra_args);
+ add (len, my_strftime (p, maxsize - i, subfmt,
+ tp extra_args));
+
+ if (to_uppcase)
+ while (old_start < p)
{
- struct tm non_const_timeptr;
+ *old_start = TOUPPER ((UCHAR_T) *old_start);
+ ++old_start;
+ }
+ }
+ break;
+
+#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
+ underlying_strftime:
+ {
+ /* The relevant information is available only via the
+ underlying strftime implementation, so use that. */
+ char ufmt[4];
+ char *u = ufmt;
+ char ubuf[1024]; /* enough for any single format in practice */
+ size_t len;
+ /* Make sure we're calling the actual underlying strftime.
+ In some cases, config.h contains something like
+ "#define strftime rpl_strftime". */
+# ifdef strftime
+# undef strftime
+ size_t strftime ();
+# endif
+
+ *u++ = '%';
+ if (modifier != 0)
+ *u++ = modifier;
+ *u++ = format_char;
+ *u = '\0';
+ len = strftime (ubuf, sizeof ubuf, ufmt, tp);
+ if (len == 0 && ubuf[0] != '\0')
+ return 0;
+ cpy (len, ubuf);
+ }
+ break;
+#endif
- non_const_timeptr = *timeptr;
- sprintf(tbuf, "%ld", mktime(& non_const_timeptr));
- break;
+ case L_('C'): /* POSIX.2 extension. */
+ if (modifier == L_('O'))
+ goto bad_format;
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ size_t len = __wcslen (era->era_wname);
+ cpy (len, era->era_wname);
+# else
+ size_t len = strlen (era->era_name);
+ cpy (len, era->era_name);
+# endif
+ break;
}
-#endif /* defined(HAVE_MKTIME) || defined(GAWK) */
-
- case 'S': /* second, 00 - 60 */
- i = range(0, timeptr->tm_sec, 60);
- sprintf(tbuf, "%02d", i);
- break;
-
- case 't': /* same as \t */
- tbuf[0] = '\t';
- tbuf[1] = '\0';
- break;
-
- case 'T': /* time as %H:%M:%S */
- the_time:
- strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
- break;
-
- case 'u':
- /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */
- sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 :
- timeptr->tm_wday);
- break;
-
- case 'U': /* week of year, Sunday is first day of week */
- sprintf(tbuf, "%02d", weeknumber(timeptr, 0));
- break;
-
- case 'V': /* week of year according ISO 8601 */
- sprintf(tbuf, "%02d", iso8601wknum(timeptr));
- break;
-
- case 'w': /* weekday, Sunday == 0, 0 - 6 */
- i = range(0, timeptr->tm_wday, 6);
- sprintf(tbuf, "%d", i);
- break;
-
- case 'W': /* week of year, Monday is first day of week */
- sprintf(tbuf, "%02d", weeknumber(timeptr, 1));
- break;
-
- case 'x': /* appropriate date representation */
- strftime(tbuf, sizeof tbuf, "%A %B %d %Y", timeptr);
- break;
-
- case 'X': /* appropriate time representation */
- goto the_time;
- break;
-
- case 'y': /* year without a century, 00 - 99 */
- year:
- i = timeptr->tm_year % 100;
- sprintf(tbuf, "%02d", i);
- break;
-
- case 'Y': /* year with century */
- fullyear:
- sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
- break;
-
- /*
- * From: Chip Rosenthal <chip@chinacat.unicom.com>
- * Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST)
- *
- * Warning: the %z [code] is implemented by inspecting the
- * timezone name conditional compile settings, and
- * inferring a method to get timezone offsets. I've tried
- * this code on a couple of machines, but I don't doubt
- * there is some system out there that won't like it.
- * Maybe the easiest thing to do would be to bracket this
- * with an #ifdef that can turn it off. The %z feature
- * would be an admittedly obscure one that most folks can
- * live without, but it would be a great help to those of
- * us that muck around with various message processors.
- */
- case 'z': /* time zone offset east of GMT e.g. -0600 */
-#ifdef HAVE_TM_NAME
- /*
- * Systems with tm_name probably have tm_tzadj as
- * secs west of GMT. Convert to mins east of GMT.
- */
- off = -timeptr->tm_tzadj / 60;
-#else /* !HAVE_TM_NAME */
-#ifdef HAVE_TM_ZONE
- /*
- * Systems with tm_zone probably have tm_gmtoff as
- * secs east of GMT. Convert to mins east of GMT.
- */
- off = timeptr->tm_gmtoff / 60;
-#else /* !HAVE_TM_ZONE */
-#if HAVE_TZNAME
- /*
- * Systems with tzname[] probably have timezone as
- * secs west of GMT. Convert to mins east of GMT.
- */
- off = -(daylight ? timezone : altzone) / 60;
-#else /* !HAVE_TZNAME */
- off = -zone.tz_minuteswest;
-#endif /* !HAVE_TZNAME */
-#endif /* !HAVE_TM_ZONE */
-#endif /* !HAVE_TM_NAME */
- if (off < 0) {
- tbuf[0] = '-';
- off = -off;
- } else {
- tbuf[0] = '+';
- }
- sprintf(tbuf+1, "%02d%02d", off/60, off%60);
- break;
-
- case 'Z': /* time zone name or abbrevation */
-#ifdef HAVE_TZNAME
- i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */
- strcpy(tbuf, tzname[i]);
#else
-#ifdef HAVE_TM_ZONE
- strcpy(tbuf, timeptr->tm_zone);
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+
+ {
+ int year = tp->tm_year + TM_YEAR_BASE;
+ DO_NUMBER (1, year / 100 - (year % 100 < 0));
+ }
+
+ case L_('x'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
+ goto subformat;
#else
-#ifdef HAVE_TM_NAME
- strcpy(tbuf, timeptr->tm_name);
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('D'): /* POSIX.2 extension. */
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%m/%d/%y");
+ goto subformat;
+
+ case L_('d'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_mday);
+
+ case L_('e'): /* POSIX.2 extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER_SPACEPAD (2, tp->tm_mday);
+
+ /* All numeric formats set DIGITS and NUMBER_VALUE and then
+ jump to one of these two labels. */
+
+ do_number_spacepad:
+ /* Force `_' flag unless overwritten by `0' flag. */
+ if (pad != L_('0'))
+ pad = L_('_');
+
+ do_number:
+ /* Format the number according to the MODIFIER flag. */
+
+ if (modifier == L_('O') && 0 <= number_value)
+ {
+#ifdef _NL_CURRENT
+ /* Get the locale specific alternate representation of
+ the number NUMBER_VALUE. If none exist NULL is returned. */
+# ifdef COMPILE_WIDE
+ const wchar_t *cp = _nl_get_walt_digit (number_value);
+# else
+ const char *cp = _nl_get_alt_digit (number_value);
+# endif
+
+ if (cp != NULL)
+ {
+ size_t digitlen = STRLEN (cp);
+ if (digitlen != 0)
+ {
+ cpy (digitlen, cp);
+ break;
+ }
+ }
#else
- gettimeofday(& tv, & zone);
- strcpy(tbuf, timezone(zone.tz_minuteswest,
- timeptr->tm_isdst > 0));
-#endif /* HAVE_TM_NAME */
-#endif /* HAVE_TM_ZONE */
-#endif /* HAVE_TZNAME */
- break;
-
-#ifdef SUNOS_EXT
- case 'k': /* hour, 24-hour clock, blank pad */
- sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
- break;
-
- case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */
- i = range(0, timeptr->tm_hour, 23);
- if (i == 0)
- i = 12;
- else if (i > 12)
- i -= 12;
- sprintf(tbuf, "%2d", i);
- break;
-#endif
-
-#ifdef HPUX_EXT
- case 'N': /* Emperor/Era name */
- /* this is essentially the same as the century */
- goto century; /* %C */
-
- case 'o': /* Emperor/Era year */
- goto year; /* %y */
-#endif /* HPUX_EXT */
-
-
-#ifdef VMS_EXT
- case 'v': /* date as dd-bbb-YYYY */
- sprintf(tbuf, "%2d-%3.3s-%4d",
- range(1, timeptr->tm_mday, 31),
- months_a[range(0, timeptr->tm_mon, 11)],
- timeptr->tm_year + 1900);
- for (i = 3; i < 6; i++)
- if (islower(tbuf[i]))
- tbuf[i] = toupper(tbuf[i]);
- break;
-#endif
-
- default:
- tbuf[0] = '%';
- tbuf[1] = *format;
- tbuf[2] = '\0';
- break;
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ {
+ unsigned int u = number_value;
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+ negative_number = number_value < 0;
+
+ if (negative_number)
+ u = -u;
+
+ do
+ *--bufp = u % 10 + L_('0');
+ while ((u /= 10) != 0);
+ }
+
+ do_number_sign_and_padding:
+ if (negative_number)
+ *--bufp = L_('-');
+
+ if (pad != L_('-'))
+ {
+ int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
+ - bufp);
+
+ if (pad == L_('_'))
+ {
+ while (0 < padding--)
+ *--bufp = L_(' ');
}
- i = strlen(tbuf);
- if (i) {
- if (s + i < endp - 1) {
- strcpy(s, tbuf);
- s += i;
- } else
- return 0;
+ else
+ {
+ bufp += negative_number;
+ while (0 < padding--)
+ *--bufp = L_('0');
+ if (negative_number)
+ *--bufp = L_('-');
}
- }
-out:
- if (s < endp && *format == '\0') {
- *s = '\0';
- return (s - start);
- } else
- return 0;
-}
+ }
-/* isleap --- is a year a leap year? */
+ cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
+ break;
-static int
-isleap(int year)
-{
- return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
-}
+ case L_('F'):
+ if (modifier != 0)
+ goto bad_format;
+ subfmt = L_("%Y-%m-%d");
+ goto subformat;
+ case L_('H'):
+ if (modifier == L_('E'))
+ goto bad_format;
-/* iso8601wknum --- compute week number according to ISO 8601 */
+ DO_NUMBER (2, tp->tm_hour);
-static int
-iso8601wknum(const struct tm *timeptr)
-{
- /*
- * From 1003.2:
- * If the week (Monday to Sunday) containing January 1
- * has four or more days in the new year, then it is week 1;
- * otherwise it is the highest numbered week of the previous
- * year (52 or 53), and the next week is week 1.
- *
- * ADR: This means if Jan 1 was Monday through Thursday,
- * it was week 1, otherwise week 52 or 53.
- *
- * XPG4 erroneously included POSIX.2 rationale text in the
- * main body of the standard. Thus it requires week 53.
- */
-
- int weeknum, jan1day, diff;
-
- /* get week number, Monday as first day of the week */
- weeknum = weeknumber(timeptr, 1);
-
- /*
- * With thanks and tip of the hatlo to tml@tik.vtt.fi
- *
- * What day of the week does January 1 fall on?
- * We know that
- * (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
- * (timeptr->tm_wday - jan1.tm_wday) MOD 7
- * and that
- * jan1.tm_yday == 0
- * and that
- * timeptr->tm_wday MOD 7 == timeptr->tm_wday
- * from which it follows that. . .
- */
- jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
- if (jan1day < 0)
- jan1day += 7;
-
- /*
- * If Jan 1 was a Monday through Thursday, it was in
- * week 1. Otherwise it was last year's highest week, which is
- * this year's week 0.
- *
- * What does that mean?
- * If Jan 1 was Monday, the week number is exactly right, it can
- * never be 0.
- * If it was Tuesday through Thursday, the weeknumber is one
- * less than it should be, so we add one.
- * Otherwise, Friday, Saturday or Sunday, the week number is
- * OK, but if it is 0, it needs to be 52 or 53.
- */
- switch (jan1day) {
- case 1: /* Monday */
- break;
- case 2: /* Tuesday */
- case 3: /* Wednesday */
- case 4: /* Thursday */
- weeknum++;
- break;
- case 5: /* Friday */
- case 6: /* Saturday */
- case 0: /* Sunday */
- if (weeknum == 0) {
-#ifdef USE_BROKEN_XPG4
- /* XPG4 (as of March 1994) says 53 unconditionally */
- weeknum = 53;
-#else
- /* get week number of last week of last year */
- struct tm dec31ly; /* 12/31 last year */
- dec31ly = *timeptr;
- dec31ly.tm_year--;
- dec31ly.tm_mon = 11;
- dec31ly.tm_mday = 31;
- dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
- dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900);
- weeknum = iso8601wknum(& dec31ly);
-#endif
- }
- break;
- }
+ case L_('I'):
+ if (modifier == L_('E'))
+ goto bad_format;
- if (timeptr->tm_mon == 11) {
- /*
- * The last week of the year
- * can be in week 1 of next year.
- * Sigh.
- *
- * This can only happen if
- * M T W
- * 29 30 31
- * 30 31
- * 31
- */
- int wday, mday;
-
- wday = timeptr->tm_wday;
- mday = timeptr->tm_mday;
- if ( (wday == 1 && (mday >= 29 && mday <= 31))
- || (wday == 2 && (mday == 30 || mday == 31))
- || (wday == 3 && mday == 31))
- weeknum = 1;
- }
+ DO_NUMBER (2, hour12);
- return weeknum;
-}
+ case L_('k'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
-/* weeknumber --- figure how many weeks into the year */
+ DO_NUMBER_SPACEPAD (2, tp->tm_hour);
-/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
+ case L_('l'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
-static int
-weeknumber(const struct tm *timeptr, int firstweekday)
-{
- int wday = timeptr->tm_wday;
- int ret;
-
- if (firstweekday == 1) {
- if (wday == 0) /* sunday */
- wday = 6;
- else
- wday--;
- }
- ret = ((timeptr->tm_yday + 7 - wday) / 7);
- if (ret < 0)
- ret = 0;
- return ret;
-}
+ DO_NUMBER_SPACEPAD (2, hour12);
-#if 0
-/* ADR --- I'm loathe to mess with ado's code ... */
-
-Date: Wed, 24 Apr 91 20:54:08 MDT
-From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
-To: arnold@audiofax.com
-
-Hi Arnold,
-in a process of fixing of strftime() in libraries on Atari ST I grabbed
-some pieces of code from your own strftime. When doing that it came
-to mind that your weeknumber() function compiles a little bit nicer
-in the following form:
-/*
- * firstweekday is 0 if starting in Sunday, non-zero if in Monday
- */
-{
- return (timeptr->tm_yday - timeptr->tm_wday +
- (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
-}
-How nicer it depends on a compiler, of course, but always a tiny bit.
-
- Cheers,
- Michal
- ntomczak@vm.ucs.ualberta.ca
-#endif
-
-#ifdef TEST_STRFTIME
-
-/*
- * NAME:
- * tst
- *
- * SYNOPSIS:
- * tst
- *
- * DESCRIPTION:
- * "tst" is a test driver for the function "strftime".
- *
- * OPTIONS:
- * None.
- *
- * AUTHOR:
- * Karl Vogel
- * Control Data Systems, Inc.
- * vogelke@c-17igp.wpafb.af.mil
- *
- * BUGS:
- * None noticed yet.
- *
- * COMPILE:
- * cc -o tst -DTEST_STRFTIME strftime.c
- */
-
-/* ADR: I reformatted this to my liking, and deleted some unneeded code. */
+ case L_('j'):
+ if (modifier == L_('E'))
+ goto bad_format;
-#ifndef NULL
-#include <stdio.h>
-#endif
-#include <sys/time.h>
-#include <string.h>
+ DO_NUMBER (3, 1 + tp->tm_yday);
-#define MAXTIME 132
+ case L_('M'):
+ if (modifier == L_('E'))
+ goto bad_format;
-/*
- * Array of time formats.
- */
+ DO_NUMBER (2, tp->tm_min);
-static char *array[] =
-{
- "(%%A) full weekday name, var length (Sunday..Saturday) %A",
- "(%%B) full month name, var length (January..December) %B",
- "(%%C) Century %C",
- "(%%D) date (%%m/%%d/%%y) %D",
- "(%%E) Locale extensions (ignored) %E",
- "(%%F) full month name, var length (January..December) %F",
- "(%%H) hour (24-hour clock, 00..23) %H",
- "(%%I) hour (12-hour clock, 01..12) %I",
- "(%%M) minute (00..59) %M",
- "(%%N) Emporer/Era Name %N",
- "(%%O) Locale extensions (ignored) %O",
- "(%%R) time, 24-hour (%%H:%%M) %R",
- "(%%S) second (00..60) %S",
- "(%%T) time, 24-hour (%%H:%%M:%%S) %T",
- "(%%U) week of year, Sunday as first day of week (00..53) %U",
- "(%%V) week of year according to ISO 8601 %V",
- "(%%W) week of year, Monday as first day of week (00..53) %W",
- "(%%X) appropriate locale time representation (%H:%M:%S) %X",
- "(%%Y) year with century (1970...) %Y",
- "(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
- "(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
- "(%%b) locale's abbreviated month name (Jan..Dec) %b",
- "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
- "(%%d) day of the month (01..31) %d",
- "(%%e) day of the month, blank-padded ( 1..31) %e",
- "(%%h) should be same as (%%b) %h",
- "(%%j) day of the year (001..366) %j",
- "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
- "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l",
- "(%%m) month (01..12) %m",
- "(%%o) Emporer/Era Year %o",
- "(%%p) locale's AM or PM based on 12-hour clock %p",
- "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
- "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
- "(%%v) VMS date (dd-bbb-YYYY) %v",
- "(%%w) day of week (0..6, Sunday == 0) %w",
- "(%%x) appropriate locale date representation %x",
- "(%%y) last two digits of year (00..99) %y",
- "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
- (char *) NULL
-};
+ case L_('m'):
+ if (modifier == L_('E'))
+ goto bad_format;
-/* main routine. */
+ DO_NUMBER (2, tp->tm_mon + 1);
-int
-main(argc, argv)
-int argc;
-char **argv;
-{
- long time();
+ case L_('N'): /* GNU extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
- char *next;
- char string[MAXTIME];
+ number_value = ns;
+ if (width != -1)
+ {
+ /* Take an explicit width less than 9 as a precision. */
+ int j;
+ for (j = width; j < 9; j++)
+ number_value /= 10;
+ }
- int k;
- int length;
+ DO_NUMBER (9, number_value);
- struct tm *tm;
+ case L_('n'): /* POSIX.2 extension. */
+ add (1, *p = L_('\n'));
+ break;
- long clock;
+ case L_('P'):
+ to_lowcase = 1;
+#if !defined _NL_CURRENT && HAVE_STRFTIME
+ format_char = L_('p');
+#endif
+ /* FALLTHROUGH */
+
+ case L_('p'):
+ if (change_case)
+ {
+ to_uppcase = 0;
+ to_lowcase = 1;
+ }
+#if defined _NL_CURRENT || !HAVE_STRFTIME
+ cpy (ap_len, ampm);
+ break;
+#else
+ goto underlying_strftime;
+#endif
- /* Call the function. */
+ case L_('R'): /* ISO C99 extension. */
+ subfmt = L_("%H:%M");
+ goto subformat;
- clock = time((long *) 0);
- tm = localtime(&clock);
+ case L_('r'): /* POSIX.2 extension. */
+#ifdef _NL_CURRENT
+ if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
+ NLW(T_FMT_AMPM)))
+ == L_('\0'))
+#endif
+ subfmt = L_("%I:%M:%S %p");
+ goto subformat;
+
+ case L_('S'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, tp->tm_sec);
+
+ case L_('s'): /* GNU extension. */
+ {
+ struct tm ltm;
+ time_t t;
+
+ ltm = *tp;
+ t = mktime (&ltm);
+
+ /* Generate string value for T using time_t arithmetic;
+ this works even if sizeof (long) < sizeof (time_t). */
+
+ bufp = buf + sizeof (buf) / sizeof (buf[0]);
+ negative_number = t < 0;
+
+ do
+ {
+ int d = t % 10;
+ t /= 10;
+
+ if (negative_number)
+ {
+ d = -d;
+
+ /* Adjust if division truncates to minus infinity. */
+ if (0 < -1 % 10 && d < 0)
+ {
+ t++;
+ d += 10;
+ }
+ }
+
+ *--bufp = d + L_('0');
+ }
+ while (t != 0);
+
+ digits = 1;
+ goto do_number_sign_and_padding;
+ }
+
+ case L_('X'):
+ if (modifier == L_('O'))
+ goto bad_format;
+#ifdef _NL_CURRENT
+ if (! (modifier == L_('E')
+ && (*(subfmt =
+ (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
+ != L_('\0'))))
+ subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
+ goto subformat;
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# else
+ /* Fall through. */
+# endif
+#endif
+ case L_('T'): /* POSIX.2 extension. */
+ subfmt = L_("%H:%M:%S");
+ goto subformat;
+
+ case L_('t'): /* POSIX.2 extension. */
+ add (1, *p = L_('\t'));
+ break;
+
+ case L_('u'): /* POSIX.2 extension. */
+ DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
+
+ case L_('U'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
+
+ case L_('V'):
+ case L_('g'): /* ISO C99 extension. */
+ case L_('G'): /* ISO C99 extension. */
+ if (modifier == L_('E'))
+ goto bad_format;
+ {
+ int year = tp->tm_year + TM_YEAR_BASE;
+ int days = iso_week_days (tp->tm_yday, tp->tm_wday);
+
+ if (days < 0)
+ {
+ /* This ISO week belongs to the previous year. */
+ year--;
+ days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
+ tp->tm_wday);
+ }
+ else
+ {
+ int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
+ tp->tm_wday);
+ if (0 <= d)
+ {
+ /* This ISO week belongs to the next year. */
+ year++;
+ days = d;
+ }
+ }
+
+ switch (*f)
+ {
+ case L_('g'):
+ DO_NUMBER (2, (year % 100 + 100) % 100);
+
+ case L_('G'):
+ DO_NUMBER (1, year);
+
+ default:
+ DO_NUMBER (2, days / 7 + 1);
+ }
+ }
+
+ case L_('W'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
+
+ case L_('w'):
+ if (modifier == L_('E'))
+ goto bad_format;
+
+ DO_NUMBER (1, tp->tm_wday);
+
+ case L_('Y'):
+ if (modifier == 'E')
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp);
+ if (era)
+ {
+# ifdef COMPILE_WIDE
+ subfmt = era->era_wformat;
+# else
+ subfmt = era->era_format;
+# endif
+ goto subformat;
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ if (modifier == L_('O'))
+ goto bad_format;
+ else
+ DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
+
+ case L_('y'):
+ if (modifier == L_('E'))
+ {
+#if HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp);
+ if (era)
+ {
+ int delta = tp->tm_year - era->start_date[0];
+ DO_NUMBER (1, (era->offset
+ + delta * era->absolute_direction));
+ }
+#else
+# if HAVE_STRFTIME
+ goto underlying_strftime;
+# endif
+#endif
+ }
+ DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
+
+ case L_('Z'):
+ if (change_case)
+ {
+ to_uppcase = 0;
+ to_lowcase = 1;
+ }
+
+#if HAVE_TZNAME
+ /* The tzset() call might have changed the value. */
+ if (!(zone && *zone) && tp->tm_isdst >= 0)
+ zone = tzname[tp->tm_isdst];
+#endif
+ if (! zone)
+ zone = ""; /* POSIX.2 requires the empty string here. */
+
+#ifdef COMPILE_WIDE
+ {
+ /* The zone string is always given in multibyte form. We have
+ to transform it first. */
+ wchar_t *wczone;
+ size_t len;
+ widen (zone, wczone, len);
+ cpy (len, wczone);
+ }
+#else
+ cpy (strlen (zone), zone);
+#endif
+ break;
- for (k = 0; next = array[k]; k++) {
- length = strftime(string, MAXTIME, next, tm);
- printf("%s\n", string);
+ case L_('z'): /* ISO C99 extension. */
+ if (tp->tm_isdst < 0)
+ break;
+
+ {
+ int diff;
+#if HAVE_TM_GMTOFF
+ diff = tp->tm_gmtoff;
+#else
+ if (ut)
+ diff = 0;
+ else
+ {
+ struct tm gtm;
+ struct tm ltm;
+ time_t lt;
+
+ ltm = *tp;
+ lt = mktime (&ltm);
+
+ if (lt == (time_t) -1)
+ {
+ /* mktime returns -1 for errors, but -1 is also a
+ valid time_t value. Check whether an error really
+ occurred. */
+ struct tm tm;
+
+ if (! my_strftime_localtime_r (&lt, &tm)
+ || ((ltm.tm_sec ^ tm.tm_sec)
+ | (ltm.tm_min ^ tm.tm_min)
+ | (ltm.tm_hour ^ tm.tm_hour)
+ | (ltm.tm_mday ^ tm.tm_mday)
+ | (ltm.tm_mon ^ tm.tm_mon)
+ | (ltm.tm_year ^ tm.tm_year)))
+ break;
+ }
+
+ if (! my_strftime_gmtime_r (&lt, &gtm))
+ break;
+
+ diff = tm_diff (&ltm, &gtm);
+ }
+#endif
+
+ if (diff < 0)
+ {
+ add (1, *p = L_('-'));
+ diff = -diff;
+ }
+ else
+ add (1, *p = L_('+'));
+
+ diff /= 60;
+ DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
+ }
+
+ case L_('\0'): /* GNU extension: % at end of format. */
+ --f;
+ /* Fall through. */
+ default:
+ /* Unknown format; output the format, including the '%',
+ since this is most likely the right thing to do if a
+ multibyte string has been misparsed. */
+ bad_format:
+ {
+ int flen;
+ for (flen = 1; f[1 - flen] != L_('%'); flen++)
+ continue;
+ cpy (flen, &f[1 - flen]);
+ }
+ break;
}
+ }
+
+ if (p && maxsize != 0)
+ *p = L_('\0');
+ return i;
+}
+
- exit(0);
+#ifdef emacs
+/* For Emacs we have a separate interface which corresponds to the normal
+ strftime function plus the ut argument, but without the ns argument. */
+size_t
+emacs_strftimeu (s, maxsize, format, tp, ut)
+ char *s;
+ size_t maxsize;
+ const char *format;
+ const struct tm *tp;
+ int ut;
+{
+ return my_strftime (s, maxsize, format, tp, ut, 0);
}
-#endif /* TEST_STRFTIME */
+#endif
diff --git a/missing_d/strtod.c b/missing_d/strtod.c
index cdcefe9f..2c4ee574 100644
--- a/missing_d/strtod.c
+++ b/missing_d/strtod.c
@@ -22,6 +22,9 @@
*
* Fall 2000: Changed to enforce C89 semantics, so that 0x... returns 0.
* C99 has hexadecimal floating point numbers.
+ *
+ * Summer 2001. Try to make it smarter, so that a string like "0000"
+ * doesn't look like we failed. Sigh.
*/
#if 0
@@ -36,8 +39,8 @@ register const char *s;
register const char **ptr;
{
double ret = 0.0;
- const char *start = s;
- const char *begin = NULL;
+ const char *start = s; /* save original start of string */
+ const char *begin = NULL; /* where the number really begins */
int success = 0;
/* optional white space */
@@ -98,7 +101,7 @@ register const char **ptr;
ret = atof(begin);
out:
- if (! success)
+ if (! success && s == begin)
s = start; /* in case all we did was skip whitespace */
if (ptr)