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