mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-03 08:01:25 +08:00
336 lines
8.4 KiB
C
336 lines
8.4 KiB
C
/*
|
|
Copyright (c) 1998-2017 University Corporation for Atmospheric Research/Unidata
|
|
See LICENSE.txt for license information.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "ncdispatch.h"
|
|
#include "ncuri.h"
|
|
#include "nclog.h"
|
|
#include "ncbytes.h"
|
|
#include "ncrc.h"
|
|
|
|
/* Required for getcwd, other functions. */
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/* Required for getcwd, other functions. */
|
|
#ifdef _MSC_VER
|
|
#include <direct.h>
|
|
#define getcwd _getcwd
|
|
#endif
|
|
|
|
|
|
/* Define vectors of zeros and ones for use with various nc_get_varX function*/
|
|
size_t nc_sizevector0[NC_MAX_VAR_DIMS];
|
|
size_t nc_sizevector1[NC_MAX_VAR_DIMS];
|
|
ptrdiff_t nc_ptrdiffvector1[NC_MAX_VAR_DIMS];
|
|
size_t NC_coord_zero[NC_MAX_VAR_DIMS];
|
|
size_t NC_coord_one[NC_MAX_VAR_DIMS];
|
|
|
|
/* Define the known protocols and their manipulations */
|
|
static struct NCPROTOCOLLIST {
|
|
char* protocol;
|
|
char* substitute;
|
|
int model;
|
|
} ncprotolist[] = {
|
|
{"http",NULL,0},
|
|
{"https",NULL,0},
|
|
{"file",NULL,0},
|
|
{"dods","http",NC_FORMATX_DAP2},
|
|
{"dodss","https",NC_FORMATX_DAP2},
|
|
{"dap4","http",NC_FORMATX_DAP4},
|
|
{"dap4s","https",NC_FORMATX_DAP4},
|
|
{NULL,NULL,0} /* Terminate search */
|
|
};
|
|
|
|
NCRCglobalstate ncrc_globalstate;
|
|
|
|
/*
|
|
static nc_type longtype = (sizeof(long) == sizeof(int)?NC_INT:NC_INT64);
|
|
static nc_type ulongtype = (sizeof(unsigned long) == sizeof(unsigned int)?NC_UINT:NC_UINT64);
|
|
*/
|
|
|
|
/* Allow dispatch to do general initialization and finalization */
|
|
int
|
|
NCDISPATCH_initialize(void)
|
|
{
|
|
int status = NC_NOERR;
|
|
int i;
|
|
|
|
memset(&ncrc_globalstate,0,sizeof(NCRCglobalstate));
|
|
|
|
for(i=0;i<NC_MAX_VAR_DIMS;i++) {
|
|
nc_sizevector0[i] = 0;
|
|
nc_sizevector1[i] = 1;
|
|
nc_ptrdiffvector1[i] = 1;
|
|
}
|
|
for(i=0;i<NC_MAX_VAR_DIMS;i++) {
|
|
NC_coord_one[i] = 1;
|
|
NC_coord_zero[i] = 0;
|
|
}
|
|
|
|
/* Capture temp dir*/
|
|
{
|
|
char* tempdir;
|
|
char* p;
|
|
char* q;
|
|
char cwd[4096];
|
|
#ifdef _MSC_VER
|
|
tempdir = getenv("TEMP");
|
|
#else
|
|
tempdir = "/tmp";
|
|
#endif
|
|
if(tempdir == NULL) {
|
|
fprintf(stderr,"Cannot find a temp dir; using ./\n");
|
|
tempdir = getcwd(cwd,sizeof(cwd));
|
|
if(tempdir == NULL || *tempdir == '\0') tempdir = ".";
|
|
}
|
|
ncrc_globalstate.tempdir= (char*)malloc(strlen(tempdir) + 1);
|
|
for(p=tempdir,q=ncrc_globalstate.tempdir;*p;p++,q++) {
|
|
if((*p == '/' && *(p+1) == '/')
|
|
|| (*p == '\\' && *(p+1) == '\\')) {p++;}
|
|
*q = *p;
|
|
}
|
|
*q = '\0';
|
|
#ifdef _MSC_VER
|
|
#else
|
|
/* Canonicalize */
|
|
for(p=ncrc_globalstate.tempdir;*p;p++) {
|
|
if(*p == '\\') {*p = '/'; };
|
|
}
|
|
*q = '\0';
|
|
#endif
|
|
}
|
|
|
|
/* Capture $HOME */
|
|
{
|
|
char* p;
|
|
char* q;
|
|
char* home = getenv("HOME");
|
|
|
|
if(home == NULL) {
|
|
/* use tempdir */
|
|
home = ncrc_globalstate.tempdir;
|
|
}
|
|
ncrc_globalstate.home = (char*)malloc(strlen(home) + 1);
|
|
for(p=home,q=ncrc_globalstate.home;*p;p++,q++) {
|
|
if((*p == '/' && *(p+1) == '/')
|
|
|| (*p == '\\' && *(p+1) == '\\')) {p++;}
|
|
*q = *p;
|
|
}
|
|
*q = '\0';
|
|
#ifdef _MSC_VER
|
|
#else
|
|
/* Canonicalize */
|
|
for(p=home;*p;p++) {
|
|
if(*p == '\\') {*p = '/'; };
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Now load RC File */
|
|
status = NC_rcload();
|
|
ncloginit();
|
|
|
|
return status;
|
|
}
|
|
|
|
int
|
|
NCDISPATCH_finalize(void)
|
|
{
|
|
int status = NC_NOERR;
|
|
nullfree(ncrc_globalstate.tempdir);
|
|
nullfree(ncrc_globalstate.home);
|
|
NC_rcclear(&ncrc_globalstate.rcinfo);
|
|
memset(&ncrc_globalstate,0,sizeof(NCRCglobalstate));
|
|
return status;
|
|
}
|
|
|
|
/* return 1 if path looks like a url; 0 otherwise */
|
|
int
|
|
NC_testurl(const char* path)
|
|
{
|
|
int isurl = 0;
|
|
NCURI* tmpurl = NULL;
|
|
char* p;
|
|
|
|
if(path == NULL) return 0;
|
|
|
|
/* find leading non-blank */
|
|
for(p=(char*)path;*p;p++) {if(*p != ' ') break;}
|
|
|
|
/* Do some initial checking to see if this looks like a file path */
|
|
if(*p == '/') return 0; /* probably an absolute file path */
|
|
|
|
/* Ok, try to parse as a url */
|
|
if(ncuriparse(path,&tmpurl)==NCU_OK) {
|
|
/* Do some extra testing to make sure this really is a url */
|
|
/* Look for a known/accepted protocol */
|
|
struct NCPROTOCOLLIST* protolist;
|
|
for(protolist=ncprotolist;protolist->protocol;protolist++) {
|
|
if(strcmp(tmpurl->protocol,protolist->protocol) == 0) {
|
|
isurl=1;
|
|
break;
|
|
}
|
|
}
|
|
ncurifree(tmpurl);
|
|
return isurl;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
Return an NC_FORMATX_... value.
|
|
Assumes that the path is known to be a url
|
|
*/
|
|
|
|
int
|
|
NC_urlmodel(const char* path, int mode, char** newurl)
|
|
{
|
|
int found, model = 0;
|
|
struct NCPROTOCOLLIST* protolist;
|
|
NCURI* url = NULL;
|
|
char* p;
|
|
|
|
if(path == NULL) return 0;
|
|
|
|
/* find leading non-blank */
|
|
for(p=(char*)path;*p;p++) {if(*p != ' ') break;}
|
|
|
|
/* Do some initial checking to see if this looks like a file path */
|
|
if(*p == '/') return 0; /* probably an absolute file path */
|
|
|
|
/* Parse the url */
|
|
if(ncuriparse(path,&url) != NCU_OK)
|
|
goto fail; /* Not parseable as url */
|
|
|
|
/* Look up the protocol */
|
|
for(found=0,protolist=ncprotolist;protolist->protocol;protolist++) {
|
|
if(strcmp(url->protocol,protolist->protocol) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if(found) {
|
|
model = protolist->model;
|
|
/* Substitute the protocol in any case */
|
|
if(protolist->substitute) ncurisetprotocol(url,protolist->substitute);
|
|
} else
|
|
goto fail; /* Again, does not look like a url */
|
|
|
|
if(model != NC_FORMATX_DAP2 && model != NC_FORMATX_DAP4) {
|
|
/* Look for and of the following params:
|
|
"dap2", "protocol=dap2", "dap4", "protocol=dap4" */
|
|
const char* proto = NULL;
|
|
const char* match = NULL;
|
|
if((proto=ncurilookup(url,"protocol")) == NULL) proto = NULL;
|
|
if(proto == NULL) proto = "";
|
|
if((match=ncurilookup(url,"dap2")) != NULL || strcmp(proto,"dap2") == 0)
|
|
model = NC_FORMATX_DAP2;
|
|
else if((match=ncurilookup(url,"dap4")) != NULL || strcmp(proto,"dap4") == 0)
|
|
model = NC_FORMATX_DAP4;
|
|
else
|
|
model = 0; /* Still don't know */
|
|
}
|
|
if(model == 0) {/* Last resort: use the mode */
|
|
/* If mode specifies netcdf-4, then this is assumed to be dap4 */
|
|
if(mode & NC_NETCDF4)
|
|
model = NC_FORMATX_DAP4;
|
|
else
|
|
model = NC_FORMATX_DAP2; /* Default */
|
|
}
|
|
if(newurl)
|
|
*newurl = ncuribuild(url,NULL,NULL,NCURIALL);
|
|
if(url) ncurifree(url);
|
|
return model;
|
|
fail:
|
|
if(url) ncurifree(url);
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************/
|
|
/**
|
|
* Provide a hidden interface to allow utilities
|
|
* to check if a given path name is really an ncdap3 url.
|
|
* If no, put null in basenamep, else put basename of the url
|
|
* minus any extension into basenamep; caller frees.
|
|
* Return 1 if it looks like a url, 0 otherwise.
|
|
*/
|
|
|
|
int
|
|
nc__testurl(const char* path, char** basenamep)
|
|
{
|
|
NCURI* uri;
|
|
int ok = 0;
|
|
if(ncuriparse(path,&uri) == NCU_OK) {
|
|
char* slash = (uri->path == NULL ? NULL : strrchr(uri->path, '/'));
|
|
char* dot;
|
|
if(slash == NULL) slash = (char*)path; else slash++;
|
|
slash = nulldup(slash);
|
|
if(slash == NULL)
|
|
dot = NULL;
|
|
else
|
|
dot = strrchr(slash, '.');
|
|
if(dot != NULL && dot != slash) *dot = '\0';
|
|
if(basenamep)
|
|
*basenamep=slash;
|
|
else if(slash)
|
|
free(slash);
|
|
ncurifree(uri);
|
|
ok = 1;
|
|
}
|
|
return ok;
|
|
}
|
|
/**************************************************/
|
|
|
|
#ifdef OBSOLETE
|
|
/* Override dispatch table management */
|
|
static NC_Dispatch* NC_dispatch_override = NULL;
|
|
|
|
/* Override dispatch table management */
|
|
NC_Dispatch*
|
|
NC_get_dispatch_override(void) {
|
|
return NC_dispatch_override;
|
|
}
|
|
|
|
void NC_set_dispatch_override(NC_Dispatch* d)
|
|
{
|
|
NC_dispatch_override = d;
|
|
}
|
|
#endif
|
|
|
|
/* OBSOLETE
|
|
Overlay by treating the tables as arrays of void*.
|
|
Overlay rules are:
|
|
overlay base merge
|
|
------- ---- -----
|
|
null null null
|
|
null y y
|
|
x null x
|
|
x y x
|
|
*/
|
|
|
|
#ifdef OBSOLETE
|
|
int
|
|
NC_dispatch_overlay(const NC_Dispatch* overlay, const NC_Dispatch* base, NC_Dispatch* merge)
|
|
{
|
|
void** voverlay = (void**)overlay;
|
|
void** vmerge;
|
|
int i;
|
|
size_t count = sizeof(NC_Dispatch) / sizeof(void*);
|
|
/* dispatch table must be exact multiple of sizeof(void*) */
|
|
assert(count * sizeof(void*) == sizeof(NC_Dispatch));
|
|
*merge = *base;
|
|
vmerge = (void**)merge;
|
|
for(i=0;i<count;i++) {
|
|
if(voverlay[i] == NULL) continue;
|
|
vmerge[i] = voverlay[i];
|
|
}
|
|
/* Finally, the merge model should always be the overlay model */
|
|
merge->model = overlay->model;
|
|
return NC_NOERR;
|
|
}
|
|
#endif
|