Moved various to_str files from packet.{c,h} to a separate
[obnox/wireshark/wip.git] / epan / to_str.c
1 /* to_str.h
2  * Routines  for utilities to convert various other types to strings.
3  *
4  * $Id: to_str.c,v 1.1 2001/04/01 02:47:55 hagbard Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef NEED_SNPRINTF_H
31 # include "snprintf.h"
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45
46 #ifdef NEED_INET_V6DEFS_H
47 # include "inet_v6defs.h"
48 #endif
49
50 #include "to_str.h"
51 #include "resolv.h"
52 #include "pint.h"
53 #include <stdio.h>
54 #include <time.h>
55
56 /* Wrapper for the most common case of asking
57  * for a string using a colon as the hex-digit separator.
58  */
59
60 gchar *
61 ether_to_str(const guint8 *ad)
62 {
63         return ether_to_str_punct(ad, ':');
64 }
65
66 /* Places char punct in the string as the hex-digit separator.
67  * If punct is '\0', no punctuation is applied (and thus
68  * the resulting string is 5 bytes shorter)
69  */
70 gchar *
71 ether_to_str_punct(const guint8 *ad, char punct) {
72   static gchar  str[3][18];
73   static gchar *cur;
74   gchar        *p;
75   int          i;
76   guint32      octet;
77   static const gchar hex_digits[16] = "0123456789abcdef";
78
79   if (cur == &str[0][0]) {
80     cur = &str[1][0];
81   } else if (cur == &str[1][0]) {  
82     cur = &str[2][0];
83   } else {  
84     cur = &str[0][0];
85   }
86   p = &cur[18];
87   *--p = '\0';
88   i = 5;
89   for (;;) {
90     octet = ad[i];
91     *--p = hex_digits[octet&0xF];
92     octet >>= 4;
93     *--p = hex_digits[octet&0xF];
94     if (i == 0)
95       break;
96     if (punct)
97       *--p = punct;
98     i--;
99   }
100   return p;
101 }
102
103 gchar *
104 ip_to_str(const guint8 *ad) {
105   static gchar  str[3][16];
106   static gchar *cur;
107
108   if (cur == &str[0][0]) {
109     cur = &str[1][0];
110   } else if (cur == &str[1][0]) {  
111     cur = &str[2][0];
112   } else {  
113     cur = &str[0][0];
114   }
115   ip_to_str_buf(ad, cur);
116   return cur;
117 }
118
119 void
120 ip_to_str_buf(const guint8 *ad, gchar *buf)
121 {
122   gchar        *p;
123   int           i;
124   guint32       octet;
125   guint32       digit;
126   gboolean      saw_nonzero;
127
128   p = buf;
129   i = 0;
130   for (;;) {
131     saw_nonzero = FALSE;
132     octet = ad[i];
133     digit = octet/100;
134     if (digit != 0) {
135       *p++ = digit + '0';
136       saw_nonzero = TRUE;
137     }
138     octet %= 100;
139     digit = octet/10;
140     if (saw_nonzero || digit != 0)
141       *p++ = digit + '0';
142     digit = octet%10;
143     *p++ = digit + '0';
144     if (i == 3)
145       break;
146     *p++ = '.';
147     i++;
148   }
149   *p = '\0';
150 }
151
152 gchar *
153 ip6_to_str(struct e_in6_addr *ad) {
154 #ifndef INET6_ADDRSTRLEN
155 #define INET6_ADDRSTRLEN 46
156 #endif
157   static gchar buf[INET6_ADDRSTRLEN];
158
159   inet_ntop(AF_INET6, (u_char*)ad, (gchar*)buf, sizeof(buf));
160   return buf;
161 }
162
163 gchar*
164 ipx_addr_to_str(guint32 net, const guint8 *ad)
165 {
166         static gchar    str[3][8+1+MAXNAMELEN+1]; /* 8 digits, 1 period, NAME, 1 null */
167         static gchar    *cur;
168         char            *name;
169
170         if (cur == &str[0][0]) {
171                 cur = &str[1][0];
172         } else if (cur == &str[1][0]) {
173                 cur = &str[2][0];
174         } else {
175                 cur = &str[0][0];
176         }
177
178         name = get_ether_name_if_known(ad);
179
180         if (name) {
181                 sprintf(cur, "%s.%s", get_ipxnet_name(net), name);
182         }
183         else {
184                 sprintf(cur, "%s.%s", get_ipxnet_name(net), ether_to_str_punct(ad, '\0'));
185         }
186         return cur;
187 }
188
189 gchar*
190 ipxnet_to_string(const guint8 *ad)
191 {
192         guint32 addr = pntohl(ad);
193         return ipxnet_to_str_punct(addr, ' ');
194 }
195
196 gchar *
197 ipxnet_to_str_punct(const guint32 ad, char punct)
198 {
199   static gchar  str[3][12];
200   static gchar *cur;
201   gchar        *p;
202   int          i;
203   guint32      octet;
204   static const gchar hex_digits[16] = "0123456789ABCDEF";
205   static const guint32  octet_mask[4] =
206           { 0xff000000 , 0x00ff0000, 0x0000ff00, 0x000000ff };
207
208   if (cur == &str[0][0]) {
209     cur = &str[1][0];
210   } else if (cur == &str[1][0]) {  
211     cur = &str[2][0];
212   } else {  
213     cur = &str[0][0];
214   }
215   p = &cur[12];
216   *--p = '\0';
217   i = 3;
218   for (;;) {
219     octet = (ad & octet_mask[i]) >> ((3 - i) * 8);
220     *--p = hex_digits[octet&0xF];
221     octet >>= 4;
222     *--p = hex_digits[octet&0xF];
223     if (i == 0)
224       break;
225     if (punct)
226       *--p = punct;
227     i--;
228   }
229   return p;
230 }
231
232
233 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
234 #define COMMA(do_it)    ((do_it) ? ", " : "")
235
236 gchar *
237 time_secs_to_str(guint32 time)
238 {
239   static gchar  str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
240   static gchar *cur, *p;
241   int hours, mins, secs;
242   int do_comma;
243
244   if (cur == &str[0][0]) {
245     cur = &str[1][0];
246   } else if (cur == &str[1][0]) {  
247     cur = &str[2][0];
248   } else {  
249     cur = &str[0][0];
250   }
251
252   if (time == 0) {
253     sprintf(cur, "0 time");
254     return cur;
255   }
256
257   secs = time % 60;
258   time /= 60;
259   mins = time % 60;
260   time /= 60;
261   hours = time % 24;
262   time /= 24;
263
264   p = cur;
265   if (time != 0) {
266     sprintf(p, "%u day%s", time, PLURALIZE(time));
267     p += strlen(p);
268     do_comma = 1;
269   } else
270     do_comma = 0;
271   if (hours != 0) {
272     sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
273     p += strlen(p);
274     do_comma = 1;
275   } else
276     do_comma = 0;
277   if (mins != 0) {
278     sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
279     p += strlen(p);
280     do_comma = 1;
281   } else
282     do_comma = 0;
283   if (secs != 0)
284     sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
285   return cur;
286 }
287
288 static const char *mon_names[12] = {
289         "Jan",
290         "Feb",
291         "Mar",
292         "Apr",
293         "May",
294         "Jun",
295         "Jul",
296         "Aug",
297         "Sep",
298         "Oct",
299         "Nov",
300         "Dec"
301 };
302
303 gchar *
304 abs_time_to_str(struct timeval *abs_time)
305 {
306         struct tm *tmp;
307         static gchar *cur;
308         static char str[3][3+1+2+2+4+1+2+1+2+1+2+1+4+1 + 5 /* extra */];
309
310         if (cur == &str[0][0]) {
311                 cur = &str[1][0];
312         } else if (cur == &str[1][0]) {
313                 cur = &str[2][0];
314         } else {
315                 cur = &str[0][0];
316         }
317
318         tmp = localtime(&abs_time->tv_sec);
319         sprintf(cur, "%s %2d, %d %02d:%02d:%02d.%04ld",
320             mon_names[tmp->tm_mon],
321             tmp->tm_mday,
322             tmp->tm_year + 1900,
323             tmp->tm_hour,
324             tmp->tm_min,
325             tmp->tm_sec,
326             (long)abs_time->tv_usec/100);
327
328         return cur;
329 }
330
331 #define REL_TIME_LEN    (1+10+1+6+1)
332
333 void
334 display_signed_time(gchar *buf, int buflen, gint32 sec, gint32 usec)
335 {
336         char *sign;
337
338         /* If the microseconds part of the time stamp is negative,
339            print its absolute value and, if the seconds part isn't
340            (the seconds part should be zero in that case), stick
341            a "-" in front of the entire time stamp. */
342         sign = "";
343         if (usec < 0) {
344                 usec = -usec;
345                 if (sec >= 0)
346                         sign = "-";
347         }
348         snprintf(buf, buflen, "%s%d.%06d", sign, sec, usec);
349 }
350
351 gchar *
352 rel_time_to_str(struct timeval *rel_time)
353 {
354         static gchar *cur;
355         static char str[3][REL_TIME_LEN];
356
357         if (cur == &str[0][0]) {
358                 cur = &str[1][0];
359         } else if (cur == &str[1][0]) {
360                 cur = &str[2][0];
361         } else {
362                 cur = &str[0][0];
363         }
364
365         display_signed_time(cur, REL_TIME_LEN, rel_time->tv_sec,
366             rel_time->tv_usec);
367         return cur;
368 }
369
370 /* Generate, into "buf", a string showing the bits of a bitfield.
371    Return a pointer to the character after that string. */
372 char *
373 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
374 {
375   int i;
376   guint32 bit;
377   char *p;
378
379   i = 0;
380   p = buf;
381   bit = 1 << (width - 1);
382   for (;;) {
383     if (mask & bit) {
384       /* This bit is part of the field.  Show its value. */
385       if (val & bit)
386         *p++ = '1';
387       else
388         *p++ = '0';
389     } else {
390       /* This bit is not part of the field. */
391       *p++ = '.';
392     }
393     bit >>= 1;
394     i++;
395     if (i >= width)
396       break;
397     if (i % 4 == 0)
398       *p++ = ' ';
399   }
400   strcpy(p, " = ");
401   p += 3;
402   return p;
403 }
404
405 /* Generate a string describing a Boolean bitfield (a one-bit field that
406    says something is either true of false). */
407 const char *
408 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
409     const char *truedesc, const char *falsedesc)
410 {
411   static char buf[1025];
412   char *p;
413
414   p = decode_bitfield_value(buf, val, mask, width);
415   if (val & mask)
416     strcpy(p, truedesc);
417   else
418     strcpy(p, falsedesc);
419   return buf;
420 }
421
422 /* Generate a string describing a numeric bitfield (an N-bit field whose
423    value is just a number). */
424 const char *
425 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
426     const char *fmt)
427 {
428   static char buf[1025];
429   char *p;
430   int shift = 0;
431
432   /* Compute the number of bits we have to shift the bitfield right
433      to extract its value. */
434   while ((mask & (1<<shift)) == 0)
435     shift++;
436
437   p = decode_bitfield_value(buf, val, mask, width);
438   sprintf(p, fmt, (val & mask) >> shift);
439   return buf;
440 }
441
442
443