Add "tvb_get_ntoh64()" and "tvb_get_letoh64()" routines to fetch 64-bit
[gd/wireshark/.git] / epan / ftypes / ftype-time.c
1 /*
2  * $Id$
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@ethereal.com>
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
174         curptr = s;
175
176         /*
177          * If it doesn't begin with ".", it should contain a seconds
178          * value.
179          */
180         if (*curptr != '.') {
181                 /*
182                  * Get the seconds value.
183                  */
184                 fv->value.time.secs = strtoul(curptr, &endptr, 10);
185                 if (endptr == curptr || (*endptr != '\0' && *endptr != '.'))
186                         goto fail;
187                 curptr = endptr;
188                 if (*curptr == '.')
189                         curptr++;       /* skip the decimal point */
190         } else {
191                 /*
192                  * No seconds value - it's 0.
193                  */
194                 fv->value.time.secs = 0;
195                 curptr++;               /* skip the decimal point */
196         }
197
198         /*
199          * If there's more stuff left in the string, it should be the
200          * nanoseconds value.
201          */
202         if (*curptr != '\0') {
203                 /*
204                  * Get the nanoseconds value.
205                  */
206                 if (!get_nsecs(curptr, &fv->value.time.nsecs))
207                         goto fail;
208         } else {
209                 /*
210                  * No nanoseconds value - it's 0.
211                  */
212                 fv->value.time.nsecs = 0;
213         }
214
215         /*
216          * XXX - what about negative values?
217          */
218         return TRUE;
219
220 fail:
221         if (logfunc != NULL)
222                 logfunc("\"%s\" is not a valid time.", s);
223         return FALSE;
224 }
225
226
227 static gboolean
228 absolute_val_from_string(fvalue_t *fv, char *s, LogFunc logfunc)
229 {
230         struct tm tm;
231         char    *curptr;
232
233         curptr = strptime(s,"%b %d, %Y %H:%M:%S", &tm);
234         if (curptr == NULL)
235                 goto fail;
236         tm.tm_isdst = -1;       /* let the computer figure out if it's DST */
237         fv->value.time.secs = mktime(&tm);
238         if (*curptr != '\0') {
239                 /*
240                  * Something came after the seconds field; it must be
241                  * a nanoseconds field.
242                  */
243                 if (*curptr != '.')
244                         goto fail;      /* it's not */
245                 curptr++;       /* skip the "." */
246                 if (!isdigit((unsigned char)*curptr))
247                         goto fail;      /* not a digit, so not valid */
248                 if (!get_nsecs(curptr, &fv->value.time.nsecs))
249                         goto fail;
250         } else {
251                 /*
252                  * No nanoseconds value - it's 0.
253                  */
254                 fv->value.time.nsecs = 0;
255         }
256
257         if (fv->value.time.secs == -1) {
258                 /*
259                  * XXX - should we supply an error message that mentions
260                  * that the time specified might be syntactically valid
261                  * but might not actually have occurred, e.g. a time in
262                  * the non-existent time range after the clocks are
263                  * set forward during daylight savings time (or possibly
264                  * that it's in the time range after the clocks are set
265                  * backward, so that there are two different times that
266                  * it could be)?
267                  */
268                 goto fail;
269         }
270
271         return TRUE;
272
273 fail:
274         if (logfunc != NULL)
275                 logfunc("\"%s\" is not a valid absolute time. Example: \"Nov 12, 1999 08:55:44.123\"",
276                     s);
277         return FALSE;
278 }
279
280 static gboolean
281 absolute_val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
282 {
283         return absolute_val_from_string(fv, s, logfunc);
284 }
285
286 static void
287 time_fvalue_new(fvalue_t *fv)
288 {
289         fv->value.time.secs = 0;
290         fv->value.time.nsecs = 0;
291 }
292
293 static void
294 time_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
295 {
296         g_assert(!already_copied);
297         memcpy(&(fv->value.time), value, sizeof(nstime_t));
298 }
299
300 static gpointer
301 value_get(fvalue_t *fv)
302 {
303         return &(fv->value.time);
304 }
305    
306 static int
307 absolute_val_repr_len(fvalue_t *fv, ftrepr_t rtype _U_)
308 {
309         gchar *rep;
310
311         rep = abs_time_to_str(&fv->value.time);
312         return strlen(rep) + 2; /* 2 for opening and closing quotes */
313 }
314
315 static void
316 absolute_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
317 {
318         sprintf(buf, "\"%s\"", abs_time_to_str(&fv->value.time));
319 }
320    
321 static int
322 relative_val_repr_len(fvalue_t *fv, ftrepr_t rtype _U_)
323 {
324         gchar *rep;
325
326         rep = rel_time_to_secs_str(&fv->value.time);
327         return strlen(rep);
328 }
329
330 static void
331 relative_val_to_repr(fvalue_t *fv, ftrepr_t rtype _U_, char *buf)
332 {
333         strcpy(buf, rel_time_to_secs_str(&fv->value.time));
334 }
335
336 void
337 ftype_register_time(void)
338 {
339
340         static ftype_t abstime_type = {
341                 "FT_ABSOLUTE_TIME",             /* name */
342                 "date/time",                    /* pretty_name */
343                 0,                              /* wire_size */
344                 time_fvalue_new,                /* new_value */
345                 NULL,                           /* free_value */
346                 absolute_val_from_unparsed,     /* val_from_unparsed */
347                 absolute_val_from_string,       /* val_from_string */
348                 absolute_val_to_repr,           /* val_to_string_repr */
349                 absolute_val_repr_len,          /* len_string_repr */
350
351                 time_fvalue_set,                /* set_value */
352                 NULL,                           /* set_value_integer */
353                 NULL,                           /* set_value_integer64 */
354                 NULL,                           /* set_value_floating */
355
356                 value_get,                      /* get_value */
357                 NULL,                           /* get_value_integer */
358                 NULL,                           /* get_value_integer64 */
359                 NULL,                           /* get_value_floating */
360
361                 cmp_eq,
362                 cmp_ne,
363                 cmp_gt,
364                 cmp_ge,
365                 cmp_lt,
366                 cmp_le,
367                 NULL,                           /* cmp_bitwise_and */
368                 NULL,                           /* cmp_contains */
369                 NULL,                           /* cmp_matches */
370
371                 NULL,
372                 NULL
373         };
374         static ftype_t reltime_type = {
375                 "FT_RELATIVE_TIME",             /* name */
376                 "time offset",                  /* pretty_name */
377                 0,                              /* wire_size */
378                 time_fvalue_new,                /* new_value */
379                 NULL,                           /* free_value */
380                 relative_val_from_unparsed,     /* val_from_unparsed */
381                 NULL,                           /* val_from_string */
382                 relative_val_to_repr,           /* val_to_string_repr */
383                 relative_val_repr_len,          /* len_string_repr */
384
385                 time_fvalue_set,                /* set_value */
386                 NULL,                           /* set_value_integer */
387                 NULL,                           /* set_value_integer64 */
388                 NULL,                           /* set_value_floating */
389
390                 value_get,                      /* get_value */
391                 NULL,                           /* get_value_integer */
392                 NULL,                           /* get_value_integer64 */
393                 NULL,                           /* get_value_floating */
394
395                 cmp_eq,
396                 cmp_ne,
397                 cmp_gt,
398                 cmp_ge,
399                 cmp_lt,
400                 cmp_le,
401                 NULL,                           /* cmp_bitwise_and */
402                 NULL,                           /* cmp_contains */
403                 NULL,                           /* cmp_matches */
404
405                 NULL,
406                 NULL
407         };
408
409         ftype_register(FT_ABSOLUTE_TIME, &abstime_type);
410         ftype_register(FT_RELATIVE_TIME, &reltime_type);
411 }