1 |
dashley |
64 |
/* $Header$ */
|
2 |
dashley |
25 |
|
3 |
|
|
/*
|
4 |
|
|
* strftime.c --
|
5 |
|
|
*
|
6 |
|
|
* This file contains a modified version of the BSD 4.4 strftime
|
7 |
|
|
* function.
|
8 |
|
|
*
|
9 |
|
|
* This file is a modified version of the strftime.c file from the BSD 4.4
|
10 |
|
|
* source. See the copyright notice below for details on redistribution
|
11 |
|
|
* restrictions. The "license.terms" file does not apply to this file.
|
12 |
|
|
*
|
13 |
|
|
* RCS: @(#) $Id: strftime.c,v 1.1.1.1 2001/06/13 04:32:38 dtashley Exp $
|
14 |
|
|
*/
|
15 |
|
|
|
16 |
|
|
/*
|
17 |
|
|
* Copyright (c) 1989 The Regents of the University of California.
|
18 |
|
|
* All rights reserved.
|
19 |
|
|
*
|
20 |
|
|
* Redistribution and use in source and binary forms, with or without
|
21 |
|
|
* modification, are permitted provided that the following conditions
|
22 |
|
|
* are met:
|
23 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
24 |
|
|
* notice, this list of conditions and the following disclaimer.
|
25 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
26 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
27 |
|
|
* documentation and/or other materials provided with the distribution.
|
28 |
|
|
* 3. All advertising materials mentioning features or use of this software
|
29 |
|
|
* must display the following acknowledgement:
|
30 |
|
|
* This product includes software developed by the University of
|
31 |
|
|
* California, Berkeley and its contributors.
|
32 |
|
|
* 4. Neither the name of the University nor the names of its contributors
|
33 |
|
|
* may be used to endorse or promote products derived from this software
|
34 |
|
|
* without specific prior written permission.
|
35 |
|
|
*
|
36 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
37 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
38 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
39 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
40 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
41 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
42 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
43 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
44 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
45 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
46 |
|
|
* SUCH DAMAGE.
|
47 |
|
|
*/
|
48 |
|
|
|
49 |
|
|
#if defined(LIBC_SCCS)
|
50 |
|
|
static char *rcsid = "$Id: strftime.c,v 1.1.1.1 2001/06/13 04:32:38 dtashley Exp $";
|
51 |
|
|
#endif /* LIBC_SCCS */
|
52 |
|
|
|
53 |
|
|
#include <time.h>
|
54 |
|
|
#include <string.h>
|
55 |
|
|
#include <locale.h>
|
56 |
|
|
#include "tclInt.h"
|
57 |
|
|
#include "tclPort.h"
|
58 |
|
|
|
59 |
|
|
#define TM_YEAR_BASE 1900
|
60 |
|
|
#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
|
61 |
|
|
|
62 |
|
|
typedef struct {
|
63 |
|
|
const char *abday[7];
|
64 |
|
|
const char *day[7];
|
65 |
|
|
const char *abmon[12];
|
66 |
|
|
const char *mon[12];
|
67 |
|
|
const char *am_pm[2];
|
68 |
|
|
const char *d_t_fmt;
|
69 |
|
|
const char *d_fmt;
|
70 |
|
|
const char *t_fmt;
|
71 |
|
|
const char *t_fmt_ampm;
|
72 |
|
|
} _TimeLocale;
|
73 |
|
|
|
74 |
|
|
static const _TimeLocale _DefaultTimeLocale =
|
75 |
|
|
{
|
76 |
|
|
{
|
77 |
|
|
"Sun","Mon","Tue","Wed","Thu","Fri","Sat",
|
78 |
|
|
},
|
79 |
|
|
{
|
80 |
|
|
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
|
81 |
|
|
"Friday", "Saturday"
|
82 |
|
|
},
|
83 |
|
|
{
|
84 |
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
85 |
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
86 |
|
|
},
|
87 |
|
|
{
|
88 |
|
|
"January", "February", "March", "April", "May", "June", "July",
|
89 |
|
|
"August", "September", "October", "November", "December"
|
90 |
|
|
},
|
91 |
|
|
{
|
92 |
|
|
"AM", "PM"
|
93 |
|
|
},
|
94 |
|
|
"%a %b %d %H:%M:%S %Y",
|
95 |
|
|
"%m/%d/%y",
|
96 |
|
|
"%H:%M:%S",
|
97 |
|
|
"%I:%M:%S %p"
|
98 |
|
|
};
|
99 |
|
|
|
100 |
|
|
static const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale;
|
101 |
|
|
|
102 |
|
|
static size_t gsize;
|
103 |
|
|
static char *pt;
|
104 |
|
|
static int _add _ANSI_ARGS_((const char* str));
|
105 |
|
|
static int _conv _ANSI_ARGS_((int n, int digits, int pad));
|
106 |
|
|
static int _secs _ANSI_ARGS_((const struct tm *t));
|
107 |
|
|
static size_t _fmt _ANSI_ARGS_((const char *format,
|
108 |
|
|
const struct tm *t));
|
109 |
|
|
|
110 |
|
|
size_t
|
111 |
|
|
TclpStrftime(s, maxsize, format, t)
|
112 |
|
|
char *s;
|
113 |
|
|
size_t maxsize;
|
114 |
|
|
const char *format;
|
115 |
|
|
const struct tm *t;
|
116 |
|
|
{
|
117 |
|
|
if (format[0] == '%' && format[1] == 'Q') {
|
118 |
|
|
/* Format as a stardate */
|
119 |
|
|
sprintf(s, "Stardate %2d%03d.%01d",
|
120 |
|
|
(((t->tm_year + TM_YEAR_BASE) + 377) - 2323),
|
121 |
|
|
(((t->tm_yday + 1) * 1000) /
|
122 |
|
|
(365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))),
|
123 |
|
|
(((t->tm_hour * 60) + t->tm_min)/144));
|
124 |
|
|
return(strlen(s));
|
125 |
|
|
}
|
126 |
|
|
|
127 |
|
|
tzset();
|
128 |
|
|
|
129 |
|
|
pt = s;
|
130 |
|
|
if ((gsize = maxsize) < 1)
|
131 |
|
|
return(0);
|
132 |
|
|
if (_fmt(format, t)) {
|
133 |
|
|
*pt = '\0';
|
134 |
|
|
return(maxsize - gsize);
|
135 |
|
|
}
|
136 |
|
|
return(0);
|
137 |
|
|
}
|
138 |
|
|
|
139 |
|
|
#define SUN_WEEK(t) (((t)->tm_yday + 7 - \
|
140 |
|
|
((t)->tm_wday)) / 7)
|
141 |
|
|
#define MON_WEEK(t) (((t)->tm_yday + 7 - \
|
142 |
|
|
((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7)
|
143 |
|
|
|
144 |
|
|
static size_t
|
145 |
|
|
_fmt(format, t)
|
146 |
|
|
const char *format;
|
147 |
|
|
const struct tm *t;
|
148 |
|
|
{
|
149 |
|
|
for (; *format; ++format) {
|
150 |
|
|
if (*format == '%') {
|
151 |
|
|
++format;
|
152 |
|
|
if (*format == 'E') {
|
153 |
|
|
/* Alternate Era */
|
154 |
|
|
++format;
|
155 |
|
|
} else if (*format == 'O') {
|
156 |
|
|
/* Alternate numeric symbols */
|
157 |
|
|
++format;
|
158 |
|
|
}
|
159 |
|
|
switch(*format) {
|
160 |
|
|
case '\0':
|
161 |
|
|
--format;
|
162 |
|
|
break;
|
163 |
|
|
case 'A':
|
164 |
|
|
if (t->tm_wday < 0 || t->tm_wday > 6)
|
165 |
|
|
return(0);
|
166 |
|
|
if (!_add(_CurrentTimeLocale->day[t->tm_wday]))
|
167 |
|
|
return(0);
|
168 |
|
|
continue;
|
169 |
|
|
case 'a':
|
170 |
|
|
if (t->tm_wday < 0 || t->tm_wday > 6)
|
171 |
|
|
return(0);
|
172 |
|
|
if (!_add(_CurrentTimeLocale->abday[t->tm_wday]))
|
173 |
|
|
return(0);
|
174 |
|
|
continue;
|
175 |
|
|
case 'B':
|
176 |
|
|
if (t->tm_mon < 0 || t->tm_mon > 11)
|
177 |
|
|
return(0);
|
178 |
|
|
if (!_add(_CurrentTimeLocale->mon[t->tm_mon]))
|
179 |
|
|
return(0);
|
180 |
|
|
continue;
|
181 |
|
|
case 'b':
|
182 |
|
|
case 'h':
|
183 |
|
|
if (t->tm_mon < 0 || t->tm_mon > 11)
|
184 |
|
|
return(0);
|
185 |
|
|
if (!_add(_CurrentTimeLocale->abmon[t->tm_mon]))
|
186 |
|
|
return(0);
|
187 |
|
|
continue;
|
188 |
|
|
case 'C':
|
189 |
|
|
if (!_conv((t->tm_year + TM_YEAR_BASE) / 100,
|
190 |
|
|
2, '0'))
|
191 |
|
|
return(0);
|
192 |
|
|
continue;
|
193 |
|
|
case 'c':
|
194 |
|
|
if (!_fmt(_CurrentTimeLocale->d_t_fmt, t))
|
195 |
|
|
return(0);
|
196 |
|
|
continue;
|
197 |
|
|
case 'D':
|
198 |
|
|
if (!_fmt("%m/%d/%y", t))
|
199 |
|
|
return(0);
|
200 |
|
|
continue;
|
201 |
|
|
case 'd':
|
202 |
|
|
if (!_conv(t->tm_mday, 2, '0'))
|
203 |
|
|
return(0);
|
204 |
|
|
continue;
|
205 |
|
|
case 'e':
|
206 |
|
|
if (!_conv(t->tm_mday, 2, ' '))
|
207 |
|
|
return(0);
|
208 |
|
|
continue;
|
209 |
|
|
case 'H':
|
210 |
|
|
if (!_conv(t->tm_hour, 2, '0'))
|
211 |
|
|
return(0);
|
212 |
|
|
continue;
|
213 |
|
|
case 'I':
|
214 |
|
|
if (!_conv(t->tm_hour % 12 ?
|
215 |
|
|
t->tm_hour % 12 : 12, 2, '0'))
|
216 |
|
|
return(0);
|
217 |
|
|
continue;
|
218 |
|
|
case 'j':
|
219 |
|
|
if (!_conv(t->tm_yday + 1, 3, '0'))
|
220 |
|
|
return(0);
|
221 |
|
|
continue;
|
222 |
|
|
case 'k':
|
223 |
|
|
if (!_conv(t->tm_hour, 2, ' '))
|
224 |
|
|
return(0);
|
225 |
|
|
continue;
|
226 |
|
|
case 'l':
|
227 |
|
|
if (!_conv(t->tm_hour % 12 ?
|
228 |
|
|
t->tm_hour % 12: 12, 2, ' '))
|
229 |
|
|
return(0);
|
230 |
|
|
continue;
|
231 |
|
|
case 'M':
|
232 |
|
|
if (!_conv(t->tm_min, 2, '0'))
|
233 |
|
|
return(0);
|
234 |
|
|
continue;
|
235 |
|
|
case 'm':
|
236 |
|
|
if (!_conv(t->tm_mon + 1, 2, '0'))
|
237 |
|
|
return(0);
|
238 |
|
|
continue;
|
239 |
|
|
case 'n':
|
240 |
|
|
if (!_add("\n"))
|
241 |
|
|
return(0);
|
242 |
|
|
continue;
|
243 |
|
|
case 'p':
|
244 |
|
|
if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12]))
|
245 |
|
|
return(0);
|
246 |
|
|
continue;
|
247 |
|
|
case 'R':
|
248 |
|
|
if (!_fmt("%H:%M", t))
|
249 |
|
|
return(0);
|
250 |
|
|
continue;
|
251 |
|
|
case 'r':
|
252 |
|
|
if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t))
|
253 |
|
|
return(0);
|
254 |
|
|
continue;
|
255 |
|
|
case 'S':
|
256 |
|
|
if (!_conv(t->tm_sec, 2, '0'))
|
257 |
|
|
return(0);
|
258 |
|
|
continue;
|
259 |
|
|
case 's':
|
260 |
|
|
if (!_secs(t))
|
261 |
|
|
return(0);
|
262 |
|
|
continue;
|
263 |
|
|
case 'T':
|
264 |
|
|
if (!_fmt("%H:%M:%S", t))
|
265 |
|
|
return(0);
|
266 |
|
|
continue;
|
267 |
|
|
case 't':
|
268 |
|
|
if (!_add("\t"))
|
269 |
|
|
return(0);
|
270 |
|
|
continue;
|
271 |
|
|
case 'U':
|
272 |
|
|
if (!_conv(SUN_WEEK(t), 2, '0'))
|
273 |
|
|
return(0);
|
274 |
|
|
continue;
|
275 |
|
|
case 'u':
|
276 |
|
|
if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0'))
|
277 |
|
|
return(0);
|
278 |
|
|
continue;
|
279 |
|
|
case 'V':
|
280 |
|
|
{
|
281 |
|
|
/* ISO 8601 Week Of Year:
|
282 |
|
|
If the week (Monday - Sunday) containing
|
283 |
|
|
January 1 has four or more days in the new
|
284 |
|
|
year, then it is week 1; otherwise it is
|
285 |
|
|
week 53 of the previous year and the next
|
286 |
|
|
week is week one. */
|
287 |
|
|
|
288 |
|
|
int week = MON_WEEK(t);
|
289 |
|
|
|
290 |
|
|
int days = (((t)->tm_yday + 7 - \
|
291 |
|
|
((t)->tm_wday ? (t)->tm_wday - 1 : 6)) % 7);
|
292 |
|
|
|
293 |
|
|
|
294 |
|
|
if (days >= 4) {
|
295 |
|
|
week++;
|
296 |
|
|
} else if (week == 0) {
|
297 |
|
|
week = 53;
|
298 |
|
|
}
|
299 |
|
|
|
300 |
|
|
if (!_conv(week, 2, '0'))
|
301 |
|
|
return(0);
|
302 |
|
|
continue;
|
303 |
|
|
}
|
304 |
|
|
case 'W':
|
305 |
|
|
if (!_conv(MON_WEEK(t), 2, '0'))
|
306 |
|
|
return(0);
|
307 |
|
|
continue;
|
308 |
|
|
case 'w':
|
309 |
|
|
if (!_conv(t->tm_wday, 1, '0'))
|
310 |
|
|
return(0);
|
311 |
|
|
continue;
|
312 |
|
|
case 'x':
|
313 |
|
|
if (!_fmt(_CurrentTimeLocale->d_fmt, t))
|
314 |
|
|
return(0);
|
315 |
|
|
continue;
|
316 |
|
|
case 'X':
|
317 |
|
|
if (!_fmt(_CurrentTimeLocale->t_fmt, t))
|
318 |
|
|
return(0);
|
319 |
|
|
continue;
|
320 |
|
|
case 'y':
|
321 |
|
|
if (!_conv((t->tm_year + TM_YEAR_BASE) % 100,
|
322 |
|
|
2, '0'))
|
323 |
|
|
return(0);
|
324 |
|
|
continue;
|
325 |
|
|
case 'Y':
|
326 |
|
|
if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0'))
|
327 |
|
|
return(0);
|
328 |
|
|
continue;
|
329 |
|
|
#ifndef MAC_TCL
|
330 |
|
|
case 'Z': {
|
331 |
|
|
char *name = TclpGetTZName(t->tm_isdst);
|
332 |
|
|
if (name && !_add(name)) {
|
333 |
|
|
return 0;
|
334 |
|
|
}
|
335 |
|
|
continue;
|
336 |
|
|
}
|
337 |
|
|
#endif
|
338 |
|
|
case '%':
|
339 |
|
|
/*
|
340 |
|
|
* X311J/88-090 (4.12.3.5): if conversion char is
|
341 |
|
|
* undefined, behavior is undefined. Print out the
|
342 |
|
|
* character itself as printf(3) does.
|
343 |
|
|
*/
|
344 |
|
|
default:
|
345 |
|
|
break;
|
346 |
|
|
}
|
347 |
|
|
}
|
348 |
|
|
if (!gsize--)
|
349 |
|
|
return(0);
|
350 |
|
|
*pt++ = *format;
|
351 |
|
|
}
|
352 |
|
|
return(gsize);
|
353 |
|
|
}
|
354 |
|
|
|
355 |
|
|
static int
|
356 |
|
|
_secs(t)
|
357 |
|
|
const struct tm *t;
|
358 |
|
|
{
|
359 |
|
|
static char buf[15];
|
360 |
|
|
register time_t s;
|
361 |
|
|
register char *p;
|
362 |
|
|
struct tm tmp;
|
363 |
|
|
|
364 |
|
|
/* Make a copy, mktime(3) modifies the tm struct. */
|
365 |
|
|
tmp = *t;
|
366 |
|
|
s = mktime(&tmp);
|
367 |
|
|
for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
|
368 |
|
|
*p-- = (char)(s % 10 + '0');
|
369 |
|
|
return(_add(++p));
|
370 |
|
|
}
|
371 |
|
|
|
372 |
|
|
static int
|
373 |
|
|
_conv(n, digits, pad)
|
374 |
|
|
int n, digits;
|
375 |
|
|
int pad;
|
376 |
|
|
{
|
377 |
|
|
static char buf[10];
|
378 |
|
|
register char *p;
|
379 |
|
|
|
380 |
|
|
for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
|
381 |
|
|
*p-- = (char)(n % 10 + '0');
|
382 |
|
|
while (p > buf && digits-- > 0)
|
383 |
|
|
*p-- = (char) pad;
|
384 |
|
|
return(_add(++p));
|
385 |
|
|
}
|
386 |
|
|
|
387 |
|
|
static int
|
388 |
|
|
_add(str)
|
389 |
|
|
const char *str;
|
390 |
|
|
{
|
391 |
|
|
for (;; ++pt, --gsize) {
|
392 |
|
|
if (!gsize)
|
393 |
|
|
return(0);
|
394 |
|
|
if (!(*pt = *str++))
|
395 |
|
|
return(1);
|
396 |
|
|
}
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
/* $History: strftime.c $
|
400 |
|
|
*
|
401 |
|
|
* ***************** Version 1 *****************
|
402 |
|
|
* User: Dtashley Date: 1/02/01 Time: 12:17a
|
403 |
|
|
* Created in $/IjuScripter, IjuConsole/Source/Tcl Base
|
404 |
|
|
* Initial check-in.
|
405 |
|
|
*/
|
406 |
|
|
|
407 |
|
|
/* End of STRFTIME.C */ |