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