Merge branch 'winutf8.dmh' of https://github.com/DennisHeimbigner/netcdf-c into gh2222.wif

This commit is contained in:
Ward Fisher 2022-04-05 10:46:22 -06:00
commit 3446aa0c13
44 changed files with 833 additions and 592 deletions

View File

@ -7,7 +7,7 @@
name: Run macOS-based netCDF Tests
on: [pull_request]
on: [pull_request,push]
jobs:

View File

@ -57,6 +57,21 @@ IF(UNAME)
set(TMP_BUILDNAME "${osname}-${osrel}-${cpu}")
ENDIF()
# Define some Platforms
if(osname MATCHES "CYGWIN.*")
SET(ISCYGWIN yes)
endif()
if(osname MATCHES "Darwin.*")
SET(ISOSX yes)
endif()
if(MSVC)
SET(ISMSVC yes)
endif()
if(osname MATCHES "MINGW.*")
SET(ISMINGW yes)
SET(MINGW yes)
endif()
###
# Allow for some customization of the buildname.
# This will make it easier to identify different builds,
@ -88,6 +103,7 @@ INCLUDE(GNUInstallDirs)
IF(MSVC)
SET(GLOBAL PROPERTY USE_FOLDERS ON)
ADD_COMPILE_OPTIONS("/utf-8")
ENDIF()
#Add custom CMake Module
@ -427,7 +443,6 @@ IF(NOT MSVC)
ENDIF(BUILD_FORTRAN)
ENDIF()
###
# Allow the user to specify libraries
# to link against, similar to automakes 'LIBS' variable.
@ -1846,6 +1861,26 @@ IF(ENABLE_MMAP)
ENDIF(ENABLE_MMAP)
#CHECK_FUNCTION_EXISTS(alloca HAVE_ALLOCA)
# Used in the `configure_file` calls below
SET(ISCMAKE "1")
IF(MSVC)
SET(ISMSVC ON CACHE BOOL "" FORCE)
SET(REGEDIT ON CACHE BOOL "" FORCE)
# Get windows major version and build number
EXECUTE_PROCESS(COMMAND "systeminfo" OUTPUT_VARIABLE WININFO)
IF(WININFO STREQUAL "")
SET(WVM 0)
SET(WVB 0)
ELSE()
STRING(REGEX MATCH "\nOS Version:[ \t]+[0-9.]+" WINVERLINE "${WININFO}")
STRING(REGEX REPLACE "[^0-9]*([0-9]+)[.]([0-9])+[.]([0-9]+)" "\\1" WVM "${WINVERLINE}")
STRING(REGEX REPLACE "[^0-9]*([0-9]+)[.]([0-9])+[.]([0-9]+)" "\\3" WVB "${WINVERLINE}")
ENDIF()
SET(WINVERMAJOR ${WVM} CACHE STRING "" FORCE)
SET(WINVERBUILD ${WVB} CACHE STRING "" FORCE)
ENDIF()
#####
# End system inspection checks.
#####
@ -2467,13 +2502,6 @@ configure_file(
${netCDF_SOURCE_DIR}/include/netcdf_dispatch.h.in
${netCDF_BINARY_DIR}/include/netcdf_dispatch.h @ONLY NEWLINE_STYLE LF)
# Used in the `configure_file` calls below
SET(ISCMAKE "1")
IF(MSVC)
SET(ISMSVC "1")
SET(REGEDIT 1)
ENDIF()
####
# Build test_common.sh
#####

View File

