char jdb_id[]="jdb version 1.0b  8 Sep 99";
/* jdb.c  - forms primary routines for the JGOFS data system		*/
/*              used from jgofs.a					*/
/*  08 Sep 99.  1.0b.  CLH						*/
/*	Resolve differences from 2 sources - v1.0a and OO version  	*/
/*									*/
/*  15 Aug 99.  1.0a.  WJS						*/
/*    Looks to me like there is an "open file leak" in localopen/	*/
/*    jdbclose interaction.  We open a pipe to the child and one from	*/
/*    it, but only close the one from it.  Try closing the pipe to it	*/
/*    right from the start - don't see that we should be writing to	*/
/*    child...								*/
/*	[Begin 1.0a]							*/
/*  November 3, 1998, clh  system version 1.5 upgrade			*/
/*  November 10, 1998, clh several functions need to be 'typed'	 	*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#if SOL || HP
#include <sys/time.h>
#include <sys/resource.h>
#endif


/* added for v1.5 compatibility */
#include OPTIONS
#include INNEROPTIONS

int HTDoConnect();
int HTDoRead();

HTCheckActiveIcon(i)
int i;
{
return 0;
}

void HTClearActiveIcon()
{
}

void HTProgress(msg)
char *msg;
{
/*
fprintf(stderr,"%s\n",msg);
*/
}

int HTDoConnect();
int HTDoRead();


/* below values indicating buffers should be minimally 4k */
#define HTSIZE INBUFSIZE
#define MAX_BUF INBUFSIZE
#define NUMNAMES NVAR

#define MAX_UNITS 5

struct OBJECT {
 char htbuff[HTSIZE];
 int htbufflen;
 int htbuffptr;
 int socket;
 int maxlevel,ntotal;
 int lvlpntr[11];
 int rdpntr[NUMNAMES];
 char attributes[NUMNAMES][TOTATTRSIZE], *attributeptr[NUMNAMES];
 char comments[COMMENTSIZE], *commentptr;
}  *object[MAX_UNITS]={NULL,NULL,NULL,NULL,NULL};

int bgets(comm,len,obj)
char *comm;
int len;
struct OBJECT *obj;
{
int op;
char c;
/*
printf("entered bgets\n");
*/
if(obj->htbufflen<0) return 1;
op=0;
while(1){
  if(obj->htbuffptr >= obj->htbufflen){
    obj->htbufflen=HTDoRead(obj->socket,obj->htbuff,HTSIZE);
    if(obj->htbufflen == 0){
      obj->htbufflen= -1;
      return 1;
    };
    obj->htbuffptr = 0;
  };
  if((c=obj->htbuff[obj->htbuffptr++]) != 13)comm[op++]=c;
  if(c==10){comm[--op]=0;return 0;};
};
}  
  
int htopen(comm,par,obj)
char *comm,*par;
struct OBJECT *obj;
{
  char *cp,met[MAX_BUF];
  int i,handle;

  cp=strchr(comm+2,'/');
  if(cp==NULL)return -999;
  strcpy(obj->htbuff,"GET /jg/serv/");
  strcat(obj->htbuff,cp+1);
  *cp =0;
  if(par){
    if(*par){
      strcat(obj->htbuff,"?");
      strcat(obj->htbuff,par);
    };
  };
  strcpy(met,"http:");
  strcat(met,comm);
  i=HTDoConnect(met,"HTTP",80,&handle);
  if(i) {printf("Connect to %s failed\n",met);return -999;};
  obj->socket = handle;
  cp=obj->htbuff+strlen(obj->htbuff);
  *(cp++)=13;
  *(cp++)=10;
  *cp=0;
  write(handle,obj->htbuff,strlen(obj->htbuff));
  return 0;
}

int localopen(comm,par,obj)
char *comm,*par;
struct OBJECT *obj;
{
  char *cp,met[MAX_BUF];
  int i,handle;
  FILE *cin,*cout;
  static int pipeto[2],pipefrom[2];
  char *parptr[250],*sp;
  int j,np,childpid,numfds;
#if SOL || HP
  struct rlimit rlp;
#endif
  j=0;
  parptr[j]=comm;
  if(*par){
    parptr[++j]=par;
    np=0;
    sp=par+1;
    while(*sp){
      switch(*sp){
      case '(':np++;break;
      case ')':np--;break;
      case ',':if(np)break;
	*sp=0;
	parptr[++j]=sp+1;
	break;
      };
      sp++;
    };
  };
  parptr[++j]=NULL;
  
