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