If bytes_to_str() is passed a zero length value, return an empty string
[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  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>         /* needed for <netinet/in.h> */
34 #endif
35
36 #ifdef HAVE_NETINET_IN_H
37 # include <netinet/in.h>        /* needed for <arpa/inet.h> on some platforms */
38 #endif
39
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43
44 #ifdef HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>         /* needed to define AF_ values on UNIX */
46 #endif
47
48 #ifdef HAVE_WINSOCK2_H
49 #include <winsock2.h>           /* needed to define AF_ values on Windows */
50 #endif
51
52 #ifdef NEED_INET_V6DEFS_H
53 # include "inet_v6defs.h"
54 #endif
55
56 #include "to_str.h"
57 #include "value_string.h"
58 #include "addr_resolv.h"
59 #include "pint.h"
60 #include "atalk-utils.h"
61 #include "sna-utils.h"
62 #include "osi-utils.h"
63 #include <epan/dissectors/packet-mtp3.h>
64 #include <stdio.h>
65 #include <time.h>
66 #include "emem.h"
67
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.
71  *
72  * If punct is '\0', no punctuation is applied (and thus
73  * the resulting string is (len-1) bytes shorter)
74  */
75 gchar *
76 bytestring_to_str(const guint8 *ad, guint32 len, char punct) {
77   gchar *buf;
78   gchar        *p;
79   int          i = (int) len - 1;
80   guint32      octet;
81   size_t       buflen;
82   /* At least one version of Apple's C compiler/linker is buggy, causing
83      a complaint from the linker about the "literal C string section"
84      not ending with '\0' if we initialize a 16-element "char" array with
85      a 16-character string, the fact that initializing such an array with
86      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
87      '\0' byte in the string nonwithstanding. */
88   static const gchar hex_digits[16] =
89       { '0', '1', '2', '3', '4', '5', '6', '7',
90         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
91
92   if (punct)
93     buflen=len*3;
94   else
95     buflen=len*2 + 1;
96
97   if (buflen < 3 || i < 0) {
98     return "";
99   }
100
101   buf=ep_alloc(buflen);
102   p = &buf[buflen - 1];
103   *p = '\0';
104   for (;;) {
105     octet = ad[i];
106     *--p = hex_digits[octet&0xF];
107     octet >>= 4;
108     *--p = hex_digits[octet&0xF];
109     if (i <= 0)
110       break;
111     if (punct)
112       *--p = punct;
113     i--;
114   }
115   return p;
116 }
117
118 /* Wrapper for the most common case of asking
119  * for a string using a colon as the hex-digit separator.
120  */
121 /* XXX FIXME
122 remove this one later when every call has been converted to address_to_str()
123 */
124 gchar *
125 ether_to_str(const guint8 *ad)
126 {
127         return bytestring_to_str(ad, 6, ':');
128 }
129
130 /*
131  This function is very fast and this function is called a lot.
132  XXX update the address_to_str stuff to use this function.
133 */
134 gchar *
135 ip_to_str(const guint8 *ad) {
136   gchar *buf;
137
138   buf=ep_alloc(16);
139   ip_to_str_buf(ad, buf);
140   return buf;
141 }
142
143 /*
144  This function is very fast and this function is called a lot.
145  XXX update the address_to_str stuff to use this function.
146 */
147 static const char * const fast_strings[] = {
148 "0", "1", "2", "3", "4", "5", "6", "7",
149 "8", "9", "10", "11", "12", "13", "14", "15",
150 "16", "17", "18", "19", "20", "21", "22", "23",
151 "24", "25", "26", "27", "28", "29", "30", "31",
152 "32", "33", "34", "35", "36", "37", "38", "39",
153 "40", "41", "42", "43", "44", "45", "46", "47",
154 "48", "49", "50", "51", "52", "53", "54", "55",
155 "56", "57", "58", "59", "60", "61", "62", "63",
156 "64", "65", "66", "67", "68", "69", "70", "71",
157 "72", "73", "74", "75", "76", "77", "78", "79",
158 "80", "81", "82", "83", "84", "85", "86", "87",
159 "88", "89", "90", "91", "92", "93", "94", "95",
160 "96", "97", "98", "99", "100", "101", "102", "103",
161 "104", "105", "106", "107", "108", "109", "110", "111",
162 "112", "113", "114", "115", "116", "117", "118", "119",
163 "120", "121", "122", "123", "124", "125", "126", "127",
164 "128", "129", "130", "131", "132", "133", "134", "135",
165 "136", "137", "138", "139", "140", "141", "142", "143",
166 "144", "145", "146", "147", "148", "149", "150", "151",
167 "152", "153", "154", "155", "156", "157", "158", "159",
168 "160", "161", "162", "163", "164", "165", "166", "167",
169 "168", "169", "170", "171", "172", "173", "174", "175",
170 "176", "177", "178", "179", "180", "181", "182", "183",
171 "184", "185", "186", "187", "188", "189", "190", "191",
172 "192", "193", "194", "195", "196", "197", "198", "199",
173 "200", "201", "202", "203", "204", "205", "206", "207",
174 "208", "209", "210", "211", "212", "213", "214", "215",
175 "216", "217", "218", "219", "220", "221", "222", "223",
176 "224", "225", "226", "227", "228", "229", "230", "231",
177 "232", "233", "234", "235", "236", "237", "238", "239",
178 "240", "241", "242", "243", "244", "245", "246", "247",
179 "248", "249", "250", "251", "252", "253", "254", "255"
180 };
181 void
182 ip_to_str_buf(const guint8 *ad, gchar *buf)
183 {
184         register gchar const *p;
185         register gchar *b=buf;
186
187         p=fast_strings[*ad++];
188         do {
189                 *b++=*p;
190                 p++;
191         } while(*p);
192         *b++='.';
193
194         p=fast_strings[*ad++];
195         do {
196                 *b++=*p;
197                 p++;
198         } while(*p);
199         *b++='.';
200
201         p=fast_strings[*ad++];
202         do {
203                 *b++=*p;
204                 p++;
205         } while(*p);
206         *b++='.';
207
208         p=fast_strings[*ad];
209         do {
210                 *b++=*p;
211                 p++;
212         } while(*p);
213         *b=0;
214 }
215
216
217 /* XXX FIXME
218 remove this one later when every call has been converted to address_to_str()
219 */
220 gchar *
221 ip6_to_str(const struct e_in6_addr *ad) {
222 #ifndef INET6_ADDRSTRLEN
223 #define INET6_ADDRSTRLEN 46
224 #endif
225   static gchar *str;
226
227   str=ep_alloc(INET6_ADDRSTRLEN+1);
228
229   ip6_to_str_buf(ad, str);
230   return str;
231 }
232
233 void
234 ip6_to_str_buf(const struct e_in6_addr *ad, gchar *buf)
235 {
236   inet_ntop(AF_INET6, (const guchar*)ad, buf, INET6_ADDRSTRLEN);
237 }
238
239 gchar*
240 ipx_addr_to_str(guint32 net, const guint8 *ad)
241 {
242         gchar   *buf;
243         char    *name;
244
245         buf=ep_alloc(8+1+MAXNAMELEN+1); /* 8 digits, 1 period, NAME, 1 null */
246         name = get_ether_name_if_known(ad);
247
248         if (name) {
249                 g_snprintf(buf, 8+1+MAXNAMELEN+1, "%s.%s", get_ipxnet_name(net), name);
250         }
251         else {
252                 g_snprintf(buf, 8+1+MAXNAMELEN+1, "%s.%s", get_ipxnet_name(net),
253                     bytestring_to_str(ad, 6, '\0'));
254         }
255         return buf;
256 }
257
258 gchar*
259 ipxnet_to_string(const guint8 *ad)
260 {
261         guint32 addr = pntohl(ad);
262         return ipxnet_to_str_punct(addr, ' ');
263 }
264
265 gchar *
266 ipxnet_to_str_punct(const guint32 ad, char punct)
267 {
268   gchar        *buf;
269   gchar        *p;
270   int          i;
271   guint32      octet;
272   /* At least one version of Apple's C compiler/linker is buggy, causing
273      a complaint from the linker about the "literal C string section"
274      not ending with '\0' if we initialize a 16-element "char" array with
275      a 16-character string, the fact that initializing such an array with
276      such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
277      '\0' byte in the string nonwithstanding. */
278   static const gchar hex_digits[16] =
279       { '0', '1', '2', '3', '4', '5', '6', '7',
280         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
281   static const guint32  octet_mask[4] =
282           { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
283
284   buf=ep_alloc(12);
285   p = &buf[12];
286   *--p = '\0';
287   i = 3;
288   for (;;) {
289     octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
290     *--p = hex_digits[octet&0xF];
291     octet >>= 4;
292     *--p = hex_digits[octet&0xF];
293     if (i == 0)
294       break;
295     if (punct)
296       *--p = punct;
297     i--;
298   }
299   return p;
300 }
301
302 gchar *
303 vines_addr_to_str(const guint8 *addrp)
304 {
305   gchar *buf;
306
307   buf=ep_alloc(214);
308
309   vines_addr_to_str_buf(addrp, buf, 214);
310   return buf;
311 }
312
313 void
314 vines_addr_to_str_buf(const guint8 *addrp, gchar *buf, int buf_len)
315 {
316   g_snprintf(buf, buf_len, "%08x.%04x", pntohl(&addrp[0]), pntohs(&addrp[4]));
317 }
318
319 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
320 #define COMMA(do_it)    ((do_it) ? ", " : "")
321
322 /*
323  * Maximum length of a string showing days/hours/minutes/seconds.
324  * (Does not include the terminating '\0'.)
325  * Includes space for a '-' sign for any negative compunents.
326  */
327 #define TIME_SECS_LEN   (10+1+4+2+2+5+2+2+7+2+2+7+4)
328
329 /*
330  * Convert a value in seconds and fractions of a second to a string,
331  * giving time in days, hours, minutes, and seconds, and put the result
332  * into a buffer.
333  * "is_nsecs" says that "frac" is microseconds if true and milliseconds
334  * if false.
335  * If time is negative, add a '-' to all non-null components.
336  */
337 static void
338 time_secs_to_str_buf(gint32 time, guint32 frac, gboolean is_nsecs,
339                            gchar *buf, int buf_len)
340 {
341   static gchar *p;
342   int hours, mins, secs;
343   const gchar *msign = "";
344   gboolean do_comma = FALSE;
345
346   if(time<0){
347     time= -time;
348     msign="-";
349   }
350
351   if(time<0){   /* We've overflowed. */
352     g_snprintf(buf, buf_len, "Unable to cope with time value %d", time);
353     return;
354   }
355
356   secs = time % 60;
357   time /= 60;
358   mins = time % 60;
359   time /= 60;
360   hours = time % 24;
361   time /= 24;
362
363   /* This would probably be cleaner if we used GStrings instead. */
364   p = buf;
365   if (time != 0) {
366     p += g_snprintf(p, buf_len, "%s%u day%s", time?msign:"", time, PLURALIZE(time));
367     do_comma = TRUE;
368   }
369   if (hours != 0) {
370     p += g_snprintf(p, buf_len-(p-buf), "%s%s%u hour%s", COMMA(do_comma), hours?msign:"", hours, PLURALIZE(hours));
371     do_comma = TRUE;
372   }
373   if (mins != 0) {
374     p += g_snprintf(p, buf_len-(p-buf), "%s%s%u minute%s", COMMA(do_comma), mins?msign:"", mins, PLURALIZE(mins));
375     do_comma = TRUE;
376   }
377   if (secs != 0 || frac != 0) {
378     if (frac != 0) {
379       if (is_nsecs)
380         p += g_snprintf(p, buf_len-(p-buf), "%s%s%u.%09u seconds", COMMA(do_comma), msign, secs, frac);
381       else
382         p += g_snprintf(p, buf_len-(p-buf), "%s%s%u.%03u seconds", COMMA(do_comma), msign, secs, frac);
383     } else
384       p += g_snprintf(p, buf_len-(p-buf), "%s%s%u second%s", COMMA(do_comma), msign, secs, PLURALIZE(secs));
385   }
386 }
387
388 gchar *
389 time_secs_to_str(gint32 time)
390 {
391   gchar *buf;
392
393   buf=ep_alloc(TIME_SECS_LEN+1);
394
395   if (time == 0) {
396     g_snprintf(buf, TIME_SECS_LEN+1, "0 time");
397     return buf;
398   }
399
400   time_secs_to_str_buf(time, 0, FALSE, buf, TIME_SECS_LEN+1);
401   return buf;
402 }
403
404 gchar *
405 time_msecs_to_str(gint32 time)
406 {
407   gchar *buf;
408   int msecs;
409
410   buf=ep_alloc(TIME_SECS_LEN+1+3+1);
411
412   if (time == 0) {
413     g_snprintf(buf, TIME_SECS_LEN+1+3+1, "0 time");
414     return buf;
415   }
416
417   if(time<0){
418     /* oops we got passed a negative time */
419     time= -time;
420     msecs = time % 1000;
421     time /= 1000;
422     time= -time;
423   } else {
424     msecs = time % 1000;
425     time /= 1000;
426   }
427
428   time_secs_to_str_buf(time, msecs, FALSE, buf, TIME_SECS_LEN+1+3+1);
429   return buf;
430 }
431
432 static const char *mon_names[12] = {
433         "Jan",
434         "Feb",
435         "Mar",
436         "Apr",
437         "May",
438         "Jun",
439         "Jul",
440         "Aug",
441         "Sep",
442         "Oct",
443         "Nov",
444         "Dec"
445 };
446
447 gchar *
448 abs_time_to_str(nstime_t *abs_time)
449 {
450         struct tm *tmp;
451         gchar *buf;
452
453         buf=ep_alloc(3+1+2+2+4+1+2+1+2+1+2+1+9+1);
454
455         tmp = localtime(&abs_time->secs);
456         if (tmp) {
457                 g_snprintf(buf, 3+1+2+2+4+1+2+1+2+1+2+1+9+1,
458                     "%s %2d, %d %02d:%02d:%02d.%09ld",
459                     mon_names[tmp->tm_mon],
460                     tmp->tm_mday,
461                     tmp->tm_year + 1900,
462                     tmp->tm_hour,
463                     tmp->tm_min,
464                     tmp->tm_sec,
465                     (long)abs_time->nsecs);
466         } else
467                 strncpy(buf, "Not representable", 3+1+2+2+4+1+2+1+2+1+2+1+9+1);
468         return buf;
469 }
470
471 gchar *
472 abs_time_secs_to_str(time_t abs_time)
473 {
474         struct tm *tmp;
475         gchar *buf;
476
477         buf=ep_alloc(3+1+2+2+4+1+2+1+2+1+2+1);
478
479         tmp = localtime(&abs_time);
480         if (tmp) {
481                 g_snprintf(buf, 3+1+2+2+4+1+2+1+2+1+2+1,
482                     "%s %2d, %d %02d:%02d:%02d",
483                     mon_names[tmp->tm_mon],
484                     tmp->tm_mday,
485                     tmp->tm_year + 1900,
486                     tmp->tm_hour,
487                     tmp->tm_min,
488                     tmp->tm_sec);
489         } else
490                 strncpy(buf, "Not representable", 3+1+2+2+4+1+2+1+2+1+2+1);
491         return buf;
492 }
493
494 void
495 display_signed_time(gchar *buf, int buflen, gint32 sec, gint32 frac,
496     time_res_t units)
497 {
498         const char *sign;
499
500         /* If the fractional part of the time stamp is negative,
501            print its absolute value and, if the seconds part isn't
502            (the seconds part should be zero in that case), stick
503            a "-" in front of the entire time stamp. */
504         sign = "";
505         if (frac < 0) {
506                 frac = -frac;
507                 if (sec >= 0)
508                         sign = "-";
509         }
510         switch (units) {
511
512         case SECS:
513                 g_snprintf(buf, buflen, "%s%d", sign, sec);
514                 break;
515
516         case DSECS:
517                 g_snprintf(buf, buflen, "%s%d.%01d", sign, sec, frac);
518                 break;
519
520         case CSECS:
521                 g_snprintf(buf, buflen, "%s%d.%02d", sign, sec, frac);
522                 break;
523
524         case MSECS:
525                 g_snprintf(buf, buflen, "%s%d.%03d", sign, sec, frac);
526                 break;
527
528         case USECS:
529                 g_snprintf(buf, buflen, "%s%d.%06d", sign, sec, frac);
530                 break;
531
532         case NSECS:
533                 g_snprintf(buf, buflen, "%s%d.%09d", sign, sec, frac);
534                 break;
535         }
536 }
537
538 /*
539  * Display a relative time as days/hours/minutes/seconds.
540  */
541 gchar *
542 rel_time_to_str(nstime_t *rel_time)
543 {
544         gchar *buf;
545         char *p;
546         const char *sign;
547         gint32 time;
548         gint32 nsec;
549
550         buf=ep_alloc(1+TIME_SECS_LEN+1+6+1);
551         p = buf;
552
553         /* If the nanoseconds part of the time stamp is negative,
554            print its absolute value and, if the seconds part isn't
555            (the seconds part should be zero in that case), stick
556            a "-" in front of the entire time stamp. */
557         sign = "";
558         time = rel_time->secs;
559         nsec = rel_time->nsecs;
560         if (time == 0 && nsec == 0) {
561                 g_snprintf(buf, 1+TIME_SECS_LEN+1+6+1, "0.000000000 seconds");
562                 return buf;
563         }
564         if (nsec < 0) {
565                 nsec = -nsec;
566                 *p++ = '-';
567
568                 /*
569                  * We assume here that "rel_time->secs" is negative
570                  * or zero; if it's not, the time stamp is bogus,
571                  * with a positive seconds and negative microseconds.
572                  */
573                 time = -rel_time->secs;
574         }
575
576         time_secs_to_str_buf(time, nsec, TRUE, p, 1+TIME_SECS_LEN+1+6+1);
577         return buf;
578 }
579
580 #define REL_TIME_SECS_LEN       (1+10+1+9+1)
581
582 /*
583  * Display a relative time as seconds.
584  */
585 gchar *
586 rel_time_to_secs_str(nstime_t *rel_time)
587 {
588         gchar *buf;
589
590         buf=ep_alloc(REL_TIME_SECS_LEN);
591
592         display_signed_time(buf, REL_TIME_SECS_LEN, rel_time->secs,
593             rel_time->nsecs, NSECS);
594         return buf;
595 }
596
597
598 /* XXX FIXME
599 remove this one later when every call has been converted to address_to_str()
600 */
601 gchar *
602 fc_to_str(const guint8 *ad)
603 {
604     return bytestring_to_str (ad, 3, '.');
605 }
606
607 /* FC Network Header Network Address Authority Identifiers */
608
609 #define FC_NH_NAA_IEEE          1       /* IEEE 802.1a */
610 #define FC_NH_NAA_IEEE_E        2       /* IEEE Exteneded */
611 #define FC_NH_NAA_LOCAL         3
612 #define FC_NH_NAA_IP            4       /* 32-bit IP address */
613 #define FC_NH_NAA_IEEE_R        5       /* IEEE Registered */
614 #define FC_NH_NAA_IEEE_R_E      6       /* IEEE Registered Exteneded */
615 /* according to FC-PH 3 draft these are now reclaimed and reserved */
616 #define FC_NH_NAA_CCITT_INDV    12      /* CCITT 60 bit individual address */
617 #define FC_NH_NAA_CCITT_GRP     14      /* CCITT 60 bit group address */
618
619 gchar *
620 fcwwn_to_str (const guint8 *ad)
621 {
622     int fmt;
623     guint8 oui[6];
624     gchar *ethstr;
625
626     if (ad == NULL) return NULL;
627
628     ethstr=ep_alloc(512);
629
630     fmt = (ad[0] & 0xF0) >> 4;
631
632     switch (fmt) {
633
634     case FC_NH_NAA_IEEE:
635     case FC_NH_NAA_IEEE_E:
636         memcpy (oui, &ad[2], 6);
637         g_snprintf (ethstr, 512, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
638                  ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
639                  get_manuf_name (oui));
640         break;
641
642     case FC_NH_NAA_IEEE_R:
643         oui[0] = ((ad[0] & 0x0F) << 4) | ((ad[1] & 0xF0) >> 4);
644         oui[1] = ((ad[1] & 0x0F) << 4) | ((ad[2] & 0xF0) >> 4);
645         oui[2] = ((ad[2] & 0x0F) << 4) | ((ad[3] & 0xF0) >> 4);
646         oui[3] = ((ad[3] & 0x0F) << 4) | ((ad[4] & 0xF0) >> 4);
647         oui[4] = ((ad[4] & 0x0F) << 4) | ((ad[5] & 0xF0) >> 4);
648         oui[5] = ((ad[5] & 0x0F) << 4) | ((ad[6] & 0xF0) >> 4);
649
650         g_snprintf (ethstr, 512, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)", ad[0],
651                  ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7],
652                  get_manuf_name (oui));
653         break;
654
655     default:
656         g_snprintf (ethstr, 512, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ad[0],
657                  ad[1], ad[2], ad[3], ad[4], ad[5], ad[6], ad[7]);
658         break;
659     }
660     return (ethstr);
661 }
662
663 /* Generate, into "buf", a string showing the bits of a bitfield.
664    Return a pointer to the character after that string. */
665 /*XXX this needs a buf_len check */
666 char *
667 other_decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
668 {
669   int i;
670   guint32 bit;
671   char *p;
672
673   i = 0;
674   p = buf;
675   bit = 1 << (width - 1);
676   for (;;) {
677     if (mask & bit) {
678       /* This bit is part of the field.  Show its value. */
679       if (val & bit)
680         *p++ = '1';
681       else
682         *p++ = '0';
683     } else {
684       /* This bit is not part of the field. */
685       *p++ = '.';
686     }
687     bit >>= 1;
688     i++;
689     if (i >= width)
690       break;
691     if (i % 4 == 0)
692       *p++ = ' ';
693   }
694   *p = '\0';
695   return p;
696 }
697
698 char *
699 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
700 {
701   char *p;
702
703   p = other_decode_bitfield_value(buf, val, mask, width);
704   strcpy(p, " = ");
705   p += 3;
706   return p;
707 }
708
709 /* Generate a string describing a Boolean bitfield (a one-bit field that
710    says something is either true of false). */
711 const char *
712 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
713     const char *truedesc, const char *falsedesc)
714 {
715   char *buf;
716   char *p;
717
718   buf=ep_alloc(1025); /* is this a bit overkill? */
719   p = decode_bitfield_value(buf, val, mask, width);
720   if (val & mask)
721     strcpy(p, truedesc);
722   else
723     strcpy(p, falsedesc);
724   return buf;
725 }
726
727 /* Generate a string describing a numeric bitfield (an N-bit field whose
728    value is just a number). */
729 const char *
730 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
731     const char *fmt)
732 {
733   char *buf;
734   char *p;
735   int shift = 0;
736
737   buf=ep_alloc(1025); /* isnt this a bit overkill? */
738   /* Compute the number of bits we have to shift the bitfield right
739      to extract its value. */
740   while ((mask & (1<<shift)) == 0)
741     shift++;
742
743   p = decode_bitfield_value(buf, val, mask, width);
744   g_snprintf(p, 1025-(p-buf), fmt, (val & mask) >> shift);
745   return buf;
746 }
747
748
749 /*XXX FIXME the code below may be called very very frequently in the future.
750   optimize it for speed and get rid of the slow sprintfs */
751 /* XXX - perhaps we should have individual address types register
752    a table of routines to do operations such as address-to-name translation,
753    address-to-string translation, and the like, and have this call them,
754    and also have an address-to-string-with-a-name routine */
755 /* XXX - use this, and that future address-to-string-with-a-name routine,
756    in "col_set_addr()"; it might also be useful to have address types
757    export the names of the source and destination address fields, so
758    that "col_set_addr()" need know nothing whatsoever about particular
759    address types */
760 /* convert an address struct into a printable string */
761 gchar*
762 address_to_str(const address *addr)
763 {
764   gchar *str;
765
766   str=ep_alloc(256);
767   address_to_str_buf(addr, str, 256);
768   return str;
769 }
770
771 void
772 address_to_str_buf(const address *addr, gchar *buf, int buf_len)
773 {
774   struct atalk_ddp_addr ddp_addr;
775
776   switch(addr->type){
777   case AT_ETHER:
778     g_snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x", addr->data[0], addr->data[1], addr->data[2], addr->data[3], addr->data[4], addr->data[5]);
779     break;
780   case AT_IPv4:
781     ip_to_str_buf(addr->data, buf);
782     break;
783   case AT_IPv6:
784     inet_ntop(AF_INET6, addr->data, buf, INET6_ADDRSTRLEN);
785     break;
786   case AT_IPX:
787     g_snprintf(buf, buf_len, "%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]);
788     break;
789   case AT_SNA:
790     sna_fid_to_str_buf(addr, buf, buf_len);
791     break;
792   case AT_ATALK:
793     memcpy(&ddp_addr, addr->data, sizeof ddp_addr);
794     atalk_addr_to_str_buf(&ddp_addr, buf, buf_len);
795     break;
796   case AT_VINES:
797     vines_addr_to_str_buf(addr->data, buf, buf_len);
798     break;
799   case AT_OSI:
800     print_nsap_net_buf(addr->data, addr->len, buf, buf_len);
801     break;
802   case AT_ARCNET:
803     g_snprintf(buf, buf_len, "0x%02X", addr->data[0]);
804     break;
805   case AT_FC:
806     g_snprintf(buf, buf_len, "%02x.%02x.%02x", addr->data[0], addr->data[1], addr->data[2]);
807     break;
808   case AT_SS7PC:
809     mtp3_addr_to_str_buf(addr->data, buf, buf_len);
810     break;
811   case AT_STRINGZ:
812     g_snprintf(buf, buf_len, "%s", addr->data);
813     break;
814   case AT_EUI64:
815     g_snprintf(buf, buf_len, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
816             addr->data[0], addr->data[1], addr->data[2], addr->data[3],
817             addr->data[4], addr->data[5], addr->data[6], addr->data[7]);
818     break;
819   case AT_URI: {
820     int copy_len = addr->len < buf_len ? addr->len : buf_len;
821     memmove(buf, addr->data, copy_len );
822     buf[copy_len] = '\0';
823     }
824     break;
825   default:
826     g_assert_not_reached();
827   }
828 }
829
830 gchar* oid_to_str(const guint8 *oid, gint oid_len) {
831   gchar *buf;
832
833   buf=ep_alloc(MAX_OID_STR_LEN);
834   return oid_to_str_buf(oid, oid_len, buf, MAX_OID_STR_LEN);
835 }
836
837 gchar* oid_to_str_buf(const guint8 *oid, gint oid_len, gchar *buf, int buf_len) {
838   gint i;
839   guint8 byte;
840   guint32 value;
841   gchar *bufp;
842
843   bufp = buf; value=0;
844   for (i=0; i<oid_len; i++){
845     byte = oid[i];
846     if ((bufp - buf) > (MAX_OID_STR_LEN - 16)) {    /* "4294967295" + ".>>>" + '\0' + 1 */
847       bufp += g_snprintf(bufp, buf_len-(bufp-buf), ".>>>");
848       break;
849     }
850     if (i == 0) {
851       bufp += g_snprintf(bufp, buf_len-(bufp-buf), "%u.%u", byte/40, byte%40);
852       continue;
853     }
854     value = (value << 7) | (byte & 0x7F);
855     if (byte & 0x80) {
856       continue;
857     }
858     bufp += g_snprintf(bufp, buf_len-(bufp-buf), ".%u", value);
859     value = 0;
860   }
861   *bufp = '\0';
862
863   return buf;
864 }
865
866 gchar* guid_to_str(const guint8 *guid) {
867   gchar *buf;
868
869   buf=ep_alloc(GUID_STR_LEN);
870   return guid_to_str_buf(guid, buf, GUID_STR_LEN);
871 }
872
873 gchar* guid_to_str_buf(const guint8 *guid, gchar *buf, int buf_len) {
874   g_snprintf(buf, buf_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
875           guid[0], guid[1], guid[2], guid[3],
876           guid[4], guid[5],
877           guid[6], guid[7],
878           guid[8], guid[9],
879           guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
880   return buf;
881 }