/* *******************************************************************
 *                                                                   *
 * Copyright (c) L-DGO/MIT/JGOFS                                     *
 *                                                                   *
 *                                                                   *
 * File             : def.c                                          *
 *                                                                   *
 * Purpose          :                                                *         
 *                                                                   *
 * Version Number   : 1.7                                            *
 *                                                                   *
 * Revision History :                                                *
 *                                                                   *
 * Date                              Developer                       *
 * ----                              ---------                       *
 *                                                                   *
 * Sat Oct 17  1992 10.00           Glenn Flierl                     *
 * Oct 1993                         tabattributes                    *
 * July 1995                        Christine Hammond                *
 *        change to add field width determination based on width of  *
 *        the label in the data.  Preparer must determine max width  *
 *        of column from inspection of data column width.            *
 *        Ex:  event___ , sta__ ,bot                                 *
 *        will give lengths of 8, 5, and 3 for the respective cols   *
 * July 1995                        Christine Hammond                *
 *        change to allow subfiles to be located in different        *
 *        directories from header file                               *
 *                                                                   *
 * January 1996                     Christine Hammond                * 
 *       'type' the functions that outer method calls to avoid       *
 *        warnings on ANSI compilers - void() used for functions     * 
 *        returning no value  (e.g., return;)                        *
 *                                                                   *
 * March  1996                      Christine Hammond                * 
 *       fix proclabel (width sensing) to ignore attributes with a   *
 *       substring 'width=', ex: 'inpwidth=N', and to properly deal  *
 *       with a 'width=N' attr when it occurs after a ';', as in     *
 *       a series of attributes, ex: 'meters;color=pink;width=12'    *
 *                                                                   *
 * March  1996                      Warren Sass, Christine Hammond   * 
 *       use a .h include file to set sizes of buffers used          *
 *       NOTE:  'minbufsize.h' also included in outer.c, to achieve  *
 *       some correspondence.  User-specified include file allowed   *
 *       (see minbufsize.h) as a compile switch IOBUF_INCLUDE        * 
 *                                                                   *
 * November  1996                   Warren Sass, Christine Hammond   *
 *       ioattrout change - remove code after getwidth() call whose  *
 *       comment stated:  don't show the width attribute             *
 *       code was:        str = '\0';                                *
 *       we want outer to determine what gets shown.                 *
 *                                                                   *
 * November  1996                        Christine Hammond           *
 *       proclabel change - place separating ';' AFTER first attrib  *
 *                                                                   *
 * May 1997                         Glenn Flierl                     *
 *       changed error calls to use error_ in outer.c                *
 *                                                                   *
 * June 1997 grf                                                     *
 *       changed sub names to in_xxxx, fixes for v 1.5               *
 ******************************************************************* */

#include <stdio.h>
#include <string.h>
#include OPTIONS
#include INNEROPTIONS

double strtod();

/* #define DEBUG  */


#define SEPARATOR " \t,\n"
#define W_EXTEND '_'
#define DIRSEP '/'

char tabnames[NVAR][VARNAMESIZE];
char tabvalues[NVAR][DATUMSIZE];
char tabattributes[NVAR][ATTRSIZE];
char tabcomments[COMMENTSIZE];

int tabwidths[NVAR];
int nvarlevel[6];
int fileopen[5] = {0,0,0,0,0};
FILE *fl[5];
int maxlev;
int pointers[NVAR];
char dirstring[DATUMSIZE];

/* * * * * *     end of declarations    * * * * * */

void in_proclabel(n, ptr, attr)
int n;
char *ptr, attr[];
/* 
attr[] is string local to scanheader.
routine to determine the length of the title string indexed at 'n' and
pointed to by 'ptr', and based on the idea that the user preparing the
data has placed W_EXTEND characters to pad the title to the desired
width.  An attribute is constructed to be saved in the calling routine,
beginning with 'width='.  Then, the W_EXTEND characters must be
stripped from the tabnames. If an explicit width= attribute is
found, it is used.
*/