@ -12,6 +12,7 @@ This file contains a high-level description of this package's evolution. Release
* [Bug Fix] Require that the type of the variable in nc_def_var_filter is not variable length. See [Github #/2231](https://github.com/Unidata/netcdf-c/pull/2231).
* [File Change] Apply HDF5 v1.8 format compatibility when writing to previous files, as well as when creating new files. The superblock version remains at 2 for newly created files. Full backward read/write compatibility for netCDF-4 is maintained in all cases. See [Github #2176](https://github.com/Unidata/netcdf-c/issues/2176).
* [Enhancement] Add ability to set dataset alignment for netcdf-4/HDF5 files. See [Github #2206](https://github.com/Unidata/netcdf-c/pull/2206).
* [Bug Fix] Improve UTF8 support on windows so that it can use utf8 natively. See [Github #2222](https://github.com/Unidata/netcdf-c/pull/2222).
* [Enhancement] Add complete bitgroom support to NCZarr. See [Github #2197](https://github.com/Unidata/netcdf-c/pull/2197).
* [Bug Fix] Clean up the handling of deeply nested VLEN types. Marks nc_free_vlen() and nc_free_string as deprecated in favor of ncaux_reclaim_data(). See [Github #2179](https://github.com/Unidata/netcdf-c/pull/2179).
* [Bug Fix] Make sure that netcdf.h accurately defines the flags in the open/create mode flags. See [Github #2183](https://github.com/Unidata/netcdf-c/pull/2183).

View File

@ -157,12 +157,6 @@ are set when opening a binary file on Windows. */
/* if true, Allow dynamically loaded plugins */
#cmakedefine ENABLE_PLUGINS 1
/* Do we have access to the Windows Registry */
#cmakedefine REGEDIT 1
/* define the possible sources for remote test servers */
#cmakedefine REMOTETESTSERVERS "${REMOTETESTSERVERS}"
/* if true, run extra tests which may not work yet */
#cmakedefine EXTRA_TESTS 1
@ -510,6 +504,12 @@ with zip */
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "${netCDF_VERSION}"
/* Do we have access to the Windows Registry */
#cmakedefine REGEDIT 1
/* define the possible sources for remote test servers */
#cmakedefine REMOTETESTSERVERS "${REMOTETESTSERVERS}"
/* The size of `ulonglong` as computed by sizeof. */
#cmakedefine SIZEOF_ULONGLONG @SIZEOF_ULONGLONG@
@ -628,6 +628,10 @@ with zip */
/* Version number of package */
#cmakedefine VERSION "${netCDF_VERSION}"
/* Capture Windows version and build */
#cmakedefine WINVERMAJOR ${WINVERMAJOR}
#cmakedefine WINVERBUILD ${WINVERBUILD}
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD

View File

@ -106,6 +106,15 @@ ISMINGW=yes
ISMSYS=yes
fi
# Get windows version info
WINVER=`systeminfo | sed -e '/^OS Version:/p' -ed | sed -e 's|[^0-9]*\([0-9.]*\).*|\1|'`
WINVERMAJOR=`echo $WVER | sed -e 's|\([^.]*\)[.]\([^.]*\)[.]\(.*\)|\1|'`
WINVERBUILD=`echo $WVER | sed -e 's|\([^.]*\)[.]\([^.]*\)[.]\(.*\)|\3|'`
if test "x$WINVERMAJOR" = x ; then WINVERMAJOR=0; fi
if test "x$WINVERBUILD" = x ; then WINVERBUILD=0; fi
AC_DEFINE_UNQUOTED([WINVERMAJOR], [$WINVERMAJOR], [windows version major])
AC_DEFINE_UNQUOTED([WINVERBUILD], [$WINVERBUILD], [windows version build])
AC_MSG_NOTICE([checking supported formats])
# An explicit disable of netcdf-4 | netcdf4 is treated as if it was disable-hdf5
@ -1279,6 +1288,8 @@ AM_CONDITIONAL(ISMINGW, [test "x$ISMINGW" = xyes])
AM_CONDITIONAL(ISMSYS, [test "x$ISMSYS" = xyes])
AC_SUBST([ISMSVC], [${ISMSVC}])
AC_SUBST([WINVERMAJOR], [${WINVERMAJOR}])
AC_SUBST([WINVERBUILD], [${WINVERBUILD}])
AC_SUBST([ISCYGWIN], [${ISCYGWIN}])
AC_SUBST([ISOSX], [${ISOSX}])
AC_SUBST([ISMINGW], [${ISMINGW}])

View File

@ -26,26 +26,6 @@ static char* outfile = NULL;
static int ncid = 0;
static int translatenc4 = 0;
static int
readfile(const char* filename, NCbytes* content)
{
FILE* stream;
char part[1024];
stream = fopen(filename,"r");
if(stream == NULL) return errno;
for(;;) {
size_t count = fread(part, 1, sizeof(part), stream);
if(count <= 0) break;
ncbytesappendn(content,part,count);
if(ferror(stream)) {fclose(stream); return NC_EIO;}
if(feof(stream)) break;
}
ncbytesnull(content);
fclose(stream);
return NC_NOERR;
}
static void
fail(int code)
{
@ -86,7 +66,7 @@ setup(int tdmr, int argc, char** argv)
outfile = NULL;
input = ncbytesnew();
output = ncbytesnew();
if((ret = readfile(infile,input))) fail(ret);
if((ret = NC_readfile(infile,input))) fail(ret);
{
const char* trans = getenv("translatenc4");
if(trans != NULL)

View File

@ -20,6 +20,8 @@
#include "netcdf.h"
#include "netcdf_filter.h"
#include "nc_logging.h"
#include "ncpathmgr.h"
#include "ncrc.h"
#ifdef USE_PARALLEL
#include "netcdf_par.h"
#endif

View File

@ -86,6 +86,8 @@ EXTERNL int NC__testurl(const char* path, char** basenamep);
EXTERNL int NC_isLittleEndian(void);
EXTERNL char* NC_entityescape(const char* s);
EXTERNL int NC_readfile(const char* filename, NCbytes* content);
EXTERNL int NC_readfilen(const char* filename, NCbytes* content, long long len);
EXTERNL int NC_readfileF(FILE* fp, NCbytes* content, long long len);
EXTERNL int NC_writefile(const char* filename, size_t size, void* content);
EXTERNL char* NC_mktmp(const char* base);
EXTERNL int NC_getmodelist(const char* modestr, NClist** modelistp);

View File

@ -395,17 +395,17 @@ set_curl_properties(NCD4INFO* d4info)
FILE* f = NULL;
char* fname = d4info->auth->curlflags.cookiejar;
/* See if the file exists already */
f = fopen(fname,"r");
f = NCfopen(fname,"r");
if(f == NULL) {
/* Ok, create it */
f = fopen(fname,"w+");
f = NCfopen(fname,"w+");
if(f == NULL) {
fprintf(stderr,"Cookie file cannot be read and written: %s\n",fname);
{ret= NC_EPERM; goto fail;}
}
} else { /* test if file can be written */
fclose(f);
f = fopen(fname,"r+");
f = NCfopen(fname,"r+");
if(f == NULL) {
fprintf(stderr,"Cookie file is cannot be written: %s\n",fname);
{ret = NC_EPERM; goto fail;}

View File

@ -42,6 +42,7 @@
#include "ncuri.h"
#include "nclog.h"
#include "ncdap.h"
#include "ncpathmgr.h"
#include "d4util.h"

View File

@ -346,73 +346,6 @@ NCD4_elidenuls(char* s, size_t slen)
return j;
}
int
NCD4_readfile(const char* filename, NCbytes* content)
{
int ret = NC_NOERR;
FILE* stream = NULL;
char part[1024];
stream = fopen(filename,"r");
if(stream == NULL) {ret=errno; goto done;}
for(;;) {
size_t count = fread(part, 1, sizeof(part), stream);
if(count <= 0) break;
ncbytesappendn(content,part,count);
if(ferror(stream)) {ret = NC_EIO; goto done;}
if(feof(stream)) break;
}
ncbytesnull(content);
done:
if(stream) fclose(stream);
return ret;
}
/**
Wrap mktmp and return the generated name
*/
int
NCD4_mktmp(const char* base, char** tmpnamep)
{
int fd;
char tmp[NC_MAX_PATH];
#ifdef HAVE_MKSTEMP
mode_t mask;
#endif
strncpy(tmp,base,sizeof(tmp));
#ifdef HAVE_MKSTEMP
strlcat(tmp,"XXXXXX", sizeof(tmp));
/* Note Potential problem: old versions of this function
leave the file in mode 0666 instead of 0600 */
mask=umask(0077);
fd = mkstemp(tmp);
(void)umask(mask);
#else /* !HAVE_MKSTEMP */
/* Need to simulate by using some kind of pseudo-random number */
{
int rno = rand();
char spid[7];
if(rno < 0) rno = -rno;
snprintf(spid,sizeof(spid),"%06d",rno);
strlcat(tmp,spid,sizeof(tmp));
#if defined(_WIN32) || defined(_WIN64)
fd=open(tmp,O_RDWR|O_BINARY|O_CREAT, _S_IREAD|_S_IWRITE);
# else
fd=open(tmp,O_RDWR|O_CREAT|O_EXCL, S_IRWXU);
# endif
}
#endif /* !HAVE_MKSTEMP */
if(fd < 0) {
nclog(NCLOGERR, "Could not create temp file: %s",tmp);
return THROW(NC_EPERM);
} else
close(fd);
if(tmpnamep) *tmpnamep = strdup(tmp);
return THROW(NC_NOERR);
}
void
NCD4_hostport(NCURI* uri, char* space, size_t len)
{

View File

@ -64,114 +64,114 @@ defined here, including function-like #defines.
/* DSP API wrappers */
#ifdef FIX
extern int dsp_getDMR(ND4dsp* dsp, DCR** dcrp);
extern int dsp_getDAP(ND4dsp* dsp, DCR** dcrp);
extern int dsp_close(ND4dsp* dsp);
EXTERNL int dsp_getDMR(ND4dsp* dsp, DCR** dcrp);
EXTERNL int dsp_getDAP(ND4dsp* dsp, DCR** dcrp);
EXTERNL int dsp_close(ND4dsp* dsp);
/* DSP API */
extern int dsp_open(const char* path, ND4dsp** dspp);
EXTERNL int dsp_open(const char* path, ND4dsp** dspp);
#endif
/**************************************************/
/* From d4http.c */
extern long NCD4_fetchhttpcode(CURL* curl);
extern int NCD4_fetchurl_file(CURL* curl, const char* url, FILE* stream, d4size_t* sizep, long* filetime);
extern int NCD4_fetchurl(CURL* curl, const char* url, NCbytes* buf, long* filetime, int* httpcode);
extern int NCD4_curlopen(CURL** curlp);
extern void NCD4_curlclose(CURL* curl);
extern int NCD4_fetchlastmodified(CURL* curl, char* url, long* filetime);
extern int NCD4_ping(const char* url);
EXTERNL long NCD4_fetchhttpcode(CURL* curl);
EXTERNL int NCD4_fetchurl_file(CURL* curl, const char* url, FILE* stream, d4size_t* sizep, long* filetime);
EXTERNL int NCD4_fetchurl(CURL* curl, const char* url, NCbytes* buf, long* filetime, int* httpcode);
EXTERNL int NCD4_curlopen(CURL** curlp);
EXTERNL void NCD4_curlclose(CURL* curl);
EXTERNL int NCD4_fetchlastmodified(CURL* curl, char* url, long* filetime);
EXTERNL int NCD4_ping(const char* url);
/* From d4read.c */
extern int NCD4_readDMR(NCD4INFO* state, int flags);
extern int NCD4_readDAP(NCD4INFO* state, int flags);
extern int NCD4_seterrormessage(NCD4meta* metadata, size_t len, char* msg);
EXTERNL int NCD4_readDMR(NCD4INFO* state, int flags);
EXTERNL int NCD4_readDAP(NCD4INFO* state, int flags);
EXTERNL int NCD4_seterrormessage(NCD4meta* metadata, size_t len, char* msg);
/* From d4parser.c */
extern int NCD4_parse(NCD4meta*);
extern NCD4node* NCD4_findAttr(NCD4node* container, const char* attrname);
extern NCD4node* NCD4_groupFor(NCD4node* node);
extern int NCD4_defineattr(NCD4meta* meta, NCD4node* parent, const char* aname, const char* typename, NCD4node** attrp);
EXTERNL int NCD4_parse(NCD4meta*);
EXTERNL NCD4node* NCD4_findAttr(NCD4node* container, const char* attrname);
EXTERNL NCD4node* NCD4_groupFor(NCD4node* node);
EXTERNL int NCD4_defineattr(NCD4meta* meta, NCD4node* parent, const char* aname, const char* typename, NCD4node** attrp);
/* From d4printer.c */
extern int NCD4_print(NCD4meta*, NCbytes* output);
EXTERNL int NCD4_print(NCD4meta*, NCbytes* output);
/* From d4meta.c */
extern NCD4meta* NCD4_newmeta(NCD4INFO*);
extern void NCD4_attachraw(NCD4meta*, size_t size, void* rawdata);
extern void NCD4_reclaimMeta(NCD4meta*);
extern void NCD4_resetMeta(NCD4meta*);
extern void reclaimNode(NCD4node* node);
extern void NCD4_setdebuglevel(NCD4meta*,int);
extern int NCD4_metabuild(NCD4meta*, int ncid);
extern size_t NCD4_computeTypeSize(NCD4meta*, NCD4node* type);
extern int NCD4_findvar(NC* ncp, int ncid, int varid, NCD4node** varp, NCD4node** grpp);
EXTERNL NCD4meta* NCD4_newmeta(NCD4INFO*);
EXTERNL void NCD4_attachraw(NCD4meta*, size_t size, void* rawdata);
EXTERNL void NCD4_reclaimMeta(NCD4meta*);
EXTERNL void NCD4_resetMeta(NCD4meta*);
EXTERNL void reclaimNode(NCD4node* node);
EXTERNL void NCD4_setdebuglevel(NCD4meta*,int);
EXTERNL int NCD4_metabuild(NCD4meta*, int ncid);
EXTERNL size_t NCD4_computeTypeSize(NCD4meta*, NCD4node* type);
EXTERNL int NCD4_findvar(NC* ncp, int ncid, int varid, NCD4node** varp, NCD4node** grpp);
/* From d4chunk.c */
extern int NCD4_dechunk(NCD4meta*);
extern int NCD4_infermode(NCD4meta* meta);
EXTERNL int NCD4_dechunk(NCD4meta*);
EXTERNL int NCD4_infermode(NCD4meta* meta);
struct NCD4serial;
extern void NCD4_resetSerial(struct NCD4serial* serial, size_t rawsize, void* rawdata);
EXTERNL void NCD4_resetSerial(struct NCD4serial* serial, size_t rawsize, void* rawdata);
/* From d4swap.c */
extern int NCD4_swapdata(NCD4meta*, NClist* topvars);
EXTERNL int NCD4_swapdata(NCD4meta*, NClist* topvars);
/* From d4fix.c */
extern int NCD4_delimit(NCD4meta*, NCD4node* var, void** offsetp);
extern int NCD4_moveto(NCD4meta*, NCD4node* var, d4size_t count, void** offsetp);
extern int NCD4_toposort(NCD4meta*);
EXTERNL int NCD4_delimit(NCD4meta*, NCD4node* var, void** offsetp);
EXTERNL int NCD4_moveto(NCD4meta*, NCD4node* var, d4size_t count, void** offsetp);
EXTERNL int NCD4_toposort(NCD4meta*);
/* From d4data.c */
extern int NCD4_processdata(NCD4meta*);
extern int NCD4_fillinstance(NCD4meta*, NCD4node* type, void** offsetp, void** dstp, NClist* blobs);
extern int NCD4_getToplevelVars(NCD4meta* meta, NCD4node* group, NClist* toplevel);
EXTERNL int NCD4_processdata(NCD4meta*);
EXTERNL int NCD4_fillinstance(NCD4meta*, NCD4node* type, void** offsetp, void** dstp, NClist* blobs);
EXTERNL int NCD4_getToplevelVars(NCD4meta* meta, NCD4node* group, NClist* toplevel);
/* From d4util.c */
extern d4size_t NCD4_dimproduct(NCD4node* node);
extern size_t NCD4_typesize(nc_type tid);
extern int NCD4_isLittleEndian(void);/* Return 1 if this machine is little endian */
extern int NCD4_errorNC(int code, const int line, const char* file);
extern int NCD4_error(int code, const int line, const char* file, const char* fmt, ...);
extern char* NCD4_makeFQN(NCD4node* node);
extern char* NCD4_makeName(NCD4node*,const char* sep);
extern int NCD4_parseFQN(const char* fqn0, NClist* pieces);
extern char* NCD4_deescape(const char* esc);
extern char* NCD4_entityescape(const char* s);
extern size_t NCD4_elidenuls(char* s, size_t slen);
extern void* NCD4_getheader(void* p, NCD4HDR* hdr, int hostlittleendian);
extern void NCD4_reporterror(NCD4INFO* state);
EXTERNL d4size_t NCD4_dimproduct(NCD4node* node);
EXTERNL size_t NCD4_typesize(nc_type tid);
EXTERNL int NCD4_isLittleEndian(void);/* Return 1 if this machine is little endian */
EXTERNL int NCD4_errorNC(int code, const int line, const char* file);
EXTERNL int NCD4_error(int code, const int line, const char* file, const char* fmt, ...);
EXTERNL char* NCD4_makeFQN(NCD4node* node);
EXTERNL char* NCD4_makeName(NCD4node*,const char* sep);
EXTERNL int NCD4_parseFQN(const char* fqn0, NClist* pieces);
EXTERNL char* NCD4_deescape(const char* esc);
EXTERNL char* NCD4_entityescape(const char* s);
EXTERNL size_t NCD4_elidenuls(char* s, size_t slen);
EXTERNL void* NCD4_getheader(void* p, NCD4HDR* hdr, int hostlittleendian);
EXTERNL void NCD4_reporterror(NCD4INFO* state);
/* From d4dump.c */
extern void NCD4_dumpbytes(size_t size, const void* data0, int swap);
extern void NCD4_tagdump(size_t size, const void* data0, int swap, const char* tag);
extern void NCD4_dumpvars(NCD4node* group);
extern union ATOMICS* NCD4_dumpatomic(NCD4node* var, void* data);
EXTERNL void NCD4_dumpbytes(size_t size, const void* data0, int swap);
EXTERNL void NCD4_tagdump(size_t size, const void* data0, int swap, const char* tag);
EXTERNL void NCD4_dumpvars(NCD4node* group);
EXTERNL union ATOMICS* NCD4_dumpatomic(NCD4node* var, void* data);
/* From d4rc.c */
extern int NCD4_rcload(void);
extern int NCD4_rcprocess(NCD4INFO* info);
extern void NCD4_rcfree(NClist* rc);
extern char* NCD4_rclookup(char* key, char* hostport);
extern int NCD4_parseproxy(NCD4INFO* info, const char* surl);
extern int NCD4_rcdefault(NCD4INFO*);
EXTERNL int NCD4_rcload(void);
EXTERNL int NCD4_rcprocess(NCD4INFO* info);
EXTERNL void NCD4_rcfree(NClist* rc);
EXTERNL char* NCD4_rclookup(char* key, char* hostport);
EXTERNL int NCD4_parseproxy(NCD4INFO* info, const char* surl);
EXTERNL int NCD4_rcdefault(NCD4INFO*);
/* From d4cvt.c */
extern int NCD4_convert(nc_type srctype, nc_type dsttype, char* memory0, char* value0, size_t count);
EXTERNL int NCD4_convert(nc_type srctype, nc_type dsttype, char* memory0, char* value0, size_t count);
/* d4file.c */
extern void NCD4_applyclientparamcontrols(NCD4INFO*);
extern int NCD4_readDMRorDAP(NCD4INFO* d4info, NCD4mode mode);
EXTERNL void NCD4_applyclientparamcontrols(NCD4INFO*);
EXTERNL int NCD4_readDMRorDAP(NCD4INFO* d4info, NCD4mode mode);
/* ncd4dispatch.c */
struct NC_reservedatt; /*forward*/
extern const struct NC_reservedatt* NCD4_lookupreserved(const char* name);
EXTERNL const struct NC_reservedatt* NCD4_lookupreserved(const char* name);
/* Add an extra function whose sole purpose is to allow
configure(.ac) to test for the presence of this code.
*/
extern int nc__dap4(void);
EXTERNL int nc__dap4(void);
/**************************************************/
/* Macro defined functions */

View File

@ -199,7 +199,7 @@ local void make_crc_table()
{
FILE *out;
out = fopen("dcrc32.h", "w");
out = NCfopen("dcrc32.h", "w");
if (out == NULL) return;
fprintf(out, "/* dcrc32.h -- tables for rapid CRC calculation\n");
fprintf(out, " * Generated automatically by dcrc32.c\n */\n\n");

View File

@ -1263,9 +1263,8 @@ openmagic(struct MagicFile* file)
} else
#endif /* USE_PARALLEL */
{
if(file->path == NULL || strlen(file->path)==0)
{status = NC_EINVAL; goto done;}
if (file->path == NULL || strlen(file->path) == 0)
{status = NC_EINVAL; goto done;}
file->fp = NCfopen(file->path, "r");
if(file->fp == NULL)
{status = errno; goto done;}
@ -1296,6 +1295,8 @@ static int
readmagic(struct MagicFile* file, long pos, char* magic)
{
int status = NC_NOERR;
NCbytes* buf = ncbytesnew();
memset(magic,0,MAGIC_NUMBER_LEN);
if(fIsSet(file->omode,NC_INMEMORY)) {
char* mempos;
@ -1315,19 +1316,18 @@ readmagic(struct MagicFile* file, long pos, char* magic)
if(file->iss3) {
if((status = NC_s3sdkread(file->s3client,file->s3.bucket,file->s3.rootkey,start,count,(void*)magic,&file->errmsg)))
{goto done;}
} else
}
else
#endif
{
NCbytes* buf = ncbytesnew();
status = nc_http_read(file->state,file->curlurl,start,count,buf);
if(status == NC_NOERR) {
if(ncbyteslength(buf) != count)
status = NC_EINVAL;
else
memcpy(magic,ncbytescontents(buf),count);
}
ncbytesfree(buf);
}
{
status = nc_http_read(file->state, file->curlurl, start, count, buf);
if (status == NC_NOERR) {
if (ncbyteslength(buf) != count)
status = NC_EINVAL;
else
memcpy(magic, ncbytescontents(buf), count);
}
}
#endif
} else {
#ifdef USE_PARALLEL
@ -1337,23 +1337,21 @@ readmagic(struct MagicFile* file, long pos, char* magic)
if((retval = MPI_File_read_at_all(file->fh, pos, magic,
MAGIC_NUMBER_LEN, MPI_CHAR, &mstatus)) != MPI_SUCCESS)
{status = NC_EPARINIT; goto done;}
} else
}
else
#endif /* USE_PARALLEL */
{
int count;
int i = fseek(file->fp,pos,SEEK_SET);
if(i < 0)
{status = errno; goto done;}
for(i=0;i<MAGIC_NUMBER_LEN;) {/* make sure to read proper # of bytes */
count=fread(&magic[i],1,(size_t)(MAGIC_NUMBER_LEN-i),file->fp);
if(count == 0 || ferror(file->fp))
{status = errno; goto done;}
i += count;
}
}
{ /* Ordinary read */
long i;
i = fseek(file->fp, pos, SEEK_SET);
if (i < 0) { status = errno; goto done; }
ncbytessetlength(buf, 0);
if ((status = NC_readfileF(file->fp, buf, MAGIC_NUMBER_LEN))) goto done;
memcpy(magic, ncbytescontents(buf), MAGIC_NUMBER_LEN);
}
}
done:
ncbytesfree(buf);
if(file && file->fp) clearerr(file->fp);
return check(status);
}

View File

@ -153,14 +153,15 @@ reclaim_datar(int ncid, nc_type xtype, Position* offset)
int klass, isf;
if((stat = NC4_inq_type_fixed_size(ncid,xtype,&isf))) goto done;
/* Get relevant type info */
if((stat = NC_inq_any_type(ncid,xtype,NULL,&xsize,&basetype,&nfields,&klass))) goto done;
if(isf) { /* no need to reclaim anything */
offset->offset += xsize;
goto done;
}
/* Get relevant type info */
if((stat = NC_inq_any_type(ncid,xtype,NULL,&xsize,&basetype,&nfields,&klass))) goto done;
switch (xtype) {
case NC_STRING: {
char** sp = (char**)(offset->memory + offset->offset);

View File

@ -25,13 +25,9 @@
#include <windows.h>
#include <io.h>
#include <wchar.h>
#include <locale.h>
#include <direct.h>
#endif
#ifdef __hpux
#include <locale.h>
#endif
#include "netcdf.h"
#include "ncpathmgr.h"
#include "nclog.h"
@ -55,6 +51,14 @@ static int pathdebug = -1;
#define mkdir _mkdir
#define rmdir _rmdir
#define getcwd _getcwd
#if WINVERMAJOR > 10 || (WINVERMAJOR == 10 && WINVERBUILD >= 17134)
/* Should be possible to use UTF8 directly */
#define WINUTF8
#else
#undef WINUTF8
#endif
#endif
/*
@ -87,6 +91,11 @@ static const struct Path {
/* Keep the working directory kind and drive */
static char wdprefix[8192];
/* The current codepage */
#ifdef _WIN32
static int acp = -1;
#endif
/* Keep CYGWIN/MSYS2 mount point */
static struct MountPoint {
int defined;
@ -267,6 +276,7 @@ static void
pathinit(void)
{
if(pathinitialized) return;
pathinitialized = 1; /* avoid recursion */
/* Check for path debug env vars */
if(pathdebug < 0) {
@ -274,6 +284,12 @@ pathinit(void)
pathdebug = (s == NULL ? 0 : 1);
}
(void)getwdpath();
#ifdef _WIN32
/* Get the current code page */
acp = GetACP();
#endif
memset(&mountpoint,0,sizeof(mountpoint));
#ifdef REGEDIT
{ /* See if we can get the MSYS2 prefix from the registry */
@ -369,31 +385,44 @@ NCfopen(const char* path, const char* flags)
{
int stat = NC_NOERR;
FILE* f = NULL;
char* bflags = NULL;
char bflags[64];
char* path8 = NULL; /* ACP -> UTF=8 */
char* bflags8 = NULL;
char* cvtpath = NULL;
wchar_t* wpath = NULL;
wchar_t* wflags = NULL;
size_t flaglen = strlen(flags)+1+1;
bflags = (char*)malloc(flaglen);
bflags[0] = '\0';
strlcat(bflags,flags,flaglen);
strlcat(bflags, flags, sizeof(bflags));
#ifdef _WIN32
strlcat(bflags,"b",flaglen);
strlcat(bflags,"b",sizeof(bflags));
#endif
cvtpath = NCpathcvt(path);
if(cvtpath == NULL) return NULL;
/* Convert from local to wide */
if((stat = utf82wide(cvtpath,&wpath)))
{REPORT(stat,"utf282wide"); goto done;}
if((stat = ansi2wide(bflags,&wflags)))
{REPORT(stat,"ansi2wide"); goto done;}
f = _wfopen(wpath,wflags);
/* First, convert from current Code Page to utf8 */
if((stat = ansi2utf8(path,&path8))) goto done;
if((stat = ansi2utf8(bflags,&bflags8))) goto done;
/* Localize */
if((cvtpath = NCpathcvt(path8))==NULL) goto done;
#ifdef WINUTF8
if(acp == CP_UTF8) {
/* This should take utf8 directly */
f = fopen(cvtpath,bflags8);
} else
#endif
{
/* Convert from utf8 to wide */
if((stat = utf82wide(cvtpath,&wpath))) goto done;
if((stat = utf82wide(bflags8,&wflags))) goto done;
f = _wfopen(wpath,wflags);
}
done:
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
nullfree(wflags);
nullfree(bflags);
return f;
}
@ -404,17 +433,32 @@ NCopen3(const char* path, int flags, int mode)
int stat = NC_NOERR;
int fd = -1;
char* cvtpath = NULL;
char* path8 = NULL;
wchar_t* wpath = NULL;
cvtpath = NCpathcvt(path);
if(cvtpath == NULL) goto done;
/* Convert from utf8 to wide */
if((stat = utf82wide(cvtpath,&wpath))) goto done;
/* First, convert from current Code Page to utf8 */
if((stat = ansi2utf8(path,&path8))) goto done;
if((cvtpath = NCpathcvt(path8))==NULL) goto done;
#ifdef _WIN32
flags |= O_BINARY;
#endif
fd = _wopen(wpath,flags,mode);
#ifdef WINUTF8
if(acp == CP_UTF8) {
/* This should take utf8 directly */
fd = _open(cvtpath,flags,mode);
} else
#endif
{
/* Convert from utf8 to wide */
if((stat = utf82wide(cvtpath,&wpath))) goto done;
fd = _wopen(wpath,flags,mode);
}
done:
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
return fd;
}
@ -435,7 +479,7 @@ NCopendir(const char* path)
char* cvtname = NCpathcvt(path);
if(cvtname == NULL) return NULL;
ent = opendir(cvtname);
free(cvtname);
nullfree(cvtname);
return ent;
}
@ -458,17 +502,32 @@ EXTERNL
int
NCaccess(const char* path, int mode)
{
int status = 0;
int stat = 0;
char* cvtpath = NULL;
char* path8 = NULL;
wchar_t* wpath = NULL;
if((cvtpath = NCpathcvt(path)) == NULL)
{status = EINVAL; goto done;}
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_waccess(wpath,mode) < 0) {status = errno; goto done;}
/* First, convert from current Code Page to utf8 */
if((stat = ansi2utf8(path,&path8))) goto done;
if((cvtpath = NCpathcvt(path8)) == NULL) {stat = EINVAL; goto done;}
#ifdef WINUTF8
if(acp == CP_UTF8) {
/* This should take utf8 directly */
if(_access(cvtpath,mode) < 0) {stat = errno; goto done;}
} else
#endif
{
/* Convert from utf8 to wide */
if((stat = utf82wide(cvtpath,&wpath))) goto done;
if(_waccess(wpath,mode) < 0) {stat = errno; goto done;}
}
done:
free(cvtpath);
free(wpath);
errno = status;
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
errno = stat;
return (errno?-1:0);
}
@ -477,14 +536,29 @@ int
NCremove(const char* path)
{
int status = 0;
char* path8 = NULL;
char* cvtpath = NULL;
wchar_t* wpath = NULL;
if((cvtpath = NCpathcvt(path)) == NULL) {status=ENOMEM; goto done;}
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wremove(wpath) < 0) {status = errno; goto done;}
/* First, convert from current Code Page to utf8 */
if((status = ansi2utf8(path,&path8))) goto done;
if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;}
#ifdef WINUTF8
if(acp == CP_UTF8) {
/* This should take utf8 directly */
if(remove(cvtpath) < 0) {status = errno; goto done;}
} else
#endif
{
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wremove(wpath) < 0) {status = errno; goto done;}
}
done:
free(cvtpath);
free(wpath);
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
errno = status;
return (errno?-1:0);
}
@ -495,13 +569,28 @@ NCmkdir(const char* path, int mode)
{
int status = 0;
char* cvtpath = NULL;
char* path8 = NULL;
wchar_t* wpath = NULL;
if((cvtpath = NCpathcvt(path)) == NULL) {status=ENOMEM; goto done;}
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wmkdir(wpath) < 0) {status = errno; goto done;}
/* First, convert from current Code Page to utf8 */
if((status = ansi2utf8(path,&path8))) goto done;
if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;}
#ifdef WINUTF8
if(acp == CP_UTF8) {
/* This should take utf8 directly */
if(_mkdir(cvtpath) < 0) {status = errno; goto done;}
} else
#endif
{
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wmkdir(wpath) < 0) {status = errno; goto done;}
}
done:
free(cvtpath);
free(wpath);
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
errno = status;
return (errno?-1:0);
}
@ -511,10 +600,18 @@ int
NCrmdir(const char* path)
{
int status = 0;
char* cvtname = NCpathcvt(path);
if(cvtname == NULL) {errno = ENOENT; return -1;}
char* cvtname = NULL;
char* path8 = NULL;
/* First, convert from current Code Page to utf8 */
if((status = ansi2utf8(path,&path8))) goto done;
cvtname = NCpathcvt(path8);
if(cvtname == NULL) {errno = ENOENT; status = -1;}
status = rmdir(cvtname);
free(cvtname);
done:
nullfree(cvtname);
nullfree(path8);
return status;
}
@ -591,13 +688,26 @@ NCstat(const char* path, struct stat* buf)
{
int status = 0;
char* cvtpath = NULL;
char* path8 = NULL;
wchar_t* wpath = NULL;
if((cvtpath = NCpathcvt(path)) == NULL) {status=ENOMEM; goto done;}
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wstat64(wpath,buf) < 0) {status = errno; goto done;}
if((status = ansi2utf8(path,&path8))) goto done;
if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;}
#ifdef WINUTF8
if(acp == CP_UTF8) {
if(_stat64(cvtpath,buf) < 0) {status = errno; goto done;}
} else
#endif
{
if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;}
if(_wstat64(wpath,buf) < 0) {status = errno; goto done;}
}
done:
free(cvtpath);
free(wpath);
nullfree(cvtpath);
nullfree(path8);
nullfree(wpath);
errno = status;
return (errno?-1:0);
}
@ -674,6 +784,7 @@ parsepath(const char* inpath, struct Path* path)
memset(path,0,sizeof(struct Path));
if(inpath == NULL) goto done; /* defensive driving */
if(!pathinitialized) pathinit();
#if 0
/* Convert to UTF8 */
@ -1001,7 +1112,7 @@ getwdpath(void)
wpath = _wgetcwd(wcwd, 8192);
path = NULL;
stat = wide2utf8(wpath, &path);
free(wcwd);
nullfree(wcwd);
if (stat) return stat;
strlcat(wdprefix,path,sizeof(wdprefix));
}
@ -1069,9 +1180,9 @@ NCgetkindname(int kind)
#ifdef WINPATH
/**
* Converts the filename from Locale character set (presumably some
* Converts the file path from current character set (presumably some
* ANSI character set like ISO-Latin-1 or UTF-8 to UTF-8
* @param local Pointer to a nul-terminated string in locale char set.
* @param local Pointer to a nul-terminated string in current char set.
* @param u8p Pointer for returning the output utf8 string
*
* @return NC_NOERR return converted filename
@ -1080,21 +1191,32 @@ NCgetkindname(int kind)
*
*/
static int
ansi2utf8(const char* local, char** u8p)
ansi2utf8(const char* path, char** u8p)
{
int stat=NC_NOERR;
char* u8 = NULL;
int n;
wchar_t* u16 = NULL;
if(path == NULL) goto done;
if(!pathinitialized) pathinit();
#ifdef WINUTF8
if(acp == CP_UTF8) { /* Current code page is UTF8 and Windows supports */
u8 = strdup(path);
if(u8 == NULL) stat = NC_ENOMEM;
} else
#endif
/* Use wide character conversion plus current code page*/
{
/* Get length of the converted string */
n = MultiByteToWideChar(CP_ACP, 0, local, -1, NULL, 0);
n = MultiByteToWideChar(acp, 0, path, -1, NULL, 0);
if (!n) {stat = NC_EINVAL; goto done;}
if((u16 = malloc(sizeof(wchar_t) * n))==NULL)
if((u16 = malloc(sizeof(wchar_t) * (n)))==NULL)
{stat = NCTHROW(NC_ENOMEM); goto done;}
/* do the conversion */
if (!MultiByteToWideChar(CP_ACP, 0, local, -1, u16, n))
if (!MultiByteToWideChar(CP_ACP, 0, path, -1, u16, n))
{stat = NC_EINVAL; goto done;}
/* Now reverse the process to produce utf8 */
n = WideCharToMultiByte(CP_UTF8, 0, u16, -1, NULL, 0, NULL, NULL);
@ -1104,8 +1226,8 @@ ansi2utf8(const char* local, char** u8p)
if (!WideCharToMultiByte(CP_UTF8, 0, u16, -1, u8, n, NULL, NULL))
{stat = NC_EINVAL; goto done;}
}
if(u8p) {*u8p = u8; u8 = NULL;}
done:
if(u8p) {*u8p = u8; u8 = NULL;}
nullfree(u8);
nullfree(u16);
return stat;
@ -1118,6 +1240,8 @@ ansi2wide(const char* local, wchar_t** u16p)
wchar_t* u16 = NULL;
int n;
if(!pathinitialized) pathinit();
/* Get length of the converted string */
n = MultiByteToWideChar(CP_ACP, 0, local, -1, NULL, 0);
if (!n) {stat = NC_EINVAL; goto done;}
@ -1139,6 +1263,8 @@ utf82wide(const char* utf8, wchar_t** u16p)
wchar_t* u16 = NULL;
int n;
if(!pathinitialized) pathinit();
/* Get length of the converted string */
n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
if (!n) {stat = NC_EINVAL; goto done;}
@ -1160,6 +1286,8 @@ wide2utf8(const wchar_t* u16, char** u8p)
char* u8 = NULL;
int n;
if(!pathinitialized) pathinit();
/* Get length of the converted string */
n = WideCharToMultiByte(CP_UTF8, 0, u16, -1, NULL, 0, NULL, NULL);
if (!n) {stat = NC_EINVAL; goto done;}
@ -1174,17 +1302,6 @@ done:
return stat;
}
/* Set locale */
void
nc_setlocale_utf8(void)
{
#ifdef __hpux
setlocale(LC_CTYPE,"");
#else
setlocale(LC_ALL,"C.UTF8");
#endif
}
#endif /*WINPATH*/
static char*

View File

@ -211,16 +211,41 @@ NC_mktmp(const char* base)
int fd = -1;
char* tmp = NULL;
size_t len;
int tries;
#define MAXTRIES 4
#ifdef HAVE_MKSTEMP
mode_t mask;
#endif
len = strlen(base)+6+1;
if((tmp = (char*)malloc(len))==NULL)
if((tmp = (char*)calloc(1,len))==NULL)
goto done;
strncpy(tmp,base,len);
#ifdef HAVE_MKSTEMP
strlcat(tmp,base,len);
strlcat(tmp, "XXXXXX", len);
mask=umask(0077);
fd = NCmkstemp(tmp);
(void)umask(mask);
#else /* !HAVE_MKSTEMP */
/* Need to simulate by using some kind of pseudo-random number */
for(tries=0;tries<MAXTRIES;tries++) {
int rno = rand();
char spid[7];
if(rno < 0) rno = -rno;
tmp[0] = '\0';
strlcat(tmp,base,len);
snprintf(spid,sizeof(spid),"%06d",rno);
strlcat(tmp,spid,len);
fd=NCopen3(tmp,O_RDWR|O_CREAT, _S_IREAD|_S_IWRITE);
if(fd >= 0) break; /* sucess */
fd = -1; /* try again */
}
#endif /* !HAVE_MKSTEMP */
if(fd < 0) {
nclog(NCLOGERR, "Could not create temp file: %s",tmp);
goto done;
nclog(NCLOGERR, "Could not create temp file: %s",tmp);
nullfree(tmp);
tmp = NULL;
goto done;
}
done:
if(fd >= 0) close(fd);
@ -230,23 +255,47 @@ done:
/** \internal */
int
NC_readfile(const char* filename, NCbytes* content)
{
int stat;
stat = NC_readfilen(filename, content, -1);
return stat;
}
int
NC_readfilen(const char* filename, NCbytes* content, long long amount)
{
int ret = NC_NOERR;
FILE* stream = NULL;
char part[1024];
stream = NCfopen(filename,"r");
if(stream == NULL) {ret=errno; goto done;}
for(;;) {
ret = NC_readfileF(stream,content,amount);
if (stream) fclose(stream);
done:
return ret;
}
int
NC_readfileF(FILE* stream, NCbytes* content, long long amount)
{
int ret = NC_NOERR;
long long red = 0;
char part[1024];
while(amount < 0 || red < amount) {
size_t count = fread(part, 1, sizeof(part), stream);
if(count <= 0) break;
ncbytesappendn(content,part,count);
if(ferror(stream)) {ret = NC_EIO; goto done;}
if(feof(stream)) break;
if(count > 0) ncbytesappendn(content,part,(unsigned long)count);
red += count;
if (feof(stream)) break;
}
/* Keep only amount */
if(amount >= 0) {
if(red > amount) ncbytessetlength(content,amount); /* read too much */
if(red < amount) ret = NC_ETRUNC; /* |file| < amount */
}
ncbytesnull(content);
done:
if(stream) fclose(stream);
return ret;
}
@ -268,8 +317,8 @@ NC_writefile(const char* filename, size_t size, void* content)
while(remain > 0) {
size_t written = fwrite(p, 1, remain, stream);
if(ferror(stream)) {ret = NC_EIO; goto done;}
if(feof(stream)) break;
remain -= written;
if (feof(stream)) break;
}
done:
if(stream) fclose(stream);

View File

@ -1,220 +1,284 @@
// XGetopt.cpp Version 1.2
//
// Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// Description:
// XGetopt.cpp implements getopt(), a function to parse command lines.
//
// History
// Version 1.2 - 2003 May 17
// - Added Unicode support
//
// Version 1.1 - 2002 March 10
// - Added example to XGetopt.cpp module header
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// if you are not using precompiled headers then include these lines:
///////////////////////////////////////////////////////////////////////////////
// XGetopt.cpp Version 1.2
//
// Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// Description:
// XGetopt.cpp implements getopt(), a function to parse command lines.
//
// History
// Version 1.2 - 2003 May 17
// - Added Unicode support
//
// Version 1.1 - 2002 March 10
// - Added example to XGetopt.cpp module header
//
// This software is released into the public domain.
// You are free to use it in any way you like.
//
// This software is provided "as is" with no expressed
// or implied warranty. I accept no liability for any
// damage or loss of business that this software may cause.
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// if you are not using precompiled headers then include these lines:
///////////////////////////////////////////////////////////////////////////////
#ifndef DLL_EXPORT
#define DLL_EXPORT
#endif
#include "XGetopt.h"
///////////////////////////////////////////////////////////////////////////////
//
// X G e t o p t . c p p
//
//
// NAME
// getopt -- parse command line options
//
// SYNOPSIS
// int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
//
// extern TCHAR *optarg;
// extern int optind;
//
// DESCRIPTION
// The getopt() function parses the command line arguments. Its
// arguments argc and argv are the argument count and array as
// passed into the application on program invocation. In the case
// of Visual C++ programs, argc and argv are available via the
// variables __argc and __argv (double underscores), respectively.
// getopt returns the next option letter in argv that matches a
// letter in optstring. (Note: Unicode programs should use
// __targv instead of __argv. Also, all character and string
// literals should be enclosed in _T( ) ).
//
// optstring is a string of recognized option letters; if a letter
// is followed by a colon, the option is expected to have an argument
// that may or may not be separated from it by white space. optarg
// is set to point to the start of the option argument on return from
// getopt.
//
// Option letters may be combined, e.g., "-ab" is equivalent to
// "-a -b". Option letters are case sensitive.
//
// getopt places in the external variable optind the argv index
// of the next argument to be processed. optind is initialized
// to 0 before the first call to getopt.
//
// When all options have been processed (i.e., up to the first
// non-option argument), getopt returns EOF, optarg will point
// to the argument, and optind will be set to the argv index of
// the argument. If there are no non-option arguments, optarg
// will be set to NULL.
//
// The special option "--" may be used to delimit the end of the
// options; EOF will be returned, and "--" (and everything after it)
// will be skipped.
//
// RETURN VALUE
// For option letters contained in the string optstring, getopt
// will return the option letter. getopt returns a question mark (?)
// when it encounters an option letter not included in optstring.
// EOF is returned when processing is finished.
//
// BUGS
// 1) Long options are not supported.
// 2) The GNU double-colon extension is not supported.
// 3) The environment variable POSIXLY_CORRECT is not supported.
// 4) The + syntax is not supported.
// 5) The automatic permutation of arguments is not supported.
// 6) This implementation of getopt() returns EOF if an error is
// encountered, instead of -1 as the latest standard requires.
//
// EXAMPLE
// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[])
// {
// int c;
//
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
// {
// switch (c)
// {
// case _T('a'):
// TRACE(_T("option a\n"));
// //
// // set some flag here
// //
// break;
//
// case _T('B'):
// TRACE( _T("option B\n"));
// //
// // set some other flag here
// //
// break;
//
// case _T('n'):
// TRACE(_T("option n: value=%d\n"), atoi(optarg));
// //
// // do something with value here
// //
// break;
//
// case _T('?'):
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
// return FALSE;
// break;
//
// default:
// TRACE(_T("WARNING: no handler for option %c\n"), c);
// return FALSE;
// break;
// }
// }
// //
// // check for non-option args here
// //
// return TRUE;
// }
//
///////////////////////////////////////////////////////////////////////////////
GTOPT_EXTRA TCHAR *optarg; // global argument pointer
GTOPT_EXTRA int optind = 0; // global argv index
#include "XGetopt.h"
#include "nclist.h"
#include "ncbytes.h"
#ifdef _MSC_VER
static void XCommandLineToArgvA(int* argcp, char*** argvp);
#endif
///////////////////////////////////////////////////////////////////////////////
//
// X G e t o p t . c p p
//
//
// NAME
// getopt -- parse command line options
//
// SYNOPSIS
// int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
//
// extern TCHAR *optarg;
// extern int optind;
//
// DESCRIPTION
// The getopt() function parses the command line arguments. Its
// arguments argc and argv are the argument count and array as
// passed into the application on program invocation. In the case
// of Visual C++ programs, argc and argv are available via the
// variables __argc and __argv (double underscores), respectively.
// getopt returns the next option letter in argv that matches a
// letter in optstring. (Note: Unicode programs should use
// __targv instead of __argv. Also, all character and string
// literals should be enclosed in _T( ) ).
//
// optstring is a string of recognized option letters; if a letter
// is followed by a colon, the option is expected to have an argument
// that may or may not be separated from it by white space. optarg
// is set to point to the start of the option argument on return from
// getopt.
//
// Option letters may be combined, e.g., "-ab" is equivalent to
// "-a -b". Option letters are case sensitive.
//
// getopt places in the external variable optind the argv index
// of the next argument to be processed. optind is initialized
// to 0 before the first call to getopt.
//
// When all options have been processed (i.e., up to the first
// non-option argument), getopt returns EOF, optarg will point
// to the argument, and optind will be set to the argv index of
// the argument. If there are no non-option arguments, optarg
// will be set to NULL.
//
// The special option "--" may be used to delimit the end of the
// options; EOF will be returned, and "--" (and everything after it)
// will be skipped.
//
// RETURN VALUE
// For option letters contained in the string optstring, getopt
// will return the option letter. getopt returns a question mark (?)
// when it encounters an option letter not included in optstring.
// EOF is returned when processing is finished.
//
// BUGS
// 1) Long options are not supported.
// 2) The GNU double-colon extension is not supported.
// 3) The environment variable POSIXLY_CORRECT is not supported.
// 4) The + syntax is not supported.
// 5) The automatic permutation of arguments is not supported.
// 6) This implementation of getopt() returns EOF if an error is
// encountered, instead of -1 as the latest standard requires.
//
// EXAMPLE
// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[])
// {
// int c;
//
// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF)
// {
// switch (c)
// {
// case _T('a'):
// TRACE(_T("option a\n"));
// //
// // set some flag here
// //
// break;
//
// case _T('B'):
// TRACE( _T("option B\n"));
// //
// // set some other flag here
// //
// break;
//
// case _T('n'):
// TRACE(_T("option n: value=%d\n"), atoi(optarg));
// //
// // do something with value here
// //
// break;
//
// case _T('?'):
// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]);
// return FALSE;
// break;
//
// default:
// TRACE(_T("WARNING: no handler for option %c\n"), c);
// return FALSE;
// break;
// }
// }
// //
// // check for non-option args here
// //
// return TRUE;
// }
//
///////////////////////////////////////////////////////////////////////////////
GTOPT_EXTRA TCHAR *optarg; // global argument pointer
GTOPT_EXTRA int optind = 0; // global argv index
GTOPT_EXTRA int opterr; // print error
GTOPT_EXTRA
int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
{
static TCHAR *next = NULL;
TCHAR c;
TCHAR *cp = malloc(sizeof(TCHAR)*1024);
if (optind == 0)
next = NULL;
optarg = NULL;
if (next == NULL || *next == _T('\0'))
{
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0'))
{
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
if (_tcscmp(argv[optind], _T("--")) == 0)
{
optind++;
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
next = argv[optind];
next++; // skip past -
optind++;
}
c = *next++;
cp = strchr(optstring, c);
if (cp == NULL || c == _T(':'))
return _T('?');
cp++;
if (*cp == _T(':'))
{
if (*next != _T('\0'))
{
optarg = next;
next = NULL;
}
else if (optind < argc)
{
optarg = argv[optind];
optind++;
}
else
{
return _T('?');
}
}
return c;
}
int getopt(int argc, TCHAR *argv[], TCHAR *optstring)
{
static TCHAR *next = NULL;
TCHAR c;
TCHAR *cp = malloc(sizeof(TCHAR)*1024);
#ifdef _MSC_VER
{
int xargc = -1;
char** xargv = NULL;
XCommandLineToArgvA(&xargc, &xargv);
}
#endif
if (optind == 0)
next = NULL;
optarg = NULL;
if (next == NULL || *next == _T('\0'))
{
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0'))
{
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
if (_tcscmp(argv[optind], _T("--")) == 0)
{
optind++;
optarg = NULL;
if (optind < argc)
optarg = argv[optind];
return EOF;
}
next = argv[optind];
next++; // skip past -
optind++;
}
c = *next++;
cp = strchr(optstring, c);
if (cp == NULL || c == _T(':'))
return _T('?');
cp++;
if (*cp == _T(':'))
{
if (*next != _T('\0'))
{
optarg = next;
next = NULL;
}
else if (optind < argc)
{
optarg = argv[optind];
optind++;
}
else
{
return _T('?');
}
}
return c;
}
/**************************************************/
#define ESCAPE '\\'
#define SQUOTE '\''
#define DQUOTE '"'
/* Convert a UTF8 command line into a series of words for use by XGetOpt */
/* Note only checks for ASCII '\' '\'' '"' */
static void
XCommandLineToArgvA(int* argcp, char*** argvp)
{
const char* line = NULL;
size_t len;
int whitespace;
int quote = 0;
enum State state;
NClist* argv = NULL;
NCbytes* word = NULL;
char** p;
line = GetCommandLineA();
len = strlen(line);
argv = nclistnew();
word = ncbytesnew();
whitespace = 1; /* start in whitespace mode */
for(p=line;*p;p++) {
int c = *p;
if(whitespace && c <= ' ' || c == 127) continue; /* more whitespace */
if(!whitespace && c <= ' ' || c == 127) {
whitespace = 1; /* end of word */
ncbytesnull(word);
nclistpush(argv,ncbytesextract(word)); /* capture the word */
continue;
}
whitespace = 0; /* end whitespace */
if(c == ESCAPE) {
c = *(++p); /* move to next char */
} else if(c == SQUOTE || c == DQUOTE) {
if(!quote) {quote = c; continue;} /* Start quoted text */
if(quote == c) {quote = 0; continue;} /* end quoted text */
}
/* Just collect the character as part of the current word */
ncbytesappend(word,c);
}
/* Return parsed words */
if(argcp) *argcp = nclistlength(argv);
nclistpush(argv,NULL); /* Just to be sure */
if(argvp) *argvp = (char**)nclistextract(argv);
nclistfree(argv);
ncbytesfree(word);
}

View File

@ -63,7 +63,7 @@ ncFile_create(const char *path, int ioflags, ncstdio** filepp)
File* f;
struct ncFileState* state;
f = fopen(path,"w+");
f = NCfopen(path,"w+");
if(f == NULL)
return errno;
filep = (ncstdio*)calloc(sizeof(ncstdio),1);

View File

@ -83,7 +83,9 @@ ncio_open(const char *path, int ioflags,
void* parameters,
ncio** iopp, void** const mempp)
{
#ifdef ENABLE_BYTERANGE
int modetest = urlmodetest(path);
#endif
/* Diskless open has the following constraints:
1. file must be classic version 1 or 2 or 5

View File

@ -83,7 +83,7 @@ get_file_size(char *filename, size_t *file_size)
FILE *fp;
assert(filename && file_size);
fp = fopen(filename, "r");
fp = NCfopen(filename, "r");
if (fp)
{
fseek(fp, 0 , SEEK_END);

View File

@ -82,7 +82,7 @@ get_file_size(char *filename, size_t *file_size)
FILE *fp;
assert(filename && file_size);
fp = fopen(filename, "r");
fp = NCfopen(filename, "r");
if (fp)
{
fseek(fp, 0 , SEEK_END);

View File

@ -45,7 +45,7 @@ get_mem_used1(int *mem_used)
system(cmd);
/* Read the results and delete temp file. */
if (!(fp = fopen(TMP_FILE_NAME, "r"))) ERR;
if (!(fp = NCfopen(TMP_FILE_NAME, "r"))) ERR;
fread(blob, MAX_LEN, 1, fp);
sscanf(blob, "%d", mem_used);
fclose(fp);
@ -60,7 +60,7 @@ get_mem_used2(int *mem_used)
FILE *pf;
snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
pf = fopen(buf, "r");
pf = NCfopen(buf, "r");
if (pf) {
unsigned size; /* total program size */
unsigned resident;/* resident set size */

View File

@ -167,7 +167,7 @@ get_mem_used2(int *mem_used)
FILE *pf;
snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
pf = fopen(buf, "r");
pf = NCfopen(buf, "r");
if (pf) {
unsigned size; /* total program size */
unsigned resident;/* resident set size */

View File

@ -30,7 +30,7 @@ get_mem_used2(int *mem_used)
FILE *pf;
snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
pf = fopen(buf, "r");
pf = NCfopen(buf, "r");
if (pf) {
unsigned size; /* total program size */
unsigned resident;/* resident set size */

View File

@ -91,7 +91,7 @@ main(int argc, const char* argv[])
#endif
#ifdef MEM
fd = open(PATH,O_RDONLY);
fd = NCopen2(PATH,O_RDONLY);
if(fd < 0) {
fprintf(stderr,"could not open foo.nc\n");
assert(0);

View File

@ -31,6 +31,7 @@ See \ref copyright file for more info.
#endif
#include "netcdf.h"
#include "ncpathmgr.h"
#define CLEANUP
@ -131,7 +132,8 @@ fail(int ret)
void
exists(const char* file)
{
FILE* f = fopen(file,"r");
int stat = 0;
FILE* f = NCfopen(file, "r");
if(f == NULL) fail(NC_EPERM);
fclose(f);
}
@ -139,7 +141,7 @@ exists(const char* file)
void
notexists(const char* file)
{
FILE* f = fopen(file,"r");
FILE* f = NCfopen(file,"r");
if(f != NULL) {fclose(f); fail(NC_EEXIST);}
}

View File

@ -162,80 +162,27 @@ static int
readfile(const char* path, NC_memio* memio)
{
int status = NC_NOERR;
FILE* f = NULL;
size_t filesize = 0;
size_t count = 0;
char* memory = NULL;
char* p = NULL;
/* Open the file for reading */
f = NCfopen(path,"r");
if(f == NULL)
{status = errno; goto done;}
/* get current filesize */
if(fseek(f,0,SEEK_END) < 0)
{status = errno; goto done;}
filesize = (size_t)ftell(f);
/* allocate memory */
memory = malloc((size_t)filesize);
if(memory == NULL)
{status = NC_ENOMEM; goto done;}
/* move pointer back to beginning of file */
rewind(f);
count = filesize;
p = memory;
while(count > 0) {
size_t actual;
actual = fread(p,1,count,f);
if(actual == 0 || ferror(f))
{status = NC_EIO; goto done;}
count -= actual;
p += actual;
}
NCbytes* buf = ncbytesnew();
if((status = NC_readfile(path,buf))) goto done;
if(memio) {
memio->size = (size_t)filesize;
memio->memory = memory;
memio->size = (size_t)ncbyteslength(buf);
memio->memory = ncbytesextract(buf);
}
done:
if(status != NC_NOERR && memory != NULL)
free(memory);
if(f != NULL) fclose(f);
ncbytesfree(buf);
return status;
}
static int
writefile(const char* path, NC_memio* memio)
{
int status = NC_NOERR;
FILE* f = NULL;
size_t count = 0;
char* p = NULL;
/* Open the file for writing */
#ifdef _WIN32
f = fopen(path,"wb");
#else
f = fopen(path,"w");
#endif
if(f == NULL)
{status = errno; goto done;}
count = memio->size;
p = memio->memory;
while(count > 0) {
size_t actual;
actual = fwrite(p,1,count,f);
if(actual == 0 || ferror(f))
{status = NC_EIO; goto done;}
count -= actual;
p += actual;
}
if((status = NC_writefile(path,memio->size,memio->memory))) goto done;
done:
if(f != NULL) fclose(f);
return status;
}
/* Duplicate an NC_memio instance; needed to avoid
attempting to use memory that might have been realloc'd
Allow the new memory to be larger than the src memory

View File

@ -43,7 +43,7 @@ main(int argc, char **argv)
for (i = DATA_LEN; i >= 0; i--)
{
/* Create a small file which is not a netCDF file. */
if (!(file = fopen(FILE_NAME, "w+"))) ERR;
if (!(file = NCfopen(FILE_NAME, "w+"))) ERR;
if (fwrite(dummy_data, 1, i, file) != i) ERR;
if (fclose(file)) ERR;

View File

@ -680,7 +680,7 @@ get_mem_used2(int *mem_used)
assert(mem_used);
snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
if ((pf = fopen(buf, "r")))
if ((pf = NCfopen(buf, "r")))
{
(void)fscanf(pf, "%u %u %u %u %u %u", &size, &resident, &share,
&text, &lib, &data);

View File

@ -325,7 +325,7 @@ main(int argc, char **argv)
int i;
/* Create a file with magic number at start. */
if (!(FP = fopen(FILE_NAME, "w"))) ERR;
if (!(FP = NCfopen(FILE_NAME, "w"))) ERR;
if (fwrite(magic_number, sizeof(char), strlen(magic_number), FP)
!= strlen(magic_number)) ERR;
if (fwrite(dummy_data, sizeof(char), strlen(dummy_data), FP)

View File

@ -150,7 +150,7 @@ testrc(const char* prefix, const char* url)
FILE* rc;
snprintf(rcpath,sizeof(rcpath),"%s/%s",prefix,RC);
rc = fopen(rcpath,"w");
rc = NCfopen(rcpath,"w");
if(rc == NULL) {
fprintf(stderr,"Cannot create ./%s\n",RC);
exit(1);
@ -178,7 +178,7 @@ fillrc(const char* path)
FILE* rc;
killrc();
rc = fopen(path,"w");
rc = NCfopen(path,"w");
if(rc == NULL) {
fprintf(stderr,"cannot create rc file: %s\n",path);
exit(1);

View File

@ -94,6 +94,7 @@ IF(MSVC)
setbinprops(ocprint)
ENDIF(ENABLE_DAP)
ENDIF()
IF(ENABLE_TESTS)
@ -281,14 +282,11 @@ endif()
ENDIF()
ENDIF(EXTRA_TESTS)
# The unicode tests are complicated
IF(USE_HDF5)
IF(NOT MSVC AND NOT MINGW)
# These tests do not work under windows
add_sh_test(ncdump test_unicode_directory)
add_sh_test(ncdump test_unicode_path)
ENDIF()
ENDIF(USE_HDF5)
# The unicode tests
if(NOT ISMINGW)
add_sh_test(ncdump test_unicode_directory)
add_sh_test(ncdump test_unicode_path)
ENDIF()
IF(USE_CDF5)
add_sh_test(ncdump test_keywords)

View File

@ -148,7 +148,6 @@ if !ISMINGW
if !ISCYGWIN
TESTS += tst_output.sh
TESTS += tst_nccopy3.sh
TESTS += test_unicode_directory.sh test_unicode_path.sh
if USE_HDF5
TESTS += run_back_comp_tests.sh tst_netcdf4_4.sh
TESTS += tst_nccopy4.sh tst_nccopy5.sh
@ -156,6 +155,11 @@ endif
endif
endif
# The unicode tests
if !ISMINGW
TESTS += test_unicode_directory.sh test_unicode_path.sh
endif
endif BUILD_TESTSETS
# These files all have to be included with the distribution.

30
ncdump/acpget.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <locale.h>
#include <windows.h>
int
main(int argc, char** argv)
{
int acp = -1;
const char* acpid = NULL;
const char* lcall = NULL;
const char* lcctype = NULL;
char digits[16];
switch (acp = GetACP()) {
case 1252: acpid = "CP_1252"; break;
case 65001: acpid = "CP_UTF8"; break;
default:
snprintf(digits,sizeof(digits),"%d",acp);
acpid = digits;
break;
}
lcall = setlocale(LC_ALL,NULL);
lcctype = setlocale(LC_CTYPE,NULL);
printf("ACP=%s locale: LC_ALL=%s LC_CTYPE=%s\n",acpid,lcall,lcctype);
return 0;
}

View File

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "nc_tests.h"
#define BUFLEN 100000
@ -19,7 +20,7 @@ main(int argc, char** argv)
FILE* input = stdin;
if(argc > 1) {
input = fopen(argv[1],"r");
input = NCfopen(argv[1],"r");
}
/* Read the whole file */

View File

@ -243,7 +243,7 @@ main(int argc, char **argv)
if(ocopt.output != NULL) fclose(ocopt.output);
if(optarg == NULL)
usage("-o does not specify a file name");
ocopt.output = fopen(optarg,"w");
ocopt.output = NCfopen(optarg,"w");
if(ocopt.output == NULL)
usage("-o file not writeable");
break;

10
ncdump/run_cygutf8.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash -x
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
. ../test_common.sh
echo "Test unicode paths"
${execdir}/acpget
${execdir}/tst_cygutf8
ls xutf8*
rm xutf8*

View File

@ -10,9 +10,6 @@ if test "x$srcdir" = x ; then srcdir=`pwd`; fi
set -e
LC_ALL="C.UTF-8"
export LC_ALL
# Passing a utf8 name using either \x or actual characters
# to Visual Studio does not work well.
if test "x$FP_ISMSVC" = x ; then

55
ncdump/tst_cygutf8.c Normal file
View File

@ -0,0 +1,55 @@
/*
https://www.cygwin.com/cygwin-ug-net/using-specialnames.html
https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/september/c-unicode-encoding-conversions-with-stl-strings-and-win32-apis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#endif
#include "netcdf.h"
#include "ncpathmgr.h"
static const unsigned char name1[] = {
'x','u','t','f','8','_',
'\xe6', '\xb5', '\xb7',
'\0'
};
static unsigned char name2[] = {
'x','u','t','f','8','_',
0xCE, 0x9A, /* GREEK CAPITAL LETTER KAPPA : 2-bytes utf8 */
0xCE, 0xB1, /* GREEK SMALL LETTER LAMBDA : 2-bytes utf8 */
0xCE, 0xBB, /* GREEK SMALL LETTER ALPHA : 2-bytes utf8 */
0xCE, 0xB7, /* GREEK SMALL LETTER ETA : 2-bytes utf8 */
0xCE, 0xBC, /* GREEK SMALL LETTER MU : 2-bytes utf8 */
0xCE, 0xAD, /* GREEK SMALL LETTER EPSILON WITH TONOS
: 2-bytes utf8 */
0xCF, 0x81, /* GREEK SMALL LETTER RHO : 2-bytes utf8 */
0xCE, 0xB1, /* GREEK SMALL LETTER ALPHA : 2-bytes utf8 */
0x00
};
static char* name3 = "xutf8_사람/접는사람";
/* This is CP_1252 */
//static char* name4 = "xutf8_Å";
static char name4[8] = {'x','u','t','f','8','_',0XC5,0x00} ;
int
main()
{
FILE* f;
f = NCfopen((char*)name1,"w");
if (f) fclose(f);
f = NCfopen((char*)name2,"w");
if (f) fclose(f);
f = NCfopen((char*)name3,"w");
if (f) fclose(f);
printf("|name4|=%u\n",(unsigned)strlen(name4));
f = NCfopen((char*)name4,"w");
if (f) fclose(f);
return 0;
}

View File

@ -5,9 +5,10 @@
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
. ../test_common.sh
set -e
echo "*** Testing ncgen3 for netCDF-4."
set -e
echo "*** creating netCDF-4 file c0_4.nc from c0.cdl..."
${NCGEN3} -k3 -b -o c0_4.nc ${ncgen3c0}
echo "*** creating netCDF-4 classic model file c0_4c.nc from c0.cdl..."

Binary file not shown.

View File

@ -73,11 +73,11 @@ case "$zext" in
# Move into position
rm -f ${execdir}/ref_zarr_test_data.cdl
# Use gunzip because it always appears to be available
if gunzip ${srcdir}/ref_zarr_test_data.cdl.gz ; then ignore=1; fi
if test -f ${srcdir}/ref_zarr_test_data.cdl ; then
testcases3 zarr_test_data.zarr ref_zarr_test_data xarray
fi
;;
if ! test -f ${srcdir}/ref_zarr_test_data.cdl ; then
gunzip -c ${srcdir}/ref_zarr_test_data.cdl.gz > ${srcdir}/ref_zarr_test_data.cdl
fi
testcases3 zarr_test_data.zarr ref_zarr_test_data xarray
;;
*) echo "unimplemented kind: $1" ; exit 1;;
esac
}

View File

@ -10,11 +10,13 @@ TOPSRCDIR='@abs_top_srcdir@'
TOPBUILDDIR='@abs_top_builddir@'
FP_ISCMAKE=@ISCMAKE@
FP_ISMSVC=@ISMSVC@
FP_WINVERMAJOR=@WINVERMAJOR@
FP_WINVERBUILD=@WINVERBUILD@
FP_ISCYGWIN=@ISCYGWIN@
FP_ISMINGW=@ISMINGW@
FP_ISMSYS=@ISMSYS@
FP_ISREGEDIT=@ISREGEDIT@
FP_USEPLUGINS=@USEPLUGINS@
FP_ISREGEDIT=@ISREGEDIT@
# Feature flags
FEATURE_HDF5=@HAS_HDF5@
@ -154,6 +156,7 @@ ncgenc04="${top_srcdir}/ncgen/c0_4.cdl"
avail() {
if test yes = `${execdir}/../ncdump/ncfilteravail $1` ; then return 0 ; else echo "filter $1 not available" ; return 1; fi
}
if test "x$FP_ISMSVC" = xyes || test "x$FP_ISCYGWIN" = xyes; then export LC_ALL="en_US.utf8"; fi
# Make sure we are in builddir (not execdir)
cd $builddir