GNU shell utilities
[gnulib.git] / lib / posixtm.y
1 /* Parse dates for touch.
2    Copyright (C) 1989, 1990, 1991 Free Software Foundation Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /* Written by Jim Kingdon and David MacKenzie. */
19 %{
20 #ifdef __GNUC__
21 #define alloca __builtin_alloca
22 #else
23 #ifdef HAVE_ALLOCA_H
24 #include <alloca.h>
25 #else
26 #ifdef _AIX
27  #pragma alloca
28 #else
29 void *alloca ();
30 #endif
31 #endif
32 #endif
33
34 #ifdef HAVE_CONFIG_H
35 #if defined (CONFIG_BROKETS)
36 /* We use <config.h> instead of "config.h" so that a compilation
37    using -I. -I will use ./config.h rather than /config.h
38    (which it would do because it found this file in ).  */
39 #include <config.h>
40 #else
41 #include "config.h"
42 #endif
43 #endif
44
45 #include <stdio.h>
46 #include <sys/types.h>
47
48 #ifdef TM_IN_SYS_TIME
49 #include <sys/time.h>
50 #else
51 #include <time.h>
52 #endif
53
54 /* Some old versions of bison generate parsers that use bcopy.
55    That loses on systems that don't provide the function, so we have
56    to redefine it here.  */
57 #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
58 #define bcopy(from, to, len) memcpy ((to), (from), (len))
59 #endif
60
61 #define YYDEBUG 1
62
63 /* Lexical analyzer's current scan position in the input string. */
64 static char *curpos;
65
66 /* The return value. */
67 static struct tm t;
68
69 time_t mktime ();
70
71 #define yyparse posixtime_yyparse
72 static int yylex ();
73 static int yyerror ();
74 %}
75
76 %token DIGIT
77
78 %%
79 date :
80        digitpair /* month */
81        digitpair /* day */
82        digitpair /* hours */
83        digitpair /* minutes */
84        year
85        seconds {
86                  if ($1 >= 1 && $1 <= 12)
87                    t.tm_mon = $1 - 1;
88                  else {
89                    YYABORT;
90                  }
91                  if ($2 >= 1 && $2 <= 31)
92                    t.tm_mday = $2;
93                  else {
94                    YYABORT;
95                  }
96                  if ($3 >= 0 && $3 <= 23)
97                    t.tm_hour = $3;
98                  else {
99                    YYABORT;
100                  }
101                  if ($4 >= 0 && $4 <= 59)
102                    t.tm_min = $4;
103                  else {
104                    YYABORT;
105                  }
106                }
107
108 year : digitpair {
109                    t.tm_year = $1;
110                    /* Deduce the century based on the year.
111                       See POSIX.2 section 4.63.3.  */
112                    if ($1 <= 68)
113                      t.tm_year += 100;
114                  }
115     | digitpair digitpair {
116                             t.tm_year = $1 * 100 + $2;
117                             if (t.tm_year < 1900) {
118                               YYABORT;
119                             } else
120                               t.tm_year -= 1900;
121                           }
122     | /* empty */ {
123                     time_t now;
124                     struct tm *tmp;
125
126                     /* Use current year.  */
127                     time (&now);
128                     tmp = localtime (&now);
129                     t.tm_year = tmp->tm_year;
130                   }
131     ;
132
133 seconds : /* empty */ {
134                         t.tm_sec = 0;
135                       }
136         | '.' digitpair {
137                           if ($2 >= 0 && $2 <= 61)
138                             t.tm_sec = $2;
139                           else {
140                             YYABORT;
141                           }
142                         }
143         ;
144
145 digitpair : DIGIT DIGIT {
146                           $$ = $1 * 10 + $2;
147                         }
148           ;
149 %%
150 static int
151 yylex ()
152 {
153   char ch = *curpos++;
154
155   if (ch >= '0' && ch <= '9')
156     {
157       yylval = ch - '0';
158       return DIGIT;
159     }
160   else if (ch == '.' || ch == 0)
161     return ch;
162   else
163     return '?';                 /* Cause an error.  */
164 }
165
166 static int
167 yyerror ()
168 {
169   return 0;
170 }
171
172 /* Parse a POSIX-style date and return it, or (time_t)-1 for an error.  */
173
174 time_t
175 posixtime (s)
176      char *s;
177 {
178   curpos = s;
179   /* Let mktime decide whether it is daylight savings time.  */
180   t.tm_isdst = -1;
181   if (yyparse ())
182     return (time_t)-1;
183   else
184     return mktime (&t);
185 }
186
187 /* Parse a POSIX-style date and return it, or NULL for an error.  */
188
189 struct tm *
190 posixtm (s)
191      char *s;
192 {
193   if (posixtime (s) == -1)
194     return NULL;
195   return &t;
196 }