~ubuntu-branches/ubuntu/quantal/sudo/quantal

« back to all changes in this revision

Viewing changes to plugins/sudoers/getdate.y

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-11-20 12:07:45 UTC
  • mfrom: (1.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20111120120745-o3qpklobmygytndc
Tags: 1.8.3p1-1ubuntu1
* Merge from debian/testing, remaining changes:
  - debian/patches/keep_home_by_default.patch:
    + Set HOME in initial_keepenv_table. (rebased for 1.8.3p1)
  - debian/patches/enable_badpass.patch: turn on "mail_badpass" by default:
    + attempting sudo without knowing a login password is as bad as not
      being listed in the sudoers file, especially if getting the password
      wrong means doing the access-check-email-notification never happens
      (rebased for 1.8.3p1)
  - debian/rules:
    + compile with --without-lecture --with-tty-tickets (Ubuntu specific)
    + install man/man8/sudo_root.8 (Ubuntu specific)
    + install apport hooks
    + The ubuntu-sudo-as-admin-successful.patch was taken upstream by
      Debian however it requires a --enable-admin-flag configure flag to
      actually enable it.
  - debian/sudoers: 
    + grant admin group sudo access
  - debian/sudo-ldap.dirs, debian/sudo.dirs: 
    + add usr/share/apport/package-hooks
  - debian/sudo.preinst:
    + avoid conffile prompt by checking for known default /etc/sudoers
      and if found installing the correct default /etc/sudoers file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%{
 
2
/*
 
3
**  Originally written by Steven M. Bellovin <smb@research.att.com> while
 
4
**  at the University of North Carolina at Chapel Hill.  Later tweaked by
 
5
**  a couple of people on Usenet.  Completely overhauled by Rich $alz
 
6
**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
 
7
**
 
8
**  This grammar has 10 shift/reduce conflicts.
 
9
**
 
10
**  This code is in the public domain and has no copyright.
 
11
*/
 
12
/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
 
13
/* SUPPRESS 288 on yyerrlab *//* Label unused */
 
14
 
 
15
#include <config.h>
 
16
 
 
17
#include <sys/types.h>
 
18
#include <sys/time.h>
 
19
#include <stdio.h>
 
20
#ifdef STDC_HEADERS
 
21
# include <stdlib.h>
 
22
# include <stddef.h>
 
23
#else
 
24
# ifdef HAVE_STDLIB_H
 
25
#  include <stdlib.h>
 
26
# endif
 
27
#endif /* STDC_HEADERS */
 
28
#ifdef HAVE_STRING_H
 
29
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
 
30
#  include <memory.h>
 
31
# endif
 
32
# include <string.h>
 
33
#endif /* HAVE_STRING_H */
 
34
#ifdef HAVE_STRINGS_H
 
35
# include <strings.h>
 
36
#endif /* HAVE_STRINGS_H */
 
37
#if TIME_WITH_SYS_TIME
 
38
# include <time.h>
 
39
#endif
 
40
#include <ctype.h>
 
41
 
 
42
#include "missing.h"
 
43
 
 
44
 
 
45
#define EPOCH           1970
 
46
#define HOUR(x)         ((time_t)(x) * 60)
 
47
#define SECSPERDAY      (24L * 60L * 60L)
 
48
 
 
49
 
 
50
/*
 
51
**  An entry in the lexical lookup table.
 
52
*/
 
53
typedef struct _TABLE {
 
54
    char        *name;
 
55
    int         type;
 
56
    time_t      value;
 
57
} TABLE;
 
58
 
 
59
 
 
60
/*
 
61
**  Daylight-savings mode:  on, off, or not yet known.
 
62
*/
 
63
typedef enum _DSTMODE {
 
64
    DSTon, DSToff, DSTmaybe
 
65
} DSTMODE;
 
66
 
 
67
/*
 
68
**  Meridian:  am, pm, or 24-hour style.
 
69
*/
 
70
typedef enum _MERIDIAN {
 
71
    MERam, MERpm, MER24
 
72
} MERIDIAN;
 
73
 
 
74
 
 
75
/*
 
76
**  Global variables.  We could get rid of most of these by using a good
 
77
**  union as the yacc stack.  (This routine was originally written before
 
78
**  yacc had the %union construct.)  Maybe someday; right now we only use
 
79
**  the %union very rarely.
 
80
*/
 
81
static char     *yyInput;
 
82
static DSTMODE  yyDSTmode;
 
83
static time_t   yyDayOrdinal;
 
84
static time_t   yyDayNumber;
 
85
static int      yyHaveDate;
 
86
static int      yyHaveDay;
 
87
static int      yyHaveRel;
 
88
static int      yyHaveTime;
 
89
static int      yyHaveZone;
 
90
static time_t   yyTimezone;
 
91
static time_t   yyDay;
 
92
static time_t   yyHour;
 
93
static time_t   yyMinutes;
 
94
static time_t   yyMonth;
 
95
static time_t   yySeconds;
 
96
static time_t   yyYear;
 
97
static MERIDIAN yyMeridian;
 
98
static time_t   yyRelMonth;
 
99
static time_t   yyRelSeconds;
 
100
 
 
101
static int      yyerror(char *s);
 
102
static int      yylex(void);
 
103
       int      yyparse(void);
 
104
 
 
105
%}
 
106
 
 
107
%union {
 
108
    time_t              Number;
 
109
    enum _MERIDIAN      Meridian;
 
110
}
 
111
 
 
112
%token  tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
 
113
%token  tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
 
114
 
 
115
%type   <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
 
116
%type   <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
 
117
%type   <Meridian>      tMERIDIAN o_merid
 
118
 
 
119
%%
 
120
 
 
121
spec    : /* NULL */
 
122
        | spec item
 
123
        ;
 
124
 
 
125
item    : time {
 
126
            yyHaveTime++;
 
127
        }
 
128
        | zone {
 
129
            yyHaveZone++;
 
130
        }
 
131
        | date {
 
132
            yyHaveDate++;
 
133
        }
 
134
        | day {
 
135
            yyHaveDay++;
 
136
        }
 
137
        | rel {
 
138
            yyHaveRel++;
 
139
        }
 
140
        | number
 
141
        ;
 
142
 
 
143
time    : tUNUMBER tMERIDIAN {
 
144
            yyHour = $1;
 
145
            yyMinutes = 0;
 
146
            yySeconds = 0;
 
147
            yyMeridian = $2;
 
148
        }
 
149
        | tUNUMBER ':' tUNUMBER o_merid {
 
150
            yyHour = $1;
 
151
            yyMinutes = $3;
 
152
            yySeconds = 0;
 
153
            yyMeridian = $4;
 
154
        }
 
155
        | tUNUMBER ':' tUNUMBER tSNUMBER {
 
156
            yyHour = $1;
 
157
            yyMinutes = $3;
 
158
            yyMeridian = MER24;
 
159
            yyDSTmode = DSToff;
 
160
            yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
 
161
        }
 
162
        | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
 
163
            yyHour = $1;
 
164
            yyMinutes = $3;
 
165
            yySeconds = $5;
 
166
            yyMeridian = $6;
 
167
        }
 
