backport to buster
[hcoop/debian/openafs.git] / src / util / kreltime.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10#include <afsconfig.h>
11#include <afs/param.h>
12#include <afs/stds.h>
13
14#include <roken.h>
15
16#include <ctype.h>
17
18#include "ktime.h"
19#include "afsutil.h"
20
21/* maximum values for relative dates */
22
23#define MAX_YEAR_VALUE 0
24#define MAX_MONTH_VALUE 11
25#define MAX_DAY_VALUE 30
26
27/* for parsing relative expiration dates */
28static struct parseseqS {
29 afs_int32 ps_field;
30 char ps_keychar;
31 afs_int32 ps_maxValue;
32} parseseq[] = {
33 {
34 KTIMEDATE_YEAR, 'y', MAX_YEAR_VALUE,}, /* no max. value */
35 {
36 KTIMEDATE_MONTH, 'm', MAX_MONTH_VALUE,}, /* months max. 12 */
37 {
38 KTIMEDATE_DAY, 'd', MAX_DAY_VALUE,}, /* days max. 31 */
39 {
40 0, 0, 0,}
41};
42
43/* Encodings to and from relative dates. The caller is responsible for
44 * enforcing appropriate use of these routines
45 */
46
47
48/* ktimeRelDate_ToInt32
49 * converts a relative ktime date into an afs_int32.
50 * exit:
51 * afs_int32 value of encoded date.
52 */
53
54afs_int32
55ktimeRelDate_ToInt32(struct ktime_date *kdptr)
56{
57 afs_int32 retval;
58
59 retval =
60 (((kdptr->year * (MAX_MONTH_VALUE + 1)) +
61 kdptr->month) * (MAX_DAY_VALUE + 1)) + kdptr->day;
62 return (retval);
63}
64
65/* Int32To_ktimeRelDate
66 * Convert a relative date encoded in an afs_int32 - back into a ktime_date
67 * structure
68 */
69
70int
71Int32To_ktimeRelDate(afs_int32 int32Date, struct ktime_date *kdptr)
72{
73 memset(kdptr, 0, sizeof(*kdptr));
74
75 kdptr->day = int32Date % (MAX_DAY_VALUE + 1);
76 if (kdptr->day != 0)
77 kdptr->mask |= KTIMEDATE_DAY;
78
79 int32Date = int32Date / (MAX_DAY_VALUE + 1);
80
81 kdptr->month = int32Date % (MAX_MONTH_VALUE + 1);
82 if (kdptr->month != 0)
83 kdptr->mask |= KTIMEDATE_MONTH;
84
85 int32Date = int32Date / (MAX_MONTH_VALUE + 1);
86
87 kdptr->year = int32Date;
88 if (kdptr->year != 0)
89 kdptr->mask |= KTIMEDATE_YEAR;
90
91 return (0);
92}
93
94/* ktimeDate_FromInt32
95 * Converts a time in seconds, to a time (in ktime_date format).
96 * Result is a conventional ktime_date structure.
97 * placed in the supplied structure
98 * entry:
99 * timeSecs - time in seconds
100 * ktimePtr - ptr to struct for the return value
101 */
102
103int
104ktimeDate_FromInt32(afs_int32 timeSecs, struct ktime_date *ktimePtr)
105{
106 time_t tt = timeSecs;
107 struct tm *timePtr;
108#ifndef AFS_NT40_ENV
109 struct tm timeP;
110
111 timePtr = &timeP;
112
113 memset(&timeP, 0, sizeof(timeP));
114 localtime_r(&tt, &timeP);
115#else
116 timePtr = localtime(&tt);
117#endif
118
119 /* copy the relevant fields */
120 ktimePtr->sec = timePtr->tm_sec;
121 ktimePtr->min = timePtr->tm_min;
122 ktimePtr->hour = timePtr->tm_hour;
123 ktimePtr->day = timePtr->tm_mday;
124 ktimePtr->month = timePtr->tm_mon + 1;
125 ktimePtr->year = timePtr->tm_year;
126
127 ktimePtr->mask =
128 KTIMEDATE_YEAR | KTIMEDATE_MONTH | KTIMEDATE_DAY | KTIMEDATE_HOUR |
129 KTIMEDATE_MIN | KTIMEDATE_SEC;
130
131 return (0);
132}
133
134#define RD_DIGIT_LIMIT 4 /* max. no. digits permitted */
135
136/* ParseRelDate
137 * Parses a relative date of the form <n>y<n>m<n>d representing years
138 * months and days. <n> is limited to RD_DIGIT_LIMIT digits in length
139 * and is further restricted by the maximums specified at the head
140 * of the file.
141 * entry:
142 * dateStr - ptr to string to parse. Leading white space ingnored.
143 * exit:
144 * returns a ptr to a static ktime_date structure containing
145 * appropriately set fields. The mask field is unused.
146 * 0 - error in date specification
147 */
148
149afs_int32
150ParseRelDate(char *dateStr, struct ktime_date * relDatePtr)
151{
152 struct parseseqS *psPtr;
153 afs_int32 value, digit_limit;
154 afs_int32 type_index;
155
156 memset(relDatePtr, 0, sizeof(*relDatePtr));
157 type_index = 0;
158
159 while (1) { /*w */
160
161 while (isspace(*dateStr)) /* skip leading whitespace */
162 dateStr++;
163
164 if (isdigit(*dateStr) == 0)
165 goto error;
166
167 digit_limit = RD_DIGIT_LIMIT;
168 value = 0;
169 while (isdigit(*dateStr)) {
170 value = value * 10 + *dateStr - '0';
171 dateStr++;
172 if (digit_limit-- == 0)
173 goto error;
174 }
175
176 psPtr = &parseseq[type_index];
177 /* determine the units. Search for a matching type character */
178 while ((psPtr->ps_keychar != *dateStr)
179 && (psPtr->ps_keychar != 0)
180 ) {
181 type_index++;
182 psPtr = &parseseq[type_index];
183 }
184
185 /* no matching type found */
186 if (psPtr->ps_keychar == 0)
187 goto error;
188
189 /* check the bounds on the maximum value. Can't be negative
190 * and if a maximum value is specified, check against it
191 */
192 if ((value < 0)
193 || ((psPtr->ps_maxValue > 0) && (value > psPtr->ps_maxValue))
194 )
195 goto error;
196
197 /* save computed value in the relevant type field */
198 switch (psPtr->ps_field) {
199 case KTIMEDATE_YEAR:
200 relDatePtr->year = value;
201 relDatePtr->mask |= KTIMEDATE_YEAR;
202 break;
203
204 case KTIMEDATE_MONTH:
205 if (value > MAX_MONTH_VALUE)
206 goto error;
207 relDatePtr->month = value;
208 relDatePtr->mask |= KTIMEDATE_MONTH;
209 break;
210
211 case KTIMEDATE_DAY:
212 if (value > MAX_DAY_VALUE)
213 goto error;
214
215 relDatePtr->mask |= KTIMEDATE_DAY;
216 relDatePtr->day = value;
217 break;
218
219 default:
220 goto error;
221 }
222 dateStr++; /* next digit */
223
224 if (*dateStr == 0) {
225 /* no more chars to process, return the result */
226 return (0);
227 }
228 } /*w */
229
230 error:
231 return (1);
232}
233
234/* RelDatetoString
235 * returns a static string representing the relative date. This is in
236 * a format acceptable to the relative date parser.
237 * entry:
238 * datePtr - relative date to be converted.
239 * exit:
240 * ptr to static string
241 */
242
243char *
244RelDatetoString(struct ktime_date *datePtr)
245{
246 static char dateString[64];
247 char tempstring[64], *sptr;
248
249 dateString[0] = 0;
250 sptr = &dateString[0];
251
252 if (datePtr->mask & KTIMEDATE_YEAR) {
253 sprintf(tempstring, "%-dy", datePtr->year);
254 strcat(sptr, tempstring);
255 }
256
257 if (datePtr->mask & KTIMEDATE_MONTH) {
258 strcat(sptr, " ");
259 sprintf(tempstring, "%-dm", datePtr->month);
260 strcat(sptr, tempstring);
261 }
262
263 if (datePtr->mask & KTIMEDATE_DAY) {
264 strcat(sptr, " ");
265 sprintf(tempstring, "%-dd", datePtr->day);
266 strcat(sptr, tempstring);
267 }
268 return (sptr);
269}
270
271/* Add_RelDate_to_Time
272 * Returns current time with a relative time added. Note that the
273 * computation adds in most significant fields first, i.e. year, month
274 * day etc. Addition of least significant fields would produce different
275 * results (depending on the data).
276 * entry:
277 * relDatePtr - a ktime_date containing a relative time specification
278 * exit:
279 * returns specified time with relative time added.
280 */
281
282afs_int32
283Add_RelDate_to_Time(struct ktime_date * relDatePtr, afs_int32 atime)
284{
285 afs_int32 moreYears;
286 static struct ktime_date absDate;
287
288 ktimeDate_FromInt32(atime, &absDate); /* convert to ktime */
289
290 /* add in years */
291 if (relDatePtr->mask & KTIMEDATE_YEAR)
292 absDate.year += relDatePtr->year;
293
294 /* add in months */
295 if (relDatePtr->mask & KTIMEDATE_MONTH)
296 absDate.month += relDatePtr->month;
297
298 if (absDate.month > 12) {
299 moreYears = absDate.month / 12;
300 absDate.month = absDate.month % 12;
301 absDate.year += moreYears;
302 }
303
304 /* day computations depend upon month size, so do these in seconds */
305 atime = ktime_InterpretDate(&absDate);
306
307 if (relDatePtr->mask & KTIMEDATE_DAY)
308 atime = atime + relDatePtr->day * 24 * 60 * 60;
309
310 if (relDatePtr->mask & KTIMEDATE_HOUR)
311 atime = atime + relDatePtr->hour * 60 * 60;
312
313 if (relDatePtr->mask & KTIMEDATE_MIN)
314 atime = atime + relDatePtr->min * 60;
315
316 if (relDatePtr->mask & KTIMEDATE_SEC)
317 atime = atime + relDatePtr->sec;
318
319 return (atime);
320}