Protect against NULL pointers as input. Based on the stacktrace provided, this shoul...
[metze/wireshark/wip.git] / epan / to_str.c
1 /* to_str.c
2  * Routines for utilities to convert various other types to strings.
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <time.h>
32 #include <glib.h>
33
34 #include "emem.h"
35 #include "to_str.h"
36
37 /*
38  * If a user _does_ pass in a too-small buffer, this is probably
39  * going to be too long to fit.  However, even a partial string
40  * starting with "[Buf" should provide enough of a clue to be
41  * useful.
42  */
43 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
44
45 static inline char *
46 byte_to_hex(char *out, guint32 dword) {
47   /* At least one version of Apple's C compiler/linker is buggy, causing
48      a complaint from the linker about the "literal C string section"
49      not ending with '\0' if we initialize a 16-element "char" array with
50      a 16-character string, the fact that initializing such an array with
51      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
52      '\0' byte in the string nonwithstanding. */
53   static const gchar hex_digits[16] =
54       { '0', '1', '2', '3', '4', '5', '6', '7',
55         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
56
57   *out++ = hex_digits[(dword >> 4) & 0xF];
58   *out++ = hex_digits[dword & 0xF];
59   return out;
60 }
61
62 char *
63 word_to_hex(char *out, guint16 word) {
64   out = byte_to_hex(out, word >> 8);
65   out = byte_to_hex(out, word);
66   return out;
67 }
68
69 char *
70 word_to_hex_npad(char *out, guint16 word) {
71   static const gchar hex_digits[16] =
72       { '0', '1', '2', '3', '4', '5', '6', '7',
73         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
74
75         if (word >= 0x1000)
76                 *out++ = hex_digits[(word >> 12) & 0xF];
77         if (word >= 0x0100)
78                 *out++ = hex_digits[(word >> 8) & 0xF];
79         if (word >= 0x0010)
80                 *out++ = hex_digits[(word >> 4) & 0xF];
81         *out++ = hex_digits[word & 0xF];
82         return out;
83 }
84
85 char *
86 dword_to_hex(char *out, guint32 dword) {
87   out = byte_to_hex(out, dword >> 24);
88   out = byte_to_hex(out, dword >> 16);
89   out = byte_to_hex(out, dword >>  8);
90   out = byte_to_hex(out, dword);
91   return out;
92 }
93
94 char *
95 dword_to_hex_punct(char *out, guint32 dword, char punct) {
96   out = byte_to_hex(out, dword >> 24);
97   *out++ = punct;
98   out = byte_to_hex(out, dword >> 16);
99   *out++ = punct;
100   out = byte_to_hex(out, dword >>  8);
101   *out++ = punct;
102   out = byte_to_hex(out, dword);
103   return out;
104 }
105
106 /* buffer need to be at least len * 2 size */
107 char *
108 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len) {
109     guint32 i;
110
111     if (!ad || !len) {
112         *out = '\0';
113     } else {
114         for (i = 0; i < len; i++)
115             out = byte_to_hex(out, ad[i]);
116     }
117     return out;
118 }
119
120 /* buffer need to be at least len * 3 - 1 size */
121 char *
122 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct) {
123     guint32 i;
124
125     if (!ad || !len) {
126         *out = 0;
127     } else {
128         out = byte_to_hex(out, ad[0]);
129         for (i = 1; i < len; i++) {
130             *out++ = punct;
131             out = byte_to_hex(out, ad[i]);
132         }
133     }
134     return out;
135 }
136
137 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
138  * digits at at a time, with a specified punctuation character between
139  * the bytes.
140  *
141  * If punct is '\0', no punctuation is applied (and thus
142  * the resulting string is (len-1) bytes shorter)
143  */
144 gchar *
145 bytestring_to_str(const guint8 *ad, const guint32 len, const char punct) {
146   gchar *buf;
147   size_t       buflen;
148
149   /* XXX, Old code was using int as iterator... Why len is guint32 anyway?! (darkjames) */
150   if ( ((int) len) < 0)
151      return "";
152
153   if (!ad || !len)
154      return "";
155
156   if (punct)
157     buflen=len*3;
158   else
159     buflen=len*2 + 1;
160
161   buf=ep_alloc(buflen);
162
163   if (punct)
164     bytes_to_hexstr_punct(buf, ad, len, punct);
165   else
166     bytes_to_hexstr(buf, ad, len);
167
168   buf[buflen-1] = '\0';
169   return buf;
170 }
171
172 /* Max string length for displaying byte string.  */
173 #define MAX_BYTE_STR_LEN        48
174
175 gchar *
176 bytes_to_str(const guint8 *bd, int bd_len) {
177   gchar *cur;
178   gchar *cur_ptr;
179   int truncated = 0;
180
181   cur=ep_alloc(MAX_BYTE_STR_LEN+3+1);
182   if (!bd || bd_len <= 0) { cur[0] = '\0'; return cur; }
183
184   if (bd_len > MAX_BYTE_STR_LEN/2) {    /* bd_len > 24 */
185     truncated = 1;
186     bd_len = MAX_BYTE_STR_LEN/2;
187   }
188
189   cur_ptr = bytes_to_hexstr(cur, bd, bd_len);   /* max MAX_BYTE_STR_LEN bytes */
190
191   if (truncated)
192     cur_ptr = g_stpcpy(cur_ptr, "...");         /* 3 bytes */
193
194   *cur_ptr = '\0';                              /* 1 byte */
195   return cur;
196 }
197
198 /* Turn an array of bytes into a string showing the bytes in hex with
199  * punct as a bytes separator.
200  */
201 gchar *
202 bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct) {
203   gchar *cur;
204   gchar *cur_ptr;
205   int truncated = 0;
206
207   if (!punct)
208     return bytes_to_str(bd, bd_len);
209
210   cur=ep_alloc(MAX_BYTE_STR_LEN+3+1);
211   if (!bd || bd_len <= 0) { cur[0] = '\0'; return cur; }
212
213   if (bd_len > MAX_BYTE_STR_LEN/3) {    /* bd_len > 16 */
214     truncated = 1;
215     bd_len = MAX_BYTE_STR_LEN/3;
216   }
217
218   cur_ptr = bytes_to_hexstr_punct(cur, bd, bd_len, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
219
220   if (truncated) {
221     *cur_ptr++ = punct;                         /* 1 byte */
222     cur_ptr    = g_stpcpy(cur_ptr, "...");      /* 3 bytes */
223   }
224
225   *cur_ptr = '\0';
226   return cur;
227 }
228
229 static int
230 guint32_to_str_buf_len(const guint32 u) {
231     if (u >= 1000000000)return 10;
232     if (u >= 100000000) return 9;
233     if (u >= 10000000)  return 8;
234     if (u >= 1000000)   return 7;
235     if (u >= 100000)    return 6;
236     if (u >= 10000)     return 5;
237     if (u >= 1000)      return 4;
238     if (u >= 100)       return 3;
239     if (u >= 10)        return 2;
240
241     return 1;
242 }
243
244 static const char * const fast_strings[] = {
245 "0", "1", "2", "3", "4", "5", "6", "7",
246 "8", "9", "10", "11", "12", "13", "14", "15",
247 "16", "17", "18", "19", "20", "21", "22", "23",
248 "24", "25", "26", "27", "28", "29", "30", "31",
249 "32", "33", "34", "35", "36", "37", "38", "39",
250 "40", "41", "42", "43", "44", "45", "46", "47",
251 "48", "49", "50", "51", "52", "53", "54", "55",
252 "56", "57", "58", "59", "60", "61", "62", "63",
253 "64", "65", "66", "67", "68", "69", "70", "71",
254 "72", "73", "74", "75", "76", "77", "78", "79",
255 "80", "81", "82", "83", "84", "85", "86", "87",
256 "88", "89", "90", "91", "92", "93", "94", "95",
257 "96", "97", "98", "99", "100", "101", "102", "103",
258 "104", "105", "106", "107", "108", "109", "110", "111",
259 "112", "113", "114", "115", "116", "117", "118", "119",
260 "120", "121", "122", "123", "124", "125", "126", "127",
261 "128", "129", "130", "131", "132", "133", "134", "135",
262 "136", "137", "138", "139", "140", "141", "142", "143",
263 "144", "145", "146", "147", "148", "149", "150", "151",
264 "152", "153", "154", "155", "156", "157", "158", "159",
265 "160", "161", "162", "163", "164", "165", "166", "167",
266 "168", "169", "170", "171", "172", "173", "174", "175",
267 "176", "177", "178", "179", "180", "181", "182", "183",
268 "184", "185", "186", "187", "188", "189", "190", "191",
269 "192", "193", "194", "195", "196", "197", "198", "199",
270 "200", "201", "202", "203", "204", "205", "206", "207",
271 "208", "209", "210", "211", "212", "213", "214", "215",
272 "216", "217", "218", "219", "220", "221", "222", "223",
273 "224", "225", "226", "227", "228", "229", "230", "231",
274 "232", "233", "234", "235", "236", "237", "238", "239",
275 "240", "241", "242", "243", "244", "245", "246", "247",
276 "248", "249", "250", "251", "252", "253", "254", "255"
277 };
278
279 void
280 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len) {
281   int str_len = guint32_to_str_buf_len(u)+1;
282
283   gchar *bp = &buf[str_len];
284   gchar const *p;
285
286   if (buf_len < str_len) {
287     g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
288     return;
289   }
290
291   *--bp = '\0';
292
293   while (u >= 10) {
294     p = fast_strings[100 + (u % 100)];
295
296     *--bp = p[2];
297     *--bp = p[1];
298
299     u /= 100;
300   }
301
302   if (bp != buf) /* ugly, fixme! */
303     *--bp = (u % 10) | '0';
304 }
305
306 gchar *
307 guint32_to_str(const guint32 u) {
308   int str_len = 16; /* guint32_to_str_buf_len(u)+1; */
309
310   gchar *bp = ep_alloc(str_len);
311   guint32_to_str_buf(u, bp, str_len);
312
313   return bp;
314 }
315
316 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
317 #define COMMA(do_it)    ((do_it) ? ", " : "")
318
319 /*
320  * Maximum length of a string showing days/hours/minutes/seconds.
321  * (Does not include the terminating '\0'.)
322  * Includes space for a '-' sign for any negative components.
323  * -12345 days, 12 hours, 12 minutes, 12.123 seconds
324  */
325 #define TIME_SECS_LEN   (10+1+4+2+2+5+2+2+7+2+2+7+4)
326
327 /*
328  * Convert a value in seconds and fractions of a second to a string,
329  * giving time in days, hours, minutes, and seconds, and put the result
330  * into a buffer.
331  * "is_nsecs" says that "frac" is microseconds if true and milliseconds
332  * if false.
333  * If time is negative, add a '-' to all non-null components.
334  */
335 static void
336 time_secs_to_str_buf(gint32 time_val, const guint32 frac, const gboolean is_nsecs,
337                            emem_strbuf_t *buf)
338 {
339   int hours, mins, secs;
340   const gchar *msign = "";
341   gboolean do_comma = FALSE;
342
343   if(time_val == G_MININT32) {  /* That Which Shall Not Be Negated */
344     ep_strbuf_append_printf(buf, "Unable to cope with time value %d", time_val);
345     return;
346   }
347
348   if(time_val < 0){
349     time_val = -time_val;
350     msign = "-";
351   }
352
353   secs = time_val % 60;
354   time_val /= 60;
355   mins = time_val % 60;
356   time_val /= 60;
357   hours = time_val % 24;
358   time_val /= 24;
359
360   if (time_val != 0) {
361     ep_strbuf_append_printf(buf, "%s%u day%s", msign, time_val, PLURALIZE(time_val));
362     do_comma = TRUE;
363     msign="";
364   }
365   if (hours != 0) {
366     ep_strbuf_append_printf(buf, "%s%s%u hour%s", COMMA(do_comma), msign, hours, PLURALIZE(hours));
367     do_comma = TRUE;
368     msign="";
369   }
370   if (mins != 0) {
371     ep_strbuf_append_printf(buf, "%s%s%u minute%s", COMMA(do_comma), msign, mins, PLURALIZE(mins));
372     do_comma = TRUE;
373     msign="";
374   }
375   if (secs != 0 || frac != 0) {
376     if (frac != 0) {
377       if (is_nsecs)
378         ep_strbuf_append_printf(buf, "%s%s%u.%09u seconds", COMMA(do_comma), msign, secs, frac);
379       else
380         ep_strbuf_append_printf(buf, "%s%s%u.%03u seconds", COMMA(do_comma), msign, secs, frac);
381     } else
382       ep_strbuf_append_printf(buf, "%s%s%u second%s", COMMA(do_comma), msign, secs, PLURALIZE(secs));
383   }
384 }
385
386 gchar *
387 time_secs_to_str(const gint32 time_val)
388 {
389   emem_strbuf_t *buf;
390
391   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
392
393   if (time_val == 0) {
394     ep_strbuf_append(buf, "0 seconds");
395     return buf->str;
396   }
397
398   time_secs_to_str_buf(time_val, 0, FALSE, buf);
399   return buf->str;
400 }
401
402 static void
403 time_secs_to_str_buf_unsigned(guint32 time_val, const guint32 frac, const gboolean is_nsecs,
404                          emem_strbuf_t *buf)
405 {
406   int hours, mins, secs;
407   gboolean do_comma = FALSE;
408
409   secs = time_val % 60;
410   time_val /= 60;
411   mins = time_val % 60;
412   time_val /= 60;
413   hours = time_val % 24;
414   time_val /= 24;
415
416   if (time_val != 0) {
417     ep_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
418     do_comma = TRUE;
419   }
420   if (hours != 0) {
421     ep_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
422     do_comma = TRUE;
423   }
424   if (mins != 0) {
425     ep_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
426     do_comma = TRUE;
427   }
428   if (secs != 0 || frac != 0) {
429     if (frac != 0) {
430       if (is_nsecs)
431         ep_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
432       else
433         ep_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
434     } else
435       ep_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
436   }
437 }
438
439 gchar *
440 time_secs_to_str_unsigned(const guint32 time_val)
441 {
442   emem_strbuf_t *buf;
443
444   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
445
446   if (time_val == 0) {
447     ep_strbuf_append(buf, "0 seconds");
448     return buf->str;
449   }
450
451   time_secs_to_str_buf_unsigned(time_val, 0, FALSE, buf);
452   return buf->str;
453 }
454
455
456 gchar *
457 time_msecs_to_str(gint32 time_val)
458 {
459   emem_strbuf_t *buf;
460   int msecs;
461
462   buf=ep_strbuf_sized_new(TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
463
464   if (time_val == 0) {
465     ep_strbuf_append(buf, "0 seconds");
466     return buf->str;
467   }
468
469   if(time_val<0){
470     /* oops we got passed a negative time */
471     time_val= -time_val;
472     msecs = time_val % 1000;
473     time_val /= 1000;
474     time_val= -time_val;
475   } else {
476     msecs = time_val % 1000;
477     time_val /= 1000;
478   }
479
480   time_secs_to_str_buf(time_val, msecs, FALSE, buf);
481   return buf->str;
482 }
483
484 static const char *mon_names[12] = {
485         "Jan",
486         "Feb",
487         "Mar",
488         "Apr",
489         "May",
490         "Jun",
491         "Jul",
492         "Aug",
493         "Sep",
494         "Oct",
495         "Nov",
496         "Dec"
497 };
498
499 static const gchar *get_zonename(struct tm *tmp) {
500 #if defined(HAVE_TM_ZONE)
501         return tmp->tm_zone;
502 #else
503         if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
504                 return "???";
505         }
506 # if defined(HAVE_TZNAME)
507         return tzname[tmp->tm_isdst];
508
509 # elif defined(_WIN32)
510         /* Windows C Runtime:                                                 */
511         /*   _tzname is encoded using the "system default ansi code page"     */
512         /*     ("which is not necessarily the same as the C library locale"). */
513         /*     So: _tzname must be converted to UTF8 before use.              */
514         /*   Alternative: use Windows GetTimeZoneInformation() to get the     */
515         /*     timezone name in UTF16 and convert same to UTF8.               */
516         /*   XXX: the result is that the timezone name will be based upon the */
517         /*    system code page (iow: the charset of the system).              */
518         /*    Since Wireshark is not internationalized, it would seem more    */
519         /*    correct to show the timezone name in English, no matter what    */
520         /*    the system code page, but I don't how to do that (or if it's    */
521         /*    really even possible).                                          */
522         /*    In any case converting to UTF8 presumably at least keeps GTK    */
523         /*    happy. (A bug was reported wherein Wireshark crashed in GDK     */
524         /*    on a "Japanese version of Windows XP" when trying to copy       */
525         /*    the date/time string (containing a copy of _tz_name) to the     */
526         /*    clipboard).                                                     */
527
528         {
529                 static char *ws_tzname[2] = {NULL, NULL};
530
531                 /* The g_malloc'd value returned from g_locale_to_utf8() is   */
532                 /*  cached for all further use so there's no need to ever     */
533                 /*  g_free() that value.                                      */
534                 if (ws_tzname[tmp->tm_isdst] == NULL) {
535                         ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
536                         if (ws_tzname[tmp->tm_isdst] == NULL) {
537                                 ws_tzname[tmp->tm_isdst] = "???";
538                         }
539                 }
540                 return ws_tzname[tmp->tm_isdst];
541         }
542 # else
543         return tmp->tm_isdst ? "?DT" : "?ST";
544
545 # endif
546 #endif
547 }
548
549 gchar *
550 abs_time_to_str(const nstime_t *abs_time, const absolute_time_display_e fmt,
551    gboolean show_zone)
552 {
553         struct tm *tmp = NULL;
554         const char *zonename = "???";
555         gchar *buf = NULL;
556
557 #ifdef _MSC_VER
558         /* calling localtime() on MSVC 2005 with huge values causes it to crash */
559         /* XXX - find the exact value that still does work */
560         /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
561         if(abs_time->secs > 2000000000) {
562             tmp = NULL;
563         } else
564 #endif
565         switch (fmt) {
566
567         case ABSOLUTE_TIME_UTC:
568         case ABSOLUTE_TIME_DOY_UTC:
569                 tmp = gmtime(&abs_time->secs);
570                 zonename = "UTC";
571                 break;
572
573         case ABSOLUTE_TIME_LOCAL:
574                 tmp = localtime(&abs_time->secs);
575                 if (tmp) {
576                         zonename = get_zonename(tmp);
577                 }
578                 break;
579         }
580         if (tmp) {
581                 switch (fmt) {
582
583                 case ABSOLUTE_TIME_DOY_UTC:
584                         if (show_zone) {
585                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld %s",
586                                     tmp->tm_year + 1900,
587                                     tmp->tm_yday + 1,
588                                     tmp->tm_hour,
589                                     tmp->tm_min,
590                                     tmp->tm_sec,
591                                     (long)abs_time->nsecs,
592                                     zonename);
593                         } else {
594                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld",
595                                     tmp->tm_year + 1900,
596                                     tmp->tm_yday + 1,
597                                     tmp->tm_hour,
598                                     tmp->tm_min,
599                                     tmp->tm_sec,
600                                     (long)abs_time->nsecs);
601                         }
602                         break;
603
604                 case ABSOLUTE_TIME_UTC:
605                 case ABSOLUTE_TIME_LOCAL:
606                         if (show_zone) {
607                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld %s",
608                                     mon_names[tmp->tm_mon],
609                                     tmp->tm_mday,
610                                     tmp->tm_year + 1900,
611                                     tmp->tm_hour,
612                                     tmp->tm_min,
613                                     tmp->tm_sec,
614                                     (long)abs_time->nsecs,
615                                     zonename);
616                         } else {
617                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld",
618                                     mon_names[tmp->tm_mon],
619                                     tmp->tm_mday,
620                                     tmp->tm_year + 1900,
621                                     tmp->tm_hour,
622                                     tmp->tm_min,
623                                     tmp->tm_sec,
624                                     (long)abs_time->nsecs);
625                         }
626                         break;
627                 }
628         } else
629                 buf = ep_strdup("Not representable");
630         return buf;
631 }
632
633 gchar *
634 abs_time_secs_to_str(const time_t abs_time, const absolute_time_display_e fmt,
635     gboolean show_zone)
636 {
637         struct tm *tmp = NULL;
638         const char *zonename = "???";
639         gchar *buf = NULL;
640
641 #ifdef _MSC_VER
642         /* calling localtime() on MSVC 2005 with huge values causes it to crash */
643         /* XXX - find the exact value that still does work */
644         /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
645         if(abs_time > 2000000000) {
646             tmp = NULL;
647         } else
648 #endif
649         switch (fmt) {
650
651         case ABSOLUTE_TIME_UTC:
652         case ABSOLUTE_TIME_DOY_UTC:
653                 tmp = gmtime(&abs_time);
654                 zonename = "UTC";
655                 break;
656
657         case ABSOLUTE_TIME_LOCAL:
658                 tmp = localtime(&abs_time);
659                 if (tmp) {
660                         zonename = get_zonename(tmp);
661                 }
662                 break;
663         }
664         if (tmp) {
665                 switch (fmt) {
666
667                 case ABSOLUTE_TIME_DOY_UTC:
668                         if (show_zone) {
669                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d %s",
670                                     tmp->tm_year + 1900,
671                                     tmp->tm_yday + 1,
672                                     tmp->tm_hour,
673                                     tmp->tm_min,
674                                     tmp->tm_sec,
675                                     zonename);
676                         } else {
677                                 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d",
678                                     tmp->tm_year + 1900,
679                                     tmp->tm_yday + 1,
680                                     tmp->tm_hour,
681                                     tmp->tm_min,
682                                     tmp->tm_sec);
683                         }
684                         break;
685
686                 case ABSOLUTE_TIME_UTC:
687                 case ABSOLUTE_TIME_LOCAL:
688                         if (show_zone) {
689                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d %s",
690                                     mon_names[tmp->tm_mon],
691                                     tmp->tm_mday,
692                                     tmp->tm_year + 1900,
693                                     tmp->tm_hour,
694                                     tmp->tm_min,
695                                     tmp->tm_sec,
696                                     zonename);
697                         } else {
698                                 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d",
699                                     mon_names[tmp->tm_mon],
700                                     tmp->tm_mday,
701                                     tmp->tm_year + 1900,
702                                     tmp->tm_hour,
703                                     tmp->tm_min,
704                                     tmp->tm_sec);
705                         }
706                         break;
707                 }
708         } else
709                 buf = ep_strdup("Not representable");
710         return buf;
711 }
712
713 void
714 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
715     const to_str_time_res_t units)
716 {
717         /* If the fractional part of the time stamp is negative,
718            print its absolute value and, if the seconds part isn't
719            (the seconds part should be zero in that case), stick
720            a "-" in front of the entire time stamp. */
721         if (frac < 0) {
722                 frac = -frac;
723                 if (sec >= 0) {
724                         if (buflen < 1) {
725                           return;
726                         }
727                         buf[0] = '-';
728                         buf++;
729                         buflen--;
730                 }
731         }
732         switch (units) {
733
734         case TO_STR_TIME_RES_T_SECS:
735                 g_snprintf(buf, buflen, "%d", sec);
736                 break;
737
738         case TO_STR_TIME_RES_T_DSECS:
739                 g_snprintf(buf, buflen, "%d.%01d", sec, frac);
740                 break;
741
742         case TO_STR_TIME_RES_T_CSECS:
743                 g_snprintf(buf, buflen, "%d.%02d", sec, frac);
744                 break;
745
746         case TO_STR_TIME_RES_T_MSECS:
747                 g_snprintf(buf, buflen, "%d.%03d", sec, frac);
748                 break;
749
750         case TO_STR_TIME_RES_T_USECS:
751                 g_snprintf(buf, buflen, "%d.%06d", sec, frac);
752                 break;
753
754         case TO_STR_TIME_RES_T_NSECS:
755                 g_snprintf(buf, buflen, "%d.%09d", sec, frac);
756                 break;
757         }
758 }
759
760
761 void
762 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
763     const to_str_time_res_t units)
764 {
765         double elapsed_secs;
766
767         elapsed_secs = difftime(sec,(time_t)0);
768
769         /* This code copied from display_signed_time; keep it in case anyone
770            is looking at captures from before 1970 (???).
771            If the fractional part of the time stamp is negative,
772            print its absolute value and, if the seconds part isn't
773            (the seconds part should be zero in that case), stick
774            a "-" in front of the entire time stamp. */
775         if (frac < 0) {
776                 frac = -frac;
777                 if (elapsed_secs >= 0) {
778                         if (buflen < 1) {
779                           return;
780                         }
781                         buf[0] = '-';
782                         buf++;
783                         buflen--;
784                 }
785         }
786         switch (units) {
787
788         case TO_STR_TIME_RES_T_SECS:
789                 g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
790                 break;
791
792         case TO_STR_TIME_RES_T_DSECS:
793                 g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
794                 break;
795
796         case TO_STR_TIME_RES_T_CSECS:
797                 g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
798                 break;
799
800         case TO_STR_TIME_RES_T_MSECS:
801                 g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
802                 break;
803
804         case TO_STR_TIME_RES_T_USECS:
805                 g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
806                 break;
807
808         case TO_STR_TIME_RES_T_NSECS:
809                 g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
810                 break;
811         }
812 }
813
814 /*
815  * Display a relative time as days/hours/minutes/seconds.
816  */
817 gchar *
818 rel_time_to_str(const nstime_t *rel_time)
819 {
820         emem_strbuf_t *buf;
821         gint32 time_val;
822         gint32 nsec;
823
824         buf=ep_strbuf_sized_new(1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
825
826         /* If the nanoseconds part of the time stamp is negative,
827            print its absolute value and, if the seconds part isn't
828            (the seconds part should be zero in that case), stick
829            a "-" in front of the entire time stamp. */
830         time_val = (gint) rel_time->secs;
831         nsec = rel_time->nsecs;
832         if (time_val == 0 && nsec == 0) {
833                 ep_strbuf_append(buf, "0.000000000 seconds");
834                 return buf->str;
835         }
836         if (nsec < 0) {
837                 nsec = -nsec;
838                 ep_strbuf_append_c(buf, '-');
839
840                 /*
841                  * We assume here that "rel_time->secs" is negative
842                  * or zero; if it's not, the time stamp is bogus,
843                  * with a positive seconds and negative microseconds.
844                  */
845                 time_val = (gint) -rel_time->secs;
846         }
847
848         time_secs_to_str_buf(time_val, nsec, TRUE, buf);
849         return buf->str;
850 }
851
852 #define REL_TIME_SECS_LEN       (1+10+1+9+1)
853
854 /*
855  * Display a relative time as seconds.
856  */
857 gchar *
858 rel_time_to_secs_str(const nstime_t *rel_time)
859 {
860         gchar *buf;
861
862         buf=ep_alloc(REL_TIME_SECS_LEN);
863
864         display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
865             rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
866         return buf;
867 }
868
869 /*
870  * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
871  * with the length in bits of no_of_bits based on value.
872  * Ex: ..xx x...
873  */
874
875 char *
876 decode_bits_in_field(const gint bit_offset, const gint no_of_bits, const guint64 value)
877 {
878         guint64 mask = 0,tmp;
879         char *str;
880         int bit;
881         int i;
882
883         mask = 1;
884         mask = mask << (no_of_bits-1);
885
886         /* prepare the string */
887         str=ep_alloc(256);
888         str[0]='\0';
889         for(bit=0;bit<((int)(bit_offset&0x07));bit++){
890                 if(bit&&(!(bit%4))){
891                         g_strlcat(str, " ", 256);
892                 }
893                 g_strlcat(str, ".", 256);
894         }
895
896         /* read the bits for the int */
897         for(i=0;i<no_of_bits;i++){
898                 if(bit&&(!(bit%4))){
899                         g_strlcat(str, " ", 256);
900                 }
901                 if(bit&&(!(bit%8))){
902                         g_strlcat(str, " ", 256);
903                 }
904                 bit++;
905                 tmp = value & mask;
906                 if(tmp != 0){
907                         g_strlcat(str, "1", 256);
908                 } else {
909                         g_strlcat(str, "0", 256);
910                 }
911                 mask = mask>>1;
912         }
913
914         for(;bit%8;bit++){
915                 if(bit&&(!(bit%4))){
916                         g_strlcat(str, " ", 256);
917                 }
918                 g_strlcat(str, ".", 256);
919         }
920         return str;
921 }
922
923 /* Generate, into "buf", a string showing the bits of a bitfield.
924    Return a pointer to the character after that string. */
925 /*XXX this needs a buf_len check */
926 char *
927 other_decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
928 {
929   int i;
930   guint32 bit;
931   char *p;
932
933   i = 0;
934   p = buf;
935   bit = 1 << (width - 1);
936   for (;;) {
937     if (mask & bit) {
938       /* This bit is part of the field.  Show its value. */
939       if (val & bit)
940         *p++ = '1';
941       else
942         *p++ = '0';
943     } else {
944       /* This bit is not part of the field. */
945       *p++ = '.';
946     }
947     bit >>= 1;
948     i++;
949     if (i >= width)
950       break;
951     if (i % 4 == 0)
952       *p++ = ' ';
953   }
954   *p = '\0';
955   return p;
956 }
957
958 char *
959 decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
960 {
961   char *p;
962
963   p = other_decode_bitfield_value(buf, val, mask, width);
964   strcpy(p, " = ");
965   p += 3;
966   return p;
967 }
968
969 /* Generate a string describing a Boolean bitfield (a one-bit field that
970    says something is either true of false). */
971 const char *
972 decode_boolean_bitfield(const guint32 val, const guint32 mask, const int width,
973     const char *truedesc, const char *falsedesc)
974 {
975   char *buf;
976   char *p;
977
978   buf=ep_alloc(1025); /* is this a bit overkill? */
979   p = decode_bitfield_value(buf, val, mask, width);
980   if (val & mask)
981     strcpy(p, truedesc);
982   else
983     strcpy(p, falsedesc);
984   return buf;
985 }
986
987 /* Generate a string describing a numeric bitfield (an N-bit field whose
988    value is just a number). */
989 const char *
990 decode_numeric_bitfield(const guint32 val, const guint32 mask, const int width,
991     const char *fmt)
992 {
993   char *buf;
994   char *p;
995   int shift = 0;
996
997   buf=ep_alloc(1025); /* isnt this a bit overkill? */
998   /* Compute the number of bits we have to shift the bitfield right
999      to extract its value. */
1000   while ((mask & (1<<shift)) == 0)
1001     shift++;
1002
1003   p = decode_bitfield_value(buf, val, mask, width);
1004   g_snprintf(p, (gulong) (1025-(p-buf)), fmt, (val & mask) >> shift);
1005   return buf;
1006 }
1007
1008 /*
1009  This function is very fast and this function is called a lot.
1010  XXX update the ep_address_to_str stuff to use this function.
1011 */
1012 void
1013 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
1014 {
1015         register gchar const *p;
1016         register gchar *b=buf;
1017
1018         if (buf_len < MAX_IP_STR_LEN) {
1019                 g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR );                 /* Let the unexpected value alert user */
1020                 return;
1021         }
1022
1023         p=fast_strings[*ad++];
1024         do {
1025                 *b++=*p;
1026                 p++;
1027         } while(*p);
1028         *b++='.';
1029
1030         p=fast_strings[*ad++];
1031         do {
1032                 *b++=*p;
1033                 p++;
1034         } while(*p);
1035         *b++='.';
1036
1037         p=fast_strings[*ad++];
1038         do {
1039                 *b++=*p;
1040                 p++;
1041         } while(*p);
1042         *b++='.';
1043
1044         p=fast_strings[*ad];
1045         do {
1046                 *b++=*p;
1047                 p++;
1048         } while(*p);
1049         *b=0;
1050 }
1051
1052 gchar* guid_to_str(const e_guid_t *guid) {
1053   gchar *buf;
1054
1055   buf=ep_alloc(GUID_STR_LEN);
1056   return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1057 }
1058
1059 gchar* guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len) {
1060   char *tempptr = buf;
1061
1062   if (buf_len < GUID_STR_LEN) {
1063      g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1064      return buf;
1065   }
1066
1067   /* 37 bytes */
1068   tempptr    = dword_to_hex(tempptr, guid->data1);              /*  8 bytes */
1069   *tempptr++ = '-';                                             /*  1 byte */
1070   tempptr    = word_to_hex(tempptr, guid->data2);               /*  4 bytes */
1071   *tempptr++ = '-';                                             /*  1 byte */
1072   tempptr    = word_to_hex(tempptr, guid->data3);               /*  4 bytes */
1073   *tempptr++ = '-';                                             /*  1 byte */
1074   tempptr    = bytes_to_hexstr(tempptr, &guid->data4[0], 2);    /*  4 bytes */
1075   *tempptr++ = '-';                                             /*  1 byte */
1076   tempptr    = bytes_to_hexstr(tempptr, &guid->data4[2], 6);    /* 12 bytes */
1077
1078   *tempptr   = '\0';
1079   return buf;
1080 }
1081