]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/pw/psdate.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / pw / psdate.c
1 /*-
2  * Copyright (C) 1996
3  *      David L. Nugent.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #ifndef lint
28 static const char rcsid[] =
29   "$FreeBSD$";
30 #endif /* not lint */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "psdate.h"
38
39
40 static int
41 a2i(char const ** str)
42 {
43         int             i = 0;
44         char const     *s = *str;
45
46         if (isdigit((unsigned char)*s)) {
47                 i = atoi(s);
48                 while (isdigit((unsigned char)*s))
49                         ++s;
50                 *str = s;
51         }
52         return i;
53 }
54
55 static int
56 numerics(char const * str)
57 {
58         int             rc = isdigit((unsigned char)*str);
59
60         if (rc)
61                 while (isdigit((unsigned char)*str) || *str == 'x')
62                         ++str;
63         return rc && !*str;
64 }
65
66 static int
67 aindex(char const * arr[], char const ** str, int len)
68 {
69         int             l, i;
70         char            mystr[32];
71
72         mystr[len] = '\0';
73         l = strlen(strncpy(mystr, *str, len));
74         for (i = 0; i < l; i++)
75                 mystr[i] = (char) tolower((unsigned char)mystr[i]);
76         for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++);
77         if (arr[i] == NULL)
78                 i = -1;
79         else {                  /* Skip past it */
80                 while (**str && isalpha((unsigned char)**str))
81                         ++(*str);
82                 /* And any following whitespace */
83                 while (**str && (**str == ',' || isspace((unsigned char)**str)))
84                         ++(*str);
85         }                       /* Return index */
86         return i;
87 }
88
89 static int
90 weekday(char const ** str)
91 {
92         static char const *days[] =
93         {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL};
94
95         return aindex(days, str, 3);
96 }
97
98 static int
99 month(char const ** str)
100 {
101         static char const *months[] =
102         {"jan", "feb", "mar", "apr", "may", "jun", "jul",
103         "aug", "sep", "oct", "nov", "dec", NULL};
104
105         return aindex(months, str, 3);
106 }
107
108 static void
109 parse_time(char const * str, int *hour, int *min, int *sec)
110 {
111         *hour = a2i(&str);
112         if ((str = strchr(str, ':')) == NULL)
113                 *min = *sec = 0;
114         else {
115                 ++str;
116                 *min = a2i(&str);
117                 *sec = ((str = strchr(str, ':')) == NULL) ? 0 : atoi(++str);
118         }
119 }
120
121
122 static void
123 parse_datesub(char const * str, int *day, int *mon, int *year)
124 {
125         int             i;
126
127         static char const nchrs[] = "0123456789 \t,/-.";
128
129         if ((i = month(&str)) != -1) {
130                 *mon = i;
131                 if ((i = a2i(&str)) != 0)
132                         *day = i;
133         } else if ((i = a2i(&str)) != 0) {
134                 *day = i;
135                 while (*str && strchr(nchrs + 10, *str) != NULL)
136                         ++str;
137                 if ((i = month(&str)) != -1)
138                         *mon = i;
139                 else if ((i = a2i(&str)) != 0)
140                         *mon = i - 1;
141         } else
142                 return;
143
144         while (*str && strchr(nchrs + 10, *str) != NULL)
145                 ++str;
146         if (isdigit((unsigned char)*str)) {
147                 *year = atoi(str);
148                 if (*year > 1900)
149                         *year -= 1900;
150                 else if (*year < 32)
151                         *year += 100;
152         }
153 }
154
155
156 /*-
157  * Parse time must be flexible, it handles the following formats:
158  * nnnnnnnnnnn          UNIX timestamp (all numeric), 0 = now
159  * 0xnnnnnnnn           UNIX timestamp in hexadecimal
160  * 0nnnnnnnnn           UNIX timestamp in octal
161  * 0                    Given time
162  * +nnnn[smhdwoy]       Given time + nnnn hours, mins, days, weeks, months or years
163  * -nnnn[smhdwoy]       Given time - nnnn hours, mins, days, weeks, months or years
164  * dd[ ./-]mmm[ ./-]yy  Date }
165  * hh:mm:ss             Time } May be combined
166  */
167
168 time_t
169 parse_date(time_t dt, char const * str)
170 {
171         char           *p;
172         int             i;
173         long            val;
174         struct tm      *T;
175
176         if (dt == 0)
177                 dt = time(NULL);
178
179         while (*str && isspace((unsigned char)*str))
180                 ++str;
181
182         if (numerics(str)) {
183                 dt = strtol(str, &p, 0);
184         } else if (*str == '+' || *str == '-') {
185                 val = strtol(str, &p, 0);
186                 switch (*p) {
187                 case 'h':
188                 case 'H':       /* hours */
189                         dt += (val * 3600L);
190                         break;
191                 case '\0':
192                 case 'm':
193                 case 'M':       /* minutes */
194                         dt += (val * 60L);
195                         break;
196                 case 's':
197                 case 'S':       /* seconds */
198                         dt += val;
199                         break;
200                 case 'd':
201                 case 'D':       /* days */
202                         dt += (val * 86400L);
203                         break;
204                 case 'w':
205                 case 'W':       /* weeks */
206                         dt += (val * 604800L);
207                         break;
208                 case 'o':
209                 case 'O':       /* months */
210                         T = localtime(&dt);
211                         T->tm_mon += (int) val;
212                         i = T->tm_mday;
213                         goto fixday;
214                 case 'y':
215                 case 'Y':       /* years */
216                         T = localtime(&dt);
217                         T->tm_year += (int) val;
218                         i = T->tm_mday;
219         fixday:
220                         dt = mktime(T);
221                         T = localtime(&dt);
222                         if (T->tm_mday != i) {
223                                 T->tm_mday = 1;
224                                 dt = mktime(T);
225                                 dt -= (time_t) 86400L;
226                         }
227                 default:        /* unknown */
228                         break;  /* leave untouched */
229                 }
230         } else {
231                 char           *q, tmp[64];
232
233                 /*
234                  * Skip past any weekday prefix
235                  */
236                 weekday(&str);
237                 strlcpy(tmp, str, sizeof(tmp));
238                 str = tmp;
239                 T = localtime(&dt);
240
241                 /*
242                  * See if we can break off any timezone
243                  */
244                 while ((q = strrchr(tmp, ' ')) != NULL) {
245                         if (strchr("(+-", q[1]) != NULL)
246                                 *q = '\0';
247                         else {
248                                 int             j = 1;
249
250                                 while (q[j] && isupper((unsigned char)q[j]))
251                                         ++j;
252                                 if (q[j] == '\0')
253                                         *q = '\0';
254                                 else
255                                         break;
256                         }
257                 }
258
259                 /*
260                  * See if there is a time hh:mm[:ss]
261                  */
262                 if ((p = strchr(tmp, ':')) == NULL) {
263
264                         /*
265                          * No time string involved
266                          */
267                         T->tm_hour = T->tm_min = T->tm_sec = 0;
268                         parse_datesub(tmp, &T->tm_mday, &T->tm_mon, &T->tm_year);
269                 } else {
270                         char            datestr[64], timestr[64];
271
272                         /*
273                          * Let's chip off the time string
274                          */
275                         if ((q = strpbrk(p, " \t")) != NULL) {  /* Time first? */
276                                 int             l = q - str;
277
278                                 strlcpy(timestr, str, l + 1);
279                                 strlcpy(datestr, q + 1, sizeof(datestr));
280                                 parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec);
281                                 parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year);
282                         } else if ((q = strrchr(tmp, ' ')) != NULL) {   /* Time last */
283                                 int             l = q - tmp;
284
285                                 strlcpy(timestr, q + 1, sizeof(timestr));
286                                 strlcpy(datestr, tmp, l + 1);
287                         } else  /* Bail out */
288                                 return dt;
289                         parse_time(timestr, &T->tm_hour, &T->tm_min, &T->tm_sec);
290                         parse_datesub(datestr, &T->tm_mday, &T->tm_mon, &T->tm_year);
291                 }
292                 dt = mktime(T);
293         }
294         return dt;
295 }