netcdf-c/libdispatch/ddispatch.c

336 lines
8.4 KiB
C

/*
Copyright (c) 1998-2018 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