/* outer.c version 2.5 - clh modified outer.c to include field widths July 10, 1995 - clh added option to NOT print the OTHER OPTIONS links, using a precompiler option 'NOOTHEROPTS' Sept 13, 1995 - clh added option to NOT generate links from quoted strings code taken from outerqn.c, using precompiler option 'QUOTENOLINK' Sept 13, 1995 - clh added 'void' typing to the functions that this outer method expects from its inners; to avoid warnings from ANSI compilers January 23, 1996 - wjs 1) Added inclusion of buffer size logic via include file outer_bufsize.h 2) Re-parametrized some sizes 3) Removed tmp buffer from main since it didn't seem used Jan 27 1996 - 2.0 clh resolved differences among several outer.c versions - grf's version using getenv("OPTIONSERVER") - wjs's version implementing a buffer size include file Feb 14, 1996 - 2.1 clh allow more links at top Directory Page | Documentation | Plotting and Other Operations List at Level 0 | List all at next level | Flat listing NOOTHEROPTS compiler option will remove Plotting link NOTOPLINKS compiler option will remove all but first link Feb 28, 1996 - grf added error routine callable from outer or inner - should produce sensible output in all modes - grf added BUTTON flag for new links if you wish them to be displayed as buttons rather than links May 96 - grf Jun 1997 lots of fixes for v 1.5 */ #include #include #include #include OPTIONS htmlescape(str) char *str; { char tmp[1024],*i,*o,*htmlcode; char htmlstuff[1024]; i=str; o=tmp; *o=0; while(*i){ switch(*i){ case '<': if(htmlcode=strpbrk(i," >")){ strcpy(htmlstuff,""); *htmlcode='>'; *(htmlcode+1)=0; if((htmlcode=strstr(i,htmlstuff))){ htmlcode +=strlen(htmlstuff); *htmlstuff = *htmlcode; *htmlcode=0; strcpy(o,i); o += strlen(i); i += strlen(i)-1; *htmlcode = *htmlstuff; break; }; }; strcpy(o,"<"); o += 4; break; case '&': strcpy(o,"&"); o += 5; break; case '>': strcpy(o,">"); o += 4; break; default: *(o++) = *i; break; }; i++; }; *o = 0; strcpy(str,tmp); } double strtod(); #define NPREFIX 2 #define NINFIX 6 #define NTEST 12 #define NCOMPS 10 int ntotal; int numsel; int maxlevel; int reqlevel; int cl; int minlevel; int htmlflag=0; int flatflag=0; int *level=NULL; char dirurl[PATHSIZE]; char infourl[PATHSIZE]; char extend[PATHSIZE]; static int anchor; static char *outnames=NULL; static char objsav[PATHSIZE],parsav[PARSAVSIZE]; char *getenv(); /* =========================================== Subroutines required: =========================================== */ int ioopen_(); /* int ioopen_(s,nparams,ntotal) char s[][]; int *nparams,*ntotal; s[0..nparams-1]: parameter strings. Inner sets s[j][0]=0 for any strings which it processes; others will be processed by outer. Thus selection/projections would normally be ignored by inner. nparams: number of parameter strings ntotal (returned): total number of variable names */ int ioreadrec_(); /* int ioreadrec_(level) int *level; Read record at appropriate level. Return 0 if end at that level. Return 1 if ok. */ void ioclose_(); /* ioclose_() Close files */ void iovalreal_(); /* iovalreal_(vn,f) int *vn; float *f; Return real value (f) for variable indexed by vn. -9999 for strings */ void iovalstr_(); /* iovalstr_(vn,tmp) int *vn; char *tmp; Return string value (tmp) for variable indexed by vn. */ int iovarlevel_(); /* int iovarlevel_(vn) int *vn; Return level corresponding to variable indexed by vn. */ int ioattrout_(); /* ioattrout_(vn, str) int *vn; char *str; Output next attribute for variable indexed by vn. 0=none left. */ void ioname_(); /* ioname_(vn,s) int *vn; char *s; Return name (s) corresponding to variable number vn. */ int iowidth_(); /* int iowidth_(vn); int *vn; Return length of variable field indexed by vn. */ int iocommout_(); /* int iocommout_(s) char *s; Return next comment string. 0=none left. -1=next comment contains a URL */ error_(s1,s2) char *s1,*s2; { if(htmlflag){ printf("

%s: %s

