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