2 * Routines for utilities to convert various other types to strings.
4 * $Id: to_str.c,v 1.30 2003/08/23 13:56:39 sahlberg Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h> /* needed for <netinet/in.h> */
36 #ifdef NEED_SNPRINTF_H
37 # include "snprintf.h"
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h> /* needed for <arpa/inet.h> on some platforms */
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
48 #ifdef HAVE_SYS_SOCKET_H
49 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
52 #ifdef HAVE_WINSOCK2_H
53 #include <winsock2.h> /* needed to define AF_ values on Windows */
56 #ifdef NEED_INET_V6DEFS_H
57 # include "inet_v6defs.h"
66 #define MAX_BYTESTRING_LEN 6
68 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
69 * digits at at a time, with a specified punctuation character between
70 * the bytes. The sequence of bytes must be no longer than
73 * If punct is '\0', no punctuation is applied (and thus
74 * the resulting string is (len-1) bytes shorter)
77 bytestring_to_str(const guint8 *ad, guint32 len, char punct) {
78 static gchar str[3][MAX_BYTESTRING_LEN*3];
83 /* At least one version of Apple's C compiler/linker is buggy, causing
84 a complaint from the linker about the "literal C string section"
85 not ending with '\0' if we initialize a 16-element "char" array with
86 a 16-character string, the fact that initializing such an array with
87 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
88 '\0' byte in the string nonwithstanding. */
89 static const gchar hex_digits[16] =
90 { '0', '1', '2', '3', '4', '5', '6', '7',
91 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
93 g_assert(len > 0 && len <= MAX_BYTESTRING_LEN);
96 if (cur == &str[0][0]) {
98 } else if (cur == &str[1][0]) {
108 *--p = hex_digits[octet&0xF];
110 *--p = hex_digits[octet&0xF];
120 /* Wrapper for the most common case of asking
121 * for a string using a colon as the hex-digit separator.
125 ether_to_str(const guint8 *ad)
127 return bytestring_to_str(ad, 6, ':');
131 ip_to_str(const guint8 *ad) {
132 static gchar str[4][16];
135 if (cur == &str[0][0]) {
137 } else if (cur == &str[1][0]) {
139 } else if (cur == &str[2][0]) {
144 ip_to_str_buf(ad, cur);
149 ip_to_str_buf(const guint8 *ad, gchar *buf)
155 gboolean saw_nonzero;
169 if (saw_nonzero || digit != 0)
182 ip6_to_str(const struct e_in6_addr *ad) {
183 #ifndef INET6_ADDRSTRLEN
184 #define INET6_ADDRSTRLEN 46
187 static gchar *strp, str[4][INET6_ADDRSTRLEN];
195 inet_ntop(AF_INET6, (const guchar*)ad, (gchar*)strp, INET6_ADDRSTRLEN);
200 ipx_addr_to_str(guint32 net, const guint8 *ad)
202 static gchar str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
206 if (cur == &str[0][0]) {
208 } else if (cur == &str[1][0]) {
214 name = get_ether_name_if_known(ad);
217 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
220 sprintf(cur, "%s.%s", get_ipxnet_name(net),
221 bytestring_to_str(ad, 6, '\0'));
227 ipxnet_to_string(const guint8 *ad)
229 guint32 addr = pntohl(ad);
230 return ipxnet_to_str_punct(addr, ' ');
234 ipxnet_to_str_punct(const guint32 ad, char punct)
236 static gchar str[3][12];
241 /* At least one version of Apple's C compiler/linker is buggy, causing
242 a complaint from the linker about the "literal C string section"
243 not ending with '\0' if we initialize a 16-element "char" array with
244 a 16-character string, the fact that initializing such an array with
245 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
246 '\0' byte in the string nonwithstanding. */
247 static const gchar hex_digits[16] =
248 { '0', '1', '2', '3', '4', '5', '6', '7',
249 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
250 static const guint32 octet_mask[4] =
251 { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
253 if (cur == &str[0][0]) {
255 } else if (cur == &str[1][0]) {
264 octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
265 *--p = hex_digits[octet&0xF];
267 *--p = hex_digits[octet&0xF];
278 vines_addr_to_str(const guint8 *addrp)
280 static gchar str[3][214];
283 if (cur == &str[0][0]) {
285 } else if (cur == &str[1][0]) {
291 sprintf(cur, "%08x.%04x", pntohl(&addrp[0]), pntohs(&addrp[4]));
295 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
296 #define COMMA(do_it) ((do_it) ? ", " : "")
299 * Maximum length of a string showing days/hours/minutes/seconds.
300 * (Does not include the terminating '\0'.)
302 #define TIME_SECS_LEN (8+1+4+2+2+5+2+2+7+2+2+7)
305 * Convert a value in seconds and fractions of a second to a string,
306 * giving time in days, hours, minutes, and seconds, and put the result
308 * "is_nsecs" says that "frac" is microseconds if true and milliseconds
312 time_secs_to_str_buf(guint32 time, guint32 frac, gboolean is_nsecs,
316 int hours, mins, secs;
328 sprintf(p, "%u day%s", time, PLURALIZE(time));
334 sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
340 sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
345 if (secs != 0 || frac != 0) {
348 sprintf(p, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
350 sprintf(p, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
352 sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
357 time_secs_to_str(guint32 time)
359 static gchar str[3][TIME_SECS_LEN+1];
362 if (cur == &str[0][0]) {
364 } else if (cur == &str[1][0]) {
371 sprintf(cur, "0 time");
375 time_secs_to_str_buf(time, 0, FALSE, cur);
380 time_msecs_to_str(guint32 time)
382 static gchar str[3][TIME_SECS_LEN+1+3+1];
386 if (cur == &str[0][0]) {
388 } else if (cur == &str[1][0]) {
395 sprintf(cur, "0 time");
402 time_secs_to_str_buf(time, msecs, FALSE, cur);
406 static const char *mon_names[12] = {
422 abs_time_to_str(nstime_t *abs_time)
426 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+9+1];
428 if (cur == &str[0][0]) {
430 } else if (cur == &str[1][0]) {
436 tmp = localtime(&abs_time->secs);
438 sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%09ld",
439 mon_names[tmp->tm_mon],
445 (long)abs_time->nsecs);
447 strncpy(cur, "Not representable", sizeof(str[0]));
452 abs_time_secs_to_str(time_t abs_time)
456 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1];
458 if (cur == &str[0][0]) {
460 } else if (cur == &str[1][0]) {
466 tmp = localtime(&abs_time);
468 sprintf(cur, "%s %2d, %d %02d:%02d:%02d",
469 mon_names[tmp->tm_mon],
476 strncpy(cur, "Not representable", sizeof(str[0]));
481 display_signed_time(gchar *buf, int buflen, gint32 sec, gint32 frac,
486 /* If the fractional part of the time stamp is negative,
487 print its absolute value and, if the seconds part isn't
488 (the seconds part should be zero in that case), stick
489 a "-" in front of the entire time stamp. */
499 snprintf(buf, buflen, "%s%d.%03d", sign, sec, frac);
503 snprintf(buf, buflen, "%s%d.%06d", sign, sec, frac);
507 snprintf(buf, buflen, "%s%d.%09d", sign, sec, frac);
513 * Display a relative time as days/hours/minutes/seconds.
516 rel_time_to_str(nstime_t *rel_time)
519 static char str[3][1+TIME_SECS_LEN+1+6+1];
525 if (cur == &str[0][0]) {
527 } else if (cur == &str[1][0]) {
534 /* If the nanoseconds part of the time stamp is negative,
535 print its absolute value and, if the seconds part isn't
536 (the seconds part should be zero in that case), stick
537 a "-" in front of the entire time stamp. */
539 time = rel_time->secs;
540 nsec = rel_time->nsecs;
541 if (time == 0 && nsec == 0) {
542 sprintf(cur, "0.000000000 seconds");
550 * We assume here that "rel_time->secs" is negative
551 * or zero; if it's not, the time stamp is bogus,
552 * with a positive seconds and negative microseconds.
554 time = -rel_time->secs;
557 time_secs_to_str_buf(time, nsec, TRUE, p);
561 #define REL_TIME_SECS_LEN (1+10+1+9+1)
564 * Display a relative time as seconds.
567 rel_time_to_secs_str(nstime_t *rel_time)
570 static char str[3][REL_TIME_SECS_LEN];
572 if (cur == &str[0][0]) {
574 } else if (cur == &str[1][0]) {
580 display_signed_time(cur, REL_TIME_SECS_LEN, rel_time->secs,
581 rel_time->nsecs, NSECS);
587 fc_to_str(const guint8 *ad)
589 return bytestring_to_str (ad, 3, '.');
593 fc32_to_str(address *addr)
596 static gchar str[3][9];
598 if (cur == &str[0][0]) {
600 } else if (cur == &str[1][0]) {
606 sprintf(cur,"%02x.%02x.%02x", addr->data[0], addr->data[1], addr->data[2]);
610 /* FC Network Header Network Address Authority Identifiers */
612 #define FC_NH_NAA_IEEE 1 /* IEEE 802.1a */
613 #define FC_NH_NAA_IEEE_E 2 /* IEEE Exteneded */
614 #define FC_NH_NAA_LOCAL 3
615 #define FC_NH_NAA_IP 4 /* 32-bit IP address */
616 #define FC_NH_NAA_IEEE_R 5 /* IEEE Registered */
617 #define FC_NH_NAA_IEEE_R_E 6 /* IEEE Registered Exteneded */
618 /* according to FC-PH 3 draft these are now reclaimed and reserved */
619 #define FC_NH_NAA_CCITT_INDV 12 /* CCITT 60 bit individual address */
620 #define FC_NH_NAA_CCITT_GRP 14 /* CCITT 60 bit group address */
623 fcwwn_to_str (const guint8 *ad)
627 static gchar ethstr[512];
629 if (ad == NULL) return NULL;
631 fmt = (ad[0] & 0xF0) >> 4;
636 case FC_NH_NAA_IEEE_E:
637 memcpy (oui, &ad[2], 6);
638 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
639 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
640 get_manuf_name (oui));
643 case FC_NH_NAA_IEEE_R:
644 oui[0] = ((ad[0] & 0x0F) << 4) | ((ad[1] & 0xF0) >> 4);
645 oui[1] = ((ad[1] & 0x0F) << 4) | ((ad[2] & 0xF0) >> 4);
646 oui[2] = ((ad[2] & 0x0F) << 4) | ((ad[3] & 0xF0) >> 4);
647 oui[3] = ((ad[3] & 0x0F) << 4) | ((ad[4] & 0xF0) >> 4);
648 oui[4] = ((ad[4] & 0x0F) << 4) | ((ad[5] & 0xF0) >> 4);
649 oui[5] = ((ad[5] & 0x0F) << 4) | ((ad[6] & 0xF0) >> 4);
651 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
652 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
653 get_manuf_name (oui));
657 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ad[0],
658 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7]);
664 /* Generate, into "buf", a string showing the bits of a bitfield.
665 Return a pointer to the character after that string. */
667 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
675 bit = 1 << (width - 1);
678 /* This bit is part of the field. Show its value. */
684 /* This bit is not part of the field. */
699 /* Generate a string describing a Boolean bitfield (a one-bit field that
700 says something is either true of false). */
702 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
703 const char *truedesc, const char *falsedesc)
705 static char buf[1025];
708 p = decode_bitfield_value(buf, val, mask, width);
712 strcpy(p, falsedesc);
716 /* Generate a string describing a numeric bitfield (an N-bit field whose
717 value is just a number). */
719 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
722 static char buf[1025];
726 /* Compute the number of bits we have to shift the bitfield right
727 to extract its value. */
728 while ((mask & (1<<shift)) == 0)
731 p = decode_bitfield_value(buf, val, mask, width);
732 sprintf(p, fmt, (val & mask) >> shift);