\n",s1,s2); } else if(flatflag) { printf("%s %s\n",s1,s2); } else { printf("&x %s: %s\n",s1,s2); }; if(level)free(level); if(outnames)free(outnames); ioclose_(); exit(0); } /* P-code form: 128..255 exec test(n-128) [negative #'s on Sun] 1=or,2=and,3=not 0: end */ static char *prefix[]={"!","not"}; static char *infix[]={"||","or","|","&&","and","&"}; static char *testop[]={"<","","=","==",">","","<=","","<>","!=",">=",""}; static struct { int testlev; int testvar; int testcode; float testval; char teststr[TOKEN]; int testres; } tst[NCOMPS]; static int tstcnt=0; static int tstproc[NCOMPS]; static int tstproccnt=0; parse(s) char *s; { int opstkp; float f; int opstack[20]; int opprior[20]; char *t,*t1,tok[TOKEN],tmp[TOKEN]; int i,state,typ,finaland; opstkp= 0; opstack[0]=0; opprior[0]= -1; state=0; if (tstproccnt==0) finaland=0; else finaland=1; strcat(s,"$"); t=s; while(t != NULL){ if(isdigit(*t) || *t=='.' || *t=='+' || *t=='-'){ f=strtod(t,&t1); if(strchr(" ()$=<>|&!",*t1)){ typ=1; t=t1; } else { i=strcspn(t," ()$=<>|&!"); strncpy(tok,t,i); tok[i]='\0'; t += i; typ=0; }; } else if(isalpha(*t) || *t=='#'){ i=strcspn(t," ()$=<>|&!"); strncpy(tok,t,i); tok[i]='\0'; t += i; typ=0; } else if(*t == '('){ typ=2; t++; } else if(*t == ')'){ typ=3; t++; } else if(*t == '$'){ typ=4; t=NULL; } else { tok[0]= *t; if((int)strspn(t+1,"&|=>")>0){ tok[1]= *(++t); tok[2]='\0'; } else tok[1]='\0'; t++; typ=5; }; switch(state*10+typ){ case 0: /* variable,not */ for(i=0;i=128) printf("%d %d %f %s\n",tst[tstproc[i]-128].testvar, tst[tstproc[i]-128].testcode,tst[tstproc[i]-128].testval, tst[tstproc[i]-128].teststr); else printf("\n"); }; #endif return; default: error_("Parsing error",""); }; if(*t==' ')t++; }; } int test(cl) int cl; { float f; char tmp[DATUMSIZE]; int i,j,m; int stk[NCOMPS],stkp; #ifdef DEBUG printf("entered test at level %d\n",cl); #endif stkp = -1; stk[0]=1; for(i=0;i= 128){ j=tstproc[i]-128; if(tst[j].testlev < cl)stk[++stkp]=tst[j].testres; else if(tst[j].testlev>cl)stk[++stkp]=1; else { m=0; if(tst[j].testcode<0){ iovalstr_(&(tst[j].testvar),tmp); switch (tst[j].testcode){ case -2:if(strcmp(tmp,tst[j].teststr)==0)m=1;break; case -5:if(strcmp(tmp,tst[j].teststr)!=0)m=1;break; }; } else { iovalreal_(&(tst[j].testvar),&f); #ifdef DEBUG printf("-- %f %d %f -- ",f,tst[j].testcode,tst[j].testval); #endif switch (tst[j].testcode){ case 1:if(ftst[j].testval)m=1;break; case 4:if(f<=tst[j].testval)m=1;break; case 5:if(f!=tst[j].testval)m=1;break; case 6:if(f>=tst[j].testval)m=1;break; }; }; tst[j].testres=m; stk[++stkp]=m; }; } else { switch(tstproc[i]){ case 1: stk[stkp-1]=stk[stkp-1] || stk[stkp];stkp--;break; case 2: stk[stkp-1]=stk[stkp-1] && stk[stkp];stkp--;break; case 3: stk[stkp]=1-stk[stkp]; }; }; }; #ifdef DEBUG printf("test result = %d\n",stk[0]); #endif return stk[0]; } outvar() /* outvar outputs tabs as this is likely being fed into another program or being transferred across a network and therefore, we wish to minimize size of transfer to one character separating fields */ { int i,j; char tmp[OUTVARBUFSIZE],attr[TOTATTRSIZE]; i=1; while(iocommout_(tmp)){ if(i) { printf("&c\n"); i=0; }; printf("%s\n",tmp); }; for(i=0;i<=maxlevel;i++){ printf("&v%d\n",i); for(j=0;j=0){ strcpy(attr,"["); while(ioattrout_(&j,tmp)){strcat(attr,tmp);strcat(attr,";");}; if(strcmp(attr,"[")) attr[strlen(attr)-1]=']'; else attr[0]=0; strcpy(tmp,outnames+j*VARNAMESIZE); if (strstr(attr,"width=") == NULL) strcat(tmp,attr); len=iowidth_(&j); printf("%-*s ",len,tmp); /* output var name in enough space + 2 */ }; printf("\n"); } outputflat(firsttime) int firsttime; { int j,len; char tmp[OUTBUFSIZE]; while(iocommout_(tmp)); for(j=0;j=0){ iovalstr_(&j,tmp); len=iowidth_(&j); printf("%-*s ",len,tmp); }; printf("\n"); minlevel=maxlevel; } outvarhtml() /* routine to print the heading of all data objects if in HTML mode The directory button should always direct the browser back to the directory from which it came. Send link back to referring host for documentation - the .remoteobjects at that site has responsibility of correctly id'ing the INFOSERVER, using hyperlinks from a static obj.info file or Redirect to another host with HTTPD function (NCSA HTTPD 1.5.1 or gt) */ { char tmp[OUTVARBUFSIZE],*ep,*sp; int j; htmlescape(parsav); printf("%s -- Level %d\n",objsav,reqlevel); printf("

%s --%s-- Level %d

\n",objsav,parsav,reqlevel); sp=strrchr(objsav,'/'); sp++; if (*dirurl) { #ifdef BUTTONIMAGESDIR printf("\"Directory\"", dirurl,BUTTONIMAGESDIR); #else printf("Directory | ", dirurl); #endif } #ifndef NOTOPLINKS if (*infourl) { #ifdef BUTTONIMAGESDIR printf(" \ \"Documentation\" ", infourl,dirurl,MYADDR,objsav,reqlevel,BUTTONIMAGESDIR); #else printf(" \ Documentation | ", infourl,dirurl,MYADDR,objsav,reqlevel); #endif } #endif #ifndef NOOTHEROPTS /* syntax of OPTIONSERVER is //machine.domain/jg/script-or-binary */ ep = getenv("OPTIONSERVER"); /* check for no value at all, and default to one set in builde-env */ if (ep == NULL) { strcpy(tmp,OPTIONSERVER); } else strcpy(tmp,ep); #ifdef BUTTONIMAGESDIR printf(" \"Plotting

", tmp, MYADDR,objsav,reqlevel,parsav,BUTTONIMAGESDIR); #else printf(" Plotting and Other Operations... | ", tmp, MYADDR,objsav,reqlevel,parsav); #endif #else printf("

"); #endif tmp[0] = '\0'; #ifndef NOTOPLINKS #ifdef BUTTONIMAGESDIR printf(" \ \"Level ", objsav,extend,BUTTONIMAGESDIR); #else printf("Level 0 | ", objsav,extend); #endif if (parsav) #ifdef BUTTONIMAGESDIR printf(" \"Next ", objsav,reqlevel+1,extend,parsav,BUTTONIMAGESDIR); #else printf(" Next level | ", objsav,reqlevel+1,extend,parsav); #endif else #ifdef BUTTONIMAGESDIR printf(" \"Next ", objsav,reqlevel+1,extend,BUTTONIMAGESDIR); #else printf(" Next level | ", objsav,reqlevel+1,extend); #endif #ifdef BUTTONIMAGESDIR printf(" \"Flat
", objsav,reqlevel,parsav,BUTTONIMAGESDIR); #else printf(" Flat list
", objsav,reqlevel,parsav); #endif #endif printf("\n"); printf("

