]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - time/strftime.c
switch to avr-libc 1.8.1 time library
[z180-stamp.git] / time / strftime.c
diff --git a/time/strftime.c b/time/strftime.c
new file mode 100644 (file)
index 0000000..4dcfd30
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: strftime.c 2391 2013-05-03 20:53:06Z swfltek $ */
+
+/*
+    Standard strftime(). This is a memory hungry monster.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+extern long     __utc_offset;
+
+#ifdef __MEMX
+
+const __memx char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
+const __memx char strfmonths[] = "January February March April May June July August September October November December ";
+
+#else
+
+const char      strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
+const char      strfmonths[] = "January February March April May June July August September October November December ";
+
+#endif
+
+#ifdef __MEMX
+
+unsigned char
+pgm_copystring(const char __memx * p, unsigned char i, char *b, unsigned char l)
+{
+
+#else
+
+unsigned char
+pgm_copystring(const char *p, unsigned char i, char *b, unsigned char l)
+{
+
+#endif
+
+    unsigned char   ret, c;
+
+    ret = 0;
+    while (i) {
+        c = *p++;
+        if (c == ' ')
+            i--;
+    }
+
+    c = *p++;
+    while (c != ' ' && l--) {
+        *b++ = c;
+        ret++;
+        c = *p++;
+    }
+    *b = 0;
+    return ret;
+}
+
+size_t
+strftime(char *buffer, size_t limit, const char *pattern, const struct tm * timeptr)
+{
+    unsigned int    count, length;
+    int             d, w;
+    char            c;
+    char            _store[26];
+    struct week_date wd;
+
+    count = length = 0;
+    while (count < limit) {
+        c = *pattern++;
+        if (c == '%') {
+            c = *pattern++;
+            if (c == 'E' || c == 'O')
+                c = *pattern++;
+            switch (c) {
+            case ('%'):
+                _store[0] = c;
+                length = 1;
+                break;
+
+            case ('a'):
+                length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 3);
+                break;
+
+            case ('A'):
+                length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 255);
+                break;
+
+            case ('b'):
+            case ('h'):
+                length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 3);
+                break;
+
+            case ('B'):
+                length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 255);
+                break;
+
+            case ('c'):
+                asctime_r(timeptr, _store);
+                length = 0;
+                while (_store[length])
+                    length++;
+                break;
+
+            case ('C'):
+                d = timeptr->tm_year + 1900;
+                d /= 100;
+                length = sprintf(_store, "%.2d", d);
+                break;
+
+            case ('d'):
+                length = sprintf(_store, "%.2u", timeptr->tm_mday);
+                break;
+
+            case ('D'):
+                length = sprintf(_store, "%.2u/%.2u/%.2u", \
+                         timeptr->tm_mon + 1, \
+                         timeptr->tm_mday, \
+                         timeptr->tm_year % 100 \
+                    );
+                break;
+
+            case ('e'):
+                length = sprintf(_store, "%2d", timeptr->tm_mday);
+                break;
+
+            case ('F'):
+                length = sprintf(_store, "%d-%.2d-%.2d", \
+                         timeptr->tm_year + 1900, \
+                         timeptr->tm_mon + 1, \
+                         timeptr->tm_mday \
+                    );
+                break;
+
+            case ('g'):
+                       case ('G'):
+                               iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
+                if (c == 'g') {
+                    length = sprintf(_store, "%.2d", wd.year % 100);
+                } else {
+                    length = sprintf(_store, "%.4d", wd.year);
+                }
+
+                               break;
+
+            case ('H'):
+                length = sprintf(_store, "%.2u", timeptr->tm_hour);
+                break;
+
+            case ('I'):
+                d = timeptr->tm_hour % 12;
+                if (d == 0)
+                    d = 12;
+                length = sprintf(_store, "%.2u", d);
+                break;
+
+            case ('j'):
+                length = sprintf(_store, "%.3u", timeptr->tm_yday + 1);
+                break;
+
+            case ('m'):
+                length = sprintf(_store, "%.2u", timeptr->tm_mon + 1);
+                break;
+
+            case ('M'):
+                length = sprintf(_store, "%.2u", timeptr->tm_min);
+                break;
+
+            case ('n'):
+                _store[0] = 10;
+                length = 1;
+                break;
+
+            case ('p'):
+                length = 2;
+                _store[0] = 'A';
+                if (timeptr->tm_hour > 11)
+                    _store[0] = 'P';
+                _store[1] = 'M';
+                _store[2] = 0;
+                break;
+
+            case ('r'):
+                d = timeptr->tm_hour % 12;
+                if (d == 0)
+                    d = 12;
+                length = sprintf(_store, "%2d:%.2d:%.2d AM", \
+                         d, \
+                         timeptr->tm_min, \
+                         timeptr->tm_sec \
+                    );
+                if (timeptr->tm_hour > 11)
+                    _store[10] = 'P';
+                break;
+
+            case ('R'):
+                length = sprintf(_store, "%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min);
+                break;
+
+            case ('S'):
+                length = sprintf(_store, "%.2u", timeptr->tm_sec);
+                break;
+
+            case ('t'):
+                length = sprintf(_store, "\t");
+                break;
+
+            case ('T'):
+                length = sprintf(_store, "%.2d:%.2d:%.2d", \
+                         timeptr->tm_hour, \
+                         timeptr->tm_min, \
+                         timeptr->tm_sec \
+                    );
+                break;
+
+            case ('u'):
+                w = timeptr->tm_wday;
+                if (w == 0)
+                    w = 7;
+                length = sprintf(_store, "%d", w);
+                break;
+
+            case ('U'):
+                length = sprintf(_store, "%.2u", week_of_year(timeptr, 0));
+                break;
+
+                       case ('V'):
+                               iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
+                length = sprintf(_store, "%.2u", wd.week);
+                               break;
+
+            case ('w'):
+                length = sprintf(_store, "%u", timeptr->tm_wday);
+                break;
+
+            case ('W'):
+                w = week_of_year(timeptr, 1);
+                length = sprintf(_store, "%.2u", w);
+                break;
+
+            case ('x'):
+                length = sprintf(_store, "%.2u/%.2u/%.2u", timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_year % 100);
+                break;
+
+            case ('X'):
+                length = sprintf(_store, "%.2u:%.2u:%.2u", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
+                break;
+
+            case ('y'):
+                length = sprintf(_store, "%.2u", timeptr->tm_year % 100);
+                break;
+
+            case ('Y'):
+                length = sprintf(_store, "%u", timeptr->tm_year + 1900);
+                break;
+
+            case ('z'):
+                d = __utc_offset / 60;
+                w = timeptr->tm_isdst / 60;
+                if (w > 0)
+                    d += w;
+                w = abs(d % 60);
+                d = d / 60;
+                length = sprintf(_store, "%+.2d%.2d", d, w);
+                break;
+
+            default:
+                length = 1;
+                _store[0] = '?';
+                _store[1] = 0;
+                break;
+            }
+
+            if ((length + count) < limit) {
+                count += length;
+                for (d = 0; d < (int) length; d++) {
+                    *buffer++ = _store[d];
+                }
+            } else {
+                *buffer = 0;
+                return count;
+            }
+
+        } else {    /* copy a literal */
+            *buffer = c;
+            buffer++;
+            count++;
+            if (c == 0)
+                return count;
+        }
+    }
+
+    *buffer = 0;
+    return count;
+}