  if (pipe(pipeto) || pipe(pipefrom) <0)
    {
      perror("no pipes");
      exit(1);
    }
  switch(childpid = fork())
    {
    case -1:
      perror("bad fork");
      exit(1);
    case 0:
      /*    printf("got here after fork\n");*/
      dup2(pipeto[0],0);
      dup2(pipefrom[1],1);
#if SOL || HP
      getrlimit(RLIMIT_NOFILE,&rlp);
      numfds=rlp.rlim_cur;
#else
      numfds = getdtablesize();
#endif
      for (i=3; i<numfds; i++)
	close(i);
      
      execvp(comm,parptr);
      perror(comm);
      return -999;
      /*    exit(1); */
    default:
      close(pipeto[0]);
      close(pipefrom[1]);
      /*    ptoch = pipeto[1];*/
      /*    pfrch = pipefrom[0];*/
      obj->socket=pipefrom[0];
      close(pipeto[1]);			/*  wjs addition 15 Aug 99	*/
      /*    setbuf(frch,NULL);*/
      return 0;
    }
  
}

#if IBM || HP
int jdbopen(unit,obj,names,namesize,num)
#else
int jdbopen_(unit,obj,names,namesize,num)
#endif
int *unit;
char *obj;
char *names;
int *namesize;
int *num;
{
  int i,j,k,numd,tunit;
  char comm[MAX_BUF],met[MAX_BUF],par[MAX_BUF],state,*cp,*ap;
  struct OBJECT *o;

  for(tunit=0;tunit<MAX_UNITS;tunit++)if(!object[tunit])break;
  if(tunit>=MAX_UNITS){
    printf("Out of units\n");return -999;
  };
  o=(struct OBJECT *)malloc(sizeof(struct OBJECT));
  object[tunit]=o;
  *unit = tunit;

  strcpy(comm,obj);
  numd= *num;
  if(*num <0) *num=0;
  else {
    if(comm[strlen(comm)-1]==')')comm[strlen(comm)-1]=',';
    else strcat(comm,"(");
    for(i=0;i<numd;i++){
      strcat(comm,names+i*(*namesize));
      strcat(comm,",");
    };
    comm[strlen(comm)-1]=')';
  };
/*
  printf("++%s++\n",comm);
*/

/* find it */
  if(cp=strchr(comm,'(')){strcpy(par,cp+1);*cp=0;par[strlen(par)-1]=0;}
  else *par=0;
  if(dctsearch(comm,met,par,1)==0){
    printf("&x <b>Error - not found:</b> %s %s\n",met,comm);
    exit(1);
  };

  if(strstr(met,"//")==met){
    if(htopen(met,par,o)){
      printf("&x <b>Error opening remote object:</b> %s\n",met);
      return -999;
    };
    tunit=0;
  } else {
    if(localopen(met,par,o)){
      printf("&x <b>Error opening local object:</b> %s\n",met);
      return -999;
    };
    tunit=1;
  };      

  o->htbufflen=0;
  o->htbuffptr=0;
  *(o->comments)='\0'; 
  o->commentptr = o->comments;


  for(i=0;i<NUMNAMES;i++){
    o->rdpntr[i]= -1;
    o->attributeptr[i] = o->attributes[i];
  };
  o->ntotal=0;
  
  if(tunit){
    if(bgets(comm,MAX_BUF-1,o))return -999;
    if(comm[0]=='&') if(comm[1]=='x'){
      printf("%s\n",comm);
      close(o->socket);
      free(o);
      object[tunit]=NULL;
      return -999;
    };
    if(bgets(comm,MAX_BUF-1,o))return -999;
    if(comm[0]=='&') if(comm[1]=='x'){
      printf("%s\n",comm);
      close(o->socket);
      free(o);
      object[tunit]=NULL;
      return -999;
    };
  };
  state='c';
  o->maxlevel= 0;
  while(1) {
    if(bgets(comm,MAX_BUF-1,o))return -999;
    if(comm[0]=='&') state=comm[1];
    switch(state){
    case 'x':
      printf("%s\n",comm);
      close(o->socket);
      free(o);
      object[tunit]=NULL;
      return -999;
    case 'e':
      /*      printf("%s\n",comm); */
      close(o->socket);
      free(o);
      object[tunit]=NULL;
      return -999;
    case 'c':
      if(comm[0] != '&'){
	strcat(o->comments,comm);
	strcat(o->comments,"\n");};
      break;
    case 'r':
      if(numd > 0){
        for(i=0;i< numd;i++){
          for(j=0;j<o->ntotal;j++) if(o->rdpntr[j] == i)break;
          if(j == o->ntotal){
	    close(o->socket);
	    free(o);
	    object[tunit]=NULL;
            return -(i+1);
          };
        };
      };
      o->lvlpntr[o->maxlevel+1]=o->ntotal;
      return o->maxlevel;
    case 'v':
      if(comm[0]=='&'){
	o->maxlevel=comm[2]-'0';
	o->lvlpntr[o->maxlevel]=o->ntotal;
      } else {
	cp=strtok(comm,"\t\n");
	while(cp){
	  ap=strchr(cp,'[');
	  if(ap) {
	    *ap=0;
	    ap++;
	    *(ap+strlen(ap)-1) = ';';
	  };
	  o->ntotal++;
	  if(numd < 0){
	    (*num)++;
	    if(*num > -numd){
	      printf("Too many variables\n");
	      close(o->socket);
	      free(o);
	      object[tunit]=NULL;
	      return -999;
	    };
	    strcpy(names+(*namesize)*(*num-1),cp);
	    if(ap) strcpy(o->attributes[*num-1],ap);
	    k= *num -1;
	  } else {
	    k= -1;
	    for(i=0;i< *num;i++) 
	      if(strcmp(names+(*namesize)*i,cp)==0){
		k=i;
		if(ap) strcpy(o->attributes[i],ap);
	      };
	  };
	  if(k>=0) o->rdpntr[o->ntotal-1]=k;
	  cp=strtok(NULL,"\t\n");
	};
      };
    };
  };
}

