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