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