#if IBM || HP
int jdbread(unit,values)
#else
int jdbread_(unit,values)
#endif
int *unit;
float values[];
{
  char comm[MAX_BUF],state,*cp;
  int i,k,ilvl,iret;
  struct OBJECT *o;
  if(!(o=object[*unit]))return -1;
  ilvl=o->maxlevel;
  iret=ilvl;
  state='d';
  while(1) {
    /*   printf(">>%c>>%s\n",state,comm);  */
    if(bgets(comm,MAX_BUF-1,o))return -1;

    if(comm[0]=='&') {
      state=comm[1];
      switch(state){
      case 'x':
	printf("%s\n",comm);
	close(o->socket);
	free(o);
	object[*unit]=NULL;
	return -999;
      case 'e':
	close(o->socket);
	free(o);
	object[*unit]=NULL;
	return -1;
      case 'd':
        ilvl=comm[2]-'0';
	if(ilvl<iret)iret=ilvl;
	break;
      case 'c':
	*(o->comments)='\0';
	o->commentptr = o->comments;
      };
    } else {
      switch(state){
      case 'c':
	strcat(o->comments,comm);
	strcat(o->comments,"\n");
	break;
      case 'd':
	cp=strtok(comm,"\t\n");
	for(i=o->lvlpntr[ilvl];i<o->lvlpntr[ilvl+1];i++){
	  k=o->rdpntr[i];
	  if(cp && k>=0){
	    if(strspn(cp,"0123456789.+-")==0) values[k]= -9999.99;
	    else values[k]=atof(cp);
	    cp=strtok(NULL,"\t\n");
	  } else if(cp) cp=strtok(NULL,"\t\n");
	  else if(k>=0) values[k]= -9999.99;
	};
	if(ilvl == o->maxlevel)return iret;
      };
    };
  };
}


#if IBM || HP
int jdbreada(unit,values,valuesize)
#else
int jdbreada_(unit,values,valuesize)
#endif
int *unit;
char *values;
int *valuesize;
{
  char comm[MAX_BUF],state,*cp;
  int i,k,ilvl,iret;
  struct OBJECT *o;

  if(!(o=object[*unit]))return -1;
  ilvl=o->maxlevel;
  iret=ilvl;
  state='d';
  while(1) {
    /*   printf(">>%c>>%s\n",state,comm);  */
    if(bgets(comm,MAX_BUF-1,o))return -1;

    if(comm[0]=='&') {
      state=comm[1];
      switch(state){
      case 'x':
	printf("%s\n",comm);
	close(o->socket);
	free(o);
	object[*unit]=NULL;
	return -999;
      case 'e':
	close(o->socket);
	free(o);
	object[*unit]=NULL;
	return -1;
      case 'd':
        ilvl=comm[2]-'0';
	if(ilvl<iret)iret=ilvl;
	break;
      case 'c':
	*(o->comments)='\0';
	o->commentptr = o->comments;
      };
    } else {
      switch(state){
      case 'c':
	strcat(o->comments,comm);
	strcat(o->comments,"\n");
	break;
      case 'd':
	cp=strtok(comm,"\t\n");
	for(i=o->lvlpntr[ilvl];i<o->lvlpntr[ilvl+1];i++){
	  k=o->rdpntr[i];
	  if(cp && k>=0){
	    strcpy(values+(*valuesize)*k,cp);
	    cp=strtok(NULL,"\t\n");}
	  else if(cp) cp=strtok(NULL,"\t\n");
	  else if(k>=0)strcpy(values+(*valuesize)*k,"nd");
	};
	if(ilvl == o->maxlevel)return iret;
      };
    };
  };
}

