]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - usr.sbin/pw/psdate.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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 <ctype.h>
33 #include <err.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <xlocale.h>
37
38 #include "psdate.h"
39
40
41 static int
42 numerics(char const * str)
43 {
44         int             rc = isdigit((unsigned char)*str);
45
46         if (rc)
47                 while (isdigit((unsigned char)*str) || *str == 'x')
48                         ++str;
49         return rc && !*str;
50 }
51
52 static int
53 aindex(char const * arr[], char const ** str, int len)
54 {
55         int             l, i;
56         char            mystr[32];
57
58         mystr[len] = '\0';
59         l = strlen(strncpy(mystr, *str, len));
60         for (i = 0; i < l; i++)
61                 mystr[i] = (char) tolower((unsigned char)mystr[i]);
62         for (i = 0; arr[i] && strcmp(mystr, arr[i]) != 0; i++);
63         if (arr[i] == NULL)
64                 i = -1;
65         else {                  /* Skip past it */
66                 while (**str && isalpha((unsigned char)**str))
67                         ++(*str);
68                 /* And any following whitespace */
69                 while (**str && (**str == ',' || isspace((unsigned char)**str)))
70                         ++(*str);
71         }                       /* Return index */
72         return i;
73 }
74
75 static int
76 weekday(char const ** str)
77 {
78         static char const *days[] =
79         {"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL};
80
81         return aindex(days, str, 3);
82 }
83
84 static void
85 parse_datesub(char const * str, struct tm *t)
86 {
87         struct tm        tm;
88         locale_t         l;
89         int              i;
90         char            *ret;
91         const char      *valid_formats[] = {
92                 "%d-%b-%y",
93                 "%d-%b-%Y",
94                 "%d-%m-%y",
95                 "%d-%m-%Y",
96                 "%H:%M %d-%b-%y",
97                 "%H:%M %d-%b-%Y",
98                 "%H:%M %d-%m-%y",
99                 "%H:%M %d-%m-%Y",
100                 "%H:%M:%S %d-%b-%y",
101                 "%H:%M:%S %d-%b-%Y",
102                 "%H:%M:%S %d-%m-%y",
103                 "%H:%M:%S %d-%m-%Y",
104                 "%d-%b-%y %H:%M",
105                 "%d-%b-%Y %H:%M",
106                 "%d-%m-%y %H:%M",
107                 "%d-%m-%Y %H:%M",
108                 "%d-%b-%y %H:%M:%S",
109                 "%d-%b-%Y %H:%M:%S",
110                 "%d-%m-%y %H:%M:%S",
111                 "%d-%m-%Y %H:%M:%S",
112                 "%H:%M\t%d-%b-%y",
113                 "%H:%M\t%d-%b-%Y",
114                 "%H:%M\t%d-%m-%y",
115                 "%H:%M\t%d-%m-%Y",
116                 "%H:%M\t%S %d-%b-%y",
117                 "%H:%M\t%S %d-%b-%Y",
118                 "%H:%M\t%S %d-%m-%y",
119                 "%H:%M\t%S %d-%m-%Y",
120                 "%d-%b-%y\t%H:%M",
121                 "%d-%b-%Y\t%H:%M",
122                 "%d-%m-%y\t%H:%M",
123                 "%d-%m-%Y\t%H:%M",
124                 "%d-%b-%y\t%H:%M:%S",
125                 "%d-%b-%Y\t%H:%M:%S",
126                 "%d-%m-%y\t%H:%M:%S",
127                 "%d-%m-%Y\t%H:%M:%S",
128                 NULL,
129         };
130
131         l = newlocale(LC_ALL_MASK, "C", NULL);
132
133         memset(&tm, 0, sizeof(tm));
134         for (i=0; valid_formats[i] != NULL; i++) {
135                 ret = strptime_l(str, valid_formats[i], &tm, l);
136                 if (ret && *ret == '\0') {
137                         t->tm_mday = tm.tm_mday;
138                         t->tm_mon = tm.tm_mon;
139                         t->tm_year = tm.tm_year;
140                         t->tm_hour = tm.tm_hour;
141                         t->tm_min = tm.tm_min;
142                         t->tm_sec = tm.tm_sec;
143                         freelocale(l);
144                         return;
145                 }
146         }
147
148         freelocale(l);
149
150         errx(EXIT_FAILURE, "Invalid date");
151 }
152
153
154 /*-
155  * Parse time must be flexible, it handles the following formats:
156  * nnnnnnnnnnn          UNIX timestamp (all numeric), 0 = now
157  * 0xnnnnnnnn           UNIX timestamp in hexadecimal
158  * 0nnnnnnnnn           UNIX timestamp in octal
159  * 0                    Given time
160  * +nnnn[smhdwoy]       Given time + nnnn hours, mins, days, weeks, months or years
161  * -nnnn[smhdwoy]       Given time - nnnn hours, mins, days, weeks, months or years
162  * dd[ ./-]mmm[ ./-]yy  Date }
163  * hh:mm:ss             Time } May be combined
164  */
165
166 time_t
167 parse_date(time_t dt, char const * str)
168 {
169         char           *p;
170         int             i;
171         long            val;
172         struct tm      *T;
173
174         if (dt == 0)
175                 dt = time(NULL);
176
177         while (*str && isspace((unsigned char)*str))
178                 ++str;
179
180         if (numerics(str)) {
181                 dt = strtol(str, &p, 0);
182         } else if (*str == '+' || *str == '-') {
183                 val = strtol(str, &p, 0);
184                 switch (*p) {
185                 case 'h':
186                 case 'H':       /* hours */
187                         dt += (val * 3600L);
188                         break;
189                 case '\0':
190                 case 'm':
191                 case 'M':       /* minutes */
192                         dt += (val * 60L);
193                         break;
194                 case 's':
195                 case 'S':       /* seconds */
196                         dt += val;
197                         break;
198                 case 'd':
199                 case 'D':       /* days */
200                         dt += (val * 86400L);
201                         break;
202                 case 'w':
203                 case 'W':       /* weeks */
204                         dt += (val * 604800L);
205                         break;
206                 case 'o':
207                 case 'O':       /* months */
208                         T = localtime(&dt);
209                         T->tm_mon += (int) val;
210                         i = T->tm_mday;
211                         goto fixday;
212                 case 'y':
213                 case 'Y':       /* years */
214                         T = localtime(&dt);
215                         T->tm_year += (int) val;
216                         i = T->tm_mday;
217         fixday:
218                         dt = mktime(T);
219                         T = localtime(&dt);
220                         if (T->tm_mday != i) {
221                                 T->tm_mday = 1;
222                                 dt = mktime(T);
223                                 dt -= (time_t) 86400L;
224                         }
225                 default:        /* unknown */
226                         break;  /* leave untouched */
227                 }
228         } else {
229                 char           *q, tmp[64];
230
231                 /*
232                  * Skip past any weekday prefix
233                  */
234                 weekday(&str);
235                 strlcpy(tmp, str, sizeof(tmp));
236                 str = tmp;
237                 T = localtime(&dt);
238
239                 /*
240                  * See if we can break off any timezone
241                  */
242                 while ((q = strrchr(tmp, ' ')) != NULL) {
243                         if (strchr("(+-", q[1]) != NULL)
244                                 *q = '\0';
245                         else {
246                                 int             j = 1;
247
248                                 while (q[j] && isupper((unsigned char)q[j]))
249                                         ++j;
250                                 if (q[j] == '\0')
251                                         *q = '\0';
252                                 else
253                                         break;
254                         }
255                 }
256
257                 parse_datesub(tmp, T);
258                 dt = mktime(T);
259         }
260         return dt;
261 }