glibc/time/strftime.c
Roland McGrath b20e47cb14 Tue Mar 19 14:18:42 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
* sysdeps/unix/bsd/pause.c: Moved to sysdeps/unix/common/pause.c.

Mon Mar  4 20:17:28 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/unix/sysv/linux/adjtime.c: Use INT_MAX instead of LONG_MAX.

	* sysdeps/unix/sysv/Makefile (sysdep_routines): Don't add s_getdents.

	* sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Don't add mount,
	umount.

	* sysdeps/alpha/__math.h (atan, cabs): New functions.

	* sysdeps/unix/sysv/linux/alpha/sigsuspend.S: new file (syscall
 	expects set-value, not pointer to it).

Sun Feb 25 22:36:10 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/unix/sysv/linux/alpha/profil-counter.h: New file.

	* gmon/gmon.c (__bb_head): new variable.
	(write_hist, write_call_graph, write_bb_counts): new functions.
	(_mcleanup): modified to call above functions instead of directly
 	writing out gmon.out.
	* gmon/sys/gmon.h (struct __bb): New type.
	(struct gmonhdr): Type removed.
	(struct gmonparam): New member `log_hashfraction'.
	(GMONVERSION): Macro removed.

	* gmon/sys/gmon_out.h, gmon/bb_exit_func.c,
 	sysdeps/generic/bb_init_func.c, sysdeps/alpha/bb_init_func.S: new
 	files.
	* gmon/Makefile (headers): Add sys/gmon_out.h.
	(routines): Add bb_init_func, bb_exit_func.

	* gmon/mcount.c: Avoid integer division.

Wed Feb 21 23:56:41 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/alpha/setjmp.S: switched order in which sp and fp are
 	passed to match what __sigsetjmp_aux() expects.

Tue Feb 20 11:33:46 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/unix/sysv/linux/alpha/syscalls.list (select, bind,
 	connect, getpeername, getsockname, listen, recv, recvfrom,
 	recvmsg, send, sendmsg, sendto, setsockopt, shutdown, socketpair):
 	added to override same-name assembly file in the parent directory.

	* stdlib/stdlib.h: add include of sys/types.h in front of random
 	etc declarations to ensure int32_t is declared.

	* stdlib/random.c, stdlib/random_r.c: replaced "long int" by int32_t
	where 32 bit integers are required.  Also change LONG_MAX into
	0x7fffffff since the intent is to turn off the sign bit in a
	32 bit integer.

	* time/offtime.c (__offtime): Use Paul Eggert's code to deal
	with very large values for "days" (e.g., 64 bit values).

Mon Feb 19 22:22:12 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* stdlib/stdlib.h (__random, __random_r, random_r, struct
 	random_data): use int32_t instead of `long int'.

Sat Feb 17 11:29:29 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/unix/sysv/linux/alpha/ioperm.c: new file.

	* sysdeps/alpha/ffs.S: new file.

	* sysdeps/alpha/fabs.c: File removed.

	* time/tzfile.c (__tzfile_read): counter variable is i, *not*
	num_transitions!

	* time/offtime.c: make capable of dealing with very large (64 bit)
 	time_t values.  Use old algorithm until a year is reached that
	is an integer multiple of 400, then use DAYS_PER_400_YEARS to
	do the remainder in a single division.

	* sysdeps/generic/ffs.c (ffs): fix variable declarations to
	be unsigned int, not unsigned long.

	* string/test-ffs.c (main): add test case with all upper bits
	set.

	* stdlib/tst-strtol.c: add tests cases for machines where
	sizeof(long)==8.

	* stdlib/testrand.c (main): disallow rand() to return negative
 	integers.

	* stdlib/testmb.c (main): fix format to use %lx instead of %x.

	* stdlib/stdlib.h: on 64 bit machines, declare
	struct random_data, __random(),  __random_r, and random_r to
	return "int" instead of "long int".

	* stdlib/random_r.c: 64 bit machines use "int" instead of "long
 	int".  Similarly, use INT_MAX instead of LONG_MAX.

	* stdlib/random.c: on 64 bit machines, randtbl[] and __random[]
 	need to operate on "int" instead of "long int".

	* locale/locfile-hash.c (compute_hashval): make shifted constant
	a long to avoid loosing bits on 64 bit machines.

	* dirent/tst-seekdir.c (main): fix confusing comment; print
	a line to mark point where directory is rewound.

