[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: netcdf 3.1 build help



> Date:    Thu, 17 Oct 1996 18:12:13 -0400
> From:    Steve Simpson <address@hidden>
> To:      address@hidden
> Subject: netcdf 3.1 build help
>
> Could you release a copy of your msoft32.mak for the directory
> netcdf-3.1a/src/libsrc

I built this in "Microsoft Developer Studio".
The procedure I used was to

0) Create an appropriate libsrc/ncconfig.h for this system
        I'll attach the one I used. Also, I needed to modify the header portion
of posixio.c slightly in order to find read, write, and so on. This isn't in
the
general source release yet, so I will attach that as well.

1) Create a "Project Workspace" to build the library.
        In "Microsoft Developer Studio", select File:New:"Project Workspace",
in the resulting dialog, set the type to "Static Library". (Or DLL, if you
know how to link those. I don't.)

2) Select Insert:"Files Into Project" and pick up all the *.c files in libsrc
EXCEPT ffio.c ncio.c ncx_cray.c and t_*.c.

3) Build ...

I can send you the *.mak file that this produced, but I think it would cause
more frustration than good.


> The 3.1 zip file on the web does not include the files used to build
> the xdr library for C++ Win32.

That's because netcdf-3.1 doesn't use the XDR programming interface.
The file format still looks the same. We replaced calls to the XDR
library with our own interface, declared in ncx.h and defined in ncx.c
(ncx.m4).

> I'm having a heck of a time trying to build a version of netcdf in
> C++ (MSVC++ 4.2) for Win95/WinNT.  No matter what I've tried something
> doesn't build or link.  I've tried T. Hondo's library that was
> supposedly for Win32 but I could not get it to link.  I've tried to
> build the 2.4.3 version.  It will build but not link.
>
> I'm trying to compile the netcdf/xdr files for a Win32 MFC environment.
> Can you release the source that was used to build the nc31a.zip file?
>
> Any help would be appreciated.  Thanks.
>
> Steve Simpson

If what you need is the XDR lib, I'm probably not going to be able to help.
One reason we went to 'ncx' was to get out of the business of supporting XDR
on lots of platforms. If what you need is netcdf, then nc31a.zip should work
for you or I can help you figure out what you need to do to build from source.

-glenn



/* libsrc/ncconfig.h. Manually generated from
 * $Id: ncconfig.in,v 1.19 1996/08/15 21:12:08 davis Exp $
 * for WIN32 Build
 * -glenn
 */
#ifndef _NCCONFIG_H_
#define _NCCONFIG_H_

/* Define if type char is unsigned and you are not using gcc.  */
#ifndef __CHAR_UNSIGNED__
#undef __CHAR_UNSIGNED__
#endif

/* Define if your struct stat has st_blksize.  */
#undef HAVE_ST_BLKSIZE

/* Define to `long' if <sys/types.h> doesn't define.  */
/* #undef off_t */

/* Define to `unsigned' if <sys/types.h> doesn't define.  */
/* #undef size_t */

/* Define if you have the ANSI C header files.  */
#undef STDC_HEADERS

/* Define if your processor stores words with the most significant
   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
#undef WORDS_BIGENDIAN

/* Define if you don't have the <stdlib.h>.  */
#undef NO_STDLIB_H

/* Define if you don't have the <sys/types.h>.  */
#undef NO_SYS_TYPES_H

/* Define if you have the ftruncate function  */
#undef HAVE_FTRUNCATE

/* Define if you don't have the strerror function  */
#undef NO_STRERROR

/* The number of bytes in a size_t */
#define SIZEOF_SIZE_T 4

/* The number of bytes in a off_t */
#define SIZEOF_OFF_T 4

/* Define to `int' if system doesn't define.  */
/* #undef ssize_t */

/* Define to `int' if system doesn't define.  */
/* #undef ptrdiff_t */

/* Define to `unsigned char' if system doesn't define.  */
/* #undef uchar */
typedef unsigned char uchar;

/* Define if the system does not use IEEE floating point representation */
#undef NO_IEEE_FLOAT

/* The number of bytes in a double.  */
#define SIZEOF_DOUBLE 8

/* The number of bytes in a float.  */
#define SIZEOF_FLOAT 4

/* The number of bytes in a int.  */
#define SIZEOF_INT 4

/* The number of bytes in a long.  */
#define SIZEOF_LONG 4

