/* program that prints IP address ranges */
#include "prips.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "except.h"

typedef enum {
	FORMAT_HEX = 0,
	FORMAT_DEC = 1,
	FORMAT_DOT = 2
} AddrFormat;

#define FORMATS "hex", "dec", "dot"

const char *MAINTAINER = "dan@vertekcorp.com";
const char *VERSION =
	"\rprips 0.9.4\n"\
"	\rThis program comes with NO WARRANTY,\n"\
"	\rto the extent permitted by law.\n"\
"	\rYou may redistribute copies under\n"\
"	\rthe terms of the GNU General Public License.\n";

void usage(char *prog);
AddrFormat get_format(char *format);

int main(int argc, char *argv[])
{
	char ch, *argstr = "d:f:i:e:cv";
	unsigned long start = 0, end = 0, current;
	int octet[4][256];	/* Holds all of the exceptions if -e is used */
	int format = FORMAT_DOT;	/* Dotted decimal by default */
	int delimiter = 10; 	/* New line by default */
	int increment = 1;	/* Standard incrementer is one */
	char *prefix, *offset;
	
	/* flags */
	int exception_flag = 0;	/* If one, check for exclusions */
	int print_as_cidr_flag= 0;	/* If one, print range as addr/offset */

	opterr = 0;
        while ((ch = getopt(argc, argv, argstr)) != EOF) {
                switch (ch) {
                case 'c':
			print_as_cidr_flag = 1;
			break;
                case 'd':
			delimiter = atoi(optarg);
			
			if(delimiter < 0 || delimiter > 255)
			{
				fprintf(stderr, "%s: delimiter must be between 0 and 255\n", 	
					argv[0]);
				exit(1);
			}
                        break;
		case 'f':
			format = get_format(optarg);
			break;
		case 'i':
			if((increment = atoi(optarg)) < 1)
			{
				fprintf(stderr, "%s: increment must be a positive integer\n",
					 argv[0]);
				exit(1);
			}
			break;
		case 'e':
			set_exceptions(optarg, octet);
			exception_flag = 1;
			break;
		case 'v':
			printf("%s", VERSION);
			exit(0);
		case '?':
			usage(argv[0]);
			exit(1);
		}
	}

	/*************************************************************/
	/* Figure out what we have to work with.  argc - optind is   */
 	/* the number of arguments we have.  If there is one argu-   */
	/* ment, we are dealing with CIDR, or a mistake.  If ther    */
	/* are two arguments, we are dealing with start address and  */
	/* end address.  We also make sure to test if the CIDR nota- */
	/* tion is proper.                                           */
	/*************************************************************/
	
	switch(argc - optind)
	{
	case 1: /* CIDR? */
		prefix = strtok(argv[optind], "/");
		
		if((offset = strtok(NULL, "/"))) /* CIDR */
		{
			start = numberize(prefix);
			if(start == -1)
			{
				fprintf(stderr, "%s: bad IP address\n", argv[0]);
				exit(1);
			}
			end = add_offset(prefix, atoi(offset));
		}
		else
		{
			usage(argv[0]);
			exit(1);
		}
		break;
	case 2: /* start address, end address */
	        start = numberize(argv[optind]);
                end = numberize(argv[optind+1]);
		if(start == -1 || end == -1)
		{		
			fprintf(stderr, "%s: bad IP address\n", argv[0]);
			exit(1);
		}
                break;
	default:
		usage(argv[0]);
		exit(1);
	}

	/***************************************************************/
	/* OK- at this point we have the start and end address.  If    */
	/* the start is greater than the end, we exit with an error.   */
	/* Otherwise, we start printing addresses that are not part of */
	/* the exception list, if one exists.                          */
	/***************************************************************/

	if(start > end)
	{
		fprintf(stderr, 
			"%s: start address must be smaller than end address\n",
			argv[0]);
		exit(1);
	}

	if(print_as_cidr_flag) /* print start - end as start/offset */ 
		printf("%s%c", cidrize(start, end), delimiter);
	else
	{
		for(current = start; current <= end; current += increment) 
		{	if(!exception_flag || !except(&current, octet))
			{
				switch(format)
				{
				case FORMAT_HEX:
					printf("%lx%c", current, delimiter);
					break;
				case FORMAT_DEC:
					printf("%lu%c", current, delimiter);
					break;
				default: 
					printf("%s%c", denumberize(current),
						delimiter);
					break;
				}
			}
		}
	}
	return(0);
} /* end main */

void usage(char *prog)
{
	fprintf(stderr, "usage: %s [options] <start end | CIDR block>\n"\
"	-c		print range in CIDR notation\n"\
"	-d <x>		set the delimeter 'x' where 0 =< x =< 255\n"\
"	-f <x> 		set the format of addresses (hex, dec, or dot)\n"\
"	-i <x>		set the increment to 'x'\n"\
"	-e <x.x.x,x.x>	e.g. -e ..4. will not print 192.168.4.[0-255]\n\n"\
"	\rReport bugs to %s\n",
			prog, MAINTAINER);
}

AddrFormat get_format(char *format)
{
	char *list[] = {FORMATS};
	int i;

	for (i = 0; i < 3; i++)
		if( strcmp(format, list[i]) == 0)
			break;
	return(i);
}	


syntax highlighted by Code2HTML, v. 0.9.1