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