//
// aegis - project change supervisor
// Copyright (C) 1994, 1996, 2002, 2004-2008 Peter Miller
//
// 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 3 of the License, 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
//
// NAME
// strftime - string from time
//
// SYNOPSIS
// size_t strftime(char *s, size_t maxsize, const char *format,
// const struct tm *timeptr);
//
// DESCRIPTION
// The strftime function places characters into the array pointed to
// by s as controlled by the string pointed to by format. The format
// string consists of zero or more directives and ordinary characters.
// A directive consists of a % character followed by a character that
// determined the dirrective's behaviour. All ordinary characters
// (including the terminating null character) are copied unchanged
// into the array. No more thaqn maxsize characters are placed into
// the array. Each directive is replaced by appropriate characters as
// described in the following list. The appropriate characters are
// determined by the program's locale and by the values contained in
// the structure pointed to by timeptr.
//
// %a is replaced by the locale's abbreviated weekday name
// %A is replaced by the locale's full weekday name
// %b is replaced by the locale's abbreviated month name
// %B is replaced by the locale's full month name
// %c is replaced by the locale's appropriae date and time representation
// %d is replaced by the day of the month as decimal number (01-31)
// %H is replaced by the hour (24-hour clock) as decimal number (00-23)
// %I is replaced by the hour (12-hour clock) as decimal number (01-12)
// %j is replaced by the day of te year as decimal number (001-366)
// %m is replaced by the month as decomal number (01-12)
// %M is replaced by the minute as decimal number (00-59)
// %p is replaced by the locale's equivalent of either AM or PM
// %S is replaced by the second as decimal number (00-59)
// %U is replaced by the week number of they year (Sunday as the first
// day of the week) as decimal number (00-52)
// %w is replaced by the weekday as decimal number (0=Sunday to 6=Saturday)
// %W is replaced by the week number of the year (Monday as the first
// day of the week) as decimal number (00-52)
// %x is replaced by the locale's appropriate date representation
// %X is replaced by the locale's appropriate time representation
// %y is replaced by the year without century as decimal number (00-99)
// %Y is replaced by the year with century as decimal number
// %Z is replaced by the time zone name, or no characters in no time
// zone name is available
// %% is replaced by %
//
// RETURNS
// If the total number of resulting characters including the terminating
// null character is not more than maxsize, the strftime function returns
// the number of characters placed into the array pointed to by s not
// including the terminating null character. Otherwise, zero is returned
// and the contents of the array are indeterminate.
//
// CAVEAT
// This suffers from a serious design flaw: there is no way to
// distinguish between a result which is the empty string, and a result
// which is more than maxsize characters.
//
// The behaviour for unknow directivbes is not only undefined,
// it is unmentioned! (Normally the standard specifically allows
// implementation defined behaviour on weird boundary conditions.)
// This implementation will echo unknown directives into the output.
//
#ifndef HAVE_STRFTIME
#include
#include
#ifndef HAVE_tm_zone
extern char *tzname[2];
#endif
size_t
strftime(char *buf, size_t max, const char *fmt, struct tm *tm)
{
char *cp;
char *end;
char output[1000];
int n;
size_t len;
static const char *weekday[] =
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
static const char *month[] =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
};
end = buf + max - 1;
cp = buf;
while (*fmt)
{
if (*fmt++ != '%')
{
if (cp >= end)
return 0;
*cp++ = fmt[-1];
continue;
}
switch (*fmt++)
{
case 0:
--fmt;
output[0] = '%';
output[1] = 0;
break;
default:
output[0] = '%';
output[1] = fmt[-1];
output[2] = 0;
break;
case '%':
output[0] = '%';
output[1] = 0;
break;
case 'a':
//
// the abbreviated weekday name
//
snprintf(output, sizeof(output), "%3.3s", weekday[tm->tm_wday]);
break;
case 'A':
//
// the full weekday name
//
strendcpy(output, weekday[tm->tm_wday], output + sizeof(output));
break;
case 'b':
case 'h':
//
// the abbreviated month name
//
snprintf(output, sizeof(output), "%3.3s", month[tm->tm_mon]);
break;
case 'B':
//
// the full month name
//
strendcpy(output, month[tm->tm_mon], output + sizeof(output));
break;
case 'c':
//
// the date and time
//
len = strftime(output, sizeof(output), "%b %e %X %Y", tm);
if (!len)
output[0] = 0;
break;
case 'C':
//
// This looks like a Sun extra.
// Local date.
//
len = strftime(output, sizeof(output), "%A, %B %e, %Y", tm);
if (!len)
output[0] = 0;
break;
case 'd':
//
// the day of the month,
// zero padded.
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_mday);
break;
case 'D':
//
// This looks like a Sun extra.
// Local date.
//
len = strftime(output, sizeof(output), "%m/%d/%y", tm);
if (!len)
output[0] = 0;
break;
case 'e':
//
// This looks like a Sun extra.
// the day of the month,
// blank padded.
//
snprintf(output, sizeof(output), "%2d", tm->tm_mday);
break;
case 'H':
//
// the hour of a 24-hour day
// zero padded
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_hour);
break;
case 'I':
//
// the hour of a 12-hour day,
// zero padded
//
n = tm->tm_hour % 12;
snprintf(output, sizeof(output), "%2.2d", n ? n : 12);
break;
case 'j':
//
// the day of the year,
// zero padded, one based
//
snprintf(output, sizeof(output), "%3.3d", tm->tm_yday + 1);
break;
case 'k':
//
// This looks like a Sun extra.
// the hour of the 24-hour day,
// blank padded.
//
snprintf(output, sizeof(output), "%2d", tm->tm_hour);
break;
case 'l':
//
// This looks like a Sun extra.
// the hour of the 12-hour day,
// blank padded.
//
n = tm->tm_hour % 12;
snprintf(output, sizeof(output), "%2d", n ? n : 12);
break;
case 'm':
//
// the month of the year,
// zero padded, one based.
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_mon + 1);
break;
case 'M':
//
// the minute of the hour,
// zero padded
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_min);
break;
case 'n':
//
// This looks like a Sun extra.
// like \n
//
output[0] = '\n';
output[1] = 0;
break;
case 'p':
//
// meridian indicator
//
if (tm->tm_hour >= 12)
strendcpy(output, "PM", output + sizeof(output));
else
strendcpy(output, "AM", output + sizeof(output));
break;
case 'r':
//
// this looks like a Sun extra.
// like %X, but 12-hour clock with meridian.
//
len = strftime(output, sizeof(output), "%I:%M:%S %p", tm);
if (!len)
output[0] = 0;
break;
case 'R':
//
// this looks like a Sun extra.
// the 24-hour time as HH:MM
//
len = strftime(output, sizeof(output), "%H:%M", tm);
if (!len)
output[0] = 0;
break;
case 'S':
//
// seconds of the minute
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_sec);
break;
case 't':
//
// this looks like a Sun extra.
// like \t
//
output[0] = '\t';
output[1] = 0;
break;
case 'T':
//
// This looks like a Sun extra.
// the 24-hour time as HH:MM:SS
//
len = strftime(output, sizeof(output), "%H:%M:%S", tm);
if (!len)
output[0] = 0;
break;
case 'U':
//
// the Sunday week of the year
//
n = (tm->tm_yday - tm->tm_wday + 5) / 7;
snprintf(output, sizeof(output), "%2.2d", n);
break;
case 'w':
//
// the day of the week,
// Sunday = 0
//
snprintf(output, sizeof(output), "%d", tm->tm_wday);
break;
case 'W':
//
// the Monday week of the year
//
n = (tm->tm_yday - ((tm->tm_wday + 6) % 7) + 5) / 7;
snprintf(output, sizeof(output), "%2.2d", n);
break;
case 'x':
//
// the date, as mmm dd yyyy
//
len = strftime(output, sizeof(output), "%b %d %Y", tm);
if (!len)
output[0] = 0;
break;
case 'X':
//
// the time as hh:mm:ss
//
len = strftime(output, sizeof(output), "%H:%M:%S", tm);
if (!len)
output[0] = 0;
break;
case 'y':
//
// the year of the century
//
snprintf(output, sizeof(output), "%2.2d", tm->tm_year % 100);
break;
case 'Y':
//
// the year including century
//
snprintf(output, sizeof(output), "%4.4d", tm->tm_year + 1900);
break;
case 'Z':
//
// the timezone name, if any
//
#ifndef HAVE_tm_zone
if (tm->tm_isdst >= 0 && tm->tm_isdst <= 1)
{
strendcpy
(
output,
tzname[tm->tm_isdst],
output + sizeof(output)
);
}
else
output[0] = 0;
#else
// Berkeley derivatives have extra tm field
strendcpy(output, tm->tm_zone, output + sizeof(output));
#endif
break;
}
//
// make sure it fits in the buffer
//
len = strlen(output);
if (cp + len > end)
return -1;
memcpy(cp, output, len);
cp += len;
}
*cp = 0;
return (cp - buf);
}
#endif // !HAVE_STRFTIME