home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / time / strftime.c.aod < prev    next >
Encoding:
Text File  |  1993-07-12  |  9.6 KB  |  387 lines

  1. #ifdef __linux__
  2. #define NOID
  3. #endif
  4.  
  5. #ifndef lint
  6. #ifndef NOID
  7. static char    elsieid[] = "@(#)strftime.c    7.15";
  8. /*
  9. ** Based on the UCB version whose ID appears below.
  10. ** This is ANSIish only when time is treated identically in all locales and
  11. ** when "multibyte character == plain character".
  12. */
  13. #endif /* !defined NOID */
  14. #endif /* !defined lint */
  15. /*
  16.  * Copyright (c) 1989 The Regents of the University of California.
  17.  * All rights reserved.
  18.  *
  19.  * Redistribution and use in source and binary forms are permitted
  20.  * provided that the above copyright notice and this paragraph are
  21.  * duplicated in all such forms and that any documentation,
  22.  * advertising materials, and other materials related to such
  23.  * distribution and use acknowledge that the software was developed
  24.  * by the University of California, Berkeley.  The name of the
  25.  * University may not be used to endorse or promote products derived
  26.  * from this software without specific prior written permission.
  27.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  28.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  29.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  30.  */
  31.  
  32. #if defined(LIBC_SCCS) && !defined(lint)
  33. static const char sccsid[] = "@(#)strftime.c    5.4 (Berkeley) 3/14/89";
  34. #endif /* LIBC_SCCS and not lint */
  35.  
  36. #ifdef __linux__
  37. #include <stdio.h>
  38. #include <sys/types.h>
  39. #include <limits.h>
  40. #include <time.h>
  41.  
  42. #define P(x)    __P(x)
  43.  
  44. #ifndef INT_STRLEN_MAXIMUM
  45. /*
  46. ** 302 / 1000 is log10(2.0) rounded up.
  47. ** Subtract one for the sign bit;
  48. ** add one for integer division truncation;
  49. ** add one more for a minus sign.
  50. */
  51. #define INT_STRLEN_MAXIMUM(type) \
  52.     ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2)
  53. #endif /* !defined INT_STRLEN_MAXIMUM */
  54.  
  55. #else
  56. #include "private.h"
  57. #endif
  58.  
  59. #include "tzfile.h"
  60.  
  61. static const char afmt[][4] = {
  62.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  63. };
  64. static const char Afmt[][10] = {
  65.     "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  66.     "Saturday"
  67. };
  68. static const char bfmt[][4] = {
  69.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
  70.     "Oct", "Nov", "Dec"
  71. };
  72. static const char Bfmt[][10] = {
  73.     "January", "February", "March", "April", "May", "June", "July",
  74.     "August", "September", "October", "November", "December"
  75. };
  76.  
  77. static char *_add P((const char *, char *, const char *));
  78. static char *_conv P((int, const char *, char *, const char *));
  79. static char *_fmt P((const char *, const struct tm *, char *, const char *));
  80.  
  81. size_t strftime P((char *, size_t, const char *, const struct tm *));
  82.  
  83. extern char *tzname[];
  84.  
  85. size_t
  86. strftime(s, maxsize, format, t)
  87.     char *s;
  88.     size_t maxsize;
  89.     const char *format;
  90.     const struct tm *t;
  91. {
  92.     char *p;
  93.  
  94.     p = _fmt(format, t, s, s + maxsize);
  95.     if (p == s + maxsize)
  96.         return 0;
  97.     *p = '\0';
  98.     return p - s;
  99. }
  100.  
  101. static char *
  102. _fmt(format, t, pt, ptlim)
  103.     const char *format;
  104.     const struct tm *t;
  105.     char *pt;
  106.     const char *ptlim;
  107. {
  108.     for (; *format; ++format) {
  109.         if (*format == '%') {
  110. label:
  111.             switch(*++format) {
  112.             case '\0':
  113.                 --format;
  114.                 break;
  115.             case 'A':
  116.                 pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
  117.                     "?" : Afmt[t->tm_wday], pt, ptlim);
  118.                 continue;
  119.             case 'a':
  120.                 pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
  121.                     "?" : afmt[t->tm_wday], pt, ptlim);
  122.                 continue;
  123.             case 'B':
  124.                 pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
  125.                     "?" : Bfmt[t->tm_mon], pt, ptlim);
  126.                 continue;
  127.             case 'b':
  128.             case 'h':
  129.                 pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
  130.                     "?" : bfmt[t->tm_mon], pt, ptlim);
  131.                 continue;
  132.             case 'c':
  133.                 pt = _fmt("%D %X", t, pt, ptlim);
  134.                 continue;
  135.             case 'C':
  136.                 /*
  137.                 ** %C used to do a...
  138.                 **    _fmt("%a %b %e %X %Y", t);
  139.                 ** ...whereas now POSIX 1003.2 calls for
  140.                 ** something completely different.
  141.                 ** (ado, 5/24/93)
  142.                 */
  143.                 pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
  144.                     "%02d", pt, ptlim);
  145.                 continue;
  146.             case 'D':
  147.                 pt = _fmt("%m/%d/%y", t, pt, ptlim);
  148.                 continue;
  149.             case 'x':
  150.                 /*
  151.                 ** Version 3.0 of strftime from Arnold Robbins
  152.                 ** (arnold@skeeve.atl.ga.us) does the
  153.                 ** equivalent of...
  154.                 **    _fmt("%a %b %e %Y");
  155.                 ** ...for %x; since the X3J11 C language
  156.                 ** standard calls for "date, using locale's
  157.                 ** date format," anything goes.  Using just
  158.                 ** numbers (as here) makes Quakers happier.
  159.                 ** Word from Paul Eggert (eggert@twinsun.com)
  160.                 ** is that %Y-%m-%d is the ISO standard date
  161.                 ** format, specified in ISO 2014 and later
  162.                 ** ISO 8601:1988, with a summary available in
  163.                 ** pub/doc/ISO/english/ISO8601.ps.Z on
  164.                 ** ftp.uni-erlangen.de.
  165.                 ** (ado, 5/30/93)
  166.                 */
  167.                 pt = _fmt("%m/%d/%y", t, pt, ptlim);
  168.                 continue;
  169.             case 'd':
  170.                 pt = _conv(t->tm_mday, "%02d", pt, ptlim);
  171.                 continue;
  172.             case 'E':
  173.             case 'O':
  174.                 /*
  175.                 ** POSIX locale extensions, a la
  176.                 ** Arnold Robbins' strftime version 3.0.
  177.                 ** The sequences
  178.                 **    %Ec %EC %Ex %Ey %EY
  179.                 **    %Od %oe %OH %OI %Om %OM
  180.                 **    %OS %Ou %OU %OV %Ow %OW %Oy
  181.                 ** are supposed to provide alternate
  182.                 ** representations.
  183.                 ** (ado, 5/24/93)
  184.                 */
  185.                 goto label;
  186.             case 'e':
  187.                 pt = _conv(t->tm_mday, "%2d", pt, ptlim);
  188.                 continue;
  189.             case 'H':
  190.                 pt = _conv(t->tm_hour, "%02d", pt, ptlim);
  191.                 continue;
  192.             case 'I':
  193.                 pt = _conv((t->tm_hour % 12) ?
  194.                     (t->tm_hour % 12) : 12,
  195.                     "%02d", pt, ptlim);
  196.                 continue;
  197.             case 'j':
  198.                 pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
  199.                 continue;
  200.             case 'k':
  201.                 /*
  202.                 ** This used to be...
  203.                 **    _conv(t->tm_hour % 12 ?
  204.                 **        t->tm_hour % 12 : 12, 2, ' ');
  205.                 ** ...and has been changed to the below to
  206.                 ** match SunOS 4.1.1 and Arnold Robbins'
  207.                 ** strftime version 3.0.  That is, "%k" and
  208.                 ** "%l" have been swapped.
  209.                 ** (ado, 5/24/93)
  210.                 */
  211.                 pt = _conv(t->tm_hour, "%2d", pt, ptlim);
  212.                 continue;
  213. #ifdef KITCHEN_SINK
  214.             case 'K':
  215.                 /*
  216.                 ** After all this time, still unclaimed!
  217.                 */
  218.                 pt = _add("kitchen sink", pt, ptlim);
  219.                 continue;
  220. #endif /* defined KITCHEN_SINK */
  221.             case 'l':
  222.                 /*
  223.                 ** This used to be...
  224.                 **    _conv(t->tm_hour, 2, ' ');
  225.                 ** ...and has been changed to the below to
  226.                 ** match SunOS 4.1.1 and Arnold Robbin's
  227.                 ** strftime version 3.0.  That is, "%k" and
  228.                 ** "%l" have been swapped.
  229.                 ** (ado, 5/24/93)
  230.                 */
  231.                 pt = _conv((t->tm_hour % 12) ?
  232.                     (t->tm_hour % 12) : 12,
  233.                     "%2d", pt, ptlim);
  234.                 continue;
  235.             case 'M':
  236.                 pt = _conv(t->tm_min, "%02d", pt, ptlim);
  237.                 continue;
  238.             case 'm':
  239.                 pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
  240.                 continue;
  241.             case 'n':
  242.                 pt = _add("\n", pt, ptlim);
  243.                 continue;
  244.             case 'p':
  245.                 pt = _add(t->tm_hour >= 12 ? "PM" : "AM",
  246.                     pt, ptlim);
  247.                 continue;
  248.             case 'R':
  249.                 pt = _fmt("%H:%M", t, pt, ptlim);
  250.                 continue;
  251.             case 'r':
  252.                 pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
  253.                 continue;
  254.             case 'S':
  255.                 pt = _conv(t->tm_sec, "%02d", pt, ptlim);
  256.                 continue;
  257.             case 'T':
  258.             case 'X':
  259.                 pt = _fmt("%H:%M:%S", t, pt, ptlim);
  260.                 continue;
  261.             case 't':
  262.                 pt = _add("\t", pt, ptlim);
  263.                 continue;
  264.             case 'U':
  265.                 pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
  266.                     "%02d", pt, ptlim);
  267.                 continue;
  268.             case 'u':
  269.                 /*
  270.                 ** From Arnold Robbins' strftime version 3.0:
  271.                 ** "ISO 8601: Weekday as a decimal number
  272.                 ** [1 (Monday) - 7]"
  273.                 ** (ado, 5/24/93)
  274.                 */
  275.                 pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
  276.                     "%d", pt, ptlim);
  277.                 continue;
  278.             case 'V':
  279.                 /*
  280.                 ** From Arnold Robbins' strftime version 3.0:
  281.                 ** "the week number of the year (the first
  282.                 ** Monday as the first day of week 1) as a
  283.                 ** decimal number (01-53).  The method for
  284.                 ** determining the week number is as specified
  285.                 ** by ISO 8601 (to wit: if the week containing
  286.                 ** January 1 has four or more days in the new
  287.                 ** year, then it is week 1, otherwise it is
  288.                 ** week 53 of the previous year and the next
  289.                 ** week is week 1)."
  290.                 ** (ado, 5/24/93)
  291.                 */
  292.                 /*
  293.                 ** XXX--If January 1 falls on a Friday,
  294.                 ** January 1-3 are part of week 53 of the
  295.                 ** previous year.  By analogy, if January
  296.                 ** 1 falls on a Thursday, are December 29-31
  297.                 ** of the PREVIOUS year part of week 1???
  298.                 ** (ado 5/24/93)
  299.                 **
  300.                 ** You are understood not to expect this.
  301.                 */
  302.                 {
  303.                     int i;
  304.  
  305.                     i = (t->tm_yday + 10 - (t->tm_wday ?
  306.                         (t->tm_wday - 1) : 6)) / 7;
  307.                     pt = _conv((i == 0) ? 53 : i,
  308.                         "%02d", pt, ptlim);
  309.                 }
  310.                 continue;
  311.             case 'v':
  312.                 /*
  313.                 ** From Arnold Robbins' strftime version 3.0:
  314.                 ** "date as dd-bbb-YYYY"
  315.                 ** (ado, 5/24/93)
  316.                 */
  317.                 pt = _fmt("%e-%b-%Y", t, pt, ptlim);
  318.                 continue;
  319.             case 'W':
  320.                 pt = _conv((t->tm_yday + 7 -
  321.                     (t->tm_wday ?
  322.                     (t->tm_wday - 1) : 6)) / 7,
  323.                     "%02d", pt, ptlim);
  324.                 continue;
  325.             case 'w':
  326.                 pt = _conv(t->tm_wday, "%d", pt, ptlim);
  327.                 continue;
  328.             case 'y':
  329.                 pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
  330.                     "%02d", pt, ptlim);
  331.                 continue;
  332.             case 'Y':
  333.                 pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
  334.                     pt, ptlim);
  335.                 continue;
  336.             case 'Z':
  337. #ifdef TM_ZONE
  338.                 if (t->TM_ZONE)
  339.                     pt = _add(t->TM_ZONE, pt, ptlim);
  340.                 else
  341. #endif /* defined TM_ZONE */
  342.                 if (t->tm_isdst == 0 || t->tm_isdst == 1) {
  343.                     pt = _add(tzname[t->tm_isdst],
  344.                         pt, ptlim);
  345.                 } else  pt = _add("?", pt, ptlim);
  346.                 continue;
  347.             case '%':
  348.             /*
  349.              * X311J/88-090 (4.12.3.5): if conversion char is
  350.              * undefined, behavior is undefined.  Print out the
  351.              * character itself as printf(3) also does.
  352.              */
  353.             default:
  354.                 break;
  355.             }
  356.         }
  357.         if (pt == ptlim)
  358.             break;
  359.         *pt++ = *format;
  360.     }
  361.     return pt;
  362. }
  363.  
  364. static char *
  365. _conv(n, format, pt, ptlim)
  366.     int n;
  367.     const char *format;
  368.     char *pt;
  369.     const char *ptlim;
  370. {
  371.     char buf[INT_STRLEN_MAXIMUM(int) + 1];
  372.  
  373.     (void) sprintf(buf, format, n);
  374.     return _add(buf, pt, ptlim);
  375. }
  376.  
  377. static char *
  378. _add(str, pt, ptlim)
  379.     const char *str;
  380.     char *pt;
  381.     const char *ptlim;
  382. {
  383.     while (pt < ptlim && (*pt = *str++) != '\0')
  384.         ++pt;
  385.     return pt;
  386. }
  387.