[BACK]Return to asctime.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

File: [cvs.NetBSD.org] / src / lib / libc / time / asctime.c (download)

Revision 1.25, Fri May 4 15:51:00 2018 UTC (5 years, 11 months ago) by christos
Branch: MAIN
CVS Tags: phil-wifi-base, pgoyette-compat-20190127, pgoyette-compat-20190118, pgoyette-compat-1226, pgoyette-compat-1126, pgoyette-compat-1020, pgoyette-compat-0930, pgoyette-compat-0906, pgoyette-compat-0728, pgoyette-compat-0625, pgoyette-compat-0521
Branch point for: phil-wifi
Changes since 1.24: +5 -11 lines

Merge 2018e

  Changes to code

    zic now accepts subsecond precision in expressions like
    00:19:32.13, which is approximately the legal time of the
    Netherlands from 1835 to 1937.  However, because it is
    questionable whether the few recorded uses of non-integer offsets
    had subsecond precision in practice, there are no plans for tzdata
    to use this feature.  (Thanks to Steve Allen for pointing out
    the limitations of historical data in this area.)

    The code is a bit more portable to MS-Windows.  Installers can
    compile with -DRESERVE_STD_EXT_IDS on MS-Windows platforms that
    reserve identifiers like 'localtime'.  (Thanks to Manuela
    Friedrich).

  Changes to documentation and commentary

    theory.html now outlines tzdb's extensions to POSIX's model for
    civil time, and has a section "POSIX features no longer needed"
    that lists POSIX API components that are now vestigial.
    (From suggestions by Steve Summit.)  It also better distinguishes
    time zones from tz regions.  (From a suggestion by Guy Harris.)

    Commentary is now more consistent about using the phrase "daylight
    saving time", to match the C name tm_isdst.  Daylight saving time
    need not occur in summer, and need not have a positive offset from
    standard time.

    Commentary about historical transitions in Uruguay has been expanded
    with links to many relevant legal documents.
    (Thanks to Tim Parenti.)

    Commentary now uses some non-ASCII characters with Unicode value
    less than U+0100, as they can be useful and should work even with
    older editors such as XEmacs.

/*	$NetBSD: asctime.c,v 1.25 2018/05/04 15:51:00 christos Exp $	*/

/* asctime and asctime_r a la POSIX and ISO C, except pad years before 1000.  */

/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/

/*
** Avoid the temptation to punt entirely to strftime;
** the output of strftime is supposed to be locale specific
** whereas the output of asctime is supposed to be constant.
*/

#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char	elsieid[] = "@(#)asctime.c	8.5";
#else
__RCSID("$NetBSD: asctime.c,v 1.25 2018/05/04 15:51:00 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */

/*LINTLIBRARY*/

#include "namespace.h"
#include "private.h"
#include <stdio.h>

#ifdef __weak_alias
__weak_alias(asctime_r,_asctime_r)
#endif

/*
** Some systems only handle "%.2d"; others only handle "%02d";
** "%02.2d" makes (most) everybody happy.
** At least some versions of gcc warn about the %02.2d;
** we conditionalize below to avoid the warning.
*/
/*
** All years associated with 32-bit time_t values are exactly four digits long;
** some years associated with 64-bit time_t values are not.
** Vintage programs are coded for years that are always four digits long
** and may assume that the newline always lands in the same place.
** For years that are less than four digits, we pad the output with
** leading zeroes to get the newline in the traditional place.
** The -4 ensures that we get four characters of output even if
** we call a strftime variant that produces fewer characters for some years.
** The ISO C and POSIX standards prohibit padding the year,
** but many implementations pad anyway; most likely the standards are buggy.
*/
#ifdef __GNUC__
#define ASCTIME_FMT	"%s %s%3d %2.2d:%2.2d:%2.2d %-4s\n"
#else /* !defined __GNUC__ */
#define ASCTIME_FMT	"%s %s%3d %02.2d:%02.2d:%02.2d %-4s\n"
#endif /* !defined __GNUC__ */
/*
** For years that are more than four digits we put extra spaces before the year
** so that code trying to overwrite the newline won't end up overwriting
** a digit within a year and truncating the year (operating on the assumption
** that no output is better than wrong output).
*/
#ifdef __GNUC__
#define ASCTIME_FMT_B	"%s %s%3d %2.2d:%2.2d:%2.2d     %s\n"
#else /* !defined __GNUC__ */
#define ASCTIME_FMT_B	"%s %s%3d %02.2d:%02.2d:%02.2d     %s\n"
#endif /* !defined __GNUC__ */

#define STD_ASCTIME_BUF_SIZE	26
/*
** Big enough for something such as
** ??? ???-2147483648 -2147483648:-2147483648:-2147483648     -2147483648\n
** (two three-character abbreviations, five strings denoting integers,
** seven explicit spaces, two explicit colons, a newline,
** and a trailing NUL byte).
** The values above are for systems where an int is 32 bits and are provided
** as an example; the define below calculates the maximum for the system at
** hand.
*/
#define MAX_ASCTIME_BUF_SIZE	(2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1)

static char	buf_asctime[MAX_ASCTIME_BUF_SIZE];

char *
asctime_r(const struct tm *timeptr, char *buf)
{
	static const char	wday_name[][4] = {
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
	};
	static const char	mon_name[][4] = {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	};
	const char *	wn;
	const char *	mn;
	char			year[INT_STRLEN_MAXIMUM(int) + 2];
	char			result[MAX_ASCTIME_BUF_SIZE];

	if (timeptr == NULL) {
		errno = EINVAL;
		return strcpy(buf, "??? ??? ?? ??:??:?? ????\n");
	}
	if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
		wn = "???";
	else	wn = wday_name[timeptr->tm_wday];
	if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
		mn = "???";
	else	mn = mon_name[timeptr->tm_mon];
	/*
	** Use strftime's %Y to generate the year, to avoid overflow problems
	** when computing timeptr->tm_year + TM_YEAR_BASE.
	** Assume that strftime is unaffected by other out-of-range members
	** (e.g., timeptr->tm_mday) when processing "%Y".
	*/
	(void) strftime(year, sizeof year, "%Y", timeptr);
	(void) snprintf(result,
		sizeof(result),
		((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B),
		wn, mn,
		timeptr->tm_mday, timeptr->tm_hour,
		timeptr->tm_min, timeptr->tm_sec,
		year);
	if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime)
		return strcpy(buf, result);
	else {
		errno = EOVERFLOW;
		return NULL;
	}
}

char *
asctime(const struct tm *timeptr)
{
	return asctime_r(timeptr, buf_asctime);
}