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