/* The number of bytes in a short.  */
#define SIZEOF_SHORT 2

typedef int mode_t;
typedef int ssize_t;

#endif /* !_NCCONFIG_H_ */
/*
 *      Copyright 1996, University Corporation for Atmospheric Research
 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
 */
/* $Id: posixio.c,v 1.47 1996/10/10 19:48:50 davis Exp $ */

#include "ncconfig.h"
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#ifndef ENOERR
#define ENOERR 0
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#ifdef _MSC_VER /* Microsoft Compilers */
#include <io.h>
#else
#include <unistd.h>
#endif

#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif

#include "ncio.h"
#include "fbits.h"
#include "rnd.h"

#if !defined(NDEBUG) && !defined(X_INT_MAX)
#define  X_INT_MAX 2147483647
#endif
#if !defined(X_ALIGN)
#define  X_ALIGN 4
#endif

/*
 * Define the following for debugging.
 */
/* #define ALWAYS_NC_SHARE 1 */

/* Begin OS */

/*
 * What is the preferred I/O block size?
 */
static size_t
blksize(int fd)
{
#if defined(HAVE_ST_BLKSIZE)
        struct stat sb;
        if (fstat(fd, &sb) > -1)
        {
                return (size_t) sb.st_blksize;
        }
        /* else, silent in the face of error */
#endif
        return (size_t) 8192L;
}


/*
 * Sortof like ftruncate, except won't make the
 * file shorter.
 */
static int
fgrow(const int fd, const off_t len)
{
        struct stat sb;
        if (fstat(fd, &sb) < 0)
                return errno;
        if (len < sb.st_size)
                return ENOERR;
#if defined(HAVE_FTRUNCATE)
        if (ftruncate(fd, len) < 0)
                return errno;
#else
        {
                const long dumb = 0;
                        /* cache current position */
                const off_t pos = lseek(fd, 0, SEEK_CUR);
                if(pos < 0)
                        return errno;
                if (lseek(fd, len-sizeof(dumb), SEEK_SET) < 0)
                        return errno;
                if(write(fd, &dumb, sizeof(dumb)) < 0)
                        return errno;
                if (lseek(fd, pos, SEEK_SET) < 0)
                        return errno;
        }
#endif /* HAVE_FTRUNCATE */
        /* else */
        return ENOERR;
}

/* End OS */
/* Begin px */

static int
px_pgout(ncio *const nciop, 
        off_t const offset,  const size_t extent,
        void *const vp, off_t *posp)
{
        assert(offset % X_ALIGN == 0);

        if(*posp != offset)
        {
                if(lseek(nciop->fd, offset, SEEK_SET) != offset)
                {
                        return errno;
                }
                *posp = offset;
        }
        if(write(nciop->fd, vp, extent) != (ssize_t) extent)
        {
                return errno;
        }
        *posp += extent;

        return ENOERR;
}


static int
px_pgin(ncio *const nciop,
        off_t const offset, const size_t extent,
        void *const vp, size_t *nreadp, off_t *posp)
{
        int status;
        ssize_t nread;

        assert(offset % X_ALIGN == 0);
        assert(extent % X_ALIGN == 0);

        if(*posp != offset)
        {
                if(lseek(nciop->fd, offset, SEEK_SET) != offset)
                {
                        status = errno;
                        return status;
                }
                *posp = offset;
        }

        errno = 0;
        nread = read(nciop->fd, vp, extent);
        if(nread != (ssize_t) extent)
        {
                status = errno;
                if(nread == -1 || status != ENOERR)
                        return status;
                /* else it's okay we read 0. */
        }
        *nreadp = nread;
        *posp += nread;

        return ENOERR;
}


typedef struct ncio_px {
        size_t blksz;
        off_t pos;
        /* buffer */
        off_t   bf_offset; 
        size_t  bf_extent;
        size_t  bf_cnt;
        void    *bf_base;
        int     bf_rflags;
        int     bf_refcount;
} ncio_px;


/*ARGSUSED*/
static int
ncio_px_rel(ncio *const nciop, off_t offset, int rflags)
{
        ncio_px *pxp = (ncio_px *)nciop->pvt;
        int status = ENOERR;

        if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))
                return EPERM; /* attempt to write readonly file */

        assert(pxp->bf_offset <= offset
                 && offset < pxp->bf_offset + (off_t) pxp->bf_extent);
        assert(pIf(fIsSet(rflags, RGN_MODIFIED),
                fIsSet(pxp->bf_rflags, RGN_WRITE)));

        if(fIsSet(rflags, RGN_MODIFIED))
        {
                fSet(pxp->bf_rflags, RGN_MODIFIED);
        }
        pxp->bf_refcount--;

        return status;
}


