#include <stdint.h>
#include <stdio.h>
#include <string.h>

typedef /*u*/int32_t ip;
typedef char ips[16];
typedef char ipb[3];

ip atoip(char *s) {
	ip ip = 0;
	if (*s == '/') {
		while (*++s)
			ip = ip * 10 + (*s - '0');
		ip = -1 >> ip - 1;
	} else while (*s) {
		if (*s == '.')
			ip <<= 8;
		else
			ip += (ip & 255) * 10 + *s - '0' - (ip & 255);
		++s;
	}
	return ip;
}

void spip(ips s, ip ip) {
	memset(s, ' ', sizeof (ips));
	s += sizeof (ips);
	char b;
	for (b = 0; b < 32; b += 8) {
		*--s = b ? '.' : 0;
		unsigned char c = ip >> b & 255;
		do {
			*--s = '0' + c % 10;
			c = (c - c % 10) / 10;
		} while (c > 0);
	}
}

void putip(ip ip) {
	ips ips; spip(ips, ip); puts(ips);
}

void snm2b(ipb s, ip netmask) {
	memset(s, ' ', sizeof (ipb));
	s += sizeof (ipb) - 1;
	*s = 0;
	char b = 0;
	while (netmask)
		netmask <<= 1, ++b;
	do {
		*--s = '0' + b % 10;
		b = (b - b % 10) / 10;
	} while (b > 0);
}

ip length_;
char **nv_;

// Subnet the network, one bit at a time
int subnet(ip network, ip netmask, char ***nv) {
	network &= netmask;
	if (!~netmask)
		return 0;
	
	ip length = ~netmask + 1;
	//printf("length1 : %u %u\n", length, network & length);
	
	int n = 0;
	if (**nv) {
		n = atoi(**nv) + 2;
		if (length >> 1 > n)
			return (subnet(network, netmask >> 1, nv) +
					subnet(network + (length >> 1), netmask >> 1, nv));
		if (length >= n) ++*nv;
		else n = 0;
	}
	
	//printf("length2 : %u %u\n", length, network & length);
	ips nws, nwf, nwl, nwb, nms;
	spip(nws, network);
	spip(nwf, network + 1);
	spip(nwl, network | ~netmask - 1);
	spip(nwb, network | ~netmask);
	spip(nms, netmask);
	ipb nbs;
	snm2b(nbs, netmask);
	printf("| %.3u | %s | %s | %s | %s | %s/%s | %u/%u hosts\n",
		   length, nws, nwf, nwl, nwb, nms, nbs, n ? n - 2 : 0, length - 2);
	
	return n;
}

int main(int argc, char *argv[]) {
	if (argc < 4) {
		puts("Usage : vlsm network netmask N...\n"
			 " network : IPv4 address (N.N.N.N)\n"
			 " network : IPv4 address (N.N.N.N)\n"
			 " N : Number of hosts in a network.");
		return 1;
	}
	
	//putip(atoip("1.22.255.23"));
	
	/*putip(atoip("255.255.255.0") >> 1);
	putip(~(atoip("255.255.255.0") >> 1));*/
	
	puts("+-----+-----------------+-----------------+-----------------+-----------------+--------------------+\n"
		 "|     |         network |            from |              to |       broadcast |            netmask |\n"
		 "+-----+-----------------+-----------------+-----------------+-----------------+--------------------+");
	
	char **nv = argv + 3;
	
	subnet(atoip(argv[1]), atoip(argv[2]), &nv);
	
	puts("+-----+-----------------+-----------------+-----------------+-----------------+--------------------+");
	
	return 0;
}
