+++ /dev/null
-/** @file\r
- Implementation of the strftime function for <time.h>.\r
-\r
- Based on the UCB version with the ID appearing below.\r
- This is ANSIish only when "multibyte character == plain character".\r
-\r
- Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available under\r
- the terms and conditions of the BSD License that accompanies this distribution.\r
- The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
- Copyright (c) 1989, 1993\r
- The Regents of the University of California. All rights reserved.\r
-\r
- Redistribution and use in source and binary forms, with or without\r
- modification, are permitted provided that the following conditions\r
- are met:\r
- 1. Redistributions of source code must retain the above copyright\r
- notice, this list of conditions and the following disclaimer.\r
- 2. Redistributions in binary form must reproduce the above copyright\r
- notice, this list of conditions and the following disclaimer in the\r
- documentation and/or other materials provided with the distribution.\r
- 3. All advertising materials mentioning features or use of this software\r
- must display the following acknowledgement:\r
- This product includes software developed by the University of\r
- California, Berkeley and its contributors.\r
- 4. Neither the name of the University nor the names of its contributors\r
- may be used to endorse or promote products derived from this software\r
- without specific prior written permission.\r
-\r
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\r
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\r
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
- SUCH DAMAGE.\r
-\r
- NetBSD: strftime.c,v 1.17.4.1 2007/08/21 20:08:21 liamjfoy Exp\r
-**/\r
-#include <LibConfig.h>\r
-#include <sys/EfiCdefs.h>\r
-\r
-#include "namespace.h"\r
-#include <time.h>\r
-#include "tzfile.h"\r
-#include "TimeVals.h"\r
-#include "fcntl.h"\r
-#include "locale.h"\r
-\r
-#include "sys/localedef.h"\r
-#include <MainData.h>\r
-\r
-/*\r
-** We don't use these extensions in strftime operation even when\r
-** supported by the local tzcode configuration. A strictly\r
-** conforming C application may leave them in undefined state.\r
-*/\r
-\r
-#ifdef _LIBC\r
-#undef TM_ZONE\r
-#undef TM_GMTOFF\r
-#endif\r
-\r
-#define Locale _CurrentTimeLocale\r
-\r
-static char * _add(const char *, char *, const char * const);\r
-static char * _conv(const int, const char * const, char * const, const char * const);\r
-static char * _fmt(const char *, const struct tm * const, char *, const char * const, int *);\r
-\r
-#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU\r
-\r
-#ifndef YEAR_2000_NAME\r
-#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"\r
-#endif /* !defined YEAR_2000_NAME */\r
-\r
-\r
-#define IN_NONE 0\r
-#define IN_SOME 1\r
-#define IN_THIS 2\r
-#define IN_ALL 3\r
-\r
-size_t\r
-strftime(\r
- char * __restrict s,\r
- size_t maxsize,\r
- const char * __restrict format,\r
- const struct tm * __restrict timeptr\r
- )\r
-{\r
- char * p;\r
- int warn;\r
-\r
- tzset();\r
- warn = IN_NONE;\r
- p = _fmt(((format == NULL) ? "%c" : format), timeptr, s, s + maxsize, &warn);\r
-\r
-#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU\r
- if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {\r
- (void) fprintf(stderr, "\n");\r
- if (format == NULL)\r
- (void) fprintf(stderr, "NULL strftime format ");\r
- else (void) fprintf(stderr, "strftime format \"%s\" ",\r
- format);\r
- (void) fprintf(stderr, "yields only two digits of years in ");\r
- if (warn == IN_SOME)\r
- (void) fprintf(stderr, "some locales");\r
- else if (warn == IN_THIS)\r
- (void) fprintf(stderr, "the current locale");\r
- else (void) fprintf(stderr, "all locales");\r
- (void) fprintf(stderr, "\n");\r
- }\r
-#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */\r
-\r
- if (p == s + maxsize)\r
- return 0;\r
- *p = '\0';\r
- return p - s;\r
-}\r
-\r
-static char *\r
-_fmt(\r
- const char * format,\r
- const struct tm * const t,\r
- char * pt,\r
- const char * const ptlim,\r
- int * warnp\r
- )\r
-{\r
- for ( ; *format; ++format) {\r
- if (*format == '%') {\r
-label:\r
- switch (*++format) {\r
- case '\0':\r
- --format;\r
- break;\r
- case 'A':\r
- pt = _add((t->tm_wday < 0 ||\r
- t->tm_wday >= DAYSPERWEEK) ?\r
- "?" : Locale->day[t->tm_wday],\r
- pt, ptlim);\r
- continue;\r
- case 'a':\r
- pt = _add((t->tm_wday < 0 ||\r
- t->tm_wday >= DAYSPERWEEK) ?\r
- "?" : Locale->abday[t->tm_wday],\r
- pt, ptlim);\r
- continue;\r
- case 'B':\r
- pt = _add((t->tm_mon < 0 ||\r
- t->tm_mon >= MONSPERYEAR) ?\r
- "?" : Locale->mon[t->tm_mon],\r
- pt, ptlim);\r
- continue;\r
- case 'b':\r
- case 'h':\r
- pt = _add((t->tm_mon < 0 ||\r
- t->tm_mon >= MONSPERYEAR) ?\r
- "?" : Locale->abmon[t->tm_mon],\r
- pt, ptlim);\r
- continue;\r
- case 'C':\r
- /*\r
- ** %C used to do a...\r
- ** _fmt("%a %b %e %X %Y", t);\r
- ** ...whereas now POSIX 1003.2 calls for\r
- ** something completely different.\r
- ** (ado, 1993-05-24)\r
- */\r
- pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,\r
- "%02d", pt, ptlim);\r
- continue;\r
- case 'c':\r
- {\r
- int warn2 = IN_SOME;\r
-\r
- pt = _fmt(Locale->d_t_fmt, t, pt, ptlim, &warn2);\r
- if (warn2 == IN_ALL)\r
- warn2 = IN_THIS;\r
- if (warn2 > *warnp)\r
- *warnp = warn2;\r
- }\r
- continue;\r
- case 'D':\r
- pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);\r
- continue;\r
- case 'd':\r
- pt = _conv(t->tm_mday, "%02d", pt, ptlim);\r
- continue;\r
- case 'E':\r
- case 'O':\r
- /*\r
- ** C99 locale modifiers.\r
- ** The sequences\r
- ** %Ec %EC %Ex %EX %Ey %EY\r
- ** %Od %oe %OH %OI %Om %OM\r
- ** %OS %Ou %OU %OV %Ow %OW %Oy\r
- ** are supposed to provide alternate\r
- ** representations.\r
- */\r
- goto label;\r
- case 'e':\r
- pt = _conv(t->tm_mday, "%2d", pt, ptlim);\r
- continue;\r
- case 'F':\r
- pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);\r
- continue;\r
- case 'H':\r
- pt = _conv(t->tm_hour, "%02d", pt, ptlim);\r
- continue;\r
- case 'I':\r
- pt = _conv((t->tm_hour % 12) ?\r
- (t->tm_hour % 12) : 12,\r
- "%02d", pt, ptlim);\r
- continue;\r
- case 'j':\r
- pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);\r
- continue;\r
- case 'k':\r
- /*\r
- ** This used to be...\r
- ** _conv(t->tm_hour % 12 ?\r
- ** t->tm_hour % 12 : 12, 2, ' ');\r
- ** ...and has been changed to the below to\r
- ** match SunOS 4.1.1 and Arnold Robbins'\r
- ** strftime version 3.0. That is, "%k" and\r
- ** "%l" have been swapped.\r
- ** (ado, 1993-05-24)\r
- */\r
- pt = _conv(t->tm_hour, "%2d", pt, ptlim);\r
- continue;\r
-#ifdef KITCHEN_SINK\r
- case 'K':\r
- /*\r
- ** After all this time, still unclaimed!\r
- */\r
- pt = _add("kitchen sink", pt, ptlim);\r
- continue;\r
-#endif /* defined KITCHEN_SINK */\r
- case 'l':\r
- /*\r
- ** This used to be...\r
- ** _conv(t->tm_hour, 2, ' ');\r
- ** ...and has been changed to the below to\r
- ** match SunOS 4.1.1 and Arnold Robbin's\r
- ** strftime version 3.0. That is, "%k" and\r
- ** "%l" have been swapped.\r
- ** (ado, 1993-05-24)\r
- */\r
- pt = _conv((t->tm_hour % 12) ?\r
- (t->tm_hour % 12) : 12,\r
- "%2d", pt, ptlim);\r
- continue;\r
- case 'M':\r
- pt = _conv(t->tm_min, "%02d", pt, ptlim);\r
- continue;\r
- case 'm':\r
- pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);\r
- continue;\r
- case 'n':\r
- pt = _add("\n", pt, ptlim);\r
- continue;\r
- case 'p':\r
- pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?\r
- Locale->am_pm[1] :\r
- Locale->am_pm[0],\r
- pt, ptlim);\r
- continue;\r
- case 'R':\r
- pt = _fmt("%H:%M", t, pt, ptlim, warnp);\r
- continue;\r
- case 'r':\r
- pt = _fmt(Locale->t_fmt_ampm, t, pt, ptlim,\r
- warnp);\r
- continue;\r
- case 'S':\r
- pt = _conv(t->tm_sec, "%02d", pt, ptlim);\r
- continue;\r
- case 's':\r
- {\r
- struct tm tm;\r
- char buf[INT_STRLEN_MAXIMUM(\r
- time_t) + 1];\r
- time_t mkt;\r
-\r
- tm = *t;\r
- mkt = mktime(&tm);\r
- /* CONSTCOND */\r
- if (TYPE_SIGNED(time_t))\r
- (void) sprintf(buf, "%ld",\r
- (long) mkt);\r
- else (void) sprintf(buf, "%lu",\r
- (unsigned long) mkt);\r
- pt = _add(buf, pt, ptlim);\r
- }\r
- continue;\r
- case 'T':\r
- pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);\r
- continue;\r
- case 't':\r
- pt = _add("\t", pt, ptlim);\r
- continue;\r
- case 'U':\r
- pt = _conv((t->tm_yday + DAYSPERWEEK -\r
- t->tm_wday) / DAYSPERWEEK,\r
- "%02d", pt, ptlim);\r
- continue;\r
- case 'u':\r
- /*\r
- ** From Arnold Robbins' strftime version 3.0:\r
- ** "ISO 8601: Weekday as a decimal number\r
- ** [1 (Monday) - 7]"\r
- ** (ado, 1993-05-24)\r
- */\r
- pt = _conv((t->tm_wday == 0) ?\r
- DAYSPERWEEK : t->tm_wday,\r
- "%d", pt, ptlim);\r
- continue;\r
- case 'V': /* ISO 8601 week number */\r
- case 'G': /* ISO 8601 year (four digits) */\r
- case 'g': /* ISO 8601 year (two digits) */\r
-/*\r
-** From Arnold Robbins' strftime version 3.0: "the week number of the\r
-** year (the first Monday as the first day of week 1) as a decimal number\r
-** (01-53)."\r
-** (ado, 1993-05-24)\r
-**\r
-** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:\r
-** "Week 01 of a year is per definition the first week which has the\r
-** Thursday in this year, which is equivalent to the week which contains\r
-** the fourth day of January. In other words, the first week of a new year\r
-** is the week which has the majority of its days in the new year. Week 01\r
-** might also contain days from the previous year and the week before week\r
-** 01 of a year is the last week (52 or 53) of the previous year even if\r
-** it contains days from the new year. A week starts with Monday (day 1)\r
-** and ends with Sunday (day 7). For example, the first week of the year\r
-** 1997 lasts from 1996-12-30 to 1997-01-05..."\r
-** (ado, 1996-01-02)\r
-*/\r
- {\r
- int year;\r
- int yday;\r
- int wday;\r
- int w;\r
-\r
- year = t->tm_year + TM_YEAR_BASE;\r
- yday = t->tm_yday;\r
- wday = t->tm_wday;\r
- for ( ; ; ) {\r
- int len;\r
- int bot;\r
- int top;\r
-\r
- len = isleap(year) ?\r
- DAYSPERLYEAR :\r
- DAYSPERNYEAR;\r
- /*\r
- ** What yday (-3 ... 3) does\r
- ** the ISO year begin on?\r
- */\r
- bot = ((yday + 11 - wday) %\r
- DAYSPERWEEK) - 3;\r
- /*\r
- ** What yday does the NEXT\r
- ** ISO year begin on?\r
- */\r
- top = bot -\r
- (len % DAYSPERWEEK);\r
- if (top < -3)\r
- top += DAYSPERWEEK;\r
- top += len;\r
- if (yday >= top) {\r
- ++year;\r
- w = 1;\r
- break;\r
- }\r
- if (yday >= bot) {\r
- w = 1 + ((yday - bot) /\r
- DAYSPERWEEK);\r
- break;\r
- }\r
- --year;\r
- yday += isleap(year) ?\r
- DAYSPERLYEAR :\r
- DAYSPERNYEAR;\r
- }\r
-#ifdef XPG4_1994_04_09\r
- if ((w == 52\r
- && t->tm_mon == TM_JANUARY)\r
- || (w == 1\r
- && t->tm_mon == TM_DECEMBER))\r
- w = 53;\r
-#endif /* defined XPG4_1994_04_09 */\r
- if (*format == 'V')\r
- pt = _conv(w, "%02d",\r
- pt, ptlim);\r
- else if (*format == 'g') {\r
- *warnp = IN_ALL;\r
- pt = _conv(year % 100, "%02d",\r
- pt, ptlim);\r
- } else pt = _conv(year, "%04d",\r
- pt, ptlim);\r
- }\r
- continue;\r
- case 'v':\r
- /*\r
- ** From Arnold Robbins' strftime version 3.0:\r
- ** "date as dd-bbb-YYYY"\r
- ** (ado, 1993-05-24)\r
- */\r
- pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);\r
- continue;\r
- case 'W':\r
- pt = _conv((t->tm_yday + DAYSPERWEEK -\r
- (t->tm_wday ?\r
- (t->tm_wday - 1) :\r
- (DAYSPERWEEK - 1))) / DAYSPERWEEK,\r
- "%02d", pt, ptlim);\r
- continue;\r
- case 'w':\r
- pt = _conv(t->tm_wday, "%d", pt, ptlim);\r
- continue;\r
- case 'X':\r
- pt = _fmt(Locale->t_fmt, t, pt, ptlim, warnp);\r
- continue;\r
- case 'x':\r
- {\r
- int warn2 = IN_SOME;\r
-\r
- pt = _fmt(Locale->d_fmt, t, pt, ptlim, &warn2);\r
- if (warn2 == IN_ALL)\r
- warn2 = IN_THIS;\r
- if (warn2 > *warnp)\r
- *warnp = warn2;\r
- }\r
- continue;\r
- case 'y':\r
- *warnp = IN_ALL;\r
- pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,\r
- "%02d", pt, ptlim);\r
- continue;\r
- case 'Y':\r
- pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",\r
- pt, ptlim);\r
- continue;\r
- case 'Z':\r
-#ifdef TM_ZONE\r
- if (t->TM_ZONE != NULL)\r
- pt = _add(t->TM_ZONE, pt, ptlim);\r
- else\r
-#endif /* defined TM_ZONE */\r
- if (t->tm_isdst >= 0)\r
- pt = _add(tzname[t->tm_isdst != 0],\r
- pt, ptlim);\r
- /*\r
- ** C99 says that %Z must be replaced by the\r
- ** empty string if the time zone is not\r
- ** determinable.\r
- */\r
- continue;\r
- case 'z':\r
- {\r
- int diff;\r
- char const * sign;\r
-\r
- if (t->tm_isdst < 0)\r
- continue;\r
-#ifdef TM_GMTOFF\r
- diff = (int)t->TM_GMTOFF;\r
-#else /* !defined TM_GMTOFF */\r
- /*\r
- ** C99 says that the UTC offset must\r
- ** be computed by looking only at\r
- ** tm_isdst. This requirement is\r
- ** incorrect, since it means the code\r
- ** must rely on magic (in this case\r
- ** altzone and timezone), and the\r
- ** magic might not have the correct\r
- ** offset. Doing things correctly is\r
- ** tricky and requires disobeying C99;\r
- ** see GNU C strftime for details.\r
- ** For now, punt and conform to the\r
- ** standard, even though it's incorrect.\r
- **\r
- ** C99 says that %z must be replaced by the\r
- ** empty string if the time zone is not\r
- ** determinable, so output nothing if the\r
- ** appropriate variables are not available.\r
- */\r
-#ifndef STD_INSPIRED\r
- if (t->tm_isdst == 0)\r
-#ifdef USG_COMPAT\r
- diff = -timezone;\r
-#else /* !defined USG_COMPAT */\r
- continue;\r
-#endif /* !defined USG_COMPAT */\r
- else\r
-#ifdef ALTZONE\r
- diff = -altzone;\r
-#else /* !defined ALTZONE */\r
- continue;\r
-#endif /* !defined ALTZONE */\r
-#else /* defined STD_INSPIRED */\r
- {\r
- struct tm tmp;\r
- time_t lct, gct;\r
-\r
- /*\r
- ** Get calendar time from t\r
- ** being treated as local.\r
- */\r
- tmp = *t; /* mktime discards const */\r
- lct = mktime(&tmp);\r
-\r
- if (lct == (time_t)-1)\r
- continue;\r
-\r
- /*\r
- ** Get calendar time from t\r
- ** being treated as GMT.\r
- **/\r
- tmp = *t; /* mktime discards const */\r
- gct = timegm(&tmp);\r
-\r
- if (gct == (time_t)-1)\r
- continue;\r
-\r
- /* LINTED difference will fit int */\r
- diff = (intmax_t)gct - (intmax_t)lct;\r
- }\r
-#endif /* defined STD_INSPIRED */\r
-#endif /* !defined TM_GMTOFF */\r
- if (diff < 0) {\r
- sign = "-";\r
- diff = -diff;\r
- } else sign = "+";\r
- pt = _add(sign, pt, ptlim);\r
- diff /= 60;\r
- pt = _conv((diff/60)*100 + diff%60,\r
- "%04d", pt, ptlim);\r
- }\r
- continue;\r
-#if 0\r
- case '+':\r
- pt = _fmt(Locale->date_fmt, t, pt, ptlim,\r
- warnp);\r
- continue;\r
-#endif\r
- case '%':\r
- /*\r
- ** X311J/88-090 (4.12.3.5): if conversion char is\r
- ** undefined, behavior is undefined. Print out the\r
- ** character itself as printf(3) also does.\r
- */\r
- default:\r
- break;\r
- }\r
- }\r
- if (pt == ptlim)\r
- break;\r
- *pt++ = *format;\r
- }\r
- return pt;\r
-}\r
-\r
-static char *\r
-_conv(\r
- const int n,\r
- const char * const format,\r
- char * const pt,\r
- const char * const ptlim\r
-)\r
-{\r
- char buf[INT_STRLEN_MAXIMUM(int) + 1];\r
-\r
- (void) sprintf(buf, format, n);\r
- return _add(buf, pt, ptlim);\r
-}\r
-\r
-static char *\r
-_add(\r
- const char * str,\r
- char * pt,\r
- const char * const ptlim\r
-)\r
-{\r
- while (pt < ptlim && (*pt = *str++) != '\0')\r
- ++pt;\r
- return pt;\r
-}\r