xref: /plan9/sys/src/cmd/unix/drawterm/libip/eipfmt.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 
5 enum
6 {
7 	Isprefix= 16,
8 };
9 
10 uchar prefixvals[256] =
11 {
12 [0x00] 0 | Isprefix,
13 [0x80] 1 | Isprefix,
14 [0xC0] 2 | Isprefix,
15 [0xE0] 3 | Isprefix,
16 [0xF0] 4 | Isprefix,
17 [0xF8] 5 | Isprefix,
18 [0xFC] 6 | Isprefix,
19 [0xFE] 7 | Isprefix,
20 [0xFF] 8 | Isprefix,
21 };
22 
23 int
eipfmt(Fmt * f)24 eipfmt(Fmt *f)
25 {
26 	char buf[5*8];
27 	static char *efmt = "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux";
28 	static char *ifmt = "%d.%d.%d.%d";
29 	uchar *p, ip[16];
30 	ulong *lp;
31 	ushort s;
32 	int i, j, n, eln, eli;
33 
34 	switch(f->r) {
35 	case 'E':		/* Ethernet address */
36 		p = va_arg(f->args, uchar*);
37 		snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
38 		return fmtstrcpy(f, buf);
39 
40 	case 'I':		/* Ip address */
41 		p = va_arg(f->args, uchar*);
42 common:
43 		if(memcmp(p, v4prefix, 12) == 0){
44 			snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
45 			return fmtstrcpy(f, buf);
46 		}
47 
48 		/* find longest elision */
49 		eln = eli = -1;
50 		for(i = 0; i < 16; i += 2){
51 			for(j = i; j < 16; j += 2)
52 				if(p[j] != 0 || p[j+1] != 0)
53 					break;
54 			if(j > i && j - i > eln){
55 				eli = i;
56 				eln = j - i;
57 			}
58 		}
59 
60 		/* print with possible elision */
61 		n = 0;
62 		for(i = 0; i < 16; i += 2){
63 			if(i == eli){
64 				n += sprint(buf+n, "::");
65 				i += eln;
66 				if(i >= 16)
67 					break;
68 			} else if(i != 0)
69 				n += sprint(buf+n, ":");
70 			s = (p[i]<<8) + p[i+1];
71 			n += sprint(buf+n, "%ux", s);
72 		}
73 		return fmtstrcpy(f, buf);
74 
75 	case 'i':		/* v6 address as 4 longs */
76 		lp = va_arg(f->args, ulong*);
77 		for(i = 0; i < 4; i++)
78 			hnputl(ip+4*i, *lp++);
79 		p = ip;
80 		goto common;
81 
82 	case 'V':		/* v4 ip address */
83 		p = va_arg(f->args, uchar*);
84 		snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
85 		return fmtstrcpy(f, buf);
86 
87 	case 'M':		/* ip mask */
88 		p = va_arg(f->args, uchar*);
89 
90 		/* look for a prefix mask */
91 		for(i = 0; i < 16; i++)
92 			if(p[i] != 0xff)
93 				break;
94 		if(i < 16){
95 			if((prefixvals[p[i]] & Isprefix) == 0)
96 				goto common;
97 			for(j = i+1; j < 16; j++)
98 				if(p[j] != 0)
99 					goto common;
100 			n = 8*i + (prefixvals[p[i]] & ~Isprefix);
101 		} else
102 			n = 8*16;
103 
104 		/* got one, use /xx format */
105 		snprint(buf, sizeof buf, "/%d", n);
106 		return fmtstrcpy(f, buf);
107 	}
108 	return fmtstrcpy(f, "(eipfmt)");
109 }
110