/******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation
 * All rights reserved.
 * This program and the accompanying materials
 * are made available under the terms of the BSD License
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/bsd-license.php
 *
 * Contributors:
 *     IBM Corporation - initial implementation
 *****************************************************************************/

#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "args.h"

/**
 * Returns pointer of the n'th argument within a string.
 *
 * @param  arg_str    string with arguments, separated with ','
 * @param  index      index of the requested arguments within arg_str
 * @return            pointer of argument[index] on success
 *                    NULL if index is out of range
 */
const char *
get_arg_ptr(const char *arg_str, unsigned int index)
{
	unsigned int i;

	for (i = 0; i < index; ++i) {
		for (; *arg_str != ',' && *arg_str != 0; ++arg_str);
		if (*arg_str == 0)
			return 0;
		++arg_str;
	}
	return arg_str;
}

/**
 * Returns number of arguments within a string.
 *
 * @param  arg_str    string with arguments, separated with ','
 * @return            number of arguments
 */
unsigned int
get_args_count(const char *arg_str)
{
	unsigned int count = 1;

	while ((arg_str = get_arg_ptr(arg_str, 1)) != 0)
		++count;
	return count;
}

/**
 * Returns the length of the first argument.
 *
 * @param  arg_str    string with arguments, separated with ','
 * @return            length of first argument
 */
unsigned int
get_arg_length(const char *arg_str)
{
	unsigned int i;

	for (i = 0; *arg_str != ',' && *arg_str != 0; ++i)
		++arg_str;
	return i;
}

/**
 * Copy the n'th argument within a string into a buffer in respect
 * to a limited buffer size
 *
 * @param  arg_str    string with arguments, separated with ','
 * @param  index      index of the requested arguments within arg_str
 * @param  buffer     pointer to the buffer
 * @param  length     size of the buffer
 * @return            pointer of buffer on success
 *                    NULL if index is out of range.
 */
char *
argncpy(const char *arg_str, unsigned int index, char *buffer,
	unsigned int length)
{
	const char *ptr = get_arg_ptr(arg_str, index);
	unsigned int len;

	if (!ptr)
		return 0;
	len = get_arg_length(ptr);
	if (!strncpy(buffer, ptr, length))
		return 0;
	buffer[len] = 0;
	return buffer;
}

/**
 * Converts "255.255.255.255\nn" -> char[4] = { 0xff, 0xff, 0xff, 0xff }
 *                                  *netmask = subnet_netmask(nn)
 *
 * @param  str        string to be converted
 * @param  ip         in case of SUCCESS - 32-bit long IP
 *                    in case of FAULT - zero
 * @param  netmask    return netmask if there is a valid /nn encoding in IP
 * @return            TRUE - IP converted successfully;
 *                    FALSE - error condition occurs (e.g. bad format)
 */
int
strtoip_netmask(const char *str, char ip[4], unsigned int *netmask)
{
	char octet[10];
	int res;
	unsigned int i = 0, len, has_nn = 0;

	while (*str != 0) {
		if (i > 3 || !isdigit(*str))
			return 0;
		if (strstr(str, ".") != NULL) {
			len = (int16_t) (strstr(str, ".") - str);
			if (len >= 10)
				return 0;
			strncpy(octet, str, len);
			octet[len] = 0;
			str += len;
		} else if (strchr(str, '\\') != NULL) {
			len = (short) (strchr(str, '\\') - str);
			if (len >= 10)
				return 0;
			strncpy(octet, str, len);
			octet[len] = 0;
			str += len;
			has_nn = 1;
		} else {
			strncpy(octet, str, 9);
			octet[9] = 0;
			str += strlen(octet);
		}
		res = strtol(octet, NULL, 10);
		if ((res > 255) || (res < 0))
			return 0;
		ip[i] = (char) res;
		i++;
		if (*str == '.')
			str++;
		if(has_nn) {
			str++;
			strncpy(octet, str, 9);
			octet[9] = 0;
			res = strtol(octet, NULL, 10);
			str += strlen(octet);
			if (res > 31 || res < 1)
				return 0;
			if (netmask)
				*netmask = 0xFFFFFFFF << (32 - res);
		}
	}

	if (i != 4)
		return 0;
	return -1;
}

/**
 * Converts "255.255.255.255" -> char[4] = { 0xff, 0xff, 0xff, 0xff }
 *
 * @param  str        string to be converted
 * @param  ip         in case of SUCCESS - 32-bit long IP
 *                    in case of FAULT - zero
 * @return            TRUE - IP converted successfully;
 *                    FALSE - error condition occurs (e.g. bad format)
 */
int
strtoip(const char *str, char ip[4])
{
	return strtoip_netmask(str, ip, NULL);
}
