mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-03-31 17:50:26 +08:00
Add ability to programmatically
extract info from libnetcdf.settings API is below. I have made this API public yet by adding it to netcdf.h. I will do that when everyone is agreed on the proper API. extern const char* nc_settings(const char* key); /*get value of a specific key */ extern const char** nc_settings_all(); /*get all settings in envv format */ extern void nc_settings_reclaim(); /* reclaim all space and clean up */ Envv format is {key,value}*,NULL Also added test: nc_test/tst_settings.c
This commit is contained in:
parent
056de3f69d
commit
be329e7a23
@ -44,9 +44,22 @@ endif # BUILD_V2
|
||||
|
||||
EXTRA_DIST=CMakeLists.txt ncsettings.hdr
|
||||
|
||||
# Build ncsettings.c as follows:
|
||||
# 1. copy ncsettings.hdr to ncsettings.c
|
||||
# 2. append libnetcdf.settings to ncsettings.c after
|
||||
# processing it as follows:
|
||||
# 1. convert tabs and cr to blanks
|
||||
# 2. convert embedded double quote (") to escaped form (\").
|
||||
# 3. append newline (\n) to each line
|
||||
# 4. surround each line with double quotes.
|
||||
# 3. finally, add a semicolon to the end of ncsettings.c
|
||||
# to complete the string constant.
|
||||
|
||||
ncsettings.c: $(top_srcdir)/libnetcdf.settings ncsettings.hdr
|
||||
rm -f ncsettings.c
|
||||
cat ncsettings.hdr > ncsettings.c
|
||||
sed -e 's/"/\\"/g' <$(top_srcdir)/libnetcdf.settings | sed -e 's/\(.*\)/"\1\\n"/' >> ncsettings.c
|
||||
tr '\t\r' ' ' <${top_srcdir}/libnetcdf.settings | \
|
||||
sed -e 's/"/\\"/g' | \
|
||||
sed -e 's/\(.*\)/\"\1\\n\"/' | \
|
||||
cat >> ncsettings.c
|
||||
echo ';' >> ncsettings.c
|
||||
|
||||
|
@ -1,36 +1,245 @@
|
||||
/*********************************************************************
|
||||
* Copyright 2014, UCAR/Unidata
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*********************************************************************/
|
||||
* Copyright 2014, UCAR/Unidata
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char* ncsettings;
|
||||
/* General rule
|
||||
try to avoid any obscure string functions.
|
||||
We currently use
|
||||
- strcasecmp
|
||||
- strchr
|
||||
- strndup
|
||||
- strlen
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/* Define the legal leading key characters */
|
||||
#define KEYCHARS1 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_."
|
||||
|
||||
/*forward*/
|
||||
static const char* ncsettings_text;
|
||||
|
||||
static char** lines;
|
||||
static int nlines;
|
||||
static char* dup;
|
||||
static char** map = NULL;
|
||||
|
||||
/*forward*/
|
||||
static void parse();
|
||||
static int parseline(const char* line, int keypos);
|
||||
static int iskeyline(const char* line);
|
||||
static void preprocess();
|
||||
|
||||
const char*
|
||||
nc_settings(const char* key)
|
||||
{
|
||||
char** mapp;
|
||||
int keylen = strlen(key);
|
||||
if(map == NULL)
|
||||
parse();
|
||||
for(mapp=map;*mapp != NULL;mapp+=2) {
|
||||
/* Note this assumes that no key is a prefix of another */
|
||||
if(strncmp(*mapp,key,keylen)==0) {
|
||||
if(strcasecmp(*mapp,key)==0) {
|
||||
return mapp[1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void parse()
|
||||
const char**
|
||||
nc_settings_all()
|
||||
{
|
||||
if(map == NULL)
|
||||
parse();
|
||||
return (const char**)map;
|
||||
}
|
||||
|
||||
static const char* ncsettings =
|
||||
const char*
|
||||
nc_settings_text()
|
||||
{
|
||||
return ncsettings_text;
|
||||
}
|
||||
|
||||
static void
|
||||
parse()
|
||||
{
|
||||
int i,keypos;
|
||||
int nkeys;
|
||||
const char** line;
|
||||
|
||||
preprocess();
|
||||
|
||||
nkeys = 0;
|
||||
/* Count # of key lines */
|
||||
for(i=0;i<nlines;i++) {
|
||||
const char* line = lines[i];
|
||||
#ifdef DEBUG
|
||||
printf("testing: %s\n",line);
|
||||
#endif
|
||||
if(iskeyline(line)) {
|
||||
#ifdef DEBUG
|
||||
printf("keyline: %s\n",line);
|
||||
#endif
|
||||
nkeys++;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fflush(stdout);
|
||||
#endif
|
||||
/* Create the map of proper size */
|
||||
map = (char**)malloc(((2*nkeys)+1) * sizeof(char*));/*+1 for terminating null*/
|
||||
if(map == NULL) {
|
||||
fprintf(stderr,"ncsettings: out of memory\n");
|
||||
return;
|
||||
}
|
||||
map[2*nkeys] = NULL; /* pre-insert terminating null */
|
||||
/* parse the keylines only */
|
||||
keypos = 0;
|
||||
for(i=0;i<nlines;i++) {
|
||||
const char* line = lines[i];
|
||||
if(!iskeyline(line)) continue;
|
||||
if(!parseline(line,keypos))
|
||||
return;
|
||||
keypos+=2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We assume that each key starts with an alphanumeric character.
|
||||
*/
|
||||
static int
|
||||
parseline(const char* line, int keypos)
|
||||
{
|
||||
const char* p;
|
||||
const char* r;
|
||||
char* q;
|
||||
ptrdiff_t delta;
|
||||
char* key;
|
||||
char* value;
|
||||
/* find colon ending of the key */
|
||||
r = strchr(line,':');
|
||||
if(r == NULL) { /* malformed */
|
||||
fprintf(stderr,"malformed libnetcdf.settings file: %s\n,line");
|
||||
return 0;
|
||||
}
|
||||
/* back up from the colon to the first non-blank */
|
||||
for(p=r;p != line;p--) {
|
||||
if(*p != ' ') break;
|
||||
}
|
||||
if(p == line) {/* empty key */
|
||||
fprintf(stderr,"malformed libnetcdf.settings file: %s\n,line");
|
||||
return 0;
|
||||
}
|
||||
delta = p - line;
|
||||
key = strndup(line,delta);
|
||||
/* skip post ':' blanks */
|
||||
for(p=r+1;;p++) {
|
||||
if(*p != ' ') break;
|
||||
}
|
||||
if(*p == '\0') /* empty value */
|
||||
value = strdup("");
|
||||
else { /* assert value is not empty */
|
||||
value = strdup(p);
|
||||
size_t len = strlen(value);
|
||||
q = value + (len - 1); /* point to last char before trailing nul */
|
||||
/* back up to the first non-blank */
|
||||
for(;(*q == ' ');q--); /* will always terminate at value at least */
|
||||
q[1] = '\0'; /* artificial end */
|
||||
}
|
||||
/* Append to the map */
|
||||
map[keypos] = key;
|
||||
map[keypos+1] = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We assume that each key starts with an alphanumeric character. */
|
||||
static int
|
||||
iskeyline(const char* line)
|
||||
{
|
||||
if(line == NULL || strlen(line) == 0)
|
||||
return 0;
|
||||
if(line[0] == '#' || line[0] == ' ')
|
||||
return 0;
|
||||
if(strchr(KEYCHARS1,line[0]) == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We need to process the text as follows:
|
||||
1. convert tabs and \r to blanks
|
||||
2. convert \n to EOL (\0)
|
||||
3. remove leading and trailing blanks from each line
|
||||
*/
|
||||
static void
|
||||
preprocess()
|
||||
{
|
||||
int c,i;
|
||||
const char* p;
|
||||
char* q;
|
||||
char* r;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("input: %s\n",ncsettings_text);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
dup = (char*)malloc(strlen(ncsettings_text)+1);
|
||||
nlines = 0;
|
||||
/* steps 1 and 2 */
|
||||
for(p=ncsettings_text,q=dup;(c=*p);p++) {
|
||||
switch (c) {
|
||||
case '\r': case '\t': *q++ = ' '; break;
|
||||
case '\n': nlines++; *q++ = '\0'; break;
|
||||
default: *q++ = c; break;
|
||||
}
|
||||
}
|
||||
/* step 3 */
|
||||
lines = (char**)malloc(nlines*sizeof(char*));
|
||||
r = dup;
|
||||
for(i=0;i<nlines;i++) {
|
||||
int suppress;
|
||||
lines[i] = r;
|
||||
r += strlen(r);
|
||||
r++; /* skip terminating nul */
|
||||
}
|
||||
for(i=0;i<nlines;i++) {
|
||||
char* line = lines[i];
|
||||
p = line;
|
||||
for(;(c=*p);p++) {
|
||||
if(c != ' ')
|
||||
break;
|
||||
}
|
||||
strcpy(line,p); /* remove leading blanks */
|
||||
q = line+strlen(line); /* terminating nul */
|
||||
while((c=*(--q))) {
|
||||
if(c != ' ')
|
||||
break;
|
||||
}
|
||||
/* terminate */
|
||||
q++;
|
||||
*q = '\0';
|
||||
#ifdef DEBUG
|
||||
printf("processed: %s\n",line);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nc_settings_reclaim()
|
||||
{
|
||||
if(lines != NULL) free(lines);
|
||||
if(dup != NULL) free(dup);
|
||||
if(map != NULL) free(map);
|
||||
lines = NULL;
|
||||
dup = NULL;
|
||||
map = NULL;
|
||||
}
|
||||
|
||||
static const char* ncsettings_text =
|
||||
|
@ -1,7 +1,7 @@
|
||||
NetCDF C Configuration Summary
|
||||
# NetCDF C Configuration Summary
|
||||
==============================
|
||||
|
||||
General
|
||||
# General
|
||||
-------
|
||||
NetCDF Version: @PACKAGE_VERSION@
|
||||
Configured On: @CONFIG_DATE@
|
||||
@ -9,7 +9,7 @@ Host System: @host_cpu@-@host_vendor@-@host_os@
|
||||
Build Directory: @abs_top_builddir@
|
||||
Install Prefix: @prefix@
|
||||
|
||||
Compiling Options
|
||||
# Compiling Options
|
||||
-----------------
|
||||
C Compiler: @CC_VERSION@
|
||||
CFLAGS: @CFLAGS@
|
||||
@ -22,7 +22,7 @@ Shared Library: @enable_shared@
|
||||
Static Library: @enable_static@
|
||||
Extra libraries: @LIBS@
|
||||
|
||||
Features
|
||||
# Features
|
||||
--------
|
||||
NetCDF-2 API: @HAS_NC2@
|
||||
NetCDF-4 API: @HAS_NC4@
|
||||
|
@ -1,10 +1,9 @@
|
||||
# Test c output
|
||||
T=tst_diskless3
|
||||
T=tst_settings
|
||||
#VG=valgrind --leak-check=full
|
||||
|
||||
CFLAGS=-g -O0 -I.. -I../include
|
||||
LDFLAGS=../liblib/.libs/libnetcdf.a -L/share/ed/local/spock/lib -lhdf5_hl -lhdf5 -lz -lm -lcurl
|
||||
LD_RUN_PATH=/share/ed/local/spock/lib
|
||||
LDFLAGS=../liblib/.libs/libnetcdf.a -L/usr/local/lib -lhdf5_hl -lhdf5 -lz -lm -lcurl
|
||||
|
||||
# cd .. ; ${MAKE} all
|
||||
|
||||
|
@ -15,8 +15,10 @@ tst_diskless3.nc tst_diskless3_file.cdl tst_diskless3_memory.cdl \
|
||||
tst_diskless4.cdl tst_diskless4.nc tst_formatx.nc
|
||||
|
||||
# These are the tests which are always run.
|
||||
TESTPROGRAMS = t_nc tst_small nc_test tst_misc tst_norm tst_names \
|
||||
tst_nofill tst_nofill2 tst_nofill3 tst_atts3
|
||||
XTESTPROGRAMS = t_nc tst_small nc_test tst_misc tst_norm tst_names \
|
||||
tst_nofill tst_nofill2 tst_nofill3 tst_atts3 tst_settings
|
||||
|
||||
TESTPROGRAMS = tst_settings
|
||||
|
||||
if USE_NETCDF4
|
||||
TESTPROGRAMS += tst_atts
|
||||
|
Loading…
x
Reference in New Issue
Block a user