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