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