home *** CD-ROM | disk | FTP | other *** search
- /*
- * strftime: print formatted information about a given time
- * Written by Eric R. Smith and placed in the public domain.
- *
- * With further modifications by Michal Jaegermann.
- * Formats in SYSV_EXT from PD strftime source by Arnold Robins.
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <ctype.h>
- #include <string.h>
-
- #define BIG_LEN 80
-
- static int weeknumber __PROTO((const struct tm *timeptr, int firstweekday));
-
-
- extern char **_LC_Mth_name; /* in setlocale.c */
- extern char **_LC_Day_name;
-
- /*
- * FIXME: I'm not sure what the formats for 'c', 'x', and 'X' should be
- * for various locales, or even for the "C" locale. I've assumed that
- * 'c' gives the same as asctime(), 'x' is e.g. Jan 01 1970, and
- * 'X' is e.g. 12:20:37.
- *
- * I would venture that for "C" locale these formats are fine - mj.
- */
-
- size_t
- strftime(str, maxsize, fmt, ts)
- char *str;
- size_t maxsize;
- const char *fmt;
- const struct tm *ts;
- {
- int num = 0;
- int len = 0, n;
- char q;
- char buf[BIG_LEN], *putstr, *s;
-
- for(;;) {
- if (num >= maxsize) return 0;
- if (!(q = *fmt++)) break;
- if (q != '%') {
- *str++ = q;
- num++;
- continue;
- }
- if (!(q = *fmt++)) break; /* get format command */
-
- /* assume that sprintf will be used, with a variable length */
- /* this is the most common case, so it saves us some coding to do it here */
- putstr = buf;
-
- switch(q) {
- case 'A':
- case 'a':
- /*
- * cases 'a' and 'b' are still wrong -
- * in some locale short names do not have to be
- * 3 characters wide - still works in North America.
- */
- if (ts->tm_wday < 0 || ts->tm_wday > 6)
- putstr = "?";
- else
- if ( 'A' == q)
- putstr = _LC_Day_name[ts->tm_wday];
- else
- sprintf(buf, "%-.3s",
- _LC_Day_name[ts->tm_wday]);
- break;
- case 'B':
- case 'b':
- #ifdef SYSV_EXT
- case 'h': /* same as 'b' */
- #endif
- if (ts->tm_mon < 0 || ts->tm_mon > 11)
- putstr = "?";
- else
- if ( 'B' == q)
- putstr = _LC_Mth_name[ts->tm_mon];
- else
- sprintf(buf, "%-.3s",
- _LC_Mth_name[ts->tm_mon]);
- break;
- case 'c':
- /* this format should be set in setlocale.c */
- strftime(buf, sizeof buf, "%a %b %d %X %Y", ts);
- break;
- case 'd':
- sprintf(buf, "%02d", ts->tm_mday);
- break;
- case 'H':
- sprintf(buf, "%02d", ts->tm_hour);
- break;
- case 'I':
- n = ts->tm_hour;
- if (n == 0) n = 12;
- else if (n > 12) n -= 12;
- sprintf(buf, "%02d", n);
- break;
- case 'j':
- sprintf(buf, "%03d", ts->tm_yday + 1);
- break;
- case 'm':
- sprintf(buf, "%02d", ts->tm_mon + 1);
- break;
- case 'M':
- sprintf(buf, "%02d", ts->tm_min);
- break;
- case 'p':
- /*
- * this is wrong - strings "AM', "PM" are
- * locale dependent
- */
- putstr = (ts->tm_hour < 12) ? "AM" : "PM";
- break;
- case 'S':
- sprintf(buf, "%02d", ts->tm_sec);
- break;
- case 'U': /* week of year - starting Sunday */
- sprintf(buf, "%02d", weeknumber(ts, 0));
- break;
- case 'W': /* week of year - starting Monday */
- sprintf(buf, "%02d", weeknumber(ts, 1));
- break;
- case 'w':
- sprintf(buf, "%d", ts->tm_wday);
- break;
- case 'x':
- /* once again - format may be locale dependent */
- strftime(buf, sizeof buf, "%b %d %Y", ts);
- break;
- case 'X':
- /* same applies to this format as well */
- sprintf(buf, "%02d:%02d:%02d", ts->tm_hour,
- ts->tm_min, ts->tm_sec);
- break;
- case 'y':
- sprintf(buf, "%02d", ts->tm_year % 100);
- break;
- case 'Y':
- sprintf(buf, "%d", ts->tm_year + 1900);
- break;
- case 'Z':
- if (NULL != (s = getenv("TZ"))) {
- strcpy(buf, s);
- s = buf;
- if (ts->tm_isdst) {
- while (*s && isalpha(*s)) s++;
- while (*s && (isdigit(*s)||
- *s == '+' ||
- *s == '-' ||
- *s == ':')) {
- s++;
- };
- if (*s)
- putstr = s;
- }
- s = putstr;
- while (*s && isalpha(*s))
- s++;
- *s++ = 0;
- }
- else
- buf[0] = '\0'; /* empty string */
- break;
- case '%':
- putstr = "%";
- break;
- #ifdef SYSV_EXT
- case 'n': /* same as \n */
- putstr = "\n";
- break;
- case 't': /* same as \t */
- putstr = "\n";
- break;
- break;
- case 'D': /* date as %m/%d/%y */
- strftime(buf, sizeof buf, "%m/%d/%y", ts);
- break;
- case 'e': /* day of month, blank padded */
- sprintf(buf, "%2d", ts->tm_mday);
- break;
- case 'r': /* time as %I:%M:%S %p */
- strftime(buf, sizeof buf, "%I:%M:%S %p", ts);
- break;
- case 'R': /* time as %H:%M */
- strftime(buf, sizeof buf, "%H:%M", ts);
- break;
- case 'T': /* time as %H:%M:%S */
- strftime(buf, sizeof buf, "%H:%M:%S", ts);
- break;
- #endif
- }
-
- if (num + (len = strlen(putstr)) >= maxsize)
- return 0;
-
- num += len;
- while (--len >= 0)
- *str++ = *putstr++;
- }
- *str = 0;
- return (size_t) num;
- }
-
- /*
- * What follows grabbed, with a small change, from PD source of strftime
- * by Arnold Robins - arnold@audiofax.com
- */
- /* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
-
- static int
- weeknumber(timeptr, firstweekday)
- const struct tm *timeptr;
- int firstweekday;
- /*
- * firstweekday is 0 if starting in Sunday, non-zero if in Monday
- */
- {
- return (timeptr->tm_yday - timeptr->tm_wday +
- (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
- }
-