util: allocate log filename buffers
[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 #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 */
28 static 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
54 afs_int32
55 ktimeRelDate_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
70 int
71 Int32To_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
103 int
104 ktimeDate_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
149 afs_int32
150 ParseRelDate(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
243 char *
244 RelDatetoString(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
282 afs_int32
283 Add_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 }