Move some code (including the optional objects) into libwsutil
[metze/wireshark/wip.git] / epan / ftypes / ftype-time.c
1 /*
2  * $Id$
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 2001 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
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  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30
31 /*
32  * Just make sure we include the prototype for strptime as well
33  * (needed for glibc 2.2) but make sure we do this only if not
34  * yet defined.
35  */
36 #ifndef __USE_XOPEN
37 #  define __USE_XOPEN
38 #endif
39
40 #include <time.h>
41
42 #include <ftypes-int.h>
43
44 #ifdef NEED_STRPTIME_H
45 #include "wsutil/strptime.h"
46 #endif
47
48 static gboolean
49 cmp_eq(fvalue_t *a, fvalue_t *b)
50 {
51         return ((a->value.time.secs) ==(b->value.time.secs))
52              &&((a->value.time.nsecs)==(b->value.time.nsecs));
53 }
54 static gboolean
55 cmp_ne(fvalue_t *a, fvalue_t *b)
56 {
57         return (a->value.time.secs !=b->value.time.secs)
58              ||(a->value.time.nsecs!=b->value.time.nsecs);
59 }
60 static gboolean
61 cmp_gt(fvalue_t *a, fvalue_t *b)
62 {
63         if (a->value.time.secs > b->value.time.secs) {
64                 return TRUE;
65         }
66         if (a->value.time.secs < b->value.time.secs) {
67                 return FALSE;
68         }
69
70         return a->value.time.nsecs > b->value.time.nsecs;
71 }
72 static gboolean
73 cmp_ge(fvalue_t *a, fvalue_t *b)
74 {
75         if (a->value.time.secs > b->value.time.secs) {
76                 return TRUE;
77         }
78         if (a->value.time.secs < b->value.time.secs) {
79                 return FALSE;
80         }
81
82         return a->value.time.nsecs >= b->value.time.nsecs;
83 }
84 static gboolean
85 cmp_lt(fvalue_t *a, fvalue_t *b)
86 {
87         if (a->value.time.secs < b->value.time.secs) {
88                 return TRUE;
89         }
90         if (a->value.time.secs > b->value.time.secs) {
91                 return FALSE;
92         }
93
94         return a->value.time.nsecs < b->value.time.nsecs;
95 }
96 static gboolean
97 cmp_le(fvalue_t *a, fvalue_t *b)
98 {
99         if (a->value.time.secs < b->value.time.secs) {
100                 return TRUE;
101         }
102         if (a->value.time.secs > b->value.time.secs) {
103                 return FALSE;
104         }
105
106         return a->value.time.nsecs <= b->value.time.nsecs;
107 }
108
109
110 /*
111  * Get a nanoseconds value, starting at "p".
112  *
113  * Returns true on success, false on failure.
114  */
115 static gboolean
116 get_nsecs(char *startp, int *nsecs)
117 {
118         int ndigits;
119         int scale;
120         char *p;
121         int val;
122         int digit;
123         int i;
124
125         /*
126          * How many characters are in the string?
127          */
128         ndigits = (int)strlen(startp);
129
130         /*
131          * If there are N characters in the string, the last of the
132          * characters would be the digit corresponding to 10^(9-N)
133          * nanoseconds.
134          */
135         scale = 9 - ndigits;
136
137         /*
138          * Start at the last character, and work backwards.
139          */
140         p = startp + ndigits;
141         val = 0;
142         while (p != startp) {
143                 p--;
144
145                 if (!isdigit((unsigned char)*p)) {
146                         /*
147                          * Not a digit - error.
148                          */
149                         return FALSE;
150                 }
151                 digit = *p - '0';
152                 if (digit != 0) {
153                         /*
154                          * Non-zero digit corresponding to that number
155                          * of (10^scale) units.
156                          *
157                          * If scale is less than zero, this digit corresponds
158                          * to a value less than a nanosecond, so this number
159                          * isn't valid.
160                          */
161                         if (scale < 0)
162                                 return FALSE;
163                         for (i = 0; i < scale; i++)
164                                 digit *= 10;
165                         val += digit;
166                 }
167                 scale++;
168         }
169         *nsecs = val;
170         return TRUE;
171 }
172
173 static gboolean
174 relative_val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
175 {
176         char    *curptr, *endptr;
177         gboolean negative = FALSE;
178
179         curptr = s;
180
181         if(*curptr == '-') {
182             negative = TRUE;
183             curptr++;
184         }
185
186         /*
187          * If it doesn't begin with ".", it should contain a seconds
188          * value.
189          */
190         if (*curptr != '.') {
191                 /*
192                  * Get the seconds value.
193                  */
194                 fv->value.time.secs = strtoul(curptr, &endptr, 10);
195                 if (endptr == curptr || (*endptr != '\0' && *endptr != '.'))
196                         goto fail;
197                 curptr = endptr;
198                 if (*curptr == '.')
199                         curptr++;       /* skip the decimal point */
200         } else {
201                 /*
202                  * No seconds value - it's 0.
203                  */
204                 fv->value.time.secs = 0;
205                 curptr++;               /* skip the decimal point */
206         }
207
208         /*
209          * If there's more stuff left in the string, it should be the
210          * nanoseconds value.
211          */
212         if (*curptr != '\0') {
213                 /*
214                  * Get the nanoseconds value.
215                  */
216                 if (!get_nsecs(curptr, &fv->value.time.nsecs))
217                         goto fail;
218         } else {
219                 /*
220                  * No nanoseconds value - it's 0.
221                  */
222                 fv->value.time.nsecs = 0;
223         }
224
225         if(negative) {
226             fv->value.time.secs = -fv->value.time.secs;
227             fv->value.time.nsecs = -fv->value.time.nsecs;
228         }
229         return TRUE;
230
231 fail:
232         if (logfunc != NULL)
233                 logfunc("\"%s\" is not a valid time.", s);
234         return FALSE;
235 }
236
237
238 static gboolean
239 absolute_val_from_string(fvalue_t *fv, char *s, LogFunc logfunc)
240 {
241         struct tm tm;
242         char    *curptr;
243
244         curptr = strptime(s,"%b %d, %Y %H:%M:%S", &tm);
245         if (curptr == NULL)
246                 goto fail;
247         tm.tm_isdst = -1;       /* let the computer figure out if it's DST */
248         fv->value.time.secs = mktime(&tm);
249         if (*curptr != '\0') {
250                 /*
251                  * Something came after the seconds field; it must be
252                  * a nanoseconds field.
253                  */
254                 if (*curptr != '.')
255                         goto fail;      /* it's not */
256                 curptr++;       /* skip the "." */
257                 if (!isdigit((unsigned char)*curptr))
258                         goto fail;      /* not a digit, so not valid */
259                 if (!get_nsecs(curptr, &fv->value.time.nsecs))
260                         goto fail;
261         } else {
262                 /*
263                  * No nanoseconds value - it's 0.
264                  */
265                 fv->value.time.nsecs = 0;
266         }
267
268         if (fv->value.time.secs == -1) {
269                 /*
270                  * XXX - should we supply an error message that mentions
271                  * that the time specified might be syntactically valid
272                  * but might not actually have occurred, e.g. a time in
273                  * the non-existent time range after the clocks are
274                  * set forward during daylight savings time (or possibly
275                  * that it's in the time range after the clocks are set
276                  * backward, so that there are two different times that
277                  * it could be)?
278                  */
279                 goto fail;
280         }
281
282         return TRUE;
283
284 fail:
285         if (logfunc != NULL)
286                 logfunc("\"%s\" is not a valid absolute time. Example: \"Nov 12, 1999 08:55:44.123\"",
287                     s);
288         return FALSE;
289 }
290
291 static gboolean
292 absolute_val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
293 {
294         return absolute_val_from_string(fv, s, logfunc);
295 }
296
297 static void
298 time_fvalue_new(fvalue_t *fv)
299 {
300         fv->value.time.secs = 0;
301         fv->value.time.nsecs = 0;
302 }
303
304 static void
305 time_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
306 {
307         g_assert(!already_copied);
308         memcpy(&(fv->value.time), value, sizeof(nstime_t));
309 }
310
311 static gpointer
312 value_get(fvalue_t *fv)
313 {
314         return &(fv->value.time);
315 }
316
317 static int
318 absolute_val_repr_len(fvalue_t *fv, ftrepr_t rtype _U_)
319 {
320         gchar *rep;
321
322         rep = abs_time_to_str(&fv->value.time, ABSOLUTE_TIME_LOCAL,
323             rtype == FTREPR_DISPLAY);
324         return (int)strlen(rep) + 2;    /* 2 for opening and closing quotes */
325 }
326
327 static void
328 absolute_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
329 {
330         sprintf(buf, "\"%s\"",
331             abs_time_to_str(&fv->value.time, ABSOLUTE_TIME_LOCAL,
332                 rtype == FTREPR_DISPLAY));
333 }
334
335 static int
336 relative_val_repr_len(fvalue_t *fv, ftrepr_t rtype _U_)
337 {
338         gchar *rep;
339
340         rep = rel_time_to_secs_str(&fv->value.time);
341         return (int)strlen(rep);
342 }
343
344 static void
345 relative_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
346 {
347         strcpy(buf, rel_time_to_secs_str(&fv->value.time));
348 }
349
350 void
351 ftype_register_time(void)
352 {
353
354         static ftype_t abstime_type = {
355                 FT_ABSOLUTE_TIME,               /* ftype */
356                 "FT_ABSOLUTE_TIME",             /* name */
357                 "date/time",                    /* pretty_name */
358                 0,                              /* wire_size */
359                 time_fvalue_new,                /* new_value */
360                 NULL,                           /* free_value */
361                 absolute_val_from_unparsed,     /* val_from_unparsed */
362                 absolute_val_from_string,       /* val_from_string */
363                 absolute_val_to_repr,           /* val_to_string_repr */
364                 absolute_val_repr_len,          /* len_string_repr */
365
366                 time_fvalue_set,                /* set_value */
367                 NULL,                           /* set_value_uinteger */
368                 NULL,                           /* set_value_sinteger */
369                 NULL,                           /* set_value_integer64 */
370                 NULL,                           /* set_value_floating */
371
372                 value_get,                      /* get_value */
373                 NULL,                           /* get_value_uinteger */
374                 NULL,                           /* get_value_sinteger */
375                 NULL,                           /* get_value_integer64 */
376                 NULL,                           /* get_value_floating */
377
378                 cmp_eq,
379                 cmp_ne,
380                 cmp_gt,
381                 cmp_ge,
382                 cmp_lt,
383                 cmp_le,
384                 NULL,                           /* cmp_bitwise_and */
385                 NULL,                           /* cmp_contains */
386                 NULL,                           /* cmp_matches */
387
388                 NULL,
389                 NULL
390         };
391         static ftype_t reltime_type = {
392                 FT_RELATIVE_TIME,               /* ftype */
393                 "FT_RELATIVE_TIME",             /* name */
394                 "time offset",                  /* pretty_name */
395                 0,                              /* wire_size */
396                 time_fvalue_new,                /* new_value */
397                 NULL,                           /* free_value */
398                 relative_val_from_unparsed,     /* val_from_unparsed */
399                 NULL,                           /* val_from_string */
400                 relative_val_to_repr,           /* val_to_string_repr */
401                 relative_val_repr_len,          /* len_string_repr */
402
403                 time_fvalue_set,                /* set_value */
404                 NULL,                           /* set_value_uinteger */
405                 NULL,                           /* set_value_sinteger */
406                 NULL,                           /* set_value_integer64 */
407                 NULL,                           /* set_value_floating */
408
409                 value_get,                      /* get_value */
410                 NULL,                           /* get_value_uinteger */
411                 NULL,                           /* get_value_sinteger */
412                 NULL,                           /* get_value_integer64 */
413                 NULL,                           /* get_value_floating */
414
415                 cmp_eq,
416                 cmp_ne,
417                 cmp_gt,
418                 cmp_ge,
419                 cmp_lt,
420                 cmp_le,
421                 NULL,                           /* cmp_bitwise_and */
422                 NULL,                           /* cmp_contains */
423                 NULL,                           /* cmp_matches */
424
425                 NULL,
426                 NULL
427         };
428
429         ftype_register(FT_ABSOLUTE_TIME, &abstime_type);
430         ftype_register(FT_RELATIVE_TIME, &reltime_type);
431 }