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