summaryrefslogtreecommitdiff
path: root/time/strftime.c
diff options
context:
space:
mode:
Diffstat (limited to 'time/strftime.c')
-rw-r--r--time/strftime.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/time/strftime.c b/time/strftime.c
new file mode 100644
index 0000000..4dcfd30
--- /dev/null
+++ b/time/strftime.c
@@ -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;
+}