/*
  File autogenerated by [@$og{name}@] version [@$OptGenVersion@]
  generated with the following command:
  [@$CMDLINE@]

  The developers of [@$og{name}@] consider the fixed text that goes in all
  [@$og{name}@] output files to be in the public domain:
  we make no copyright claims on it.
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* If we use autoconf.  */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* Check for configure's getopt check result.  */
#ifndef HAVE_GETOPT_LONG
#include "getopt.h"
#else
#include <getopt.h>
#endif

#ifndef HAVE_STRDUP
#define strdup gengetopt_strdup
#endif /* HAVE_STRDUP */

#include "[@$og{filename}@].h"


void
[@$og{funcname}@]_print_version (void)
{
  printf ("%s %s\n", PACKAGE, VERSION);
}

void
[@$og{funcname}@]_print_help (void)
{
  [@$og{funcname}@]_print_version ();
  [@
   #//-- intro: purpose
   $OUT .= join("\n  ",
		q{printf("\n");},
		q{printf("Purpose:\n");},
		sprintf("printf(\"  %s\\n\");",
			defined($og{purpose}) ? $og{purpose} : "???"),
		q{printf("\n");},
	       );

  @]
  [@

   #// -- intro: usage
   $OUT .= ("\n  ".'printf("Usage: %s');
   #// -- intro: usage: options?
   if (@{$og{optl}}) {
     $OUT .= ' [OPTIONS]...';
   }
   #// -- intro: usage: argument names
   if ($og{unnamed}) {
     if (@{$og{args}}) {
       $OUT .= join("", map { " $_->{name}" } @{$og{args}});
     } else {
       $OUT .= " [FILES]...";
     }
   }
   $OUT .= '\n", PACKAGE);';

  @]
  [@

   #// -- summary: argument descriptions
   if ($og{unnamed} && @{$og{args}}) {
     my ($arg,$maxarglen);
     #// -- get argument field-lengths
     foreach $arg (@{$og{args}}) {
      $maxarglen = length($arg->{name})
	if (!defined($maxarglen) || $maxarglen < length($arg));
     }
     $OUT .= ("\n  "
	      .join("\n  ",
		    q{printf("\n");},
		    q{printf(" Arguments:\n");},
		    map {
		    ("printf(\""
		     .sprintf("   %-${maxarglen}s  %s", $_->{name}, $_->{descr})
		     .'\n");'),
		    } @{$og{args}}));
   }
   '';
  @]
  [@

    #// -- summary: option descriptions
    if (@{$og{optl}}) {
      #// -- get option field-lengths
      my ($optid,$opt,$maxshortlen,$maxlonglen,$oshortlen,$olonglen);
      my ($short,$long,$descr);
      foreach $opt (values(%{$og{opth}})) {
	$oshortlen = defined($opt->{short}) ? 2 : 0;
	$olonglen = defined($opt->{long}) ? length($opt->{long}) : 0;
	if ($opt->{arg}) {
	  $oshortlen += length($opt->{arg});
	  $olonglen += 1+length($opt->{arg});
	}
	$maxshortlen = $oshortlen
	  if (!defined($maxshortlen) || $maxshortlen < $oshortlen);
	$maxlonglen = $olonglen
	  if (!defined($maxlonglen) || $maxlonglen < $olonglen);
      }
      #// -- print option summary
      my $group = '';
      foreach $optid (@{$og{optl}}) {
	$opt = $og{opth}{$optid};
	if ($opt->{group} ne $group) {
          #// -- print group header
	  $group = $opt->{group};
	  $OUT .= ("\n  ".'printf("\n");'
		   ."\n  ".'printf(" '.$group.':\n");');
	}
        #// -- print option
	$short = $long = $descr = '';
	if (defined($opt->{short}) && $opt->{short} ne '-') {
	  $short = "-$opt->{short}";
	  $short .= $opt->{arg} if (defined($opt->{arg}));
	}
	if (defined($opt->{long}) && $opt->{long} ne '-') {
	  $long = $opt->{long};
	  $long =~ s/^\"//;
	  $long =~ s/\"$//;
	  $long = '--'.$long;
	  $long .= '='.$opt->{arg} if (defined($opt->{arg}));
	}
	next if ($short eq '' && !$og{longhelp});
	$OUT .= ("\n  "
		 .'printf("   '
		 .sprintf("%-${maxshortlen}s", $short)
		 .($og{longhelp} ? sprintf("  %-${maxlonglen}s", $long) : '')
		 .'  '.$opt->{descr}
		 .'\n");');
      }
    }
  @]
}