Fri Feb 16 15:01:49 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* time/strftime.c (strftime): any hour > 11 is PM (not > 12!).

Wed Feb 14 00:21:17 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* sysdeps/unix/sysv/linux/alpha/Makefile,
	sysdeps/unix/sysv/linux/alpha/brk.S,
	sysdeps/unix/sysv/linux/alpha/fpu_control.c,
	sysdeps/unix/sysv/linux/alpha/fpu_control.h,
	sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S,
	sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S,
	sysdeps/unix/sysv/linux/alpha/pipe.S,
	sysdeps/unix/sysv/linux/alpha/setfpucw.c,
	sysdeps/unix/sysv/linux/alpha/sigprocmask.c,
	sysdeps/unix/sysv/linux/alpha/speed.c,
	sysdeps/unix/sysv/linux/alpha/start.S,
	sysdeps/unix/sysv/linux/alpha/syscall.S,
	sysdeps/unix/sysv/linux/alpha/syscalls.list,
	sysdeps/unix/sysv/linux/alpha/alpha/regdef.h,
	sysdeps/unix/sysv/linux/alpha/sysdep.S,
	sysdeps/unix/sysv/linux/alpha/sysdep.h: New files.

	* sysdeps/alpha/setjmp_aux.c (__sigsetjmp_aux): restore return
 	address register before returning (gcc 2.7.1 doesn't do it,
 	presumably because $26 is declared as a global variable).

	* sysdeps/unix/sysv/linux/sys/mman.h: msync was missing "flags"
	argument.

	* sysdeps/unix/alarm.c (alarm): do roundup using test & increment
	instead of multiplication.

	* sysdeps/posix/sleep.c (sleep): initialize sa_mask to mask of
	currently blocked signals instead of the empty mask to ensure
	that execution of alarm handler occurs with none of the currently
	blocked signals enabled.

	* sysdeps/unix/alpha/sysdep.h: new file (adapted from OSF/1 version).

	* sysdeps/unix/bsd/osf/alpha/sysdep.h: include
 	sysdeps/unix/alpha/sysdep.h and removed definitions now in that file.

	* sysdeps/alpha/divrem.S, sysdeps/alpha/htonl.S,
	sysdeps/alpha/htons.S, sysdeps/alpha/machine-gmon.h,
	sysdeps/alpha/_mcount.S, sysdeps/alpha/ntohl.s, sysdeps/alpha/ntohs.s,
	sysdeps/alpha/strlen.S: New files.

	* sysdeps/alpha/divl.S, sysdeps/alpha/divlu.S, sysdeps/alpha/divq.S,
	sysdeps/alpha/divqu.S, sysdeps/alpha/divrem.m4,
	sysdeps/alpha/macros.m4, sysdeps/alpha/reml.S, sysdeps/alpha/remlu.S,
	sysdeps/alpha/remq.S, sysdeps/alpha/remqu.S, sysdeps/alpha/strlen.c:
 	Removed.

	* sysdeps/generic/sbrk.c (__sbrk): argument is of type ptrdiff_t, not
	int.

	* sysdeps/alpha/__longjmp.c (__longjmp): moved dummy while loop
	to end of function to avoid a jump across NOPs.

	* sysdeps/alpha/Makefile (sysdep_routines): Removed all rules
 	pertaining to integer division/remainder routines since new code
 	doesn't require them.

	* sunrpc/xdr_mem.c, sunrpc/xdr_stdio.c: Use 4 instead of sizeof(long)
	where 32 bit quantities are consumed/stored.  Various other minor
	64-bit cleanups (casting).

	* sunrpc/xdr.c (xdr_int): test for sizeof(int)==4 to determine
 	whether xdr_long or xdr_short should be used to encode an int.
  	Notice that an xdr_long is 4 bytes independent of the architecture
	(otherwise no Alpha could interoperate with existing NFS servers,
 	for example).  Ditto for enums.

	* sunrpc/svc_udp.c (svcudp_recv): changed test from 4*sizeof(u_long)
	to 16 since it really wants 16 bytes.

	* sunrpc/svc.c (maskp): changed from u_long* to u_int32*.

	* sunrpc/rpc_cmsg.c (xdr_callmsg), sunrpc/svc_authux.c: increment
	"buf" pointer by casting it to a char* first since a long* may be 8
 	bytes or more and oa->oa_length may be any multiple of 4.

	* sunrpc/rpc/xdr.h (IXDR_GET_LONG, IXDR_PUT_LONG): change casts to
 	u_int32_t (instead of u_long).

	* sunrpc/clnt_udp.c (clntudp_call): replaced sizeof(u_long) by 4
	since it really is testing for 32 bits.  Fixed casts to use
	u_int32 instead of u_long.
	* sunrpc/xdr_rec.c: Likewise.

	* sunrpc/clnt_tcp.c (clnttcp_call): replaced u_long by u_int32.
	* sunrpc/rpc/auth.h: Likewise.

	* limits.h (LONG_MAX, LONG_MIN, ULONG_MAX): use 64 bit values
	for Alpha.

