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

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "argument.h"

static const char *delete_arg(int *argcp, char *argv[], int i)
{
  const char *ret;
  if (i > *argcp - 1)
    return NULL;
  ret = argv[i];
  (*argcp)--;
  for (; i < *argcp; i++)
    argv[i] = argv[i + 1];
  return ret;
}

static const argument_t *check_arg(int argc, char *argv[], int i,
				   const argument_t *args)
{
  int len;
  if (i > argc - 1)
    return NULL;
  for (; args->name; args++) {
    len = strlen(args->name);
    switch (args->name[len - 1]) {
    case '=':
      if (!strncmp(argv[i], args->name, len))
	return args;
      break;
    case ';':
      if (!strncmp(argv[i], args->name, len - 1))
	return args;
      break;
    default:
      if (!strcmp(argv[i], args->name))
	return args;
      break;
    }
  }
  return NULL;
}

int argument_read(int *argcp, char *argv[], const argument_t argument[], unsigned int flags)
{
  int i, len;
  const char *p;
  int n = 0;
  const argument_t *arg;

  i = 0;
  if (flags & ARGUMENT_IGNORE_FIRST)
    i++;

  for (; i < *argcp; i++) {
    while ((arg = check_arg(*argcp, argv, i, argument)) != NULL) {
      p = NULL;
      len = strlen(arg->name);
      switch (arg->name[len - 1]) {
      case '=': p = &argv[i][len]; break;
      case ';': p = &argv[i][len - 1]; break;
      default:
	break;
      }
      delete_arg(argcp, argv, i);
      n++;
      switch (arg->type) {
      case ARGUMENT_TYPE_NONE:
	/* None */
	break;
      case ARGUMENT_TYPE_FUNCTION:
	((void (*)())(arg->value))();
	break;
      case ARGUMENT_TYPE_FLAG_ON:
	*((int *)(arg->value)) = ARGUMENT_FLAG_ON;
	break;
      case ARGUMENT_TYPE_FLAG_OFF:
	*((int *)(arg->value)) = ARGUMENT_FLAG_OFF;
	break;
      case ARGUMENT_TYPE_INTEGER:
	if (p == NULL)
	  p = delete_arg(argcp, argv, i);
	if (p) *((int *)(arg->value)) = atoi(p);
	break;
#ifdef ARGUMENT_SUPPORT_FLOAT
      case ARGUMENT_TYPE_FLOAT:
	if (p == NULL)
	  p = delete_arg(argcp, argv, i);
	if (p) *((double *)(arg->value)) = atof(p);
	break;
#endif
      case ARGUMENT_TYPE_STRING:
	if (p == NULL)
	  p = delete_arg(argcp, argv, i);
	if (p) *((const char **)(arg->value)) = p;
	break;
      }
    }
    if (flags & ARGUMENT_NOTFOUND_BREAK)
      break;
  }

  if (flags & ARGUMENT_DELETE_REST) {
    while (*argcp > 1) {
      fprintf(stderr, "ERROR : Unknown Argument : %s\n", argv[1]);
      delete_arg(argcp, argv, 1);
    }
  }

  return n;
}
