#define SERV_VERSION "serv version 2.1  6 Feb 2013"

/*   6 Feb 13.  WJS							*/
/*	Recode to use dctsearch1					*/
/*		[Needs dct 2.0]						*/
/*		[Begin v 2.1]						*/

/*   3 Jun 05.  WJS							*/
/*	Fix typo in declaration of add_id_to_err			*/
/*		[Begin v 2.0b]						*/
/*   8 Sep 04.  WJS							*/
/*	Move QUERY_STRING parsing into query_string_routines		*/
/*		[Begin v 2.0a]						*/
/*  26 Aug 04.  WJS							*/
/*	Use parse_path_info to get around bug relating to .object	*/
/*    subdirs that contain .s in PATH_INFOs that don't have proto/	*/
/*    level fields							*/
/*	Bite the bullet and throw out env var stuff.  Apparently	*/
/*    needed once upon a time - never understood why, so let's see...	*/
/*	Lots more error checking, parametrization, etc.			*/
/*		[Begin v 2.0]						*/

#include "core.h"

char *obj;
char *option;

char *file;
char *par;
char *empty = {'\0'};

/*  #define ENVMAX 200		*
/
/*  static char *env[ENVMAX];		*/
/*  static int envmax=0;		*/
/*  char *getenv();		*/
/*  extern char **environ;		*/
int putenv();

int dctsearch1();

  /*  From utils							*/
char *buildstring();
char *strdupl();
char *copy_into_fixed_len_buffer();
Logical add_id_to_err();
void errn();

  /*  From path_info_routines						*/
char *get_object();

  /*  From query_string_routines					*/
char **split_query_string();

int exit_status=1;
/************************************************************************/

void error_(s,t)
char *s,*t;
{
  char *ss = "", *tt = "",  *ss_eol = "",  *tt_eol= "";

    /*  Take care of null strings and strings w/o newlines.  This work	*/
    /*  should be redundant, but easier to do it than make sure...	*/
    /*  This code also makes it easy to modify into a message format	*/
    /*  of "s:t" if one prefers.  (Note, however, that if called from	*/
    /*  err, s is whole error message and t is time/program ID info)	*/
  if (s != NULL) {
    ss = s;
    if (ss[strlen(ss)-1] != '\n') ss_eol = "\n";
  }
  if (t != NULL) {
    tt = t;
    if (tt[strlen(tt)-1] != '\n') tt_eol = "\n";
  }

/*  Go to stdout because that's the way it "always has been".  See	*/
/*  list (from which this is stolen) for more general "stdout & stderr	*/
/*  unless they are the same" approach (which will have to be adapted	*/
/*  here because of html issues)					*/
/*  Arbitrarily decided to bold "first line"				*/
  printf("Content-type: text/html\n\n");
  printf ("&x <b>%s%s</b><br>%s%s",ss,ss_eol,tt,tt_eol);

/*  Most errors will occur because of dctsearch failure.  dctsearch	*/
/*  returns 1 for all errors.  Except for execvp failure, which will	*/
/*  set errno, all other problems are things like buffer checks &	*/
/*  memory allocation failures.  Decided to exit w/errno if we have	*/
/*  have that.  Otherwise, default to ERROR_EXIT_STATUS (see core.h	*/
/*  for defn; more)							*/
  if (exit_status == 1) exit_status=ERROR_EXIT_STATUS;
  exit(exit_status);
}

void err(s,t)
char *s,*t;
{
  char *new_s,*new_t;
  add_id_to_err(&new_s,&new_t,s,t,SERV_VERSION);
  error_(new_s,new_t);
  return;		/*  Not that it should ever get here...		*/
}

char *serv_return_vers()
/*  Routine exists mostly to force .h file version string into this	*/
/*  module, but we could call it if we want.  Note string must not be	*/
/*  global or we'll have conflicts if another routine similarly		*/
/*  includes the version string						*/
{
  static char version[] = SERV_VERSION"/"COREH_VERSION;
  return version;
}

