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