From c768fa74de0a05c284a73c9dc147c55da65ac416 Mon Sep 17 00:00:00 2001 From: oetiker Date: Sun, 10 Apr 2005 11:53:01 +0000 Subject: [PATCH] added extra strftime.[ch] which supports ISO 8601 week numbers, together with instructions in the NT-BUILD-TIPPS file git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@383 a5681a0c-68f1-0310-ab6d-d61299d08faa --- NT-BUILD-TIPS.txt | 7 + confignt/config.h | 1 + src/strftime.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++ src/strftime.h | 18 +++ 4 files changed, 377 insertions(+) create mode 100644 src/strftime.c create mode 100644 src/strftime.h diff --git a/NT-BUILD-TIPS.txt b/NT-BUILD-TIPS.txt index 5fa5e7f..d2f7213 100644 --- a/NT-BUILD-TIPS.txt +++ b/NT-BUILD-TIPS.txt @@ -1,5 +1,12 @@ Compiling RRDtool 1.1.x on Win32 with Microsoft Visual C++: --------------------------------------------------------------- +4/10/05 Tobi +The windows implementation of strftime does not seem to support +the ISO 8601 week number (%V) I have therfore included the file +strftime.[ch] which provides strftime_ ... if you compile rrdtool +with -Dstrftime=_strftime and link strftime.o then you will +get propper support for %V. + 7/29/04 Jake Brutlag As of Jan 2004, code for libraries utilized by rrdtool diff --git a/confignt/config.h b/confignt/config.h index 7b9d68c..62ebc54 100644 --- a/confignt/config.h +++ b/confignt/config.h @@ -27,3 +27,4 @@ #define RRDGRAPH_YLEGEND_ANGLE 90.0 #define HAVE_STRING_H 1 + diff --git a/src/strftime.c b/src/strftime.c new file mode 100644 index 0000000..f349bbf --- /dev/null +++ b/src/strftime.c @@ -0,0 +1,351 @@ +/** + * + * strftime.c + * + * implements the ansi c function strftime() + * + * written 6 september 1989 by jim nutt + * released into the public domain by jim nutt + * + * modified 21-Oct-89 by Rob Duff + * + * modified 08-Dec-04 by Tobi Oetiker (added %V) +**/ + +#include /* for size_t */ +#include /* for va_arg */ +#include /* for struct tm */ +#include "strftime.h" + +static char *aday[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static char *day[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; + +static char *amonth[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char *month[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + +char *tzname_[2] = {"CST", "CDT"}; /* Add your own defaults here */ + +static char buf[26]; + +static void strfmt(char *str, const char *fmt, ...); + +/** + * + * size_t strftime_(char *str, + * size_t maxs, + * const char *fmt, + * const struct tm *t) + * + * this functions acts much like a sprintf for time/date output. + * given a pointer to an output buffer, a format string and a + * time, it copies the time to the output buffer formatted in + * accordance with the format string. the parameters are used + * as follows: + * + * str is a pointer to the output buffer, there should + * be at least maxs characters available at the address + * pointed to by str. + * + * maxs is the maximum number of characters to be copied + * into the output buffer, included the '\0' terminator + * + * fmt is the format string. a percent sign (%) is used + * to indicate that the following character is a special + * format character. the following are valid format + * characters: + * + * %A full weekday name (Monday) + * %a abbreviated weekday name (Mon) + * %B full month name (January) + * %b abbreviated month name (Jan) + * %c standard date and time representation + * %d day-of-month (01-31) + * %H hour (24 hour clock) (00-23) + * %I hour (12 hour clock) (01-12) + * %j day-of-year (001-366) + * %M minute (00-59) + * %m month (01-12) + * %p local equivalent of AM or PM + * %S second (00-59) + * %U week-of-year, first day sunday (00-53) + * %W week-of-year, first day monday (00-53) + * %V ISO 8601 Week number + * %w weekday (0-6, sunday is 0) + * %X standard time representation + * %x standard date representation + * %Y year with century + * %y year without century (00-99) + * %Z timezone name + * %% percent sign + * + * the standard date string is equivalent to: + * + * %a %b %d %Y + * + * the standard time string is equivalent to: + * + * %H:%M:%S + * + * the standard date and time string is equivalent to: + * + * %a %b %d %H:%M:%S %Y + * + * strftime_() returns the number of characters placed in the + * buffer, not including the terminating \0, or zero if more + * than maxs characters were produced. + * +**/ + +size_t strftime_(char *s, size_t maxs, const char *f, const struct tm *t) +{ + int w,d; + char *p, *q, *r; + + p = s; + q = s + maxs - 1; + while ((*f != '\0')) + { + if (*f++ == '%') + { + r = buf; + switch (*f++) + { + case '%' : + r = "%"; + break; + + case 'a' : + r = aday[t->tm_wday]; + break; + + case 'A' : + r = day[t->tm_wday]; + break; + + case 'b' : + r = amonth[t->tm_mon]; + break; + + case 'B' : + r = month[t->tm_mon]; + break; + + case 'c' : + strfmt(r, "%0 %0 %2 %2:%2:%2 %4", + aday[t->tm_wday], amonth[t->tm_mon], + t->tm_mday,t->tm_hour, t->tm_min, + t->tm_sec, t->tm_year+1900); + break; + + case 'd' : + strfmt(r,"%2",t->tm_mday); + break; + + case 'H' : + strfmt(r,"%2",t->tm_hour); + break; + + case 'I' : + strfmt(r,"%2",(t->tm_hour%12)?t->tm_hour%12:12); + break; + + case 'j' : + strfmt(r,"%3",t->tm_yday+1); + break; + + case 'm' : + strfmt(r,"%2",t->tm_mon+1); + break; + + case 'M' : + strfmt(r,"%2",t->tm_min); + break; + + case 'p' : + r = (t->tm_hour>11)?"PM":"AM"; + break; + + case 'S' : + strfmt(r,"%2",t->tm_sec); + break; + + case 'U' : + w = t->tm_yday/7; + if (t->tm_yday%7 > t->tm_wday) + w++; + strfmt(r, "%2", w); + break; + + case 'W' : + w = t->tm_yday/7; + if (t->tm_yday%7 > (t->tm_wday+6)%7) + w++; + strfmt(r, "%2", w); + break; + + case 'V': + + /* ISO 8601 Week Of Year: + If the week (Monday - Sunday) containing January 1 has four or more + days in the new year, then it is week 1; otherwise it is week 53 of + the previous year and the next week is week one. */ + + w = (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) / 7; + d = (t->tm_yday + 7 - (t->tm_wday ? t->tm_wday - 1 : 6)) % 7; + + if (d >= 4) { w++; } else if (w == 0) { w = 53; } + strfmt(r, "%2", w); + break; + + case 'w' : + strfmt(r,"%1",t->tm_wday); + break; + + case 'x' : + strfmt(r, "%3s %3s %2 %4", aday[t->tm_wday], + amonth[t->tm_mon], t->tm_mday, t->tm_year+1900); + break; + + case 'X' : + strfmt(r, "%2:%2:%2", t->tm_hour, + t->tm_min, t->tm_sec); + break; + + case 'y' : + strfmt(r,"%2",t->tm_year%100); + break; + + case 'Y' : + strfmt(r,"%4",t->tm_year+1900); + break; + + case 'Z' : + r = (t->tm_isdst && tzname_[1][0]) ? + tzname_[1] : tzname_[0]; + break; + + default: + buf[0] = '%'; /* reconstruct the format */ + buf[1] = f[-1]; + buf[2] = '\0'; + if (buf[1] == 0) + f--; /* back up if at end of string */ + } + while (*r) + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = *r++; + } + } + else + { + if (p == q) + { + *q = '\0'; + return 0; + } + *p++ = f[-1]; + } + } + *p = '\0'; + return p - s; +} + +/* + * stdarg.h + * +typedef void *va_list; +#define va_start(vp,v) (vp=((char*)&v)+sizeof(v)) +#define va_arg(vp,t) (*((t*)(vp))++) +#define va_end(vp) + * + */ + +static int pow[5] = { 1, 10, 100, 1000, 10000 }; + +/** + * static void strfmt(char *str, char *fmt); + * + * simple sprintf for strftime + * + * each format descriptor is of the form %n + * where n goes from zero to four + * + * 0 -- string %s + * 1..4 -- int %?.?d + * +**/ + +static void strfmt(char *str, const char *fmt, ...) +{ + int ival, ilen; + char *sval; + va_list vp; + + va_start(vp, fmt); + while (*fmt) + { + if (*fmt++ == '%') + { + ilen = *fmt++ - '0'; + if (ilen == 0) /* zero means string arg */ + { + sval = va_arg(vp, char*); + while (*sval) + *str++ = *sval++; + } + else /* always leading zeros */ + { + ival = va_arg(vp, int); + while (ilen) + { + ival %= pow[ilen--]; + *str++ = (char)('0' + ival / pow[ilen]); + } + } + } + else *str++ = fmt[-1]; + } + *str = '\0'; + va_end(vp); +} + +#ifdef TEST + +#include /* for printf */ +#include /* for strftime */ + +char test[80]; + +int main(int argc, char *argv[]) +{ + int len; + char *fmt; + time_t now; + + time(&now); + + fmt = (argc == 1) ? "%I:%M %p\n%c\n" : argv[1]; + len = strftime_(test,sizeof test, fmt, localtime(&now)); + printf("%d: %s\n", len, test); + return !len; +} + +#endif /* TEST */ diff --git a/src/strftime.h b/src/strftime.h new file mode 100644 index 0000000..44da0ea --- /dev/null +++ b/src/strftime.h @@ -0,0 +1,18 @@ +/* +** STRFTIME.H - For older compilers which lack strftime() +** +** Note: To avoid name collision with newer compilers, the function name +** strftime_() is used. +*/ + +#ifndef STRFTIME__H +#define STRFTIME__H + +#include /* for size_t */ +#include /* for struct tm */ + +size_t strftime_(char *s, size_t maxs, const char *f, const struct tm *t); + +extern char * tzname_[2]; + +#endif /* STRFTIME__H */ -- 2.30.2