int main(argc,argv,envp)
int argc;
char *argv[];
char **envp;
{
char *sp;
int i,j,nparams;
char **parptr,**method_parameters;
char **dctsearch_param2,**dctsearch_param3;

/*  envmax=0;		*/
/*  while (envp[envmax] && envmax<ENVMAX) {		*/
/*    env[envmax]=envp[envmax];		*/
/*    envmax++;		*/
/*  }		*/
/*  if (envmax >= ENVMAX) errn ("Too many env vars.  Limit = ",ENVMAX);		*/
/*  env[envmax]=NULL;		*/
/*  environ=env;		*/

if (  (obj=get_object(NULL)) == NULL  )
  err ("Failed to get object spec","(Missing PATH_INFO?)");
if ( *obj == '\0') 
  err ("No object info in PATH_INFO.  \nPATH_INFO=",getenv("PATH_INFO"));

sp=getenv("QUERY_STRING");
if (sp == NULL) sp = empty;

option = buildstring("OPTIONSERVER=",OPTIONSERVER,"",
		     "creating OPTIONSERVER= string");
if (putenv(option) != 0) {
  exit_status = errno;
  errn ("putenv failure.  errno=",errno);
}

dctsearch_param2 = &file;
dctsearch_param3 = &sp;
if (  (dctsearch1(obj,dctsearch_param2,dctsearch_param3,0) == 0)  )
		err("dctsearch problem",buildstring(*dctsearch_param2," ",obj));
par = *dctsearch_param3;

method_parameters = split_query_string(par,&nparams);
/*  Would be possible to  free (par)  here if split_query_string	*/
/*  allocates its own space.  Not possible if method_parameters point	*/
/*  "into" par string							*/

  /*  +2 = 1 for method name parameter & 1 for terminating NULL		*/
parptr = (char **)malloc((nparams+2)*sizeof(char *));
if (parptr == NULL) 
  errn ("Could not allocate enough character pointers.  Attempted to get ",
	nparams+2);
j = 0;
parptr[j++] = file;
for (i=0; i<nparams; i++)
  parptr[j++] = method_parameters[i];
parptr[j] = NULL;

execvp(file,parptr);
exit_status = errno;
errn(buildstring("Execvp failure trying to execute ",
		 file,
		 "\n  errno=",
		 "building execvp error string"),
     errno);

exit(errno);
}
/*    WJS-modified to a void - does not work w/dct, which declares it int */
/*    (assuming dct uses this one when linked w/serv, & system one when	*/
/*    linked w/jdb!)		*/
/*  void putenv(str)		*/
/*  char *str;		*/
/*    Don't know if we still need to manipulate the env vars as coded	*/
/*    Apparently when serv was originally written, there was trouble 	*/
/*    some sort, addressed w/this copying/rewriting of the		*/
/*  {		*/
/*  int i;		*/
/*  char *sp,sv;		*/
/*  		*/
/*  sp=strchr(str,'=');		*/
/*  if(sp == NULL) err("Illegal env var (no = sign).  Bad string=",str); */
/*  		*/
/*  sp++;		*/
/*  sv = *sp;		*/
/*  *sp = 0;		*/
/*  		*/
/*  i=0;		*/
/*	  i < ENVMAX should be redundant since env concludes w/a NULL	*/
/*  while (  (env[i] != NULL) && i<ENVMAX  ) {		*/
/*    if (strstr(env[i],str) == env[i]) break;		*/
/*    i++;		*/
/*  }		*/
/*    Next line takes care of case where we are redefining an env	*/
/*    defined by serv during this program run				*/
/*  if (  (i >= envmax) && (env[i] != NULL)  ) free(env[i]);		*/
/*  if (env[i] == NULL) {		*/
/*    We want to add a new env var					*/
/*    if (i > ENVMAX-1) errn("Cannot add env var.  Max = ",ENVMAX);	*/
/*    env[i+1]=NULL;		*/
/*  }		*/
/*  		*/
/*  *sp = sv;		*/
/*  strdupl(&env[i],str,"duplicating an env var");		*/
/*  		*/
/*  return;		*/
/*  }		*/
