1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)strftime.c 8.1 (Berkeley) 06/04/93"; 10 #endif /* LIBC_SCCS and not lint */ 11 12 #include <sys/types.h> 13 #include <sys/time.h> 14 #include <tzfile.h> 15 #include <string.h> 16 17 static char *afmt[] = { 18 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 19 }; 20 static char *Afmt[] = { 21 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 22 "Saturday", 23 }; 24 static char *bfmt[] = { 25 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 26 "Oct", "Nov", "Dec", 27 }; 28 static char *Bfmt[] = { 29 "January", "February", "March", "April", "May", "June", "July", 30 "August", "September", "October", "November", "December", 31 }; 32 33 static size_t gsize; 34 static char *pt; 35 static int _add __P((char *)); 36 static int _conv __P((int, int, int)); 37 static int _secs __P((const struct tm *)); 38 static size_t _fmt __P((const char *, const struct tm *)); 39 40 size_t 41 strftime(s, maxsize, format, t) 42 char *s; 43 size_t maxsize; 44 const char *format; 45 const struct tm *t; 46 { 47 48 pt = s; 49 if ((gsize = maxsize) < 1) 50 return(0); 51 if (_fmt(format, t)) { 52 *pt = '\0'; 53 return(maxsize - gsize); 54 } 55 return(0); 56 } 57 58 static size_t 59 _fmt(format, t) 60 register const char *format; 61 const struct tm *t; 62 { 63 for (; *format; ++format) { 64 if (*format == '%') 65 switch(*++format) { 66 case '\0': 67 --format; 68 break; 69 case 'A': 70 if (t->tm_wday < 0 || t->tm_wday > 6) 71 return(0); 72 if (!_add(Afmt[t->tm_wday])) 73 return(0); 74 continue; 75 case 'a': 76 if (t->tm_wday < 0 || t->tm_wday > 6) 77 return(0); 78 if (!_add(afmt[t->tm_wday])) 79 return(0); 80 continue; 81 case 'B': 82 if (t->tm_mon < 0 || t->tm_mon > 11) 83 return(0); 84 if (!_add(Bfmt[t->tm_mon])) 85 return(0); 86 continue; 87 case 'b': 88 case 'h': 89 if (t->tm_mon < 0 || t->tm_mon > 11) 90 return(0); 91 if (!_add(bfmt[t->tm_mon])) 92 return(0); 93 continue; 94 case 'C': 95 if (!_fmt("%a %b %e %H:%M:%S %Y", t)) 96 return(0); 97 continue; 98 case 'c': 99 if (!_fmt("%m/%d/%y %H:%M:%S", t)) 100 return(0); 101 continue; 102 case 'D': 103 if (!_fmt("%m/%d/%y", t)) 104 return(0); 105 continue; 106 case 'd': 107 if (!_conv(t->tm_mday, 2, '0')) 108 return(0); 109 continue; 110 case 'e': 111 if (!_conv(t->tm_mday, 2, ' ')) 112 return(0); 113 continue; 114 case 'H': 115 if (!_conv(t->tm_hour, 2, '0')) 116 return(0); 117 continue; 118 case 'I': 119 if (!_conv(t->tm_hour % 12 ? 120 t->tm_hour % 12 : 12, 2, '0')) 121 return(0); 122 continue; 123 case 'j': 124 if (!_conv(t->tm_yday + 1, 3, '0')) 125 return(0); 126 continue; 127 case 'k': 128 if (!_conv(t->tm_hour, 2, ' ')) 129 return(0); 130 continue; 131 case 'l': 132 if (!_conv(t->tm_hour % 12 ? 133 t->tm_hour % 12 : 12, 2, ' ')) 134 return(0); 135 continue; 136 case 'M': 137 if (!_conv(t->tm_min, 2, '0')) 138 return(0); 139 continue; 140 case 'm': 141 if (!_conv(t->tm_mon + 1, 2, '0')) 142 return(0); 143 continue; 144 case 'n': 145 if (!_add("\n")) 146 return(0); 147 continue; 148 case 'p': 149 if (!_add(t->tm_hour >= 12 ? "PM" : "AM")) 150 return(0); 151 continue; 152 case 'R': 153 if (!_fmt("%H:%M", t)) 154 return(0); 155 continue; 156 case 'r': 157 if (!_fmt("%I:%M:%S %p", t)) 158 return(0); 159 continue; 160 case 'S': 161 if (!_conv(t->tm_sec, 2, '0')) 162 return(0); 163 continue; 164 case 's': 165 if (!_secs(t)) 166 return(0); 167 continue; 168 case 'T': 169 case 'X': 170 if (!_fmt("%H:%M:%S", t)) 171 return(0); 172 continue; 173 case 't': 174 if (!_add("\t")) 175 return(0); 176 continue; 177 case 'U': 178 if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7, 179 2, '0')) 180 return(0); 181 continue; 182 case 'W': 183 if (!_conv((t->tm_yday + 7 - 184 (t->tm_wday ? (t->tm_wday - 1) : 6)) 185 / 7, 2, '0')) 186 return(0); 187 continue; 188 case 'w': 189 if (!_conv(t->tm_wday, 1, '0')) 190 return(0); 191 continue; 192 case 'x': 193 if (!_fmt("%m/%d/%y", t)) 194 return(0); 195 continue; 196 case 'y': 197 if (!_conv((t->tm_year + TM_YEAR_BASE) 198 % 100, 2, '0')) 199 return(0); 200 continue; 201 case 'Y': 202 if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0')) 203 return(0); 204 continue; 205 case 'Z': 206 if (!t->tm_zone || !_add(t->tm_zone)) 207 return(0); 208 continue; 209 case '%': 210 /* 211 * X311J/88-090 (4.12.3.5): if conversion char is 212 * undefined, behavior is undefined. Print out the 213 * character itself as printf(3) does. 214 */ 215 default: 216 break; 217 } 218 if (!gsize--) 219 return(0); 220 *pt++ = *format; 221 } 222 return(gsize); 223 } 224 225 static int 226 _secs(t) 227 const struct tm *t; 228 { 229 static char buf[15]; 230 register time_t s; 231 register char *p; 232 struct tm tmp; 233 234 /* Make a copy, mktime(3) modifies the tm struct. */ 235 tmp = *t; 236 s = mktime(&tmp); 237 for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) 238 *p-- = s % 10 + '0'; 239 return(_add(++p)); 240 } 241 242 static int 243 _conv(n, digits, pad) 244 int n, digits, pad; 245 { 246 static char buf[10]; 247 register char *p; 248 249 for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) 250 *p-- = n % 10 + '0'; 251 while (p > buf && digits-- > 0) 252 *p-- = pad; 253 return(_add(++p)); 254 } 255 256 static int 257 _add(str) 258 register char *str; 259 { 260 for (;; ++pt, --gsize) { 261 if (!gsize) 262 return(0); 263 if (!(*pt = *str++)) 264 return(1); 265 } 266 } 267