Tue Mar 19 13:27:49 1996  Roland McGrath  <roland@charlie-brown.gnu.ai.mit.edu>

	* sysdeps/i386/fpu/__math.h: New file.
	Contributed by John C. Bowman <bowman@hagar.ph.utexas.edu>.

Sun Mar 17 00:28:16 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/posix/clock.c: Don't multiply the return value by
	CLOCKS_PER_SEC or CLK_TCK.

	* sysdeps/mach/hurd/getcwd.c: Fail with ENOENT if a parent directory
	scan finds no match.

	* posix/unistd.h (setpgrp): Declare no-arg version unless __FAVOR_BSD.
	* misc/bsd-compat.c (setpgrp): New function, two arg version.
	* sysdeps/stub/setpgid.c: Remove setpgrp alias.
	* sysdeps/mach/hurd/setpgid.c: Likewise.
	* sysdeps/unix/sysv/sysv4/setpgid.c: Likewise.
	* sysdeps/unix/common/syscalls.list (setpgid): Remove setpgrp alias.
	* sysdeps/unix/sysv/irix4/syscalls.list: Likewise.
	* sysdeps/unix/sysv/linux/setpgrp.c: Obsolete file removed.
	* posix/setpgrp.c (setpgrp): New file.
	* posix/Makefile (routines): Add setpgrp.

Tue Feb  6 12:46:29 1996  David Mosberger-Tang  <davidm@azstarnet.com>

	* libc-symbols.h (weak_alias, weak_symbol): added definitions
	for ECOFF (HAVE_ECOFF).
1996-03-19 20:21:54 +00:00

424 lines
9.2 KiB
C

