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