/* * GVDR library for reading GVDR data files * Copyright (C) 1994 Michael J. Maurer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Michael Maurer * Durand Bldg - Room 232 * Stanford, CA 94305-4055 * (415) 723-1024 */ static char rcsid[]="$Id: sfdug.c,v 1.1 1993/08/02 01:02:18 maurer Exp $"; /****************************************************************************** sfdug.c Function: Generic SFDU creating, writing, reading and parsing. This file is part of the STARLab Magellan Altimeter Data Processing Software. Michael Maurer, May 1993. ******************************************************************************/ /* $Log: sfdug.c,v $ * Revision 1.1 1993/08/02 01:02:18 maurer * Renamed bytes2int to byte2int for public distribution. * Removed map.h and util.h for public distribution. * * Revision 1.0 1993/06/12 00:39:29 maurer * Initial revision * */ #include #include #include #include "libmisc.h" #include "sfdug.h" #define SFDUG_C #include "sfdug.p" /****************************************************************************** kc_write Write a set of KEYWORD=VALUE pairs to file f. If total size is odd number of bytes, a space is added before the last . Returns total number of bytes written. ******************************************************************************/ int kc_write(f,kp) FILE *f; keycat_t *kp; { int nb=0; while (kp->name) { fputs(kp->name,f); fputc('=',f); if (kp->val) { fputs(kp->val,f); nb+=strlen(kp->val); } nb+=strlen(kp->name)+3; kp++; if (!kp->name && nb%2) { fputc(' ',f); nb++; } fputs("\r\n",f); } return nb; } /****************************************************************************** kc_len Returns number of bytes required to write keys to file. Always even. ******************************************************************************/ int kc_len(kp) keycat_t *kp; { int nb=0; while (kp->name) { nb+=strlen(kp->name)+3; if (kp->val) nb+=strlen(kp->val); kp++; } if (nb%2) nb++; return nb; } keycat_t * kc_lookup(keycat_t *kp, char *key) { if (!kp || !key) return NULL; while (kp->name) { if (!strcmp(kp->name,key)) return kp; kp++; } return NULL; } /****************************************************************************** kc_set Set the value of keyword with the given key to val. If the val field is a K_MAL type and the pointer is non-null, it is freed and then allocated to accomodate val. If the val field is a K_PTR type it is set to point to the new value. If the value is read-only, an error occurs. Returns zero on success. ******************************************************************************/ int kc_set(kp,key,val) keycat_t *kp; char *key,*val; { if (!key || !val) return 1; if ((kp=kc_lookup(kp,key))==NULL) return 2; switch (kp->flag) { case K_PTR: kp->val=val; break; case K_MAL: if (kp->val) free(kp->val); malloc_err(kp->val,strlen(val)+1); strcpy(kp->val,val); break; default: return 3; } return 0; } /****************************************************************************** kc_sprintf Accepts 1 integer sprintf-like parameter and uses it to create the keyword value. ******************************************************************************/ int kc_sprintf(kp,key,num) keycat_t *kp; char *key; int num; { char val[1024]; if ((kp=kc_lookup(kp,key))==NULL) return 1; if (kp->flag!=K_FMT) return 2; if (kp->val) free(kp->val); sprintf(val,kp->fmt,num); malloc_err(kp->val,strlen(val)+1); strcpy(kp->val,val); return 0; } /****************************************************************************** sf_set Sets the first 12 characters of the SFDU to lbl, then uses the length code to write the length as ASCII or binary into the last 8 bytes. ******************************************************************************/ void sf_set(sf,lbl,len) sfdu_t *sf; char *lbl; int len; { char L[9]; strncpy(sf->ctrl,lbl,12); switch (sf->vers) { case VERS_ASCII : sprintf(L,"%08d",len); strncpy(sf->length.alen,L,8); break; case VERS_BINARY : memset(&sf->length.blen[0],0,4); memcpy(&sf->length.blen[4],&len,4); break; default: error(-1,0,"[sf_set] invalid SFDU \"%s\"",lbl); } } /****************************************************************************** sf_read Reads one sfdu_t structure; that is, reads a SFDU label and then reads N more bytes, where N is the length specified in the sfdu_t 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(). [If malloced, an extra NUL character is appended to the data in *bufp for convenience.] Returns N if successful, 0 on EOF, negative number on failure. ******************************************************************************/ int sf_read(f,sf,bufp) FILE *f; sfdu_t *sf; char **bufp; { int N; int mal = (*bufp==NULL); if ((N = sf_rlbl(f,sf)) < 0) return N; if (*bufp == NULL && (*bufp=malloc(N+1)) == NULL) return -1; if (fread(*bufp,1,N,f) != N) { free(*bufp); return -2; } if (mal) (*bufp)[N]='\0'; return N; } /****************************************************************************** sf_rlbl 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 sf_rlbl(f,sf) FILE *f; sfdu_t *sf; { if (fread(sf,sizeof(sfdu_t),1,f) != 1) { if (feof(f)) return 0; else return -2; } return sf_len(sf); } /****************************************************************************** sf_len 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. ******************************************************************************/ int sf_len(sf) sfdu_t *sf; { int len; switch (sf->vers) { case VERS_ASCII : len = asc2int(sf->length.alen,sizeof(sf->length.alen)); break; case VERS_BINARY : len = byte2int(&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]; (void)strncpy(str,p,len); str[len] = '\0'; return atoi(str); } /****************************************************************************** byte2int This function interprets an array of bytes as if it were a Big-Endian (non-VAX) integer. ******************************************************************************/ static int byte2int(p, n) char *p; int n; { int I; I = *p++; switch (n) { case 4: I = (I << 8) + *p++; case 3: I = (I << 8) + *p++; case 2: I = (I << 8) + *p++; case 1: break; default: while (--n) I = (I << 8) + *p++; } return I; } /****************************************************************************** kv_parse Parses a set of keyword=value pairs in memory location buf, which must be terminated with a NULL character. Allocates *kvp as an array of keyval_t elements, and allocates each pair of elements (*kvp)[i] and fills them with keywords and values. ******************************************************************************/ #define DELIM "=\r\n " int kv_parse(buf,kvp) char *buf; keyval_t **kvp; { int nkey,i; char *p,*pk,*pv; keyval_t *kv; p=buf; nkey=0; while (p && (p=strchr(p,(int)'='))) { nkey++; p++; } if ((kv=(keyval_t *)malloc((nkey+1)*sizeof(keyval_t))) == NULL) return -1; *kvp=kv; pk=strtok(buf,DELIM); pv=strtok(NULL,DELIM); i=0; while (pk && pv && ikey && kv->val) { if (!strcmp(kv->key,key)) return kv->val; kv++; } return NULL; } int kc_kv_sscanf(kc,kv,key,ptr) keycat_t *kc; keyval_t *kv; char *key; void *ptr; { keycat_t *k; char *val; if ((k=kc_lookup(kc,key))==NULL) return 1; if (k->flag!=K_FMT) return 2; if ((val=kv_lookup(kv,key))==NULL) return 3; if (sscanf(val,k->fmt,ptr)!=1) return 4; return 0; } /****************************************************************************** kv_print Prints out all keyword=value pairs in the catalog kv to the stream f. Format is pretty-printed for humans, not machines. ******************************************************************************/ void kv_print(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); } /****************************************************************************** kv_free Frees memory allocated to all keyword and value pairs in catalog kv, and then frees the array of pairs itself. ******************************************************************************/ void kv_free(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(kv); }