static char rcsid[]="$Id: scvparse.c,v 1.1 1992/07/29 00:38:16 maurer$"; /*********************************************************************** scvparse.c Function: Parses the SFDU headers on SCVDR format files. This file is part of the STARLab Magellan Altimeter Data Processing Software. Michael Maurer, June 1992. ***********************************************************************/ /* $Log: scvparse.c,v $ * Revision 1.1 1992/07/29 00:38:16 maurer * Removed flookingat() and read_sfdu_buf() to avoid use of fseek() * function. Extra logic accomplishes same in scv_rhdr(). * * Revision 1.0 1992/07/28 23:07:53 maurer * Initial revision * */ #include /*#include */ #include #include #include #include #include "scvdr.h" #include "scvparse.h" /* codes for sfdu field 'vers' */ #define VERS_ASCII '1' /* ASCII length field */ #define VERS_BINARY '2' /* Binary length field */ #define SCVPARSE_C #include "scvparse.i" /*********************************************************************** read_sfdu Reads one sfdu structure; that is, reads a SFDU label and then reads N more bytes, where N is the length specified in the sfdu label. The sfdu label is read into sf and its data into *bufp. If bufp points to a NULL pointer, *bufp is allocated using malloc(). [An extra NULL character is appended to the data in *bufp for convenience.] Returns N if successful, 0 on EOF, negative number on failure. ***********************************************************************/ static int read_sfdu(f,sf,bufp) FILE *f; sfdu *sf; char **bufp; { int N; if ((N = read_sfdu_label(f,sf)) < 0) return N; if (*bufp == NULL && (*bufp=malloc(N+1)) == NULL) return -3; if (fread(*bufp,1,N,f) != N) { free(*bufp); return -4; } (*bufp)[N]='\0'; return N; } /*********************************************************************** read_sfdu_label Reads 12-byte label and 8-byte length string (parsing only the last four bytes if binary). Returns label length on success, 0 at EOF, and negative numbers for failure. ***********************************************************************/ static int read_sfdu_label(f,sf) FILE *f; sfdu *sf; { if (fread((char *)sf,sizeof(sfdu),1,f) != 1) { if (feof(f) || (! ferror(f) && *(char *)sf == '^')) return 0; else return -2; } return parse_sfdu_label(sf); } /*********************************************************************** parse_sfdu_label Parses the 8-byte length portion of an SFDU label. If SFDU indicates length is in binary format, parses only the lower significant 4 bytes. Returns length value, or -1 for unrecognized length format. ***********************************************************************/ static int parse_sfdu_label(sf) sfdu *sf; { int len; switch (sf->vers) { case VERS_ASCII : len = asc2int(sf->length.alen,sizeof(sf->length.alen)); break; case VERS_BINARY : len = bytes2int(&sf->length.blen[sizeof(sf->length.blen)-4],4); break; default: len = -1; } return len; } /*********************************************************************** asc2int Converts ASCII string of length len to integer. String need not be terminated by a NULL character. ***********************************************************************/ static int asc2int(p, len) char *p; int len; { char str[20]; assert(lenkey && kv->val) { if (!strcmp(kv->key,key)) return kv->val; kv++; } return NULL; } /*********************************************************************** print_catalog Prints out all keyword=value pairs in the catalog kv to the stream f. ***********************************************************************/ void print_catalog(f,kv) FILE *f; keyval_t *kv; { keyval_t *k; int len,maxl=0; if (!kv) return; for (k=kv; k->key && k->val; k++) if ((len=strlen(k->key))>maxl) maxl=len; for (k=kv; k->key && k->val; k++) fprintf(f," %-*s%s\n",maxl+3,k->key,k->val); fflush(f); } /*********************************************************************** free_catalog Frees memory allocated to all keyword and value pairs in catalog kv, and then frees the array of pairs itself. ***********************************************************************/ void free_catalog(kv) keyval_t *kv; { keyval_t *k; if (!kv) return; for (k=kv; k->key && k->val; k++) { free(k->key); free(k->val); } free((char *)kv); } /*********************************************************************** scv_rhdr scv_rhdr(f,sf1,sf2,keyval2,sf3,hdr3p,sf4,keyval4) FILE *f; sfdu *sf1,*sf2; keyval_t **keyval2; sfdu *sf3; char **hdr3p; sfdu *sf4; keyval_t **keyval4; Reads up to 4 SFDU records that form the header of SCVDR format files. SCVDR files begin with some or all of the following SFDUs: #1 CCSD file header required #2 NJPL catalog items optional #3 NJPL header record optional #4 CCSD aggregation start required unless EOF (Note that the optional SFDUs are logically part of the first CCSD label's record.) If the "aggregation start" label is present,it may be followed by any number of NJPL records, followed by a CCSD "aggregation end" label. (These are not read by this function.) Some files also have a CCSD file trailer corresponding to the CCSD file header. Input is the file pointer f, already opened. All other values are outputs. If *keyval2, *hdr3p or *keyval4 are not already malloc()ed, they should be set to NULL, and free()d after they are used. (If you somehow know in advance how much space each will need, you may pre-allocate them if you wish. However, if you guess wrong, there is no error checking.) The pointers sf1, sf2, sf3 and sf4 must be already allocated. Sample usage: { sfdu sf1,sf2,sf3,sf4; keyval_t *kv2,*kv4; char *hdr3; int err; FILE *f; f=fopen(...); hdr3=NULL; kv2=NULL; kv4=NULL; err=scv_rhdr(f,&sf1,&sf2,&kv2,&sf3,&hdr3,&sf4,&kv4); ... free(hdr3); free_catalog(kv2); free_catalog(kv4); } If SFDU #1 is present, sf1 is filled with the 20-byte label. If SFDU #2 is present, sf2 is filled with the 20-byte label, and *keyval2 is allocated and filled with the catalog entries. If the SFDU is absent, *keyval2 will have zero items, and SFDU #3 must not be present either. If SFDU #3 is present, sf3 is filled with the 20-byte label, and hdr3p is allocated and filled with the corresponding data record (including a duplicate of the 20-byte SFDU label). If the SFDU is absent, *hdr3p will be set to a 20-byte SFDU label filled with NULL characters. If SFDU #4 is present, sf4 is filled with the 20-byte label, and *keyval4 is allocated and filled with the catalog entries. If the SFDU is absent, *keyval4 will have zero items, and there must not be any more data in the file. If any SFDU is absent, the corresponding SFDU label is filled with NULL characters. If any errors are detected, the return value is nonzero. ***********************************************************************/ int scv_rhdr(f,sf1,sf2,keyval2,sf3,hdr3p,sf4,keyval4) FILE *f; sfdu *sf1,*sf2; keyval_t **keyval2; sfdu *sf3; char **hdr3p; sfdu *sf4; keyval_t **keyval4; { char *buf; int N; sfdu sf; /* Fill SFDU labels with NULLs */ bzero((char *)sf1,sizeof(sfdu)); bzero((char *)sf2,sizeof(sfdu)); bzero((char *)sf3,sizeof(sfdu)); bzero((char *)sf4,sizeof(sfdu)); /* Read SFDU #1, should be CCSD */ if ((N = read_sfdu_label(f,sf1)) <= 0) return -1; /* Read next SFDU: will be either #2, #3, #4 or EOF. */ buf=NULL; if ((N = read_sfdu(f,&sf,&buf)) < 0) return -2; /* If it is optional SFDU #2 (NJPL), parse and fill catalog */ if (strncmp(sf.ctrl,"NJPL",4)==0) { *sf2=sf; if (parse_catalog(buf,keyval2) < 0) return -3; free(buf); /* Read next SFDU: will be either #3, #4 or EOF. */ buf=NULL; if ((N = read_sfdu(f,&sf,&buf)) < 0) return -4; /* If it is optional SFDU #3 (NJPL), parse and read data record */ if (strncmp(sf.ctrl,"NJPL",4)==0) { *sf3=sf; if (*hdr3p==NULL && (*hdr3p=malloc(N+sizeof(sfdu)+1))==NULL) return -5; memcpy(*hdr3p,(char *)&sf,sizeof(sfdu)); memcpy(*hdr3p+sizeof(sfdu),buf,N); (*hdr3p)[N+sizeof(sfdu)]='\0'; free(buf); /* Read next SFDU: will either be #4 or EOF. */ buf=NULL; if ((N = read_sfdu(f,&sf,&buf)) < 0) return -6; } } /* At this point, SFDU #4 has been read into sf and buf, but is not yet parsed. If we found EOF (SFDU #4 is not present), then N==0, buf[0]='\0' and parse_catalog will return 0. */ if (N>0 && strncmp(sf.ctrl,"CCSD",4)!=0) return -7; /* Parse SFDU #4 if present. */ if (N>0) *sf4=sf; if (parse_catalog(buf,keyval4) < 0) return -8; free(buf); /* Success! */ return 0; } #ifdef MAIN /*********************************************************************** Here's an example program that uses scv_rhdr() to print out the header SFDU's for SCVDR format files. Usage: scvparse rdf00601.1 vhf00601.1 ohf00601.1 .... ***********************************************************************/ int main(argc,argv) int argc; char *argv[]; { char *fn; FILE *f; char *hdr,*key,*val; sfdu sf1,sf2,sf3,sf4; keyval_t *kv2,*kv4; int i,j,S,err,ntotal,nused; for (i=1; i