scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

strftime.c (4026B)


      1 #include <time.h>
      2 #include <string.h>
      3 
      4 #include "../libc.h"
      5 #undef strftime
      6 
      7 static char *days[] = {
      8 	"Sunday",   "Monday", "Tuesday",  "Wednesday",
      9 	"Thursday", "Friday", "Saturday", 
     10 };
     11 
     12 static char *months[] = {
     13 	"January",   "February", "March",    "April",
     14 	"May",       "June",     "July",     "August",
     15 	"September", "October",  "November", "December"
     16 };
     17 
     18 static char *am_pm[] = {"AM", "PM"};
     19 
     20 static size_t
     21 sval(char *s, size_t siz, char **strs, int abrev, int idx, int max)
     22 {
     23 	char *str;
     24 	size_t len;
     25 
     26 	if (idx < 0 && idx >= max)
     27 		goto wrong;
     28 
     29 	str = strs[idx];
     30 	len = (!abrev) ? strlen(str) : 3;
     31 	if (len > siz)
     32 		goto wrong;
     33 
     34 	memcpy(s, str, len);
     35 	return len;
     36 
     37 wrong:
     38 	*s = '?';
     39 	return 1;
     40 }
     41 
     42 static size_t
     43 dval(char *s, size_t siz, int prec, int fill, int val)
     44 {
     45 	char *t;
     46 	int n;
     47 	static char digits[] = "0123456789";
     48 
     49 	if (prec > siz || val < 0) {
     50 		*s = '?';
     51 		return 1;
     52 	}
     53 
     54 	n = prec;
     55 	do {
     56 		s[--n] = digits[val % 10];
     57 		val /= 10;
     58 	} while (n > 0 && val > 0);
     59 
     60 	while (n > 0)
     61 		s[--n] = fill;
     62 
     63 	return prec;
     64 }
     65 
     66 static size_t
     67 timezone(char *s, size_t prec, const struct tm * restrict tm)
     68 {
     69 	long off = tm->tm_gmtoff;
     70 
     71 	if (prec < 5) {
     72 		*s = '?';
     73 		return 1;
     74 	}
     75 
     76 	if (off >= 0) {
     77 		*s++ = '+';
     78 	} else {
     79 		*s++ = '-';
     80 		off = -off;
     81 	}
     82 
     83 	dval(s, 2, 2, '0', off / 3600);
     84 	dval(s, 2, 2, '0', (off % 3600) / 60);
     85 
     86 	return 5;
     87 }
     88 
     89 size_t
     90 strftime(char * restrict s, size_t siz,
     91          const char * restrict fmt,
     92          const struct tm * restrict tm)
     93 {
     94 	int ch, abrev, val, fill, width;
     95 	size_t n, inc;
     96 	char *tfmt;
     97 
     98 	for (n = siz-1; (ch = *fmt++) && n > 0; s += inc, n -= inc) {
     99 		if (ch != '%') {
    100 			*s = ch;
    101 			inc = 1;
    102 			continue;
    103 		}
    104 
    105 		abrev = 0;
    106 		fill = '0';
    107 		width = 2;
    108 
    109 		switch (*fmt++) {
    110 		case 'Z':
    111 			if (!tm->tm_zone)
    112 				break;
    113 			inc = sval(s, n, &tm->tm_zone, 0, 0, 1);
    114 			break;
    115 		case 'a':
    116 			abrev = 1;
    117 		case 'A':
    118 			inc = sval(s, n, days, abrev, tm->tm_wday, 7);
    119 			break;
    120 		case 'h':
    121 		case 'b':
    122 			abrev = 1;
    123 		case 'B':
    124 			inc = sval(s, n, months, abrev, tm->tm_mon, 12);
    125 			break;
    126 		case 'p':
    127 			inc = sval(s, n, am_pm, 0, tm->tm_hour > 12, 2);
    128 			break;
    129 		case 'c':
    130 			tfmt = "%a %b %e %T %Y";
    131 			goto recursive;
    132 		case 'D':
    133 			tfmt = "%m/%d/%y";
    134 			goto recursive;
    135 		case 'F':
    136 			tfmt = "%Y-%m-%d";
    137 			goto recursive;
    138 		case 'R':
    139 			tfmt = "%H:%M";
    140 			goto recursive;
    141 		case 'X':
    142 		case 'T':
    143 			tfmt = "%H:%M:%S";
    144 			goto recursive;
    145 		case 'r':
    146 			tfmt = "%I:%M:%S %p";
    147 			goto recursive;
    148 		case 'x':
    149 			tfmt = "%m/%d/%y";
    150 			goto recursive;
    151 		recursive:
    152 			inc = strftime(s, n+1, tfmt, tm) - 1;
    153 			break;
    154 		case 'n':
    155 			val = '\n';
    156 			goto character;
    157 		case 't': 
    158 			val = '\t';
    159 			goto character;
    160 		case '%': 
    161 			val = '%';
    162 		character:
    163 			*s = val;
    164 			inc = 1;
    165 			break;
    166 		case 'e':
    167 			fill = ' ';
    168 			val = tm->tm_mday;
    169 			goto number;
    170 		case 'd':
    171 			val = tm->tm_mday;
    172 			goto number;
    173 		case 'V':
    174 		case 'g':
    175 		case 'G':
    176 			/* TODO */
    177 			break;
    178 		case 'C':
    179 			val = tm->tm_year / 100;
    180 			goto number;
    181 		case 'H':
    182 			val = tm->tm_hour;
    183 			goto number;
    184 		case 'I':
    185 			val = tm->tm_hour;
    186 			if (val == 0)
    187 				val = 12;
    188 			if (val > 12)
    189 				val -= 12;
    190 			goto number;
    191 		case 'j':
    192 			width = 3;
    193 			val = tm->tm_yday+1;
    194 			goto number;
    195 		case 'm':
    196 			val = tm->tm_mon+1;
    197 			goto number;
    198 		case 'M':
    199 			val = tm->tm_min;
    200 			goto number;
    201 		case 'S':
    202 			val = tm->tm_sec;
    203 			goto number;
    204 		case 'u':
    205 			width = 1;
    206 			val = tm->tm_wday+1;
    207 			goto number;
    208 		case 'U':
    209 			val = tm->tm_yday / 7;
    210 			if (_newyear(tm->tm_year) == SAT)
    211 				val++;
    212 			goto number;
    213 		case 'W':
    214 			val = tm->tm_yday / 7;
    215 			if (_newyear(tm->tm_year) == MON)
    216 				val++;
    217 			goto number;
    218 		case 'w':
    219 			width = 1;
    220 			val = tm->tm_wday;
    221 			goto number;
    222 		case 'y':
    223 			val = tm->tm_year%100;
    224 			goto number;
    225 		case 'Y':
    226 			width = 4;
    227 			val = 1900 + tm->tm_year;
    228 		number:
    229 			inc = dval(s, n, width, fill, val);
    230 			break;
    231 		case 'z':
    232 			inc = timezone(s, n, tm);
    233 			break;
    234 		case 'E':
    235 		case 'O':
    236 			if (*fmt != '\0')
    237 				fmt += 2;;
    238 		case '\0':
    239 			inc = 0;
    240 			--fmt;
    241 			break;
    242 		}
    243 	}
    244 	*s = '\0';
    245 
    246 	return siz - n;
    247 }