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