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