summaryrefslogtreecommitdiffstats
path: root/apps/plugins/lua/strftime.c
blob: cc110469bf50a852206d362fe0cb5e5c5dcf7e04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <sys/types.h>
#include <time.h>
#include "plugin.h"

static const char   sweekdays [7] [4] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char   weekdays [7] [10] = {
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};
static const char   smonths [12] [4] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static const char*  months [12] = {
    "January", "February", "March", "April", smonths[5-1], "June",
    "July", "August", "September", "October", "November", "December"
};
static const char   ampm [4] [3] = {
    "am", "pm",
    "AM", "PM"
};

static void i2a ( char* dest,unsigned long x )
{
    int  div = 10;
    *dest++ = x/div + '0';
    *dest++ = x%div + '0';
    *dest++ = '\0';
}

size_t  strftime ( char* dst, size_t max, const char* format, const struct tm* tm )
{
    char*         p = dst;
    const char*   src;
    unsigned long no;
    char          buf [5];
#if CONFIG_RTC
    char sbuf[101];
#endif

    if (!max) return 0;
    for ( ; *format != '\0'; format++ ) {
    if (*format == '%') {
        if (*++format == '%') {
            *p++ = '%';
        }
        else
again:
        switch (*format) {
//          case '%': *p++ = '%';                  break;            // reduce size of jump table
        case 'n': *p++ = '\n';                 break;
        case 't': *p++ = '\t';                 break;
        case 'O': case 'E': ++format; goto again;
        case 'c': src = "%b %a %d %k:%M:%S %Z %Y";            goto _strf;
        case 'r': src = "%I:%M:%S %p";                        goto _strf;
        case 'R': src = "%H:%M";                  goto _strf;
        case 'x': src = "%b %a %d";               goto _strf;
        case 'X': src = "%k:%M:%S";               goto _strf;
        case 'D': src = "%m/%d/%y";               goto _strf;
        case 'F': src = "%Y-%m-%d";               goto _strf;
        case 'T': src = "%H:%M:%S";
           _strf: p  += strftime (p, (size_t)(dst+max-p), src, tm);      break;
        case 'a': src = sweekdays [tm->tm_wday];         goto _str;
        case 'A': src = weekdays  [tm->tm_wday];         goto _str;
        case 'h':
        case 'b': src = smonths   [tm->tm_mon];          goto _str;
        case 'B': src = months    [tm->tm_mon];          goto _str;
        case 'p': src = ampm [tm->tm_hour > 12 ? 3 : 2]; goto _str;
        case 'P': src = ampm [tm->tm_hour > 12 ? 1 : 0]; goto _str;
        case 'C': no  = tm->tm_year/100 + 19;         goto _no;
        case 'd': no  = tm->tm_mday;                  goto _no;
        case 'e': no  = tm->tm_mday;                  goto _nos;
        case 'H': no  = tm->tm_hour;                  goto _no;
        case 'I': no  = tm->tm_hour % 12;             goto _no;
        case 'j': no  = tm->tm_yday;                  goto _no;
        case 'k': no  = tm->tm_hour;                  goto _nos;
        case 'l': no  = tm->tm_hour % 12;             goto _nos;
        case 'm': no  = tm->tm_mon + 1;               goto _no;
        case 'M': no  = tm->tm_min;                   goto _no;
        case 'S': no  = tm->tm_sec;                   goto _no;
        case 'u': no  = tm->tm_wday ? tm->tm_wday : 7;       goto _no;
        case 'w': no  = tm->tm_wday;                         goto _no;
        case 'U': no  = (tm->tm_yday - tm->tm_wday + 7) / 7; goto _no;
        case 'W': no  = (tm->tm_yday - (tm->tm_wday - 1 + 7) % 7 + 7) / 7; goto _no;
        case 's': {
#if CONFIG_RTC
            time_t t = rb->mktime((struct tm*)tm);
            char* c;
            sbuf[100]=0;
            for (c=sbuf+99; c>sbuf; --c) {
              *c=(t%10)+'0';
              t/=10;
              if (!t) break;
            }
#else
            char* c = "0";
#endif
            src=c;
            goto _str;
              }
        case 'Z':
#ifdef WANT_TZFILE_PARSER
              tzset(); src = tzname[0];
#else
              src = "[unknown timezone]";
#endif
              goto _str;
        case 'Y': i2a ( buf+0, (unsigned int)(tm->tm_year / 100 + 19) );
              i2a ( buf+2, (unsigned int)(tm->tm_year % 100) );
              src = buf;
              goto _str;
        case 'y': no  = tm->tm_year % 100;              goto _no;
         _no: i2a ( buf, no );                 /* append number 'no' */
              src = buf;
              goto _str;
        _nos: i2a ( buf, no );                 /* the same, but '0'->' ' */
              if (buf[0] == '0')
              buf[0] = ' ';
              src = buf;
        _str: while (*src  &&  p < dst+max)         /* append string */
              *p++ = *src++;
              break;
        };
    } else {
        *p++ = *format;
    }

    if (p >= dst+max)
        break;
    }

    if ((size_t)(p-dst)>=max) {
      if (max) p[-1]=0;
    } else
      *p = '\0';
    return p - dst;
}