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