{
#define YES  0
#define NO   1

   void in_striptoken();
   int len, docalc, others;
   char attrib[ATTRSIZE], *attrptr;

/* default value for flag indicating attributes other than 'width=' */

   others = NO;

/* calculate a field width if no attributes are present or, 
   if none of the attributes are exactly == 'width=N'       */

   docalc = YES;
   attrptr = attr;
   while (attrptr) {
      if (strncmp(attrptr,"width=",6) == 0) docalc = NO;
      if ((attrptr = strchr(attrptr,';')) != NULL) {
         attrptr++;
         others = YES;
      };
   }

   if (docalc == YES) {

     len = strlen(ptr);           /* length of (possibly) extended label */
     sprintf(attrib, "width=%d", len);
     if (others == YES) {         /* add to end of other attributes? */
        strcat(attr,";");
        strcat(attr,attrib);
     } else
        strcpy(attr,attrib);

  };   /* end docalc loop */
  
/* strip off the column extenders from the label */
   in_striptoken(ptr);

/* and save label name without the extra W_EXTEND characters */
   strcpy(tabnames[n], ptr);
   return;
}

void in_striptoken(p)
char *p;
{
  char *tp;
  int i;

/* if there are extending characters at end of string, strip them */

  i = strlen(p);
  while ( (tp = strrchr(p,W_EXTEND)) == p+i-1) {
     *tp = '\0';        /* shorten string by that one extend char */
     i = strlen(p);
  };
  return;
}

int in_scanheader(lev)
int lev;
{
void in_striptoken(), in_proclabel();
int ncnt,i,j,k,m;
char tmp[INBUFSIZE],*tok,attrsav[ATTRSIZE],*attr;

ncnt= 0;
i=0;j=1;
if(lev>0){
  for(i=nvarlevel[lev-1];i<nvarlevel[lev];i++)pointers[i]= -1;
  m=nvarlevel[lev-1];
  };

while(j){
  if (fgets(tmp,INBUFSIZE-1,fl[lev]) == NULL)error_("Bad file structure","");
  if (tmp[0] == '#'){
    while (tmp[0] == '#') {
      strcat(tabcomments,tmp+1);
      if (fgets(tmp,INBUFSIZE-1,fl[lev]) == NULL)error_("Bad file structure","");
      };
    };
  tok=strtok(tmp,SEPARATOR);
  while (tok != NULL) {
    if(tok[0] == '"') {
       tok++,tok[strlen(tok)-1]=0;
    };

    if(attr=strchr(tok,'[')){
       strcpy(attrsav,attr+1);
       attrsav[strlen(attrsav)-1]='\0';
       *attr = '\0';
    } else 
       attrsav[0]='\0';

    if(lev==0) {
/*       strcpy(tabnames[ncnt],tok);   moved copy to in_proclabel */
       in_proclabel(ncnt,tok,attrsav);
       strcpy(tabattributes[ncnt],attrsav);
       pointers[ncnt]=ncnt;ncnt++;
    } else if(strcmp(tok,">")) {
      in_striptoken(tok);
      for(k=nvarlevel[lev-1];k<nvarlevel[lev];k++)
	if(strcmp(tabnames[k],tok)==0)break;
      if(k==nvarlevel[lev])error_("New variable name in file ",tok);
      pointers[k]=m++;
    };
    tok=strtok(NULL,SEPARATOR);
  };
  if(lev==0){
    if(tabnames[ncnt-1][0]=='>') ncnt--; else j=0;
    nvarlevel[i]=ncnt;
    if(j) i++;
    } else j=0;
  };
if(lev==0)
  maxlev=i;
else
  for(i=lev;i<maxlev;i++)
   if(fgets(tmp,INBUFSIZE-1,fl[lev])==NULL)error_("Bad file structure","");
return ncnt;
}

int ioopen_(s,nparams,ntotal)
char *s[];
int *nparams,*ntotal;
{
char tmp[INBUFSIZE],*tok;
int ncnt,i,j;
strcpy(dirstring,s[0]);
if((tok=strrchr(dirstring,DIRSEP))!=NULL)*(tok+1)='\0';
  else dirstring[0]='\0';
if((fl[0]=fopen(s[0],"r")) == NULL)error_("Bad header file name ",s[0]);
s[0][0] = 0;
*tabcomments = '\0';
*ntotal=in_scanheader(0);
fileopen[0]=1;
return maxlev;
}

void ioname_(vn,s)
int *vn;
char *s;
{
strcpy(s,tabnames[*vn]);
}

int iovarlevel_(vn)
int *vn;
{
int i;
for(i=maxlev-1;i>=0;i--)if (*vn >= nvarlevel[i]) return i+1;
return 0;
}

