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

#if defined(__GNUC__) && !defined(FORCED)
#include "unistd.h"
#else

char * optarg = NULL;
int opterr = 1;
int optind = 1;
int optopt = 0;

int _sp = 1;

int getopt(int argc, char * argv[], const char * opts)
{
  char c;
  char * cp;

  if (_sp == 1) {
    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
      return EOF;
    else if (strcmp(argv[optind], "--") == 0) {
      optind++;
      return EOF;
    }
  }
  
  optopt = c = (unsigned char)argv[optind][_sp];
  if (c == ':' || (cp = strchr(opts, c)) == NULL) {
    /* If 'getopt' detects a missing option it returns a question-mark (?)
     * character, if the application has not set the variable 'opterr' to
     * zero and the first character of 'opts' is not a colon, 'getopt' also
     * prints a diagnostic message to 'stderr'.
     */
    if (opterr && *opts != ':')
      fprintf(stderr, "%s: llegal option -- %c\n", argv[0], c);

    if (argv[optind][++_sp] == '\0') {
      optind++;
      _sp = 1;
    }
    return('?');
  }
  if (*++cp == ':') {
    if (argv[optind][_sp+1] != '\0')
      optarg = &argv[optind++][_sp+1];
    else if(++optind >= argc) {
    /* If 'getopt' detects a missing option-argument, it returns the colon
     * character (:) if the first character of 'opts' was a colon, or a
     * question-mark (?) character otherwise.  If the application has not set
     * the variable 'opterr' to zero and the first character of 'opts' is not
     * a colon, 'getopt' also prints a diagnostic message to 'stderr'.
     */
    optarg = NULL;
    if (*opts == ':') {
      _sp = 1;
      return(':');
    }
    if (opterr)
      fprintf(stderr, "%s: Option requires an argument -- %c\n", argv[0], c);
      _sp = 1;
      return('?');
    } else
      optarg = argv[optind++];
    _sp = 1;
  } else {
    if (argv[optind][++_sp] == '\0') {
      _sp = 1;
      optind++;
    }
    optarg = NULL;
  }
  return(c);
}

/*
 * reset everyting.
 * We opterr alone since thats already under user control
 */
void getoptreset(void)
{
  optind = 1;
  optarg = NULL;
  optopt = 0;
  _sp = 1;
}
#endif

/*!
 */
static void print_help(char * prog_name)
{
  printf("Usage: %s [options]\n\
  -h \t\t\tprint this help message\n\
  -i <integer>\t\tset the ineteger\n\
  -f <floating-point>\tset the floating point number\n\
  -s <string>\t\tset the string\n\
  -u <unsigned integer>\tset the unsigned integer\n\
  -v \t\t\ttoggle verbose\n", prog_name);
}


#if defined(_MSC_VER)
#define DIR_SEP '\\'
#else
#define DIR_SEP '/'
#endif

char option_str[] = "hf:i:s:u:v";

int main(int argc, char * argv[])
{
  int c;
  int integer = 0;
  double floating_point = 0.0;
  char * str = 0;
  unsigned int unsigned_integer = 0;
  int verbose = 0;
  
  char * prog_name = strrchr(argv[0], DIR_SEP);
  prog_name = (prog_name) ? prog_name+1 : argv[0];

  while ((c = getopt(argc, argv, option_str)) != EOF) {
    switch (c) {
     case 'h': print_help(prog_name); return 1;
     case 'i': integer = atoi(optarg); break;
     case 'f': floating_point = atof(optarg); break;
     case 's': str = optarg; break;
     case 'u': unsigned_integer = strtoul(optarg, 0, 0); break;
     case 'v': verbose = !verbose; break;

     default:
      fprintf(stderr, "Try `%s -h' for more information.\n", prog_name);
      return -1;
    }
  }

  if (verbose) {
    printf("%17s %d\n", "integer:", integer);
    printf("%17s %f\n", "floating point:", floating_point);
    printf("%17s 0x%x\n", "unsigned integer:", unsigned_integer);
    printf("%17s %s\n", "string:", (str) ? str : "");
    printf("\noptind: %d\n", optind);
  }
  return 0;
}
