Witness: add pidl output
[wireshark-wip.git] / epan / to_str.c
blob03e81f6a0d101f18e15863b118b3e1d4778aea79
1 /* to_str.c
2 * Routines for utilities to convert various other types to strings.
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
25 #include "config.h"
27 #include <stdio.h>
28 #include <string.h>
29 #include <time.h>
30 #include <glib.h>
32 #include "emem.h"
33 #include "proto.h"
34 #include "to_str.h"
35 #include "to_str-int.h"
36 #include "strutil.h"
39 * If a user _does_ pass in a too-small buffer, this is probably
40 * going to be too long to fit. However, even a partial string
41 * starting with "[Buf" should provide enough of a clue to be
42 * useful.
44 #define BUF_TOO_SMALL_ERR "[Buffer too small]"
46 static inline char
47 low_nibble_of_octet_to_hex(guint8 oct)
49 /* At least one version of Apple's C compiler/linker is buggy, causing
50 a complaint from the linker about the "literal C string section"
51 not ending with '\0' if we initialize a 16-element "char" array with
52 a 16-character string, the fact that initializing such an array with
53 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
54 '\0' byte in the string nonwithstanding. */
55 static const gchar hex_digits[16] =
56 { '0', '1', '2', '3', '4', '5', '6', '7',
57 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
59 return hex_digits[oct & 0xF];
62 static inline char *
63 byte_to_hex(char *out, guint32 dword) {
64 *out++ = low_nibble_of_octet_to_hex(dword >> 4);
65 *out++ = low_nibble_of_octet_to_hex(dword);
66 return out;
69 char *
70 word_to_hex(char *out, guint16 word) {
71 out = byte_to_hex(out, word >> 8);
72 out = byte_to_hex(out, word);
73 return out;
76 char *
77 word_to_hex_npad(char *out, guint16 word) {
78 if (word >= 0x1000)
79 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 12));
80 if (word >= 0x0100)
81 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 8));
82 if (word >= 0x0010)
83 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 4));
84 *out++ = low_nibble_of_octet_to_hex((guint8)(word >> 0));
85 return out;
88 char *
89 dword_to_hex(char *out, guint32 dword) {
90 out = byte_to_hex(out, dword >> 24);
91 out = byte_to_hex(out, dword >> 16);
92 out = byte_to_hex(out, dword >> 8);
93 out = byte_to_hex(out, dword);
94 return out;
97 char *
98 dword_to_hex_punct(char *out, guint32 dword, char punct) {
99 out = byte_to_hex(out, dword >> 24);
100 *out++ = punct;
101 out = byte_to_hex(out, dword >> 16);
102 *out++ = punct;
103 out = byte_to_hex(out, dword >> 8);
104 *out++ = punct;
105 out = byte_to_hex(out, dword);
106 return out;
110 * This does *not* null-terminate the string. It returns a pointer
111 * to the position in the string following the last character it
112 * puts there, so that the caller can either put the null terminator
113 * in or can append more stuff to the buffer.
115 * There needs to be at least len * 2 bytes left in the buffer.
117 char *
118 bytes_to_hexstr(char *out, const guint8 *ad, guint32 len) {
119 guint32 i;
121 if (!ad)
122 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr()");
124 for (i = 0; i < len; i++)
125 out = byte_to_hex(out, ad[i]);
126 return out;
130 * This does *not* null-terminate the string. It returns a pointer
131 * to the position in the string following the last character it
132 * puts there, so that the caller can either put the null terminator
133 * in or can append more stuff to the buffer.
135 * There needs to be at least len * 3 - 1 bytes left in the buffer.
137 char *
138 bytes_to_hexstr_punct(char *out, const guint8 *ad, guint32 len, char punct) {
139 guint32 i;
141 if (!ad)
142 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_hexstr_punct()");
144 out = byte_to_hex(out, ad[0]);
145 for (i = 1; i < len; i++) {
146 *out++ = punct;
147 out = byte_to_hex(out, ad[i]);
149 return out;
152 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
153 * digits at at a time, with a specified punctuation character between
154 * the bytes.
156 * If punct is '\0', no punctuation is applied (and thus
157 * the resulting string is (len-1) bytes shorter)
159 const gchar *
160 bytestring_to_str(const guint8 *ad, const guint32 len, const char punct) {
161 gchar *buf;
162 size_t buflen;
164 if (!ad)
165 REPORT_DISSECTOR_BUG("Null pointer passed to bytestring_to_str()");
167 /* XXX, Old code was using int as iterator... Why len is guint32 anyway?! (darkjames) */
168 if ( ((int) len) < 0)
169 return "";
171 if (!len)
172 return "";
174 if (punct)
175 buflen=len*3;
176 else
177 buflen=len*2 + 1;
179 buf=(gchar *)ep_alloc(buflen);
181 if (punct)
182 bytes_to_hexstr_punct(buf, ad, len, punct);
183 else
184 bytes_to_hexstr(buf, ad, len);
186 buf[buflen-1] = '\0';
187 return buf;
190 /* Max string length for displaying byte string. */
191 #define MAX_BYTE_STR_LEN 48
193 gchar *
194 bytes_to_str(const guint8 *bd, int bd_len) {
195 gchar *cur;
196 gchar *cur_ptr;
197 int truncated = 0;
199 if (!bd)
200 REPORT_DISSECTOR_BUG("Null pointer passed to bytes_to_str()");
202 cur=(gchar *)ep_alloc(MAX_BYTE_STR_LEN+3+1);
203 if (bd_len <= 0) { cur[0] = '\0'; return cur; }
205 if (bd_len > MAX_BYTE_STR_LEN/2) { /* bd_len > 24 */
206 truncated = 1;
207 bd_len = MAX_BYTE_STR_LEN/2;
210 cur_ptr = bytes_to_hexstr(cur, bd, bd_len); /* max MAX_BYTE_STR_LEN bytes */
212 if (truncated)
213 cur_ptr = g_stpcpy(cur_ptr, "..."); /* 3 bytes */
215 *cur_ptr = '\0'; /* 1 byte */
216 return cur;
219 /* Turn an array of bytes into a string showing the bytes in hex with
220 * punct as a bytes separator.
222 gchar *
223 bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct) {
224 gchar *cur;
225 gchar *cur_ptr;
226 int truncated = 0;
228 if (!punct)
229 return bytes_to_str(bd, bd_len);
231 cur=(gchar *)ep_alloc(MAX_BYTE_STR_LEN+3+1);
232 if (bd_len <= 0) { cur[0] = '\0'; return cur; }
234 if (bd_len > MAX_BYTE_STR_LEN/3) { /* bd_len > 16 */
235 truncated = 1;
236 bd_len = MAX_BYTE_STR_LEN/3;
239 cur_ptr = bytes_to_hexstr_punct(cur, bd, bd_len, punct); /* max MAX_BYTE_STR_LEN-1 bytes */
241 if (truncated) {
242 *cur_ptr++ = punct; /* 1 byte */
243 cur_ptr = g_stpcpy(cur_ptr, "..."); /* 3 bytes */
246 *cur_ptr = '\0';
247 return cur;
250 static int
251 guint32_to_str_buf_len(const guint32 u) {
252 if (u >= 1000000000)return 10;
253 if (u >= 100000000) return 9;
254 if (u >= 10000000) return 8;
255 if (u >= 1000000) return 7;
256 if (u >= 100000) return 6;
257 if (u >= 10000) return 5;
258 if (u >= 1000) return 4;
259 if (u >= 100) return 3;
260 if (u >= 10) return 2;
262 return 1;
265 static const char fast_strings[][4] = {
266 "0", "1", "2", "3", "4", "5", "6", "7",
267 "8", "9", "10", "11", "12", "13", "14", "15",
268 "16", "17", "18", "19", "20", "21", "22", "23",
269 "24", "25", "26", "27", "28", "29", "30", "31",
270 "32", "33", "34", "35", "36", "37", "38", "39",
271 "40", "41", "42", "43", "44", "45", "46", "47",
272 "48", "49", "50", "51", "52", "53", "54", "55",
273 "56", "57", "58", "59", "60", "61", "62", "63",
274 "64", "65", "66", "67", "68", "69", "70", "71",
275 "72", "73", "74", "75", "76", "77", "78", "79",
276 "80", "81", "82", "83", "84", "85", "86", "87",
277 "88", "89", "90", "91", "92", "93", "94", "95",
278 "96", "97", "98", "99", "100", "101", "102", "103",
279 "104", "105", "106", "107", "108", "109", "110", "111",
280 "112", "113", "114", "115", "116", "117", "118", "119",
281 "120", "121", "122", "123", "124", "125", "126", "127",
282 "128", "129", "130", "131", "132", "133", "134", "135",
283 "136", "137", "138", "139", "140", "141", "142", "143",
284 "144", "145", "146", "147", "148", "149", "150", "151",
285 "152", "153", "154", "155", "156", "157", "158", "159",
286 "160", "161", "162", "163", "164", "165", "166", "167",
287 "168", "169", "170", "171", "172", "173", "174", "175",
288 "176", "177", "178", "179", "180", "181", "182", "183",
289 "184", "185", "186", "187", "188", "189", "190", "191",
290 "192", "193", "194", "195", "196", "197", "198", "199",
291 "200", "201", "202", "203", "204", "205", "206", "207",
292 "208", "209", "210", "211", "212", "213", "214", "215",
293 "216", "217", "218", "219", "220", "221", "222", "223",
294 "224", "225", "226", "227", "228", "229", "230", "231",
295 "232", "233", "234", "235", "236", "237", "238", "239",
296 "240", "241", "242", "243", "244", "245", "246", "247",
297 "248", "249", "250", "251", "252", "253", "254", "255"
300 char *uint_to_str_back(char *ptr, guint32 value);
302 void
303 guint32_to_str_buf(guint32 u, gchar *buf, int buf_len) {
304 int str_len = guint32_to_str_buf_len(u)+1;
306 gchar *bp = &buf[str_len];
308 if (buf_len < str_len) {
309 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len); /* Let the unexpected value alert user */
310 return;
313 *--bp = '\0';
315 uint_to_str_back(bp, u);
318 gchar *
319 guint32_to_str(const guint32 u) {
320 int str_len = 16; /* guint32_to_str_buf_len(u)+1; */
322 gchar *bp = (gchar *)ep_alloc(str_len);
323 guint32_to_str_buf(u, bp, str_len);
325 return bp;
328 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
329 #define COMMA(do_it) ((do_it) ? ", " : "")
332 * Maximum length of a string showing days/hours/minutes/seconds.
333 * (Does not include the terminating '\0'.)
334 * Includes space for a '-' sign for any negative components.
335 * -12345 days, 12 hours, 12 minutes, 12.123 seconds
337 #define TIME_SECS_LEN (10+1+4+2+2+5+2+2+7+2+2+7+4)
340 * Convert a value in seconds and fractions of a second to a string,
341 * giving time in days, hours, minutes, and seconds, and put the result
342 * into a buffer.
343 * "is_nsecs" says that "frac" is microseconds if true and milliseconds
344 * if false.
345 * If time is negative, add a '-' to all non-null components.
347 static void
348 time_secs_to_str_buf(gint32 time_val, const guint32 frac, const gboolean is_nsecs,
349 emem_strbuf_t *buf)
351 int hours, mins, secs;
352 const gchar *msign = "";
353 gboolean do_comma = FALSE;
355 if(time_val == G_MININT32) { /* That Which Shall Not Be Negated */
356 ep_strbuf_append_printf(buf, "Unable to cope with time value %d", time_val);
357 return;
360 if(time_val < 0){
361 time_val = -time_val;
362 msign = "-";
365 secs = time_val % 60;
366 time_val /= 60;
367 mins = time_val % 60;
368 time_val /= 60;
369 hours = time_val % 24;
370 time_val /= 24;
372 if (time_val != 0) {
373 ep_strbuf_append_printf(buf, "%s%u day%s", msign, time_val, PLURALIZE(time_val));
374 do_comma = TRUE;
375 msign="";
377 if (hours != 0) {
378 ep_strbuf_append_printf(buf, "%s%s%u hour%s", COMMA(do_comma), msign, hours, PLURALIZE(hours));
379 do_comma = TRUE;
380 msign="";
382 if (mins != 0) {
383 ep_strbuf_append_printf(buf, "%s%s%u minute%s", COMMA(do_comma), msign, mins, PLURALIZE(mins));
384 do_comma = TRUE;
385 msign="";
387 if (secs != 0 || frac != 0) {
388 if (frac != 0) {
389 if (is_nsecs)
390 ep_strbuf_append_printf(buf, "%s%s%u.%09u seconds", COMMA(do_comma), msign, secs, frac);
391 else
392 ep_strbuf_append_printf(buf, "%s%s%u.%03u seconds", COMMA(do_comma), msign, secs, frac);
393 } else
394 ep_strbuf_append_printf(buf, "%s%s%u second%s", COMMA(do_comma), msign, secs, PLURALIZE(secs));
398 gchar *
399 time_secs_to_str(const gint32 time_val)
401 emem_strbuf_t *buf;
403 buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
405 if (time_val == 0) {
406 ep_strbuf_append(buf, "0 seconds");
407 return buf->str;
410 time_secs_to_str_buf(time_val, 0, FALSE, buf);
411 return buf->str;
414 static void
415 time_secs_to_str_buf_unsigned(guint32 time_val, const guint32 frac, const gboolean is_nsecs,
416 emem_strbuf_t *buf)
418 int hours, mins, secs;
419 gboolean do_comma = FALSE;
421 secs = time_val % 60;
422 time_val /= 60;
423 mins = time_val % 60;
424 time_val /= 60;
425 hours = time_val % 24;
426 time_val /= 24;
428 if (time_val != 0) {
429 ep_strbuf_append_printf(buf, "%u day%s", time_val, PLURALIZE(time_val));
430 do_comma = TRUE;
432 if (hours != 0) {
433 ep_strbuf_append_printf(buf, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
434 do_comma = TRUE;
436 if (mins != 0) {
437 ep_strbuf_append_printf(buf, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
438 do_comma = TRUE;
440 if (secs != 0 || frac != 0) {
441 if (frac != 0) {
442 if (is_nsecs)
443 ep_strbuf_append_printf(buf, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
444 else
445 ep_strbuf_append_printf(buf, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
446 } else
447 ep_strbuf_append_printf(buf, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
451 gchar *
452 time_secs_to_str_unsigned(const guint32 time_val)
454 emem_strbuf_t *buf;
456 buf=ep_strbuf_sized_new(TIME_SECS_LEN+1, TIME_SECS_LEN+1);
458 if (time_val == 0) {
459 ep_strbuf_append(buf, "0 seconds");
460 return buf->str;
463 time_secs_to_str_buf_unsigned(time_val, 0, FALSE, buf);
464 return buf->str;
468 gchar *
469 time_msecs_to_str(gint32 time_val)
471 emem_strbuf_t *buf;
472 int msecs;
474 buf=ep_strbuf_sized_new(TIME_SECS_LEN+1+3+1, TIME_SECS_LEN+1+3+1);
476 if (time_val == 0) {
477 ep_strbuf_append(buf, "0 seconds");
478 return buf->str;
481 if(time_val<0){
482 /* oops we got passed a negative time */
483 time_val= -time_val;
484 msecs = time_val % 1000;
485 time_val /= 1000;
486 time_val= -time_val;
487 } else {
488 msecs = time_val % 1000;
489 time_val /= 1000;
492 time_secs_to_str_buf(time_val, msecs, FALSE, buf);
493 return buf->str;
496 static const char mon_names[12][4] = {
497 "Jan",
498 "Feb",
499 "Mar",
500 "Apr",
501 "May",
502 "Jun",
503 "Jul",
504 "Aug",
505 "Sep",
506 "Oct",
507 "Nov",
508 "Dec"
511 static const gchar *get_zonename(struct tm *tmp) {
512 #if defined(HAVE_TM_ZONE)
513 return tmp->tm_zone;
514 #else
515 if ((tmp->tm_isdst != 0) && (tmp->tm_isdst != 1)) {
516 return "???";
518 # if defined(HAVE_TZNAME)
519 return tzname[tmp->tm_isdst];
521 # elif defined(_WIN32)
522 /* Windows C Runtime: */
523 /* _tzname is encoded using the "system default ansi code page" */
524 /* ("which is not necessarily the same as the C library locale"). */
525 /* So: _tzname must be converted to UTF8 before use. */
526 /* Alternative: use Windows GetTimeZoneInformation() to get the */
527 /* timezone name in UTF16 and convert same to UTF8. */
528 /* XXX: the result is that the timezone name will be based upon the */
529 /* system code page (iow: the charset of the system). */
530 /* Since Wireshark is not internationalized, it would seem more */
531 /* correct to show the timezone name in English, no matter what */
532 /* the system code page, but I don't how to do that (or if it's */
533 /* really even possible). */
534 /* In any case converting to UTF8 presumably at least keeps GTK */
535 /* happy. (A bug was reported wherein Wireshark crashed in GDK */
536 /* on a "Japanese version of Windows XP" when trying to copy */
537 /* the date/time string (containing a copy of _tz_name) to the */
538 /* clipboard). */
541 static char *ws_tzname[2] = {NULL, NULL};
543 /* The g_malloc'd value returned from g_locale_to_utf8() is */
544 /* cached for all further use so there's no need to ever */
545 /* g_free() that value. */
546 if (ws_tzname[tmp->tm_isdst] == NULL) {
547 ws_tzname[tmp->tm_isdst] = g_locale_to_utf8(_tzname[tmp->tm_isdst], -1, NULL, NULL, NULL);
548 if (ws_tzname[tmp->tm_isdst] == NULL) {
549 ws_tzname[tmp->tm_isdst] = "???";
552 return ws_tzname[tmp->tm_isdst];
554 # else
555 return tmp->tm_isdst ? "?DT" : "?ST";
557 # endif
558 #endif
561 gchar *
562 abs_time_to_str(const nstime_t *abs_time, const absolute_time_display_e fmt,
563 gboolean show_zone)
565 struct tm *tmp = NULL;
566 const char *zonename = "???";
567 gchar *buf = NULL;
569 #if (defined _WIN32) && (_MSC_VER < 1500)
570 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
571 /* XXX - find the exact value that still does work */
572 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
573 if(abs_time->secs > 2000000000) {
574 tmp = NULL;
575 } else
576 #endif
577 switch (fmt) {
579 case ABSOLUTE_TIME_UTC:
580 case ABSOLUTE_TIME_DOY_UTC:
581 tmp = gmtime(&abs_time->secs);
582 zonename = "UTC";
583 break;
585 case ABSOLUTE_TIME_LOCAL:
586 tmp = localtime(&abs_time->secs);
587 if (tmp) {
588 zonename = get_zonename(tmp);
590 break;
592 if (tmp) {
593 switch (fmt) {
595 case ABSOLUTE_TIME_DOY_UTC:
596 if (show_zone) {
597 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld %s",
598 tmp->tm_year + 1900,
599 tmp->tm_yday + 1,
600 tmp->tm_hour,
601 tmp->tm_min,
602 tmp->tm_sec,
603 (long)abs_time->nsecs,
604 zonename);
605 } else {
606 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d.%09ld",
607 tmp->tm_year + 1900,
608 tmp->tm_yday + 1,
609 tmp->tm_hour,
610 tmp->tm_min,
611 tmp->tm_sec,
612 (long)abs_time->nsecs);
614 break;
616 case ABSOLUTE_TIME_UTC:
617 case ABSOLUTE_TIME_LOCAL:
618 if (show_zone) {
619 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld %s",
620 mon_names[tmp->tm_mon],
621 tmp->tm_mday,
622 tmp->tm_year + 1900,
623 tmp->tm_hour,
624 tmp->tm_min,
625 tmp->tm_sec,
626 (long)abs_time->nsecs,
627 zonename);
628 } else {
629 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d.%09ld",
630 mon_names[tmp->tm_mon],
631 tmp->tm_mday,
632 tmp->tm_year + 1900,
633 tmp->tm_hour,
634 tmp->tm_min,
635 tmp->tm_sec,
636 (long)abs_time->nsecs);
638 break;
640 } else
641 buf = ep_strdup("Not representable");
642 return buf;
645 gchar *
646 abs_time_secs_to_str(const time_t abs_time, const absolute_time_display_e fmt,
647 gboolean show_zone)
649 struct tm *tmp = NULL;
650 const char *zonename = "???";
651 gchar *buf = NULL;
653 #if (defined _WIN32) && (_MSC_VER < 1500)
654 /* calling localtime() on MSVC 2005 with huge values causes it to crash */
655 /* XXX - find the exact value that still does work */
656 /* XXX - using _USE_32BIT_TIME_T might be another way to circumvent this problem */
657 if(abs_time > 2000000000) {
658 tmp = NULL;
659 } else
660 #endif
661 switch (fmt) {
663 case ABSOLUTE_TIME_UTC:
664 case ABSOLUTE_TIME_DOY_UTC:
665 tmp = gmtime(&abs_time);
666 zonename = "UTC";
667 break;
669 case ABSOLUTE_TIME_LOCAL:
670 tmp = localtime(&abs_time);
671 if (tmp) {
672 zonename = get_zonename(tmp);
674 break;
676 if (tmp) {
677 switch (fmt) {
679 case ABSOLUTE_TIME_DOY_UTC:
680 if (show_zone) {
681 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d %s",
682 tmp->tm_year + 1900,
683 tmp->tm_yday + 1,
684 tmp->tm_hour,
685 tmp->tm_min,
686 tmp->tm_sec,
687 zonename);
688 } else {
689 buf = ep_strdup_printf("%04d/%03d:%02d:%02d:%02d",
690 tmp->tm_year + 1900,
691 tmp->tm_yday + 1,
692 tmp->tm_hour,
693 tmp->tm_min,
694 tmp->tm_sec);
696 break;
698 case ABSOLUTE_TIME_UTC:
699 case ABSOLUTE_TIME_LOCAL:
700 if (show_zone) {
701 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d %s",
702 mon_names[tmp->tm_mon],
703 tmp->tm_mday,
704 tmp->tm_year + 1900,
705 tmp->tm_hour,
706 tmp->tm_min,
707 tmp->tm_sec,
708 zonename);
709 } else {
710 buf = ep_strdup_printf("%s %2d, %d %02d:%02d:%02d",
711 mon_names[tmp->tm_mon],
712 tmp->tm_mday,
713 tmp->tm_year + 1900,
714 tmp->tm_hour,
715 tmp->tm_min,
716 tmp->tm_sec);
718 break;
720 } else
721 buf = ep_strdup("Not representable");
722 return buf;
725 void
726 display_signed_time(gchar *buf, int buflen, const gint32 sec, gint32 frac,
727 const to_str_time_res_t units)
729 /* If the fractional part of the time stamp is negative,
730 print its absolute value and, if the seconds part isn't
731 (the seconds part should be zero in that case), stick
732 a "-" in front of the entire time stamp. */
733 if (frac < 0) {
734 frac = -frac;
735 if (sec >= 0) {
736 if (buflen < 1) {
737 return;
739 buf[0] = '-';
740 buf++;
741 buflen--;
744 switch (units) {
746 case TO_STR_TIME_RES_T_SECS:
747 g_snprintf(buf, buflen, "%d", sec);
748 break;
750 case TO_STR_TIME_RES_T_DSECS:
751 g_snprintf(buf, buflen, "%d.%01d", sec, frac);
752 break;
754 case TO_STR_TIME_RES_T_CSECS:
755 g_snprintf(buf, buflen, "%d.%02d", sec, frac);
756 break;
758 case TO_STR_TIME_RES_T_MSECS:
759 g_snprintf(buf, buflen, "%d.%03d", sec, frac);
760 break;
762 case TO_STR_TIME_RES_T_USECS:
763 g_snprintf(buf, buflen, "%d.%06d", sec, frac);
764 break;
766 case TO_STR_TIME_RES_T_NSECS:
767 g_snprintf(buf, buflen, "%d.%09d", sec, frac);
768 break;
773 void
774 display_epoch_time(gchar *buf, int buflen, const time_t sec, gint32 frac,
775 const to_str_time_res_t units)
777 double elapsed_secs;
779 elapsed_secs = difftime(sec,(time_t)0);
781 /* This code copied from display_signed_time; keep it in case anyone
782 is looking at captures from before 1970 (???).
783 If the fractional part of the time stamp is negative,
784 print its absolute value and, if the seconds part isn't
785 (the seconds part should be zero in that case), stick
786 a "-" in front of the entire time stamp. */
787 if (frac < 0) {
788 frac = -frac;
789 if (elapsed_secs >= 0) {
790 if (buflen < 1) {
791 return;
793 buf[0] = '-';
794 buf++;
795 buflen--;
798 switch (units) {
800 case TO_STR_TIME_RES_T_SECS:
801 g_snprintf(buf, buflen, "%0.0f", elapsed_secs);
802 break;
804 case TO_STR_TIME_RES_T_DSECS:
805 g_snprintf(buf, buflen, "%0.0f.%01d", elapsed_secs, frac);
806 break;
808 case TO_STR_TIME_RES_T_CSECS:
809 g_snprintf(buf, buflen, "%0.0f.%02d", elapsed_secs, frac);
810 break;
812 case TO_STR_TIME_RES_T_MSECS:
813 g_snprintf(buf, buflen, "%0.0f.%03d", elapsed_secs, frac);
814 break;
816 case TO_STR_TIME_RES_T_USECS:
817 g_snprintf(buf, buflen, "%0.0f.%06d", elapsed_secs, frac);
818 break;
820 case TO_STR_TIME_RES_T_NSECS:
821 g_snprintf(buf, buflen, "%0.0f.%09d", elapsed_secs, frac);
822 break;
827 * Display a relative time as days/hours/minutes/seconds.
829 gchar *
830 rel_time_to_str(const nstime_t *rel_time)
832 emem_strbuf_t *buf;
833 gint32 time_val;
834 gint32 nsec;
836 buf=ep_strbuf_sized_new(1+TIME_SECS_LEN+1+6+1, 1+TIME_SECS_LEN+1+6+1);
838 /* If the nanoseconds part of the time stamp is negative,
839 print its absolute value and, if the seconds part isn't
840 (the seconds part should be zero in that case), stick
841 a "-" in front of the entire time stamp. */
842 time_val = (gint) rel_time->secs;
843 nsec = rel_time->nsecs;
844 if (time_val == 0 && nsec == 0) {
845 ep_strbuf_append(buf, "0.000000000 seconds");
846 return buf->str;
848 if (nsec < 0) {
849 nsec = -nsec;
850 ep_strbuf_append_c(buf, '-');
853 * We assume here that "rel_time->secs" is negative
854 * or zero; if it's not, the time stamp is bogus,
855 * with a positive seconds and negative microseconds.
857 time_val = (gint) -rel_time->secs;
860 time_secs_to_str_buf(time_val, nsec, TRUE, buf);
861 return buf->str;
864 #define REL_TIME_SECS_LEN (1+10+1+9+1)
867 * Display a relative time as seconds.
869 gchar *
870 rel_time_to_secs_str(const nstime_t *rel_time)
872 gchar *buf;
874 buf=(gchar *)ep_alloc(REL_TIME_SECS_LEN);
876 display_signed_time(buf, REL_TIME_SECS_LEN, (gint32) rel_time->secs,
877 rel_time->nsecs, TO_STR_TIME_RES_T_NSECS);
878 return buf;
882 * Generates a string representing the bits in a bitfield at "bit_offset" from an 8 bit boundary
883 * with the length in bits of no_of_bits based on value.
884 * Ex: ..xx x...
887 char *
888 decode_bits_in_field(const guint bit_offset, const gint no_of_bits, const guint64 value)
890 guint64 mask = 0,tmp;
891 char *str;
892 int bit, str_p = 0;
893 int i;
895 mask = 1;
896 mask = mask << (no_of_bits-1);
898 /* Prepare the string, 256 pos for the bits and zero termination, + 64 for the spaces */
899 str=(char *)ep_alloc0(256+64);
900 for(bit=0;bit<((int)(bit_offset&0x07));bit++){
901 if(bit&&(!(bit%4))){
902 str[str_p] = ' ';
903 str_p++;
905 str[str_p] = '.';
906 str_p++;
909 /* read the bits for the int */
910 for(i=0;i<no_of_bits;i++){
911 if(bit&&(!(bit%4))){
912 str[str_p] = ' ';
913 str_p++;
915 if(bit&&(!(bit%8))){
916 str[str_p] = ' ';
917 str_p++;
919 bit++;
920 tmp = value & mask;
921 if(tmp != 0){
922 str[str_p] = '1';
923 str_p++;
924 } else {
925 str[str_p] = '0';
926 str_p++;
928 mask = mask>>1;
931 for(;bit%8;bit++){
932 if(bit&&(!(bit%4))){
933 str[str_p] = ' ';
934 str_p++;
936 str[str_p] = '.';
937 str_p++;
939 return str;
942 /* Generate, into "buf", a string showing the bits of a bitfield.
943 Return a pointer to the character after that string. */
944 /*XXX this needs a buf_len check */
945 char *
946 other_decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
948 int i;
949 guint32 bit;
950 char *p;
952 i = 0;
953 p = buf;
954 bit = 1 << (width - 1);
955 for (;;) {
956 if (mask & bit) {
957 /* This bit is part of the field. Show its value. */
958 if (val & bit)
959 *p++ = '1';
960 else
961 *p++ = '0';
962 } else {
963 /* This bit is not part of the field. */
964 *p++ = '.';
966 bit >>= 1;
967 i++;
968 if (i >= width)
969 break;
970 if (i % 4 == 0)
971 *p++ = ' ';
973 *p = '\0';
974 return p;
977 char *
978 decode_bitfield_value(char *buf, const guint32 val, const guint32 mask, const int width)
980 char *p;
982 p = other_decode_bitfield_value(buf, val, mask, width);
983 p = g_stpcpy(p, " = ");
985 return p;
988 /* Generate a string describing a Boolean bitfield (a one-bit field that
989 says something is either true or false). */
990 const char *
991 decode_boolean_bitfield(const guint32 val, const guint32 mask, const int width,
992 const char *truedesc, const char *falsedesc)
994 char *buf;
995 char *p;
997 buf=(char *)ep_alloc(1025); /* is this a bit overkill? */
998 p = decode_bitfield_value(buf, val, mask, width);
999 if (val & mask)
1000 strcpy(p, truedesc);
1001 else
1002 strcpy(p, falsedesc);
1003 return buf;
1006 /* Generate a string describing a numeric bitfield (an N-bit field whose
1007 value is just a number). */
1008 const char *
1009 decode_numeric_bitfield(const guint32 val, const guint32 mask, const int width,
1010 const char *fmt)
1012 char *buf;
1013 char *p;
1014 int shift = 0;
1016 buf=(char *)ep_alloc(1025); /* isnt this a bit overkill? */
1017 /* Compute the number of bits we have to shift the bitfield right
1018 to extract its value. */
1019 while ((mask & (1<<shift)) == 0)
1020 shift++;
1022 p = decode_bitfield_value(buf, val, mask, width);
1023 g_snprintf(p, (gulong) (1025-(p-buf)), fmt, (val & mask) >> shift);
1024 return buf;
1028 This function is very fast and this function is called a lot.
1029 XXX update the ep_address_to_str stuff to use this function.
1031 void
1032 ip_to_str_buf(const guint8 *ad, gchar *buf, const int buf_len)
1034 register gchar const *p;
1035 register gchar *b=buf;
1037 if (buf_len < MAX_IP_STR_LEN) {
1038 g_snprintf ( buf, buf_len, BUF_TOO_SMALL_ERR ); /* Let the unexpected value alert user */
1039 return;
1042 p=fast_strings[*ad++];
1043 do {
1044 *b++=*p;
1045 p++;
1046 } while(*p);
1047 *b++='.';
1049 p=fast_strings[*ad++];
1050 do {
1051 *b++=*p;
1052 p++;
1053 } while(*p);
1054 *b++='.';
1056 p=fast_strings[*ad++];
1057 do {
1058 *b++=*p;
1059 p++;
1060 } while(*p);
1061 *b++='.';
1063 p=fast_strings[*ad];
1064 do {
1065 *b++=*p;
1066 p++;
1067 } while(*p);
1068 *b=0;
1071 gchar* guid_to_str(const e_guid_t *guid) {
1072 gchar *buf;
1074 buf=(gchar *)ep_alloc(GUID_STR_LEN);
1075 return guid_to_str_buf(guid, buf, GUID_STR_LEN);
1078 gchar* guid_to_str_buf(const e_guid_t *guid, gchar *buf, int buf_len) {
1079 char *tempptr = buf;
1081 if (buf_len < GUID_STR_LEN) {
1082 g_strlcpy(buf, BUF_TOO_SMALL_ERR, buf_len);/* Let the unexpected value alert user */
1083 return buf;
1086 /* 37 bytes */
1087 tempptr = dword_to_hex(tempptr, guid->data1); /* 8 bytes */
1088 *tempptr++ = '-'; /* 1 byte */
1089 tempptr = word_to_hex(tempptr, guid->data2); /* 4 bytes */
1090 *tempptr++ = '-'; /* 1 byte */
1091 tempptr = word_to_hex(tempptr, guid->data3); /* 4 bytes */
1092 *tempptr++ = '-'; /* 1 byte */
1093 tempptr = bytes_to_hexstr(tempptr, &guid->data4[0], 2); /* 4 bytes */
1094 *tempptr++ = '-'; /* 1 byte */
1095 tempptr = bytes_to_hexstr(tempptr, &guid->data4[2], 6); /* 12 bytes */
1097 *tempptr = '\0';
1098 return buf;
1101 const gchar* port_type_to_str (port_type type) {
1102 switch (type) {
1103 case PT_NONE: return "NONE";
1104 case PT_SCTP: return "SCTP";
1105 case PT_TCP: return "TCP";
1106 case PT_UDP: return "UDP";
1107 case PT_DCCP: return "DCCP";
1108 case PT_IPX: return "IPX";
1109 case PT_NCP: return "NCP";
1110 case PT_EXCHG: return "FC EXCHG";
1111 case PT_DDP: return "DDP";
1112 case PT_SBCCS: return "FICON SBCCS";
1113 case PT_IDP: return "IDP";
1114 case PT_TIPC: return "TIPC";
1115 case PT_USB: return "USB";
1116 case PT_I2C: return "I2C";
1117 case PT_IBQP: return "IBQP";
1118 case PT_BLUETOOTH: return "BLUETOOTH";
1119 default: return "[Unknown]";
1123 char *
1124 oct_to_str_back(char *ptr, guint32 value)
1126 while (value) {
1127 *(--ptr) = '0' + (value & 0x7);
1128 value >>= 3;
1131 *(--ptr) = '0';
1132 return ptr;
1135 char *
1136 hex_to_str_back(char *ptr, int pad, guint32 value)
1138 do {
1139 *(--ptr) = low_nibble_of_octet_to_hex(value);
1140 value >>= 4;
1141 pad--;
1142 } while (value);
1144 /* pad */
1145 while (pad > 0) {
1146 *(--ptr) = '0';
1147 pad--;
1150 *(--ptr) = 'x';
1151 *(--ptr) = '0';
1153 return ptr;
1156 char *
1157 uint_to_str_back(char *ptr, guint32 value)
1159 char const *p;
1161 /* special case */
1162 if (value == 0)
1163 *(--ptr) = '0';
1165 while (value >= 10) {
1166 p = fast_strings[100 + (value % 100)];
1168 value /= 100;
1170 *(--ptr) = p[2];
1171 *(--ptr) = p[1];
1174 if (value)
1175 *(--ptr) = (value) | '0';
1177 return ptr;
1180 char *
1181 int_to_str_back(char *ptr, gint32 value)
1183 if (value < 0) {
1184 ptr = uint_to_str_back(ptr, -value);
1185 *(--ptr) = '-';
1186 } else
1187 ptr = uint_to_str_back(ptr, value);
1189 return ptr;