168
        | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
 
169
            yyHour = $1;
 
170
            yyMinutes = $3;
 
171
            yySeconds = $5;
 
172
            yyMeridian = MER24;
 
173
            yyDSTmode = DSToff;
 
174
            yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
 
175
        }
 
176
        ;
 
177
 
 
178
zone    : tZONE {
 
179
            yyTimezone = $1;
 
180
            yyDSTmode = DSToff;
 
181
        }
 
182
        | tDAYZONE {
 
183
            yyTimezone = $1;
 
184
            yyDSTmode = DSTon;
 
185
        }
 
186
        |
 
187
          tZONE tDST {
 
188
            yyTimezone = $1;
 
189
            yyDSTmode = DSTon;
 
190
        }
 
191
        ;
 
192
 
 
193
day     : tDAY {
 
194
            yyDayOrdinal = 1;
 
195
            yyDayNumber = $1;
 
196
        }
 
197
        | tDAY ',' {
 
198
            yyDayOrdinal = 1;
 
199
            yyDayNumber = $1;
 
200
        }
 
201
        | tUNUMBER tDAY {
 
202
            yyDayOrdinal = $1;
 
203
            yyDayNumber = $2;
 
204
        }
 
205
        ;
 
206
 
 
207
date    : tUNUMBER '/' tUNUMBER {
 
208
            yyMonth = $1;
 
209
            yyDay = $3;
 
210
        }
 
211
        | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
 
212
            if ($1 >= 100) {
 
213
                yyYear = $1;
 
214
                yyMonth = $3;
 
215
                yyDay = $5;
 
216
            } else {
 
217
                yyMonth = $1;
 
218
                yyDay = $3;
 
219
                yyYear = $5;
 
220
            }
 
221
        }
 
222
        | tUNUMBER tSNUMBER tSNUMBER {
 
223
            /* ISO 8601 format.  yyyy-mm-dd.  */
 
224
            yyYear = $1;
 
225
            yyMonth = -$2;
 
226
            yyDay = -$3;
 
227
        }
 
228
        | tUNUMBER tMONTH tSNUMBER {
 
229
            /* e.g. 17-JUN-1992.  */
 
230
            yyDay = $1;
 
231
            yyMonth = $2;
 
232
            yyYear = -$3;
 
233
        }
 
234
        | tMONTH tUNUMBER {
 
235
            yyMonth = $1;
 
236
            yyDay = $2;
 
237
        }
 
238
        | tMONTH tUNUMBER ',' tUNUMBER {
 
239
            yyMonth = $1;
 
240
            yyDay = $2;
 
241
            yyYear = $4;
 
242
        }
 
