// subnet calculator, version 1
// by Jacek Stanislawski <jacek@jacek-dom.net>

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

typedef int bool;
enum { false = 0 };

void usage(char *av)
{
	fprintf(stderr, "usage: %s ip[/bits]\nor:    %s ip [bits]\n", av, av);
	fprintf(stderr, "e.g.:\n%s 192.168.1.2/24\n", av);
	fprintf(stderr, "192.168.1.0/24 = 192.168.1.1 - 192.168.1.255\n");
}

void ip2dotted_decimal(int ip, int bytes[4])
{
	bytes[3] = (ip & 0xFF000000) >> 24;
	bytes[2] = (ip & 0x00FF0000) >> 16;
	bytes[1] = (ip & 0x0000FF00) >> 8;
	bytes[0] = (ip & 0x000000FF) >> 0;
}

void print_net_and_range(int ip, int bits, bool sparse)
{
	int shift, network, byte1, byte2, byte3, byte4, first_ip, last_ip;
	int net_bytes[4], first_ip_bytes[4], last_ip_bytes[4];
	
	shift = 32 - bits;
	network = (ip >> shift) << shift;
	ip2dotted_decimal(network, net_bytes);
	
	first_ip = network;// + 1;
	ip2dotted_decimal(first_ip, first_ip_bytes);
	
	last_ip = (((ip >> shift) + 1) << shift) - 1;// - 1
	ip2dotted_decimal(last_ip, last_ip_bytes);
	
	if (sparse)
	{
		for (int i = 3; i >= 0; i--)
			if (first_ip_bytes[i] == last_ip_bytes[i])
			{
				fprintf(stdout, "%d.", first_ip_bytes[i]);
			}
			else
			{
				if ((first_ip_bytes[i] != 0) || (last_ip_bytes[i] != 255))
				{
					fprintf(stdout, "%d-%d", first_ip_bytes[i], last_ip_bytes[i]);
					if (i > 0)
						fprintf(stdout, ".");
				}
				fprintf(stdout, "\n");
				break;
			}
	}
	else
	{
		fprintf(stdout, "%d.%d.%d.%d/%d = %d.%d.%d.%d - %d.%d.%d.%d\n",
						net_bytes[3], net_bytes[2], net_bytes[1], net_bytes[0], bits,
						first_ip_bytes[3], first_ip_bytes[2], first_ip_bytes[1], first_ip_bytes[0],
						last_ip_bytes[3], last_ip_bytes[2], last_ip_bytes[1], last_ip_bytes[0]);
	}
}

int main(int argc, char **argv)
{
	if(argc < 2) 
	{
		usage(argv[0]);
	 	return 1;
	}
	
	int byte1 = 0, byte2 = 0, byte3 = 0, byte4 = 0, bits = 0;
	int matched = sscanf(argv[1], "%d.%d.%d.%d/%d", &byte1, &byte2, &byte3, &byte4, &bits);
	switch (matched) {
		case 5: break;
		case 4: break;
		case 3: 
			matched = sscanf(argv[1], "%d.%d.%d/%d", &byte1, &byte2, &byte3, &bits);
			if (matched != 4 && matched != 3)
			{
				usage(argv[0]);
			 	return 1;
			}
			break;
		case 2:
			matched = sscanf(argv[1], "%d.%d/%d", &byte1, &byte2, &bits);
			if (matched != 3 && matched != 2)
			{
				usage(argv[0]);
			 	return 1;
			}
			break;
		case 1:
			matched = sscanf(argv[1], "%d/%d", &byte1, &bits);
			if (matched != 2 && matched != 1)
			{
				usage(argv[0]);
			 	return 1;
			}
			break;
			
	}
	int ip = byte4 + (byte3 << 8) + (byte2 << 16) + (byte1 << 24);
	//printf("ip: %x\n", ip);
	
	if (argc > 2)
		sscanf(argv[2], "%d", &bits);
	//printf("bits: %d\n", bits);
	
	if (bits > 0)
	{
		//printf("bits: %d\n", bits);
		print_net_and_range(ip, bits, (argc > 2) && (strcmp(argv[2], "-s") == 0));
	}
	else
	{
		for (bits = 8; bits <= 30; bits++)
		{
			//printf("ip: %d, bits: %d\n", ip, bits);
			print_net_and_range(ip, bits, false);
		}
	}
}
