// // 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