home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / time / strftime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-30  |  9.2 KB  |  365 lines

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