/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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 Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define HAVE_MBLEN 1
# define HAVE_TM_ZONE 1
# define STDC_HEADERS 1
# include <ansidecl.h>
# include "../locale/localeinfo.h"
#endif
#include <stdio.h>
#include <sys/types.h> /* Some systems define `time_t' here. */
#include <time.h>
#if HAVE_MBLEN
# include <ctype.h>
#endif
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#if STDC_HEADERS
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
#else
# define memcpy(d, s, n) bcopy (s, d, n)
#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
static unsigned int week __P((const struct tm *const, int));
#define add(n, f) \
do \
{ \
i += (n); \
if (i >= maxsize) \
return 0; \
else \
if (p) \
{ \
f; \
p += (n); \
} \
} while (0)
#define cpy(n, s) add((n), memcpy((PTR) p, (PTR) (s), (n)))
#ifdef _LIBC
#define fmt(n, args) add((n), if (sprintf args != (n)) return 0)
#else
#define fmt(n, args) add((n), sprintf args; if (strlen (p) != (n)) return 0)
#endif
/* Return the week in the year specified by TP,
with weeks starting on STARTING_DAY. */
#ifdef __GNUC__
inline
#endif
static unsigned int
week (tp, starting_day)
const struct tm *const tp;
int starting_day;
{
int wday, dl;
wday = tp->tm_wday - starting_day;
if (wday < 0)
wday += 7;
/* Set DL to the day in the year of the last day of the week previous to the
one containing the day specified in TP. If DL is negative or zero, the
day specified in TP is in the first week of the year. Otherwise,
calculate the number of complete weeks before our week (DL / 7) and
add any partial week at the start of the year (DL % 7). */
dl = tp->tm_yday - wday;
return dl <= 0 ? 0 : ((dl / 7) + ((dl % 7) == 0 ? 0 : 1));
}
#ifndef _NL_CURRENT
static char const weekday_name[][10] =
{
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
static char const month_name[][10] =
{
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
#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 (s, maxsize, format, tp)
char *s;
size_t maxsize;
const char *format;
register const struct tm *tp;
{
int hour12 = tp->tm_hour;
#ifdef _NL_CURRENT
const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
const char *const ampm = _NL_CURRENT (LC_TIME,
hour12 > 11 ? PM_STR : AM_STR);
size_t aw_len = strlen(a_wkday);
size_t am_len = strlen(a_month);
size_t ap_len = strlen (ampm);
#else
const char *const f_wkday = weekday_name[tp->tm_wday];
const char *const f_month = month_name[tp->tm_mon];
const char *const a_wkday = f_wkday;
const char *const a_month = f_month;
const char *const ampm = "AMPM" + 2 * (hour12 > 11);
size_t aw_len = 3;
size_t am_len = 3;
size_t ap_len = 2;
#endif
size_t wkday_len = strlen(f_wkday);
size_t month_len = strlen(f_month);
const unsigned int y_week0 = week (tp, 0);
const unsigned int y_week1 = week (tp, 1);
const char *zone;
size_t zonelen;
register size_t i = 0;
register char *p = s;
register const char *f;
char number_fmt[5];
/* Initialize the buffer we will use for the sprintf format for numbers. */
number_fmt[0] = '%';
zone = 0;
#if HAVE_TM_ZONE
zone = (const char *) tp->tm_zone;
#endif
#if HAVE_TZNAME
if (!(zone && *zone) && tp->tm_isdst >= 0)
zone = tzname[tp->tm_isdst];
#endif
if (!(zone && *zone))
zone = "???";
zonelen = strlen (zone);
if (hour12 > 12)
hour12 -= 12;
else
if (hour12 == 0) hour12 = 12;
for (f = format; *f != '\0'; ++f)
{
enum { pad_zero, pad_space, pad_none } pad; /* Padding for number. */
unsigned int maxdigits; /* Max digits for numeric format. */
unsigned int number_value; /* Numeric value to be printed. */
const char *subfmt;
#if HAVE_MBLEN
if (!isascii(*f))
{
/* Non-ASCII, may be a multibyte. */
int len = mblen(f, strlen(f));
if (len > 0)
{
cpy(len, f);
continue;
}
}
#endif
if (*f != '%')
{
add(1, *p = *f);
continue;
}
/* Check for flags that can modify a number format. */
++f;
switch (*f)
{
case '_':
pad = pad_space;
++f;
break;
case '-':
pad = pad_none;
++f;
break;
default:
pad = pad_zero;
break;
}
/* Now do the specified format. */
switch (*f)
{
case '\0':
case '%':
add(1, *p = *f);
break;
case 'a':
cpy(aw_len, a_wkday);
break;
case 'A':
cpy(wkday_len, f_wkday);
break;
case 'b':
case 'h': /* GNU extension. */
cpy(am_len, a_month);
break;
case 'B':
cpy(month_len, f_month);
break;
case 'c':
#ifdef _NL_CURRENT
subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
#else
subfmt = "%a %b %d %H:%M:%S %Z %Y";
#endif
subformat:
{
size_t len = strftime (p, maxsize - i, subfmt, tp);
if (len == 0 && *subfmt)
return 0;
add(len, );
}
break;
#define DO_NUMBER(digits, value) \
maxdigits = digits; number_value = value; goto do_number
#define DO_NUMBER_NOPAD(digits, value) \
maxdigits = digits; number_value = value; goto do_number_nopad
case 'C':
DO_NUMBER (2, (1900 + tp->tm_year) / 100);
case 'x':
#ifdef _NL_CURRENT
subfmt = _NL_CURRENT (LC_TIME, D_FMT);
goto subformat;
#endif
/* Fall through. */
case 'D': /* GNU extension. */
subfmt = "%m/%d/%y";
goto subformat;
case 'd':
DO_NUMBER (2, tp->tm_mday);
case 'e': /* GNU extension: %d, but blank-padded. */
DO_NUMBER_NOPAD (2, tp->tm_mday);
/* All numeric formats set MAXDIGITS and NUMBER_VALUE and then
jump to one of these two labels. */
do_number_nopad:
/* Force `-' flag. */
pad = pad_none;
do_number:
{
/* Format the number according to the PAD flag. */
register char *nf = &number_fmt[1];
int printed;
switch (pad)
{
case pad_zero:
*nf++ = '0';
case pad_space:
*nf++ = '0' + maxdigits;
case pad_none:
*nf++ = 'u';
*nf = '\0';
}
#ifdef _LIBC
add (maxdigits, printed = sprintf (p, number_fmt, number_value));
#else
add (sprintf (p, number_fmt, number_value);
printed = strlen (p));
#endif
break;
}
case 'H':
DO_NUMBER (2, tp->tm_hour);
case 'I':
DO_NUMBER (2, hour12);
case 'k': /* GNU extension. */
DO_NUMBER_NOPAD (2, tp->tm_hour);
case 'l': /* GNU extension. */
DO_NUMBER_NOPAD (2, hour12);
case 'j':
DO_NUMBER (3, 1 + tp->tm_yday);
case 'M':
DO_NUMBER (2, tp->tm_min);
case 'm':
DO_NUMBER (2, tp->tm_mon + 1);
case 'n': /* GNU extension. */
add (1, *p = '\n');
break;
case 'p':
cpy(ap_len, ampm);
break;
case 'R': /* GNU extension. */
subfmt = "%H:%M";
goto subformat;
case 'r': /* GNU extension. */
subfmt = "%I:%M:%S %p";
goto subformat;
case 'S':
DO_NUMBER (2, tp->tm_sec);
case 'X':
#ifdef _NL_CURRENT
subfmt = _NL_CURRENT (LC_TIME, T_FMT);
goto subformat;
#endif
/* Fall through. */
case 'T': /* GNU extenstion. */
subfmt = "%H:%M:%S";
goto subformat;
case 't': /* GNU extenstion. */
add (1, *p = '\t');
break;
case 'U':
DO_NUMBER (2, y_week0);
case 'W':
DO_NUMBER (2, y_week1);
case 'w':
DO_NUMBER (2, tp->tm_wday);
case 'Y':
DO_NUMBER (4, 1900 + tp->tm_year);
case 'y':
DO_NUMBER (2, tp->tm_year % 100);
case 'Z':
cpy(zonelen, zone);
break;
default:
/* Bad format. */
break;
}
}
if (p)
*p = '\0';
return i;
}