\n");

  if (*parsav) strcat(parsav,",");

  while( (j=iocommout_(tmp)) != 0 ) {
    if (j>0) 
      htmlescape(tmp);
    printf("# %s\n",tmp);
  };

/* look at attributes to process width attrib - see ioattrout_ */
  for(j=0; j=0) {
      while(ioattrout_(&j,tmp))
        ;
    }
}

outputhtml(firsttime)
int firsttime;
{
  int i,j,len;
  char tmp[OUTBUFSIZE];
  if(minlevel0) 
      htmlescape(tmp);
    printf("# %s\n",tmp);
  };

    for(i=minlevel;i<=maxlevel;i++){
      printf("=========================\n");
      for(j=0;j%-s%*s",                objsav,reqlevel+1,extend,parsav,outnames+j*VARNAMESIZE,
                   tmp,tmp,len-strlen(tmp)+2," ");
	else printf("%-*s  ",len,tmp);
      };

      printf("\n");
    };
    minlevel=maxlevel;
  } else {
    for(j=0;j%-s%*s",
          objsav,reqlevel+1,extend,parsav,outnames+j*VARNAMESIZE,
                   tmp,tmp,len-strlen(tmp)+2," ");
      else printf("%-*s  ",len,tmp);

     };
    printf("\n");
  };
}

