/*****
 NAME
	coptparser.m - source code for COptParser class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/coptparser.h>
#include <coconut/carray.h>
#include <coconut/csystem.h>
#include <coconut/cerror.h>
#include <stdio.h>
#include <errno.h>

static void set_popt_option(struct poptOption *opt, const char * lname,
  char sname, int info, void * arg, int val, const char * desc,
  const char * argdesc) ;

@implementation COptParser

- init
{
	this_context = NULL ;
	this_array = [[CArray alloc] initArray: sizeof(struct poptOption)
	   dealloc: NULL]  ;
	return [super init] ;
}

- (void) dealloc
{
	if(this_context)
		poptFreeContext(this_context) ;
	[this_array release] ;
	[super dealloc] ;
}

- (id <PError>) defineOption: (arg_t) typ code:(int) code
    long_name: (const char *) lname short_name: (char) sname
    result: (void *) result
    desc: (const char *) desc arg_desc: (const char *) argdesc 
{
	struct poptOption opt ;
	set_popt_option(&opt, lname, sname, ARGT2POPT(typ),
	  result, code, desc, argdesc) ;
	[this_array append: &opt] ;
	return nil ;
}

- setCallbackFunc: (optparser_callback_func_t) func param: (void *) param
{
	struct poptOption opt ;
	set_popt_option(&opt, NULL, '\0', 
	  POPT_ARG_CALLBACK, func, 0, param, NULL) ;
	[this_array append: &opt] ;
	return nil ;
}

- includeOptions: (id <POptParser>) obj desc: (const char *) desc
{
	struct poptOption opt ;
	set_popt_option(&opt, NULL, '\0',
 	  POPT_ARG_INCLUDE_TABLE, [obj exportTable], 0, desc, NULL);
	[this_array append: &opt] ;
	return nil ;
}

- (id <PError>) setOnedashProperty
{
	struct poptOption * opt ;
	opt = (struct poptOption *) [this_array last] ;
	if(opt){
		opt->argInfo |= POPT_ARGFLAG_ONEDASH ;
		return nil ;
	} else
		return [CError not_exist] ;
}

- (id <PError>) setDocHiddenProperty
{
	struct poptOption * opt ;
	opt = (struct poptOption *) [this_array last] ;
	if(opt){
		opt->argInfo |= POPT_ARGFLAG_DOC_HIDDEN ;
		return nil ;
	} else
		return [CError not_exist] ;
}

- (id <PError>) setOptionalProperty
{
	struct poptOption * opt ;
	opt = (struct poptOption *) [this_array last] ;
	if(opt){
		opt->argInfo |= POPT_ARGFLAG_OPTIONAL ;
		return nil ;
	} else
		return [CError not_exist] ;
}

- (id <PError>) load: (const char *) filename
{
	if(poptReadConfigFile(this_context, filename) == 0){
		return nil ;
	} else {
		return [CError system: errno] ;
	}
}

- finishOption
{
	struct poptOption lastopt = { NULL, '\0', 0, NULL, 0 } ;
	return [this_array append: &lastopt] ;
}

- startAnalysis: (const char *) appname argc: (int) argc
    argv: (const char **) argv
{
	struct poptOption lastopts[] = {
		POPT_AUTOHELP
		{ NULL, '\0', 0, NULL, 0 }} ;
	struct poptOption * firstopt ;

	[this_array append: &lastopts[0]] ;
	[this_array append: &lastopts[1]] ;
	firstopt = (struct poptOption *) [this_array first] ;
	this_context = poptGetContext(appname, argc, argv, firstopt, 0) ;
	[CSystem checkPtr: this_context] ;
	return nil ;
}

- setHelpString: (const utf8_char *) msg
{
	if(msg){
		poptSetOtherOptionHelp(this_context, msg) ;
	}
	return nil ;
}

- resetAnalysis
{
	poptResetContext(this_context) ;
	return nil ;
}

- (int) nextOpt
{
	return poptGetNextOpt(this_context) ;
}

- (const char *) optArg
{
	return poptGetOptArg(this_context) ;
}

- (const char *) arg
{
	return poptGetArg(this_context) ;
}

- (const char **) allArgs
{
	return poptGetArgs(this_context) ;
}

- printHelp
{
	poptPrintHelp(this_context, stderr, 0) ;
	return nil ;
}

- printUsage
{
	poptPrintUsage(this_context, stderr, 0) ;
	return nil ;
}

- (int) getErrorMessage: (char *) buf size:(size_t) size code:(int) num
{
	const char * strerr ;
	const char * badopt ;
	char *	     bufstart ;
	char *	     bufend ;
	char	     c ;

	strerr = poptStrerror(num) ;
	badopt = poptBadOption(this_context, POPT_BADOPTION_NOALIAS);

	bufstart = buf ;
	for(bufend = buf + size - 1 ; buf < bufend ; buf++, strerr++){
		if((c = *strerr) == '\0')
			break ;
		else
			*buf = c ;
	}
	if(buf < bufend){
		*(buf++) = ':' ;
	}
	for( ; buf < bufend ; buf++, badopt++){
		if((c = *badopt) == '\0')
			break ;
		else
			*buf = c ;
	}
	*buf = '\0' ;
	return bufend - bufstart ;
}

- (void *) exportTable
{
	return (void *) [this_array first] ;
}

@end

static void set_popt_option(struct poptOption *opt, const char * lname,
  char sname, int info, void * arg, int val, const char * desc,
  const char * argdesc)
{
	opt->longName = lname ;
	opt->shortName = sname ;
	opt->argInfo = info ;
	opt->arg = arg ;
	opt->val = val ;
	opt->descrip = desc ;
	opt->argDescrip = argdesc ;
}

