mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-03 08:01:25 +08:00
be329e7a23
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
246 lines
5.0 KiB
Plaintext
246 lines
5.0 KiB
Plaintext
/*********************************************************************
|
|
* 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>
|
|
|
|
/* 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;
|
|
if(map == NULL)
|
|
parse();
|
|
for(mapp=map;*mapp != NULL;mapp+=2) {
|
|
/* Note this assumes that no key is a prefix of another */
|
|
if(strcasecmp(*mapp,key)==0) {
|
|
return mapp[1];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char**
|
|
nc_settings_all()
|
|
{
|
|
if(map == NULL)
|
|
parse();
|
|
return (const char**)map;
|
|
}
|
|
|
|
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 =
|