1/** \file dfile.c
2
3File create and open functions
4
5These functions end up calling functions in one of the dispatch layers
6(netCDF-4, dap server, etc).
7
8Copyright 2010 University Corporation for Atmospheric
9Research/Unidata. See COPYRIGHT file for more info.
10*/
11
12#include "config.h"
13#include <stdlib.h>
14#ifdef HAVE_SYS_RESOURCE_H
15#include <sys/resource.h>
16#endif
17#ifdef HAVE_SYS_TYPES_H
18#include <sys/types.h>
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
26#include "ncdispatch.h"
27
28extern int NC_initialized;
29extern int NC_finalized;
30
31
32/** \defgroup datasets NetCDF File and Data I/O
33
34NetCDF opens datasets as files or remote access URLs.
35
36A netCDF dataset that has not yet been opened can only be referred to
37by its dataset name. Once a netCDF dataset is opened, it is referred
38to by a netCDF ID, which is a small non-negative integer returned when
39you create or open the dataset. A netCDF ID is much like a file
40descriptor in C or a logical unit number in FORTRAN. In any single
41program, the netCDF IDs of distinct open netCDF datasets are
42distinct. A single netCDF dataset may be opened multiple times and
43will then have multiple distinct netCDF IDs; however at most one of
44the open instances of a single netCDF dataset should permit
45writing. When an open netCDF dataset is closed, the ID is no longer
46associated with a netCDF dataset.
47
48Functions that deal with the netCDF library include:
49- Get version of library.
50- Get error message corresponding to a returned error code.
51
52The operations supported on a netCDF dataset as a single object are:
53- Create, given dataset name and whether to overwrite or not.
54- Open for access, given dataset name and read or write intent.
55- Put into define mode, to add dimensions, variables, or attributes.
56- Take out of define mode, checking consistency of additions.
57- Close, writing to disk if required.
58- Inquire about the number of dimensions, number of variables,
59number of global attributes, and ID of the unlimited dimension, if
60any.
61- Synchronize to disk to make sure it is current.
62- Set and unset nofill mode for optimized sequential writes.
63- After a summary of conventions used in describing the netCDF
64interfaces, the rest of this chapter presents a detailed description
65of the interfaces for these operations.
66*/
67
68
69/*!
70  Interpret the magic number found in the header of a netCDF file.
71
72  This function interprets the magic number/string contained in the header of a netCDF file and sets the appropriate NC_FORMATX flags.
73
74  @param[in] magic Pointer to a character array with the magic number block.
75  @param[out] model Pointer to an integer to hold the corresponding netCDF type.
76  @param[out] version Pointer to an integer to hold the corresponding netCDF version.
77  @param[in] use_parallel 1 if using parallel, 0 if not.
78  @return Returns an error code or 0 on success.
79
80\internal
81\ingroup datasets
82
83*/
84static int
85NC_interpret_magic_number(char* magic, int* model, int* version, int use_parallel)
86{
87    int status = NC_NOERR;
88    /* Look at the magic number */
89    /* Ignore the first byte for HDF */
90#ifdef USE_NETCDF4
91    if(magic[1] == 'H' && magic[2] == 'D' && magic[3] == 'F') {
92 *model = NC_FORMATX_NC4;
93 *version = 5;
94#ifdef USE_HDF4
95    } else if(magic[0] == '\016' && magic[1] == '\003'
96              && magic[2] == '\023' && magic[3] == '\001') {
97 *model = NC_FORMATX_NC4;
98 *version = 4;
99#endif
100    } else
101#endif
102    if(magic[0] == 'C' && magic[1] == 'D' && magic[2] == 'F') {
103        if(magic[3] == '\001') {
104            *version = 1; /* netcdf classic version 1 */
105     *model = NC_FORMATX_NC3;
106         } else if(magic[3] == '\002') {
107            *version = 2; /* netcdf classic version 2 */
108     *model = NC_FORMATX_NC3;
109         } else if(magic[3] == '\005') {
110            *version = 5; /* cdf5 (including pnetcdf) file */
111     *model = NC_FORMATX_NC3;
112  } else
113     {status = NC_ENOTNC; goto done;}
114     } else
115        {status = NC_ENOTNC; goto done;}
116done:
117     return status;
118}
119
120/*!
121Given an existing file, figure out its format
122and return that format value (NC_FORMATX_XXX)
123in model arg.
124*/
125static int NC_check_file_type(const char *path, int flags, void *parameters,
126    int* model, int* version)
127{
128   char magic[MAGIC_NUMBER_LEN];
129   int status = NC_NOERR;
130   int diskless = ((flags & NC_DISKLESS) == NC_DISKLESS);
131   int use_parallel = ((flags & NC_MPIIO) == NC_MPIIO);
132   int inmemory = (diskless && ((flags & NC_INMEMORY) == NC_INMEMORY));
133
134   *model = 0;
135
136    if(inmemory)  {
137 NC_MEM_INFOmeminfo = (NC_MEM_INFO*)parameters;
138 if(meminfo == NULL || meminfo->size < MAGIC_NUMBER_LEN)
139     {status = NC_EDISKLESS; goto done;}
140 memcpy(magic,meminfo->memory,MAGIC_NUMBER_LEN);
141    } else {/* presumably a real file */
142       /* Get the 4-byte magic from the beginning of the file. Don't use posix
143        * for parallel, use the MPI functions instead. */
144#ifdef USE_PARALLEL
145 if (use_parallel) {
146     MPI_File fh;
147     MPI_Status mstatus;
148     int retval;
149     MPI_Comm comm = MPI_COMM_WORLD;
150     MPI_Info info = MPI_INFO_NULL;
151
152     if(parameters != NULL) {
153         comm = ((NC_MPI_INFO*)parameters)->comm;
154 info = ((NC_MPI_INFO*)parameters)->info;
155     }
156     if((retval = MPI_File_open(comm,(char*)path,MPI_MODE_RDONLY,info,
157        &fh)) != MPI_SUCCESS)
158 {status = NC_EPARINIT; goto done;}
159     if((retval = MPI_File_read(fhmagicMAGIC_NUMBER_LENMPI_CHAR,
160  &mstatus)) != MPI_SUCCESS)
161 {status = NC_EPARINIT; goto done;}
162     if((retval = MPI_File_close(&fh)) != MPI_SUCCESS)
163 {status = NC_EPARINIT; goto done;}
164 } else
165#endif /* USE_PARALLEL */
166 {
167     FILE *fp;
168     size_t i;
169#ifdef HAVE_SYS_STAT_H
170     struct stat st;
171#endif
172     if(path == NULL || strlen(path)==0)
173 {status = NC_EINVAL; goto done;}
174
175     if (!(fp = fopen(path, "r")))
176 {status = errno; goto done;}
177
178#ifdef HAVE_SYS_STAT_H
179     /* The file must be at least MAGIC_NUMBER_LEN in size,
180        or otherwise the following fread will exhibit unexpected
181          behavior. */
182
183        /* Windows and fstat have some issues, this will work around that. */
184#ifdef HAVE_FILE_LENGTH_I64
185        __int64 file_len = 0;
186        if((file_len = _filelengthi64(fileno(fp))) < 0) {
187          fclose(fp);
188          status = errno;
189          goto done;
190        }
191
192        if(file_len < MAGIC_NUMBER_LEN) {
193          fclose(fp);
194          status = NC_ENOTNC;
195          goto done;
196        }
197#else
198
199     if(!(fstat(fileno(fp),&st) == 0)) {
200         fclose(fp);
201         status = errno;
202         goto done;
203     }
204
205     if(st.st_size < MAGIC_NUMBER_LEN) {
206          fclose(fp);
207          status = NC_ENOTNC;
208          goto done;
209     }
210#endif //HAVE_FILE_LENGTH_I64
211
212#endif
213
214     i = fread(magicMAGIC_NUMBER_LEN, 1, fp);
215     fclose(fp);
216     if(i == 0)
217 {status = NC_ENOTNC; goto done;}
218     if(i != 1)
219 {status = errno; goto done;}
220 }
221    } /* !inmemory */
222
223    /* Look at the magic number */
224    status = NC_interpret_magic_number(magic,model,version,use_parallel);
225
226done:
227   return status;
228}
229
230/**  \ingroup datasets
231Create a new netCDF file.
232
233This function creates a new netCDF dataset, returning a netCDF ID that
234can subsequently be used to refer to the netCDF dataset in other
235netCDF function calls. The new netCDF dataset opened for write access
236and placed in define mode, ready for you to add dimensions, variables,
237and attributes.
238
239\param path The file name of the new netCDF dataset.
240
241\param cmode The creation mode flag. The following flags are available:
242  NC_NOCLOBBER (do not overwrite existing file),
243  NC_SHARE (limit write caching - netcdf classic files only),
244  NC_64BIT_OFFSET (create 64-bit offset file),
245  NC_64BIT_DATA (Alias NC_CDF5) (create CDF-5 file),
246  NC_NETCDF4 (create netCDF-4/HDF5 file),
247  NC_CLASSIC_MODEL (enforce netCDF classic mode on netCDF-4/HDF5 files),
248  NC_DISKLESS (store data only in memory),
249  NC_MMAP (use MMAP for NC_DISKLESS),
250  and NC_WRITE.
251  See discussion below.
252
253\param ncidp Pointer to location where returned netCDF ID is to be
254stored.
255
256<h2>The cmode Flag</h2>
257
258The cmode flag is used to control the type of file created, and some
259aspects of how it may be used.
260
261Setting NC_NOCLOBBER means you do not want to clobber (overwrite) an
262existing dataset; an error (NC_EEXIST) is returned if the specified
263dataset already exists.
264
265The NC_SHARE flag is appropriate when one process may be writing the
266dataset and one or more other processes reading the dataset
267concurrently; it means that dataset accesses are not buffered and
268caching is limited. Since the buffering scheme is optimized for
269sequential access, programs that do not access data sequentially may
270see some performance improvement by setting the NC_SHARE flag. This
271flag is ignored for netCDF-4 files.
272
273Setting NC_64BIT_OFFSET causes netCDF to create a 64-bit offset format
274file, instead of a netCDF classic format file. The 64-bit offset
275format imposes far fewer restrictions on very large (i.e. over 2 GB)
276data files. See Large File Support.
277
278Setting NC_64BIT_DATA (Alias NC_CDF5) causes netCDF to create a CDF-5
279file format that supports large files (i.e. over 2GB) and large
280variables (over 2B array elements.). See Large File Support.
281
282Note that the flag NC_PNETCDF also exists as the combination of
283NC_CDF5 or'd with NC_MPIIO to indicate that the pnetcdf library
284should be used.
285
286A zero value (defined for convenience as NC_CLOBBER) specifies the
287default behavior: overwrite any existing dataset with the same file
288name and buffer and cache accesses for efficiency. The dataset will be
289in netCDF classic format. See NetCDF Classic Format Limitations.
290
291Setting NC_NETCDF4 causes netCDF to create a HDF5/NetCDF-4 file.
292
293Setting NC_CLASSIC_MODEL causes netCDF to enforce the classic data
294model in this file. (This only has effect for netCDF-4/HDF5 files, as
295classic and 64-bit offset files always use the classic model.) When
296used with NC_NETCDF4, this flag ensures that the resulting
297netCDF-4/HDF5 file may never contain any new constructs from the
298enhanced data model. That is, it cannot contain groups, user defined
299types, multiple unlimited dimensions, or new atomic types. The
300advantage of this restriction is that such files are guaranteed to
301work with existing netCDF software.
302
303Setting NC_DISKLESS causes netCDF to create the file only in memory.
304This allows for the use of files that have no long term purpose. Note that
305with one exception, the in-memory file is destroyed upon calling
306nc_close. If, however, the flag combination (NC_DISKLESS|NC_WRITE)
307is used, then at close, the contents of the memory file will be
308made persistent in the file path that was specified in the nc_create
309call. If NC_DISKLESS is going to be used for creating a large classic file,
310it behooves one to use either nc__create or nc_create_mp and specify
311an appropriately large value of the initialsz parameter to avoid
312to many extensions to the in-memory space for the file.
313This flag applies to files in classic format and to file in extended
314format (netcdf-4).
315
316Normally, NC_DISKLESS allocates space in the heap for
317storing the in-memory file. If, however, the ./configure
318flags --enable-mmap is used, and the additional mode flag
319NC_MMAP is specified, then the file will be created using
320the operating system MMAP facility.
321This flag only applies to files in classic format. Extended
322format (netcdf-4) files will ignore the NC_MMAP flag.
323
324Using NC_MMAP for nc_create is
325only included for completeness vis-a-vis nc_open. The
326ability to use MMAP is of limited use for nc_create because
327nc_create is going to create the file in memory anyway.
328Closing a MMAP'd file will be slightly faster, but not significantly.
329
330Note that nc_create(path,cmode,ncidp) is equivalent to the invocation of
331nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp).
332
333\returns ::NC_NOERR No error.
334
335\returns ::NC_ENOMEM System out of memory.
336
337\returns ::NC_EHDFERR HDF5 error (netCDF-4 files only).
338
339\returns ::NC_EFILEMETA Error writing netCDF-4 file-level metadata in
340HDF5 file. (netCDF-4 files only).
341
342\returns ::NC_EDISKLESS if there was an error in creating the
343in-memory file.
344
345\note When creating a netCDF-4 file HDF5 error reporting is turned
346off, if it is on. This doesn't stop the HDF5 error stack from
347recording the errors, it simply stops their display to the user
348through stderr.
349
350<h1>Examples</h1>
351
352In this example we create a netCDF dataset named foo.nc; we want the
353dataset to be created in the current directory only if a dataset with
354that name does not already exist:
355
356@code
357     #include <netcdf.h>
358        ...
359     int status = NC_NOERR;
360     int ncid;
361        ...
362     status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
363     if (status != NC_NOERR) handle_error(status);
364@endcode
365
366In this example we create a netCDF dataset named foo_large.nc. It will
367be in the 64-bit offset format.
368
369@code
370     #include <netcdf.h>
371        ...
372     int status = NC_NOERR;
373     int ncid;
374        ...
375     status = nc_create("foo_large.nc", NC_NOCLOBBER|NC_64BIT_OFFSET, &ncid);
376     if (status != NC_NOERR) handle_error(status);
377@endcode
378
379In this example we create a netCDF dataset named foo_HDF5.nc. It will
380be in the HDF5 format.
381
382@code
383     #include <netcdf.h>
384        ...
385     int status = NC_NOERR;
386     int ncid;
387        ...
388     status = nc_create("foo_HDF5.nc", NC_NOCLOBBER|NC_NETCDF4, &ncid);
389     if (status != NC_NOERR) handle_error(status);
390@endcode
391
392In this example we create a netCDF dataset named
393foo_HDF5_classic.nc. It will be in the HDF5 format, but will not allow
394the use of any netCDF-4 advanced features. That is, it will conform to
395the classic netCDF-3 data model.
396
397@code
398     #include <netcdf.h>
399        ...
400     int status = NC_NOERR;
401     int ncid;
402        ...
403     status = nc_create("foo_HDF5_classic.nc", NC_NOCLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL, &ncid);
404     if (status != NC_NOERR) handle_error(status);
405@endcode
406
407In this example we create a in-memory netCDF classic dataset named
408diskless.nc whose content will be lost when nc_close() is called.
409
410@code
411     #include <netcdf.h>
412        ...
413     int status = NC_NOERR;
414     int ncid;
415        ...
416     status = nc_create("diskless.nc", NC_DISKLESS, &ncid);
417     if (status != NC_NOERR) handle_error(status);
418@endcode
419
420In this example we create a in-memory netCDF classic dataset named
421diskless.nc and specify that it should be made persistent
422in a file named diskless.nc when nc_close() is called.
423
424@code
425     #include <netcdf.h>
426        ...
427     int status = NC_NOERR;
428     int ncid;
429        ...
430     status = nc_create("diskless.nc", NC_DISKLESS|NC_WRITE, &ncid);
431     if (status != NC_NOERR) handle_error(status);
432@endcode
433
434A variant of nc_create(), nc__create() (note the double underscore) allows
435users to specify two tuning parameters for the file that it is
436creating.  */
437int
438nc_create(const char *path, int cmode, int *ncidp)
439{
440   return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp);
441}
442
443/*!
444Create a netCDF file with some extra parameters controlling classic
445file cacheing.
446
447Like nc_create(), this function creates a netCDF file.
448
449\param path The file name of the new netCDF dataset.
450
451\param cmode The creation mode flag, the same as in nc_create().
452
453\param initialsz On some systems, and with custom I/O layers, it may
454be advantageous to set the size of the output file at creation
455time. This parameter sets the initial size of the file at creation
456time. This only applies to classic and 64-bit offset files.
457The special value NC_SIZEHINT_DEFAULT (which is the value 0),
458lets the netcdf library choose a suitable initial size.
459
460\param chunksizehintp A pointer to the chunk size hint,
461which controls a space versus time tradeoff, memory
462allocated in the netcdf library versus number of system
463calls. Because of internal requirements, the value may not
464be set to exactly the value requested. The actual value
465chosen is returned by reference. Using a NULL pointer or
466having the pointer point to the value NC_SIZEHINT_DEFAULT
467causes the library to choose a default. How the system
468chooses the default depends on the system. On many systems,
469the "preferred I/O block size" is available from the stat()
470system call, struct stat member st_blksize. If this is
471available it is used. Lacking that, twice the system
472pagesize is used. Lacking a call to discover the system
473pagesize, we just set default bufrsize to 8192. The bufrsize
474is a property of a given open netcdf descriptor ncid, it is
475not a persistent property of the netcdf dataset. This only
476applies to classic and 64-bit offset files.
477
478\param ncidp Pointer to location where returned netCDF ID is to be
479stored.
480
481\note This function uses the same return codes as the nc_create()
482function.
483
484<h1>Examples</h1>
485
486In this example we create a netCDF dataset named foo_large.nc; we want
487the dataset to be created in the current directory only if a dataset
488with that name does not already exist. We also specify that bufrsize
489and initial size for the file.
490
491\code
492#include <netcdf.h>
493        ...
494     int status = NC_NOERR;
495     int ncid;
496     int intialsz = 2048;
497     int *bufrsize;
498        ...
499     *bufrsize = 1024;
500     status = nc__create("foo.nc", NC_NOCLOBBER, initialsz, bufrsize, &ncid);
501     if (status != NC_NOERR) handle_error(status);
502\endcode
503
504\ingroup datasets
505
506*/
507int
508nc__create(const char *path, int cmode, size_t initialsz,
509    size_t *chunksizehintp, int *ncidp)
510{
511   return NC_create(pathcmodeinitialsz, 0,
512     chunksizehintp, 0, NULLncidp);
513
514}
515/**
516\internal
517
518\deprecated This function was used in the old days with the Cray at
519NCAR. The Cray is long gone, and this call is supported only for
520backward compatibility.
521
522 */
523int
524nc__create_mp(const char *path, int cmode, size_t initialsz,
525       int basepe, size_t *chunksizehintp, int *ncidp)
526{
527   return NC_create(pathcmodeinitialszbasepe,
528     chunksizehintp, 0, NULLncidp);
529}
530
531/** \ingroup datasets
532Open an existing netCDF file.
533
534This function opens an existing netCDF dataset for access. It
535determines the underlying file format automatically. Use the same call
536to open a netCDF classic, 64-bit offset, or netCDF-4 file.
537
538\param path File name for netCDF dataset to be opened. When DAP
539support is enabled, then the path may be an OPeNDAP URL rather than a
540file path.
541
542\param mode The mode flag may include NC_WRITE (for read/write
543access) and NC_SHARE (see below) and NC_DISKLESS (see below).
544
545\param ncidp Pointer to location where returned netCDF ID is to be
546stored.
547
548<h2>Open Mode</h2>
549
550A zero value (or ::NC_NOWRITE) specifies the default behavior: open the
551dataset with read-only access, buffering and caching accesses for
552efficiency.
553
554Otherwise, the open mode is ::NC_WRITE, ::NC_SHARE, or
555::NC_WRITE|::NC_SHARE. Setting the ::NC_WRITE flag opens the dataset with
556read-write access. ("Writing" means any kind of change to the dataset,
557including appending or changing data, adding or renaming dimensions,
558variables, and attributes, or deleting attributes.)
559
560The NC_SHARE flag is only used for netCDF classic and 64-bit offset
561files. It is appropriate when one process may be writing the dataset
562and one or more other processes reading the dataset concurrently; it
563means that dataset accesses are not buffered and caching is
564limited. Since the buffering scheme is optimized for sequential
565access, programs that do not access data sequentially may see some
566performance improvement by setting the NC_SHARE flag.
567
568This procedure may also be invoked with the NC_DISKLESS flag
569set in the mode argument if the file to be opened is a
570classic format file.  For nc_open(), this flag applies only
571to files in classic format.  If the file is of type
572NC_NETCDF4, then the NC_DISKLESS flag will be ignored.
573
574If NC_DISKLESS is specified, then the whole file is read completely into
575memory. In effect this creates an in-memory cache of the file.
576If the mode flag also specifies NC_WRITE, then the in-memory cache
577will be re-written to the disk file when nc_close() is called.
578For some kinds of manipulations, having the in-memory cache can
579speed up file processing. But in simple cases, non-cached
580processing may actually be faster than using cached processing.
581You will need to experiment to determine if the in-memory caching
582is worthwhile for your application.
583
584Normally, NC_DISKLESS allocates space in the heap for
585storing the in-memory file. If, however, the ./configure
586flags --enable-mmap is used, and the additional mode flag
587NC_MMAP is specified, then the file will be opened using
588the operating system MMAP facility.
589This flag only applies to files in classic format. Extended
590format (netcdf-4) files will ignore the NC_MMAP flag.
591
592In most cases, using MMAP provides no advantage
593for just NC_DISKLESS. The one case where using MMAP is an
594advantage is when a file is to be opened and only a small portion
595of its data is to be read and/or written.
596In this scenario, MMAP will cause only the accessed data to be
597retrieved from disk. Without MMAP, NC_DISKLESS will read the whole
598file into memory on nc_open. Thus, MMAP will provide some performance
599improvement in this case.
600
601It is not necessary to pass any information about the format of the
602file being opened. The file type will be detected automatically by the
603netCDF library.
604
605If a the path is a DAP URL, then the open mode is read-only.
606Setting NC_WRITE will be ignored.
607
608As of version 4.3.1.2, multiple calls to nc_open with the same
609path will return the same ncid value.
610
611\note When opening a netCDF-4 file HDF5 error reporting is turned off,
612if it is on. This doesn't stop the HDF5 error stack from recording the
613errors, it simply stops their display to the user through stderr.
614
615nc_open()returns the value NC_NOERR if no errors occurred. Otherwise,
616the returned status indicates an error. Possible causes of errors
617include:
618
619Note that nc_open(path,cmode,ncidp) is equivalent to the invocation of
620nc__open(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp).
621
622\returns ::NC_NOERR No error.
623
624\returns ::NC_ENOMEM Out of memory.
625
626\returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.)
627
628\returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4 files only.)
629
630<h1>Examples</h1>
631
632Here is an example using nc_open()to open an existing netCDF dataset
633named foo.nc for read-only, non-shared access:
634
635@code
636#include <netcdf.h>
637   ...
638int status = NC_NOERR;
639int ncid;
640   ...
641status = nc_open("foo.nc", 0, &ncid);
642if (status != NC_NOERR) handle_error(status);
643@endcode
644*/
645int
646nc_open(const char *path, int mode, int *ncidp)
647{
648   return NC_open(pathmode, 0, NULL, 0, NULLncidp);
649}
650
651/** \ingroup datasets
652Open a netCDF file with extra performance parameters for the classic
653library.
654
655\param path File name for netCDF dataset to be opened. When DAP
656support is enabled, then the path may be an OPeNDAP URL rather than a
657file path.
658
659\param mode The mode flag may include NC_WRITE (for read/write
660access) and NC_SHARE as in nc_open().
661
662\param chunksizehintp A size hint for the classic library. Only
663applies to classic and 64-bit offset files. See below for more
664information.
665
666\param ncidp Pointer to location where returned netCDF ID is to be
667stored.
668
669<h1>The chunksizehintp Parameter</h1>
670
671The argument referenced by bufrsizehintp controls a space versus time
672tradeoff, memory allocated in the netcdf library versus number of
673system calls.
674
675Because of internal requirements, the value may not be set to exactly
676the value requested. The actual value chosen is returned by reference.
677
678Using a NULL pointer or having the pointer point to the value
679NC_SIZEHINT_DEFAULT causes the library to choose a default.
680How the system chooses the default depends on the system. On
681many systems, the "preferred I/O block size" is available from the
682stat() system call, struct stat member st_blksize. If this is
683available it is used. Lacking that, twice the system pagesize is used.
684
685Lacking a call to discover the system pagesize, we just set default
686bufrsize to 8192.
687
688The bufrsize is a property of a given open netcdf descriptor ncid, it
689is not a persistent property of the netcdf dataset.
690
691
692\returns ::NC_NOERR No error.
693
694\returns ::NC_ENOMEM Out of memory.
695
696\returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.)
697
698\returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4
699files only.)
700
701*/
702int
703nc__open(const char *path, int mode,
704  size_t *chunksizehintp, int *ncidp)
705{
706   /* this API is for non-parallel access: TODO check for illegal cmode
707    * flags, such as NC_PNETCDF, NC_MPIIO, or NC_MPIPOSIX, before entering
708    * NC_open()? Note nc_open_par() also calls NC_open().
709    */
710   return NC_open(pathmode, 0, chunksizehintp, 0,
711   NULLncidp);
712}
713
714/** \ingroup datasets
715Open a netCDF file with the contents taken from a block of memory.
716
717\param path Must be non-null, but otherwise only used to set the dataset name.
718
719\param mode the mode flags; Note that this procedure uses a limited set of flags because it forcibly sets NC_NOWRITE|NC_DISKLESS|NC_INMEMORY.
720
721\param size The length of the block of memory being passed.
722
723\param memory Pointer to the block of memory containing the contents
724of a netcdf file.
725
726\param ncidp Pointer to location where returned netCDF ID is to be
727stored.
728
729\returns ::NC_NOERR No error.
730
731\returns ::NC_ENOMEM Out of memory.
732
733\returns ::NC_EDISKLESS diskless io is not enabled for fails.
734
735\returns ::NC_EINVAL, etc. other errors also returned by nc_open.
736
737<h1>Examples</h1>
738
739Here is an example using nc_open_mem() to open an existing netCDF dataset
740named foo.nc for read-only, non-shared access. It differs from the nc_open()
741example in that it assumes the contents of foo.nc have been read into memory.
742
743@code
744#include <netcdf.h>
745#include <netcdf_mem.h>
746   ...
747int status = NC_NOERR;
748int ncid;
749size_t size;
750void* memory;
751   ...
752size = <compute file size of foo.nc in bytes>;
753memory = malloc(size);
754   ...
755status = nc_open_mem("foo.nc", 0, size, memory, &ncid);
756if (status != NC_NOERR) handle_error(status);
757@endcode
758*/
759int
760nc_open_mem(const char* path, int mode, size_t size, void* memory, int* ncidp)
761{
762#ifdef USE_DISKLESS
763    NC_MEM_INFO meminfo;
764
765    /* Sanity checks */
766    if(memory == NULL || size < MAGIC_NUMBER_LEN || path == NULL)
767  return NC_EINVAL;
768    if(mode & (NC_WRITE|NC_MPIIO|NC_MPIPOSIX|NC_MMAP))
769 return NC_EINVAL;
770    mode |= (NC_INMEMORY|NC_DISKLESS);
771    meminfo.size = size;
772    meminfo.memory = memory;
773    return NC_open(pathmode, 0, NULL, 0, &meminfoncidp);
774#else
775    return NC_EDISKLESS;
776#endif
777}
778
779/**
780\internal
781
782\deprecated This function was used in the old days with the Cray at
783NCAR. The Cray is long gone, and this call is supported only for
784backward compatibility.
785
786 */
787int
788nc__open_mp(const char *path, int mode, int basepe,
789     size_t *chunksizehintp, int *ncidp)
790{
791   return NC_open(pathmodebasepechunksizehintp,
792   0, NULLncidp);
793}
794
795/** \ingroup datasets
796Get the file pathname (or the opendap URL) which was used to
797open/create the ncid's file.
798
799\param ncid NetCDF ID, from a previous call to nc_open() or
800nc_create().
801
802\param pathlen Pointer where length of path will be returned. Ignored
803if NULL.
804
805\param path Pointer where path name will be copied. Space must already
806be allocated. Ignored if NULL.
807
808\returns ::NC_NOERR No error.
809
810\returns ::NC_EBADID Invalid ncid passed.
811*/
812int
813nc_inq_path(int ncid, size_t *pathlen, char *path)
814{
815   NCncp;
816   int stat = NC_NOERR;
817   if ((stat = NC_check_id(ncid, &ncp)))
818      return stat;
819   if(ncp->path == NULL) {
820 if(pathlen) *pathlen = 0;
821 if(pathpath[0] = '\0';
822   } else {
823       if (pathlen) *pathlen = strlen(ncp->path);
824       if (pathstrcpy(pathncp->path);
825   }
826   return stat;
827}
828
829/** \ingroup datasets
830Put open netcdf dataset into define mode
831
832The function nc_redef puts an open netCDF dataset into define mode, so
833dimensions, variables, and attributes can be added or renamed and
834attributes can be deleted.
835
836For netCDF-4 files (i.e. files created with NC_NETCDF4 in the cmode in
837their call to nc_create()), it is not necessary to call nc_redef()
838unless the file was also created with NC_STRICT_NC3. For straight-up
839netCDF-4 files, nc_redef() is called automatically, as needed.
840
841For all netCDF-4 files, the root ncid must be used. This is the ncid
842returned by nc_open() and nc_create(), and points to the root of the
843hierarchy tree for netCDF-4 files.
844
845\param ncid NetCDF ID, from a previous call to nc_open() or
846nc_create().
847
848\returns ::NC_NOERR No error.
849
850\returns ::NC_EBADID Bad ncid.
851
852\returns ::NC_EBADGRPID The ncid must refer to the root group of the
853file, that is, the group returned by nc_open() or nc_create().
854
855\returns ::NC_EINDEFINE Already in define mode.
856
857\returns ::NC_EPERM File is read-only.
858
859<h1>Example</h1>
860
861Here is an example using nc_redef to open an existing netCDF dataset
862named foo.nc and put it into define mode:
863
864\code
865#include <netcdf.h>
866   ...
867int status = NC_NOERR;
868int ncid;
869   ...
870status = nc_open("foo.nc", NC_WRITE, &ncid);
871if (status != NC_NOERR) handle_error(status);
872   ...
873status = nc_redef(ncid);
874if (status != NC_NOERR) handle_error(status);
875\endcode
876 */
877int
878nc_redef(int ncid)
879{
880   NCncp;
881   int stat = NC_check_id(ncid, &ncp);
882   if(stat != NC_NOERR) return stat;
883   return ncp->dispatch->redef(ncid);
884}
885
886/** \ingroup datasets
887Leave define mode
888
889The function nc_enddef() takes an open netCDF dataset out of define
890mode. The changes made to the netCDF dataset while it was in define
891mode are checked and committed to disk if no problems
892occurred. Non-record variables may be initialized to a "fill value" as
893well with nc_set_fill(). The netCDF dataset is then placed in data
894mode, so variable data can be read or written.
895
896It's not necessary to call nc_enddef() for netCDF-4 files. With netCDF-4
897files, nc_enddef() is called when needed by the netcdf-4 library. User
898calls to nc_enddef() for netCDF-4 files still flush the metadata to
899disk.
900
901This call may involve copying data under some circumstances. For a
902more extensive discussion see File Structure and Performance.
903
904For netCDF-4/HDF5 format files there are some variable settings (the
905compression, endianness, fletcher32 error correction, and fill value)
906which must be set (if they are going to be set at all) between the
907nc_def_var() and the next nc_enddef(). Once the nc_enddef() is called,
908these settings can no longer be changed for a variable.
909
910\param ncid NetCDF ID, from a previous call to nc_open() or
911nc_create().
912
913If you use a group id (in a netCDF-4/HDF5 file), the enddef
914will apply to the entire file. That means the enddef will not just end
915define mode in one group, but in the entire file.
916
917\returns ::NC_NOERR no error
918
919\returns ::NC_EBADID Invalid ncid passed.
920
921<h1>Example</h1>
922
923Here is an example using nc_enddef() to finish the definitions of a new
924netCDF dataset named foo.nc and put it into data mode:
925
926\code
927     #include <netcdf.h>
928        ...
929     int status = NC_NOERR;
930     int ncid;
931        ...
932     status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
933     if (status != NC_NOERR) handle_error(status);
934
935        ...  create dimensions, variables, attributes
936
937     status = nc_enddef(ncid);
938     if (status != NC_NOERR) handle_error(status);
939\endcode
940 */
941int
942nc_enddef(int ncid)
943{
944   int status = NC_NOERR;
945   NC *ncp;
946   status = NC_check_id(ncid, &ncp);
947   if(status != NC_NOERR) return status;
948   return ncp->dispatch->_enddef(ncid,0,1,0,1);
949}
950
951/** \ingroup datasets
952Leave define mode with performance tuning
953
954The function nc__enddef takes an open netCDF dataset out of define
955mode. The changes made to the netCDF dataset while it was in define
956mode are checked and committed to disk if no problems
957occurred. Non-record variables may be initialized to a "fill value" as
958well with nc_set_fill(). The netCDF dataset is then placed in data mode,
959so variable data can be read or written.
960
961This call may involve copying data under some circumstances. For a
962more extensive discussion see File Structure and Performance.
963
964\warning This function exposes internals of the netcdf version 1 file
965format. Users should use nc_enddef() in most circumstances. This
966function may not be available on future netcdf implementations.
967
968The classic netcdf file format has three sections, the "header"
969section, the data section for fixed size variables, and the data
970section for variables which have an unlimited dimension (record
971variables).
972
973The header begins at the beginning of the file. The index (offset) of
974the beginning of the other two sections is contained in the
975header. Typically, there is no space between the sections. This causes
976copying overhead to accrue if one wishes to change the size of the
977sections, as may happen when changing names of things, text attribute
978values, adding attributes or adding variables. Also, for buffered i/o,
979there may be advantages to aligning sections in certain ways.
980
981The minfree parameters allow one to control costs of future calls to
982nc_redef, nc_enddef() by requesting that minfree bytes be available at
983the end of the section.
984
985The align parameters allow one to set the alignment of the beginning
986of the corresponding sections. The beginning of the section is rounded
987up to an index which is a multiple of the align parameter. The flag
988value ALIGN_CHUNK tells the library to use the bufrsize (see above) as
989the align parameter. It has nothing to do with the chunking
990(multidimensional tiling) features of netCDF-4.
991
992The file format requires mod 4 alignment, so the align parameters are
993silently rounded up to multiples of 4. The usual call,
994
995\code
996     nc_enddef(ncid);
997\endcode
998
999is equivalent to
1000
1001\code
1002     nc__enddef(ncid, 0, 4, 0, 4);
1003\endcode
1004
1005The file format does not contain a "record size" value, this is
1006calculated from the sizes of the record variables. This unfortunate
1007fact prevents us from providing minfree and alignment control of the
1008"records" in a netcdf file. If you add a variable which has an
1009unlimited dimension, the third section will always be copied with the
1010new variable added.
1011
1012\param ncid NetCDF ID, from a previous call to nc_open() or
1013nc_create().
1014
1015\param h_minfree Sets the pad at the end of the "header" section.
1016
1017\param v_align Controls the alignment of the beginning of the data
1018section for fixed size variables.
1019
1020\param v_minfree Sets the pad at the end of the data section for fixed
1021size variables.
1022
1023\param r_align Controls the alignment of the beginning of the data
1024section for variables which have an unlimited dimension (record
1025variables).
1026
1027\returns ::NC_NOERR No error.
1028
1029\returns ::NC_EBADID Invalid ncid passed.
1030
1031 */
1032int
1033nc__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree,
1034    size_t r_align)
1035{
1036   NCncp;
1037   int stat = NC_check_id(ncid, &ncp);
1038   if(stat != NC_NOERR) return stat;
1039   return ncp->dispatch->_enddef(ncid,h_minfree,v_align,v_minfree,r_align);
1040}
1041
1042/** \ingroup datasets
1043Synchronize an open netcdf dataset to disk
1044
1045The function nc_sync() offers a way to synchronize the disk copy of a
1046netCDF dataset with in-memory buffers. There are two reasons you might
1047want to synchronize after writes:
1048- To minimize data loss in case of abnormal termination, or
1049- To make data available to other processes for reading immediately
1050  after it is written. But note that a process that already had the
1051  dataset open for reading would not see the number of records
1052  increase when the writing process calls nc_sync(); to accomplish this,
1053  the reading process must call nc_sync.
1054
1055This function is backward-compatible with previous versions of the
1056netCDF library. The intent was to allow sharing of a netCDF dataset
1057among multiple readers and one writer, by having the writer call
1058nc_sync() after writing and the readers call nc_sync() before each
1059read. For a writer, this flushes buffers to disk. For a reader, it
1060makes sure that the next read will be from disk rather than from
1061previously cached buffers, so that the reader will see changes made by
1062the writing process (e.g., the number of records written) without
1063having to close and reopen the dataset. If you are only accessing a
1064small amount of data, it can be expensive in computer resources to
1065always synchronize to disk after every write, since you are giving up
1066the benefits of buffering.
1067
1068An easier way to accomplish sharing (and what is now recommended) is
1069to have the writer and readers open the dataset with the NC_SHARE
1070flag, and then it will not be necessary to call nc_sync() at
1071all. However, the nc_sync() function still provides finer granularity
1072than the NC_SHARE flag, if only a few netCDF accesses need to be
1073synchronized among processes.
1074
1075It is important to note that changes to the ancillary data, such as
1076attribute values, are not propagated automatically by use of the
1077NC_SHARE flag. Use of the nc_sync() function is still required for this
1078purpose.
1079
1080Sharing datasets when the writer enters define mode to change the data
1081schema requires extra care. In previous releases, after the writer
1082left define mode, the readers were left looking at an old copy of the
1083dataset, since the changes were made to a new copy. The only way
1084readers could see the changes was by closing and reopening the
1085dataset. Now the changes are made in place, but readers have no
1086knowledge that their internal tables are now inconsistent with the new
1087dataset schema. If netCDF datasets are shared across redefinition,
1088some mechanism external to the netCDF library must be provided that
1089prevents access by readers during redefinition and causes the readers
1090to call nc_sync before any subsequent access.
1091
1092When calling nc_sync(), the netCDF dataset must be in data mode. A
1093netCDF dataset in define mode is synchronized to disk only when
1094nc_enddef() is called. A process that is reading a netCDF dataset that
1095another process is writing may call nc_sync to get updated with the
1096changes made to the data by the writing process (e.g., the number of
1097records written), without having to close and reopen the dataset.
1098
1099Data is automatically synchronized to disk when a netCDF dataset is
1100closed, or whenever you leave define mode.
1101
1102\param ncid NetCDF ID, from a previous call to nc_open() or
1103nc_create().
1104
1105\returns ::NC_NOERR No error.
1106
1107\returns ::NC_EBADID Invalid ncid passed.
1108 */
1109int
1110nc_sync(int ncid)
1111{
1112   NCncp;
1113   int stat = NC_check_id(ncid, &ncp);
1114   if(stat != NC_NOERR) return stat;
1115   return ncp->dispatch->sync(ncid);
1116}
1117
1118/** \ingroup datasets
1119No longer necessary for user to invoke manually.
1120
1121
1122\warning Users no longer need to call this function since it is called
1123automatically by nc_close() in case the dataset is in define mode and
1124something goes wrong with committing the changes. The function
1125nc_abort() just closes the netCDF dataset, if not in define mode. If
1126the dataset is being created and is still in define mode, the dataset
1127is deleted. If define mode was entered by a call to nc_redef(), the
1128netCDF dataset is restored to its state before definition mode was
1129entered and the dataset is closed.
1130
1131\param ncid NetCDF ID, from a previous call to nc_open() or
1132nc_create().
1133
1134\returns ::NC_NOERR No error.
1135
1136<h1>Example</h1>
1137
1138Here is an example using nc_abort to back out of redefinitions of a
1139dataset named foo.nc:
1140
1141\code
1142     #include <netcdf.h>
1143        ...
1144     int ncid, status, latid;
1145        ...
1146     status = nc_open("foo.nc", NC_WRITE, &ncid);
1147     if (status != NC_NOERR) handle_error(status);
1148        ...
1149     status = nc_redef(ncid);
1150     if (status != NC_NOERR) handle_error(status);
1151        ...
1152     status = nc_def_dim(ncid, "lat", 18L, &latid);
1153     if (status != NC_NOERR) {
1154        handle_error(status);
1155        status = nc_abort(ncid);
1156        if (status != NC_NOERR) handle_error(status);
1157     }
1158\endcode
1159
1160 */
1161int
1162nc_abort(int ncid)
1163{
1164   NCncp;
1165   int stat = NC_check_id(ncid, &ncp);
1166   if(stat != NC_NOERR) return stat;
1167
1168#ifdef USE_REFCOUNT
1169   /* What to do if refcount > 0? */
1170   /* currently, forcibly abort */
1171   ncp->refcount = 0;
1172#endif
1173
1174   stat = ncp->dispatch->abort(ncid);
1175   del_from_NCList(ncp);
1176   free_NC(ncp);
1177   return stat;
1178}
1179
1180/** \ingroup datasets
1181Close an open netCDF dataset
1182
1183If the dataset in define mode, nc_enddef() will be called before
1184closing. (In this case, if nc_enddef() returns an error, nc_abort() will
1185automatically be called to restore the dataset to the consistent state
1186before define mode was last entered.) After an open netCDF dataset is
1187closed, its netCDF ID may be reassigned to the next netCDF dataset
1188that is opened or created.
1189
1190\param ncid NetCDF ID, from a previous call to nc_open() or nc_create().
1191
1192\returns ::NC_NOERR No error.
1193
1194\returns ::NC_EBADID Invalid id passed.
1195
1196\returns ::NC_EBADGRPID ncid did not contain the root group id of this
1197file. (NetCDF-4 only).
1198
1199<h1>Example</h1>
1200
1201Here is an example using nc_close to finish the definitions of a new
1202netCDF dataset named foo.nc and release its netCDF ID:
1203
1204\code
1205     #include <netcdf.h>
1206        ...
1207     int status = NC_NOERR;
1208     int ncid;
1209        ...
1210     status = nc_create("foo.nc", NC_NOCLOBBER, &ncid);
1211     if (status != NC_NOERR) handle_error(status);
1212
1213        ...   create dimensions, variables, attributes
1214
1215     status = nc_close(ncid);
1216     if (status != NC_NOERR) handle_error(status);
1217\endcode
1218
1219 */
1220int
1221nc_close(int ncid)
1222{
1223   NCncp;
1224   int stat = NC_check_id(ncid, &ncp);
1225   if(stat != NC_NOERR) return stat;
1226
1227#ifdef USE_REFCOUNT
1228   ncp->refcount--;
1229   if(ncp->refcount <= 0)
1230#endif
1231   {
1232
1233    stat = ncp->dispatch->close(ncid);
1234       /* Remove from the nc list */
1235       del_from_NCList(ncp);
1236       free_NC(ncp);
1237   }
1238   return stat;
1239}
1240
1241/** \ingroup datasets
1242Change the fill-value mode to improve write performance.
1243
1244This function is intended for advanced usage, to optimize writes under
1245some circumstances described below. The function nc_set_fill() sets the
1246fill mode for a netCDF dataset open for writing and returns the
1247current fill mode in a return parameter. The fill mode can be
1248specified as either ::NC_FILL or ::NC_NOFILL. The default behavior
1249corresponding to ::NC_FILL is that data is pre-filled with fill values,
1250that is fill values are written when you create non-record variables
1251or when you write a value beyond data that has not yet been
1252written. This makes it possible to detect attempts to read data before
1253it was written. For more information on the use of fill values see
1254Fill Values. For information about how to define your own fill values
1255see Attribute Conventions.
1256
1257The behavior corresponding to ::NC_NOFILL overrides the default behavior
1258of prefilling data with fill values. This can be used to enhance
1259performance, because it avoids the duplicate writes that occur when
1260the netCDF library writes fill values that are later overwritten with
1261data.
1262
1263A value indicating which mode the netCDF dataset was already in is
1264returned. You can use this value to temporarily change the fill mode
1265of an open netCDF dataset and then restore it to the previous mode.
1266
1267After you turn on ::NC_NOFILL mode for an open netCDF dataset, you must
1268be certain to write valid data in all the positions that will later be
1269read. Note that nofill mode is only a transient property of a netCDF
1270dataset open for writing: if you close and reopen the dataset, it will
1271revert to the default behavior. You can also revert to the default
1272behavior by calling nc_set_fill() again to explicitly set the fill mode
1273to ::NC_FILL.
1274
1275There are three situations where it is advantageous to set nofill
1276mode:
1277- Creating and initializing a netCDF dataset. In this case, you should
1278  set nofill mode before calling nc_enddef() and then write completely
1279  all non-record variables and the initial records of all the record
1280  variables you want to initialize.
1281- Extending an existing record-oriented netCDF dataset. Set nofill
1282  mode after opening the dataset for writing, then append the
1283  additional records to the dataset completely, leaving no intervening
1284  unwritten records.
1285- Adding new variables that you are going to initialize to an existing
1286  netCDF dataset. Set nofill mode before calling nc_enddef() then write
1287  all the new variables completely.
1288
1289If the netCDF dataset has an unlimited dimension and the last record
1290was written while in nofill mode, then the dataset may be shorter than
1291if nofill mode was not set, but this will be completely transparent if
1292you access the data only through the netCDF interfaces.
1293
1294The use of this feature may not be available (or even needed) in
1295future releases. Programmers are cautioned against heavy reliance upon
1296this feature.
1297
1298\param ncid NetCDF ID, from a previous call to nc_open() or
1299nc_create().
1300
1301\param fillmode Desired fill mode for the dataset, either ::NC_NOFILL or
1302::NC_FILL.
1303
1304\param old_modep Pointer to location for returned current fill mode of
1305the dataset before this call, either ::NC_NOFILL or ::NC_FILL.
1306
1307\returns ::NC_NOERR No error.
1308
1309\returns ::NC_EBADID The specified netCDF ID does not refer to an open
1310netCDF dataset.
1311
1312\returns ::NC_EPERM The specified netCDF ID refers to a dataset open for
1313read-only access.
1314
1315\returns ::NC_EINVAL The fill mode argument is neither ::NC_NOFILL nor
1316::NC_FILL.
1317
1318<h1>Example</h1>
1319
1320Here is an example using nc_set_fill() to set nofill mode for subsequent
1321writes of a netCDF dataset named foo.nc:
1322
1323\code
1324     #include <netcdf.h>
1325        ...
1326     int ncid, status, old_fill_mode;
1327        ...
1328     status = nc_open("foo.nc", NC_WRITE, &ncid);
1329     if (status != NC_NOERR) handle_error(status);
1330
1331        ...     write data with default prefilling behavior
1332
1333     status = nc_set_fill(ncid, ::NC_NOFILL, &old_fill_mode);
1334     if (status != NC_NOERR) handle_error(status);
1335
1336        ...    write data with no prefilling
1337\endcode
1338 */
1339int
1340nc_set_fill(int ncid, int fillmode, int *old_modep)
1341{
1342   NCncp;
1343   int stat = NC_check_id(ncid, &ncp);
1344   if(stat != NC_NOERR) return stat;
1345   return ncp->dispatch->set_fill(ncid,fillmode,old_modep);
1346}
1347
1348/**
1349\internal
1350
1351\deprecated This function was used in the old days with the Cray at
1352NCAR. The Cray is long gone, and this call is supported only for
1353backward compatibility.
1354
1355\returns ::NC_NOERR No error.
1356
1357\returns ::NC_EBADID Invalid ncid passed.
1358 */
1359int
1360nc_inq_base_pe(int ncid, int *pe)
1361{
1362   NCncp;
1363   int stat = NC_check_id(ncid, &ncp);
1364   if(stat != NC_NOERR) return stat;
1365   return ncp->dispatch->inq_base_pe(ncid,pe);
1366}
1367
1368/**
1369\internal
1370
1371\deprecated This function was used in the old days with the Cray at
1372NCAR. The Cray is long gone, and this call is supported only for
1373backward compatibility.
1374
1375\returns ::NC_NOERR No error.
1376
1377\returns ::NC_EBADID Invalid ncid passed.
1378 */
1379int
1380nc_set_base_pe(int ncid, int pe)
1381{
1382   NCncp;
1383   int stat = NC_check_id(ncid, &ncp);
1384   if(stat != NC_NOERR) return stat;
1385   return ncp->dispatch->set_base_pe(ncid,pe);
1386}
1387
1388/** \ingroup datasets
1389Inquire about the binary format of a netCDF file
1390as presented by the API.
1391
1392This function returns the (rarely needed) format version.
1393
1394\param ncid NetCDF ID, from a previous call to nc_open() or
1395nc_create().
1396
1397\param formatp Pointer to location for returned format version, one of
1398NC_FORMAT_CLASSIC, NC_FORMAT_64BIT_OFFSET, NC_FORMAT_CDF5, NC_FORMAT_NETCDF4,
1399NC_FORMAT_NETCDF4_CLASSIC.
1400
1401\returns ::NC_NOERR No error.
1402
1403\returns ::NC_EBADID Invalid ncid passed.
1404
1405 */
1406int
1407nc_inq_format(int ncid, int *formatp)
1408{
1409   NCncp;
1410   int stat = NC_check_id(ncid, &ncp);
1411   if(stat != NC_NOERR) return stat;
1412   return ncp->dispatch->inq_format(ncid,formatp);
1413}
1414
1415/** \ingroup datasets
1416Obtain more detailed (vis-a-vis nc_inq_format)
1417format information about an open dataset.
1418
1419Note that the netcdf API will present the file
1420as if it had the format specified by nc_inq_format.
1421The true file format, however, may not even be
1422a netcdf file; it might be DAP, HDF4, or PNETCDF,
1423for example. This function returns that true file type.
1424It also returns the effective mode for the file.
1425
1426\param ncid NetCDF ID, from a previous call to nc_open() or
1427nc_create().
1428
1429\param formatp Pointer to location for returned true format.
1430
1431\param modep Pointer to location for returned mode flags.
1432
1433Refer to the actual list in the file netcdf.h to see the
1434currently defined set.
1435
1436\returns ::NC_NOERR No error.
1437
1438\returns ::NC_EBADID Invalid ncid passed.
1439
1440 */
1441int
1442nc_inq_format_extended(int ncid, int *formatp, int *modep)
1443{
1444   NCncp;
1445   int stat = NC_check_id(ncid, &ncp);
1446   if(stat != NC_NOERR) return stat;
1447   return ncp->dispatch->inq_format_extended(ncid,formatp,modep);
1448}
1449
1450/**\ingroup datasets
1451Inquire about a file or group.
1452
1453\param ncid NetCDF or group ID, from a previous call to nc_open(),
1454nc_create(), nc_def_grp(), or associated inquiry functions such as
1455nc_inq_ncid().
1456
1457\param ndimsp Pointer to location for returned number of dimensions
1458defined for this netCDF dataset. Ignored if NULL.
1459
1460\param nvarsp Pointer to location for returned number of variables
1461defined for this netCDF dataset. Ignored if NULL.
1462
1463\param nattsp Pointer to location for returned number of global
1464attributes defined for this netCDF dataset. Ignored if NULL.
1465
1466\param unlimdimidp Pointer to location for returned ID of the
1467unlimited dimension, if there is one for this netCDF dataset. If no
1468unlimited length dimension has been defined, -1 is returned. Ignored
1469if NULL.  If there are multiple unlimited dimensions (possible only
1470for netCDF-4 files), only a pointer to the first is returned, for
1471backward compatibility.  If you want them all, use nc_inq_unlimids().
1472
1473\returns ::NC_NOERR No error.
1474
1475\returns ::NC_EBADID Invalid ncid passed.
1476
1477<h1>Example</h1>
1478
1479Here is an example using nc_inq to find out about a netCDF dataset
1480named foo.nc:
1481
1482\code
1483     #include <netcdf.h>
1484        ...
1485     int status, ncid, ndims, nvars, ngatts, unlimdimid;
1486        ...
1487     status = nc_open("foo.nc", NC_NOWRITE, &ncid);
1488     if (status != NC_NOERR) handle_error(status);
1489        ...
1490     status = nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid);
1491     if (status != NC_NOERR) handle_error(status);
1492\endcode
1493 */
1494int
1495nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
1496{
1497   NCncp;
1498   int stat = NC_check_id(ncid, &ncp);
1499   if(stat != NC_NOERR) return stat;
1500   return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp);
1501}
1502
1503int
1504nc_inq_nvars(int ncid, int *nvarsp)
1505{
1506   NCncp;
1507   int stat = NC_check_id(ncid, &ncp);
1508   if(stat != NC_NOERR) return stat;
1509   return ncp->dispatch->inq(ncidNULLnvarspNULLNULL);
1510}
1511
1512/**\ingroup datasets
1513Inquire about a type.
1514
1515Given an ncid and a typeid, get the information about a type. This
1516function will work on any type, including atomic and any user defined
1517type, whether compound, opaque, enumeration, or variable length array.
1518
1519For even more information about a user defined type nc_inq_user_type().
1520
1521\param ncid The ncid for the group containing the type (ignored for
1522atomic types).
1523
1524\param xtype The typeid for this type, as returned by nc_def_compound,
1525nc_def_opaque, nc_def_enum, nc_def_vlen, or nc_inq_var, or as found in
1526netcdf.h in the list of atomic types (NC_CHAR, NC_INT, etc.).
1527
1528\param name If non-NULL, the name of the user defined type will be
1529copied here. It will be NC_MAX_NAME bytes or less. For atomic types,
1530the type name from CDL will be given.
1531
1532\param size If non-NULL, the (in-memory) size of the type in bytes
1533will be copied here. VLEN type size is the size of nc_vlen_t. String
1534size is returned as the size of a character pointer. The size may be
1535used to malloc space for the data, no matter what the type.
1536
1537\returns ::NC_NOERR No error.
1538
1539\returns ::NC_EBADTYPE Bad typeid.
1540
1541\returns ::NC_ENOTNC4 Seeking a user-defined type in a netCDF-3 file.
1542
1543\returns ::NC_ESTRICTNC3 Seeking a user-defined type in a netCDF-4 file
1544for which classic model has been turned on.
1545
1546\returns ::NC_EBADGRPID Bad group ID in ncid.
1547
1548\returns ::NC_EBADID Type ID not found.
1549
1550\returns ::NC_EHDFERR An error was reported by the HDF5 layer.
1551
1552<h1>Example</h1>
1553
1554This example is from the test program tst_enums.c, and it uses all the
1555possible inquiry functions on an enum type.
1556
1557\code
1558           if (nc_inq_user_type(ncid, typeids[0], name_in, &base_size_in, &base_nc_type_in,
1559                                &nfields_in, &class_in)) ERR;
1560           if (strcmp(name_in, TYPE_NAME) || base_size_in != sizeof(int) ||
1561               base_nc_type_in != NC_INT || nfields_in != NUM_MEMBERS || class_in != NC_ENUM) ERR;
1562           if (nc_inq_type(ncid, typeids[0], name_in, &base_size_in)) ERR;
1563           if (strcmp(name_in, TYPE_NAME) || base_size_in != sizeof(int)) ERR;
1564           if (nc_inq_enum(ncid, typeids[0], name_in, &base_nc_type, &base_size_in, &num_members)) ERR;
1565           if (strcmp(name_in, TYPE_NAME) || base_nc_type != NC_INT || num_members != NUM_MEMBERS) ERR;
1566           for (i = 0; i < NUM_MEMBERS; i++)
1567           {
1568              if (nc_inq_enum_member(ncid, typeid, i, name_in, &value_in)) ERR;
1569              if (strcmp(name_in, member_name[i]) || value_in != member_value[i]) ERR;
1570              if (nc_inq_enum_ident(ncid, typeid, member_value[i], name_in)) ERR;
1571              if (strcmp(name_in, member_name[i])) ERR;
1572           }
1573
1574           if (nc_close(ncid)) ERR;
1575\endcode
1576 */
1577int
1578nc_inq_type(int ncidnc_type xtype, char *name, size_t *size)
1579{
1580   NCncp;
1581   int stat;
1582
1583   /* Do a quick triage on xtype */
1584   if(xtype <= NC_NAT) return NC_EBADTYPE;
1585   /* See if the ncid is valid */
1586   stat = NC_check_id(ncid, &ncp);
1587   if(stat != NC_NOERR) { /* bad ncid; do what we can */
1588       /* For compatibility, we need to allow inq about
1589          atomic types, even if ncid is ill-defined */
1590 if(xtype <= ATOMICTYPEMAX4) {
1591            if(namestrncpy(name,NC_atomictypename(xtype),NC_MAX_NAME);
1592            if(size) *size = NC_atomictypelen(xtype);
1593            return NC_NOERR;
1594 } else
1595     return NC_EBADTYPE;
1596   } else { /* have good ncid */
1597      return ncp->dispatch->inq_type(ncid,xtype,name,size);
1598   }
1599#if 0
1600       int maxtype;
1601       int format;
1602   nc_inq_format(ncid, &format);
1603   switch (format) {
1604   case NC_FORMAT_NETCDF4_CLASSIC: /*fall thru*/
1605   case NC_FORMAT_64BIT_OFFSET: /*fall thru*/
1606   case NC_FORMAT_CLASSICmaxtype = ATOMICTYPEMAX3; break;
1607   case NC_FORMAT_NETCDF4maxtype = ATOMICTYPEMAX4; break;
1608   case NC_FORMAT_CDF5maxtype = ATOMICTYPEMAX5; break;
1609   default: return NC_EINVAL;
1610   }
1611#endif
1612}
1613
1614/**
1615\internal
1616\ingroup dispatch
1617
1618Create a file, calling the appropriate dispatch create call.
1619
1620For create, we have the following pieces of information to use to
1621determine the dispatch table:
1622- table specified by override
1623- path
1624- cmode
1625
1626\param path The file name of the new netCDF dataset.
1627
1628\param cmode The creation mode flag, the same as in nc_create().
1629
1630\param initialsz This parameter sets the initial size of the file at creation
1631time. This only applies to classic and 64-bit offset files.
1632
1633\param basepe Deprecated parameter from the Cray days.
1634
1635\param chunksizehintp A pointer to the chunk size hint. This only
1636applies to classic and 64-bit offset files.
1637
1638\param useparallel Non-zero if parallel I/O is to be used on this
1639file.
1640
1641\param parameters Pointer to MPI comm and info.
1642
1643\param ncidp Pointer to location where returned netCDF ID is to be
1644stored.
1645
1646\returns ::NC_NOERR No error.
1647*/
1648int
1649NC_create(const char *path, int cmode, size_t initialsz,
1650   int basepe, size_t *chunksizehintp, int useparallel,
1651   void* parameters, int *ncidp)
1652{
1653   int stat = NC_NOERR;
1654   NCncp = NULL;
1655   NC_Dispatchdispatcher = NULL;
1656   /* Need three pieces of information for now */
1657   int model = NC_FORMATX_UNDEFINED; /* one of the NC_FORMATX values */
1658   int isurl = 0;   /* dap or cdmremote or neither */
1659   int xcmode = 0; /* for implied cmode flags */
1660
1661   TRACE(nc_create);
1662   /* Initialize the dispatch table. The function pointers in the
1663    * dispatch table will depend on how netCDF was built
1664    * (with/without netCDF-4, DAP, CDMREMOTE). */
1665   if(!NC_initialized)
1666   {
1667      if ((stat = nc_initialize()))
1668  return stat;
1669   }
1670
1671#ifdef USE_REFCOUNT
1672   /* If this path is already open, then fail */
1673   ncp = find_in_NCList_by_name(path);
1674   if(ncp != NULL)
1675 return NC_ENFILE;
1676#endif
1677
1678   if((isurl = NC_testurl(path)))
1679 model = NC_urlmodel(path);
1680
1681   /* Look to the incoming cmode for hints */
1682   if(model == NC_FORMATX_UNDEFINED) {
1683#ifdef USE_NETCDF4
1684      if((cmode & NC_NETCDF4) == NC_NETCDF4)
1685 model = NC_FORMATX_NC4;
1686      else
1687#endif
1688#ifdef USE_PNETCDF
1689      /* pnetcdf is used for parallel io on CDF-1, CDF-2, and CDF-5 */
1690      if((cmode & NC_MPIIO) == NC_MPIIO)
1691 model = NC_FORMATX_PNETCDF;
1692      else
1693#endif
1694 {}
1695    }
1696    if(model == NC_FORMATX_UNDEFINED) {
1697      /* Check default format (not formatx) */
1698      int format = nc_get_default_format();
1699      switch (format) {
1700#ifdef USE_NETCDF4
1701  case NC_FORMAT_NETCDF4:
1702     xcmode |= NC_NETCDF4;
1703     model = NC_FORMATX_NC4;
1704     break;
1705  case NC_FORMAT_NETCDF4_CLASSIC:
1706     xcmode |= NC_CLASSIC_MODEL;
1707     model = NC_FORMATX_NC4;
1708     break;
1709#endif
1710  case NC_FORMAT_CDF5:
1711     xcmode |= NC_64BIT_DATA;
1712     model = NC_FORMATX_NC3;
1713     break;
1714  case NC_FORMAT_64BIT_OFFSET:
1715     xcmode |= NC_64BIT_OFFSET;
1716     model = NC_FORMATX_NC3;
1717     break;
1718  case NC_FORMAT_CLASSIC:
1719     model = NC_FORMATX_NC3;
1720     break;
1721  default:
1722     model = NC_FORMATX_NC3;
1723     break;
1724      }
1725   }
1726
1727   /* Add inferred flags */
1728   cmode |= xcmode;
1729
1730   /* Clean up illegal combinations */
1731   if((cmode & (NC_64BIT_OFFSET|NC_64BIT_DATA)) == (NC_64BIT_OFFSET|NC_64BIT_DATA))
1732 cmode &= ~(NC_64BIT_OFFSET); /*NC_64BIT_DATA=>NC_64BIT_OFFSET*/
1733
1734   if((cmode & NC_MPIIO) && (cmode & NC_MPIPOSIX))
1735      return  NC_EINVAL;
1736
1737#ifdef OBSOLETE
1738   dispatcher = NC_get_dispatch_override();
1739#endif
1740   if (dispatcher == NULL)
1741   {
1742
1743      /* Figure out what dispatcher to use */
1744#ifdef USE_NETCDF4
1745      if(model == (NC_FORMATX_NC4))
1746  dispatcher = NC4_dispatch_table;
1747      else
1748#endif /*USE_NETCDF4*/
1749#ifdef USE_PNETCDF
1750      if(model == (NC_FORMATX_PNETCDF))
1751 dispatcher = NCP_dispatch_table;
1752      else
1753#endif
1754      if(model == (NC_FORMATX_NC3))
1755  dispatcher = NC3_dispatch_table;
1756      else
1757  return NC_ENOTNC;
1758   }
1759
1760   /* Create the NC* instance and insert its dispatcher */
1761   stat = new_NC(dispatcher,path,cmode,&ncp);
1762   if(stat) return stat;
1763
1764   /* Add to list of known open files and define ext_ncid */
1765   add_to_NCList(ncp);
1766
1767#ifdef USE_REFCOUNT
1768   /* bump the refcount */
1769   ncp->refcount++;
1770#endif
1771
1772   /* Assume create will fill in remaining ncp fields */
1773   if ((stat = dispatcher->create(pathcmodeinitialszbasepechunksizehintp,
1774    useparallelparametersdispatcherncp))) {
1775 del_from_NCList(ncp); /* oh well */
1776 free_NC(ncp);
1777     } else {
1778       if(ncidp)*ncidp = ncp->ext_ncid;
1779     }
1780   return stat;
1781}
1782
1783/**
1784\internal
1785\ingroup dispatch
1786
1787Open a netCDF file (or remote dataset) calling the appropriate
1788dispatch function.
1789
1790For open, we have the following pieces of information to use to determine the dispatch table.
1791- table specified by override
1792- path
1793- cmode
1794- the contents of the file (if it exists), basically checking its magic number.
1795
1796\returns ::NC_NOERR No error.
1797*/
1798int
1799NC_open(const char *path, int cmode,
1800 int basepe, size_t *chunksizehintp,
1801        int useparallel, void* parameters,
1802        int *ncidp)
1803{
1804   int stat = NC_NOERR;
1805   NCncp = NULL;
1806   NC_Dispatchdispatcher = NULL;
1807   int inmemory = ((cmode & NC_INMEMORY) == NC_INMEMORY);
1808   /* Need pieces of information for now to decide model*/
1809   int model = 0;
1810   int isurl = 0;
1811   int version = 0;
1812   int flags = 0;
1813
1814   TRACE(nc_open);
1815   if(!NC_initialized) {
1816      stat = nc_initialize();
1817      if(stat) return stat;
1818   }
1819
1820#ifdef USE_REFCOUNT
1821   /* If this path is already open, then bump the refcount and return it */
1822   ncp = find_in_NCList_by_name(path);
1823   if(ncp != NULL) {
1824 ncp->refcount++;
1825 if(ncidp) *ncidp = ncp->ext_ncid;
1826 return NC_NOERR;
1827   }
1828#endif
1829
1830   if(!inmemory) {
1831       isurl = NC_testurl(path);
1832       if(isurl)
1833           model = NC_urlmodel(path);
1834    }
1835    if(model == 0) {
1836 version = 0;
1837 /* Try to find dataset type */
1838 if(useparallelflags |= NC_MPIIO;
1839 if(inmemoryflags |= NC_INMEMORY;
1840 stat = NC_check_file_type(path,flags,parameters,&model,&version);
1841        if(stat == NC_NOERR) {
1842    if(model == 0)
1843     return NC_ENOTNC;
1844 } else /* presumably not a netcdf file */
1845     return stat;
1846    }
1847
1848   if(model == 0) {
1849 fprintf(stderr,"Model == 0\n");
1850 return NC_ENOTNC;
1851   }
1852
1853   /* Force flag consistentcy */
1854   if(model == NC_FORMATX_NC4)
1855      cmode |= NC_NETCDF4;
1856   else if(model == NC_FORMATX_NC3) {
1857      cmode &= ~NC_NETCDF4; /* must be netcdf-3 (CDF-1, CDF-2, CDF-5) */
1858      /* User may want to open file using the pnetcdf library */
1859      if(cmode & NC_PNETCDF) {
1860         /* dispatch is determined by cmode, rather than file format */
1861         model = NC_FORMATX_PNETCDF;
1862      }
1863      /* For opening an existing file, flags NC_64BIT_OFFSET and NC_64BIT_DATA
1864       * will be ignored, as the file is already in either CDF-1, 2, or 5
1865       * format. However, below we add the file format info to cmode so the
1866       * internal netcdf file open subroutine knows what file format to open.
1867       * The mode will be saved in ncp->mode, to be used by
1868       * nc_inq_format_extended() to report the file format.
1869       * See NC3_inq_format_extended() in libsrc/nc3internal.c for example.
1870       */
1871      if(version == 2) cmode |= NC_64BIT_OFFSET;
1872      else if(version == 5) {
1873        cmode |= NC_64BIT_DATA;
1874        cmode &= ~(NC_64BIT_OFFSET); /*NC_64BIT_DATA=>NC_64BIT_OFFSET*/
1875      }
1876   } else if(model == NC_FORMATX_PNETCDF) {
1877     cmode &= ~(NC_NETCDF4|NC_64BIT_OFFSET);
1878     cmode |= NC_64BIT_DATA;
1879   }
1880
1881   if((cmode & NC_MPIIO && cmode & NC_MPIPOSIX))
1882     return  NC_EINVAL;
1883
1884   /* override any other table choice */
1885#ifdef OBSOLETE
1886   dispatcher = NC_get_dispatch_override();
1887#endif
1888   if(dispatcher != NULL) goto havetable;
1889
1890   /* Figure out what dispatcher to use */
1891#if  defined(USE_CDMREMOTE)
1892   if(model == (NC_DISPATCH_NC4 | NC_DISPATCH_NCR))
1893 dispatcher = NCCR_dispatch_table;
1894   else
1895#endif
1896#if defined(USE_DAP)
1897   if(model == (NC_FORMATX_DAP2))
1898 dispatcher = NCD2_dispatch_table;
1899   else
1900#endif
1901#if  defined(USE_PNETCDF)
1902   if(model == (NC_FORMATX_PNETCDF))
1903 dispatcher = NCP_dispatch_table;
1904   else
1905#endif
1906#if defined(USE_NETCDF4)
1907   if(model == (NC_FORMATX_NC4))
1908 dispatcher = NC4_dispatch_table;
1909   else
1910#endif
1911   if(model == (NC_FORMATX_NC3))
1912 dispatcher = NC3_dispatch_table;
1913   else
1914      return  NC_ENOTNC;
1915
1916havetable:
1917
1918   /* Create the NC* instance and insert its dispatcher */
1919   stat = new_NC(dispatcher,path,cmode,&ncp);
1920   if(stat) return stat;
1921
1922   /* Add to list of known open files */
1923   add_to_NCList(ncp);
1924
1925#ifdef USE_REFCOUNT
1926   /* bump the refcount */
1927   ncp->refcount++;
1928#endif
1929
1930   /* Assume open will fill in remaining ncp fields */
1931   stat = dispatcher->open(pathcmodebasepechunksizehintp,
1932    useparallelparametersdispatcherncp);
1933   if(stat == NC_NOERR) {
1934     if(ncidp) *ncidp = ncp->ext_ncid;
1935   } else {
1936 del_from_NCList(ncp);
1937 free_NC(ncp);
1938   }
1939   return stat;
1940}
1941
1942/*Provide an internal function for generating pseudo file descriptors
1943  for systems that are not file based (e.g. dap, memio).
1944*/
1945
1946/* Static counter for pseudo file descriptors (incremented) */
1947static int pseudofd = 0;
1948
1949/* Create a pseudo file descriptor that does not
1950   overlap real file descriptors
1951*/
1952int
1953nc__pseudofd(void)
1954{
1955    if(pseudofd == 0)  {
1956        int maxfd = 32767; /* default */
1957#ifdef HAVE_GETRLIMIT
1958        struct rlimit rl;
1959        if(getrlimit(RLIMIT_NOFILE,&rl) == 0) {
1960     if(rl.rlim_max != RLIM_INFINITY)
1961         maxfd = (int)rl.rlim_max;
1962     if(rl.rlim_cur != RLIM_INFINITY)
1963         maxfd = (int)rl.rlim_cur;
1964 }
1965 pseudofd = maxfd+1;
1966#endif
1967    }
1968    return pseudofd++;
1969}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed