#define DCT_VERSION "dct version 1.2c  10 Dec 2004"

/*  10 Dec 2004.  v 1.2c  WJS						*/
/*    Bug fix: incorrect strdupl call					*/
/*		[Begin 1.2c]						*/
/*  25 Aug 2004.  v 1.2b  WJS						*/
/*    serv had its own putenv.  Recode dct to use the system one	*/
/*	Not checking return value yet - that's a job for dct v 2.0	*/
/*    Put MAX_SERV_DCT_BUF (formerly MAX_BUF) in core.h so serv &	*/
/*	dct can be coordinated						*/
/*    Standardize version stuff						*/
/*		[Begin 1.2b]						*/
/*  11 Feb 2004.  v 1.2a  WJS						*/
/*    Declare putenv to avoid diagnostic.  #include stdlib since man	*/
/*	page says it "goes with" putenv - don't know why.		*/
/*    Remove declaration for getenv since it's unused			*/
/*		[Begin 1.2a]						*/
/*  17 Jan 2004.  v 1.2  WJS						*/
/*    Divider between obj defn and env vars was 1st blank in obj defn	*/
/*      Arrange things not to count blanks between parens		*/
/*    Put a void type on mergeparams (this mod made on synthesis'	*/
/*	version 6 Nov 2000 by Chris Hammond)				*/
/*		[Begin 1.2]						*/

#include "core.h"
/*
#define OBJECT_ROOT "/d3/glenn/jg/objects"
#define METHOD_ROOT "/d3/glenn/jg/methods/"
#define DEBUG
*/

int putenv();
char *strdupl();		/*  from utils.c			*/

/************************************************************************/

char *dct_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[] = DCT_VERSION"/"COREH_VERSION;
  return version;
}

/* ====================  search sequence: =============
 //machine
 path/tail -  tail in path/.objects [local]
 /jgpath/tail - tail in OBJECT_ROOT/jgpath/.objects
 /jgpath/tail - tail in OBJECT_ROOT/jgpath/.remoteobjects
 path/exec - executeable program METHOD_ROOT/path/exec
         [local || dctcount<8 (not first pass)]
 path/datafile - use def method on local file [local]
   ===================================================== */

int scandct(s,t)
char *s,*t;
{
  FILE *fdic;
  char tdic[MAX_SERV_DCT_BUF],dctname[MAX_SERV_DCT_BUF],*sp;
  int nok,nb,l;
    /*  Next comment based on the idea that putenv does NOT make a copy	*/
    /*  of its argument [from man putenv on talia.whoi.edu, a linux box	*/
    /*   "Thus, it is an error is to call putenv() with  an  auto-	*/
    /*    matic  variable  as the argument, then return from the call-	*/
    /*    ing function while string is still part of the environment."]	*/
    /*  Next is a volatile pointer that is set to dynamically allocated	*/
    /*  memory.  Thus, the pointer will be lost upon function return,	*/
    /*  and the memory cannot be freed.  This is OK, since idea is to	*/
    /*  have this memory survive exit from scandct so env vars will be	*/
    /*  "present" when/if calling program needs them.  Cannot use a	*/
    /*  static buffer here in case scandct is called more than once	*/
  char *list_of_env_vars;

#ifdef DEBUG
  printf("Searching >%s< for >%s<\n",s,t);
#endif

  sp=strrchr(t,'/');
  if(sp){
    *(sp++)=0;
    strcpy(dctname,t);
    strcat(dctname,"/");
    strcat(dctname,s);
  } else {
    strcpy(dctname,s);
    sp=t;
  };
  strcat(sp,"=");
#ifdef DEBUG
  printf("Open >%s< and look for >%s<\n",dctname,sp);
#endif
  fdic=fopen(dctname,"r");
  if(fdic==NULL)return 0;

  nok=1;
  while (!feof(fdic) && nok)
    {
    fgets(tdic,MAX_SERV_DCT_BUF-1,fdic);
    if (strstr(tdic,sp)==tdic) nok=0;
    };
  fclose(fdic);
  if (nok) return 0;

  strcpy(t,strchr(tdic,'=')+1);
  l=strlen(t);
  if (t[l-1] == '\n')   t[--l] = '\0';
  nb=0;
  for(sp=t; sp<t+l; sp++) {
    if (*sp == '(') nb++;
    else if (*sp == ')') nb--;
    else if ((*sp == ' ') && (nb == 0)) break;
  }
  if (sp < t+l) {
    *sp = '\0';
    strdupl(&list_of_env_vars,sp+1,
			"copying list of env vars from end of .objects entry");
    sp = strtok(list_of_env_vars," ");
    while (sp) {
      putenv(sp);
      sp = strtok(NULL," ");
    };
  };
  return 1;
}

