github.com/afumu/libc@v0.0.6/musl/src/time/strftime.c (about) 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <langinfo.h> 5 #include <locale.h> 6 #include <time.h> 7 #include <limits.h> 8 #include "locale_impl.h" 9 #include "time_impl.h" 10 11 static int is_leap(int y) 12 { 13 /* Avoid overflow */ 14 if (y>INT_MAX-1900) y -= 2000; 15 y += 1900; 16 return !(y%4) && ((y%100) || !(y%400)); 17 } 18 19 static int week_num(const struct tm *tm) 20 { 21 int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; 22 /* If 1 Jan is just 1-3 days past Monday, 23 * the previous week is also in this year. */ 24 if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2) 25 val++; 26 if (!val) { 27 val = 52; 28 /* If 31 December of prev year a Thursday, 29 * or Friday of a leap year, then the 30 * prev year has 53 weeks. */ 31 int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7; 32 if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1))) 33 val++; 34 } else if (val == 53) { 35 /* If 1 January is not a Thursday, and not 36 * a Wednesday of a leap year, then this 37 * year has only 52 weeks. */ 38 int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7; 39 if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year))) 40 val = 1; 41 } 42 return val; 43 } 44 45 const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad) 46 { 47 nl_item item; 48 long long val; 49 const char *fmt = "-"; 50 int width = 2, def_pad = '0'; 51 52 switch (f) { 53 case 'a': 54 if (tm->tm_wday > 6U) goto string; 55 item = ABDAY_1 + tm->tm_wday; 56 goto nl_strcat; 57 case 'A': 58 if (tm->tm_wday > 6U) goto string; 59 item = DAY_1 + tm->tm_wday; 60 goto nl_strcat; 61 case 'h': 62 case 'b': 63 if (tm->tm_mon > 11U) goto string; 64 item = ABMON_1 + tm->tm_mon; 65 goto nl_strcat; 66 case 'B': 67 if (tm->tm_mon > 11U) goto string; 68 item = MON_1 + tm->tm_mon; 69 goto nl_strcat; 70 case 'c': 71 item = D_T_FMT; 72 goto nl_strftime; 73 case 'C': 74 val = (1900LL+tm->tm_year) / 100; 75 goto number; 76 case 'e': 77 def_pad = '_'; 78 case 'd': 79 val = tm->tm_mday; 80 goto number; 81 case 'D': 82 fmt = "%m/%d/%y"; 83 goto recu_strftime; 84 case 'F': 85 fmt = "%Y-%m-%d"; 86 goto recu_strftime; 87 case 'g': 88 case 'G': 89 val = tm->tm_year + 1900LL; 90 if (tm->tm_yday < 3 && week_num(tm) != 1) val--; 91 else if (tm->tm_yday > 360 && week_num(tm) == 1) val++; 92 if (f=='g') val %= 100; 93 else width = 4; 94 goto number; 95 case 'H': 96 val = tm->tm_hour; 97 goto number; 98 case 'I': 99 val = tm->tm_hour; 100 if (!val) val = 12; 101 else if (val > 12) val -= 12; 102 goto number; 103 case 'j': 104 val = tm->tm_yday+1; 105 width = 3; 106 goto number; 107 case 'm': 108 val = tm->tm_mon+1; 109 goto number; 110 case 'M': 111 val = tm->tm_min; 112 goto number; 113 case 'n': 114 *l = 1; 115 return "\n"; 116 case 'p': 117 item = tm->tm_hour >= 12 ? PM_STR : AM_STR; 118 goto nl_strcat; 119 case 'r': 120 item = T_FMT_AMPM; 121 goto nl_strftime; 122 case 'R': 123 fmt = "%H:%M"; 124 goto recu_strftime; 125 case 's': 126 val = __tm_to_secs(tm) - tm->__tm_gmtoff; 127 width = 1; 128 goto number; 129 case 'S': 130 val = tm->tm_sec; 131 goto number; 132 case 't': 133 *l = 1; 134 return "\t"; 135 case 'T': 136 fmt = "%H:%M:%S"; 137 goto recu_strftime; 138 case 'u': 139 val = tm->tm_wday ? tm->tm_wday : 7; 140 width = 1; 141 goto number; 142 case 'U': 143 val = (tm->tm_yday + 7U - tm->tm_wday) / 7; 144 goto number; 145 case 'W': 146 val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; 147 goto number; 148 case 'V': 149 val = week_num(tm); 150 goto number; 151 case 'w': 152 val = tm->tm_wday; 153 width = 1; 154 goto number; 155 case 'x': 156 item = D_FMT; 157 goto nl_strftime; 158 case 'X': 159 item = T_FMT; 160 goto nl_strftime; 161 case 'y': 162 val = (tm->tm_year + 1900LL) % 100; 163 if (val < 0) val = -val; 164 goto number; 165 case 'Y': 166 val = tm->tm_year + 1900LL; 167 if (val >= 10000) { 168 *l = snprintf(*s, sizeof *s, "+%lld", val); 169 return *s; 170 } 171 width = 4; 172 goto number; 173 case 'z': 174 if (tm->tm_isdst < 0) { 175 *l = 0; 176 return ""; 177 } 178 *l = snprintf(*s, sizeof *s, "%+.4ld", 179 tm->__tm_gmtoff/3600*100 + tm->__tm_gmtoff%3600/60); 180 return *s; 181 case 'Z': 182 if (tm->tm_isdst < 0) { 183 *l = 0; 184 return ""; 185 } 186 fmt = __tm_to_tzname(tm); 187 goto string; 188 case '%': 189 *l = 1; 190 return "%"; 191 default: 192 return 0; 193 } 194 number: 195 switch (pad ? pad : def_pad) { 196 case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break; 197 case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break; 198 case '0': 199 default: *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break; 200 } 201 return *s; 202 nl_strcat: 203 fmt = __nl_langinfo_l(item, loc); 204 string: 205 *l = strlen(fmt); 206 return fmt; 207 nl_strftime: 208 fmt = __nl_langinfo_l(item, loc); 209 recu_strftime: 210 *l = __strftime_l(*s, sizeof *s, fmt, tm, loc); 211 if (!*l) return 0; 212 return *s; 213 } 214 215 size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc) 216 { 217 size_t l, k; 218 char buf[100]; 219 char *p; 220 const char *t; 221 int pad, plus; 222 unsigned long width; 223 for (l=0; l<n; f++) { 224 if (!*f) { 225 s[l] = 0; 226 return l; 227 } 228 if (*f != '%') { 229 s[l++] = *f; 230 continue; 231 } 232 f++; 233 pad = 0; 234 if (*f == '-' || *f == '_' || *f == '0') pad = *f++; 235 if ((plus = (*f == '+'))) f++; 236 width = strtoul(f, &p, 10); 237 if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { 238 if (!width && p!=f) width = 1; 239 } else { 240 width = 0; 241 } 242 f = p; 243 if (*f == 'E' || *f == 'O') f++; 244 t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad); 245 if (!t) break; 246 if (width) { 247 /* Trim off any sign and leading zeros, then 248 * count remaining digits to determine behavior 249 * for the + flag. */ 250 if (*t=='+' || *t=='-') t++, k--; 251 for (; *t=='0' && t[1]-'0'<10U; t++, k--); 252 if (width < k) width = k; 253 size_t d; 254 for (d=0; t[d]-'0'<10U; d++); 255 if (tm->tm_year < -1900) { 256 s[l++] = '-'; 257 width--; 258 } else if (plus && d+(width-k) >= (*p=='C'?3:5)) { 259 s[l++] = '+'; 260 width--; 261 } 262 for (; width > k && l < n; width--) 263 s[l++] = '0'; 264 } 265 if (k > n-l) k = n-l; 266 memcpy(s+l, t, k); 267 l += k; 268 } 269 if (n) { 270 if (l==n) l=n-1; 271 s[l] = 0; 272 } 273 return 0; 274 } 275 276 size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm) 277 { 278 return __strftime_l(s, n, f, tm, CURRENT_LOCALE); 279 } 280 281 weak_alias(__strftime_l, strftime_l);