static int
ncio_px_get(ncio *const nciop,
                off_t offset, size_t extent,
                int rflags,
                void **const vpp)
{
        ncio_px *pxp = (ncio_px *)nciop->pvt;
        off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);
        size_t diff = (size_t)(offset - blkoffset);
        size_t blkextent = _RNDUP(diff + extent, pxp->blksz);
        int status = ENOERR;
        
        if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
                return EPERM; /* attempt to write readonly file */
        assert(extent != 0);
        assert(extent < X_INT_MAX); /* sanity check */
        assert(offset < X_INT_MAX); /* sanity check */

        if(pxp->bf_offset != blkoffset ||
                pxp->bf_extent < blkextent)
        {
                if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
                {
                        assert(pxp->bf_refcount <= 0);
                        status = px_pgout(nciop, pxp->bf_offset,
                                pxp->bf_cnt,
                                pxp->bf_base, &pxp->pos);
                        if(status != ENOERR)
                                return status;
                        pxp->bf_rflags = 0;
                        pxp->bf_offset = OFF_NONE;
                }
                if(pxp->bf_extent < blkextent)
                {
                        if(pxp->bf_base != NULL)
                        {
                                free(pxp->bf_base);
                                pxp->bf_base = NULL;
                                pxp->bf_extent = 0;
                        }
                        assert(pxp->bf_extent == 0);
                        pxp->bf_base = malloc(blkextent);
                        if(pxp->bf_base == NULL)
                        {
                                status = errno;
                                return status;
                        }
                        pxp->bf_extent = blkextent;
                }

                status = px_pgin(nciop, blkoffset,
                         pxp->bf_extent,
                         pxp->bf_base,
                         &pxp->bf_cnt, &pxp->pos);
                if(status != ENOERR)
                        return status;
                 pxp->bf_offset = blkoffset;
        }

        extent += diff; 
        if(pxp->bf_cnt < extent)
        {
                (void) memset((char *)pxp->bf_base + pxp->bf_cnt, 0,
                        extent - pxp->bf_cnt);
                pxp->bf_cnt = extent;
        }

        pxp->bf_rflags |= rflags;
        pxp->bf_refcount++;

        *vpp = (char *)pxp->bf_base + diff;
        return ENOERR;
}


static int
ncio_px_move(ncio *const nciop, off_t to, off_t from,
                        size_t nbytes, int rflags)
{
        int status = ENOERR;
        off_t lower = from;     
        off_t upper = to;
        char *base;
        size_t diff = (size_t)(upper - lower);
        size_t extent = diff + nbytes;

        rflags &= RGN_NOLOCK; /* filter unwanted flags */

        if(to == from)
                return ENOERR; /* NOOP */
        
        if(to > from)
        {
                /* growing */
                lower = from;   
                upper = to;
        }
        else
        {
                /* shrinking */
                lower = to;
                upper = from;
        }

        diff = (size_t)(upper - lower);
        extent = diff + nbytes;

        status = ncio_px_get(nciop, lower, extent, RGN_WRITE|rflags,
                        (void **)&base);

        if(status != ENOERR)
                return status;

        if(to > from)
                (void) memmove(base + diff, base, nbytes); 
        else
                (void) memmove(base, base + diff, nbytes); 
                
        (void) ncio_px_rel(nciop, lower, RGN_MODIFIED);

        return status;
}


static int
ncio_px_sync(ncio *const nciop)
{
        ncio_px *pxp = (ncio_px *)nciop->pvt;
        int status = ENOERR;
        if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))
        {
                assert(pxp->bf_refcount <= 0);
                status = px_pgout(nciop, pxp->bf_offset,
                        pxp->bf_cnt,
                        pxp->bf_base, &pxp->pos);
                if(status != ENOERR)
                        return status;
                pxp->bf_rflags = 0;
        }
        pxp->bf_offset = OFF_NONE;
        return status;
}

static void
ncio_px_free(void *const pvt)
{
        ncio_px *pxp = (ncio_px *)pvt;
        if(pxp == NULL)
                return;

        if(pxp->bf_base != NULL)
        {
                free(pxp->bf_base);
                pxp->bf_base = NULL;
                pxp->bf_extent = 0;
                pxp->bf_offset = OFF_NONE;
        }
}


