/*---------------------------------------------------------------*/
/*   Copyright (c) 1988 Regents of the University of California  */
/*                 All Rights Reserved                           */
/*---------------------------------------------------------------*/
/*
      @(#)getcmd.c	1.6  (UCLA, IGPP) 20 Apr 1994 
 */
#include <stdio.h>
#include <string.h>
#include "pipec.h"

/* -- GETCMDLINEOPT --------------------------------------------------------- */
/*                                                                            */
/* This function reads the next option from the command line or an options    */
/* file.  Options are assumed to be in the form OPTION=value.  If the option  */
/* read is OPTFILE, an options file is opened and the first command is read.  */
/* If the option is PREFIX, the prefix for the options file is set and the    */
/* next option is read.  Except for the declarations in the include file,     */
/* handling of options files and prefixes is transparent to the program       */
/* calling this function. If an option is unknown or ambiguous then the       */
/* argument is reconstructed and passed back as the value. Thus allow the     */
/* the calling routine to use the information.                                */
/*                                                                            */
/* NOTE:  initpipe should be called once before this function is called.      */
/* NOTE:  CMDFILE is synonymous with OPTFILE for backwards compatibility.     */
/*                                                                            */
/* ENTRY REQUIREMENTS:                                                        */
/*	argc:		the number of arguments in argv.                      */
/*	argv:		an array of pointers to the command line arguments.   */
/*	options:	the array of names of command line options            */
/*	value:		the value for the option read is returned through     */
/*			this variable.  ("" returned if no value read)        */
/*      p_mesg:		Controls whether messages are printed for non-fatal   */
/*			errors. At present this applies to ambiguous and      */
/*			unknown keyword errors. If true messages are printed  */
/*			Otherwise they are not.                               */
/*                                                                            */
/* RETURN VALUES:                                                             */
/*	* The index of the element in the options array corresponding to the  */
/*	  option read                                                         */
/*      * -1 returned if there were no more arguments left to read.           */
/*                                                                            */
/*	Development History:                                                  */
/*		Begun:  7/24/86 - Marco Zagha                                 */
/*                  Under GG44 support.                                       */
/*		Additions: 8/12/86 - Todd King                                */
/*                  Under GH06 support.                                       */
/*		Additions: 9/30/86 - Todd King (fix non-equate core dump)     */
/*                  Under GH06 support.                                       */
/*		Additions: 2/24/87 - Marco Zagha (_BP_LINE option)            */
/*                  Under GG44 support.                                       */
/*              Modified: 4/15/87 - Todd King                                 */
/*                        Have 'pdbArgNumber' reset to 1 when last entry      */
/*                        is encountered. This allows this function to be     */
/*                        called multiple times.                              */
/*                  Under GH06 support.                                       */
/*		Additions: 4/26/88 - Marco Zagha (unquoting added)            */
/*                  Under GY49 support.                                       */
/*                                                                            */
/*              Modified: 03/23/94 - Gilbert Hyatt                            */
/*                          Now slips NULL in argument list                   */ 
/*              Edited:   04/14/94 - Gilbert Hyatt   */
/*                          Now uses pipec.h as entry point  into the library.*/
/* -------------------------------------------------------------------------- */

