/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tcldate.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tcldate.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (8 years, 1 month ago) by dashley
File MIME type: text/plain
File size: 55773 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
2 /*
3 * tclDate.c --
4 *
5 * This file is generated from a yacc grammar defined in
6 * the file tclGetDate.y. It should not be edited directly.
7 *
8 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
9 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
10 *
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tcldate.c,v 1.1.1.1 2001/06/13 04:36:47 dtashley Exp $
15 */
16
17 #include "tclInt.h"
18 #include "tclPort.h"
19
20 #ifdef MAC_TCL
21 # define EPOCH 1904
22 # define START_OF_TIME 1904
23 # define END_OF_TIME 2039
24 #else
25 # define EPOCH 1970
26 # define START_OF_TIME 1902
27 # define END_OF_TIME 2037
28 #endif
29
30 /*
31 * The offset of tm_year of struct tm returned by localtime, gmtime, etc.
32 * I don't know how universal this is; K&R II, the NetBSD manpages, and
33 * ../compat/strftime.c all agree that tm_year is the year-1900. However,
34 * some systems may have a different value. This #define should be the
35 * same as in ../compat/strftime.c.
36 */
37 #define TM_YEAR_BASE 1900
38
39 #define HOUR(x) ((int) (60 * x))
40 #define SECSPERDAY (24L * 60L * 60L)
41 #define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
42
43 /*
44 * An entry in the lexical lookup table.
45 */
46 typedef struct _TABLE {
47 char *name;
48 int type;
49 time_t value;
50 } TABLE;
51
52
53 /*
54 * Daylight-savings mode: on, off, or not yet known.
55 */
56 typedef enum _DSTMODE {
57 DSTon, DSToff, DSTmaybe
58 } DSTMODE;
59
60 /*
61 * Meridian: am, pm, or 24-hour style.
62 */
63 typedef enum _MERIDIAN {
64 MERam, MERpm, MER24
65 } MERIDIAN;
66
67
68 /*
69 * Global variables. We could get rid of most of these by using a good
70 * union as the yacc stack. (This routine was originally written before
71 * yacc had the %union construct.) Maybe someday; right now we only use
72 * the %union very rarely.
73 */
74 static char *TclDateInput;
75 static DSTMODE TclDateDSTmode;
76 static time_t TclDateDayOrdinal;
77 static time_t TclDateDayNumber;
78 static time_t TclDateMonthOrdinal;
79 static int TclDateHaveDate;
80 static int TclDateHaveDay;
81 static int TclDateHaveOrdinalMonth;
82 static int TclDateHaveRel;
83 static int TclDateHaveTime;
84 static int TclDateHaveZone;
85 static time_t TclDateTimezone;
86 static time_t TclDateDay;
87 static time_t TclDateHour;
88 static time_t TclDateMinutes;
89 static time_t TclDateMonth;
90 static time_t TclDateSeconds;
91 static time_t TclDateYear;
92 static MERIDIAN TclDateMeridian;
93 static time_t TclDateRelMonth;
94 static time_t TclDateRelDay;
95 static time_t TclDateRelSeconds;
96 static time_t *TclDateRelPointer;
97
98 /*
99 * Prototypes of internal functions.
100 */
101 static void TclDateerror _ANSI_ARGS_((char *s));
102 static time_t ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes,
103 time_t Seconds, MERIDIAN Meridian));
104 static int Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year,
105 time_t Hours, time_t Minutes, time_t Seconds,
106 MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr));
107 static time_t DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future));
108 static time_t NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal,
109 time_t DayNumber));
110 static time_t NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal,
111 time_t MonthNumber));
112 static int RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth,
113 time_t *TimePtr));
114 static int RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay,
115 time_t *TimePtr));
116 static int LookupWord _ANSI_ARGS_((char *buff));
117 static int TclDatelex _ANSI_ARGS_((void));
118
119 int
120 TclDateparse _ANSI_ARGS_((void));
121 typedef union
122 #ifdef __cplusplus
123 YYSTYPE
124 #endif
125 {
126 time_t Number;
127 enum _MERIDIAN Meridian;
128 } YYSTYPE;
129 # define tAGO 257
130 # define tDAY 258
131 # define tDAYZONE 259
132 # define tID 260
133 # define tMERIDIAN 261
134 # define tMINUTE_UNIT 262
135 # define tMONTH 263
136 # define tMONTH_UNIT 264
137 # define tSTARDATE 265
138 # define tSEC_UNIT 266
139 # define tSNUMBER 267
140 # define tUNUMBER 268
141 # define tZONE 269
142 # define tEPOCH 270
143 # define tDST 271
144 # define tISOBASE 272
145 # define tDAY_UNIT 273
146 # define tNEXT 274
147
148
149
150
151 #if defined(__cplusplus) || defined(__STDC__)
152
153 #if defined(__cplusplus) && defined(__EXTERN_C__)
154 extern "C" {
155 #endif
156 #ifndef TclDateerror
157 #if defined(__cplusplus)
158 void TclDateerror(CONST char *);
159 #endif
160 #endif
161 #ifndef TclDatelex
162 int TclDatelex(void);
163 #endif
164 int TclDateparse(void);
165 #if defined(__cplusplus) && defined(__EXTERN_C__)
166 }
167 #endif
168
169 #endif
170
171 #define TclDateclearin TclDatechar = -1
172 #define TclDateerrok TclDateerrflag = 0
173 extern int TclDatechar;
174 extern int TclDateerrflag;
175 YYSTYPE TclDatelval;
176 YYSTYPE TclDateval;
177 typedef int TclDatetabelem;
178 #ifndef YYMAXDEPTH
179 #define YYMAXDEPTH 150
180 #endif
181 #if YYMAXDEPTH > 0
182 int TclDate_TclDates[YYMAXDEPTH], *TclDates = TclDate_TclDates;
183 YYSTYPE TclDate_TclDatev[YYMAXDEPTH], *TclDatev = TclDate_TclDatev;
184 #else /* user does initial allocation */
185 int *TclDates;
186 YYSTYPE *TclDatev;
187 #endif
188 static int TclDatemaxdepth = YYMAXDEPTH;
189 # define YYERRCODE 256
190
191
192 /*
193 * Month and day table.
194 */
195 static TABLE MonthDayTable[] = {
196 { "january", tMONTH, 1 },
197 { "february", tMONTH, 2 },
198 { "march", tMONTH, 3 },
199 { "april", tMONTH, 4 },
200 { "may", tMONTH, 5 },
201 { "june", tMONTH, 6 },
202 { "july", tMONTH, 7 },
203 { "august", tMONTH, 8 },
204 { "september", tMONTH, 9 },
205 { "sept", tMONTH, 9 },
206 { "october", tMONTH, 10 },
207 { "november", tMONTH, 11 },
208 { "december", tMONTH, 12 },
209 { "sunday", tDAY, 0 },
210 { "monday", tDAY, 1 },
211 { "tuesday", tDAY, 2 },
212 { "tues", tDAY, 2 },
213 { "wednesday", tDAY, 3 },
214 { "wednes", tDAY, 3 },
215 { "thursday", tDAY, 4 },
216 { "thur", tDAY, 4 },
217 { "thurs", tDAY, 4 },
218 { "friday", tDAY, 5 },
219 { "saturday", tDAY, 6 },
220 { NULL }
221 };
222
223 /*
224 * Time units table.
225 */
226 static TABLE UnitsTable[] = {
227 { "year", tMONTH_UNIT, 12 },
228 { "month", tMONTH_UNIT, 1 },
229 { "fortnight", tDAY_UNIT, 14 },
230 { "week", tDAY_UNIT, 7 },
231 { "day", tDAY_UNIT, 1 },
232 { "hour", tSEC_UNIT, 60 * 60 },
233 { "minute", tSEC_UNIT, 60 },
234 { "min", tSEC_UNIT, 60 },
235 { "second", tSEC_UNIT, 1 },
236 { "sec", tSEC_UNIT, 1 },
237 { NULL }
238 };
239
240 /*
241 * Assorted relative-time words.
242 */
243 static TABLE OtherTable[] = {
244 { "tomorrow", tDAY_UNIT, 1 },
245 { "yesterday", tDAY_UNIT, -1 },
246 { "today", tDAY_UNIT, 0 },
247 { "now", tSEC_UNIT, 0 },
248 { "last", tUNUMBER, -1 },
249 { "this", tSEC_UNIT, 0 },
250 { "next", tNEXT, 1 },
251 #if 0
252 { "first", tUNUMBER, 1 },
253 { "second", tUNUMBER, 2 },
254 { "third", tUNUMBER, 3 },
255 { "fourth", tUNUMBER, 4 },
256 { "fifth", tUNUMBER, 5 },
257 { "sixth", tUNUMBER, 6 },
258 { "seventh", tUNUMBER, 7 },
259 { "eighth", tUNUMBER, 8 },
260 { "ninth", tUNUMBER, 9 },
261 { "tenth", tUNUMBER, 10 },
262 { "eleventh", tUNUMBER, 11 },
263 { "twelfth", tUNUMBER, 12 },
264 #endif
265 { "ago", tAGO, 1 },
266 { "epoch", tEPOCH, 0 },
267 { "stardate", tSTARDATE, 0},
268 { NULL }
269 };
270
271 /*
272 * The timezone table. (Note: This table was modified to not use any floating
273 * point constants to work around an SGI compiler bug).
274 */
275 static TABLE TimezoneTable[] = {
276 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
277 { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
278 { "utc", tZONE, HOUR( 0) },
279 { "uct", tZONE, HOUR( 0) }, /* Universal Coordinated Time */
280 { "wet", tZONE, HOUR( 0) }, /* Western European */
281 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
282 { "wat", tZONE, HOUR( 1) }, /* West Africa */
283 { "at", tZONE, HOUR( 2) }, /* Azores */
284 #if 0
285 /* For completeness. BST is also British Summer, and GST is
286 * also Guam Standard. */
287 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
288 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
289 #endif
290 { "nft", tZONE, HOUR( 7/2) }, /* Newfoundland */
291 { "nst", tZONE, HOUR( 7/2) }, /* Newfoundland Standard */
292 { "ndt", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */
293 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
294 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
295 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
296 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
297 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
298 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
299 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
300 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
301 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
302 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
303 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
304 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
305 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
306 { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
307 { "cat", tZONE, HOUR(10) }, /* Central Alaska */
308 { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
309 { "nt", tZONE, HOUR(11) }, /* Nome */
310 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
311 { "cet", tZONE, -HOUR( 1) }, /* Central European */
312 { "cest", tDAYZONE, -HOUR( 1) }, /* Central European Summer */
313 { "met", tZONE, -HOUR( 1) }, /* Middle European */
314 { "mewt", tZONE, -HOUR( 1) }, /* Middle European Winter */
315 { "mest", tDAYZONE, -HOUR( 1) }, /* Middle European Summer */
316 { "swt", tZONE, -HOUR( 1) }, /* Swedish Winter */
317 { "sst", tDAYZONE, -HOUR( 1) }, /* Swedish Summer */
318 { "fwt", tZONE, -HOUR( 1) }, /* French Winter */
319 { "fst", tDAYZONE, -HOUR( 1) }, /* French Summer */
320 { "eet", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */
321 { "bt", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */
322 { "it", tZONE, -HOUR( 7/2) }, /* Iran */
323 { "zp4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */
324 { "zp5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */
325 { "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */
326 { "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */
327 #if 0
328 /* For completeness. NST is also Newfoundland Stanard, nad SST is
329 * also Swedish Summer. */
330 { "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */
331 { "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */
332 #endif /* 0 */
333 { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */
334 { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */
335 { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
336 { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
337 { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
338 { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */
339 { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */
340 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
341 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
342 { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
343 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
344 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
345 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
346 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
347 /* ADDED BY Marco Nijdam */
348 { "dst", tDST, HOUR( 0) }, /* DST on (hour is ignored) */
349 /* End ADDED */
350 { NULL }
351 };
352
353 /*
354 * Military timezone table.
355 */
356 static TABLE MilitaryTable[] = {
357 { "a", tZONE, HOUR( 1) },
358 { "b", tZONE, HOUR( 2) },
359 { "c", tZONE, HOUR( 3) },
360 { "d", tZONE, HOUR( 4) },
361 { "e", tZONE, HOUR( 5) },
362 { "f", tZONE, HOUR( 6) },
363 { "g", tZONE, HOUR( 7) },
364 { "h", tZONE, HOUR( 8) },
365 { "i", tZONE, HOUR( 9) },
366 { "k", tZONE, HOUR( 10) },
367 { "l", tZONE, HOUR( 11) },
368 { "m", tZONE, HOUR( 12) },
369 { "n", tZONE, HOUR(- 1) },
370 { "o", tZONE, HOUR(- 2) },
371 { "p", tZONE, HOUR(- 3) },
372 { "q", tZONE, HOUR(- 4) },
373 { "r", tZONE, HOUR(- 5) },
374 { "s", tZONE, HOUR(- 6) },
375 { "t", tZONE, HOUR(- 7) },
376 { "u", tZONE, HOUR(- 8) },
377 { "v", tZONE, HOUR(- 9) },
378 { "w", tZONE, HOUR(-10) },
379 { "x", tZONE, HOUR(-11) },
380 { "y", tZONE, HOUR(-12) },
381 { "z", tZONE, HOUR( 0) },
382 { NULL }
383 };
384
385
386 /*
387 * Dump error messages in the bit bucket.
388 */
389 static void
390 TclDateerror(s)
391 char *s;
392 {
393 }
394
395
396 static time_t
397 ToSeconds(Hours, Minutes, Seconds, Meridian)
398 time_t Hours;
399 time_t Minutes;
400 time_t Seconds;
401 MERIDIAN Meridian;
402 {
403 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
404 return -1;
405 switch (Meridian) {
406 case MER24:
407 if (Hours < 0 || Hours > 23)
408 return -1;
409 return (Hours * 60L + Minutes) * 60L + Seconds;
410 case MERam:
411 if (Hours < 1 || Hours > 12)
412 return -1;
413 return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
414 case MERpm:
415 if (Hours < 1 || Hours > 12)
416 return -1;
417 return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
418 }
419 return -1; /* Should never be reached */
420 }
421
422 /*
423 *-----------------------------------------------------------------------------
424 *
425 * Convert --
426 *
427 * Convert a {month, day, year, hours, minutes, seconds, meridian, dst}
428 * tuple into a clock seconds value.
429 *
430 * Results:
431 * 0 or -1 indicating success or failure.
432 *
433 * Side effects:
434 * Fills TimePtr with the computed value.
435 *
436 *-----------------------------------------------------------------------------
437 */
438 static int
439 Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr)
440 time_t Month;
441 time_t Day;
442 time_t Year;
443 time_t Hours;
444 time_t Minutes;
445 time_t Seconds;
446 MERIDIAN Meridian;
447 DSTMODE DSTmode;
448 time_t *TimePtr;
449 {
450 static int DaysInMonth[12] = {
451 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
452 };
453 time_t tod;
454 time_t Julian;
455 int i;
456
457 /* Figure out how many days are in February for the given year.
458 * Every year divisible by 4 is a leap year.
459 * But, every year divisible by 100 is not a leap year.
460 * But, every year divisible by 400 is a leap year after all.
461 */
462 DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28;
463
464 /* Check the inputs for validity */
465 if (Month < 1 || Month > 12
466 || Year < START_OF_TIME || Year > END_OF_TIME
467 || Day < 1 || Day > DaysInMonth[(int)--Month])
468 return -1;
469
470 /* Start computing the value. First determine the number of days
471 * represented by the date, then multiply by the number of seconds/day.
472 */
473 for (Julian = Day - 1, i = 0; i < Month; i++)
474 Julian += DaysInMonth[i];
475 if (Year >= EPOCH) {
476 for (i = EPOCH; i < Year; i++)
477 Julian += 365 + IsLeapYear(i);
478 } else {
479 for (i = Year; i < EPOCH; i++)
480 Julian -= 365 + IsLeapYear(i);
481 }
482 Julian *= SECSPERDAY;
483
484 /* Add the timezone offset ?? */
485 Julian += TclDateTimezone * 60L;
486
487 /* Add the number of seconds represented by the time component */
488 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
489 return -1;
490 Julian += tod;
491
492 /* Perform a preliminary DST compensation ?? */
493 if (DSTmode == DSTon
494 || (DSTmode == DSTmaybe && TclpGetDate((TclpTime_t)&Julian, 0)->tm_isdst))
495 Julian -= 60 * 60;
496 *TimePtr = Julian;
497 return 0;
498 }
499
500
501 static time_t
502 DSTcorrect(Start, Future)
503 time_t Start;
504 time_t Future;
505 {
506 time_t StartDay;
507 time_t FutureDay;
508 StartDay = (TclpGetDate((TclpTime_t)&Start, 0)->tm_hour + 1) % 24;
509 FutureDay = (TclpGetDate((TclpTime_t)&Future, 0)->tm_hour + 1) % 24;
510 return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
511 }
512
513
514 static time_t
515 NamedDay(Start, DayOrdinal, DayNumber)
516 time_t Start;
517 time_t DayOrdinal;
518 time_t DayNumber;
519 {
520 struct tm *tm;
521 time_t now;
522
523 now = Start;
524 tm = TclpGetDate((TclpTime_t)&now, 0);
525 now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
526 now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
527 return DSTcorrect(Start, now);
528 }
529
530 static time_t
531 NamedMonth(Start, MonthOrdinal, MonthNumber)
532 time_t Start;
533 time_t MonthOrdinal;
534 time_t MonthNumber;
535 {
536 struct tm *tm;
537 time_t now;
538 int result;
539
540 now = Start;
541 tm = TclpGetDate((TclpTime_t)&now, 0);
542 /* To compute the next n'th month, we use this alg:
543 * add n to year value
544 * if currentMonth < requestedMonth decrement year value by 1 (so that
545 * doing next february from january gives us february of the current year)
546 * set day to 1, time to 0
547 */
548 tm->tm_year += MonthOrdinal;
549 if (tm->tm_mon < MonthNumber - 1) {
550 tm->tm_year--;
551 }
552 result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE,
553 (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now);
554 if (result < 0) {
555 return 0;
556 }
557 return DSTcorrect(Start, now);
558 }
559
560 static int
561 RelativeMonth(Start, RelMonth, TimePtr)
562 time_t Start;
563 time_t RelMonth;
564 time_t *TimePtr;
565 {
566 struct tm *tm;
567 time_t Month;
568 time_t Year;
569 time_t Julian;
570 int result;
571
572 if (RelMonth == 0) {
573 *TimePtr = 0;
574 return 0;
575 }
576 tm = TclpGetDate((TclpTime_t)&Start, 0);
577 Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth;
578 Year = Month / 12;
579 Month = Month % 12 + 1;
580 result = Convert(Month, (time_t) tm->tm_mday, Year,
581 (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
582 MER24, DSTmaybe, &Julian);
583 /*
584 * The following iteration takes into account the case were we jump
585 * into a "short month". Far example, "one month from Jan 31" will
586 * fail because there is no Feb 31. The code below will reduce the
587 * day and try converting the date until we succed or the date equals
588 * 28 (which always works unless the date is bad in another way).
589 */
590
591 while ((result != 0) && (tm->tm_mday > 28)) {
592 tm->tm_mday--;
593 result = Convert(Month, (time_t) tm->tm_mday, Year,
594 (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
595 MER24, DSTmaybe, &Julian);
596 }
597 if (result != 0) {
598 return -1;
599 }
600 *TimePtr = DSTcorrect(Start, Julian);
601 return 0;
602 }
603
604
605 /*
606 *-----------------------------------------------------------------------------
607 *
608 * RelativeDay --
609 *
610 * Given a starting time and a number of days before or after, compute the
611 * DST corrected difference between those dates.
612 *
613 * Results:
614 * 1 or -1 indicating success or failure.
615 *
616 * Side effects:
617 * Fills TimePtr with the computed value.
618 *
619 *-----------------------------------------------------------------------------
620 */
621
622 static int
623 RelativeDay(Start, RelDay, TimePtr)
624 time_t Start;
625 time_t RelDay;
626 time_t *TimePtr;
627 {
628 time_t new;
629
630 new = Start + (RelDay * 60 * 60 * 24);
631 *TimePtr = DSTcorrect(Start, new);
632 return 1;
633 }
634
635 static int
636 LookupWord(buff)
637 char *buff;
638 {
639 register char *p;
640 register char *q;
641 register TABLE *tp;
642 int i;
643 int abbrev;
644
645 /*
646 * Make it lowercase.
647 */
648
649 Tcl_UtfToLower(buff);
650
651 if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
652 TclDatelval.Meridian = MERam;
653 return tMERIDIAN;
654 }
655 if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
656 TclDatelval.Meridian = MERpm;
657 return tMERIDIAN;
658 }
659
660 /*
661 * See if we have an abbreviation for a month.
662 */
663 if (strlen(buff) == 3) {
664 abbrev = 1;
665 } else if (strlen(buff) == 4 && buff[3] == '.') {
666 abbrev = 1;
667 buff[3] = '\0';
668 } else {
669 abbrev = 0;
670 }
671
672 for (tp = MonthDayTable; tp->name; tp++) {
673 if (abbrev) {
674 if (strncmp(buff, tp->name, 3) == 0) {
675 TclDatelval.Number = tp->value;
676 return tp->type;
677 }
678 } else if (strcmp(buff, tp->name) == 0) {
679 TclDatelval.Number = tp->value;
680 return tp->type;
681 }
682 }
683
684 for (tp = TimezoneTable; tp->name; tp++) {
685 if (strcmp(buff, tp->name) == 0) {
686 TclDatelval.Number = tp->value;
687 return tp->type;
688 }
689 }
690
691 for (tp = UnitsTable; tp->name; tp++) {
692 if (strcmp(buff, tp->name) == 0) {
693 TclDatelval.Number = tp->value;
694 return tp->type;
695 }
696 }
697
698 /*
699 * Strip off any plural and try the units table again.
700 */
701 i = strlen(buff) - 1;
702 if (buff[i] == 's') {
703 buff[i] = '\0';
704 for (tp = UnitsTable; tp->name; tp++) {
705 if (strcmp(buff, tp->name) == 0) {
706 TclDatelval.Number = tp->value;
707 return tp->type;
708 }
709 }
710 }
711
712 for (tp = OtherTable; tp->name; tp++) {
713 if (strcmp(buff, tp->name) == 0) {
714 TclDatelval.Number = tp->value;
715 return tp->type;
716 }
717 }
718
719 /*
720 * Military timezones.
721 */
722 if (buff[1] == '\0' && !(*buff & 0x80)
723 && isalpha(UCHAR(*buff))) { /* INTL: ISO only */
724 for (tp = MilitaryTable; tp->name; tp++) {
725 if (strcmp(buff, tp->name) == 0) {
726 TclDatelval.Number = tp->value;
727 return tp->type;
728 }
729 }
730 }
731
732 /*
733 * Drop out any periods and try the timezone table again.
734 */
735 for (i = 0, p = q = buff; *q; q++)
736 if (*q != '.') {
737 *p++ = *q;
738 } else {
739 i++;
740 }
741 *p = '\0';
742 if (i) {
743 for (tp = TimezoneTable; tp->name; tp++) {
744 if (strcmp(buff, tp->name) == 0) {
745 TclDatelval.Number = tp->value;
746 return tp->type;
747 }
748 }
749 }
750
751 return tID;
752 }
753
754
755 static int
756 TclDatelex()
757 {
758 register char c;
759 register char *p;
760 char buff[20];
761 int Count;
762
763 for ( ; ; ) {
764 while (isspace(UCHAR(*TclDateInput))) {
765 TclDateInput++;
766 }
767
768 if (isdigit(UCHAR(c = *TclDateInput))) { /* INTL: digit */
769 /* convert the string into a number; count the number of digits */
770 Count = 0;
771 for (TclDatelval.Number = 0;
772 isdigit(UCHAR(c = *TclDateInput++)); ) { /* INTL: digit */
773 TclDatelval.Number = 10 * TclDatelval.Number + c - '0';
774 Count++;
775 }
776 TclDateInput--;
777 /* A number with 6 or more digits is considered an ISO 8601 base */
778 if (Count >= 6) {
779 return tISOBASE;
780 } else {
781 return tUNUMBER;
782 }
783 }
784 if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */
785 for (p = buff; isalpha(UCHAR(c = *TclDateInput++)) /* INTL: ISO only. */
786 || c == '.'; ) {
787 if (p < &buff[sizeof buff - 1]) {
788 *p++ = c;
789 }
790 }
791 *p = '\0';
792 TclDateInput--;
793 return LookupWord(buff);
794 }
795 if (c != '(') {
796 return *TclDateInput++;
797 }
798 Count = 0;
799 do {
800 c = *TclDateInput++;
801 if (c == '\0') {
802 return c;
803 } else if (c == '(') {
804 Count++;
805 } else if (c == ')') {
806 Count--;
807 }
808 } while (Count > 0);
809 }
810 }
811
812 /*
813 * Specify zone is of -50000 to force GMT. (This allows BST to work).
814 */
815
816 int
817 TclGetDate(p, now, zone, timePtr)
818 char *p;
819 unsigned long now;
820 long zone;
821 unsigned long *timePtr;
822 {
823 struct tm *tm;
824 time_t Start;
825 time_t Time;
826 time_t tod;
827 int thisyear;
828
829 TclDateInput = p;
830 /* now has to be cast to a time_t for 64bit compliance */
831 Start = now;
832 tm = TclpGetDate((TclpTime_t) &Start, 0);
833 thisyear = tm->tm_year + TM_YEAR_BASE;
834 TclDateYear = thisyear;
835 TclDateMonth = tm->tm_mon + 1;
836 TclDateDay = tm->tm_mday;
837 TclDateTimezone = zone;
838 if (zone == -50000) {
839 TclDateDSTmode = DSToff; /* assume GMT */
840 TclDateTimezone = 0;
841 } else {
842 TclDateDSTmode = DSTmaybe;
843 }
844 TclDateHour = 0;
845 TclDateMinutes = 0;
846 TclDateSeconds = 0;
847 TclDateMeridian = MER24;
848 TclDateRelSeconds = 0;
849 TclDateRelMonth = 0;
850 TclDateRelDay = 0;
851 TclDateRelPointer = NULL;
852
853 TclDateHaveDate = 0;
854 TclDateHaveDay = 0;
855 TclDateHaveOrdinalMonth = 0;
856 TclDateHaveRel = 0;
857 TclDateHaveTime = 0;
858 TclDateHaveZone = 0;
859
860 if (TclDateparse() || TclDateHaveTime > 1 || TclDateHaveZone > 1 || TclDateHaveDate > 1 ||
861 TclDateHaveDay > 1 || TclDateHaveOrdinalMonth > 1) {
862 return -1;
863 }
864
865 if (TclDateHaveDate || TclDateHaveTime || TclDateHaveDay) {
866 if (TclDateYear < 0) {
867 TclDateYear = -TclDateYear;
868 }
869 /*
870 * The following line handles years that are specified using
871 * only two digits. The line of code below implements a policy
872 * defined by the X/Open workgroup on the millinium rollover.
873 * Note: some of those dates may not actually be valid on some
874 * platforms. The POSIX standard startes that the dates 70-99
875 * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038.
876 * This later definition should work on all platforms.
877 */
878
879 if (TclDateYear < 100) {
880 if (TclDateYear >= 69) {
881 TclDateYear += 1900;
882 } else {
883 TclDateYear += 2000;
884 }
885 }
886 if (Convert(TclDateMonth, TclDateDay, TclDateYear, TclDateHour, TclDateMinutes, TclDateSeconds,
887 TclDateMeridian, TclDateDSTmode, &Start) < 0) {
888 return -1;
889 }
890 } else {
891 Start = now;
892 if (!TclDateHaveRel) {
893 Start -= ((tm->tm_hour * 60L * 60L) +
894 tm->tm_min * 60L) + tm->tm_sec;
895 }
896 }
897
898 Start += TclDateRelSeconds;
899 if (RelativeMonth(Start, TclDateRelMonth, &Time) < 0) {
900 return -1;
901 }
902 Start += Time;
903
904 if (RelativeDay(Start, TclDateRelDay, &Time) < 0) {
905 return -1;
906 }
907 Start += Time;
908
909 if (TclDateHaveDay && !TclDateHaveDate) {
910 tod = NamedDay(Start, TclDateDayOrdinal, TclDateDayNumber);
911 Start += tod;
912 }
913
914 if (TclDateHaveOrdinalMonth) {
915 tod = NamedMonth(Start, TclDateMonthOrdinal, TclDateMonth);
916 Start += tod;
917 }
918
919 *timePtr = Start;
920 return 0;
921 }
922 static CONST TclDatetabelem TclDateexca[] ={
923 -1, 1,
924 0, -1,
925 -2, 0,
926 };
927 # define YYNPROD 56
928 # define YYLAST 261
929 static CONST TclDatetabelem TclDateact[]={
930
931 24, 39, 23, 35, 55, 83, 40, 27, 54, 25,
932 36, 41, 59, 37, 57, 27, 26, 25, 27, 32,
933 25, 31, 62, 50, 26, 82, 78, 26, 51, 77,
934 76, 75, 29, 74, 73, 72, 70, 52, 49, 48,
935 47, 44, 38, 63, 80, 46, 45, 81, 69, 21,
936 66, 61, 68, 67, 56, 43, 64, 11, 10, 9,
937 8, 7, 34, 6, 5, 4, 3, 2, 42, 1,
938 20, 0, 0, 0, 0, 0, 0, 0, 0, 0,
939 0, 53, 0, 0, 0, 0, 0, 0, 0, 0,
940 0, 58, 0, 0, 60, 0, 0, 79, 0, 0,
941 0, 0, 0, 0, 0, 0, 0, 71, 0, 0,
942 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
943 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
944 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
946 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
947 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
948 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
949 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
950 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
951 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
952 0, 0, 0, 0, 0, 19, 14, 0, 0, 0,
953 16, 27, 22, 25, 0, 12, 13, 17, 0, 15,
954 26, 18, 30, 0, 0, 28, 0, 33, 27, 0,
955 25, 0, 0, 0, 0, 0, 0, 26, 0, 0,
956 0, 0, 0, 0, 0, 0, 0, 0, 0, 65,
957 65 };
958 static CONST TclDatetabelem TclDatepact[]={
959
960 -10000000, -43,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,
961 -10000000,-10000000, -26, -268,-10000000, -259, -226,-10000000, -257, 11,
962 -227, -212, -228,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000, -229,
963 -10000000, -230, -240, -231, -212,-10000000, -264,-10000000, 10,-10000000,
964 -10000000, -249,-10000000,-10000000, -246,-10000000,-10000000, 5, -2, 3,
965 8, 7,-10000000,-10000000,-10000000, -10, -232,-10000000,-10000000,-10000000,
966 -212, -233,-10000000, -234, -235,-10000000, -237, -238, -239, -242,
967 -10000000,-10000000,-10000000,-10000000, -1,-10000000,-10000000,-10000000, -11,-10000000,
968 -243, -263,-10000000,-10000000 };
969 static CONST TclDatetabelem TclDatepgo[]={
970
971 0, 49, 46, 70, 22, 69, 67, 66, 65, 64,
972 63, 61, 60, 59, 58, 57 };
973 static CONST TclDatetabelem TclDater1[]={
974
975 0, 5, 5, 6, 6, 6, 6, 6, 6, 6,
976 6, 6, 7, 7, 7, 7, 7, 8, 8, 8,
977 11, 11, 11, 11, 11, 9, 9, 9, 9, 9,
978 9, 9, 9, 9, 9, 10, 10, 13, 13, 13,
979 14, 12, 12, 12, 12, 12, 3, 3, 1, 1,
980 1, 2, 2, 15, 4, 4 };
981 static CONST TclDatetabelem TclDater2[]={
982
983 0, 0, 4, 3, 3, 3, 3, 3, 3, 3,
984 3, 2, 5, 9, 11, 13, 15, 5, 3, 3,
985 3, 5, 5, 7, 5, 7, 11, 3, 11, 11,
986 5, 9, 5, 3, 7, 5, 7, 7, 15, 5,
987 9, 9, 7, 5, 7, 5, 3, 3, 3, 3,
988 3, 3, 1, 3, 1, 3 };
989 static CONST TclDatetabelem TclDatechk[]={
990
991 -10000000, -5, -6, -7, -8, -9, -10, -11, -12, -13,
992 -14, -15, 268, 269, 259, 272, 263, 270, 274, 258,
993 -3, -1, 265, 45, 43, 266, 273, 264, 261, 58,
994 258, 47, 45, 263, -1, 271, 269, 272, 268, 258,
995 263, 268, -1, 44, 268, -2, 257, 268, 268, 268,
996 263, 268, 268, -2, 272, 268, 44, 263, -1, 258,
997 -1, 46, -4, 45, 58, 261, 47, 45, 45, 58,
998 268, -2, 268, 268, 268, 268, 268, 268, 268, -4,
999 45, 58, 268, 268 };
1000 static CONST TclDatetabelem TclDatedef[]={
1001
1002 1, -2, 2, 3, 4, 5, 6, 7, 8, 9,
1003 10, 11, 53, 18, 19, 27, 0, 33, 0, 20,
1004 0, 52, 0, 46, 47, 48, 49, 50, 12, 0,
1005 22, 0, 0, 32, 52, 17, 0, 39, 30, 24,
1006 35, 0, 43, 21, 0, 45, 51, 0, 54, 25,
1007 0, 0, 34, 42, 37, 0, 0, 36, 44, 23,
1008 52, 0, 13, 0, 0, 55, 0, 0, 0, 0,
1009 31, 41, 40, 14, 54, 26, 28, 29, 0, 15,
1010 0, 0, 16, 38 };
1011 typedef struct
1012 #ifdef __cplusplus
1013 TclDatetoktype
1014 #endif
1015 { char *t_name; int t_val; } TclDatetoktype;
1016 #ifndef YYDEBUG
1017 # define YYDEBUG 0 /* don't allow debugging */
1018 #endif
1019
1020 #if YYDEBUG
1021
1022 TclDatetoktype TclDatetoks[] =
1023 {
1024 "tAGO", 257,
1025 "tDAY", 258,
1026 "tDAYZONE", 259,
1027 "tID", 260,
1028 "tMERIDIAN", 261,
1029 "tMINUTE_UNIT", 262,
1030 "tMONTH", 263,
1031 "tMONTH_UNIT", 264,
1032 "tSTARDATE", 265,
1033 "tSEC_UNIT", 266,
1034 "tSNUMBER", 267,
1035 "tUNUMBER", 268,
1036 "tZONE", 269,
1037 "tEPOCH", 270,
1038 "tDST", 271,
1039 "tISOBASE", 272,
1040 "tDAY_UNIT", 273,
1041 "tNEXT", 274,
1042 "-unknown-", -1 /* ends search */
1043 };
1044
1045 char * TclDatereds[] =
1046 {
1047 "-no such reduction-",
1048 "spec : /* empty */",
1049 "spec : spec item",
1050 "item : time",
1051 "item : zone",
1052 "item : date",
1053 "item : ordMonth",
1054 "item : day",
1055 "item : relspec",
1056 "item : iso",
1057 "item : trek",
1058 "item : number",
1059 "time : tUNUMBER tMERIDIAN",
1060 "time : tUNUMBER ':' tUNUMBER o_merid",
1061 "time : tUNUMBER ':' tUNUMBER '-' tUNUMBER",
1062 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
1063 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER",
1064 "zone : tZONE tDST",
1065 "zone : tZONE",
1066 "zone : tDAYZONE",
1067 "day : tDAY",
1068 "day : tDAY ','",
1069 "day : tUNUMBER tDAY",
1070 "day : sign tUNUMBER tDAY",
1071 "day : tNEXT tDAY",
1072 "date : tUNUMBER '/' tUNUMBER",
1073 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
1074 "date : tISOBASE",
1075 "date : tUNUMBER '-' tMONTH '-' tUNUMBER",
1076 "date : tUNUMBER '-' tUNUMBER '-' tUNUMBER",
1077 "date : tMONTH tUNUMBER",
1078 "date : tMONTH tUNUMBER ',' tUNUMBER",
1079 "date : tUNUMBER tMONTH",
1080 "date : tEPOCH",
1081 "date : tUNUMBER tMONTH tUNUMBER",
1082 "ordMonth : tNEXT tMONTH",
1083 "ordMonth : tNEXT tUNUMBER tMONTH",
1084 "iso : tISOBASE tZONE tISOBASE",
1085 "iso : tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER",
1086 "iso : tISOBASE tISOBASE",
1087 "trek : tSTARDATE tUNUMBER '.' tUNUMBER",
1088 "relspec : sign tUNUMBER unit ago",
1089 "relspec : tUNUMBER unit ago",
1090 "relspec : tNEXT unit",
1091 "relspec : tNEXT tUNUMBER unit",
1092 "relspec : unit ago",
1093 "sign : '-'",
1094 "sign : '+'",
1095 "unit : tSEC_UNIT",
1096 "unit : tDAY_UNIT",
1097 "unit : tMONTH_UNIT",
1098 "ago : tAGO",
1099 "ago : /* empty */",
1100 "number : tUNUMBER",
1101 "o_merid : /* empty */",
1102 "o_merid : tMERIDIAN",
1103 };
1104 #endif /* YYDEBUG */
1105 /*
1106 * Copyright (c) 1993 by Sun Microsystems, Inc.
1107 */
1108
1109
1110 /*
1111 ** Skeleton parser driver for yacc output
1112 */
1113
1114 /*
1115 ** yacc user known macros and defines
1116 */
1117 #define YYERROR goto TclDateerrlab
1118 #define YYACCEPT return(0)
1119 #define YYABORT return(1)
1120 #define YYBACKUP( newtoken, newvalue )\
1121 {\
1122 if ( TclDatechar >= 0 || ( TclDater2[ TclDatetmp ] >> 1 ) != 1 )\
1123 {\
1124 TclDateerror( "syntax error - cannot backup" );\
1125 goto TclDateerrlab;\
1126 }\
1127 TclDatechar = newtoken;\
1128 TclDatestate = *TclDateps;\
1129 TclDatelval = newvalue;\
1130 goto TclDatenewstate;\
1131 }
1132 #define YYRECOVERING() (!!TclDateerrflag)
1133 #define YYNEW(type) malloc(sizeof(type) * TclDatenewmax)
1134 #define YYCOPY(to, from, type) \
1135 (type *) memcpy(to, (char *) from, TclDatemaxdepth * sizeof (type))
1136 #define YYENLARGE( from, type) \
1137 (type *) realloc((char *) from, TclDatenewmax * sizeof(type))
1138 #ifndef YYDEBUG
1139 # define YYDEBUG 1 /* make debugging available */
1140 #endif
1141
1142 /*
1143 ** user known globals
1144 */
1145 int TclDatedebug; /* set to 1 to get debugging */
1146
1147 /*
1148 ** driver internal defines
1149 */
1150 #define YYFLAG (-10000000)
1151
1152 /*
1153 ** global variables used by the parser
1154 */
1155 YYSTYPE *TclDatepv; /* top of value stack */
1156 int *TclDateps; /* top of state stack */
1157
1158 int TclDatestate; /* current state */
1159 int TclDatetmp; /* extra var (lasts between blocks) */
1160
1161 int TclDatenerrs; /* number of errors */
1162 int TclDateerrflag; /* error recovery flag */
1163 int TclDatechar; /* current input token number */
1164
1165
1166
1167 #ifdef YYNMBCHARS
1168 #define YYLEX() TclDatecvtok(TclDatelex())
1169 /*
1170 ** TclDatecvtok - return a token if i is a wchar_t value that exceeds 255.
1171 ** If i<255, i itself is the token. If i>255 but the neither
1172 ** of the 30th or 31st bit is on, i is already a token.
1173 */
1174 #if defined(__STDC__) || defined(__cplusplus)
1175 int TclDatecvtok(int i)
1176 #else
1177 int TclDatecvtok(i) int i;
1178 #endif
1179 {
1180 int first = 0;
1181 int last = YYNMBCHARS - 1;
1182 int mid;
1183 wchar_t j;
1184
1185 if(i&0x60000000){/*Must convert to a token. */
1186 if( TclDatembchars[last].character < i ){
1187 return i;/*Giving up*/
1188 }
1189 while ((last>=first)&&(first>=0)) {/*Binary search loop*/
1190 mid = (first+last)/2;
1191 j = TclDatembchars[mid].character;
1192 if( j==i ){/*Found*/
1193 return TclDatembchars[mid].tvalue;
1194 }else if( j<i ){
1195 first = mid + 1;
1196 }else{
1197 last = mid -1;
1198 }
1199 }
1200 /*No entry in the table.*/
1201 return i;/* Giving up.*/
1202 }else{/* i is already a token. */
1203 return i;
1204 }
1205 }
1206 #else/*!YYNMBCHARS*/
1207 #define YYLEX() TclDatelex()
1208 #endif/*!YYNMBCHARS*/
1209
1210 /*
1211 ** TclDateparse - return 0 if worked, 1 if syntax error not recovered from
1212 */
1213 #if defined(__STDC__) || defined(__cplusplus)
1214 int TclDateparse(void)
1215 #else
1216 int TclDateparse()
1217 #endif
1218 {
1219 register YYSTYPE *TclDatepvt = 0; /* top of value stack for $vars */
1220
1221 #if defined(__cplusplus) || defined(lint)
1222 /*
1223 hacks to please C++ and lint - goto's inside
1224 switch should never be executed
1225 */
1226 static int __yaccpar_lint_hack__ = 0;
1227 switch (__yaccpar_lint_hack__)
1228 {
1229 case 1: goto TclDateerrlab;
1230 case 2: goto TclDatenewstate;
1231 }
1232 #endif
1233
1234 /*
1235 ** Initialize externals - TclDateparse may be called more than once
1236 */
1237 TclDatepv = &TclDatev[-1];
1238 TclDateps = &TclDates[-1];
1239 TclDatestate = 0;
1240 TclDatetmp = 0;
1241 TclDatenerrs = 0;
1242 TclDateerrflag = 0;
1243 TclDatechar = -1;
1244
1245 #if YYMAXDEPTH <= 0
1246 if (TclDatemaxdepth <= 0)
1247 {
1248 if ((TclDatemaxdepth = YYEXPAND(0)) <= 0)
1249 {
1250 TclDateerror("yacc initialization error");
1251 YYABORT;
1252 }
1253 }
1254 #endif
1255
1256 {
1257 register YYSTYPE *TclDate_pv; /* top of value stack */
1258 register int *TclDate_ps; /* top of state stack */
1259 register int TclDate_state; /* current state */
1260 register int TclDate_n; /* internal state number info */
1261 goto TclDatestack; /* moved from 6 lines above to here to please C++ */
1262
1263 /*
1264 ** get globals into registers.
1265 ** branch to here only if YYBACKUP was called.
1266 */
1267 TclDate_pv = TclDatepv;
1268 TclDate_ps = TclDateps;
1269 TclDate_state = TclDatestate;
1270 goto TclDate_newstate;
1271
1272 /*
1273 ** get globals into registers.
1274 ** either we just started, or we just finished a reduction
1275 */
1276 TclDatestack:
1277 TclDate_pv = TclDatepv;
1278 TclDate_ps = TclDateps;
1279 TclDate_state = TclDatestate;
1280
1281 /*
1282 ** top of for (;;) loop while no reductions done
1283 */
1284 TclDate_stack:
1285 /*
1286 ** put a state and value onto the stacks
1287 */
1288 #if YYDEBUG
1289 /*
1290 ** if debugging, look up token value in list of value vs.
1291 ** name pairs. 0 and negative (-1) are special values.
1292 ** Note: linear search is used since time is not a real
1293 ** consideration while debugging.
1294 */
1295 if ( TclDatedebug )
1296 {
1297 register int TclDate_i;
1298
1299 printf( "State %d, token ", TclDate_state );
1300 if ( TclDatechar == 0 )
1301 printf( "end-of-file\n" );
1302 else if ( TclDatechar < 0 )
1303 printf( "-none-\n" );
1304 else
1305 {
1306 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1307 TclDate_i++ )
1308 {
1309 if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1310 break;
1311 }
1312 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1313 }
1314 }
1315 #endif /* YYDEBUG */
1316 if ( ++TclDate_ps >= &TclDates[ TclDatemaxdepth ] ) /* room on stack? */
1317 {
1318 /*
1319 ** reallocate and recover. Note that pointers
1320 ** have to be reset, or bad things will happen
1321 */
1322 long TclDateps_index = (TclDate_ps - TclDates);
1323 long TclDatepv_index = (TclDate_pv - TclDatev);
1324 long TclDatepvt_index = (TclDatepvt - TclDatev);
1325 int TclDatenewmax;
1326 #ifdef YYEXPAND
1327 TclDatenewmax = YYEXPAND(TclDatemaxdepth);
1328 #else
1329 TclDatenewmax = 2 * TclDatemaxdepth; /* double table size */
1330 if (TclDatemaxdepth == YYMAXDEPTH) /* first time growth */
1331 {
1332 char *newTclDates = (char *)YYNEW(int);
1333 char *newTclDatev = (char *)YYNEW(YYSTYPE);
1334 if (newTclDates != 0 && newTclDatev != 0)
1335 {
1336 TclDates = YYCOPY(newTclDates, TclDates, int);
1337 TclDatev = YYCOPY(newTclDatev, TclDatev, YYSTYPE);
1338 }
1339 else
1340 TclDatenewmax = 0; /* failed */
1341 }
1342 else /* not first time */
1343 {
1344 TclDates = YYENLARGE(TclDates, int);
1345 TclDatev = YYENLARGE(TclDatev, YYSTYPE);
1346 if (TclDates == 0 || TclDatev == 0)
1347 TclDatenewmax = 0; /* failed */
1348 }
1349 #endif
1350 if (TclDatenewmax <= TclDatemaxdepth) /* tables not expanded */
1351 {
1352 TclDateerror( "yacc stack overflow" );
1353 YYABORT;
1354 }
1355 TclDatemaxdepth = TclDatenewmax;
1356
1357 TclDate_ps = TclDates + TclDateps_index;
1358 TclDate_pv = TclDatev + TclDatepv_index;
1359 TclDatepvt = TclDatev + TclDatepvt_index;
1360 }
1361 *TclDate_ps = TclDate_state;
1362 *++TclDate_pv = TclDateval;
1363
1364 /*
1365 ** we have a new state - find out what to do
1366 */
1367 TclDate_newstate:
1368 if ( ( TclDate_n = TclDatepact[ TclDate_state ] ) <= YYFLAG )
1369 goto TclDatedefault; /* simple state */
1370 #if YYDEBUG
1371 /*
1372 ** if debugging, need to mark whether new token grabbed
1373 */
1374 TclDatetmp = TclDatechar < 0;
1375 #endif
1376 if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1377 TclDatechar = 0; /* reached EOF */
1378 #if YYDEBUG
1379 if ( TclDatedebug && TclDatetmp )
1380 {
1381 register int TclDate_i;
1382
1383 printf( "Received token " );
1384 if ( TclDatechar == 0 )
1385 printf( "end-of-file\n" );
1386 else if ( TclDatechar < 0 )
1387 printf( "-none-\n" );
1388 else
1389 {
1390 for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0;
1391 TclDate_i++ )
1392 {
1393 if ( TclDatetoks[TclDate_i].t_val == TclDatechar )
1394 break;
1395 }
1396 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1397 }
1398 }
1399 #endif /* YYDEBUG */
1400 if ( ( ( TclDate_n += TclDatechar ) < 0 ) || ( TclDate_n >= YYLAST ) )
1401 goto TclDatedefault;
1402 if ( TclDatechk[ TclDate_n = TclDateact[ TclDate_n ] ] == TclDatechar ) /*valid shift*/
1403 {
1404 TclDatechar = -1;
1405 TclDateval = TclDatelval;
1406 TclDate_state = TclDate_n;
1407 if ( TclDateerrflag > 0 )
1408 TclDateerrflag--;
1409 goto TclDate_stack;
1410 }
1411
1412 TclDatedefault:
1413 if ( ( TclDate_n = TclDatedef[ TclDate_state ] ) == -2 )
1414 {
1415 #if YYDEBUG
1416 TclDatetmp = TclDatechar < 0;
1417 #endif
1418 if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) )
1419 TclDatechar = 0; /* reached EOF */
1420 #if YYDEBUG
1421 if ( TclDatedebug && TclDatetmp )
1422 {
1423 register int TclDate_i;
1424
1425 printf( "Received token " );
1426 if ( TclDatechar == 0 )
1427 printf( "end-of-file\n" );
1428 else if ( TclDatechar < 0 )
1429 printf( "-none-\n" );
1430 else
1431 {
1432 for ( TclDate_i = 0;
1433 TclDatetoks[TclDate_i].t_val >= 0;
1434 TclDate_i++ )
1435 {
1436 if ( TclDatetoks[TclDate_i].t_val
1437 == TclDatechar )
1438 {
1439 break;
1440 }
1441 }
1442 printf( "%s\n", TclDatetoks[TclDate_i].t_name );
1443 }
1444 }
1445 #endif /* YYDEBUG */
1446 /*
1447 ** look through exception table
1448 */
1449 {
1450 register CONST int *TclDatexi = TclDateexca;
1451
1452 while ( ( *TclDatexi != -1 ) ||
1453 ( TclDatexi[1] != TclDate_state ) )
1454 {
1455 TclDatexi += 2;
1456 }
1457 while ( ( *(TclDatexi += 2) >= 0 ) &&
1458 ( *TclDatexi != TclDatechar ) )
1459 ;
1460 if ( ( TclDate_n = TclDatexi[1] ) < 0 )
1461 YYACCEPT;
1462 }
1463 }
1464
1465 /*
1466 ** check for syntax error
1467 */
1468 if ( TclDate_n == 0 ) /* have an error */
1469 {
1470 /* no worry about speed here! */
1471 switch ( TclDateerrflag )
1472 {
1473 case 0: /* new error */
1474 TclDateerror( "syntax error" );
1475 goto skip_init;
1476 /*
1477 ** get globals into registers.
1478 ** we have a user generated syntax type error
1479 */
1480 TclDate_pv = TclDatepv;
1481 TclDate_ps = TclDateps;
1482 TclDate_state = TclDatestate;
1483 skip_init:
1484 TclDatenerrs++;
1485 /* FALLTHRU */
1486 case 1:
1487 case 2: /* incompletely recovered error */
1488 /* try again... */
1489 TclDateerrflag = 3;
1490 /*
1491 ** find state where "error" is a legal
1492 ** shift action
1493 */
1494 while ( TclDate_ps >= TclDates )
1495 {
1496 TclDate_n = TclDatepact[ *TclDate_ps ] + YYERRCODE;
1497 if ( TclDate_n >= 0 && TclDate_n < YYLAST &&
1498 TclDatechk[TclDateact[TclDate_n]] == YYERRCODE) {
1499 /*
1500 ** simulate shift of "error"
1501 */
1502 TclDate_state = TclDateact[ TclDate_n ];
1503 goto TclDate_stack;
1504 }
1505 /*
1506 ** current state has no shift on
1507 ** "error", pop stack
1508 */
1509 #if YYDEBUG
1510 # define _POP_ "Error recovery pops state %d, uncovers state %d\n"
1511 if ( TclDatedebug )
1512 printf( _POP_, *TclDate_ps,
1513 TclDate_ps[-1] );
1514 # undef _POP_
1515 #endif
1516 TclDate_ps--;
1517 TclDate_pv--;
1518 }
1519 /*
1520 ** there is no state on stack with "error" as
1521 ** a valid shift. give up.
1522 */
1523 YYABORT;
1524 case 3: /* no shift yet; eat a token */
1525 #if YYDEBUG
1526 /*
1527 ** if debugging, look up token in list of
1528 ** pairs. 0 and negative shouldn't occur,
1529 ** but since timing doesn't matter when
1530 ** debugging, it doesn't hurt to leave the
1531 ** tests here.
1532 */
1533 if ( TclDatedebug )
1534 {
1535 register int TclDate_i;
1536
1537 printf( "Error recovery discards " );
1538 if ( TclDatechar == 0 )
1539 printf( "token end-of-file\n" );
1540 else if ( TclDatechar < 0 )
1541 printf( "token -none-\n" );
1542 else
1543 {
1544 for ( TclDate_i = 0;
1545 TclDatetoks[TclDate_i].t_val >= 0;
1546 TclDate_i++ )
1547 {
1548 if ( TclDatetoks[TclDate_i].t_val
1549 == TclDatechar )
1550 {
1551 break;
1552 }
1553 }
1554 printf( "token %s\n",
1555 TclDatetoks[TclDate_i].t_name );
1556 }
1557 }
1558 #endif /* YYDEBUG */
1559 if ( TclDatechar == 0 ) /* reached EOF. quit */
1560 YYABORT;
1561 TclDatechar = -1;
1562 goto TclDate_newstate;
1563 }
1564 }/* end if ( TclDate_n == 0 ) */
1565 /*
1566 ** reduction by production TclDate_n
1567 ** put stack tops, etc. so things right after switch
1568 */
1569 #if YYDEBUG
1570 /*
1571 ** if debugging, print the string that is the user's
1572 ** specification of the reduction which is just about
1573 ** to be done.
1574 */
1575 if ( TclDatedebug )
1576 printf( "Reduce by (%d) \"%s\"\n",
1577 TclDate_n, TclDatereds[ TclDate_n ] );
1578 #endif
1579 TclDatetmp = TclDate_n; /* value to switch over */
1580 TclDatepvt = TclDate_pv; /* $vars top of value stack */
1581 /*
1582 ** Look in goto table for next state
1583 ** Sorry about using TclDate_state here as temporary
1584 ** register variable, but why not, if it works...
1585 ** If TclDater2[ TclDate_n ] doesn't have the low order bit
1586 ** set, then there is no action to be done for
1587 ** this reduction. So, no saving & unsaving of
1588 ** registers done. The only difference between the
1589 ** code just after the if and the body of the if is
1590 ** the goto TclDate_stack in the body. This way the test
1591 ** can be made before the choice of what to do is needed.
1592 */
1593 {
1594 /* length of production doubled with extra bit */
1595 register int TclDate_len = TclDater2[ TclDate_n ];
1596
1597 if ( !( TclDate_len & 01 ) )
1598 {
1599 TclDate_len >>= 1;
1600 TclDateval = ( TclDate_pv -= TclDate_len )[1]; /* $$ = $1 */
1601 TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] +
1602 *( TclDate_ps -= TclDate_len ) + 1;
1603 if ( TclDate_state >= YYLAST ||
1604 TclDatechk[ TclDate_state =
1605 TclDateact[ TclDate_state ] ] != -TclDate_n )
1606 {
1607 TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
1608 }
1609 goto TclDate_stack;
1610 }
1611 TclDate_len >>= 1;
1612 TclDateval = ( TclDate_pv -= TclDate_len )[1]; /* $$ = $1 */
1613 TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] +
1614 *( TclDate_ps -= TclDate_len ) + 1;
1615 if ( TclDate_state >= YYLAST ||
1616 TclDatechk[ TclDate_state = TclDateact[ TclDate_state ] ] != -TclDate_n )
1617 {
1618 TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ];
1619 }
1620 }
1621 /* save until reenter driver code */
1622 TclDatestate = TclDate_state;
1623 TclDateps = TclDate_ps;
1624 TclDatepv = TclDate_pv;
1625 }
1626 /*
1627 ** code supplied by user is placed in this switch
1628 */
1629 switch( TclDatetmp )
1630 {
1631
1632 case 3:{
1633 TclDateHaveTime++;
1634 } break;
1635 case 4:{
1636 TclDateHaveZone++;
1637 } break;
1638 case 5:{
1639 TclDateHaveDate++;
1640 } break;
1641 case 6:{
1642 TclDateHaveOrdinalMonth++;
1643 } break;
1644 case 7:{
1645 TclDateHaveDay++;
1646 } break;
1647 case 8:{
1648 TclDateHaveRel++;
1649 } break;
1650 case 9:{
1651 TclDateHaveTime++;
1652 TclDateHaveDate++;
1653 } break;
1654 case 10:{
1655 TclDateHaveTime++;
1656 TclDateHaveDate++;
1657 TclDateHaveRel++;
1658 } break;
1659 case 12:{
1660 TclDateHour = TclDatepvt[-1].Number;
1661 TclDateMinutes = 0;
1662 TclDateSeconds = 0;
1663 TclDateMeridian = TclDatepvt[-0].Meridian;
1664 } break;
1665 case 13:{
1666 TclDateHour = TclDatepvt[-3].Number;
1667 TclDateMinutes = TclDatepvt[-1].Number;
1668 TclDateSeconds = 0;
1669 TclDateMeridian = TclDatepvt[-0].Meridian;
1670 } break;
1671 case 14:{
1672 TclDateHour = TclDatepvt[-4].Number;
1673 TclDateMinutes = TclDatepvt[-2].Number;
1674 TclDateMeridian = MER24;
1675 TclDateDSTmode = DSToff;
1676 TclDateTimezone = (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60);
1677 } break;
1678 case 15:{
1679 TclDateHour = TclDatepvt[-5].Number;
1680 TclDateMinutes = TclDatepvt[-3].Number;
1681 TclDateSeconds = TclDatepvt[-1].Number;
1682 TclDateMeridian = TclDatepvt[-0].Meridian;
1683 } break;
1684 case 16:{
1685 TclDateHour = TclDatepvt[-6].Number;
1686 TclDateMinutes = TclDatepvt[-4].Number;
1687 TclDateSeconds = TclDatepvt[-2].Number;
1688 TclDateMeridian = MER24;
1689 TclDateDSTmode = DSToff;
1690 TclDateTimezone = (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60);
1691 } break;
1692 case 17:{
1693 TclDateTimezone = TclDatepvt[-1].Number;
1694 TclDateDSTmode = DSTon;
1695 } break;
1696 case 18:{
1697 TclDateTimezone = TclDatepvt[-0].Number;
1698 TclDateDSTmode = DSToff;
1699 } break;
1700 case 19:{
1701 TclDateTimezone = TclDatepvt[-0].Number;
1702 TclDateDSTmode = DSTon;
1703 } break;
1704 case 20:{
1705 TclDateDayOrdinal = 1;
1706 TclDateDayNumber = TclDatepvt[-0].Number;
1707 } break;
1708 case 21:{
1709 TclDateDayOrdinal = 1;
1710 TclDateDayNumber = TclDatepvt[-1].Number;
1711 } break;
1712 case 22:{
1713 TclDateDayOrdinal = TclDatepvt[-1].Number;
1714 TclDateDayNumber = TclDatepvt[-0].Number;
1715 } break;
1716 case 23:{
1717 TclDateDayOrdinal = TclDatepvt[-2].Number * TclDatepvt[-1].Number;
1718 TclDateDayNumber = TclDatepvt[-0].Number;
1719 } break;
1720 case 24:{
1721 TclDateDayOrdinal = 2;
1722 TclDateDayNumber = TclDatepvt[-0].Number;
1723 } break;
1724 case 25:{
1725 TclDateMonth = TclDatepvt[-2].Number;
1726 TclDateDay = TclDatepvt[-0].Number;
1727 } break;
1728 case 26:{
1729 TclDateMonth = TclDatepvt[-4].Number;
1730 TclDateDay = TclDatepvt[-2].Number;
1731 TclDateYear = TclDatepvt[-0].Number;
1732 } break;
1733 case 27:{
1734 TclDateYear = TclDatepvt[-0].Number / 10000;
1735 TclDateMonth = (TclDatepvt[-0].Number % 10000)/100;
1736 TclDateDay = TclDatepvt[-0].Number % 100;
1737 } break;
1738 case 28:{
1739 TclDateDay = TclDatepvt[-4].Number;
1740 TclDateMonth = TclDatepvt[-2].Number;
1741 TclDateYear = TclDatepvt[-0].Number;
1742 } break;
1743 case 29:{
1744 TclDateMonth = TclDatepvt[-2].Number;
1745 TclDateDay = TclDatepvt[-0].Number;
1746 TclDateYear = TclDatepvt[-4].Number;
1747 } break;
1748 case 30:{
1749 TclDateMonth = TclDatepvt[-1].Number;
1750 TclDateDay = TclDatepvt[-0].Number;
1751 } break;
1752 case 31:{
1753 TclDateMonth = TclDatepvt[-3].Number;
1754 TclDateDay = TclDatepvt[-2].Number;
1755 TclDateYear = TclDatepvt[-0].Number;
1756 } break;
1757 case 32:{
1758 TclDateMonth = TclDatepvt[-0].Number;
1759 TclDateDay = TclDatepvt[-1].Number;
1760 } break;
1761 case 33:{
1762 TclDateMonth = 1;
1763 TclDateDay = 1;
1764 TclDateYear = EPOCH;
1765 } break;
1766 case 34:{
1767 TclDateMonth = TclDatepvt[-1].Number;
1768 TclDateDay = TclDatepvt[-2].Number;
1769 TclDateYear = TclDatepvt[-0].Number;
1770 } break;
1771 case 35:{
1772 TclDateMonthOrdinal = 1;
1773 TclDateMonth = TclDatepvt[-0].Number;
1774 } break;
1775 case 36:{
1776 TclDateMonthOrdinal = TclDatepvt[-1].Number;
1777 TclDateMonth = TclDatepvt[-0].Number;
1778 } break;
1779 case 37:{
1780 if (TclDatepvt[-1].Number != HOUR(- 7)) YYABORT;
1781 TclDateYear = TclDatepvt[-2].Number / 10000;
1782 TclDateMonth = (TclDatepvt[-2].Number % 10000)/100;
1783 TclDateDay = TclDatepvt[-2].Number % 100;
1784 TclDateHour = TclDatepvt[-0].Number / 10000;
1785 TclDateMinutes = (TclDatepvt[-0].Number % 10000)/100;
1786 TclDateSeconds = TclDatepvt[-0].Number % 100;
1787 } break;
1788 case 38:{
1789 if (TclDatepvt[-5].Number != HOUR(- 7)) YYABORT;
1790 TclDateYear = TclDatepvt[-6].Number / 10000;
1791 TclDateMonth = (TclDatepvt[-6].Number % 10000)/100;
1792 TclDateDay = TclDatepvt[-6].Number % 100;
1793 TclDateHour = TclDatepvt[-4].Number;
1794 TclDateMinutes = TclDatepvt[-2].Number;
1795 TclDateSeconds = TclDatepvt[-0].Number;
1796 } break;
1797 case 39:{
1798 TclDateYear = TclDatepvt[-1].Number / 10000;
1799 TclDateMonth = (TclDatepvt[-1].Number % 10000)/100;
1800 TclDateDay = TclDatepvt[-1].Number % 100;
1801 TclDateHour = TclDatepvt[-0].Number / 10000;
1802 TclDateMinutes = (TclDatepvt[-0].Number % 10000)/100;
1803 TclDateSeconds = TclDatepvt[-0].Number % 100;
1804 } break;
1805 case 40:{
1806 /*
1807 * Offset computed year by -377 so that the returned years will
1808 * be in a range accessible with a 32 bit clock seconds value
1809 */
1810 TclDateYear = TclDatepvt[-2].Number/1000 + 2323 - 377;
1811 TclDateDay = 1;
1812 TclDateMonth = 1;
1813 TclDateRelDay += ((TclDatepvt[-2].Number%1000)*(365 + IsLeapYear(TclDateYear)))/1000;
1814 TclDateRelSeconds += TclDatepvt[-0].Number * 144 * 60;
1815 } break;
1816 case 41:{ *TclDateRelPointer += TclDatepvt[-3].Number * TclDatepvt[-2].Number * TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break;
1817 case 42:{ *TclDateRelPointer += TclDatepvt[-2].Number * TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break;
1818 case 43:{ *TclDateRelPointer += TclDatepvt[-0].Number; } break;
1819 case 44:{ *TclDateRelPointer += TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break;
1820 case 45:{ *TclDateRelPointer += TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break;
1821 case 46:{ TclDateval.Number = -1; } break;
1822 case 47:{ TclDateval.Number = 1; } break;
1823 case 48:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelSeconds; } break;
1824 case 49:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelDay; } break;
1825 case 50:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelMonth; } break;
1826 case 51:{ TclDateval.Number = -1; } break;
1827 case 52:{ TclDateval.Number = 1; } break;
1828 case 53:{
1829 if (TclDateHaveTime && TclDateHaveDate && !TclDateHaveRel) {
1830 TclDateYear = TclDatepvt[-0].Number;
1831 } else {
1832 TclDateHaveTime++;
1833 if (TclDatepvt[-0].Number < 100) {
1834 TclDateHour = TclDatepvt[-0].Number;
1835 TclDateMinutes = 0;
1836 } else {
1837 TclDateHour = TclDatepvt[-0].Number / 100;
1838 TclDateMinutes = TclDatepvt[-0].Number % 100;
1839 }
1840 TclDateSeconds = 0;
1841 TclDateMeridian = MER24;
1842 }
1843 } break;
1844 case 54:{
1845 TclDateval.Meridian = MER24;
1846 } break;
1847 case 55:{
1848 TclDateval.Meridian = TclDatepvt[-0].Meridian;
1849 } break;
1850 }
1851 goto TclDatestack; /* reset registers in driver code */
1852 }
1853
1854 /* End of tcldate.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25