2 * Routines for utilities to convert various other types to strings.
4 * $Id: to_str.c,v 1.42 2003/12/09 05:06:22 guy 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"
63 #include "atalk-utils.h"
64 #include "sna-utils.h"
65 #include "osi-utils.h"
66 #include "packet-mtp3.h"
70 #define MAX_BYTESTRING_LEN 6
72 /* Routine to convert a sequence of bytes to a hex string, one byte/two hex
73 * digits at at a time, with a specified punctuation character between
74 * the bytes. The sequence of bytes must be no longer than
77 * If punct is '\0', no punctuation is applied (and thus
78 * the resulting string is (len-1) bytes shorter)
81 bytestring_to_str(const guint8 *ad, guint32 len, char punct) {
82 static gchar str[3][MAX_BYTESTRING_LEN*3];
87 /* At least one version of Apple's C compiler/linker is buggy, causing
88 a complaint from the linker about the "literal C string section"
89 not ending with '\0' if we initialize a 16-element "char" array with
90 a 16-character string, the fact that initializing such an array with
91 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
92 '\0' byte in the string nonwithstanding. */
93 static const gchar hex_digits[16] =
94 { '0', '1', '2', '3', '4', '5', '6', '7',
95 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
97 g_assert(len > 0 && len <= MAX_BYTESTRING_LEN);
100 if (cur == &str[0][0]) {
102 } else if (cur == &str[1][0]) {
112 *--p = hex_digits[octet&0xF];
114 *--p = hex_digits[octet&0xF];
124 /* Wrapper for the most common case of asking
125 * for a string using a colon as the hex-digit separator.
128 remove this one later when every call has been converted to address_to_str()
131 ether_to_str(const guint8 *ad)
133 return bytestring_to_str(ad, 6, ':');
137 This function is very fast and this function is called a lot.
138 XXX update the address_to_str stuff to use this function.
141 ip_to_str(const guint8 *ad) {
142 static gchar str[4][16];
143 static int cur_idx=0;
150 cur=&str[cur_idx][0];
152 ip_to_str_buf(ad, cur);
157 This function is very fast and this function is called a lot.
158 XXX update the address_to_str stuff to use this function.
160 static const char * const fast_strings[] = {
161 "0", "1", "2", "3", "4", "5", "6", "7",
162 "8", "9", "10", "11", "12", "13", "14", "15",
163 "16", "17", "18", "19", "20", "21", "22", "23",
164 "24", "25", "26", "27", "28", "29", "30", "31",
165 "32", "33", "34", "35", "36", "37", "38", "39",
166 "40", "41", "42", "43", "44", "45", "46", "47",
167 "48", "49", "50", "51", "52", "53", "54", "55",
168 "56", "57", "58", "59", "60", "61", "62", "63",
169 "64", "65", "66", "67", "68", "69", "70", "71",
170 "72", "73", "74", "75", "76", "77", "78", "79",
171 "80", "81", "82", "83", "84", "85", "86", "87",
172 "88", "89", "90", "91", "92", "93", "94", "95",
173 "96", "97", "98", "99", "100", "101", "102", "103",
174 "104", "105", "106", "107", "108", "109", "110", "111",
175 "112", "113", "114", "115", "116", "117", "118", "119",
176 "120", "121", "122", "123", "124", "125", "126", "127",
177 "128", "129", "130", "131", "132", "133", "134", "135",
178 "136", "137", "138", "139", "140", "141", "142", "143",
179 "144", "145", "146", "147", "148", "149", "150", "151",
180 "152", "153", "154", "155", "156", "157", "158", "159",
181 "160", "161", "162", "163", "164", "165", "166", "167",
182 "168", "169", "170", "171", "172", "173", "174", "175",
183 "176", "177", "178", "179", "180", "181", "182", "183",
184 "184", "185", "186", "187", "188", "189", "190", "191",
185 "192", "193", "194", "195", "196", "197", "198", "199",
186 "200", "201", "202", "203", "204", "205", "206", "207",
187 "208", "209", "210", "211", "212", "213", "214", "215",
188 "216", "217", "218", "219", "220", "221", "222", "223",
189 "224", "225", "226", "227", "228", "229", "230", "231",
190 "232", "233", "234", "235", "236", "237", "238", "239",
191 "240", "241", "242", "243", "244", "245", "246", "247",
192 "248", "249", "250", "251", "252", "253", "254", "255"
195 ip_to_str_buf(const guint8 *ad, gchar *buf)
197 register gchar const *p;
198 register gchar *b=buf;
201 p=fast_strings[*ad++];
208 p=fast_strings[*ad++];
215 p=fast_strings[*ad++];
222 p=fast_strings[*ad++];
232 remove this one later when every call has been converted to address_to_str()
235 ip6_to_str(const struct e_in6_addr *ad) {
236 #ifndef INET6_ADDRSTRLEN
237 #define INET6_ADDRSTRLEN 46
240 static gchar *strp, str[4][INET6_ADDRSTRLEN];
248 ip6_to_str_buf(ad, strp);
253 ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf)
255 inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN);
259 ipx_addr_to_str(guint32 net, const guint8 *ad)
261 static gchar str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
265 if (cur == &str[0][0]) {
267 } else if (cur == &str[1][0]) {
273 name = get_ether_name_if_known(ad);
276 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
279 sprintf(cur, "%s.%s", get_ipxnet_name(net),
280 bytestring_to_str(ad, 6, '\0'));
286 ipxnet_to_string(const guint8 *ad)
288 guint32 addr = pntohl(ad);
289 return ipxnet_to_str_punct(addr, ' ');
293 ipxnet_to_str_punct(const guint32 ad, char punct)
295 static gchar str[3][12];
300 /* At least one version of Apple's C compiler/linker is buggy, causing
301 a complaint from the linker about the "literal C string section"
302 not ending with '\0' if we initialize a 16-element "char" array with
303 a 16-character string, the fact that initializing such an array with
304 such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
305 '\0' byte in the string nonwithstanding. */
306 static const gchar hex_digits[16] =
307 { '0', '1', '2', '3', '4', '5', '6', '7',
308 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
309 static const guint32 octet_mask[4] =
310 { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
312 if (cur == &str[0][0]) {
314 } else if (cur == &str[1][0]) {
323 octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
324 *--p = hex_digits[octet&0xF];
326 *--p = hex_digits[octet&0xF];
337 vines_addr_to_str(const guint8 *addrp)
339 static gchar str[3][214];
342 if (cur == &str[0][0]) {
344 } else if (cur == &str[1][0]) {
349 vines_addr_to_str_buf(addrp, cur);
354 vines_addr_to_str_buf(const guint8 *addrp, gchar *buf)
356 sprintf(buf, "%08x.%04x", pntohl(&addrp[0]), pntohs(&addrp[4]));
359 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
360 #define COMMA(do_it) ((do_it) ? ", " : "")
363 * Maximum length of a string showing days/hours/minutes/seconds.
364 * (Does not include the terminating '\0'.)
366 #define TIME_SECS_LEN (8+1+4+2+2+5+2+2+7+2+2+7)
369 * Convert a value in seconds and fractions of a second to a string,
370 * giving time in days, hours, minutes, and seconds, and put the result
372 * "is_nsecs" says that "frac" is microseconds if true and milliseconds
376 time_secs_to_str_buf(guint32 time, guint32 frac, gboolean is_nsecs,
380 int hours, mins, secs;
392 sprintf(p, "%u day%s", time, PLURALIZE(time));
398 sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
404 sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
409 if (secs != 0 || frac != 0) {
412 sprintf(p, "%s%u.%09u seconds", COMMA(do_comma), secs, frac);
414 sprintf(p, "%s%u.%03u seconds", COMMA(do_comma), secs, frac);
416 sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
421 time_secs_to_str(guint32 time)
423 static gchar str[3][TIME_SECS_LEN+1];
426 if (cur == &str[0][0]) {
428 } else if (cur == &str[1][0]) {
435 sprintf(cur, "0 time");
439 time_secs_to_str_buf(time, 0, FALSE, cur);
444 time_msecs_to_str(guint32 time)
446 static gchar str[3][TIME_SECS_LEN+1+3+1];
450 if (cur == &str[0][0]) {
452 } else if (cur == &str[1][0]) {
459 sprintf(cur, "0 time");
466 time_secs_to_str_buf(time, msecs, FALSE, cur);
470 static const char *mon_names[12] = {
486 abs_time_to_str(nstime_t *abs_time)
490 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+9+1];
492 if (cur == &str[0][0]) {
494 } else if (cur == &str[1][0]) {
500 tmp = localtime(&abs_time->secs);
502 sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%09ld",
503 mon_names[tmp->tm_mon],
509 (long)abs_time->nsecs);
511 strncpy(cur, "Not representable", sizeof(str[0]));
516 abs_time_secs_to_str(time_t abs_time)
520 static char str[3][3+1+2+2+4+1+2+1+2+1+2+1];
522 if (cur == &str[0][0]) {
524 } else if (cur == &str[1][0]) {
530 tmp = localtime(&abs_time);
532 sprintf(cur, "%s %2d, %d %02d:%02d:%02d",
533 mon_names[tmp->tm_mon],
540 strncpy(cur, "Not representable", sizeof(str[0]));
545 display_signed_time(gchar *buf, int buflen, gint32 sec, gint32 frac,
550 /* If the fractional part of the time stamp is negative,
551 print its absolute value and, if the seconds part isn't
552 (the seconds part should be zero in that case), stick
553 a "-" in front of the entire time stamp. */
563 snprintf(buf, buflen, "%s%d.%03d", sign, sec, frac);
567 snprintf(buf, buflen, "%s%d.%06d", sign, sec, frac);
571 snprintf(buf, buflen, "%s%d.%09d", sign, sec, frac);
577 * Display a relative time as days/hours/minutes/seconds.
580 rel_time_to_str(nstime_t *rel_time)
583 static char str[3][1+TIME_SECS_LEN+1+6+1];
589 if (cur == &str[0][0]) {
591 } else if (cur == &str[1][0]) {
598 /* If the nanoseconds part of the time stamp is negative,
599 print its absolute value and, if the seconds part isn't
600 (the seconds part should be zero in that case), stick
601 a "-" in front of the entire time stamp. */
603 time = rel_time->secs;
604 nsec = rel_time->nsecs;
605 if (time == 0 && nsec == 0) {
606 sprintf(cur, "0.000000000 seconds");
614 * We assume here that "rel_time->secs" is negative
615 * or zero; if it's not, the time stamp is bogus,
616 * with a positive seconds and negative microseconds.
618 time = -rel_time->secs;
621 time_secs_to_str_buf(time, nsec, TRUE, p);
625 #define REL_TIME_SECS_LEN (1+10+1+9+1)
628 * Display a relative time as seconds.
631 rel_time_to_secs_str(nstime_t *rel_time)
634 static char str[3][REL_TIME_SECS_LEN];
636 if (cur == &str[0][0]) {
638 } else if (cur == &str[1][0]) {
644 display_signed_time(cur, REL_TIME_SECS_LEN, rel_time->secs,
645 rel_time->nsecs, NSECS);
651 remove this one later when every call has been converted to address_to_str()
654 fc_to_str(const guint8 *ad)
656 return bytestring_to_str (ad, 3, '.');
659 /* FC Network Header Network Address Authority Identifiers */
661 #define FC_NH_NAA_IEEE 1 /* IEEE 802.1a */
662 #define FC_NH_NAA_IEEE_E 2 /* IEEE Exteneded */
663 #define FC_NH_NAA_LOCAL 3
664 #define FC_NH_NAA_IP 4 /* 32-bit IP address */
665 #define FC_NH_NAA_IEEE_R 5 /* IEEE Registered */
666 #define FC_NH_NAA_IEEE_R_E 6 /* IEEE Registered Exteneded */
667 /* according to FC-PH 3 draft these are now reclaimed and reserved */
668 #define FC_NH_NAA_CCITT_INDV 12 /* CCITT 60 bit individual address */
669 #define FC_NH_NAA_CCITT_GRP 14 /* CCITT 60 bit group address */
672 fcwwn_to_str (const guint8 *ad)
676 static gchar ethstr[512];
678 if (ad == NULL) return NULL;
680 fmt = (ad[0] & 0xF0) >> 4;
685 case FC_NH_NAA_IEEE_E:
686 memcpy (oui, &ad[2], 6);
687 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
688 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
689 get_manuf_name (oui));
692 case FC_NH_NAA_IEEE_R:
693 oui[0] = ((ad[0] & 0x0F) << 4) | ((ad[1] & 0xF0) >> 4);
694 oui[1] = ((ad[1] & 0x0F) << 4) | ((ad[2] & 0xF0) >> 4);
695 oui[2] = ((ad[2] & 0x0F) << 4) | ((ad[3] & 0xF0) >> 4);
696 oui[3] = ((ad[3] & 0x0F) << 4) | ((ad[4] & 0xF0) >> 4);
697 oui[4] = ((ad[4] & 0x0F) << 4) | ((ad[5] & 0xF0) >> 4);
698 oui[5] = ((ad[5] & 0x0F) << 4) | ((ad[6] & 0xF0) >> 4);
700 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
701 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
702 get_manuf_name (oui));
706 sprintf (ethstr, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ad[0],
707 ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7]);
713 /* Generate, into "buf", a string showing the bits of a bitfield.
714 Return a pointer to the character after that string. */
716 other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
724 bit = 1 << (width - 1);
727 /* This bit is part of the field. Show its value. */
733 /* This bit is not part of the field. */
748 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
752 p = other_decode_bitfield_value(buf, val, mask, width);
758 /* Generate a string describing a Boolean bitfield (a one-bit field that
759 says something is either true of false). */
761 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
762 const char *truedesc, const char *falsedesc)
764 static char buf[1025];
767 p = decode_bitfield_value(buf, val, mask, width);
771 strcpy(p, falsedesc);
775 /* Generate a string describing a numeric bitfield (an N-bit field whose
776 value is just a number). */
778 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
781 static char buf[1025];
785 /* Compute the number of bits we have to shift the bitfield right
786 to extract its value. */
787 while ((mask & (1<<shift)) == 0)
790 p = decode_bitfield_value(buf, val, mask, width);
791 sprintf(p, fmt, (val & mask) >> shift);
796 /*XXX FIXME the code below may be called very very frequently in the future.
797 optimize it for speed and get rid of the slow sprintfs */
798 /* XXX - perhaps we should have individual address types register
799 a table of routines to do operations such as address-to-name translation,
800 address-to-string translation, and the like, and have this call them,
801 and also have an address-to-string-with-a-name routine */
802 /* XXX - use this, and that future address-to-string-with-a-name routine,
803 in "col_set_addr()"; it might also be useful to have address types
804 export the names of the source and destination address fields, so
805 that "col_set_addr()" need know nothing whatsoever about particular
807 /* convert an address struct into a printable string */
809 address_to_str(address *addr)
811 #ifndef INET6_ADDRSTRLEN
812 #define INET6_ADDRSTRLEN 46
815 static gchar *strp, str[16][INET6_ADDRSTRLEN];/* IPv6 is the largest one */
823 address_to_str_buf(addr, strp);
828 address_to_str_buf(address *addr, gchar *buf)
830 struct atalk_ddp_addr ddp_addr;
834 sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", addr->data[0], addr->data[1], addr->data[2], addr->data[3], addr->data[4], addr->data[5]);
837 ip_to_str_buf(addr->data, buf);
840 inet_ntop(AF_INET6, addr->data, buf, INET6_ADDRSTRLEN);
843 sprintf(buf, "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x", addr->data[0], addr->data[1], addr->data[2], addr->data[3], addr->data[4], addr->data[5], addr->data[6], addr->data[7], addr->data[8], addr->data[9]);
846 sna_fid_to_str_buf(addr, buf);
849 memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
850 atalk_addr_to_str_buf(&ddp_addr, buf);
853 vines_addr_to_str_buf(addr->data, buf);
856 print_nsap_net_buf(addr->data, addr->len, buf);
859 sprintf(buf, "0x%02X", addr->data[0]);
862 sprintf(buf, "%02x.%02x.%02x", addr->data[0], addr->data[1], addr->data[2]);
865 mtp3_addr_to_str_buf(addr->data, buf);
868 g_assert_not_reached();