/* outer_brev.c version 1.0 came from outer.c version 2.5, JGOFS 1.5 release (as of 10 Jan 98). Incompatibilities 1) outer_brev variable names may not include spaces or percent signs. 2) Non-numeric data values (including "nd") cannot be selected with numeric operators 3) When clicking on a datum to use it as a selection for the next level, comparisons are done as strings instead of numbers 4) Rely on program exit to free dynamically allocated memory */ #define OUTER_VERSION "outer_brev version 1.3a 16 Dec 1998" /* 16 Dec 98 v 1.3a WJS Bug fix: logical vars need to be signed. Try to learn from v 1.2a!! Bug fix: compile-time OTHEROPTS was not being used as default for runtime PLOTLINK and vice versa. [Released for beta test on synthesis 16 Dec 98] [Needs outer.h 1.0a] [Needs outer_utils.c 1.0] [Needs path_info_routines 1.2 or later (.c & .h)] [Begin 1.3a] 10 Dec 98 v 1.3 WJS Next-level links use string equality to determine what data at next level is displayed (unless GENERATE_ALPHA_SELECTIONS is turned off). Mods to "top" links 1) Add per-link display control 2) If at level 0, display "nolevel0" gif instead of "Level 0" link. 3) If at last level, display "nolevelN" gif instead of "Level N" link. 4) Use "Level N" for alternate text for next level button. 5) If TEST_GIFS defined, test for button gif existence before generating link to gif. If gif does not exist, display its "alt" text instead Mods to selection/projection code 1) String operations eq,ne,lt,le,gt,ge,contains,is_contained_in, begins_with,ends_with. (These ops typically delimited w/blanks - see trigram mod, below, for way to get blanks into query strings) 2) Parametrize stack size and increase. Still do not test for overflow 3) Do some restructuring & commenting. Remove need for a couple of compile-time constants Accept %hh trigram in selection strings and convert it to the (hopefully) ASCII character corresponding to the hex value of hh. To get a real percent sign in the query string, use %25. A leading 0 must be present, if appropriate; eg, use %09 for tab, not %9. Use iovaldouble_ function instead of iovalreal_ if USE_DOUBLE is defined as TRUE Dynamically allocate more buffers. Can remove PATHSIZE from .h file Calculate some buffer sizes. Can remove OUTVARBUFSIZE & OUTBUFSIZE from .h file More flexibility in BUTTONIMAGESDIR spec. Accept it with or without trailing /. If no protocol (ie, :// string), prepend file://localhost (with another / if necessary) Bug fix: was adding port even when MYADDR had port in it. Bug fix: remove blank btwn "Documentation" & "Plotting and Other Op" Bug fix: v 1.1 handling of query string w/blanks NG since htmlescape doesn't "do" blanks. Improper use of htmlescape anyway - it's designed to allow printing of text w/html special chars such that html formatting doesn't happen. Put htmlescape & some new routines in outer_utils.c Put lots of #defines, etc, in outer.h [Released for beta test on synthesis] [Needs outer.h 1.0] [Needs outer_utils.c 1.0] [Needs path_info_routines 1.2 or later (.c & .h)] [Begin 1.3] 15 May 98 v 1.2a WJS Remove indented macros - cause trouble w/some compilers Type parse and error_ Bug fix: mismatch between format & list of variables in ("&r\n",i) Remove the ,i which wasn't getting printed (or used by jdb) anyway Bug fix: need signed char for char vars that can go negative. [Distributed w/various defgb pkgs] [Begin 1.2a] 12 May 98 v 1.2 WJS OO_OUTER switch Bug fix: need to propagate .brev to documentation button [Not sure if 1.2 "got out". Wasn't intended to...] [Unfortunately, it appears it made it to dataone someplace. Sorry Chris...] [Begin 1.2] 4 Mar 98 v 1.1a WJS Change a couple of variable names & improve a couple of comments 13 Feb 98 v 1.1 WJS htmlescape query strings in level n+1 links in case they contain blanks. Correct path_info version requirement (always needed 1.2) [Distributed w/various defgb pkgs] [Needs path_info_routines 1.2 or later (.c & .h)] [Begin 1.1] 10 Feb 98 v 1.0 WJS Support for "short listing" format. See outer_brev.doc. Propagate SERVER_PORT if not overridden by (new) switch MYPORT (and if not port 80) Accept all compilation switches (NOTOPLINKS, etc) from environment if present there. If not, use compilation switch value. Accept TRUE, FALSE, 1, 0 as values for compilation switches. Accept "all reasonable" true/false strings as values for env variables Accept affirmative compilation switch names, too; eg, TOPLINKS=FALSE is the same as NOTOPLINKS=TRUE (which has always been the same as NOTOPLINKS) Accept *SERVER with or without leading //s Restructure outvarhtml Use path_info_routines Fix small problem with putting | after text-only links that turn out not to be the last in line. Get some memory dynamically Removes need for some default.h defns (at least PARSAVSIZE) Reduce likelihood of SEGV on htmlescape'd strings If MYADDR not supplied, use SERVER_NAME In QUOTENOLINK environment, don't truncate last char if not a " Give explicit types to out* functions Add a VMS compilation switch for convenience of WJS Comments: invert time order & reformat outer 2.5 comments [Needs path_info_routines 1.2 or later (.c & .h)] [Begin 1.0] outer.c version 2.5 Jun 97 grf lots of fixes for v 1.5 May 96 grf added BUTTON flag for new links if you wish them to be displayed as buttons rather than links ??? ?? grf added error routine callable from outer or inner - should produce sensible output in all modes 26 Feb 96 v 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 14 Feb 96 v 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 27 Jan 96 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 23 Jan 96 clh added 'void' typing to the functions that this outer method expects from its inners; to avoid warnings from ANSI compilers 13 Sep 95 clh added option to NOT print the OTHER OPTIONS links, using a precompiler option 'NOOTHEROPTS' added option to NOT generate links from quoted strings code taken from outerqn.c, using precompiler option 'QUOTENOLINK' 10 Jul 95 clh Include field widths */ /* =========================================== 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 Note: this routine should NOT call error_ */ 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 */ /* All #includes in outer.h */ #include "outer.h" typedef signed char Logical; /* NB: occasionally gets -1, */ /* hence need signed */ /* jgofs.a functions... */ /* HTDoConnect in turn requires some functions, presently found */ /* jgofs.a. Some are HT*.c modules; a couple are in jdb.c */ /* These functions needed only for testing for gifs, which is turned */ /* off by default. However, can't eliminate these defns based on */ /* compile-time TEST_GIFS, since user can spec tests at run time */ /* (only useful time, if functionality useful at all). */ /* If requiring these functions causes trouble (eg, no jgofs.a), */ /* should unconditionally set test_gifs to false. Suggest testing */ /* it first, and aborting if true (on grounds that somebody appears */ /* to want gifs tested, and we're not about to do it) */ int HTDoConnect(); int HTDoRead(); /* outer_utils.c functions... */ char *htmlescape(); char *trigram(); char *un_trigram(); #if USE_DOUBLE #define ioval iovaldouble_ typedef double Comp_precision; #else #define ioval iovalreal_ typedef float Comp_precision; #endif double strtod(); void ioval(); int ntotal; int minlevel; int maxlevel; int reqlevel; int maxobjectlevel; int cl; int brevflag=0; int htmlflag=0; int flatflag=0; int *level=NULL; int brevstart; int brevcount; int brevend; /* PATH_INFO stuff. Functions are in path_info_routines */ char *flat_PATH_INFO,*nextlevel_PATH_INFO,*level0_PATH_INFO; char *no_extURL_PATH_INFO,*full_list_PATH_INFO; char *propagate_brev_no_extURL_PATH_INFO; char *make_PATH_INFO_putenv_string(),*get_jgofs_env_datum(); int get_level(); static char *outnames=NULL; char *parsav; char *objsav; char *getenv(); Logical dirlink,doclink,plotlink,lev0link,levnlink,flatlink; Logical quotenolink,toplinks,otheropts,oo_outer; Logical test_gifs; char *buttonimagesdir; Logical trailing_buttonimagesdir_slash; /* Format of "server" is node (optionally w/port), followed by cgi */ /* program name. Program name by itself can be used if we know */ /* that node is local. A node spec does not include a leading // */ /* (but we'll strip them off found) */ char *dirserver_w_dir; char *optionserver; char *infoserver_w_obj,*infoserver_extURL; char *dataserver,*localnodeport; char *equality_test; /* Links generate string or numeric test? */ /************************************************************************/ void error_(s1,s2) char *s1,*s2; { if(htmlflag){ printf("
\n",s1,s2); } else if(flatflag) { printf("%s %s\n",s1,s2); } else { printf("&x %s: %s\n",s1,s2); }; /* More dynamically allocated memory could be explicitly freed here, */ /* and probably should be so freed, but I'm lazy */ if(level)free(level); if(outnames)free(outnames); ioclose_(); exit(0); } void out_err(s,t) char *s,*t; { char *ptr1,*ptr2; time_t timbuf; ptr1 = (char *) malloc (strlen(s) + 2 + strlen(t) + 1); if (ptr1 == NULL) error_(s,t); ptr2 = (char *) malloc (20 + 26 + 17 + strlen(OUTER_VERSION) + 1 + 1); if (ptr2 == NULL) error_(s,t); strcpy (ptr1,s); strcat (ptr1,": "); strcat (ptr1,t); strcpy (ptr2,"\n This msg issued "); time(&timbuf); strcat (ptr2,ctime(&timbuf)); /* ctime includes \n */ strcat (ptr2," This msg from "); strcat (ptr2,OUTER_VERSION); strcat (ptr2,"\n"); error_(ptr1,ptr2); return; } void out_errn(s,n,fmt) char *s,*fmt; int n; { char intbuf[25]; sprintf(intbuf,fmt,n); out_err(s,intbuf); return; } void malloc_err(s,n) char *s; int n; { /* Don't want to malloc an error buffer if we're having trouble */ /* malloc'ing in the first place */ /* Tried putting malloc in here, too, returning ptr when OK, but */ /* ran into BUSERR alignment problems. Don't know why... */ #define MAX_S 50 char idbuf[25 + MAX_S + 15 + 1] = "Could not get memory for "; int len; if ( (len = strlen(s)) > MAX_S ) len = MAX_S; strncat(idbuf,s,len); strcat(idbuf,". nbytes (hex) "); out_errn(idbuf,n,"%x"); return; } /* P-code form: 128..255 exec test(n-128) [negative #'s on Sun] [negativity not used in this code-fortunately. WJS] 1=or,2=and,3=not 0: end */ #define NTESTS 100 /* Number of selections/projections */ #define OPSTACKSIZE 20 /* Depth of operation stack; eg (a+b)*(c+d) */ /* needs a depth of 3 */ /* Within each of next 4 arrays, "equivalent" strings (eg, != & <>) */ /* are grouped together. "Group size" is constant (eg, see empty */ /* strings in testop where there are no equivalent strings). Groups */ /* are ordered to drive "switch" statements in code, so order alter- */ /* ation means code alteration. Infix array is ordered by operation */ /* priority as well. testop is parallel to teststrop as far as it */ /* goes. testop defines numeric comparisons; teststrop string */ /* comparisons. */ /* Each array ends with NULL */ /* Recoded not to use prefix array, since "not" prefix (and any */ /* future one like it) must be tested for in variable section, */ /* while ! is tested for in "normal" special character section */ static char *prefix[]={"!","not",NULL}; static char *infix[]={"||","or","|","&&","and","&",NULL}; static char *testop[]={"<","","=","==",">","","<=","","<>","!=",">=","",NULL}; static char *teststrop[]={"lt","eq","gt","le","ne","ge","contains", "is_contained_in","begins_with","ends_with",NULL}; #define SIZE_PREFIX_GROUP 2 #define SIZE_INFIX_GROUP 3 #define SIZE_TESTOP_GROUP 2 static struct { int testlev; int testvar; int testcode; Comp_precision testval; char *teststr; int lenteststr; int testres; } tst[NTESTS]; static int tstcnt=0; static int tstproc[NTESTS]; static int tstproccnt=0; void parse(s) char *s; /* Description is approximate. Seems to me it can do */ /* weird things with not... */ /* Parser has 4 states: variable or open paren */ /* comparison operator */ /* thing being compared */ /* logical operator or close paren or end */ /* Idea is to get next token, determine its type, the process it */ /* depending on the state the parser is in (possibly changing state) */ { int opstkp; Comp_precision f; int opstack[OPSTACKSIZE]; int opprior[OPSTACKSIZE]; char *t,*t1,tok[TOKEN+1],tmp[TOKEN+1]; int i,state,typ,finaland,type_string_op,paren_depth; paren_depth = 0; opstkp = 0; opstack[0] = 0; opprior[0] = -1; state = 0; finaland = (tstproccnt != 0); strcat(s,"$"); t = s; while (t != NULL) { /* Scheme: If first char not one of the special ones, save the */ /* token. Resulting alpha token can be "not" operator or one of */ /* the string operators. */ /* In original outer code, a token beginning with something like @ */ /* would show up as "bad prefix operator". In this code, I think */ /* it will show up as "error on conditions" */ /* The original outer code for this section is commented at the */ /* end of this file */ /* Skip leading blanks. Whole string cannot be blank because of */ /* appended $, above */ t += strspn(t," "); switch (*t) { case '(': paren_depth++; typ = 2; t++; break; case ')': if ((--paren_depth) < 0) out_err("Illegally nested parens",s); typ = 3; t++; break; case '$': typ = 4; t = NULL; break; case '=': case '<': case '>': case '|': case '&': case '!': tok[0] = *t; /* Check for 2nd char of 2-char ops like !=. Validity */ /* of particular 2-char combo checked later */ switch (*(t+1)) { case '&': case '|': case '=': case '>': tok[1] = *(++t); tok[2] = '\0'; break; case '$': out_err("No argument after last logical operator",s); break; default: tok[1] = '\0'; break; } typ = 5; t++; break; default: /* alpha token. Could still be string operator... */ if ( (i = strcspn(t," ()$=<>|&!")) > TOKEN ) out_err("Token too long",tok); strncpy(tok,t,i); tok[i] = '\0'; t += i; type_string_op = -1; while (teststrop[++type_string_op] != NULL) if (strcmp(teststrop[type_string_op],tok) == 0) break; if (teststrop[type_string_op] == NULL) { /* Token is not string operator. See if it's numeric */ f=strtod(tok,&t1); typ = (*t1 == '\0') ? 1 : 0; } else { type_string_op++; /* Begins-w-0 vs begins-w-1 mod */ typ = 6; } break; } switch (state*10+typ) { case 0: /* variable or the string "not" */ case 6: /* string operator could be a variable name, too */ for (i=0; i%s: %s
");
print_vert_bar (NULL,TRUE);
}
}
if (lev0link) {
if (maxlevel == 0) {
ptr = " - At level 0 - ";
ptr1 = gifs[NOLEVEL0_GIF];
print_vert_bar (ptr1,FALSE);
printf("");
} else {
ptr = "Level 0";
ptr1 = gifs[LEVEL0_GIF];
print_vert_bar (ptr1,FALSE);
/* Why doesn't the level 0 button get a query string? */
/* Don't know, but for "outer for option server", it does per */
/* Chris (Apr 98) */
if (oo_outer)
printf ("",
JGOFS_DATA_CGI_SPEC, level0_PATH_INFO, parsav);
else
printf("", JGOFS_DATA_CGI_SPEC, level0_PATH_INFO);
}
tag_toplink(ptr, ptr1);
}
if (levnlink) {
if (maxlevel < maxobjectlevel) {
ptr = next_level;
ptr1 = gifs[LEVELN_GIF];
print_vert_bar (ptr1,FALSE);
printf ("",
JGOFS_DATA_CGI_SPEC, nextlevel_PATH_INFO, parsav);
sprintf(next_level,"Level %d",maxlevel+1);
} else {
ptr = " - At last level - ";
ptr1 = gifs[NOLEVELN_GIF];
print_vert_bar (ptr1,FALSE);
printf("");
}
tag_toplink(ptr, ptr1);
}
if (flatlink) {
print_vert_bar (gifs[FLAT_GIF],FALSE);
printf ("",
JGOFS_DATA_CGI_SPEC, flat_PATH_INFO, parsav);
tag_toplink("Flat list", gifs[FLAT_GIF]);
}
/* If we are displaying buttons, " comment, above) */
if (any_buttons_on_line_1 || any_buttons_on_line_2) printf("
" (whatever that is) */
/* I wonder if this should also happen in a NOTOPLINKS environment */
/* (See
");
printf("\n");
printf("\n");
print_comments_html();
/* look at attributes to create array of widths - see ioattrout_ */
for(j=0; j%*s",
JGOFS_DATA_CGI_SPEC, nextlevel_PATH_INFO,
parsav, comma, outnames+j*VARNAMEBUFSIZE, equality_test, ptr,
tmp,
field_width-len_datum+2, " "
);
free (ptr);
}
else printf("%-*s ",field_width,tmp);
}
printf("\n");
return;
}
void print_full_list_link (s)
char *s;
{
#define BREVLINKINDENT 16
printf ("%*s%s\n",BREVLINKINDENT," ",s);
printf ("%*sFull data listing\n",
BREVLINKINDENT, " ", JGOFS_DATA_CGI_SPEC, full_list_PATH_INFO, parsav);
return;
}
Logical outputhtml(firsttime)
Logical firsttime;
{
/* linecount for abbreviated listing feature */
static int linecount;
int i,j;
/* minlevel != maxlevel for first record of each maxlevel file */
/* in a multilevel display */
if (minlevel