#define _PROCESS_0	/* those two are only for the debugging stuff */

#undef DEBUG
#undef DBGLVL

#include "includes.h"

#include "parseopts.h"


/*
 Completely unoptimized, as the shorter time using "C", the better for
 mental sanity.
*/


/********************** The Generic Option parser... **********************/

/*
Features:

Unsupported yet:
 * argument list in a file for use under systems with small command line
  (=MSDOS)

Not to be supported:
 * po_argv[0] is name under which we are called. If some macro is defined,
 it should be scanned, so that the program adapts its behavior according to
 it (example: gzip/gunzip/zcat, bash/sh, rlogin/target.machine.name, rz/rx/rb,
 mtools/mdir/mcopy/... etc).
   We assume this is already done when Parse_Options is called
*/



/****************** Option parsing variables *************************/

int	po_argc ;			/* main()'s argc argument */
char**	po_argv ;			/* main()'s argv argument */

int	po_arg_idx ;			/* current argument */
char*	po_arg_p ;			/* char in argument */
int	po_argument_forgotten ;		/* boolean: argument has (just) been */


/******************* Help for Parsing Options *********************/

void po_forget_argument (void) {
  int i;
  
  ___(9,"forgetting argument \"%s\"; %d arguments remaining.\n", \
      po_argv[po_arg_idx],po_argc-2);

  --po_argc;			/* no sanity check done ! */
  for (i=po_arg_idx;i<po_argc;i++) {
    po_argv[i]=po_argv[i+1] ;
  }
  po_arg_p=po_argv[po_arg_idx];
  po_argument_forgotten = 1 ;
}

void po_forget_argument_character () {

  ___(10,"forgetting argument character \"%c\"\n", *po_arg_p) ;
  po_arg_p++ ;
  if(*po_arg_p) po_argv[po_arg_idx]=po_arg_p ;
  else	    po_forget_argument () ;
}



/******************** The main function ***************************/

void Parse_Options (int *  argc, char *  argv[],
		    po_option  options []) {

  po_option *op ;

  po_argc=*argc; po_argv=argv;

#ifdef FIRST_SCANNED_OPTION
 Not used here. Not implemented yet.
#endif

  if(DBGLVL>=7) {
    int i ;
    ___(7,"Parsing %d parameters:",po_argc-1) ;
    for (i=1;i<po_argc;i++) {
      fprintf(stderr," %s",po_argv[i]) ;
    }
    fprintf(stderr,"\n") ;
  }

  po_arg_idx=1;
  while (po_arg_idx<po_argc) {
    po_argument_forgotten = 0 ;
    po_arg_p=po_argv[po_arg_idx] ;
    ___(8,"Testing parameter \"%s\".\n",po_arg_p) ;
    if ( (*po_arg_p=='-') && (po_arg_p[1]!=0) )
	/* (!) just '-' means stdin/out */
      {
	___(9,"It's an option !\n") ;
        if ( po_arg_p[1]=='-')
	  {
	    ___(11,"Accepting a long named option:\n") ;
	    po_arg_p++ ;
            if (*(++po_arg_p)==0) { po_forget_argument () ; return ; }
						/* end of options */
	    for (op=options;op->action;op++)	/* longnamed option */
	      {
		___(11,"comparing to option \"--%s\".\n",op->longname) ;
		if (!strcmp(po_arg_p,op->longname))
		  {
		    ___(10,"Found option --%s.\n",po_arg_p) ;
		    po_forget_argument () ;
		    (op->action)(op->actionarg) ;
		    goto parseopt_lfound ;
		  }
	      }
	    fprintf(stderr,"Unknown option --%s !\n"
		           "Use option --help for help.\n",
		    po_arg_p) ;
	    exit(100) ;
	  parseopt_lfound:
	  }
	else
	  {
	    po_forget_argument_character () ;
	    ___(11,"Accepting valid switches:\n") ;
	    while (!po_argument_forgotten) {
	      for (op=options;op->action;op++)		/* switch options */
		{
		  ___(11,"comparing to switch \"-%c\".\n",op->switchar) ;
		  if (*po_arg_p==op->switchar)
		    {
		      ___(10,"Found switch -%s.\n",po_arg_p) ;
		      po_forget_argument_character () ;
		      (op->action)(op->actionarg) ;
		      goto parseopt_found ;
		    }
		}
	      fprintf(stderr,"Unknown option -%c !\n"
		             "Use option -h or -? for help.\n",
		      *po_arg_p) ;
	      /* maybe should call prhelp(), but then prhelp() should be
	       * able to exit(100) instead of exit(0)
	       */
	      exit(100) ;
	    parseopt_found:
	    }
	  }
      }
    else /* not an option */
      {
	___(8,"It's not an option, but a regular parameter.\n");
	po_arg_idx++ ; /* or we could stop parsing */
      }
  }
  *argc=po_argc ;

  if(DBGLVL>=7) {
    int i ;
    ___(7,"Left %d parameters:",po_argc-1) ;
    for (i=1;i<po_argc;i++) {
      fprintf(stderr," %s",po_argv[i]) ;
    }
    fprintf(stderr,"\n") ;
  }

}


/******************* Help for Option actions *********************/

void * po_SetNULL (void ** dest) {
  return *dest = NULL ;
}

char * po_Parse_String_Arg (char ** dest) {
  if (!*po_arg_p)
    {
      if (!(po_arg_idx<po_argc))
	{
	  fprintf(stderr,"Option %c needs an argument",*po_arg_p) ;
	  exit(100) ;
	};
      po_forget_argument () ;
    }
  ___(9,"Got string argument \"%s\" for the option.\n",po_arg_p) ;
  if(dest) *dest=po_arg_p ;
  return po_arg_p ;
}



/*************** Stand Alone Option actions *********************/

void Nop (void) {
  ___(10,"Nop !\n") ;
}