243
        | tUNUMBER tMONTH {
 
244
            yyMonth = $2;
 
245
            yyDay = $1;
 
246
        }
 
247
        | tUNUMBER tMONTH tUNUMBER {
 
248
            yyMonth = $2;
 
249
            yyDay = $1;
 
250
            yyYear = $3;
 
251
        }
 
252
        ;
 
253
 
 
254
rel     : relunit tAGO {
 
255
            yyRelSeconds = -yyRelSeconds;
 
256
            yyRelMonth = -yyRelMonth;
 
257
        }
 
258
        | relunit
 
259
        ;
 
260
 
 
261
relunit : tUNUMBER tMINUTE_UNIT {
 
262
            yyRelSeconds += $1 * $2 * 60L;
 
263
        }
 
264
        | tSNUMBER tMINUTE_UNIT {
 
265
            yyRelSeconds += $1 * $2 * 60L;
 
266
        }
 
267
        | tMINUTE_UNIT {
 
268
            yyRelSeconds += $1 * 60L;
 
269
        }
 
270
        | tSNUMBER tSEC_UNIT {
 
271
            yyRelSeconds += $1;
 
272
        }
 
273
        | tUNUMBER tSEC_UNIT {
 
274
            yyRelSeconds += $1;
 
275
        }
 
276
        | tSEC_UNIT {
 
277
            yyRelSeconds++;
 
278
        }
 
279
        | tSNUMBER tMONTH_UNIT {
 
280
            yyRelMonth += $1 * $2;
 
281
        }
 
282
        | tUNUMBER tMONTH_UNIT {
 
283
            yyRelMonth += $1 * $2;
 
284
        }
 
285
        | tMONTH_UNIT {
 
286
            yyRelMonth += $1;
 
287
        }
 
288
        ;
 
289
 
 
290
number  : tUNUMBER {
 
291
            if (yyHaveTime && yyHaveDate && !yyHaveRel)
 
292
                yyYear = $1;
 
293
            else {
 
294
                if($1>10000) {
 
295
                    yyHaveDate++;
 
296
                    yyDay= ($1)%100;
 
297
                    yyMonth= ($1/100)%100;
 
298
                    yyYear = $1/10000;
 
299
                }
 
300
                else {
 
301
                    yyHaveTime++;
 
302
                    if ($1 < 100) {
 
303
                        yyHour = $1;
 
304
                        yyMinutes = 0;
 
305
                    }
 
306
                    else {
 
307
                        yyHour = $1 / 100;
 
308
                        yyMinutes = $1 % 100;
 
309
                    }
 
310
                    yySeconds = 0;
 
311
                    yyMeridian = MER24;
 
312
                }
 
313
            }
 
314
        }
 
315
        ;
 
316
 
 
317
o_merid : /* NULL */ {
 
318
            $$ = MER24;
 
319
        }
 
320
        | tMERIDIAN {
 
321
            $$ = $1;
 
322
        }
 
323
        ;
 
324
 
 
325
%%
 
326
 
 
327
/* Month and day table. */
 
328
static TABLE const MonthDayTable[] = {
 
329
    { "january",        tMONTH,  1 },
 
330
    { "february",       tMONTH,  2 },
 
331
    { "march",          tMONTH,  3 },
 
332
    { "april",          tMONTH,  4 },
 
333
    { "may",            tMONTH,  5 },
 
334
    { "june",           tMONTH,  6 },
 
335
    { "july",           tMONTH,  7 },
 
336
    { "august",         tMONTH,  8 },
 
337
    { "september",      tMONTH,  9 },
 
338
    { "sept",           tMONTH,  9 },
 
339
    { "october",        tMONTH, 10 },
 
340
    { "november",       tMONTH, 11 },
 
341
    { "december",       tMONTH, 12 },
 
342
    { "sunday",         tDAY, 0 },
 
343
    { "monday",         tDAY, 1 },
 
344
    { "tuesday",        tDAY, 2 },
 
345
    { "tues",           tDAY, 2 },
 
346
    { "wednesday",      tDAY, 3 },
 
347
    { "wednes",         tDAY, 3 },
 
348
    { "thursday",       tDAY, 4 },
 
349
    { "thur",           tDAY, 4 },
 
350
    { "thurs",          tDAY, 4 },
 
351
    { "friday",         tDAY, 5 },
 
352
    { "saturday",       tDAY, 6 },
 
353
    { NULL }
 
354
};
 
355
 
 
356
/* Time units table. */
 
357
static TABLE const UnitsTable[] = {
 
358
    { "year",           tMONTH_UNIT,    12 },
 
359
    { "month",          tMONTH_UNIT,    1 },
 
360
    { "fortnight",      tMINUTE_UNIT,   14 * 24 * 60 },
 
361
    { "week",           tMINUTE_UNIT,   7 * 24 * 60 },
 
362
    { "day",            tMINUTE_UNIT,   1 * 24 * 60 },
 
363
    { "hour",           tMINUTE_UNIT,   60 },
 
364
    { "minute",         tMINUTE_UNIT,   1 },
 
365
    { "min",            tMINUTE_UNIT,   1 },
 
366
    { "second",         tSEC_UNIT,      1 },
 
367
    { "sec",            tSEC_UNIT,      1 },
 
368
    { NULL }
 
369
};
 
