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