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