int ioattrout_(vn,str)
int *vn;
char *str;
{
   void in_getwidth();
   char *at;
   int j;

j= *vn;

/* if there IS an attribute, find one and move next one to front of string */

if (tabattributes[j][0]){
  at=strchr(tabattributes[j],';');
  if(at){               /* there is more than 1 attribute */
    *at = '\0';
    strcpy(str,tabattributes[j]);
    if (strncmp(str,"width=",6) == 0) {   /* width attr, use it for tabwidths */
      in_getwidth(&j,str);
    }
    strcpy(tabattributes[j],at+1);

  } else {    /* this is the only attribute for variable vn */
    strcpy(str,tabattributes[j]);
    if (strncmp(str,"width=",6) == 0) {
      in_getwidth(&j,str);
    }
    tabattributes[j][0]='\0';
  };

  return 1;
} else return 0;
}

void iovalreal_(vn,f)
int *vn;
float *f;
{
/*     following line changed by clh, May 1996
       if(strspn(tabvalues[i],"0123456789.+-"))
       to one below, to allow for strings that begin with digits
*/

int i;
char *end_char_ptr;

i=pointers[*vn];
if(i<0){*f= -9999.0;return;};

/*     if strtod does not point to NULL, make the 'number' returned a 
       'missing' one.  Note that if the string conversion produces no
        number, end_char_ptr will point to tabvalues[i], which is not NULL
*/
 *f=strtod(tabvalues[i],&end_char_ptr);
 if (*end_char_ptr != '\0')
   *f= -9999.0;

return;
}

void iovalstr_(vn,tmp)
int *vn;
char *tmp;
{
static char *s;
int i;
i=pointers[*vn];
if(i<0){strcpy(tmp,"nd");return;};
s=tabvalues[i];
s=s+strspn(s," ");
strcpy(tmp,s);
#ifdef DEBUG0
fprintf(stderr,"iovalstr %d %s\n",*vn,tmp);
#endif
return;
}

static char subfilename[80];

int ioreadrec_(level)
int *level;
{
char tmp[INBUFSIZE],*tok;
int i,j,k;
#ifdef DEBUG
fprintf(stderr,"ioreadrec %d\n",*level);
#endif

k= *level;

  if (! fileopen[k]) {
#ifdef DEBUG
fprintf(stderr,"open %s\n",subfilename);
#endif

  if((fl[k]=fopen(subfilename,"r"))  == NULL)error_("Missing file ",subfilename);
  in_scanheader(k);
  fileopen[k]=1;
  };

j=1;
while(j){
  if(fgets(tmp,INBUFSIZE-1,fl[k]) == NULL){
#ifdef DEBUG
fprintf(stderr,"eof at level %d\n",k);
#endif

    fclose(fl[k]);
    fileopen[k]=0;
    return 0;
    };
  i=strspn(tmp,SEPARATOR);
  if(i<strlen(tmp))j=0;
};

if(k==0)j=0; else j=nvarlevel[k-1];

tok=strtok(tmp,SEPARATOR);
for(i=j;i<nvarlevel[k];i++){

#ifdef DEBUG0
fprintf(stderr,"assign %d %s\n",i,tok);
#endif
    strcpy(tabvalues[i],tok);
    tok=strtok(NULL,SEPARATOR);
    };

if(k<maxlev) {
   if (strncmp(tok,"/",1) == 0)	/* check for absolute address on subfile */
      strcpy(subfilename,tok);
    else {
      strcpy(subfilename,dirstring);
      strcat(subfilename,tok);      
   };
};
return 1;
}

void ioclose_()
{
int i;
for(i=0;i<=maxlev;i++)if (fileopen[i])fclose(fl[i]);
}

int iocommout_(str)
char *str;
{
char *at;
if (tabcomments[0]){
  at=strchr(tabcomments,'\n');
  if(at){
    *at = '\0';
    strcpy(str,tabcomments);
    strcpy(tabcomments,at+1);
  } else {
    strcpy(str,tabcomments);
    tabcomments[0]='\0';
  };
  return 1;
} else return 0;
}

int iowidth_(vn)
int *vn;
{
   int i;
   i = tabwidths[*vn];
return i;

}

void in_getwidth(vn, ptr)
/* read the width from the string 'ptr' (an attribute that has
        been tested prior to coming here for containing the 
        string 'width=') and write it to the tabwidths array
        element '*vn'
*/
int *vn;
char *ptr;
{
  char *p;
  int i,len;

  i = *vn;
  p = strchr(ptr,'=');

  sscanf(p+1,"%d", &len);

  tabwidths[i] = len;
  return;
}