static int
ncio_px_init2(ncio *const nciop)
{
        ncio_px *pxp = (ncio_px *)nciop->pvt;

        assert(nciop->fd >= 0);

        pxp->blksz = blksize(nciop->fd);

        assert(pxp->bf_base == NULL);

        /* this is separate allocation because it may grow */
        pxp->bf_base = malloc(pxp->blksz);
        if(pxp->bf_base == NULL)
                return errno;
        /* else */
        pxp->bf_extent = pxp->blksz;
        return ENOERR;
}


static void
ncio_px_init(ncio *const nciop)
{
        ncio_px *pxp = (ncio_px *)nciop->pvt;

        *((ncio_relfunc **)&nciop->rel) = ncio_px_rel; /* cast away const */
        *((ncio_getfunc **)&nciop->get) = ncio_px_get; /* cast away const */
        *((ncio_movefunc **)&nciop->move) = ncio_px_move; /* cast away const */
        *((ncio_syncfunc **)&nciop->sync) = ncio_px_sync; /* cast away const */
        *((ncio_freefunc **)&nciop->free) = ncio_px_free; /* cast away const */

        pxp->blksz = 0;
        pxp->pos = -1;
        pxp->bf_offset = OFF_NONE;
        pxp->bf_extent = 0;
        pxp->bf_rflags = 0;
        pxp->bf_refcount = 0;
        pxp->bf_base = NULL;

}

/* Begin spx */

typedef struct ncio_spx {
        off_t pos;
        /* buffer */
        off_t   bf_offset; 
        size_t  bf_extent;
        size_t  bf_cnt;
        void    *bf_base;
} ncio_spx;


/*ARGSUSED*/
static int
ncio_spx_rel(ncio *const nciop, off_t offset, int rflags)
{
        ncio_spx *pxp = (ncio_spx *)nciop->pvt;
        int status = ENOERR;

        assert(pxp->bf_offset <= offset && offset < pxp->bf_offset + X_ALIGN);
        assert(pxp->bf_cnt != 0);
        assert(pxp->bf_cnt % X_ALIGN == 0 );
        assert(pxp->bf_cnt <= pxp->bf_extent);

        if(fIsSet(rflags, RGN_MODIFIED))
        {
                if(!fIsSet(nciop->ioflags, NC_WRITE))
                        return EPERM; /* attempt to write readonly file */

                status = px_pgout(nciop, pxp->bf_offset,
                        pxp->bf_cnt,
                        pxp->bf_base, &pxp->pos);
                /* if error, invalidate buffer anyway */
        }
        pxp->bf_offset = OFF_NONE;
        pxp->bf_cnt = 0;
        return status;
}


static int
ncio_spx_get(ncio *const nciop,
                off_t offset, size_t extent,
                int rflags,
                void **const vpp)
{
        ncio_spx *pxp = (ncio_spx *)nciop->pvt;
        int status = ENOERR;
        size_t rem;
        
        if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE))
                return EPERM; /* attempt to write readonly file */

        assert(extent != 0);
        assert(extent < X_INT_MAX); /* sanity check */
        assert(offset < X_INT_MAX); /* sanity check */

        assert(pxp->bf_cnt == 0);

        /* round to seekable boundaries */
        rem = (size_t)(offset % X_ALIGN);
        if(rem != 0)
        {
                offset -= rem;
                extent += rem;
        }

        {
                const size_t rndup = extent % X_ALIGN;
                if(rndup != 0)
                        extent += X_ALIGN - rndup;
        }

        assert(offset % X_ALIGN == 0);
        assert(extent % X_ALIGN == 0);

        if(pxp->bf_extent < extent)
        {
                if(pxp->bf_base != NULL)
                {
                        free(pxp->bf_base);
                        pxp->bf_base = NULL;
                        pxp->bf_extent = 0;
                }
                assert(pxp->bf_extent == 0);
                pxp->bf_base = malloc(extent);
                if(pxp->bf_base == NULL)
                {
                        status = errno;
                        return status;
                }
                pxp->bf_extent = extent;
        }

        status = px_pgin(nciop, offset,
                 extent,
                 pxp->bf_base,
                 &pxp->bf_cnt, &pxp->pos);
        if(status != ENOERR)
                return status;

        pxp->bf_offset = offset;

        if(pxp->bf_cnt < extent)
        {
                (void) memset((char *)pxp->bf_base + pxp->bf_cnt, 0,
                        extent - pxp->bf_cnt);
                pxp->bf_cnt = extent;
        }

        *vpp = (char *)pxp->bf_base + rem;
        return ENOERR;
}


