]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libip/eipfmt.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / libip / eipfmt.c
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
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 }