370
 
 
371
/* Assorted relative-time words. */
 
372
static TABLE const OtherTable[] = {
 
373
    { "tomorrow",       tMINUTE_UNIT,   1 * 24 * 60 },
 
374
    { "yesterday",      tMINUTE_UNIT,   -1 * 24 * 60 },
 
375
    { "today",          tMINUTE_UNIT,   0 },
 
376
    { "now",            tMINUTE_UNIT,   0 },
 
377
    { "last",           tUNUMBER,       -1 },
 
378
    { "this",           tMINUTE_UNIT,   0 },
 
379
    { "next",           tUNUMBER,       2 },
 
380
    { "first",          tUNUMBER,       1 },
 
381
/*  { "second",         tUNUMBER,       2 }, */
 
382
    { "third",          tUNUMBER,       3 },
 
383
    { "fourth",         tUNUMBER,       4 },
 
384
    { "fifth",          tUNUMBER,       5 },
 
385
    { "sixth",          tUNUMBER,       6 },
 
386
    { "seventh",        tUNUMBER,       7 },
 
387
    { "eighth",         tUNUMBER,       8 },
 
388
    { "ninth",          tUNUMBER,       9 },
 
389
    { "tenth",          tUNUMBER,       10 },
 
390
    { "eleventh",       tUNUMBER,       11 },
 
391
    { "twelfth",        tUNUMBER,       12 },
 
392
    { "ago",            tAGO,   1 },
 
393
    { NULL }
 
394
};
 
395
 
 
396
/* The timezone table. */
 
397
/* Some of these are commented out because a time_t can't store a float. */
 
