GCC 4.1 compiler warning fixes.
[silc.git] / lib / silcutil / silctime.c
1 /*
2
3   silctime.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2003 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21
22 /* Fills the SilcTime structure with correct values */
23
24 static SilcBool silc_time_fill(SilcTime time,
25                                unsigned int year,
26                                unsigned int month,
27                                unsigned int day,
28                                unsigned int hour,
29                                unsigned int minute,
30                                unsigned int second,
31                                unsigned int msec)
32 {
33   if (year > (1 << 15))
34     return FALSE;
35   if (month < 1 || month > 12)
36     return FALSE;
37   if (day < 1 || day > 31)
38     return FALSE;
39   if (hour > 23)
40     return FALSE;
41   if (minute > 60)
42     return FALSE;
43   if (second > 61)
44     return FALSE;
45   if (msec > 1000)
46     return FALSE;
47
48   time->year = year;
49   time->month = month;
50   time->day = day;
51   time->hour = hour;
52   time->minute = minute;
53   time->second = second;
54   time->msecond = msec;
55
56   return TRUE;
57 }
58
59 /* Return time since Epoch */
60
61 SilcInt64 silc_time(void)
62 {
63   return (SilcInt64)time(NULL);
64 }
65
66 /* Return time since Epoch in milliseconds */
67
68 SilcInt64 silc_time_msec(void)
69 {
70   struct timeval curtime;
71   silc_gettimeofday(&curtime);
72   return (curtime.tv_sec * 1000) + (curtime.tv_usec / 1000);
73 }
74
75 /* Return time since Epoch in microseconds */
76
77 SilcInt64 silc_time_usec(void)
78 {
79   struct timeval curtime;
80   silc_gettimeofday(&curtime);
81   return (curtime.tv_sec * 1000000) + curtime.tv_usec;
82 }
83
84 /* Returns time as string */
85
86 const char *silc_time_string(SilcInt64 time_val)
87 {
88   time_t curtime;
89   char *return_time;
90
91   if (!time_val)
92     curtime = silc_time();
93   else
94     curtime = (time_t)time_val;
95   return_time = ctime(&curtime);
96   if (!return_time)
97     return NULL;
98   return_time[strlen(return_time) - 1] = '\0';
99
100   return (const char *)return_time;
101 }
102
103 /* Returns time as SilcTime structure */
104
105 SilcBool silc_time_value(SilcInt64 time_val, SilcTime ret_time)
106 {
107   struct tm *time;
108   unsigned int msec = 0;
109   time_t timeval;
110
111   if (!ret_time)
112     return TRUE;
113
114   if (!time_val)
115     time_val = silc_time_msec();
116
117   msec = time_val % 1000;
118   time_val /= 1000;
119
120   time = localtime(&timeval);
121   if (!time)
122     return FALSE;
123   time_val = timeval;
124
125   memset(ret_time, 0, sizeof(*ret_time));
126   if (!silc_time_fill(ret_time, time->tm_year + 1900, time->tm_mon + 1,
127                       time->tm_mday, time->tm_hour, time->tm_min,
128                       time->tm_sec, msec))
129     return FALSE;
130
131   ret_time->dst        = time->tm_isdst ? 1 : 0;
132 #ifdef SILC_WIN32
133   ret_time->utc_east   = _timezone < 0 ? 1 : 0;
134   ret_time->utc_hour   = (ret_time->utc_east ? (-(_timezone)) / 3600 :
135                           _timezone / 3600);
136   ret_time->utc_minute = (ret_time->utc_east ? (-(_timezone)) % 3600 :
137                           _timezone % 3600);
138 #else
139 #if defined(HAVE_TZSET)
140   ret_time->utc_east   = timezone < 0 ? 1 : 0;
141   ret_time->utc_hour   = (ret_time->utc_east ? (-(timezone)) / 3600 :
142                           timezone / 3600);
143   ret_time->utc_minute = (ret_time->utc_east ? (-(timezone)) % 3600 :
144                           timezone % 3600);
145 #endif /* HAVE_TZSET */
146 #endif /* SILC_WIN32 */
147
148   return TRUE;
149 }
150
151 /* Returns time from universal time string into SilcTime */
152
153 SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time)
154 {
155   int ret;
156   unsigned int year, month, day, hour = 0, minute = 0, second = 0;
157   unsigned char z = 0;
158
159   if (!ret_time)
160     return TRUE;
161   memset(ret_time, 0, sizeof(*ret_time));
162
163   /* Parse the time string */
164   ret = sscanf(universal_time, "%02u%02u%02u%02u%02u%02u%c", &year, &month,
165                &day, &hour, &minute, &second, &z);
166   if (ret < 3) {
167     SILC_LOG_DEBUG(("Invalid UTC time string"));
168     return FALSE;
169   }
170
171   /* Fill the SilcTime structure */
172   ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
173   if (!ret) {
174     SILC_LOG_DEBUG(("Incorrect values in UTC time string"));
175     return FALSE;
176   }
177
178   /* Check timezone */
179   if (z == '-' || z == '+') {
180     ret = sscanf(universal_time + (ret * 2) + 1, "%02u%02u", &hour, &minute);
181     if (ret != 2) {
182       SILC_LOG_DEBUG(("Malformed UTC time string"));
183       return FALSE;
184     }
185
186     if (hour < 0 || hour > 23)
187       return FALSE;
188     if (minute < 0 || minute > 60)
189       return FALSE;
190
191     ret_time->utc_hour   = hour;
192     ret_time->utc_minute = minute;
193     ret_time->utc_east   = (z == '-') ? 0 : 1;
194   } else if (z != 'Z') {
195     SILC_LOG_DEBUG(("Invalid timezone"));
196     return FALSE;
197   }
198
199   /* UTC year must be fixed since it's represented only as YY not YYYY. */
200   ret_time->year += 1900;
201   if (ret_time->year < 1950)
202     ret_time->year += 100;
203
204   return TRUE;
205 }
206
207 /* Encode universal time string. */
208
209 SilcBool silc_time_universal_string(SilcTime time_val, char *ret_string,
210                                     SilcUInt32 ret_string_size)
211 {
212   int ret, len = 0;
213   memset(ret_string, 0, ret_string_size);
214   ret = silc_snprintf(ret_string, ret_string_size - 1,
215                  "%02u%02u%02u%02u%02u%02u",
216                  time_val->year % 100, time_val->month, time_val->day,
217                  time_val->hour, time_val->minute, time_val->second);
218   if (ret < 0)
219     return FALSE;
220   len += ret;
221
222   if (!time_val->utc_hour && !time_val->utc_minute) {
223     ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
224     if (ret < 0)
225       return FALSE;
226     len += ret;
227   } else {
228     ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
229                    "%c%02u%02u", time_val->utc_east ? '+' : '-',
230                    time_val->utc_hour, time_val->utc_minute);
231     if (ret < 0)
232       return FALSE;
233     len += ret;
234   }
235
236   return TRUE;
237 }
238
239 /* Returns time from generalized time string into SilcTime */
240
241 SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time)
242 {
243   int ret, i;
244   unsigned int year, month, day, hour = 0, minute = 0, second = 0;
245   unsigned int msecond = 0;
246   unsigned char z = 0;
247
248   if (!ret_time)
249     return TRUE;
250   memset(ret_time, 0, sizeof(*ret_time));
251
252   /* Parse the time string */
253   ret = sscanf(generalized_time, "%04u%02u%02u%02u%02u%02u", &year, &month,
254                &day, &hour, &minute, &second);
255   if (ret < 3) {
256     SILC_LOG_DEBUG(("Invalid generalized time string"));
257     return FALSE;
258   }
259
260   /* Fill the SilcTime structure */
261   ret = silc_time_fill(ret_time, year, month, day, hour, minute, second, 0);
262   if (!ret) {
263     SILC_LOG_DEBUG(("Incorrect values in generalized time string"));
264     return FALSE;
265   }
266
267   /* Check fractions of second and/or timezone */
268   i = ret * 4;
269   ret = sscanf(generalized_time + i, "%c", &z);
270   if (ret != 1) {
271     SILC_LOG_DEBUG(("Malformed generalized time string"));
272     return FALSE;
273   }
274
275   if (z == '.') {
276     /* Take fractions of second */
277     int l;
278     i++;
279     ret = sscanf(generalized_time + i, "%u%n", &msecond, &l);
280     if (ret != 1) {
281       SILC_LOG_DEBUG(("Malformed generalized time string"));
282       return FALSE;
283     }
284     while (l > 4) {
285       msecond /= 10;
286       l--;
287     }
288     ret_time->msecond = msecond;
289     i += l;
290
291     /* Read optional timezone */
292     if (strlen(generalized_time) < i)
293       sscanf(generalized_time + i, "%c", &z);
294   }
295
296   /* Check timezone if present */
297   if (z == '-' || z == '+') {
298     ret = sscanf(generalized_time + i + 1, "%02u%02u", &hour, &minute);
299     if (ret != 2) {
300       SILC_LOG_DEBUG(("Malformed UTC time string"));
301       return FALSE;
302     }
303
304     if (hour < 0 || hour > 23)
305       return FALSE;
306     if (minute < 0 || minute > 60)
307       return FALSE;
308
309     ret_time->utc_hour   = hour;
310     ret_time->utc_minute = minute;
311     ret_time->utc_east   = (z == '-') ? 0 : 1;
312   }
313
314   return TRUE;
315 }
316
317 /* Encode generalized time string */
318
319 SilcBool silc_time_generalized_string(SilcTime time_val, char *ret_string,
320                                       SilcUInt32 ret_string_size)
321 {
322   int len = 0, ret;
323   memset(ret_string, 0, ret_string_size);
324   ret = silc_snprintf(ret_string, ret_string_size - 1,
325                  "%04u%02u%02u%02u%02u%02u",
326                  time_val->year, time_val->month, time_val->day, time_val->hour,
327                  time_val->minute, time_val->second);
328   if (ret < 0)
329     return FALSE;
330   len += ret;
331
332   if (time_val->msecond) {
333     ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
334                    ".%lu", (unsigned long)time_val->msecond);
335     if (ret < 0)
336       return FALSE;
337     len += ret;
338   }
339
340   if (!time_val->utc_hour && !time_val->utc_minute) {
341     ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len, "Z");
342     if (ret < 0)
343       return FALSE;
344     len += ret;
345   } else {
346     ret = silc_snprintf(ret_string + len, ret_string_size - 1 - len,
347                    "%c%02u%02u", time_val->utc_east ? '+' : '-',
348                    time_val->utc_hour, time_val->utc_minute);
349     if (ret < 0)
350       return FALSE;
351     len += ret;
352   }
353
354   return TRUE;
355 }
356
357 /* Return TRUE if `smaller' is smaller than `bigger'. */
358
359 SilcBool silc_compare_timeval(struct timeval *smaller,
360                               struct timeval *bigger)
361 {
362   if ((smaller->tv_sec < bigger->tv_sec) ||
363       ((smaller->tv_sec == bigger->tv_sec) &&
364        (smaller->tv_usec < bigger->tv_usec)))
365     return TRUE;
366
367   return FALSE;
368 }