void mergeparams(req,dct)
char *req,*dct;
{
  char *j,*k;
  int i,dctopt,reqproj,nb;
  char tmp[MAX_SERV_DCT_BUF];

  /* no params in dictionary */
  if(dct==NULL)return;

  /* no params requested */
  if(*req==0){
    j=dct+1;
    k=req;
    while(*j){
      if(*j == '[' || *j == ']') j++;
      else *(k++)= *(j++);
    };
    *dct=0;
    *(k-1)=0;
    return;
  };

  /* dictionary params first */

  nb=0;
  dctopt=1;
  j=dct;
  k=tmp;
  while(*(++j)){
    switch(*j){
      case '[':nb++;dctopt=0;break;
      case ']':nb--;break;
      default:if(nb==0) *(k++) = *j;break;
      };
  };
  if(k>tmp) if(*(k-1) == ')') *(k-1)=',';

  j=req-1;
  reqproj=0;
  nb=0;
  i=1;
  while(*(++j)){
    *(k++)= *j;
    switch(*j){
      case '(':nb++;break;
      case ')':nb--;break;
      case '<':
      case '>':
      case '=':i=0;break;
      case ',':if(nb==0 && i==1)reqproj=1;
	i=1;
	break;
      };
  };
  *k=0;

  if(reqproj || dctopt) {
    while(j=strstr(tmp,",,"))strcpy(j,j+1);
    strcpy(req,tmp);
    *dct=0;
    return;
  };

  j=dct;
  nb=0;
  while(*(++j)){
    switch(*j){
      case '[':nb++;break;
      case ']':nb--;break;
      default:if(nb) *(k++) = *j;break;
      };
  };
  if(k>tmp) { 
    if(*(k-1) == ',') *(k-1)=0; else *k=0;
    while(j=strstr(tmp,",,"))strcpy(j,j+1);
    strcpy(req,tmp);
  } else *req=0;
  *dct=0;
  return;
}


int dctsearch(obj,method,params,localflag)
char *obj,*method,*params;
int localflag;
{
  char pathreq[MAX_SERV_DCT_BUF];
  char metreq[MAX_SERV_DCT_BUF];
  char parreq[MAX_SERV_DCT_BUF];
  char tmp[MAX_SERV_DCT_BUF];

  char *j;
  int dctcount;
  int dctnfound;

  COPY_INTO_FIXED_LEN_BUFFER(pathreq,obj,"dct: copying object string"); 
  COPY_INTO_FIXED_LEN_BUFFER(parreq,params,"dct: copying parameter string"); 

  *method=0;
  *params=0;

  dctcount=8;

  while(dctcount){

    dctnfound=1;

    /* //machine ... */
#ifdef DEBUG
    printf("test // ... %s**%s\n",pathreq,parreq);
#endif
    if(strstr(pathreq,"//")==pathreq){
      strcpy(method,pathreq);
      strcpy(params,parreq);
      return 1;
    };

    /* check for object dictionary */
    if(localflag){
      strcpy(tmp,pathreq);
#ifdef DEBUG
    printf("test local obj... %s**%s\n",tmp,parreq);
#endif
      if(scandct(".objects",tmp)){
	j=strchr(tmp,'(');
	if(j)mergeparams(parreq,j);
	if(strstr(tmp,"//")==tmp){
	  strcpy(method,tmp);
	  strcpy(params,parreq);
	  return 1;
	};
	strcpy(pathreq,tmp);
	dctnfound=0;
      };
    };
    
    /* check system .objects dictionary */
    if(dctnfound && *pathreq == '/'){
      strcpy(tmp,OBJECT_ROOT);
      if(*pathreq){
	strcat(tmp,"/");
	strcat(tmp,pathreq);
      };
#ifdef DEBUG
    printf("test sys local ... %s**%s\n",tmp,parreq);
#endif
      if(scandct(".objects",tmp)){
	j=strchr(tmp,'(');
	if(j)mergeparams(parreq,j);
	if(strstr(tmp,"//")==tmp){
	  strcpy(method,tmp);
	  strcpy(params,parreq);
	  return 1;
	};
	strcpy(pathreq,tmp);
	dctnfound=0;
      };
    };
    
    /* check system  .remoteobjects dictionary */
    if(dctnfound && *pathreq == '/'){
      strcpy(tmp,OBJECT_ROOT);
      if(*pathreq){
	strcat(tmp,"/");
	strcat(tmp,pathreq);
      };
#ifdef DEBUG
    printf("test sys global ... %s**%s\n",tmp,parreq);
#endif
      if(scandct(".remoteobjects",tmp)){
	j=strchr(tmp,'(');
	if(j)mergeparams(parreq,j);
	if(strstr(method,"//")==method){
	  strcpy(method,tmp);
	  strcpy(params,parreq);
	  return 1;
	};
	strcpy(pathreq,tmp);
	dctnfound=0;
      };
    };
    
    /* check for system method */
    if(dctnfound && (localflag || dctcount<8)){
      strcpy(tmp,METHOD_ROOT);
      strcat(tmp,pathreq);
#ifdef DEBUG
    printf("test sys meth ... %s**%s\n",tmp,parreq);
#endif
      if(access(tmp,X_OK)==0){
	strcpy(method,tmp);
	strcpy(params,parreq);
	return 1;
      };
    };

    /* local file - use default method */
    if(dctnfound && localflag){
#ifdef DEBUG
    printf("test def file ... %s**\n",pathreq);
#endif
      if(access(pathreq,R_OK)==0){
	strcpy(tmp,"(");
	strcat(tmp,pathreq);
	strcat(tmp,")");
	mergeparams(parreq,tmp);
	strcpy(pathreq,"def");
	dctnfound=0;
      };
    };

    /* error */
    if(dctnfound){
      strcpy(method,"Cannot be found in dictionary:");
      return 0;
    };
    dctcount--;
  };
strcpy(method,"Too many iterations in dictionary - check for loops:");
return 0;
}

/*
main(argc,argv)
int argc;
char *argv[];
{
char met[1024],par[1024];
int i;
if(dctsearch(argv[1],met,par,1))
  printf("dctsearch = %s**%s\n",met,par);
else printf("Not found\n");
}
*/