static int
ncio_spx_move(ncio *const nciop, off_t to, off_t from,
                        size_t nbytes, int rflags)
{
        int status = ENOERR;
        off_t lower = from;     
        off_t upper = to;
        char *base;
        size_t diff = (size_t)(upper - lower);
        size_t extent = diff + nbytes;

        rflags &= RGN_NOLOCK; /* filter unwanted flags */

        if(to == from)
                return ENOERR; /* NOOP */
        
        if(to > from)
        {
                /* growing */
                lower = from;   
                upper = to;
        }
        else
        {
                /* shrinking */
                lower = to;
                upper = from;
        }

        diff = (size_t)(upper - lower);
        extent = diff + nbytes;

        status = ncio_spx_get(nciop, lower, extent, RGN_WRITE|rflags,
                        (void **)&base);

        if(status != ENOERR)
                return status;

        if(to > from)
                (void) memmove(base + diff, base, nbytes); 
        else
                (void) memmove(base, base + diff, nbytes); 
                
        (void) ncio_spx_rel(nciop, lower, RGN_MODIFIED);

        return status;
}


/*ARGSUSED*/
static int
ncio_spx_sync(ncio *const nciop)
{
        /* NOOP */
        return ENOERR;
}

static void
ncio_spx_free(void *const pvt)
{
        ncio_spx *pxp = (ncio_spx *)pvt;
        if(pxp == NULL)
                return;

        if(pxp->bf_base != NULL)
        {
                free(pxp->bf_base);
                pxp->bf_base = NULL;
                pxp->bf_offset = OFF_NONE;
                pxp->bf_extent = 0;
                pxp->bf_cnt = 0;
        }
}


static int
ncio_spx_init2(ncio *const nciop)
{
        ncio_spx *pxp = (ncio_spx *)nciop->pvt;

        assert(nciop->fd >= 0);

        pxp->bf_extent = blksize(nciop->fd);

        assert(pxp->bf_base == NULL);

        /* this is separate allocation because it may grow */
        pxp->bf_base = malloc(pxp->bf_extent);
        if(pxp->bf_base == NULL)
        {
                pxp->bf_extent = 0;
                return errno;
        }
        /* else */
        return ENOERR;
}


static void
ncio_spx_init(ncio *const nciop)
{
        ncio_spx *pxp = (ncio_spx *)nciop->pvt;

        *((ncio_relfunc **)&nciop->rel) = ncio_spx_rel; /* cast away const */
        *((ncio_getfunc **)&nciop->get) = ncio_spx_get; /* cast away const */
        *((ncio_movefunc **)&nciop->move) = ncio_spx_move; /* cast away const */
        *((ncio_syncfunc **)&nciop->sync) = ncio_spx_sync; /* cast away const */
        *((ncio_freefunc **)&nciop->free) = ncio_spx_free; /* cast away const */

        pxp->pos = -1;
        pxp->bf_offset = OFF_NONE;
        pxp->bf_extent = 0;
        pxp->bf_cnt = 0;
        pxp->bf_base = NULL;
}


/* */

static void
ncio_free(ncio *nciop)
{
        if(nciop == NULL)
                return;

        if(nciop->free != NULL)
                nciop->free(nciop->pvt);
        
        free(nciop);
}


static ncio *
ncio_new(const char *path, int ioflags)
{
        size_t sz_ncio = M_RNDUP(sizeof(ncio));
        size_t sz_path = M_RNDUP(strlen(path) +1);
        size_t sz_ncio_pvt;
        ncio *nciop;
 
#if ALWAYS_NC_SHARE /* DEBUG */
        fSet(ioflags, NC_SHARE);
#endif

        if(fIsSet(ioflags, NC_SHARE))
                sz_ncio_pvt = sizeof(ncio_spx);
        else
                sz_ncio_pvt = sizeof(ncio_px);

        nciop = (ncio *) malloc(sz_ncio + sz_path + sz_ncio_pvt);
        if(nciop == NULL)
                return NULL;
        
        nciop->ioflags = ioflags;
        *((int *)&nciop->fd) = -1; /* cast away const */

        nciop->path = (char *) ((char *)nciop + sz_ncio);
        (void) strcpy((char *)nciop->path, path); /* cast away const */

                                /* cast away const */
        *((void **)&nciop->pvt) = (void *)(nciop->path + sz_path);

        if(fIsSet(ioflags, NC_SHARE))
                ncio_spx_init(nciop);
        else
                ncio_px_init(nciop);

        return nciop;
}


