/* jdb.c - forms primary routines for the JGOFS data system */ /* used from jgofs.a */ #define JDB_VERSION "jdb version 1.3b 4 Nov 2009" /* 4 Nov 09. 1.3b WJS */ /* Check that unit number is in range */ /* Check success of memory allocation for unit structure */ /* [Needs core.h 2.0d] */ /* [Begin 1.3b] */ /* 21 Mar 09. 1.3a WJS */ /* jdbread_ should allow trailing blanks in its numeric fields */ /* [Needs core.h 2.0] */ /* [Begin 1.3a] */ /* 29 Feb 08. 1.3 WJS */ /* Use is_a_remote_object instead of just initial // */ /* Take responsibility here for putting // after http: rather */ /* than relying on the object spec to start w/ // */ /* Add a test for empty object spec in htopen */ /* [Begin 1.3] */ /* */ /* 10 Jun 07. 1.2a WJS */ /* When removing ()s, check that 2nd char is a ) */ /* [Needs core.h 1.5a] */ /* [Begin 1.2a] */ /* 29 Mar 07. 1.2 WJS */ /* Check for jdbread buffer overflow (why did this take 7 years */ /* since the first buffer length checks, which were harder to do */ /* and far less common??!) */ /* Parametrize nd */ /* 16 Dec 06. 1.2 WJS */ /* Buffer comments to limits of system memory instead of to */ /* COMMENTSIZE */ /* 13 Oct 06. 1.2 WJS */ /* Mods to jdbread_ handling of non-numeric strings */ /* 1) Use strtod to see if string is numeric. Old code */ /* said "numeric if string is digits, +, -, ." which */ /* accepts as legal +01-..23 but rejects 1.33E04 */ /* 2) Return -9999. for non-numeric strings instead of */ /* -9999.99. THIS BREAKS THINGS. However, w/o it, */ /* jdbread_ users would consider -9999. a legal value */ /* Parametrize jdb conditions. Note comment of 1 Oct 99 - */ /* turns out one of those pieces of "perverse code" is defgb! */ /* [Needs core.h 1.5] */ /* [Begin 1.2] */ /* */ /* 4 Jun 05. 1.1h WJS */ /* Need type as part of HTCheckActiveIcon definition */ /* 25 Aug 04. 1.1g WJS */ /* Use core.h */ /* Standardize version stuff */ /* Get rid of strdup (ULTRIX) function */ /* 17 Jan 04. 1.1f WJS */ /* localopen was parsing "par" starting from par+1, missing */ /* initial (. Seems this was an oversight - compare w/serv.c */ /* 18 Dec 03. 1.1e WJS */ /* Get rid of last(?) 3 exits (in favor of "return error"s) */ /* 29 Jul 03. 1.1d WJS */ /* JDB_DEBUGn conditional compilations */ /* n=1 means print something to stdout for all non-0 returns */ /* 2 means enable original debug traces */ /* 3 means dump data buffers */ /* 25 Jun 03. 1.1d WJS */ /* Get rid of extra "opening" in error message */ /* 15 Nov 01. 1.1c WJS */ /* 'Bout time to fix last year's bug discoveries */ /* 4 Nov 00. 1.1c WJS */ /* Put in a couple of #### ERROR #### comments to point to probs */ /* that should be fixed. No fixes yet */ /* 5 May 00. 1.1b WJS */ /* "major" and "minor" variable names caused trouble on Mike Car- */ /* uso's Solaris 7 box. */ /* 1 Feb 00. 1.1a WJS */ /* Bug fix: HTDoRead can return a negative value. Handle this. */ /* Bug fix: -998 comment from 1 Oct not fully implemented. Do it. */ /* 18 Oct 99. 1.1 WJS */ /* Skip data before initial &. Original code assumed jdbopen be- */ /* gan in "&c" mode. Addition of HTTP/1.0 to GET causes server to */ /* respond w/various info (terminated by empty crlf line) before */ /* beginning w/real data */ /* Do some restructuring... but not enough. */ /* 1 Oct 99. 1.1 WJS */ /* Add "Host: " request-header field to GET's, along with HTTP/1.0 */ /* ID. Host: required to implement virtual hosting. ID seems to be */ /* required in order to make Host: effective... ? Content of mods */ /* from rfc 2616 and from Glenn's "last" transfer.c code, which ad- */ /* dressed this issue ~Dec 97. */ /* Add some buffer size tests in this part of the code. Return */ /* -998 if there would be overflow. There might be perverse code */ /* that thinks "only -999 means bad". -998 will take the "OK" path */ /* and die in an ugly fashion. On the other hand, w/o the buffer */ /* testing, a failure would have been ugly whether it happened be- */ /* fore or after return from jdb */ /* Define macros to make it compile more cleanly (under VMS anyway)*/ /* [Begin 1.1] */ /* */ /* 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 "core.h" #ifndef JDB_DEBUG1 #define JDB_DEBUG1 0 #endif #ifndef JDB_DEBUG2 #define JDB_DEBUG2 0 #endif #ifndef JDB_DEBUG3 #define JDB_DEBUG3 0 #endif #if JDB_DEBUG1 #define CHAR_DEBUG1 "DEBUG1 " #else #define CHAR_DEBUG1 "" #endif #if JDB_DEBUG2 #define CHAR_DEBUG2 "DEBUG2 " #else #define CHAR_DEBUG2 "" #endif #if JDB_DEBUG3 #define CHAR_DEBUG3 "DEBUG3 " #else #define CHAR_DEBUG3 "" #endif #if JDB_DEBUG1 || JDB_DEBUG2 || JDB_DEBUG3 #define NO_DEBUG "D" #else #define NO_DEBUG "No d" #endif char *debug_flags=NO_DEBUG "ebug flags " CHAR_DEBUG1 CHAR_DEBUG2 CHAR_DEBUG3; #if SOL || HP #include #include #endif /* added for JGOFS release v1.5 compatibility (not clear which parts of */ /* these OPTIONS & INNEROPTIONS are actually required - WJS) */ #include INNEROPTIONS int dctsearch(); int is_a_remote_object(); /* utils.c; library */ int HTDoConnect(); int HTDoRead(); /* As new conditions come along, define them in core.h and add them */ /* here. For various reasons, do NOT put EOF in this list */ int jdb_conditions [] = { JDB_CONDITION_ERROR, JDB_CONDITION_INTERNAL_BUFOVF, JDB_CONDITION_BADATTRLIST, JDB_CONDITION_DATA_BUFOVF, JDB_CONDITION_NOPIPES, JDB_CONDITION_BADFORK, JDB_CONDITION_DCTSEARCHFAILURE, JDB_CONDITION_VARNOTFOUND, JDB_CONDITION_COMMENT_BUF_OUT_OF_MEM, JDB_CONDITION_NO_CLOSE_PAREN, JDB_CONDITION_BADOBJECTSPEC }; /************************************************************************/ char *jdb_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[] = JDB_VERSION"/"COREH_VERSION; return version; } Logical jdb_known_condition(status) int status; { int i; for (i=0; i<(sizeof(jdb_conditions)/sizeof(int)); i++) if (status == jdb_conditions[i]) return TRUE; return FALSE; } int HTCheckActiveIcon(i) int i; { return 0; } void HTClearActiveIcon() { } void HTProgress(msg) char *msg; { /* fprintf(stderr,"%s\n",msg); */ } /* below values indicating buffers should be minimally 4k */ #define HTSIZE INBUFSIZE #define MAX_BUF INBUFSIZE #define NUMNAMES NVAR struct OBJECT { char htbuff[HTSIZE]; int htbufflen; int htbuffptr; int socket; int maxlevel,ntotal; int lvlpntr[11]; int rdpntr[NUMNAMES]; int commentbufsize, comment_size_so_far, next_unreturned_comment_offset; char *commentbuf; char attributes[NUMNAMES][TOTATTRSIZE], *attributeptr[NUMNAMES]; }; #define MAX_UNITS 5 static struct OBJECT *object[MAX_UNITS]={NULL,NULL,NULL,NULL,NULL}; int bgets(comm,len,obj) char *comm; int len; struct OBJECT *obj; { int op; char c; #if JDB_DEBUG2 printf("entered bgets\n"); #endif if (obj->htbufflen < 0) { #if JDB_DEBUG1 printf ("Immediate exit from bgets - obj->bufflen = %d on entry\n", obj->htbufflen); #endif return 1; } op = 0; while (1) { if (obj->htbuffptr >= obj->htbufflen) { obj->htbufflen = HTDoRead(obj->socket,obj->htbuff,HTSIZE); if (obj->htbufflen <= 0) { #if JDB_DEBUG1 printf("Exit from bgets due to non-pos return (%d) from HTDoRead\n", obj->htbufflen); #endif obj->htbufflen= -1; return 1; } obj->htbuffptr = 0; #if JDB_DEBUG3 printf("
DATA!!!%s!!!ENDDATA\n
",obj->htbuff); #endif } /* Note: RFC 1945 says that "bare" LF or CR (as well as CRLF) */ /* should be accepted. Code below doesn't accept bare CR */ if ( (c=obj->htbuff[obj->htbuffptr++]) != '\r' ) { if (op < len) comm[op++] = c; else { comm[len] = '\0'; /* For sanity's sake... */ obj->htbufflen= -1; #if JDB_DEBUG1 printf("Exit from bgets due to buffer ovf. buf siz = %d\n", len); #endif return -1; } } if (c == '\n') { comm[--op] = '\0'; return 0; } } } int htopen(comm,par,obj) char *comm,*par; struct OBJECT *obj; { char *cp,*host_start; char met[MAX_BUF]; int i,handle; int reqd_htbuff_size; /* dataserver host name starts after 1 or 2 initial slashes */ host_start = comm; if (*host_start == '/') { host_start++; } else { #if JDB_DEBUG1 printf ("Exit from htopen - initial / missing. buffer = %s\n",comm); #endif return JDB_CONDITION_BADOBJECTSPEC; } if (*host_start == '/') host_start++; cp=strchr(host_start,'/'); if (cp==NULL) { #if JDB_DEBUG1 printf ("Exit from htopen - / after host missing. buffer = %s\n",comm); #endif return JDB_CONDITION_BADOBJECTSPEC; } if (cp == host_start+1) { #if JDB_DEBUG1 printf ("Exit from htopen - no object spec aft host. buffer = %s\n",comm); #endif return JDB_CONDITION_BADOBJECTSPEC; } *cp =0; /* 13 for GET /jg/serv/; 9 for " HTTP/1.0"; 3 for cr,lf,null */ /* at end */ reqd_htbuff_size = 13 + strlen(cp+1) + 9 + 3; if (reqd_htbuff_size > sizeof(obj->htbuff)) return JDB_CONDITION_INTERNAL_BUFOVF; strcpy(obj->htbuff,"GET /jg/serv/"); strcat(obj->htbuff,cp+1); if(par){ if(*par){ /* 1 for ? */ reqd_htbuff_size += 1 + strlen(par); if (reqd_htbuff_size > sizeof(obj->htbuff)) return JDB_CONDITION_INTERNAL_BUFOVF; strcat(obj->htbuff,"?"); strcat(obj->htbuff,par); }; }; strcat(obj->htbuff," HTTP/1.0"); /* 7 for http:// */ if ((7 + strlen(host_start)) > sizeof(met)) return JDB_CONDITION_INTERNAL_BUFOVF; strcpy(met,"http://"); strcat(met,host_start); i=HTDoConnect(met,"HTTP",80,&handle); if (i != 0) { printf("Connect to %s failed\nHTDoConnect return = %d\n",met,i); return JDB_CONDITION_ERROR; } obj->socket = handle; cp=obj->htbuff+strlen(obj->htbuff); *(cp++)='\r'; *(cp++)='\n'; *cp=0; /* 6 for "Host: "; 4 for crs,lfs. Don't need to count null since */ /* "old" null, above, is being overwritten by stuff */ reqd_htbuff_size += 6 + strlen(comm+2) + 4; if (reqd_htbuff_size > sizeof(obj->htbuff)) return JDB_CONDITION_INTERNAL_BUFOVF; strcat(obj->htbuff,"Host: "); strcat(obj->htbuff,comm+2); cp = obj->htbuff + reqd_htbuff_size - 5; /* ... + strlen(obj->htbuff) */ *(cp++)='\r'; *(cp++)='\n'; *(cp++)='\r'; *(cp++)='\n'; *cp=0; /* -1 so null is not included */ write(handle,obj->htbuff,reqd_htbuff_size-1); 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; 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"); return JDB_CONDITION_NOPIPES; } switch(childpid = fork()) { case -1: perror("bad fork"); return JDB_CONDITION_BADFORK; case 0: #if JDB_DEBUG2 printf("got here after fork\n"); #endif 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; isocket=pipefrom[0]; close(pipeto[1]); /* wjs addition 15 Aug 99 */ /* setbuf(frch,NULL);*/ return 0; } } void close_object(tunit) int tunit; { close (object[tunit]->socket); free (object[tunit]); object[tunit] = NULL; return; } int skip_one_line_from_outer(comm,tunit) int tunit; char *comm; { switch (bgets(comm,MAX_BUF-1,object[tunit])) { case -1: printf("&x jdb: data line too big. Start of line: %s\n",comm); return JDB_CONDITION_DATA_BUFOVF; case 1: #if JDB_DEBUG1 printf ("skip_one_line exiting due to getting a 1 from bgets\n"); #endif return JDB_CONDITION_ERROR; } if (comm[0]=='&') if (comm[1]=='x') { printf("%s\n",comm); close_object(tunit); return JDB_CONDITION_ERROR; } 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,comment_len; int remote_object_flag,nitem; int http_vers_major,http_vers_minor,http_status,http_text_offset; char comm[MAX_BUF]; char met[MAX_SERV_DCT_BUF],par[MAX_SERV_DCT_BUF]; char state,*cp,*ap; struct OBJECT *o; for (tunit = 0; tunit < MAX_UNITS; tunit++) if (object[tunit] == NULL) break; if (tunit >= MAX_UNITS) { printf("Out of units\n"); return JDB_CONDITION_ERROR; } o = (struct OBJECT *)malloc(sizeof(struct OBJECT)); if (o == NULL) return JDB_CONDITION_NOMEM_FOR_UNITSTRUCT; 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]=')'; } #if JDB_DEBUG2 printf("++%s++\n",comm); #endif /* find it */ if (cp = strchr(comm,'(')) { strcpy(par,cp+1); *cp = '\0'; i = strlen(par)-1; if ( par[i] == ')' ) { par[i]='\0'; } else { printf("&x Error - parenthesis mismatch: %s\n",comm); return JDB_CONDITION_NO_CLOSE_PAREN; } } else { *par = '\0'; } if (dctsearch(comm,met,par,1) == 0) { printf("&x Error - not found: %s %s\n",met,comm); return JDB_CONDITION_DCTSEARCHFAILURE; } remote_object_flag = (is_a_remote_object(met) != 0); if (remote_object_flag) { if ( (i = htopen(met,par,o)) != 0 ) { cp = (i == JDB_CONDITION_INTERNAL_BUFOVF ) ? "htopen buffer overflow" : "Error"; printf("&x %s opening remote object: %s\n",cp,met); return i; } } else if (localopen(met,par,o) != 0) { printf("&x Error opening local object: %s\n",met); return JDB_CONDITION_ERROR; } o->htbufflen=0; o->htbuffptr=0; o->commentbufsize = COMMENTSIZE; o->commentbuf = (char *) malloc (o->commentbufsize); if (o->commentbuf == NULL) return JDB_CONDITION_COMMENT_BUF_OUT_OF_MEM; *(o->commentbuf) = '\0'; o->next_unreturned_comment_offset = 0; o->comment_size_so_far = 0; for(i=0;irdpntr[i]= -1; o->attributeptr[i] = o->attributes[i]; }; o->ntotal=0; if (remote_object_flag) { /* We sent a "full request". Check that we got a "full */ /* response" (eg, "HTTP/1.0 200 OK")... and (mostly) skip it. */ /* Details in RFC 1945. Note in particular that (as I read it) */ /* the space between the "200" and the "OK" is required. Also */ /* note that we allow more than one blank around status which */ /* may not be standard-compliant */ switch (bgets(comm,MAX_BUF-1,o)) { case -1: printf("&x jdb: data line too big. Start of line: %s\n",comm); return JDB_CONDITION_DATA_BUFOVF; case 1: #if JDB_DEBUG1 printf("jdbopen (remote obj) exiting due to return of 1 from bgets#1\n"); #endif return JDB_CONDITION_ERROR; } nitem = sscanf(comm,"HTTP/%d.%d %d %n", &http_vers_major,&http_vers_minor,&http_status,&http_text_offset); if (nitem < 3) { printf ("jdb: remote http server not >= v 1.0? response: %s\n",comm); close_object(tunit); return JDB_CONDITION_ERROR; } /* Maybe should do better job w/other statuses */ if (http_status >= 400) { printf ("jdb: http protocol error %d text: %s\n", http_status, comm + http_text_offset); close_object(tunit); return JDB_CONDITION_ERROR; } while (comm[0] != '\0') { if (bgets(comm,MAX_BUF-1,o) == 1) { #if JDB_DEBUG1 printf("jdbopen (remote obj) exiting due to return of 1 from bgets#2\n"); #endif return JDB_CONDITION_ERROR; } } } else { /* Skip "content-type:text/html"; crlf lines */ i = skip_one_line_from_outer(comm,tunit); if (i != 0) return i; i = skip_one_line_from_outer(comm,tunit); if (i != 0) return i; } state='c'; o->maxlevel= 0; while(1) { switch (bgets(comm,MAX_BUF-1,o)) { case -1: printf("&x jdb: data line too big. Start of line: %s\n",comm); return JDB_CONDITION_DATA_BUFOVF; case 1: #if JDB_DEBUG1 printf("jdbopen exiting due to return of 1 from bgets#3\n"); #endif return JDB_CONDITION_ERROR; } if(comm[0]=='&') state=comm[1]; switch(state){ case 'x': printf("%s\n",comm); close_object(tunit); return JDB_CONDITION_ERROR; case 'e': #if JDB_DEBUG1 || JDB_DEBUG2 printf("jdbopen exiting upon receipt of premature eod: %s\n",comm); #endif close_object(tunit); return JDB_CONDITION_ERROR; case 'c': if (comm[0] != '&') { /* + 1 for newline char we insert */ comment_len = strlen(comm) + 1; if ( (o->comment_size_so_far + comment_len) > o->commentbufsize ) { /* Set size to enough for this comment + 1 chunk */ o->commentbufsize = COMMENTSIZE + o->comment_size_so_far + comment_len; o->commentbuf = (char *) realloc (o->commentbuf,o->commentbufsize); if (o->commentbuf == NULL) return JDB_CONDITION_COMMENT_BUF_OUT_OF_MEM; } strcpy (o->commentbuf + o->comment_size_so_far, comm); o->comment_size_so_far += comment_len; *(o->commentbuf + o->comment_size_so_far - 1) = '\n'; *(o->commentbuf + o->comment_size_so_far) = '\0'; } 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_object(tunit); /* Wants to return index of varname not found */ /* Check, however, that this index is not also an error */ /* code. If it is, change return val. Breaks code that */ /* relies on index, but we're in trouble either way. */ /* Note that EOF, -1, cannot normally be returned by */ /* jdbopen, so it can be used as index */ j = -(i+1); if (jdb_known_condition(j)) { return (j == JDB_CONDITION_EOF) ? j : JDB_CONDITION_VARNOTFOUND; } else { return j; } } } 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) { i = strlen(ap)-1; if (ap[i] == ']') { ap[0] = '\0'; ap[i] = ';'; ap++; } else { printf("&x Malformed attribute list (missing ]): %s\n",ap); return JDB_CONDITION_BADATTRLIST; } }; o->ntotal++; if(numd < 0){ (*num)++; if(*num > -numd){ printf("&x Too many variables (max = %d)\n",-numd); close_object(tunit); return JDB_CONDITION_ERROR; }; 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; Logical is_a_number; int i,k,ilvl,iret,comment_len; struct OBJECT *o; if ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; if(!(o=object[*unit]))return -1; ilvl=o->maxlevel; iret=ilvl; state='d'; while(1) { #if JDB_DEBUG2 printf(">>%c>>%s\n",state,comm); #endif switch (bgets(comm,MAX_BUF-1,o)) { case -1: printf("&x jdb: data line too big. Start of line: %s\n",comm); return JDB_CONDITION_DATA_BUFOVF; case 1: #if JDB_DEBUG1 printf("jdbread exiting due to return of 1 from bgets#4\n"); #endif return JDB_CONDITION_ERROR; } if(comm[0]=='&') { state=comm[1]; switch(state){ case 'x': printf("%s\n",comm); close_object(*unit); return JDB_CONDITION_ERROR; case 'e': close_object(*unit); return -1; case 'd': ilvl = comm[2]-'0'; if (ilvl < iret) iret = ilvl; break; case 'c': *(o->commentbuf)='\0'; o->comment_size_so_far = 0; o->next_unreturned_comment_offset = 0; }; } else { switch(state){ case 'c': /* + 1 for newline char we insert */ comment_len = strlen(comm) + 1; if ( (o->comment_size_so_far + comment_len) > o->commentbufsize ) { /* Set size to enough for this comment + 1 chunk */ o->commentbufsize = COMMENTSIZE + o->comment_size_so_far + comment_len; o->commentbuf = (char *) realloc (o->commentbuf,o->commentbufsize); if (o->commentbuf == NULL) return JDB_CONDITION_COMMENT_BUF_OUT_OF_MEM; } strcpy (o->commentbuf + o->comment_size_so_far, comm); o->comment_size_so_far += comment_len; *(o->commentbuf + o->comment_size_so_far - 1) = '\n'; break; case 'd': cp=strtok(comm,"\t\n"); for(i=o->lvlpntr[ilvl];ilvlpntr[ilvl+1];i++){ k=o->rdpntr[i]; if(cp && k>=0){ GET_NUMBER_FROM_STRING(values[k],cp,is_a_number); if ( ! is_a_number ) values[k]= MISSING_VALUE_REAL; cp=strtok(NULL,"\t\n"); } else if(cp) cp=strtok(NULL,"\t\n"); else if(k>=0) values[k]= MISSING_VALUE_REAL; }; 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,comment_len; struct OBJECT *o; if ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; if ( ! (o=object[*unit]) ) return -1; ilvl=o->maxlevel; iret=ilvl; state='d'; while(1) { #if JDB_DEBUG2 printf(">>%c>>%s\n",state,comm); #endif switch (bgets(comm,MAX_BUF-1,o)) { case -1: printf("&x jdb: data line too big. Start of line: %s\n",comm); return JDB_CONDITION_DATA_BUFOVF; case 1: #if JDB_DEBUG1 printf("jdbreada exiting due to return of 1 from bgets#5\n"); #endif return JDB_CONDITION_ERROR; } if(comm[0]=='&') { state=comm[1]; switch(state){ case 'x': printf("%s\n",comm); close_object(*unit); return JDB_CONDITION_ERROR; case 'e': close_object(*unit); return -1; case 'd': ilvl=comm[2]-'0'; if(ilvlcommentbuf)='\0'; o->comment_size_so_far = 0; o->next_unreturned_comment_offset = 0; }; } else { switch(state){ case 'c': /* + 1 for newline char we insert */ comment_len = strlen(comm) + 1; if ( (o->comment_size_so_far + comment_len) > o->commentbufsize ) { /* Set size to enough for this comment + 1 chunk */ o->commentbufsize = COMMENTSIZE + o->comment_size_so_far + comment_len; o->commentbuf = (char *) realloc (o->commentbuf,o->commentbufsize); if (o->commentbuf == NULL) return JDB_CONDITION_COMMENT_BUF_OUT_OF_MEM; } strcpy (o->commentbuf + o->comment_size_so_far, comm); o->comment_size_so_far += comment_len; *(o->commentbuf + o->comment_size_so_far - 1) = '\n'; *(o->commentbuf + o->comment_size_so_far) = '\0'; break; case 'd': cp=strtok(comm,"\t\n"); for(i=o->lvlpntr[ilvl];ilvlpntr[ilvl+1];i++){ k=o->rdpntr[i]; if(cp && k>=0) { if (strlen(cp) > *valuesize) { printf("&x jdb: datum too big. Datum: %s\n",cp); return JDB_CONDITION_DATA_BUFOVF; } strcpy(values+(*valuesize)*k,cp); cp=strtok(NULL,"\t\n"); } else if (cp) { cp=strtok(NULL,"\t\n"); } else if (k>=0) { if (strlen(MISSING_VALUE_STRING) > *valuesize) { printf ("&x jdb: jdbreada data buffer cannot hold missing value string"); return JDB_CONDITION_DATA_BUFOVF; } strcpy(values+(*valuesize)*k,MISSING_VALUE_STRING); } } 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; int commentbufsize, comment_size_so_far, next_unreturned_comment_offset; if ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; if ( (o=object[*unit]) == NULL ) return 0; if ( o->next_unreturned_comment_offset < o->comment_size_so_far) { j=strcspn(o->commentbuf + o->next_unreturned_comment_offset,"\n"); strncpy(outcom,o->commentbuf + o->next_unreturned_comment_offset,j); *(outcom+j)='\0'; o->next_unreturned_comment_offset += 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 ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; 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 ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; if ( (o = object[*unit]) == NULL ) return 1; close_object(*unit); 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 ((*unit < 0) || (*unit >= MAX_UNITS)) return JDB_CONDITION_HANDLEOUTOFRANGE ; if(!(o=object[*unit]))return JDB_CONDITION_ERROR; for(j=0;jntotal;j++)if(*varnum==o->rdpntr[j])break; if(j>=o->ntotal)return -1; for(i=1;i<=o->maxlevel;i++)if(jlvlpntr[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= 0){ if(clev