#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;
}

// string print 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);
}

// string netmask to bit
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);
}

int i10len(int i) {
	int len = 0;
	while (i)
		i /= 10, ++len;
	return len;
}

ip length_;
char **nv_;

// Subnet the network, one bit at a time
int subnet(ip network, ip netmask) {
	network &= netmask;
	if (!~netmask)
		return 0;
	ip length = ~netmask + 1;
	
	int n = 0;
	if (*nv_) {
		n = atoi(*nv_) + 2;
		if (length >> 1 > n)
			return (subnet(network, netmask >> 1) +
					subnet(network + (length >> 1), netmask >> 1));
		if (length >= n) ++nv_;
		else n = 0;
	}
	
	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("| %s | %s | %s | %s | %s/%s | %*u | %u/%u hosts\n",
		   nws, nwf, nwl, nwb, nms, nbs, i10len(length_), length, 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"
		 "+-----------------+-----------------+-----------------+-----------------+--------------------+");
	
	ip network = atoip(argv[1]);
	ip netmask = atoip(argv[2]);
	length_ = ~netmask + 1;
	nv_ = argv + 3;
	
	subnet(network, netmask);
	
	puts("+-----------------+-----------------+-----------------+-----------------+--------------------+");
	
	return 0;
}