/* Public below this point */

int
ncio_create(const char *path, mode_t mode, int ioflags,
        size_t align, size_t initialsz,
        off_t igeto, size_t igetsz,
        ncio **nciopp, void **const igetvpp)
{
        ncio *nciop;
        int oflags = (O_RDWR|O_CREAT|O_TRUNC);
        int fd;
        int status;

        if(initialsz < igetsz)
                initialsz = igetsz;

        fSet(ioflags, NC_WRITE);

        if(path == NULL || *path == 0)
                return EINVAL;

        nciop = ncio_new(path, ioflags);
        if(nciop == NULL)
                return errno;

        if(fIsSet(ioflags, NC_NOCLOBBER))
                fSet(oflags, O_EXCL);
#ifdef O_BINARY
        fSet(oflags, O_BINARY);
#endif
#ifdef vms
        fd = open(path, oflags, mode, "ctx=stm");
#else
        fd = open(path, oflags, mode);
#endif
#if 0
        (void) fprintf(stderr, "ncio_create(): path=\"%s\"\n", path);
        (void) fprintf(stderr, "ncio_create(): oflags=0x%x\n", oflags);
#endif
        if(fd < 0)
        {
                status = errno;
                goto unwind_new;
        }
        *((int *)&nciop->fd) = fd; /* cast away const */

        nciop->align = align;
        assert(nciop->align == X_ALIGN); /* Backward */
        

        if(fIsSet(nciop->ioflags, NC_SHARE))
                status = ncio_spx_init2(nciop);
        else
                status = ncio_px_init2(nciop);

        if(status != ENOERR)
                goto unwind_open;

        if(initialsz != 0)
        {
                status = fgrow(fd, (off_t)initialsz);
                if(status != ENOERR)
                        goto unwind_open;
        }

        if(igetsz != 0)
        {
                status = nciop->get(nciop,
                                igeto, igetsz,
                                RGN_WRITE,
                                igetvpp);
                if(status != ENOERR)
                        goto unwind_open;
        }

        *nciopp = nciop;
        return ENOERR;

unwind_open:
        (void) close(fd);
        /* ?? unlink */
        /*FALLTHRU*/
unwind_new:
        ncio_free(nciop);
        return status;
}


int
ncio_open(const char *path,
        int ioflags,
        off_t igeto, size_t igetsz,
        ncio **nciopp, void **const igetvpp)
{
        ncio *nciop;
        int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY;
        int fd;
        int status;

        if(path == NULL || *path == 0)
                return EINVAL;

        nciop = ncio_new(path, ioflags);
        if(nciop == NULL)
                return errno;

#ifdef O_BINARY
        fSet(oflags, O_BINARY);
#endif
#ifdef vms
        fd = open(path, oflags, 0, "ctx=stm");
#else
        fd = open(path, oflags, 0);
#endif
        if(fd < 0)
        {
                status = errno;
                goto unwind_new;
        }
        *((int *)&nciop->fd) = fd; /* cast away const */
        nciop->align = 4; /* Backward: X_ALIGN */

        if(fIsSet(nciop->ioflags, NC_SHARE))
                status = ncio_spx_init2(nciop);
        else
                status = ncio_px_init2(nciop);

        if(status != ENOERR)
                goto unwind_open;

        if(igetsz != 0)
        {
                status = nciop->get(nciop,
                                igeto, igetsz,
                                0,
                                igetvpp);
                if(status != ENOERR)
                        goto unwind_open;
        }

        *nciopp = nciop;
        return ENOERR;

unwind_open:
        (void) close(fd);
        /*FALLTHRU*/
unwind_new:
        ncio_free(nciop);
        return status;
}


int 
ncio_close(ncio *nciop, int doUnlink)
{
        int status = ENOERR;

        if(nciop == NULL)
                return EINVAL;

        status = nciop->sync(nciop);

        (void) close(nciop->fd);
        
        if(doUnlink)
                (void) unlink(nciop->path);

        ncio_free(nciop);

        return status;
}