398
static TABLE const TimezoneTable[] = {
 
399
    { "gmt",    tZONE,     HOUR( 0) },  /* Greenwich Mean */
 
400
    { "ut",     tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
 
401
    { "utc",    tZONE,     HOUR( 0) },
 
402
    { "wet",    tZONE,     HOUR( 0) },  /* Western European */
 
403
    { "bst",    tDAYZONE,  HOUR( 0) },  /* British Summer */
 
404
    { "wat",    tZONE,     HOUR( 1) },  /* West Africa */
 
405
    { "at",     tZONE,     HOUR( 2) },  /* Azores */
 
406
#if     0
 
407
    /* For completeness.  BST is also British Summer, and GST is
 
408
     * also Guam Standard. */
 
409
    { "bst",    tZONE,     HOUR( 3) },  /* Brazil Standard */
 
410
    { "gst",    tZONE,     HOUR( 3) },  /* Greenland Standard */
 
411
#endif
 
412
#if 0
 
413
    { "nft",    tZONE,     HOUR(3.5) }, /* Newfoundland */
 
414
    { "nst",    tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
 
415
    { "ndt",    tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
 
416
#endif
 
417
    { "ast",    tZONE,     HOUR( 4) },  /* Atlantic Standard */
 
418
    { "adt",    tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
 
419
    { "est",    tZONE,     HOUR( 5) },  /* Eastern Standard */
 
420
    { "edt",    tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
 
421
    { "cst",    tZONE,     HOUR( 6) },  /* Central Standard */
 
422
    { "cdt",    tDAYZONE,  HOUR( 6) },  /* Central Daylight */
 
423
    { "mst",    tZONE,     HOUR( 7) },  /* Mountain Standard */
 
424
    { "mdt",    tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
 
425
    { "pst",    tZONE,     HOUR( 8) },  /* Pacific Standard */
 
426
    { "pdt",    tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
 
427
    { "yst",    tZONE,     HOUR( 9) },  /* Yukon Standard */
 
428
    { "ydt",    tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
 
429
    { "hst",    tZONE,     HOUR(10) },  /* Hawaii Standard */
 
430
    { "hdt",    tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
 
431
    { "cat",    tZONE,     HOUR(10) },  /* Central Alaska */
 
432
    { "ahst",   tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
 
433
    { "nt",     tZONE,     HOUR(11) },  /* Nome */
 
434
    { "idlw",   tZONE,     HOUR(12) },  /* International Date Line West */
 
435
    { "cet",    tZONE,     -HOUR(1) },  /* Central European */
 
436
    { "met",    tZONE,     -HOUR(1) },  /* Middle European */
 
437
    { "mewt",   tZONE,     -HOUR(1) },  /* Middle European Winter */
 
438
    { "mest",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
 
439
    { "swt",    tZONE,     -HOUR(1) },  /* Swedish Winter */
 
440
    { "sst",    tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
 
441
    { "fwt",    tZONE,     -HOUR(1) },  /* French Winter */
 
442
    { "fst",    tDAYZONE,  -HOUR(1) },  /* French Summer */
 
443
    { "eet",    tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
 
444
    { "bt",     tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
 
445
#if 0
 
446
    { "it",     tZONE,     -HOUR(3.5) },/* Iran */
 
447
#endif
 
448
    { "zp4",    tZONE,     -HOUR(4) },  /* USSR Zone 3 */
 
449
    { "zp5",    tZONE,     -HOUR(5) },  /* USSR Zone 4 */
 
450
#if 0
 
451
    { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
 
452
#endif
 
453
    { "zp6",    tZONE,     -HOUR(6) },  /* USSR Zone 5 */
 
454
#if     0
 
455
    /* For completeness.  NST is also Newfoundland Stanard, and SST is
 
456
     * also Swedish Summer. */
 
457
    { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
 
458
    { "sst",    tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
 
459
#endif  /* 0 */
 
460
    { "wast",   tZONE,     -HOUR(7) },  /* West Australian Standard */
 
461
    { "wadt",   tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
 
462
#if 0
 
463
    { "jt",     tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
 
464
#endif
 
465
    { "cct",    tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
 
466
    { "jst",    tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
 
467
#if 0
 
468
    { "cast",   tZONE,     -HOUR(9.5) },/* Central Australian Standard */
 
469
    { "cadt",   tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
 
470
#endif
 
471
    { "east",   tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
 
472
    { "eadt",   tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
 
473
    { "gst",    tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
 
474
    { "nzt",    tZONE,     -HOUR(12) }, /* New Zealand */
 
475
    { "nzst",   tZONE,     -HOUR(12) }, /* New Zealand Standard */
 
476
    { "nzdt",   tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
 
477
    { "idle",   tZONE,     -HOUR(12) }, /* International Date Line East */
 
478
    {  NULL  }
 
479
};
 
480
 
 
481
/* Military timezone table. */
 
482
static TABLE const MilitaryTable[] = {
 
483
    { "a",      tZONE,  HOUR(  1) },
 
484
    { "b",      tZONE,  HOUR(  2) },
 
485
    { "c",      tZONE,  HOUR(  3) },
 
486
    { "d",      tZONE,  HOUR(  4) },
 
487
    { "e",      tZONE,  HOUR(  5) },
 
488
    { "f",      tZONE,  HOUR(  6) },
 
489
    { "g",      tZONE,  HOUR(  7) },
 
490
    { "h",      tZONE,  HOUR(  8) },
 
491
    { "i",      tZONE,  HOUR(  9) },
 
492
    { "k",      tZONE,  HOUR( 10) },
 
493
    { "l",      tZONE,  HOUR( 11) },
 
494
    { "m",      tZONE,  HOUR( 12) },
 
495
    { "n",      tZONE,  HOUR(- 1) },
 
496
    { "o",      tZONE,  HOUR(- 2) },
 
497
    { "p",      tZONE,  HOUR(- 3) },
 
498
    { "q",      tZONE,  HOUR(- 4) },
 
499
    { "r",      tZONE,  HOUR(- 5) },
 
500
    { "s",      tZONE,  HOUR(- 6) },
 
501
    { "t",      tZONE,  HOUR(- 7) },
 
502
    { "u",      tZONE,  HOUR(- 8) },
 
503
    { "v",      tZONE,  HOUR(- 9) },
 
504
    { "w",      tZONE,  HOUR(-10) },
 
505
    { "x",      tZONE,  HOUR(-11) },
 
506
    { "y",      tZONE,  HOUR(-12) },
 
507
    { "z",      tZONE,  HOUR(  0) },
 
508
    { NULL }
 
509
};
 
510
 
 
511
 
 
512
 
 
513
 
 
514
/* ARGSUSED */
 
515
static int
 
516
yyerror(s)
 
517
    char        *s;
 
518
{
 
519
  return 0;
 
520
}
 
521
 
 
522
 
 
523
static time_t
 
524
ToSeconds(Hours, Minutes, Seconds, Meridian)
 
525
    time_t      Hours;
 
526
    time_t      Minutes;
 
527
    time_t      Seconds;
 
528
    MERIDIAN    Meridian;
 
529
{
 
530
    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
 
531
        return -1;
 
532
    switch (Meridian) {
 
533
    case MER24:
 
534
        if (Hours < 0 || Hours > 23)
 
535
            return -1;
 
536
        return (Hours * 60L + Minutes) * 60L + Seconds;
 
537
    case MERam:
 
538
        if (Hours < 1 || Hours > 12)
 
539
            return -1;
 
540
        if (Hours == 12)
 
541
            Hours = 0;
 
542
        return (Hours * 60L + Minutes) * 60L + Seconds;
 
543
    case MERpm:
 
544
        if (Hours < 1 || Hours > 12)
 
545
            return -1;
 
546
        if (Hours == 12)
 
547
            Hours = 0;
 
548
        return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
 
549
    default:
 
550
        abort ();
 
551
    }
 
552
    /* NOTREACHED */
 
553
}
 
554
 
 
555
 
 
556
/* Year is either
 
557
   * A negative number, which means to use its absolute value (why?)
 
558
   * A number from 0 to 99, which means a year from 1900 to 1999, or
 
559
   * The actual year (>=100).  */
 
560
static time_t
 
561
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
 
562
    time_t      Month;
 
563
    time_t      Day;
 
564
    time_t      Year;
 
565
    time_t      Hours;
 
566
    time_t      Minutes;
 
567
    time_t      Seconds;
 
568
    MERIDIAN    Meridian;
 
569
    DSTMODE     DSTmode;
 
570
{
 
571
    static int DaysInMonth[12] = {
 
572
        31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 
573
    };
 
574
    time_t      tod;
 
575
    time_t      Julian;
 
576
    int         i;
 
577
 
 
578
    if (Year < 0)
 
579
        Year = -Year;
 
580
    if (Year < 69)
 
581
        Year += 2000;
 
582
    else if (Year < 100) {
 
583
        Year += 1900;
 
584
        if (Year < EPOCH)
 
585
                Year += 100;
 
586
    }
 
587
    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
 
588
                    ? 29 : 28;
 
589
    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
 
590
       I'm too lazy to try to check for time_t overflow in another way.  */
 
591
    if (Year < EPOCH || Year > 2038
 
592
     || Month < 1 || Month > 12
 
593
     /* Lint fluff:  "conversion from long may lose accuracy" */
 
594
     || Day < 1 || Day > DaysInMonth[(int)--Month])
 
595
        return -1;
 
596
 
 
597
    for (Julian = Day - 1, i = 0; i < Month; i++)
 
598
        Julian += DaysInMonth[i];
 
599
    for (i = EPOCH; i < Year; i++)
 
600
        Julian += 365 + (i % 4 == 0);
 
601
    Julian *= SECSPERDAY;
 
602
    Julian += yyTimezone * 60L;
 
603
    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
 
604
        return -1;
 
605
    Julian += tod;
 
606
    if (DSTmode == DSTon
 
607
     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
 
608
        Julian -= 60 * 60;
 
609
    return Julian;
 
610
}
 
611
 
 
612
 
 
613
static time_t
 
614
DSTcorrect(Start, Future)
 
615
    time_t      Start;
 
616
    time_t      Future;
 
617
{
 
618
    time_t      StartDay;
 
619
    time_t      FutureDay;
 
620
 
 
621
    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
 
622
    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
 
623
    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
 
624
}
 
625
 
 
626
 
 
627
static time_t
 
628
RelativeDate(Start, DayOrdinal, DayNumber)
 
629
    time_t      Start;
 
630
    time_t      DayOrdinal;
 
631
    time_t      DayNumber;
 
632
{
 
633
    struct tm   *tm;
 
634
    time_t      now;
 
635
 
 
636
    now = Start;
 
637
    tm = localtime(&now);
 
638
    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
 
639
    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
 
640
    return DSTcorrect(Start, now);
 
641
}
 
642
 
 
643
 
 
644
static time_t
 
645
RelativeMonth(Start, RelMonth)
 
646
    time_t      Start;
 
647
    time_t      RelMonth;
 
648
{
 
649
    struct tm   *tm;
 
650
    time_t      Month;
 
651
    time_t      Year;
 
652
 
 
653
    if (RelMonth == 0)
 
654
        return 0;
 
655
    tm = localtime(&Start);
 
656
    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
 
657
    Year = Month / 12;
 
658
    Month = Month % 12 + 1;
 
659
    return DSTcorrect(Start,
 
660
            Convert(Month, (time_t)tm->tm_mday, Year,
 
661
                (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
 
662
                MER24, DSTmaybe));
 
663
}
 
664
 
 
665
 
 
666
static int
 
667
LookupWord(buff)
 
668
    char                *buff;
 
669
{
 
670
    char                *p;
 
671
    char                *q;
 
672
    const TABLE         *tp;
 
673
    int                 i;
 
674
    int                 abbrev;
 
675
 
 
676
    /* Make it lowercase. */
 
677
    for (p = buff; *p; p++)
 
678
        if (isupper((unsigned char)*p))
 
679
            *p = tolower((unsigned char)*p);
 
680
 
 
681
    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
 
682
        yylval.Meridian = MERam;
 
683
        return tMERIDIAN;
 
684
    }
 
685
    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
 
686
        yylval.Meridian = MERpm;
 
687
        return tMERIDIAN;
 
688
    }
 
689
 
 
690
    /* See if we have an abbreviation for a month. */
 
691
    if (strlen(buff) == 3)
 
692
        abbrev = 1;
 
693
    else if (strlen(buff) == 4 && buff[3] == '.') {
 
694
        abbrev = 1;
 
695
        buff[3] = '\0';
 
696
    }
 
697
    else
 
698
        abbrev = 0;
 
699
 
 
700
    for (tp = MonthDayTable; tp->name; tp++) {
 
701
        if (abbrev) {
 
702
            if (strncmp(buff, tp->name, 3) == 0) {
 
703
                yylval.Number = tp->value;
 
704
                return tp->type;
 
705
            }
 
706
        }
 
707
        else if (strcmp(buff, tp->name) == 0) {
 
708
            yylval.Number = tp->value;
 
709
            return tp->type;
 
710
        }
 
711
    }
 
712
 
 
713
    for (tp = TimezoneTable; tp->name; tp++)
 
714
        if (strcmp(buff, tp->name) == 0) {
 
715
            yylval.Number = tp->value;
 
716
            return tp->type;
 
717
        }
 
718
 
 
719
    if (strcmp(buff, "dst") == 0) 
 
720
        return tDST;
 
721
 
 
722
    for (tp = UnitsTable; tp->name; tp++)
 
723
        if (strcmp(buff, tp->name) == 0) {
 
724
            yylval.Number = tp->value;
 
725
            return tp->type;
 
726
        }
 
727
 
 
728
    /* Strip off any plural and try the units table again. */
 
729
    i = strlen(buff) - 1;
 
730
    if (buff[i] == 's') {
 
731
        buff[i] = '\0';
 
732
        for (tp = UnitsTable; tp->name; tp++)
 
733
            if (strcmp(buff, tp->name) == 0) {
 
734
                yylval.Number = tp->value;
 
735
                return tp->type;
 
736
            }
 
737
        buff[i] = 's';          /* Put back for "this" in OtherTable. */
 
738
    }
 
739
 
 
740
    for (tp = OtherTable; tp->name; tp++)
 
741
        if (strcmp(buff, tp->name) == 0) {
 
742
            yylval.Number = tp->value;
 
743
            return tp->type;
 
744
        }
 
745
 
 
746
    /* Military timezones. */
 
747
    if (buff[1] == '\0' && isalpha((unsigned char)*buff)) {
 
748
        for (tp = MilitaryTable; tp->name; tp++)
 
749
            if (strcmp(buff, tp->name) == 0) {
 
750
                yylval.Number = tp->value;
 
751
                return tp->type;
 
752
            }
 
753
    }
 
754
 
 
755
    /* Drop out any periods and try the timezone table again. */
 
756
    for (i = 0, p = q = buff; *q; q++)
 
757
        if (*q != '.')
 
758
            *p++ = *q;
 
759
        else
 
760
            i++;
 
761
    *p = '\0';
 
762
    if (i)
 
763
        for (tp = TimezoneTable; tp->name; tp++)
 
764
            if (strcmp(buff, tp->name) == 0) {
 
765
                yylval.Number = tp->value;
 
766
                return tp->type;
 
767
            }
 
768
 
 
769
    return tID;
 
770
}
 
771
 
 
772
 
 
773
static int
 
774
yylex()
 
775
{
 
776
    char                c;
 
777
    char                *p;
 
778
    char                buff[20];
 
779
    int                 Count;
 
780
    int                 sign;
 
781
 
 
782
    for ( ; ; ) {
 
783
        while (isspace((unsigned char)*yyInput))
 
784
            yyInput++;
 
785
 
 
786
        if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') {
 
787
            if (c == '-' || c == '+') {
 
788
                sign = c == '-' ? -1 : 1;
 
789
                if (!isdigit((unsigned char)*++yyInput))
 
790
                    /* skip the '-' sign */
 
791
                    continue;
 
792
            }
 
793
            else
 
794
                sign = 0;
 
795
            for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); )
 
796
                yylval.Number = 10 * yylval.Number + c - '0';
 
797
            yyInput--;
 
798
            if (sign < 0)
 
799
                yylval.Number = -yylval.Number;
 
800
            return sign ? tSNUMBER : tUNUMBER;
 
801
        }
 
802
        if (isalpha((unsigned char)c)) {
 
803
            for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; )
 
804
                if (p < &buff[sizeof buff - 1])
 
805
                    *p++ = c;
 
806
            *p = '\0';
 
807
            yyInput--;
 
808
            return LookupWord(buff);
 
809
        }
 
810
        if (c != '(')
 
811
            return *yyInput++;
 
812
        Count = 0;
 
813
        do {
 
814
            c = *yyInput++;
 
815
            if (c == '\0')
 
816
                return c;
 
817
            if (c == '(')
 
818
                Count++;
 
819
            else if (c == ')')
 
820
                Count--;
 
821
        } while (Count > 0);
 
822
    }
 
823
}
 
824
 
 
825
#define TM_YEAR_ORIGIN 1900
 
826
 
 
827
/* Yield A - B, measured in seconds.  */
 
828
static long
 
829
difftm (a, b)
 
830
     struct tm *a, *b;
 
831
{
 
832
  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
 
833
  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
 
834
  int days = (
 
835
              /* difference in day of year */
 
836
              a->tm_yday - b->tm_yday
 
837
              /* + intervening leap days */
 
838
              +  ((ay >> 2) - (by >> 2))
 
839
              -  (ay/100 - by/100)
 
840
              +  ((ay/100 >> 2) - (by/100 >> 2))
 
841
              /* + difference in years * 365 */
 
842
              +  (long)(ay-by) * 365
 
843
              );
 
844
  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
 
845
              + (a->tm_min - b->tm_min))
 
846
          + (a->tm_sec - b->tm_sec));
 
847
}
 
848
 
 
849
time_t
 
850
get_date(p)
 
851
    char                *p;
 
852
{
 
853
    struct tm           *tm, *gmt, gmtbuf;
 
854
    time_t              Start;
 
855
    time_t              tod;
 
856
    time_t              now;
 
857
    time_t              timezone;
 
858
 
 
859
    yyInput = p;
 
860
    (void)time (&now);
 
861
 
 
862
    gmt = gmtime (&now);
 
863
    if (gmt != NULL)
 
864
    {
 
865
        /* Make a copy, in case localtime modifies *tm (I think
 
866
           that comment now applies to *gmt, but I am too
 
867
           lazy to dig into how gmtime and locatime allocate the
 
868
           structures they return pointers to).  */
 
869
        gmtbuf = *gmt;
 
870
        gmt = &gmtbuf;
 
871
    }
 
872
 
 
873
    if (! (tm = localtime (&now)))
 
874
        return -1;
 
875
 
 
876
    if (gmt != NULL)
 
877
        timezone = difftm (gmt, tm) / 60;
 
878
    else
 
879
        /* We are on a system like VMS, where the system clock is
 
880
           in local time and the system has no concept of timezones.
 
881
           Hopefully we can fake this out (for the case in which the
 
882
           user specifies no timezone) by just saying the timezone
 
883
           is zero.  */
 
884
        timezone = 0;
 
885
 
 
886
    if(tm->tm_isdst)
 
887
        timezone += 60;
 
888
 
 
889
    tm = localtime(&now);
 
890
    yyYear = tm->tm_year + 1900;
 
891
    yyMonth = tm->tm_mon + 1;
 
892
    yyDay = tm->tm_mday;
 
893
    yyTimezone = timezone;
 
894
    yyDSTmode = DSTmaybe;
 
895
    yyHour = 0;
 
896
    yyMinutes = 0;
 
897
    yySeconds = 0;
 
898
    yyMeridian = MER24;
 
899
    yyRelSeconds = 0;
 
900
    yyRelMonth = 0;
 
901
    yyHaveDate = 0;
 
902
    yyHaveDay = 0;
 
903
    yyHaveRel = 0;
 
904
    yyHaveTime = 0;
 
905
    yyHaveZone = 0;
 
906
 
 
907
    if (yyparse()
 
908
     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
 
909
        return -1;
 
910
 
 
911
    if (yyHaveDate || yyHaveTime || yyHaveDay) {
 
912
        Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
 
913
                    yyMeridian, yyDSTmode);
 
914
        if (Start < 0)
 
915
            return -1;
 
916
    }
 
917
    else {
 
918
        Start = now;
 
919
        if (!yyHaveRel)
 
920
            Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
 
921
    }
 
922
 
 
923
    Start += yyRelSeconds;
 
924
    Start += RelativeMonth(Start, yyRelMonth);
 
925
 
 
926
    if (yyHaveDay && !yyHaveDate) {
 
927
        tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
 
928
        Start += tod;
 
929
    }
 
930
 
 
931
    /* Have to do *something* with a legitimate -1 so it's distinguishable
 
932
     * from the error return value.  (Alternately could set errno on error.) */
 
933
    return Start == -1 ? 0 : Start;
 
934
}
 
935
 
 
936
 
 
937
#if     defined(TEST)
 
938
 
 
939
/* ARGSUSED */
 
940
int
 
941
main(ac, av)
 
942
    int         ac;
 
943
    char        *av[];
 
944
{
 
945
    char        buff[128];
 
946
    time_t      d;
 
947
 
 
948
    (void)printf("Enter date, or blank line to exit.\n\t> ");
 
949
    (void)fflush(stdout);
 
950
    while (gets(buff) && buff[0]) {
 
951
        d = get_date(buff);
 
952
        if (d == -1)
 
953
            (void)printf("Bad format - couldn't convert.\n");
 
954
        else
 
955
            (void)printf("%s", ctime(&d));
 
956
        (void)printf("\t> ");
 
957
        (void)fflush(stdout);
 
958
    }
 
959
    exit(0);
 
960
    /* NOTREACHED */
 
961
}
 
962
#endif  /* defined(TEST) */