_GetCmdlineOpt(argc, argv, options, value, p_mesg)
  int argc;
  char *argv[];
  char *options[];
  char value[];
  unsigned p_mesg;
{
#include "cmdlineext.h"

#define NONELEFT	-1  /* Return codes                  */
#define BADMATCH		 0  /*             for this function */
#define ENDOFFILE	-1  /* Return codes                  */
#define ERROR		 0  /*              from rcomfile    */
#define UNKNOWN   	-1  /* Return codes                  */
#define AMBIGUOUS	-2  /*              from kwmatch     */

  extern char Sbuffer[];

  unsigned int OptionRead, done;
  char hold_part[MAXOPTLEN];
  char kw_list[50];
  char *possible[5];
  char *part[2];
  int ret, match, result;

/* PRESETS */
  strcpy(kw_list, "OPTFILE CMDFILE PREFIX _BP_LINE ");
  parse(kw_list, possible, " ", 5);

  if (pdbArgNumber == 1) getbpline(argc, argv);
  for (OptionRead = FALSE; !OptionRead; )
  {
    for (done = FALSE; !done; )
      if (pdboptfile) /* read commands from command file */
       {
	result = rcomfile(pdbcomfile, Sbuffer, MAXLENGTH, ":",
			  pdbprefix, pdbchk_prefix);
	if (result == ERROR) getcmdexit(argv, 0, pdbOptName);
	else if (result == ENDOFFILE)
	{
	  fclose(pdbcomfile);
	  pdboptfile = FALSE;
	}
	else done = TRUE;
       }
      else 
       {
	  done = TRUE;
          while(argv[pdbArgNumber] == NULL) pdbArgNumber++;
	  if (pdbArgNumber >= argc)
	    {
	      strcpy(value, "");
	      pdbArgNumber = 1;
	      return NONELEFT;
	    }
	  else strcpy(Sbuffer, argv[pdbArgNumber++]);
       }

    strncpy(hold_part,Sbuffer,MAXOPTLEN);  /* Save incase its unknown */
    part[0]="";
    part[1]="";
    parse(Sbuffer, part, "=", 2);
    trimspc(part[0]);
    trimspc(part[1]);
    unquote2(part[1]);
    scaseup(part[0]);  /* Upper case standard for keywords */
    match = kw_match(part[0], possible);
    ret = kw_match(part[0], options);
    /* Exit if no match in either set of keywords */
    if (ret == UNKNOWN && match == UNKNOWN)
     {
       if(p_mesg) getcmdexit(argv, 3,part[0]);
       strcpy(value,hold_part);		/* Pass whole argument */
       return BADMATCH;
     }
    /* Exit if ambiguous keyword or more than one match */
    if (ret == AMBIGUOUS || match == AMBIGUOUS || (ret >= 0 && match >= 0))
     {
       if((p_mesg) && (strlen(part[0])>0)) getcmdexit(argv, 2, part[0]);
       strcpy(value,hold_part);		/* Reconstruct equate */
       strcat(value,"=");
       strcat(value, part[1]);
       return BADMATCH;
     }

/* NOTE: chaining command files is not allowed */
    if (match == 0 || match == 1)
	{
	  if (!pdboptfile)
	  {  strcpy(pdbOptName, part[1]);
	     if ((pdbcomfile=fopen(pdbOptName,"r")) == NULL) 
			getcmdexit(argv, 1, pdbOptName);
	     pdboptfile = TRUE; 
	  }
	}
    else if (match == 2)
	{
	  strcpy(pdbprefix,part[1]);  /* PREFIX keyword */
	  scaseup(pdbprefix);         /* standardize */
	  pdbchk_prefix = TRUE;
	}
    else if (match == 3)
	  ; /* skip _BP_LINE keyword */
    else        
	{
	  OptionRead = TRUE;
	  strcpy(value, part[1]);
	  return (ret + 1);
	}
  }
}


/* -- GETCMDEXIT ------------------------------------------------------------ */
/* Subroutine to print an error message with a filler and exit the program.   */
/* The fitting name is extracted from argv[0].  The path is stripped off the  */
/* fitting name.                                                              */
/*                                                                            */
/*                                                                            */
/* ENTRY REQUIREMENTS:                                                        */
/*	argv:    the command line arguments from the program.                 */
/*	errnum:  an integer code for an error message.                        */
/*	filler:  a string which is part of the error message.                 */
/*                                                                            */
/*	Fill in:                                                              */
/*		a) the correct value for NumErrors                            */
/*		b) the individual error messages (put @ everywhere filler     */
/*                 should appear and end all fatal errors with '!')           */
/*                                                                            */
/*	Development History:                                                  */
/*		Begun:  7/16/86 - Marco Zagha                                 */
/*                                                                            */
/* -------------------------------------------------------------------------- */

static int
getcmdexit(argv, err_num, filler)
char *argv[];
int err_num;
char filler[];
{
#define NumErrors	4

  int start;
  char fitting[50];
  char tempstr[150];
  char *error[NumErrors];

  strcpy(tempstr, argv[0]);

  for (start = strlen(tempstr)-1; start > 0 && tempstr[start] != '/'; start--)
    ; /* Find the last slash in tempstr */

  if (tempstr[start] == '/') start = start + 1;

  strcpy(fitting, &tempstr[start]);

  error[0] = "Error reading options file - @!";
  error[1] = "Unable to open options file - @!";
  error[2] = "@ is an ambiguous keyword.";
  error[3] = "@ is an unknown keyword.";

  fillerrexit(err_num, NumErrors, fitting, error, filler);
#undef NumErrors
}