/* gengetopt_strdup(): automatically generated from strdup.c. */
/* strdup.c replacement of strdup, which is not standard */
static char *
gengetopt_strdup (const char *s)
{
  char *result = (char*)malloc(strlen(s) + 1);
  if (result == (char*)0)
    return (char*)0;
  strcpy(result, s);
  return result;
}


int
[@$og{funcname}@] (int argc, char * const *argv, struct [@$og{structname}@] *args_info)
{
  int c;	/* Character of the parsed option.  */
  int missing_required_options = 0;	

  [@
   join("\n  ",
	(map {
	  my $opt = $og{opth}{$_};
	  (defined($opt->{cgiven})
	   ? ("args_info-\>".$opt->{cgiven}." = 0;")
	   : qw())
         } @{$og{optl}}));
  @]

#define clear_args() { [@
   foreach my $optid (@{$og{optl}}) {
     my $opt = $og{opth}{$optid};
     next if (!defined($opt->{cname}));
     next if ($opt->{type} eq 'funct');
     $OUT .= "\\\n  ".'args_info->'.$opt->{cname}.' = ';
     if ($opt->{type} eq 'string') {
       $OUT .= (defined($opt->{default}) && $opt->{default} ne 'NULL'
		? "strdup($opt->{default})" : 'NULL');
     } else {
       $OUT .= (defined($opt->{default}) ? $opt->{default} : '0');
     }
     $OUT .= '; ';
   }
  @] \
}

  clear_args();

  optarg = 0;
  optind = 1;
  opterr = 1;
  optopt = '?';

  while (1)
    {
      int option_index = 0;
      static struct option long_options[] = {
	[@
	 join("\n	",
	       map {
		 my $opt = $og{opth}{$_};
		 (defined($opt->{long})
		  ? ('{ '.$opt->{long}.', '
		     .(defined($opt->{arg}) ? '1' : '0')
		     .', NULL, '
		     .(defined($opt->{short}) && $opt->{short} ne '-'
		       ? "'$opt->{short}'"
		       : 0)
		     .' },')
		  : qw())
	       } @{$og{optl}});
	@]
        { NULL,	0, NULL, 0 }
      };
      static char short_options[] = {
	[@
	 my $oval = 
	 join("\n	",
	       map {
		 my $opt = $og{opth}{$_};
		 (defined($opt->{short}) && $opt->{short} ne '-'
		  ? ("'$opt->{short}',"
		     .(defined($opt->{arg}) ? " ':'," : ''))
		  : qw())
	       } @{$og{optl}});
	@]
	'\0'
      };

      c = getopt_long (argc, argv, short_options, long_options, &option_index);

      if (c == -1) break;	/* Exit from `while (1)' loop.  */

      switch (c)
        {
	[@
	 my $error_action = $og{handle_error} ? 'exit' : 'return';
	 $og->{error_action} = $error_action;
	 my $indent = "        ";
	 my $zerocase = "case 0:\t /* Long option(s) with no short form */\n$indent";
	 my $gotlongonly = 0;
	 foreach my $optid (@{$og{optl}}) {
	   my $opt = $og{opth}{$optid};
	   my ($short,$long,$descr) = @$opt{qw(short long descr)};
	   $long = undef if ($long && $long eq '-');
	   $short = undef if ($short && $short eq '-');
	   my $oval = '';

	   $indent = "        ";
	   if (defined($short)) {
	     $oval .= "case '$short':\t /* $opt->{descr} */" ."\n$indent";
	   }
	   else {
	     $indent .= '  ';
	     $oval .= ("  /* $descr */\n$indent"
		       .($gotlongonly ? 'else ' : '')
		       .'if (strcmp(long_options[option_index].name, '
		       .$long.') == 0) {'."\n$indent");
	   }

	   if ($og{reparse_action} ne 'ignore') {
	     $oval .= ('  if (args_info->'.$opt->{cgiven}.') {'."\n$indent"
		      .'    fprintf(stderr, "%s:'
		      .(defined($long) ? (" \`--".OptGen::string_value($long)."'") : '')
		      .(defined($short) ? " (\`-$short\')" : '')
		      .' option given more than once\n", PACKAGE);'."\n$indent");
	     if ($og{reparse_action} eq 'error') {
	       $oval .= ('    clear_args();'."\n$indent"
			."    $error_action (EXIT_FAILURE);\n$indent");
	     }
	     $oval .= "  }\n$indent";
	   }

	   if ($opt->{ishelp} && $og{handle_help}) {
	     #// -- auto-help
	     $oval .= ('  clear_args();'."\n$indent"
		      .'  '.$og{funcname}.'_print_help();'."\n$indent"
		      .'  exit(EXIT_SUCCESS);'."\n\n$indent");
	   }
	   elsif ($opt->{isversion} && $og{handle_version}) {
	     #// -- auto-version
	     $oval .= ('  clear_args();'."\n$indent"
		      .'  '.$og{funcname}.'_print_version();'."\n$indent"
		      .'  exit(EXIT_SUCCESS);'."\n\n$indent");
	   }
	   else {  #// -- it's not an auto-handled option
	     #// -- always add a 'given' flag
	     $oval .= ('  args_info->'.$opt->{cgiven}.' = 1;'."\n$indent");

	     if ($opt->{type} eq 'funct') {
               #// -- boolean ("function") options : nothing more here
	       ;
	     }
	     elsif ($opt->{type} eq 'flag') {
               #// -- toggle ("flag") options
	       $oval .= ('  args_info->'.$opt->{cname}
			.' = !(args_info->'.$opt->{cname}.');'
			."\n$indent");
	     }
	     elsif ($opt->{type} eq 'string') {
	       #// -- string-argument options
	       $oval .= '  args_info->'.$opt->{cname}." = strdup(optarg);\n$indent";
	     }
	     elsif ($opt->{type} eq 'int'
		    || $opt->{type} eq 'short'
		    || $opt->{type} eq 'long')
	       {
		 $oval .= ('  args_info->'.$opt->{cname}
			  ." = ($opt->{type})atoi(optarg);\n$indent");
	       }
	     elsif ($opt->{type} eq 'float'
		    || $opt->{type} eq 'double'
		    || $opt->{type} eq 'longdouble')
	       {
		 $oval .= ('  args_info->'.$opt->{cname}
			  ." = ($opt->{type})strtod(optarg, NULL);\n$indent");
	       }
	   }
	   if (defined($short)) {
             #// -- add a break statement
	     $OUT .= $oval . "  break;\n\n$indent";
	   } else {
	     #// -- close the conditional-braces
	     $indent =~ s/  $//;
	     $zerocase .= $oval . "}\n$indent";
	     $gotlongonly = 1;
	   }
	 }
         #// -- add zero-case (long w/o short)
	 $OUT .= ($zerocase."  break;\n\n$indent"
		  .(#//-- add invalid-case
		    "case '?':\t /* Invalid Option */\n$indent"
		    ."  /* \`getopt_long\' already printed an error message. */\n$indent"
		    .'  '.$error_action.' (EXIT_FAILURE);'."\n"));
	@]

        default:	/* bug: options not considered.  */
          fprintf (stderr, "%s: option unknown: %c\n", PACKAGE, c);
          abort ();
        } /* switch */
    } /* while */

  [@
   #// -- check for missing required options
   foreach my $optid (@{$og{optl}}) {
     my $opt = $og{opth}{$optid};
     next if (!$opt->{required});
     my ($long,$short) = @$opt{qw(long short)};
     $long = undef if ($long && $long eq '-');
     $short = undef if ($short && $short eq '-');
     $OUT .= ('if (!args_info->'.$opt->{cgiven}.') {'."\n"
	      .'    fprintf(stderr, "%s:'
	      .(defined($long) ? (" \`--".OptGen::string_value($long)."'") : '')
	      .(defined($short) ? " (\`-$short\')" : '')
	      .' option required\n", PACKAGE);'."\n"
	      ."    missing_required_options = 1;\n"
	      ."  }\n  ");
   }
  @]

  if ( missing_required_options )
    [@ $og{handle_error} ? 'exit' : 'return'  @] (EXIT_FAILURE);

  [@
   $og{unnamed} ? '
  if (optind < argc) {
      int i = 0 ;
      args_info->inputs_num = argc - optind ;
      args_info->inputs = (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ;
      while (optind < argc)
        args_info->inputs[ i++ ] = strdup (argv[optind++]) ; 
  }' : '';
  @]

  return 0;
}