main(argc,argv)
/* 
  PATH_INFO carries the referring host
  and directory path to this program, inside curly braces {}.
*/

int argc;
char *argv[];
{
  int i,j,k,nparams,noprojflag;
  char stmp[PATHSIZE],*pp,*sp;

  reqlevel=999;

  pp=getenv("PATH_INFO");
  if(!pp) {
    printf("Content-type: text/plain\n\n");
    strcpy(dirurl,DIRSERVER);
    strcpy(infourl,INFOSERVER);
    extend[0]=0;
  } else {
    strcpy(stmp,pp);      /* make a copy of the PATH_INFO contents */
    if(sp=strstr(pp,".html")) {
        printf("Content-type: text/html\n\n");
	htmlflag=1;
    } else if(sp=strstr(pp,".flat")) {
        printf("Content-type: text/plain\n\n"); 
	flatflag=1;
    } else printf("Content-type: text/plain\n\n");
    if(htmlflag || flatflag) {
    
      reqlevel=atoi(sp+5);
      *sp=0;
      strcpy(objsav,pp);
      /* restore PATH_INFO */
      *sp='.';

/* process PATH_INFO contents which may contain referring host info */

      if(sp=strchr(stmp,'{')) {
	strcpy(extend,sp);
	*sp=0;
	
/* find the directory string, starts with dir= */
	
        if(sp=strstr(extend,"dir=")) {        
          strcpy(dirurl,sp+4);        /* move to value beyond "dir=" */
          pp=strpbrk(dirurl,",}");
          if(pp)*pp=0;
        } else {
          strcpy(dirurl,DIRSERVER);
        }

/* find the information-serving string, starts with info= */

        if(sp=strstr(extend,"info=")) {
          strcpy(infourl,sp+5);      /* move to value beyond "info=" */
          pp=strpbrk(infourl,",}");
          if(pp)*pp=0;
        } else {
          strcpy(infourl,INFOSERVER);;
        }

/* otherwise, NO EXTENDED URL supplied, signal for NO BUTTONS */

      } else {
          strcpy(dirurl,DIRSERVER);
          strcpy(infourl,INFOSERVER);
	  extend[0]=0;
      };
    };
  };

  pp=getenv("QUERY_STRING");
  if(pp)  strcpy(parsav,pp); else *parsav=0;

  level=NULL;

  nparams=argc-1;
  k=ioopen_(argv+1,&nparams,&ntotal);

  if(k>reqlevel) anchor=1; else anchor=0;
  noprojflag=1;numsel= -1;
  outnames=(char *)malloc(VARNAMESIZE*ntotal);
  for(j=0;j=")) parse(stmp);
      else {
	for(k=0;k= -reqlevel-1) 
	  *(level+k)= - *(level+k)-1;
	noprojflag=0;
      };
    };
  };

  if(noprojflag)for(i=0;i= -reqlevel-1) *(level+i)= - *(level+i)-1;

  maxlevel=0;
  for(j=0;jmaxlevel)maxlevel= *(level+j);
/*
  for(j=0;j= 128)
      if(tst[j].testlev > maxlevel) maxlevel=tst[j].testlev;
*/
  if(reqlevel>maxlevel) reqlevel=maxlevel;

#ifdef DEBUG
  printf("maxlevel %d\n",maxlevel);
#endif

  minlevel=maxlevel;
  cl=0;
  k=1;

  if(htmlflag) outvarhtml();
  else if (flatflag) outvarflat();
  else outvar();

  while(1){
    if(ioreadrec_(&cl)){
#ifdef DEBUG
      printf("succ. read at lev %d\n",cl);
#endif

      if(test(cl))
	if(cl\n"); 
  else if(!flatflag)printf("&e\n");
}