#if IBM || HP
int jdbcomments(unit,outcom)
#else
int jdbcomments_(unit,outcom)
#endif
int *unit;
char *outcom;
{
  int j;
  struct OBJECT *o;

  if(!(o=object[*unit]))return 0;
  if(*(o->commentptr)){
    j=strcspn(o->commentptr,"\n");
    strncpy(outcom,o->commentptr,j);
    *(outcom+j)='\0';
    o->commentptr += j+1;
    return 1;
  } else return 0;
}

#if IBM || HP
int jdbattributes(unit,id,outcom)
#else
int jdbattributes_(unit,id,outcom)
#endif
int *unit;
int *id;
char *outcom;
{
   int j;
   char *sp;
   struct OBJECT *o;

  if(!(o=object[*unit]))return 0;
  sp=o->attributeptr[*id];
  if(*sp){
  j=strcspn(sp,";");
  strncpy(outcom,sp,j);
  *(outcom+j)='\0';
  o->attributeptr[*id] += j+1;
  return 1;
  } else return 0;
}

#if IBM || HP
int jdbclose(unit)
#else
int jdbclose_(unit)
#endif
int *unit;
{
  struct OBJECT *o;
  
  if(!(o=object[*unit]))return 1;
  close(o->socket);
  free(o);
  object[*unit]=NULL;
  return 0;
}

#if IBM || HP
int jdblevel(unit,varnum)
#else
int jdblevel_(unit,varnum)
#endif
int *unit;
int *varnum;
{
  int i,j;
  struct OBJECT *o;
  
  if(!(o=object[*unit]))return -999;
  for(j=0;j<o->ntotal;j++)if(*varnum==o->rdpntr[j])break;
  if(j>=o->ntotal)return -1;
  for(i=1;i<=o->maxlevel;i++)if(j<o->lvlpntr[i])return i-1;
  return o->maxlevel;
}

/*
char names[20][TOKEN];
char values[20][TOKEN];
int maxlev;

main(argc,argv)
int argc;
char *argv[];
{
char objname[256];
int i,j,clev;
int unit=1;
int nn;
int namesize=TOKEN;
int valuesize=TOKEN;

nn= -20;

strcpy(names[0],"lon");
strcpy(names[1],"lat");
strcpy(names[2],"press");
strcpy(names[3],"o2");
nn=4;

strcpy(objname,argv[1]);
maxlev=jdbopen_(&unit,objname,names,&namesize,values,&valuesize,&nn);
if(maxlev<0){printf("Bad object %s\n",argv[1]);exit(1);};

*
while(jdbcomments_(&unit,objname))printf("#%s\n",objname);
/

for(i=0;i<nn;i++)printf("%-20.20s",names[i]);
printf("\n");
*
for(i=0;i<nn;i++)
  while(jdbattributes_(&unit,&i,objname))printf("%s . %s \n",names[i],objname);
for(i=0;i<nn;i++)printf("%-20d",levels[i]);
printf("\n");
for(i=0;i<nn;i++)printf("%-20d",sizes[i]);
printf("\n");
/

while((clev=jdbreada_(&unit,values,&valuesize)) >= 0){
  if(clev<maxlev) while(jdbcomments_(&unit,objname))printf("#%s\n",objname);
  for(i=0;i<nn;i++)printf("%-20.20s",values[i]);
  printf("\n");
  };
jdbclose_(&unit);
}
*/

#ifdef ULTRIX
char *strdup(s)
char *s;
{
char *t;
if(s==NULL)return NULL;
t=malloc(strlen(s)+1);
strcpy(t,s);
return t;
}
#endif
