Index: /branches/SDM_SciDAC/macros.make =================================================================== --- /branches/SDM_SciDAC/macros.make (revision 2) +++ /branches/SDM_SciDAC/macros.make (revision 2) @@ -0,0 +1,88 @@ +# $Id$ + +# The purpose of this file is to contain common make(1) macros. +# It should be processed by every execution of that utility. + + +# POSIX shell. Shouldn't be necessary -- but is under IRIX 5.3. +SHELL = /bin/sh + + +# Installation Directories: +prefix = /opt/netcdf +exec_prefix = $(prefix) +INCDIR = $(exec_prefix)/include +LIBDIR = $(exec_prefix)/lib +BINDIR = $(exec_prefix)/bin +MANDIR = $(prefix)/man + + +# Preprocessing: +M4 = m4 +M4FLAGS = -B10000 +CPP = c89 -E +CPPFLAGS = $(INCLUDES) $(DEFINES) @CPPFLAGS@ +FPP = +FPPFLAGS = $(CPPFLAGS) +CXXCPPFLAGS = $(CPPFLAGS) + + +# Compilation: +CC = c89 +CXX = CC +FC = f77 +CFLAGS = -g +CXXFLAGS = $(CFLAGS) @CXXFLAGS@ +FFLAGS = -g +CC_MAKEDEPEND = : +COMPILE.c = $(CC) -c $(CFLAGS) $(CPPFLAGS) +COMPILE.cxx = $(CXX) -c $(CXXFLAGS) $(CXXCPPFLAGS) +COMPILE.f = $(FC) -c $(FFLAGS) +# The following command isn't available on some systems; therefore, the +# `.F.o' rule is relatively complicated. +COMPILE.F = $(COMPILE.f) + + +# Linking: +MATHLIB = +FLIBS = +LIBS = +LINK.c = $(CC) -o $@ $(CFLAGS) $(LDFLAGS) +LINK.cxx = $(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) +LINK.F = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) +LINK.f = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) + + +# NetCDF files: +NCDUMP = ncdump +NCGEN = ncgen + + +# Manual pages: +WHATIS = +# The following macro should be empty on systems that don't +# allow users to create their own manual-page indexes. +MAKEWHATIS_CMD = + + +# Misc. Utilities: +AR = ar +ARFLAGS = cru # NB: SunOS 4 doesn't like `-' option prefix +RANLIB = +TARFLAGS = -chf + + +# Dummy macros: used only as placeholders to silence GNU make. They are +# redefined, as necessary, in subdirectory makefiles. +HEADER = dummy_header +HEADER1 = dummy_header1 +HEADER2 = dummy_header2 +LIBRARY = dummy_library.a +MANUAL = dummy_manual +PROGRAM = dummy_program + + +# Distribution macros: +FTPDIR = /home/ftp/pub/$(PACKAGE) +FTPBINDIR = +VERSION = dummy_version Index: /branches/SDM_SciDAC/configure =================================================================== --- /branches/SDM_SciDAC/configure (revision 2) +++ /branches/SDM_SciDAC/configure (revision 2) @@ -0,0 +1,4117 @@ +#! /bin/sh + +# From configure.in Id: configure.in +CPPFLAGS=${CPPFLAGS--DNDEBUG} +CFLAGS=${CFLAGS--O} +FPPFLAGS=${FPPFLAGS-} +FFLAGS=${FFLAGS-} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_default_prefix=`(cd ..; pwd)` + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=src/lib/ncconfig.in + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + echo "checking for top-level source-directory" 1>&6 +echo "configure:605: checking for top-level source-directory" >&5 + SRCDIR=`(cd $srcdir && pwd)` + echo "$ac_t""$SRCDIR" 1>&6 + + + + + + echo "checking for m4 preprocessor" 1>&6 +echo "configure:614: checking for m4 preprocessor" >&5 + case "${M4-unset}" in + unset) for ac_prog in m4 gm4 +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:621: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_M4'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$M4"; then + ac_cv_prog_M4="$M4" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_M4="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +M4="$ac_cv_prog_M4" +if test -n "$M4"; then + echo "$ac_t""$M4" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$M4" && break +done +test -n "$M4" || M4="m4" + ;; + *) for ac_prog in $M4 m4 gm4 +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:656: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_M4'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$M4"; then + ac_cv_prog_M4="$M4" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_M4="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +M4="$ac_cv_prog_M4" +if test -n "$M4"; then + echo "$ac_t""$M4" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$M4" && break +done +test -n "$M4" || M4="m4" + ;; + esac + echo $ac_n "checking m4 flags""... $ac_c" 1>&6 +echo "configure:688: checking m4 flags" >&5 + case "${M4FLAGS-unset}" in + unset) M4FLAGS=-B10000 ;; + esac + echo "$ac_t""$M4FLAGS" 1>&6 + + + + # Because we must have a C compiler, we treat an unset CC + # the same as an empty CC. + case "${CC}" in + '') + case `uname` in + ULTRIX) + # The native ULTRIX C compiler isn't standard. + ccs='gcc cc' + ;; + *) + # xlc is before c89 because AIX's sizeof(long long) + # differs between the two. + # + ccs='xlc c89 acc cc gcc' + ;; + esac + for cc in $ccs; do + # Extract the first word of "$cc", so it can be a program name with args. +set dummy $cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:716: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$cc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + case "$CC" in + '') ;; + *) break + ;; + esac + done + case "${CC}" in + '') + { echo "configure: error: "Could not find C compiler"" 1>&2; exit 1; } + ;; + esac + ;; + esac + # + # On some systems, a discovered compiler nevertheless won't + # work (due to licensing, for example); thus, we check the + # compiler with a test program. + # + echo $ac_n "checking C compiler \"$CC\"""... $ac_c" 1>&6 +echo "configure:761: checking C compiler \"$CC\"" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""works" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""failed to compile test program" 1>&6 +fi +rm -f conftest* + + case "$CC" in + *gcc*) + GCC=yes # Expected by autoconf(1) macros + ;; + esac + case `uname -sr` in + 'HP-UX A.09'*) + cat >> confdefs.h <<\EOF +#define _HPUX_SOURCE 1 +EOF + + ;; + esac + + + echo $ac_n "checking how to make dependencies""... $ac_c" 1>&6 +echo "configure:797: checking how to make dependencies" >&5 + case `uname -s` in + IRIX*|OSF1) + CC_MAKEDEPEND='cc -M' + ;; + SunOS) + case `uname -r` in + 4*) + CC_MAKEDEPEND='cc -M' + ;; + 5*|*) + CC_MAKEDEPEND='cc -xM' + ;; + esac + ;; + ULTRIX) + case `uname -m` in + RISC) + CC_MAKEDEPEND='cc -M' + ;; + VAX) # Can't handle prototypes in netcdf.h + ;; + esac + ;; + AIX) # Writes to .u files rather than standard out + ;; + HP-UX) # Writes escaped newlines to standard error + ;; + esac + case "${CC_MAKEDEPEND}" in + '') + CC_MAKEDEPEND=false + ;; + esac + echo "$ac_t""$CC_MAKEDEPEND" 1>&6 + + + + case "${CXX-unset}" in + unset) + case `uname` in + AIX) + preferred_cxx='xlC' + ;; + esac + possible_cxxs="${preferred_cxx} CC cxx c++ g++ gcc" + ;; + '') echo "configure: warning: "Empty CXX variable"" 1>&2 + possible_cxxs= + ;; + *) possible_cxxs=$CXX + ;; + esac + case "${possible_cxxs}" in + '') CXX= + ;; + *) + ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + + for cxx in $possible_cxxs; do + # Extract the first word of "$cxx", so it can be a program name with args. +set dummy $cxx; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:865: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$cxx" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + case "$CXX" in + '') ;; + *) # On some systems, a discovered compiler nevertheless + # won't work (because it's a script to a non-existant + # executable, for example); thus, we check the + # compiler with a test program. We also test + # for and the standard C++ library + # because we need these to work. + # + echo $ac_n "checking C++ compiler \"$CXX\"""... $ac_c" 1>&6 +echo "configure:901: checking C++ compiler \"$CXX\"" >&5 + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < + int main() { + cout << ""; + return 0; + } + +EOF +if { (eval echo configure:916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + + echo "$ac_t""works" 1>&6 + break + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + + echo "configure: warning: $CXX failed on test program" 1>&2 + CXX= + unset ac_cv_prog_CXX + +fi +rm -fr conftest* +fi + + ;; + esac + done + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + case "${CXX}" in + '') echo "configure: warning: "Could not find working C++ compiler"" 1>&2 + echo "configure: warning: Setting CXX to the empty string" 1>&2 + ;; + esac + ;; + esac + case "${CXX}" in + '') echo "configure: warning: The C++ interface will not be built" 1>&2 + ;; + esac + + case `uname` in + 'HP-UX A.09'*) + cat >> confdefs.h <<\EOF +#define _HPUX_SOURCE 1 +EOF + + ;; + esac + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:967: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:988: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1005: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1022: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + + + + case "${FC+set}" in + set) + case "$FC" in + '') + echo "configure: warning: Fortran-77 compiler is explicitly null" 1>&2 + ;; + *) + echo $ac_n "checking user-defined Fortran-77 compiler \"$FC\"""... $ac_c" 1>&6 +echo "configure:1056: checking user-defined Fortran-77 compiler \"$FC\"" >&5 + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if { (eval echo configure:1062: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""works" 1>&6 + else + echo "$ac_t""failed to compile test program" 1>&6 + FC= + fi + rm -f conftest.* + ;; + esac + ;; + *) + case "${F90+set}" in + set) + FC=$F90 + FFLAGS="${FFLAGS-${F90FLAGS--O}}" + FLIBS="${FLIBS-${F90LIBS-}}" + echo $ac_n "checking \"$FC\" as Fortran-77 compiler""... $ac_c" 1>&6 +echo "configure:1079: checking \"$FC\" as Fortran-77 compiler" >&5 + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if { (eval echo configure:1085: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""works" 1>&6 + else + echo "$ac_t""failed to compile test program" 1>&6 + unset FC + fi + rm -f conftest.* + ;; + esac + case "${FC-unset}" in + unset) + case `uname -sr` in + AIX*) + # xlf90(1) thinks fortran/ftest.F has bad syntax. + forts="xlf f77" + ;; + BSD/OS*|FreeBSD*) + forts="f77 fort77 g77" + ;; + HP-UX*) + # f77(1) doesn't have the -L option. + forts=fort77 + FLIBS=-lU77 + ;; + IRIX*) + # f90(1) can't link with c89(1)-compiled objects + forts=f77 + ;; + IRIX64*) + forts='f77 g77 fort77' + ;; + Linux*) + forts="f77 fort77 g77" + ;; + OSF1*) + # The use of f90(1) results in the following for + # an unknown reason (`make' works in the fortran/ + # directory): + # f90 -c -I../libsrc ftest.F + # Last chance handler: pc = 0xa971b8, + # sp = 0x3fece0, ra = 0xa971b8 + # Last chance handler: internal exception: unwinding + forts="f77" + ;; + 'SunOS 4'*) + forts='f77 g77 fort77' + ;; + 'SunOS 5'*) + # SunOS's f90(1) has problems passing a C `char' + # as a Fortran `integer*1' => use f77(1) + forts="f77" + ;; + sn*|UNICOS*|unicos*) + forts="fort77 cf77 f77 g77 f90" + ;; + *) + forts="xlf fort77 ghf77 f77 cf77 g77 xlf90 f90" + ;; + esac + for fc in $forts; do + # Extract the first word of "$fc", so it can be a program name with args. +set dummy $fc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1148: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_FC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$FC"; then + ac_cv_prog_FC="$FC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_FC="$fc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +FC="$ac_cv_prog_FC" +if test -n "$FC"; then + echo "$ac_t""$FC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + case "${FC}" in + '') + ;; + *) + # + # On some systems, a discovered compiler + # nevertheless won't work (due to licensing, + # for example); thus, we check the compiler + # with a test program. + # + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if { (eval echo configure:1189: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + break + else + echo "$ac_t""failed to compile test program" 1>&6 + unset FC + unset ac_cv_prog_FC + fi + ;; + esac + done + rm -f conftest.* + case "${FC}" in + '') echo "configure: warning: "Could not find working Fortran-77 compiler"" 1>&2 + ;; + esac + ;; + esac + ;; + esac + case "${FC}" in + '') echo "configure: warning: "The Fortran-77 interface will not be built"" 1>&2 + ;; + esac + + + + # + # Set the make(1) macro for compiling a .F file. + # + case "${FPP-}" in + '') + echo $ac_n "checking for Fortran .F compiler""... $ac_c" 1>&6 +echo "configure:1221: checking for Fortran .F compiler" >&5 + echo "$ac_t""$COMPILE_F" 1>&6 + case "${COMPILE_F-unset}" in + unset) + case "${FC}" in + '') + COMPILE_F= + ;; + *) + echo $ac_n "checking if Fortran-77 compiler handles *.F files""... $ac_c" 1>&6 +echo "configure:1231: checking if Fortran-77 compiler handles *.F files" >&5 + cat >conftest.h <<\EOF +#define J 1 +EOF + cat >conftest.F <<\EOF +#include "conftest.h" +#define N 5 + real r(J,N) + end +EOF + doit='$FC -o conftest ${FFLAGS} conftest.F ${FLIBS}' + if { (eval echo configure:1242: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + COMPILE_F='$(COMPILE.f) $(FPPFLAGS)' + echo "$ac_t""yes" 1>&6 + else + COMPILE_F= + echo "$ac_t""no" 1>&6 + fi + rm -f conftest* + ;; + esac + ;; + esac + ;; + *) + unset COMPILE_F + ;; + esac + case "${COMPILE_F-}" in + '') + echo $ac_n "checking for Fortran preprocessor""... $ac_c" 1>&6 +echo "configure:1262: checking for Fortran preprocessor" >&5 + case "$FPP" in + '') + + FPP="$CPP" + ;; + esac + echo "$ac_t""$FPP" 1>&6 + +;; + esac + + FPPFLAGS=${FPPFLAGS-} + + + + case "${F90+set}" in + set) + echo $ac_n "checking user-defined Fortran-90 compiler \"$F90\"""... $ac_c" 1>&6 +echo "configure:1281: checking user-defined Fortran-90 compiler \"$F90\"" >&5 + cat <conftest.f90 + subroutine foo(bar) + integer, intent(in) :: bar + end subroutine foo +EOF + doit='$F90 -c ${F90FLAGS} conftest.f90' + if { (eval echo configure:1288: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""works" 1>&6 + else + echo "$ac_t""failed to compile test program" 1>&6 + unset F90 + fi + rm -f conftest.* + ;; + *) + case "${FC+set}" in + set) + F90=$FC + F90FLAGS="${F90FLAGS-${FFLAGS--O}}" + F90LIBS="${F90LIBS-${FLIBS}}" + cat <conftest.f90 + program foo + call bar(1) + end program foo + subroutine bar(bof) + integer, intent(in) :: bof + end subroutine bar +EOF + echo $ac_n "checking \"$F90\" as Fortran-90 compiler""... $ac_c" 1>&6 +echo "configure:1311: checking \"$F90\" as Fortran-90 compiler" >&5 + doit='$F90 -o conftest ${F90FLAGS} conftest.f90 ${F90LIBS}' + if { (eval echo configure:1313: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1315: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""works" 1>&6 + else + echo "$ac_t""failed to build executable program" 1>&6 + unset F90 + fi + else + echo "$ac_t""failed to build test program" 1>&6 + unset F90 + fi + rm -f conftest* + ;; + esac + case "${F90-unset}" in + unset) + cat <conftest.f90 + program foo + call bar(1) + end program foo + subroutine bar(bof) + integer, intent(in) :: bof + end subroutine bar +EOF + for f90 in xlf90 f90; do + # Extract the first word of "$f90", so it can be a program name with args. +set dummy $f90; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1342: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_F90'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$F90"; then + ac_cv_prog_F90="$F90" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_F90="$f90" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +F90="$ac_cv_prog_F90" +if test -n "$F90"; then + echo "$ac_t""$F90" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + case "${F90}" in + '') + ;; + *) + echo $ac_n "checking Fortran-90 compiler \"$F90\"""... $ac_c" 1>&6 +echo "configure:1373: checking Fortran-90 compiler \"$F90\"" >&5 + doit='$F90 -o conftest ${F90FLAGS} conftest.f90 ${F90LIBS}' + if { (eval echo configure:1375: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1377: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""works" 1>&6 + break; + else + echo "$ac_t""failed to build executable program" 1>&6 + unset F90 + unset ac_cv_prog_F90 + fi + else + echo "$ac_t""failed to build test program" 1>&6 + unset F90 + unset ac_cv_prog_F90 + fi + ;; + esac + done + rm -f conftest* + case "${F90}" in + '') echo "configure: warning: "Could not find working Fortran-90 compiler"" 1>&2 + ;; + esac + ;; + esac + ;; + esac + case "${F90}" in + '') + echo "configure: warning: "The Fortran-90 interface will not be built"" 1>&2 + ;; + *f90*) + case `uname -s` in + IRIX*) + NETCDF_MOD=NETCDF.mod + ;; + *) + NETCDF_MOD=netcdf.mod + ;; + esac + + ;; + esac + + + + + + echo "checking for nm utility" 1>&6 +echo "configure:1424: checking for nm utility" >&5 + case "${NM-unset}" in + unset) for ac_prog in nm +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1431: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_NM="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +NM="$ac_cv_prog_NM" +if test -n "$NM"; then + echo "$ac_t""$NM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$NM" && break +done +test -n "$NM" || NM="nm" + ;; + *) for ac_prog in $NM nm +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1466: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_NM="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +NM="$ac_cv_prog_NM" +if test -n "$NM"; then + echo "$ac_t""$NM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$NM" && break +done +test -n "$NM" || NM="nm" + ;; + esac + echo $ac_n "checking nm flags""... $ac_c" 1>&6 +echo "configure:1498: checking nm flags" >&5 + case "${NMFLAGS-unset}" in + unset) NMFLAGS= ;; + esac + echo "$ac_t""$NMFLAGS" 1>&6 + + + + + case "$FC" in + '') ;; + *) + + + + echo $ac_n "checking for C-equivalent to Fortran routine \"SUB\"""... $ac_c" 1>&6 +echo "configure:1514: checking for C-equivalent to Fortran routine \"SUB\"" >&5 + cat >conftest.f <<\EOF + call sub() + end +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if { (eval echo configure:1520: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + FCALLSCSUB=`$NM $NMFLAGS conftest.o | awk ' + /SUB_/{print "SUB_";exit} + /SUB/ {print "SUB"; exit} + /sub_/{print "sub_";exit} + /sub/ {print "sub"; exit}'` + case "$FCALLSCSUB" in + '') { echo "configure: error: not found" 1>&2; exit 1; } + ;; + *) echo "$ac_t""$FCALLSCSUB" 1>&6 + ;; + esac + else + { echo "configure: error: Could not compile conftest.f" 1>&2; exit 1; } + fi + rm -f conftest* + ;; + esac + + + + case "$FC" in + '') + ;; + *) + + + for ftype in byte integer*1 "integer(kind(1))"; do + echo $ac_n "checking for Fortran \"$ftype\"""... $ac_c" 1>&6 +echo "configure:1549: checking for Fortran \"$ftype\"" >&5 + cat >conftest.f <&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + NF_INT1_T=$ftype + cat >> confdefs.h <&6 + fi + done + rm -f conftest* + + + for ftype in integer*2 "integer(kind(2))"; do + echo $ac_n "checking for Fortran \"$ftype\"""... $ac_c" 1>&6 +echo "configure:1573: checking for Fortran \"$ftype\"" >&5 + cat >conftest.f <&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + NF_INT2_T=$ftype + cat >> confdefs.h <&6 + fi + done + rm -f conftest* + + + case "${NF_INT1_T}" in + '') ;; + *) + cat >conftestf.f <&6 +echo "configure:1606: checking if Fortran \"$NF_INT1_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1617: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1619: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1621: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1654: checking if Fortran \"$NF_INT1_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1665: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1667: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1669: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1702: checking if Fortran \"$NF_INT1_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1713: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1715: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1717: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1750: checking if Fortran \"$NF_INT1_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1761: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1763: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1765: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + ;; + esac + case "${NF_INT2_T}" in + '') ;; + *) + cat >conftestf.f <&6 +echo "configure:1802: checking if Fortran \"$NF_INT2_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1813: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1815: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1817: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1850: checking if Fortran \"$NF_INT2_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1861: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1863: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1865: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1898: checking if Fortran \"$NF_INT2_T\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1909: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1911: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1913: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + ;; + esac + + cat >conftestf.f <&6 +echo "configure:1948: checking if Fortran \"integer\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:1959: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:1961: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:1963: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:1996: checking if Fortran \"real\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:2007: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:2009: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:2011: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + cat >conftestf.f <&6 +echo "configure:2044: checking if Fortran \"doubleprecision\" is C \"$ctype\"" >&5 + cat >conftest.c <&5; (eval $doit) 2>&5; }; then + doit='$FC ${FFLAGS} -c conftestf.f' + if { (eval echo configure:2055: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit='$FC -o conftest ${FFLAGS} ${FLDFLAGS} conftestf.o conftest.o ${LIBS}' + if { (eval echo configure:2057: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + doit=./conftest + if { (eval echo configure:2059: \"$doit\") 1>&5; (eval $doit) 2>&5; }; then + echo "$ac_t""yes" 1>&6 + cname=`echo $ctype | tr ' abcdefghijklmnopqrstuvwxyz' \ + _ABCDEFGHIJKLMNOPQRSTUVWXYZ` + cat >> confdefs.h <&6 + fi + else + { echo "configure: error: Could not link conftestf.o and conftest.o" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftestf.f" 1>&2; exit 1; } + fi + else + { echo "configure: error: Could not compile conftest.c" 1>&2; exit 1; } + fi + done + rm -f conftest* + + + + echo $ac_n "checking for Fortran-equivalent to netCDF \"byte\"""... $ac_c" 1>&6 +echo "configure:2086: checking for Fortran-equivalent to netCDF \"byte\"" >&5 + for type in byte integer*1 integer; do + cat >conftest.f <&5; (eval $doit) 2>&5; }; then + break; + fi + done + rm -f conftest.f conftest.o + cat >> confdefs.h <&6 + NCBYTE_T=$type + + + + echo $ac_n "checking for Fortran-equivalent to netCDF \"short\"""... $ac_c" 1>&6 +echo "configure:2108: checking for Fortran-equivalent to netCDF \"short\"" >&5 + for type in integer*2 integer; do + cat >conftest.f <&5; (eval $doit) 2>&5; }; then + break; + fi + done + rm -f conftest.f conftest.o + cat >> confdefs.h <&6 + NCSHORT_T=$type + + + + + ;; + esac + + + echo "checking for math library" 1>&6 +echo "configure:2135: checking for math library" >&5 + case "${MATHLIB}" in + '') + echo $ac_n "checking for tanh in -lc""... $ac_c" 1>&6 +echo "configure:2139: checking for tanh in -lc" >&5 +ac_lib_var=`echo c'_'tanh | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MATHLIB= +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for tanh in -lm""... $ac_c" 1>&6 +echo "configure:2177: checking for tanh in -lm" >&5 +ac_lib_var=`echo m'_'tanh | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lm $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MATHLIB=-lm +else + echo "$ac_t""no" 1>&6 +MATHLIB= +fi + +fi + + ;; + *) + echo "$ac_t""$MATHLIB (user defined)" 1>&6 + ;; + esac + + + + echo "checking for ar utility" 1>&6 +echo "configure:2228: checking for ar utility" >&5 + case "${AR-unset}" in + unset) for ac_prog in ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2235: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="ar" + ;; + *) for ac_prog in $AR ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2270: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="ar" + ;; + esac + echo $ac_n "checking ar flags""... $ac_c" 1>&6 +echo "configure:2302: checking ar flags" >&5 + case "${ARFLAGS-unset}" in + unset) ARFLAGS=cru ;; + esac + echo "$ac_t""$ARFLAGS" 1>&6 + + + + echo "checking for nm utility" 1>&6 +echo "configure:2311: checking for nm utility" >&5 + case "${NM-unset}" in + unset) for ac_prog in nm +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2318: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_NM="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +NM="$ac_cv_prog_NM" +if test -n "$NM"; then + echo "$ac_t""$NM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$NM" && break +done +test -n "$NM" || NM="nm" + ;; + *) for ac_prog in $NM nm +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2353: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_NM="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +NM="$ac_cv_prog_NM" +if test -n "$NM"; then + echo "$ac_t""$NM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$NM" && break +done +test -n "$NM" || NM="nm" + ;; + esac + echo $ac_n "checking nm flags""... $ac_c" 1>&6 +echo "configure:2385: checking nm flags" >&5 + case "${NMFLAGS-unset}" in + unset) NMFLAGS= ;; + esac + echo "$ac_t""$NMFLAGS" 1>&6 + + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2395: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +ac_safe=`echo "stdlib.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for stdlib.h""... $ac_c" 1>&6 +echo "configure:2424: checking for stdlib.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2434: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define NO_STDLIB_H 1 +EOF + +fi + +ac_safe=`echo "sys/types.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/types.h""... $ac_c" 1>&6 +echo "configure:2461: checking for sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2471: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define NO_SYS_TYPES_H 1 +EOF + +fi + +echo $ac_n "checking for strerror""... $ac_c" 1>&6 +echo "configure:2497: checking for strerror" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strerror'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char strerror(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_strerror) || defined (__stub___strerror) +choke me +#else +strerror(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2525: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_strerror=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_strerror=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'strerror`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +cat >> confdefs.h <<\EOF +#define NO_STRERROR 1 +EOF + +fi + + + echo $ac_n "checking for working ftruncate()""... $ac_c" 1>&6 +echo "configure:2550: checking for working ftruncate()" >&5 + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#include +#include +#include +#include +main() +{ + char* path = tmpnam(NULL); + int exitStatus = 1; + + if (path != NULL) + { + int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); + + if (fd != -1) + { + if (write(fd, "0", 1) == 1) + { + off_t pos = lseek(fd, 0, SEEK_CUR); + + if (pos != (off_t)-1) + { + if (ftruncate(fd, 512) != -1) + { + if (pos == lseek(fd, 0, SEEK_CUR)) + { + if (lseek(fd, 0, SEEK_SET) == 0) + { + char buf[512]; + + if (read(fd, buf, 512) == 512) + exitStatus = 0; + } + } + } + } + } + close(fd); + unlink(path); + } + } + + return exitStatus; +} + +EOF +if { (eval echo configure:2603: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_FTRUNCATE 1 +EOF + + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + echo "$ac_t""no" 1>&6 + +fi +rm -fr conftest* +fi + + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:2625: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:2637: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:2658: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:2691: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:2723: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2753: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2781: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:2808: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext < addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:2835: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2857: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:2870: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + + +echo $ac_n "checking for IEEE floating point format""... $ac_c" 1>&6 +echo "configure:2892: checking for IEEE floating point format" >&5 +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#endif + +#define EXIT_NOTIEEE 1 +#define EXIT_MAYBEIEEE 0 + +int +main() +{ +#if defined(FLT_RADIX) && FLT_RADIX != 2 + return EXIT_NOTIEEE; +#elif defined(DBL_MAX_EXP) && DBL_MAX_EXP != 1024 + return EXIT_NOTIEEE; +#elif defined(DBL_MANT_DIG) && DBL_MANT_DIG != 53 + return EXIT_NOTIEEE; +#elif defined(FLT_MAX_EXP) && !(FLT_MAX_EXP == 1024 || FLT_MAX_EXP == 128) + return EXIT_NOTIEEE; +#elif defined(FLT_MANT_DIG) && !(FLT_MANT_DIG == 53 || FLT_MANT_DIG == 24) + return EXIT_NOTIEEE; +#else + /* (assuming eight bit char) */ + if(sizeof(double) != 8) + return EXIT_NOTIEEE; + if(!(sizeof(float) == 4 || sizeof(float) == 8)) + return EXIT_NOTIEEE; + + return EXIT_MAYBEIEEE; +#endif +} +EOF +if { (eval echo configure:2930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_ieeefloat=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_ieeefloat=no +fi +rm -fr conftest* +fi + +echo "$ac_t""$ac_cv_c_ieeefloat" 1>&6 +if test $ac_cv_c_ieeefloat = no; then + cat >> confdefs.h <<\EOF +#define NO_IEEE_FLOAT 1 +EOF + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2951: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2964: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:3031: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:3055: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:3088: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for ssize_t""... $ac_c" 1>&6 +echo "configure:3121: checking for ssize_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ssize_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])ssize_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_ssize_t=yes +else + rm -rf conftest* + ac_cv_type_ssize_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_ssize_t" 1>&6 +if test $ac_cv_type_ssize_t = no; then + cat >> confdefs.h <<\EOF +#define ssize_t int +EOF + +fi + +echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:3154: checking for ptrdiff_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_ptrdiff_t=yes +else + rm -rf conftest* + ac_cv_type_ptrdiff_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6 +if test $ac_cv_type_ptrdiff_t = no; then + cat >> confdefs.h <<\EOF +#define ptrdiff_t int +EOF + +fi + +echo $ac_n "checking for uchar""... $ac_c" 1>&6 +echo "configure:3187: checking for uchar" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uchar'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])uchar[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uchar=yes +else + rm -rf conftest* + ac_cv_type_uchar=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_uchar" 1>&6 +if test $ac_cv_type_uchar = no; then + cat >> confdefs.h <<\EOF +#define uchar unsigned char +EOF + +fi + +echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 +echo "configure:3220: checking whether char is unsigned" >&5 +if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$GCC" = yes; then + # GCC predefines this symbol on systems where it applies. +cat > conftest.$ac_ext <&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_c_char_unsigned=yes +else + rm -rf conftest* + ac_cv_c_char_unsigned=no +fi +rm -f conftest* + +else +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_char_unsigned=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_char_unsigned=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_char_unsigned" 1>&6 +if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then + cat >> confdefs.h <<\EOF +#define __CHAR_UNSIGNED__ 1 +EOF + +fi + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:3283: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext < +#include +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:3301: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext < +#include +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:3316: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +echo $ac_n "checking size of short""... $ac_c" 1>&6 +echo "configure:3373: checking size of short" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +int main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) return(1); + fprintf(f, "%d\n", sizeof(short)); + return(0); +} +EOF +if { (eval echo configure:3392: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_short=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_short=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_short" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3412: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +int main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) return(1); + fprintf(f, "%d\n", sizeof(int)); + return(0); +} +EOF +if { (eval echo configure:3431: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3451: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +int main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) return(1); + fprintf(f, "%d\n", sizeof(long)); + return(0); +} +EOF +if { (eval echo configure:3470: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3490: checking size of float" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_float'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +int main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) return(1); + fprintf(f, "%d\n", sizeof(float)); + return(0); +} +EOF +if { (eval echo configure:3509: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_float=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_float=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_float" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3529: checking size of double" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_double'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +int main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) return(1); + fprintf(f, "%d\n", sizeof(double)); + return(0); +} +EOF +if { (eval echo configure:3548: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_double=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_double=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_double" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3568: checking size of off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_sizeof_off_t=0 +else + cat > conftest.$ac_ext < +#include +#if STDC_HEADERS +#include +#endif +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(off_t)); + exit(0); +} +EOF +if { (eval echo configure:3591: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_off_t=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_off_t=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_off_t" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3611: checking size of size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_sizeof_size_t=0 +else + cat > conftest.$ac_ext < +#include +#if STDC_HEADERS +#include +#endif +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(size_t)); + exit(0); +} +EOF +if { (eval echo configure:3634: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_size_t=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_size_t=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_size_t" 1>&6 +cat >> confdefs.h <&6 +echo "configure:3693: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_prog'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$prog"; then + ac_cv_prog_prog="$prog" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_prog="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +prog="$ac_cv_prog_prog" +if test -n "$prog"; then + echo "$ac_t""$prog" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$prog" && break +done + + case "$prog" in + *catman*) + MAKEWHATIS_CMD=$prog' -w -M $(MANDIR)' + ;; + *makewhatis*) + MAKEWHATIS_CMD=$prog' $(MANDIR)' + ;; + esac + ;; + esac + + + echo $ac_n "checking for manual-page index command""... $ac_c" 1>&6 +echo "configure:3735: checking for manual-page index command" >&5 + echo "$ac_t""$MAKEWHATIS_CMD" 1>&6 + + echo $ac_n "checking binary distribution directory""... $ac_c" 1>&6 +echo "configure:3739: checking binary distribution directory" >&5 + case ${FTPBINDIR-unset} in + unset) + system=`(system) 2>/dev/null || echo dummy_system` + FTPBINDIR=${FTPDIR-/home/ftp}/pub/binary/$system + ;; + esac + echo "$ac_t""$FTPBINDIR" 1>&6 + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "macros.make src/lib/ncconfig.h:src/lib/ncconfig.in +" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@SRCDIR@%$SRCDIR%g +s%@M4@%$M4%g +s%@M4FLAGS@%$M4FLAGS%g +s%@CC@%$CC%g +s%@CC_MAKEDEPEND@%$CC_MAKEDEPEND%g +s%@CXX@%$CXX%g +s%@FC@%$FC%g +s%@FLIBS@%$FLIBS%g +s%@CPP@%$CPP%g +s%@FPP@%$FPP%g +s%@COMPILE_F@%$COMPILE_F%g +s%@FPPFLAGS@%$FPPFLAGS%g +s%@F90@%$F90%g +s%@NETCDF_MOD@%$NETCDF_MOD%g +s%@F90FLAGS@%$F90FLAGS%g +s%@F90LIBS@%$F90LIBS%g +s%@NM@%$NM%g +s%@NMFLAGS@%$NMFLAGS%g +s%@MATHLIB@%$MATHLIB%g +s%@AR@%$AR%g +s%@ARFLAGS@%$ARFLAGS%g +s%@RANLIB@%$RANLIB%g +s%@ALLOCA@%$ALLOCA%g +s%@prog@%$prog%g +s%@WHATIS@%$WHATIS%g +s%@MAKEWHATIS_CMD@%$MAKEWHATIS_CMD%g +s%@FTPBINDIR@%$FTPBINDIR%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + + + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + Index: /branches/SDM_SciDAC/doc/netcdf-api.bbl =================================================================== --- /branches/SDM_SciDAC/doc/netcdf-api.bbl (revision 2) +++ /branches/SDM_SciDAC/doc/netcdf-api.bbl (revision 2) @@ -0,0 +1,10 @@ +\begin{thebibliography}{1} + +\bibitem{thakur:romio} +Rajeev Thakur, William Gropp, and Ewing Lusk. +\newblock Data sieving and collective {I/O} in {ROMIO}. +\newblock In {\em Proceedings of the Seventh Symposium on the Frontiers of + Massively Parallel Computation}, pages 182--189. IEEE Computer Society Press, + February 1999. + +\end{thebibliography} Index: /branches/SDM_SciDAC/doc/netcdf-api.tex =================================================================== --- /branches/SDM_SciDAC/doc/netcdf-api.tex (revision 2) +++ /branches/SDM_SciDAC/doc/netcdf-api.tex (revision 2) @@ -0,0 +1,994 @@ +\documentclass[10pt]{article} +\usepackage{utopia} + +\pagestyle{plain} + +\addtolength{\hoffset}{-2cm} +\addtolength{\textwidth}{4cm} + +\addtolength{\voffset}{-1.5cm} +\addtolength{\textheight}{3cm} + +\setlength{\parindent}{0pt} +\setlength{\parskip}{11pt} + +\title{A Parallel API for Creating and Reading NetCDF Files} + +\begin{document} + +\maketitle + +\begin{abstract} +Scientists recognize the importance of portable and efficient mechanisms for +storing datasets created and used by their applications. NetCDF is one such +mechanism and is popular in a number of applicaiton domains because of its +availability on a wide variety of platforms and its easy to use API. However, +this API was originally designed for use in serial codes, and so the semantics +of the interface are not designed to allow for high performance parallel +access. + +In this work we present a new API for creating and reading NetCDF datasets, +the \emph{Parallel NetCDF API}. This interface builds on the original NetCDF +interface and defines semantics for parallel access to NetCDF datasets. The +interface is built on top of MPI-IO, allowing for further performance gains +through the use of collective I/O optimizations that already exist in MPI-IO +implementations. + +\end{abstract} + +\section{Introduction} + +NetCDF is a popular package for storing data files in scientific applications. +NetCDF consists of both an API and a portable file format. The API provides a +consistent interface for access NetCDF files across multiple platforms, while +the NetCDF file format guarantees data portability. + +The NetCDF API provides a convenient mechanism for a single process to define +and access variables and attributes in a NetCDF file. However, it does not +define a parallel access mechanism. In particular there is no mechanism for +concurrently writing to a NetCDF data file. Because of this, parallel +applications operating on NetCDF files must serialize access. This is +typically accomplished by shipping all data to and from a single process that +performs NetCDF operations. This mode of access is both cumbersome to the +application programmer and considerably slower than parallel access to the +NetCDF file. This mode can be particularly inconvenient when data set sizes +exceed the size of available memory on a single node; in this case the data +must be split into pieces to be shipped and written. + +In this document we propose an alternative API for accessing NetCDF format +files in a parallel application. This API allows all processes in a parallel +application to access the NetCDF file simultaneously, which is considerably +more convenient than the serial API and allows for significantly higher +performance. + +\emph{Note subset of interface that we are implementing, including both what +types we support and any functions that we might be leaving out.} + +\section{Preliminaries} + +In MPI, communicators are typically used to describe collections of processes +to MPI calls (e.g. the collective MPI-1 calls). In our parallel NetCDF API we +will similarly use a communicator to denote a collection of MPI processes that +will access a NetCDF file. By describing this collection of processes, we +provide the underlying implementation (of our parallel NetCDF API) with +information that it can use to ensure that the file is kept in a consistent +state. + +Further, by using the collective operations provided in our parallel NetCDF +API (ones in which all processes in this collection participate), application +programmers provide the underlying implementation with an opportunity to +further optimize access to the NetCDF file. These optimizations are performed +without further intervention by the application programmer and have been +proven to provide huge performance wins in multidimensional dataset access \cite{thakur:romio}, +exactly the kinds of accesses used in NetCDF. + +All this said, the original NetCDF interface is made available with a minimum +of changes so that users migrating from the original NetCDF interface will +have little trouble moving to this new, parallel NetCDF interface. + +The decision to slightly modify the API was not made lightly. It is +relatively trivial to port NetCDF to use MPI-IO through the use of the MPI-IO +independent access calls. However, it was only though adding this concept of +a collection of processes simultaneously accessing the file and adding +collective access semantics that we could hope to eliminate the serialization +step necessary in the original API or gain the performance advantages +available from the use of collective optimizations. Thus our performance +requirements mandated these small adjustments. + +% Finally, some of the calls in our API utilize MPI datatypes. These datatypes +% allow one to describe noncontiguous regions of data (in this case memory +% regions) as an endpoint of a data transfer. + +\section{Parallel NetCDF API} + +The NetCDF interface breaks access into two \emph{modes}, ``define'' mode and +``data'' mode. The define mode is used to describe the data set to be stored, +while the data mode is used for storing and retrieving data values. + +We maintain these modes and (for the most part) maintain the operations when +in define mode. We will discuss the API for opening and closing a dataset and +for moving between modes first, next cover inquiry functions, then cover the +define mode, attribute functions, and finally discuss the API for data mode. + +% +% PREFIX +% +We will prefix our C interface calls with ``ncmpi'' and our Fortran interface +calls with ``nfmpi''. This ensures no naming clashes with existing NetCDF +libraries and does not conflict with the desire to reserve the ``MPI'' prefix +for functions that are part of the MPI standard. + +All of our functions return integer NetCDF status values, just as the original +NetCDF interface does. + +We will only discuss points where our interface deviates from the original +interface in the following sections. A complete function listing is included +in Appendix A. + +\subsection{Variable and Parameter Types} + +% +% MPI_Offset +% +Rather than using \texttt{size\_t} types for size parameters passed in to our +functions, we choose to use \texttt{MPI\_Offset} type instead. For many +systems \texttt{size\_t} is a 32-bit unsigned value, which limits the maximum +range of values to 4~GBytes. The \texttt{MPI\_Offset} is typically a 64-bit +value, so it does not have this limitation. This gives us room to extend the +file size capabilities of NetCDF at a later date. + +\emph{Add mapping of MPI types to NetCDF types.} + +\emph{Is NetCDF already exactly in external32 format?} + +\subsection{Dataset Functions} + +As mentioned before, we will define a collection of processes that are +operating on the file by passing in a MPI communicator. This communicator is +passed in the call to \texttt{ncmpi\_create} or \texttt{ncmpi\_open}. These +calls are collective across all processes in the communicator. The second +additional parameter is an \texttt{MPI\_Info}. This is used to pass hints in +to the implementation (e.g. expected access pattern, aggregation +information). The value \texttt{MPI\_INFO\_NULL} may be passed in if the user +does not want to take advantage of this feature. + +\begin{verbatim} +int ncmpi_create(MPI_Comm comm, + const char *path, + int cmode, + MPI_Info info, + int *ncidp) + +int ncmpi_open(MPI_Comm comm, + const char *path, + int omode, + MPI_Info info, + int *ncidp) +\end{verbatim} + +\subsection{Define Mode Functions} + +\emph{All define mode functions are collective} (see Appendix B for +rationale). + +All processes in the communicator must call them with the same values. At the +end of the define mode the values passed in by all processes are checked to +verify that they match, and if they do not then an error is returned from the +\texttt{ncmpi\_enddef}. + + +\subsection{Inquiry Functions} + +\emph{These calls are all collective operations} (see Appendix B for +rationale). + +As in the original NetCDF interface, they may be called from either define or +data mode. \emph{ They return information stored prior to the last open, +enddef, or sync.} + +% In the original NetCDF interface the inquiry functions could be called from +% either data or define mode. To aid in the implementation of these functions +% in a parallel library, \emph{inquiry functions may only be called in data mode +% in the parallel NetCDF API}. They return information stored prior to the last +% open, enddef, or sync. This ensures that the NetCDF metadata need only be +% kept up-to-date on all nodes when in data mode. +% + +\subsection{Attribute Functions} + +\emph{These calls are all collective operations} (see Appendix B for +rationale). + +Attributes in NetCDF are intended for storing scalar or vector values that +describe a variable in some way. As such the expectation is that these +attributes will be small enough to fit into memory. + +In the original interface, attribute operations can be performed in either +define or data mode; however, it is possible for attribute operations that +modify attributes (e.g. copy or create attributes) to fail if in data mode. +This is possible because such operations can cause the amount of space needed +to grow. In this case the cost of the operation can be on the order of a copy +of the entire dataset. We will maintain these semantics. + +\subsection{Data Mode Functions} + +The most important change from the original NetCDF interface with respect to +data mode functions is the split of data mode into two distinct modes: +\emph{collective data mode} and \emph{independent data mode}. \emph{By default when +a user calls \texttt{ncmpi\_enddef} or \texttt{ncmpi\_open}, the user will be +in collective data mode.} The expectation is that most users will be using the +collective operations; these users will never need to switch to independent +data mode. In collective data mode, all processes must call the same function +on the same ncid at the same point in the code. Different parameters for +values such as start, count, and stride, are acceptable. Knowledge that all +processes will be calling the function allows for additional optimization +under the API. In independent mode processes do not need to coordinate calls +to the API; however, this limits the optimizations that can be applied to I/O operations. + +A pair of new dataset operations \texttt{ncmpi\_begin\_indep\_data} and +\texttt{ncmpi\_end\_indep\_data} switch into and out of independent data mode. +These calls are collective. Calling \texttt{ncmpi\_close} or +\texttt{ncmpi\_redef} also leaves independent data mode. + +\begin{verbatim} +int ncmpi_begin_indep_data(int ncid) + +int ncmpi_end_indep_data(int ncid) +\end{verbatim} + +The separation of the data mode into two distinct data modes is necessary to +provide consistent views of file data when moving between MPI-IO collective +and independent operations. + +We have chosen to implement two collections of data mode functions. The first +collection closely mimics the original NetCDF access functions and is intended +to serve as an easy path of migration from the original NetCDF interface to +the parallel NetCDF interface. We call this subset of our parallel NetCDF +interface the \emph{high level data mode} interface. + +The second collection uses more MPI functionality in order to provide better +handling of internal data representations and to more fully expose the +capabilities of MPI-IO to the application programmer. All of the first +collection will be implemented in terms of these calls. We will denote this +the \emph{flexible data mode} interface. + +In both collections, both independent and collective operations are provided. +Collective function names end with \texttt{\_all}. They are collective across +the communicator associated with the ncid, so all those processes must call +the function at the same time. + +Remember that in all cases the input data type is converted into the +appropriate type for the variable stored in the NetCDF file. + +\subsubsection{High Level Data Mode Interface} + +The independent calls in this interface closely resemble the NetCDF data mode +interface. The only major change is the use of \texttt{MPI\_Offset} types in +place of \texttt{size\_t} types, as described previously. + +The collective calls have the same arguments as their independent +counterparts, but they must be called by all processes in the communicator +associated with the ncid. + +Here are the example prototypes for accessing a strided subarray of a variable +in a NetCDF file; the remainder of the functions are listed in Appendix A. + +In our initial implementation the following data function types will be +implemented for independent access: single data value read and write (var1), +entire variable read and write (var), array of values read and write (vara), +and subsampled array of values read and write (vars). Collective versions of +these types will also be provided, with the exception of a collective entire +variable write; semantically this doesn't make sense. + +We could use the same function names for both independent and collective +operations (relying instead on the mode associated with the ncid); however, we +feel that the interface is cleaner, and it will be easier to detect bugs, with +separate calls for independent and collective access. + +% \textbf{Strided Subarray Access} +% +Independent calls for writing or reading a strided subarray of values to/from +a NetCDF variable (values are contiguous in memory): +\begin{verbatim} +int ncmpi_put_vars_uchar(int ncid, + int varid, + const MPI_Offset start[], + const MPI_Offset count[], + const MPI_Offset stride[], + const unsigned char *up) + +int ncmpi_get_vars_uchar(int ncid, + int varid, + const MPI_Offset start[], + const MPI_Offset count[], + const MPI_Offset stride[], + unsigned char *up) +\end{verbatim} + +Collective calls for writing or reading a strided subarray of values to/from a +NetCDF variable (values are contiguous in memory). +\begin{verbatim} +int ncmpi_put_vars_uchar_all(int ncid, + int varid, + const MPI_Offset start[], + const MPI_Offset count[], + const MPI_Offset stride[], + unsigned char *up) + +int ncmpi_get_vars_uchar_all(int ncid, + int varid, + const MPI_Offset start[], + const MPI_Offset count[], + const MPI_Offset stride[], + unsigned char *up) +\end{verbatim} + +\emph{Note what calls are and aren't implemented at this time.} + +\subsubsection{Flexible Data Mode Interface} + +This smaller set of functions is all that is needed to implement the data mode +functions. These are also made available to the application programmer. + +The advantage of these functions is that they allow the programmer to use MPI +datatypes to describe the in-memory organization of the values. The only +mechanism provides in the original NetCDF interface for such a description is +the mapped array calls. Mapped arrays are a suboptimal method of describing +any regular pattern in memory. + +In all these functions the varid, start, count, and stride values refer to the +data in the file (just as in a NetCDF vars-type call). The buf, count, and +datatype fields refer to data in memory. + +Here are examples for subarray access: +\begin{verbatim} +int ncmpi_put_vars(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + const void *buf, + int count, + MPI_Datatype datatype) + +int ncmpi_get_vars(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype) + +int ncmpi_put_vars_all(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype) + +int ncmpi_get_vars_all(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype) +\end{verbatim} + + +\subsubsection{Mapping Between NetCDF and MPI Types} + +It is assumed here that the datatypes passed to the flexible NetCDF interface +use only one basic datatype. For example, the datatype can be arbitrarily +complex, but it cannot consist of both \texttt{MPI\_FLOAT} and +\texttt{MPI\_INT} values, but only one of these basic types. + +\emph{Describe status of type support.} + + +\subsection{Missing} + +Calls that were in John M.'s list but that we haven't mentioned here yet. + +Attribute functions, strerror, text functions, get\_vara\_text (?). + +\section{Examples} + +This section will hopefully soon hold some examples, perhaps based on writing +out the 1D and 2D Jacobi examples in the Using MPI book using our interface? + +\section{Implementation Notes} + +Here we will keep any particular implementation details. As the +implementation matures, this section should discuss implementation decisions. + +One trend that will be seen throughout here is the use of collective I/O +routines when it would be possible to use independent operations. There are +two reasons for this. First, for some operations (such as reading the +header), there are important optimizations that can be made to more +efficiently read data from the I/O system, especially as the number of NetCDF +application processes increases. Second, the use of collective routines +allows for the use of aggregation routines in the MPI-IO implementation. This +allows us to redirect I/O to nodes that have access to I/O resources in +systems where not all processes have access. This isn't currently possible +using the independent I/O calls. + +See the ROMIO User's Guide for more information on the aggregation hints, in +particular the \texttt{cb\_config\_list} hint. + +\subsection{Questions for Users on Implementation} +\begin{itemize} +\item Is this emphasis on collective operations appropriate or problematic? +\item Is C or Fortran the primary language for NetCDF programs? +\end{itemize} + +\subsection{I/O routines} + +All I/O within our implementation will be performed through MPI-IO. + +No temporary files will be created at any time. + +% +% HEADER I/O +% +\subsection{Header I/O} + +\emph{It is assumed that headers are too small to benefit from parallel I/O.} + +All header updates will be performed with collective I/O, but only rank 0 will +provide any input data. This is important because only through the collective +calls can our \texttt{cb\_config\_list} hint be used to control what hosts +actually do writing. Otherwise we could pick some arbitrary process to do +I/O, but we have no way of knowing if that was a process that the user +intended to do I/O in the first place (thus that process might not even be +able to write to the file!) + +Headers are written all at once at \texttt{ncmpi\_enddef}. + +Likewise collective I/O will be used when reading the header, which should +simply be used to read the entire header to everyone on open. + +\emph{First cut might not do this.} + +\subsection{Code Reuse} +We will not reuse any NetCDF code. This will give us an opportunity to leave +out any code pertaining to optimizations on specific machines (e.g. Cray) that +we will not need and, more importantly, cannot test. + +\subsection{Providing Independent and Collective I/O} +In order to make use of \texttt{MPI\_File\_set\_view} for both independent and +collective NetCDF operations, we will need to open the NetCDF file separately +for both, with the input communicator for collective I/O and with +MPI\_COMM\_SELF for independent I/O. However, we can defer opening the file +for independent access until an independent access call is made if we like. +This can be an important optimization as we scale. + +Synchronization when switching between collective and independent access is +mandatory to ensure correctness under the MPI I/O model. + +\subsection{Outline of I/O} + +Outline of steps to I/O: +\begin{itemize} +\item MPI\_File is extracted from ncid +\item variable type is extracted from varid +\item file view is created from: + \begin{itemize} + \item metadata associated with ncid + \item variable index info, array size, limited/unlimited, type from varid + \item start/count/stride info + \end{itemize} +\item datatype/count must match number of elements specified by + start/count/stride +\item status returns normal mpi status information, which is mapped to a + NetCDF error code. +\end{itemize} + + +\section{Future Work} + +Since MPI-IO has the capability to perform nonblocking operations, it makes +sense to provide a NetCDF interface that exposes this capability: + +\begin{verbatim} +ncmpi_iput_vars(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype, + MPI_Request *request); + +ncmpi_iget_vars(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype, + MPI_Request *request); + +int ncmpi_wait(MPI_Request *request, + MPI_Status *status); + +int ncmpi_test(MPI_Request *request, + int *flag, + MPI_Status *status); +\end{verbatim} + +% +% BIBLIOGRAPHY +% +\bibliography{./pario} +\bibliographystyle{plain} + +% +% APPENDIX A: FUNCTION LISTING +% +\section*{Appendix A: C API Listing} + +% +% DATASET FUNCTIONS +% +\subsection*{A.1 Dataset Functions} + +\begin{verbatim} +int ncmpi_create(MPI_Comm comm, const char *path, int cmode, MPI_Info info, int *ncidp); + +int ncmpi_open(MPI_Comm comm, const char *path, int omode, MPI_Info info, int *ncidp); + +int ncmpi_enddef(int ncid); + +int ncmpi_redef(int ncid); + +int ncmpi_sync(int ncid); + +int ncmpi_abort(int ncid); + +int ncmpi_begin_indep_data(int ncid); + +int ncmpi_end_indep_data(int ncid); + +int ncmpi_close(int ncid); +\end{verbatim} + +% +% INQUIRY FUNCTIONS +% +\subsection*{A.2 Inquiry Functions} + +\begin{verbatim} +int ncmpi_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp); + +int ncmpi_inq_ndims(int ncid, int *ndimsp); + +int ncmpi_inq_nvars(int ncid, int *nvarsp); + +int ncmpi_inq_natts(int ncid, int *ngattsp); + +int ncmpi_inq_unlimdim(int ncid, int *unlimdimidp); + +int ncmpi_inq_dimid(int ncid, const char *name, int *idp); + +int ncmpi_inq_dim(int ncid, int dimid, char *name, MPI_Offset *lenp); + +int ncmpi_inq_dimname(int ncid, int dimid, char *name); + +int ncmpi_inq_dimlen(int ncid, int dimid, MPI_Offset *lenp); + +int ncmpi_inq_var(int ncid, int varid, char *name, nc_type *xtypep, + int *ndimsp, int *dimidsp, int *nattsp); + +int ncmpi_inq_varid(int ncid, const char *name, int *varidp); + +int ncmpi_inq_varname(int ncid, int varid, char *name); + +int ncmpi_inq_vartype(int ncid, int varid, nc_type *xtypep); + +int ncmpi_inq_varndims(int ncid, int varid, int *ndimsp); + +int ncmpi_inq_vardimid(int ncid, int varid, int *dimidsp); + +int ncmpi_inq_varnatts(int ncid, int varid, int *nattsp); + +\end{verbatim} + +% +% DEFINE FUNCTIONS +% +\subsection*{A.3 Define Mode Functions} + +\begin{verbatim} +int ncmpi_def_dim(int ncid, const char *name, MPI_Offset len, int *idp); + +int ncmpi_def_var(int ncid, const char *name, nc_type xtype, int ndims, + const int *dimidsp, int *varidp); + +int ncmpi_rename_dim(int ncid, int dimid, const char *name); + +int ncmpi_rename_var(int ncid, int varid, const char *name); + +\end{verbatim} +% +% ATTRIBUTE FUNCTIONS +% +\subsection*{A.4 Attribute Functions} + +\begin{verbatim} +int ncmpi_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, + MPI_Offset *lenp); + +int ncmpi_inq_attid(int ncid, int varid, const char *name, int *idp); + +int ncmpi_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep); + +int ncmpi_inq_attlen(int ncid, int varid, const char *name, MPI_Offset *lenp); + +int ncmpi_inq_attname(int ncid, int varid, int attnum, char *name); + +int ncmpi_copy_att(int ncid_in, int varid_in, const char *name, int ncid_out, + int varid_out); + +int ncmpi_rename_att(int ncid, int varid, const char *name, const char *newname); + +int ncmpi_del_att(int ncid, int varid, const char *name); + +int ncmpi_put_att_text(int ncid, int varid, const char *name, MPI_Offset len, + const char *op); + +int ncmpi_get_att_text(int ncid, int varid, const char *name, char *ip); + +int ncmpi_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, + MPI_Offset len, const unsigned char *op); + +int ncmpi_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip); + +int ncmpi_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, + MPI_Offset len, const signed char *op); + +int ncmpi_get_att_schar(int ncid, int varid, const char *name, signed char *ip); + +int ncmpi_put_att_short(int ncid, int varid, const char *name, nc_type xtype, + MPI_Offset len, const short *op); + +int ncmpi_get_att_short(int ncid, int varid, const char *name, short *ip); + +int ncmpi_put_att_int(int ncid, int varid, const char *name, nc_type xtype, + MPI_Offset len, const int *op); + +int ncmpi_get_att_int(int ncid, int varid, const char *name, int *ip); + +int ncmpi_put_att_long(int ncid, int varid, const char *name, + nc_type xtype, MPI_Offset len, const long *op); + +int ncmpi_get_att_long(int ncid, int varid, const char *name, long *ip); + +int ncmpi_put_att_float(int ncid, int varid, const char *name, + nc_type xtype, MPI_Offset len, const float *op); + +int ncmpi_get_att_float(int ncid, int varid, const char *name, float *ip); + +int ncmpi_put_att_double(int ncid, int varid, const char *name, nc_type xtype, + MPI_Offset len, const double *op); + + +int ncmpi_get_att_double(int ncid, int varid, const char *name, double *ip); +\end{verbatim} +% +% DATA FUNCTIONS +% +\subsection*{A.5 Data Mode Functions} + +Recall that the data mode functions are split into the High Level data mode interface and the +Flexible data mode interface. + +\subsubsection*{A.5.1 High Level Data Mode Interface} + +The High Level functions most closely mimic the original NetCDF data mode interface. + +\emph{What about the single variable and varm functions? Are they important?} + +\begin{verbatim} +int ncmpi_put_vara_short_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const short *op); + +int ncmpi_put_vara_short(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const short *op); + +int ncmpi_put_vara_int_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const int *op); + +int ncmpi_put_vara_int(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const int *op); + +int ncmpi_put_vara_float_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const float *op); + +int ncmpi_put_vara_float(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const float *op); + +int ncmpi_put_vara_double_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const double *op); + +int ncmpi_put_vara_double(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const double *op); + +int ncmpi_get_vara_short_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], short *ip); + +int ncmpi_get_vara_short(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], short *ip); + +int ncmpi_get_vara_int_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], int *ip); + +int ncmpi_get_vara_int(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], int *ip); + +int ncmpi_get_vara_float_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], float *ip); + +int ncmpi_get_vara_float(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], float *ip); + +int ncmpi_get_vara_double_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], double *ip); + +int ncmpi_get_vara_double(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], double *ip); + +int ncmpi_put_vars_short_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const short *op); + +int ncmpi_put_vars_short(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const short *op); + +int ncmpi_put_vars_int_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const int *op); + +int ncmpi_put_vars_int(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const int *op); + +int ncmpi_put_vars_float_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const float *op); + +int ncmpi_put_vars_float(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const float *op); + +int ncmpi_put_vars_double_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const double *op); + +int ncmpi_put_vars_double(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const double *op); + +int ncmpi_get_vars_short_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + short *ip); + +int ncmpi_get_vars_short(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + short *ip); + +int ncmpi_get_vars_int_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + int *ip); + +int ncmpi_get_vars_int(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], int *ip); + +int ncmpi_get_vars_float_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + float *ip); + +int ncmpi_get_vars_float(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], float *ip); + +int ncmpi_get_vars_double_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + double *ip); + +int ncmpi_get_vars_double(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + double *ip); +\end{verbatim} + +\subsubsection*{A.5.2 Flexible Data Mode Interface} + +Note that there are considerably fewer functions in the flexible data mode +inteface, because these functions can handle all different types with the same +call. All of the high level functions are written in terms of these +functions. + +\begin{verbatim} +int ncmpi_put_vara_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const void *buf, int bufcount, + MPI_Datatype datatype); + +int ncmpi_get_vara_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], void *buf, int bufcount, + MPI_Datatype datatype); + +int ncmpi_put_vara(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const void *buf, int bufcount, + MPI_Datatype datatype); + +int ncmpi_get_vara(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], void *buf, int bufcount, + MPI_Datatype datatype); + +int ncmpi_put_vars_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], + const void *buf, int bufcount, MPI_Datatype datatype); + +int ncmpi_get_vars_all(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], void *buf, + int bufcount, MPI_Datatype datatype); + +int ncmpi_put_vars(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], const void *buf, + int bufcount, MPI_Datatype datatype); + +int ncmpi_get_vars(int ncid, int varid, const MPI_Offset start[], + const MPI_Offset count[], const MPI_Offset stride[], void *buf, + int bufcount, MPI_Datatype datatype); +\end{verbatim} +% +% APPENDIX B: RATIONALE +% +\section*{Appendix B: Rationale} + +This section covers the rationale behind our decisions on API specifics. + +% +% define mode function semantics +% +\subsection*{B.1 Define Mode Function Semantics} + +There are two options to choose from here, either forcing a single process to +make these calls (funnelled) or forcing all these calls to be collective with +the same data. Note that making them collective does \emph{not} imply any +communication at the time the call is made. + +Both of these options allow for better error detection than what we +previously described (functions independent, anyone could call, only node +0's data was used). Error detection could be performed at the end of the +define mode to minimize costs. + +In fact, it is only fractionally more costly to implement collectives than +funneled (including the error detection). To do this one simply bcast's +process 0's values out (which one would have to do anyway) and then +allgathers a single char or int from everyone indicating if there was a +problem. + +There has to be some synchronization at the end of the define mode in any +case, so this extra error detection comes at an especially low cost. + +\subsection*{B.2 Attribute and Inquiry Function Semantics} + +There are similar options here to the ones for define mode functions. + +One option would be to make these functions independent. This would be easy +for read operations, but would be more difficult for write operations. In +particular we would need to gather up modifications at some point in order to +distribute them out to all processes. Ordering of modifications might also be +an issue. Finally, we would want to constrain use of these independent +operations to the define mode so that we would have an obvious point at which +to perform this collect and distribute operation (e.g. \texttt{ncmpi\_enddef}). + +Another option would be to make all of these functions collective. This is an +unnecessary constraint for the read operations, but it helps in implementing +the write operations (we can distribute modifications right away) and allows +us to maintain the use of these functions outside define mode if we wish. +This is also more consistent with the SPMD model that (we think) our users are +using. + +The final option would be to allow independent use of the read operations but +force collective use of the write operations. This would result in confusing +semantics. + +For now we will implement the second option, all collective operation. Based +on feedback from users we will consider relaxing this constraint. + +\subsubsection*{Questions for Users Regarding Attribute and Inquiry Functions} +\begin{itemize} +\item Are attribute calls used in data mode? +\item Is it inconvenient that the inquiry functions are collective? +\end{itemize} + +\subsection*{B.3 Splitting Data Mode into Collective and Independent Data Modes} + +In both independent and collective MPI-IO operations, it is important to be +able to set the file view to allow for noncontiguous file regions. However, +since the \texttt{MPI\_File\_set\_view} is a collective operation, it is +impossible to use a single file handle to perform collective I/O and still be +able to arbitrarily reset the file view before an independent operation +(because all the processes would need to participate in the file set view). + +For this reason it is necessary to have two file handles in the case where +both independent and collective I/O will be performed. One file handle is +opened with \texttt{MPI\_COMM\_SELF} and is used for independent operations, +while the other is opened with the communicator containing all the processes +for the collective operations. + +It is difficult if not impossible in the general case to ensure consistency of +access when a collection of processes are using multiple MPI\_File handles to +access the same file with mixed independent and collective operations. +However, if explicit and collective synchronization points are introduced +between phases where collective and independent I/O operations will be +performed, then the correct set of operations to ensure a consistent view can +be inserted at this point. + +\emph{Does this explanation make any sense? I think we need to document this.} + +\subsection*{B.4 Even More MPI-Like Data Mode Functions} + +Recall that our flexible NetCDF interface has functions such as: +\begin{verbatim} +int ncmpi_put_vars(int ncid, + int varid, + MPI_Offset start[], + MPI_Offset count[], + MPI_Offset stride[], + void *buf, + int count, + MPI_Datatype datatype) +\end{verbatim} + +It is possible to move to an even more MPI-like interface by using an MPI +datatype to describe the file region in addition to using datatypes for the +memory region: +\begin{verbatim} +int ncmpi_put(int ncid, + int varid, + MPI_Datatype file_dtype, + void *buf, + int count, + MPI_Datatype mem_dtype) +\end{verbatim} + +At first glance this looks rather elegant. However, this isn't as clean as it +seems. The \texttt{file\_dtype} in this case has to describe the variable +layout \emph{in terms of the variable array}, not in terms of the file, +because the user doesn't know about the internal file layout. So the +underlying implementation would need to tear apart \texttt{file\_dtype} and +rebuild a new datatype, on the fly, that corresponded to the data layout in +the file as a whole. This is complicated by the fact that +\texttt{file\_dtype} could be arbitrarily complex. + +The flexible NetCDF interface parameters, \texttt{start}, \texttt{count}, and +\texttt{stride} must also be used to build a file type, but the process is +considerably simpler. + +\subsection*{B.5 MPI and NetCDF Types} + +\subsubsection*{Questions for Users Regarding MPI and NetCDF Types} + +\begin{itemize} +\item How do users use text strings? +\item What types are our users using? +\end{itemize} + +\end{document} + + + + + + + + Index: /branches/SDM_SciDAC/doc/Makefile =================================================================== --- /branches/SDM_SciDAC/doc/Makefile (revision 2) +++ /branches/SDM_SciDAC/doc/Makefile (revision 2) @@ -0,0 +1,6 @@ +all: doc +doc: + latex netcdf-api.tex + latex netcdf-api.tex +clean: + rm *.dvi *.log *.aux Index: /branches/SDM_SciDAC/macros.make.in =================================================================== --- /branches/SDM_SciDAC/macros.make.in (revision 2) +++ /branches/SDM_SciDAC/macros.make.in (revision 2) @@ -0,0 +1,92 @@ +# $Id$ + +# The purpose of this file is to contain common make(1) macros. +# It should be processed by every execution of that utility. + + +# POSIX shell. Shouldn't be necessary -- but is under IRIX 5.3. +SHELL = /bin/sh + + +# Installation Directories: +SRCDIR = @SRCDIR@ +prefix = @prefix@ +exec_prefix = $(prefix) +INCDIR = $(exec_prefix)/include +LIBDIR = $(exec_prefix)/lib +BINDIR = $(exec_prefix)/bin +MANDIR = $(prefix)/man + + +# Preprocessing: +M4 = @M4@ +M4FLAGS = @M4FLAGS@ +CPP = @CPP@ +CPPFLAGS = $(INCLUDES) $(DEFINES) @CPPFLAGS@ +FPP = @FPP@ +FPPFLAGS = @FPPFLAGS@ +CXXCPPFLAGS = $(CPPFLAGS) + + +# Compilation: +CC = @CC@ +CXX = @CXX@ +FC = @FC@ +F90 = @F90@ +CFLAGS = @CFLAGS@ +CXXFLAGS = @CXXFLAGS@ +FFLAGS = @FFLAGS@ +F90FLAGS = @F90FLAGS@ +NETCDF.MOD = @NETCDF_MOD@ +CC_MAKEDEPEND = @CC_MAKEDEPEND@ +COMPILE.c = $(CC) -c $(CFLAGS) $(CPPFLAGS) +COMPILE.cxx = $(CXX) -c $(CXXFLAGS) $(CXXCPPFLAGS) +COMPILE.f = $(FC) -c $(FFLAGS) +COMPILE.F90 = $(F90) -c $(F90FLAGS) +# The following command isn't available on some systems; therefore, the +# `.F.o' rule is relatively complicated. +COMPILE.F = @COMPILE_F@ + + +# Linking: +MATHLIB = @MATHLIB@ +FLIBS = @FLIBS@ +F90LIBS = @F90LIBS@ +LIBS = @LIBS@ +F90LDFLAGS = $(LDFLAGS) +LINK.c = $(CC) -o $@ $(CFLAGS) $(LDFLAGS) +LINK.cxx = $(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) +LINK.F = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) +LINK.f = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) +LINK.F90 = $(F90) -o $@ $(F90FLAGS) $(F90LDFLAGS) + + +# Manual pages: +WHATIS = @WHATIS@ +# The following macro should be empty on systems that don't +# allow users to create their own manual-page indexes. +MAKEWHATIS_CMD = @MAKEWHATIS_CMD@ + + +# Misc. Utilities: +AR = @AR@ +ARFLAGS = @ARFLAGS@ +RANLIB = @RANLIB@ +TARFLAGS = -chf + + +# Dummy macros: used only as placeholders to silence GNU make. They are +# redefined, as necessary, in subdirectory makefiles. +HEADER = dummy_header +HEADER1 = dummy_header1 +HEADER2 = dummy_header2 +HEADER3 = dummy_header3 +LIBRARY = dummy_library.a +MANUAL = dummy_manual +PROGRAM = dummy_program + + +# Distribution macros: +FTPDIR = /home/ftp/pub/$(PACKAGE) +FTPBINDIR = @FTPBINDIR@ +VERSION = dummy_version Index: /branches/SDM_SciDAC/configure.in =================================================================== --- /branches/SDM_SciDAC/configure.in (revision 2) +++ /branches/SDM_SciDAC/configure.in (revision 2) @@ -0,0 +1,52 @@ +AC_REVISION($Id$)dnl +dnl +dnl Process this file with GNU autoconf(1) to produce a configure script. +dnl + +dnl Defaults: +CPPFLAGS=${CPPFLAGS--DNDEBUG} +CFLAGS=${CFLAGS--O} +FPPFLAGS=${FPPFLAGS-} +FFLAGS=${FFLAGS-} + +AC_INIT(src/lib/ncconfig.in) +UD_SRCDIR +AC_PREFIX_DEFAULT(`(cd ..; pwd)`) +AC_CONFIG_HEADER( + src/lib/ncconfig.h:src/lib/ncconfig.in +) +UD_PROG_M4 +UD_PROG_CC +UD_PROG_CC_MAKEDEPEND +UD_PROG_CXX +UD_PROG_FC +UD_PROG_F90 +UD_FORTRAN_TYPES +UD_CHECK_LIB_MATH +UD_PROG_AR() +UD_PROG_NM() +AC_PROG_RANLIB +AC_CHECK_HEADER(stdlib.h, ,AC_DEFINE(NO_STDLIB_H)) +AC_CHECK_HEADER(sys/types.h, ,AC_DEFINE(NO_SYS_TYPES_H)) +AC_CHECK_FUNC(strerror, ,AC_DEFINE(NO_STRERROR)) +UD_CHECK_FTRUNCATE +AC_FUNC_ALLOCA +AC_STRUCT_ST_BLKSIZE +UD_CHECK_IEEE +AC_TYPE_SIZE_T +AC_TYPE_OFF_T +AC_CHECK_TYPE(ssize_t, int) +AC_CHECK_TYPE(ptrdiff_t, int) +AC_CHECK_TYPE(uchar, unsigned char) +AC_C_CHAR_UNSIGNED +AC_C_BIGENDIAN +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(float) +AC_CHECK_SIZEOF(double) +UD_CHECK_SIZEOF(off_t) +UD_CHECK_SIZEOF(size_t) +UD_MAKEWHATIS +UD_FTPBINDIR +UD_OUTPUT(macros.make) Index: /branches/SDM_SciDAC/rules.make =================================================================== --- /branches/SDM_SciDAC/rules.make (revision 2) +++ /branches/SDM_SciDAC/rules.make (revision 2) @@ -0,0 +1,221 @@ +# $Id$ + +# The purpose of this file is to contain common make(1) rules. +# It should be processed by every execution of the that utility. + +.SUFFIXES: +.SUFFIXES: .a .o .i .f .c .cpp .F .y .l .m4 + + +################################################################################ +# Compilation (including preprocessing): + +.c.o: + $(COMPILE.c) $< + +.c.i: + $(CPP) $(CPPFLAGS) $< >$@ + +.cpp.o: + $(COMPILE.cxx) $< + +# Not all FORTRAN compilers support C-preprocessing of *.F files; ergo, a +# relatively complicated rule ensues. +.F.o: + @case "$(COMPILE.F)" in \ + '') \ + set -x; \ + $(FPP) $(FPPFLAGS) $*.F | grep -v '^#' >$*-tmp.f || \ + (rm $*-tmp.f ; exit 1); \ + $(COMPILE.f) -o $@ $*-tmp.f || (rm $*-tmp.f; exit 1); \ + rm $*-tmp.f; \ + ;; \ + *) \ + set -x; \ + $(COMPILE.F) $<; \ + ;; \ + esac + +.f.o: + $(COMPILE.f) $< + +#.F.f: +# $(FPP) $(FPPFLAGS) $*.F | grep -v '^#' >$*.f || (rm $*.f; exit 1) + +.m4.c: + $(M4) $(M4FLAGS) $< >$@ + +.m4.F: + $(M4) $(M4FLAGS) $< >$@ + + +################################################################################ +# Libraries: + +lib: $(LIBRARY) + +$(LIBRARY): $(LIB_OBJS) FORCE + $(AR) $(ARFLAGS) $@ $(LIB_OBJS) + $(RANLIB) $@ + +#------------------------------------------------------------------------------- +# Shared Libraries: +# +# Here only as a place holder and notebook. Don't try to use this stuff +# unless you really, really know what you're doing! (And even then we +# guarantee nothing!) +# +shared_library: + @case `uname -sr` in \ + HP-UX*) \ + $(MAKE) hpux_shared_library;; \ + IRIX*) \ + $(MAKE) irix_shared_library;; \ + Linux*) \ + $(MAKE) linux_shared_library;; \ + OSF1*) \ + $(MAKE) osf1_shared_library;; \ + 'SunOS 4'*) \ + $(MAKE) sunos4_shared_library;; \ + 'SunOS 5'*) \ + $(MAKE) sunos5_shared_library;; \ + *) \ + echo 1>&2 "Don't know how to make a shared library" \ + "on this system"; \ + exit 1;; \ + esac + +hpux_shared_library: + nm libnetcdf.a | grep extern | grep entry | \ + awk '-F|' '{print $$1}' | sed 's/^/-u /' >symbols.log + ld -o $(LIBRARY:.a=.sl) -b -c symbols.log $(LIBRARY) + rm symbols.log +irix_shared_library: + ld -o $(LIBRARY:.a=.so) -shared -no_archive \ + -all $(LIBRARY) -none -lc -lC $(LIBS) +linux_shared_library: + ld -o $(LIBRARY:.a=.so) -shared --whole-archive $(LIBRARY) +osf1_shared_library: + ld -o $(LIBRARY:.a=.so) -shared -all $(LIBRARY) +sunos4_shared_library: + undefopts=`/bin/nm $(LIBRARY) | awk '$$2~/^T$$/{print $$3}' | \ + sed 's/^/-u /'` && \ + ld -o $(LIBRARY:.a=.so) $$undefopts $(LIBRARY) +sunos5_shared_library: + undefopts=`/usr/ccs/bin/nm $(LIBRARY) | grep GLOB | grep FUNC | \ + awk '-F|' '{print $$8}' | sed 's/^/-u /'` && \ + ld -o $(LIBRARY:.a=.so) -G $$undefopts $(LIBRARY) + + +################################################################################ +# Linking: + + +################################################################################ +# Installation: + +$(INCDIR)/$(HEADER): $(INCDIR) $(HEADER) + cp $(HEADER) $@ +$(INCDIR)/$(HEADER1): $(INCDIR) $(HEADER1) + cp $(HEADER1) $@ +$(INCDIR)/$(HEADER2): $(INCDIR) $(HEADER2) + cp $(HEADER2) $@ +$(INCDIR)/$(HEADER3): $(INCDIR) $(HEADER3) + cp $(HEADER3) $@ + +$(LIBDIR)/$(LIBRARY): $(LIBDIR) $(LIBRARY) + cp $(LIBRARY) $@ + +$(BINDIR)/$(PROGRAM): $(BINDIR) $(PROGRAM) + cp $(PROGRAM) $@ + +$(BINDIR) \ +$(INCDIR) \ +$(LIBDIR) \ +$(MANDIR) : + -test -d $@ || mkdir $@ + +$(MANDIR)/man1 \ +$(MANDIR)/man3 \ +$(MANDIR)/man3f \ +$(MANDIR)/man3f90 : $(MANDIR) + -test -d $@ || mkdir $@ + +$(MANDIR)/man1/$(MANUAL): $(MANDIR)/man1 $(MANUAL) + cp $(MANUAL) $@ +$(MANDIR)/man3/$(MANUAL): $(MANDIR)/man3 $(MANUAL) + cp $(MANUAL) $@ +$(MANDIR)/man3f/$(MANUAL): $(MANDIR)/man3 $(MANDIR)/man3/$(MANUAL) \ + $(MANDIR)/man3f + rm -f $@ + ln -s $(MANDIR)/man3/$(MANUAL) $@ +$(MANDIR)/man3f90/$(MANUAL): $(MANDIR)/man3 $(MANDIR)/man3/$(MANUAL) \ + $(MANDIR)/man3f90 + rm -f $@ + ln -s $(MANDIR)/man3/$(MANUAL) $@ + +################################################################################ +# Cleanup: + +clean: FORCE + rm -f *.o *.a *.so *.sl *.i *.Z core $(GARBAGE) + +distclean: FORCE + rm -f *.o *.a *.so *.sl *.i *.Z core $(GARBAGE) \ + MANIFEST *.log $(DIST_GARBAGE) + rm -rf SunWS_cache + +################################################################################ +# Dependencies: + +# This target should only need to be made at the UPC. +# NOTES: +# * The target file might be a symbolic link. +# * The name of the target doesn't match the name of the created file to +# prevent constant updating of the included file `depend' by make(1). +# +deps: FORCE + $(CC_MAKEDEPEND) $(CPPFLAGS) *.c | grep -v '/usr/include' >>depend + sort -u -o depend depend + + +################################################################################ +# Distribution: + +# The following rule echoes the contents of $(PACKING_LIST) in the +# current directory and in all subdirectories. All pathnames are made +# relative to the current directory. +# +MANIFEST.echo: FORCE + @echo $(PACKING_LIST) | fmt -1 + @if [ -n "$(SUBDIRS)" ]; then \ + subdirs="$(SUBDIRS)"; \ + for subdir in $$subdirs; do \ + (cd $$subdir && \ + echo 1>&2 Creating $@ in `pwd` && \ + $(MAKE) MANIFEST.echo | sed "s|^|$$subdir/|") || exit 1; \ + done; \ + else \ + :; \ + fi + +# The following rule ensures that all files in $(PACKING_LIST) exist in +# the current directory and in all subdirectories. +# +ensure_manifest: $(PACKING_LIST) FORCE + @if [ -n "$(SUBDIRS)" ]; then \ + subdirs="$(SUBDIRS)"; \ + for subdir in $$subdirs; do \ + (cd $$subdir && \ + echo 1>&2 Creating $@ in `pwd` && \ + $(MAKE) ensure_manifest) || exit 1; \ + done; \ + else \ + :; \ + fi + + +################################################################################ +# Misc: + +FORCE: Index: /branches/SDM_SciDAC/src/lib/mpincio.c =================================================================== --- /branches/SDM_SciDAC/src/lib/mpincio.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/mpincio.c (revision 2) @@ -0,0 +1,554 @@ +/*********************************************************************************** + * + * This file is created by Northwestern University and Argonne National Laboratory + * + **********************************************************************************/ + +#include "ncconfig.h" +#include +#include +#include +#ifndef ENOERR +#define ENOERR 0 +#endif +#include +#include +#include +#include +#ifdef _MSC_VER /* Microsoft Compilers */ +#include +#else +#include +#endif + +#include "ncio.h" +#include "fbits.h" +#include "rnd.h" + +/* #define INSTRUMENT 1 */ +#if INSTRUMENT /* debugging */ +#undef NDEBUG +#include +#include "instr.h" +#endif + +#undef MIN /* system may define MIN somewhere and complain */ +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +#if !defined(NDEBUG) && !defined(X_INT_MAX) +#define X_INT_MAX 2147483647 +#endif + +#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */ +#define X_ALIGN 4 +#else +#undef X_ALIGN +#endif + +#ifdef USE_MPIO /* Following code add by Jianwei Li */ + +#define MAX_NC_ID 1024 + +static unsigned char IDalloc[MAX_NC_ID]; + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +void +ncio_free(ncio *nciop) { + if (nciop != NULL) + free(nciop); +} + +#else /* Following interface modified as above by Jianwei Li */ + +static void +ncio_free(ncio *nciop) +{ + if(nciop == NULL) + return; + + if(nciop->free != NULL) + nciop->free(nciop->pvt); + + free(nciop); +} + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +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); + ncio *nciop; + + nciop = (ncio *) malloc(sz_ncio + sz_path); + if (nciop == NULL) + return NULL; + + nciop->ioflags = ioflags; + + nciop->path = (char *) ((char *)nciop + sz_ncio); + (void) strcpy((char *)nciop->path, path); + + return nciop; +} + +#else /* Following interface modified as above by Jianwei Li */ + +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; +} + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +ncio_create(MPI_Comm comm, const char *path, int ioflags, MPI_Info info, + ncio **nciopp) { + ncio *nciop; + int i; + int mpiomode = (MPI_MODE_RDWR | MPI_MODE_CREATE); + int mpireturn, status; + + + fSet(ioflags, NC_WRITE); + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + nciop->mpiomode = MPI_MODE_RDWR; + nciop->mpioflags = 0; + nciop->comm = comm; + nciop->mpiinfo = info; + + if (fIsSet(ioflags, NC_NOCLOBBER)) + fSet(mpiomode, MPI_MODE_EXCL); + else + MPI_File_delete((char *)path, info); + + mpireturn = MPI_File_open(comm, (char *)path, mpiomode, info, &nciop->collective_fh); + if (mpireturn != MPI_SUCCESS) { + ncio_free(nciop); + return NC_EOFILE; + } + + for (i = 0; i < MAX_NC_ID && IDalloc[i] != 0; i++); + if (i == MAX_NC_ID) { + ncio_free(nciop); + return NC_ENFILE; + } + *((int *)&nciop->fd) = i; + IDalloc[i] = 1; + + set_NC_collectiveFh(nciop); + + *nciopp = nciop; + return ENOERR; +} + +#else /* Following interface modified as above by Jianwei Li */ + +int +ncio_create(const char *path, int ioflags, + size_t initialsz, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp) +{ + ncio *nciop; + int oflags = (O_RDWR|O_CREAT); + int fd; + int status; + + if(initialsz < (size_t)igeto + igetsz) + initialsz = (size_t)igeto + igetsz; + + fSet(ioflags, NC_WRITE); + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + if(fIsSet(ioflags, NC_NOCLOBBER)) + fSet(oflags, O_EXCL); + else + fSet(oflags, O_TRUNC); +#ifdef O_BINARY + fSet(oflags, O_BINARY); +#endif +#ifdef vms + fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm"); +#else + /* Should we mess with the mode based on NC_SHARE ?? */ + fd = open(path, oflags, NC_DEFAULT_CREAT_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 */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + if(fIsSet(nciop->ioflags, NC_SHARE)) + status = ncio_spx_init2(nciop, sizehintp); + else + status = ncio_px_init2(nciop, sizehintp, 1); + + 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; +} + +#endif /* USE_MPIO */ + + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +ncio_open(MPI_Comm comm, const char *path, int ioflags, MPI_Info info, + ncio **nciopp) { + ncio *nciop; + int i; + int mpiomode = fIsSet(ioflags, NC_WRITE) ? MPI_MODE_RDWR : MPI_MODE_RDONLY; + int mpireturn, status; + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + nciop->mpiomode = mpiomode; + nciop->mpioflags = 0; + nciop->comm = comm; + nciop->mpiinfo = info; + + mpireturn = MPI_File_open(comm, (char *)path, mpiomode, info, &nciop->collective_fh); + if (mpireturn != MPI_SUCCESS) { + ncio_free(nciop); + return NC_EOFILE; + } + + for (i = 0; i < MAX_NC_ID && IDalloc[i] != 0; i++); + if (i == MAX_NC_ID) { + ncio_free(nciop); + return NC_ENFILE; + } + *((int *)&nciop->fd) = i; + IDalloc[i] = 1; + + set_NC_collectiveFh(nciop); + + *nciopp = nciop; + return ENOERR; +} + +#else /* Following interface modified as above by Jianwei Li */ + +int +ncio_open(const char *path, + int ioflags, + off_t igeto, size_t igetsz, size_t *sizehintp, + 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 ENOMEM; + +#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 */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + if(fIsSet(nciop->ioflags, NC_SHARE)) + status = ncio_spx_init2(nciop, sizehintp); + else + status = ncio_px_init2(nciop, sizehintp, 0); + + 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; +} + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +ncio_sync(ncio *nciop) { + if(NC_independentFhOpened(nciop)) + MPI_File_sync(nciop->independent_fh); + + if(NC_collectiveFhOpened(nciop)) + MPI_File_sync(nciop->collective_fh); + + MPI_Barrier(nciop->comm); + + return ENOERR; +} + +int +ncio_close(ncio *nciop, int doUnlink) { + int status = ENOERR; + + if (nciop == NULL) + return EINVAL; + + if(NC_independentFhOpened(nciop)) + MPI_File_close(&(nciop->independent_fh)); + + if(NC_collectiveFhOpened(nciop)) + MPI_File_close(&(nciop->collective_fh)); + + if (doUnlink) + MPI_File_delete((char *)nciop->path, nciop->mpiinfo); + + ncio_free(nciop); + + return status; +} + +#else /* Following interface modified as above by Jianwei Li */ + +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; +} + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface added by Jianwei Li */ + +int +ncio_move(ncio *const nciop, off_t to, off_t from, size_t nbytes) { + int mpireturn, mpierr = 0, errcheck; + const int bufsize = 4096; + size_t movesize, bufcount; + int rank, grpsize; + void *buf = malloc(bufsize); + MPI_Comm comm; + MPI_Status mpistatus; + + comm = nciop->comm; + MPI_Comm_size(comm, &grpsize); + MPI_Comm_rank(comm, &rank); + + movesize = nbytes; + + while (movesize > 0) { + /* find a proper number of processors to participate I/O */ + while (grpsize > 1 && movesize/grpsize < bufsize) + grpsize--; + if (grpsize > 1) { + bufcount = bufsize; + movesize -= bufsize*grpsize; + } + else if (movesize < bufsize) { + bufcount = movesize; + movesize = 0; + } + else { + bufcount = bufsize; + movesize -= bufsize; + } + + /* reset the file view */ + mpireturn = MPI_File_set_view(nciop->collective_fh, 0, MPI_BYTE, + MPI_BYTE, "native", nciop->mpiinfo); + if (mpireturn != MPI_SUCCESS) { + free(buf); + return NC_EREAD; + } + if (rank < grpsize) { + /* read the original data @ from+movesize+rank*bufsize */ + mpireturn = MPI_File_read_at(nciop->collective_fh, + from+movesize+rank*bufsize, + buf, bufcount, MPI_BYTE, &mpistatus); + if (mpireturn != MPI_SUCCESS) + mpierr = 1; + } + MPI_Allreduce(&mpierr, &errcheck, 1, MPI_INT, MPI_LOR, comm); + if (errcheck) { + free(buf); + return NC_EREAD; + } + + MPI_Barrier(comm); /* important, in case new region overlaps old region */ + + /* reset the file view */ + mpireturn = MPI_File_set_view(nciop->collective_fh, 0, MPI_BYTE, + MPI_BYTE, "native", nciop->mpiinfo); + if (mpireturn != MPI_SUCCESS) { + free(buf); + return NC_EWRITE; + } + if (rank < grpsize) { + /* write to new location @ to+movesize+rank*bufsize */ + mpireturn = MPI_File_write_at(nciop->collective_fh, + to+movesize+rank*bufsize, + buf, bufcount, MPI_BYTE, &mpistatus); + if (mpireturn != MPI_SUCCESS) + mpierr = 1; + } + MPI_Allreduce(&mpierr, &errcheck, 1, MPI_INT, MPI_LOR, comm); + if (errcheck) { + free(buf); + return NC_EWRITE; + } + } + + free(buf); + return NC_NOERR; +} + +#endif /* USE_MPIO */ Index: /branches/SDM_SciDAC/src/lib/nc.c =================================================================== --- /branches/SDM_SciDAC/src/lib/nc.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/nc.c (revision 2) @@ -0,0 +1,1439 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include "rnd.h" +#include +#include +#include +#include "ncx.h" +#if defined(LOCKNUMREC) /* && _CRAYMPP */ +# include +# include +#endif + +/* list of open netcdf's */ +static NC *NClist = NULL; + +/* static */ +void +add_to_NCList(NC *ncp) +{ + assert(ncp != NULL); + + ncp->prev = NULL; + if(NClist != NULL) + NClist->prev = ncp; + ncp->next = NClist; + NClist = ncp; +} + +/* static */ +void +del_from_NCList(NC *ncp) +{ + assert(ncp != NULL); + + if(NClist == ncp) + { + assert(ncp->prev == NULL); + NClist = ncp->next; + } + else + { + assert(ncp->prev != NULL); + ncp->prev->next = ncp->next; + } + + if(ncp->next != NULL) + ncp->next->prev = ncp->prev; + + ncp->next = NULL; + ncp->prev = NULL; +} + +#ifdef USE_MPIO /* Following interface added by Jianwei Li */ + +/* + * Check the data set definitions across all processes by + * comparing the header buffer streams of all processes. + */ +int +NC_check_def(MPI_Comm comm, void *buf, size_t nn) { + int rank; + int errcheck, compare = 0; + void *cmpbuf; + + MPI_Comm_rank(comm, &rank); + + if (rank == 0) + cmpbuf = buf; + else + cmpbuf = (void *)malloc(nn); + + MPI_Bcast(cmpbuf, nn, MPI_BYTE, 0, comm); + + if (rank != 0) { + compare = memcmp(buf, cmpbuf, nn); + free(cmpbuf); + } + + MPI_Allreduce(&compare, &errcheck, 1, MPI_INT, MPI_LOR, comm); + + if (errcheck) + return NC_EMULTIDEFINE; + else + return NC_NOERR; +} + +#endif /* USE_MPIO */ + +int +NC_check_id(int ncid, NC **ncpp) +{ + NC *ncp; + + if(ncid >= 0) + { + for(ncp = NClist; ncp != NULL; ncp = ncp->next) + { + if(ncp->nciop->fd == ncid) + { + *ncpp = ncp; + return NC_NOERR; /* normal return */ + } + } + } + + /* else, not found */ + return NC_EBADID; +} + + +/* static */ +void +free_NC(NC *ncp) +{ + if(ncp == NULL) + return; + free_NC_dimarrayV(&ncp->dims); + free_NC_attrarrayV(&ncp->attrs); + free_NC_vararrayV(&ncp->vars); +#if _CRAYMPP && defined(LOCKNUMREC) + shfree(ncp); +#else + free(ncp); +#endif /* _CRAYMPP && LOCKNUMREC */ +} + + +/* static */ +NC * +new_NC(const size_t *chunkp) +{ + NC *ncp; + +#if _CRAYMPP && defined(LOCKNUMREC) + ncp = (NC *) shmalloc(sizeof(NC)); +#else + ncp = (NC *) malloc(sizeof(NC)); +#endif /* _CRAYMPP && LOCKNUMREC */ + if(ncp == NULL) + return NULL; + (void) memset(ncp, 0, sizeof(NC)); + + ncp->xsz = MIN_NC_XSZ; + assert(ncp->xsz == hdr_len_NC(ncp)); + + ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT; + + return ncp; +} + + +/* static */ +NC * +dup_NC(const NC *ref) +{ + NC *ncp; + +#if _CRAYMPP && defined(LOCKNUMREC) + ncp = (NC *) shmalloc(sizeof(NC)); +#else + ncp = (NC *) malloc(sizeof(NC)); +#endif /* _CRAYMPP && LOCKNUMREC */ + if(ncp == NULL) + return NULL; + (void) memset(ncp, 0, sizeof(NC)); + + if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR) + goto err; + if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR) + goto err; + if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR) + goto err; + + ncp->xsz = ref->xsz; + ncp->begin_var = ref->begin_var; + ncp->begin_rec = ref->begin_rec; + ncp->recsize = ref->recsize; + NC_set_numrecs(ncp, NC_get_numrecs(ref)); + return ncp; +err: + free_NC(ncp); + return NULL; +} + + +/* + * Verify that this is a user nc_type + * Formerly +NCcktype() + * Sense of the return is changed. + */ +int +nc_cktype(nc_type type) +{ + switch((int)type){ + case NC_BYTE: + case NC_CHAR: + case NC_SHORT: + case NC_INT: + case NC_FLOAT: + case NC_DOUBLE: + return(NC_NOERR); + } + return(NC_EBADTYPE); +} + + +/* + * How many objects of 'type' + * will fit into xbufsize? + */ +size_t +ncx_howmany(nc_type type, size_t xbufsize) +{ + switch(type){ + case NC_BYTE: + case NC_CHAR: + return xbufsize; + case NC_SHORT: + return xbufsize/X_SIZEOF_SHORT; + case NC_INT: + return xbufsize/X_SIZEOF_INT; + case NC_FLOAT: + return xbufsize/X_SIZEOF_FLOAT; + case NC_DOUBLE: + return xbufsize/X_SIZEOF_DOUBLE; + } + assert("ncx_howmany: Bad type" == 0); + return(0); +} + +#define D_RNDUP(x, align) _RNDUP(x, (off_t)(align)) + +/* + * Compute each variable's 'begin' offset, + * update 'begin_rec' as well. + */ +/* static */ +void +NC_begins(NC *ncp, + size_t h_minfree, size_t v_align, + size_t v_minfree, size_t r_align) +{ + size_t ii; + off_t index = 0; + NC_var **vpp; + NC_var *last = NULL; + + if(v_align == NC_ALIGN_CHUNK) + v_align = ncp->chunk; + if(r_align == NC_ALIGN_CHUNK) + r_align = ncp->chunk; + + ncp->xsz = hdr_len_NC(ncp); + + if(ncp->vars.nelems == 0) + return; + + /* only (re)calculate begin_var if there is not sufficient space in header + or start of non-record variables is not aligned as requested by valign */ + if (ncp->begin_var < ncp->xsz + h_minfree || + ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) ) + { + index = (off_t) ncp->xsz; + ncp->begin_var = D_RNDUP(index, v_align); + if(ncp->begin_var < index + h_minfree) + { + ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align); + } + } + index = ncp->begin_var; + + /* loop thru vars, first pass is for the 'non-record' vars */ + vpp = ncp->vars.value; + for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++) + { + if( IS_RECVAR(*vpp) ) + { + /* skip record variables on this pass */ + continue; + } +#if 0 +fprintf(stderr, " VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index); +#endif + (*vpp)->begin = index; + index += (*vpp)->len; + } + + /* only (re)calculate begin_rec if there is not sufficient + space at end of non-record variables or if start of record + variables is not aligned as requested by r_align */ + if (ncp->begin_rec < index + v_minfree || + ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) ) + { + ncp->begin_rec = D_RNDUP(index, r_align); + if(ncp->begin_rec < index + v_minfree) + { + ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align); + } + } + index = ncp->begin_rec; + + ncp->recsize = 0; + + /* loop thru vars, second pass is for the 'record' vars */ + vpp = (NC_var **)ncp->vars.value; + for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++) + { + if( !IS_RECVAR(*vpp) ) + { + /* skip non-record variables on this pass */ + continue; + } + +#if 0 +fprintf(stderr, " REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index); +#endif + (*vpp)->begin = index; + index += (*vpp)->len; + ncp->recsize += (*vpp)->len; + last = (*vpp); + } + + /* + * for special case of exactly one record variable, pack value + */ + if(last != NULL && ncp->recsize == last->len) + ncp->recsize = *last->dsizes * last->xsz; + + if(NC_IsNew(ncp)) + NC_set_numrecs(ncp, 0); + +} + +#define NC_NUMRECS_OFFSET 4 +#define NC_NUMRECS_EXTENT 4 + +/* + * Read just the numrecs member. + * (A relatively expensive way to do things.) + */ + +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +read_numrecs(NC *ncp) { + int status = NC_NOERR, mpireturn; + size_t nrecs; + void *buf, *pos; + MPI_Status mpistatus; + + assert(!NC_indef(ncp)); + + pos = buf = (void *)malloc(X_SIZEOF_SIZE_T); + + /* reset the file view */ + MPI_File_set_view(ncp->nciop->collective_fh, 0, MPI_BYTE, + MPI_BYTE, "native", ncp->nciop->mpiinfo); + + mpireturn = MPI_File_read_at(ncp->nciop->collective_fh, NC_NUMRECS_OFFSET, + buf, X_SIZEOF_SIZE_T, MPI_BYTE, &mpistatus); + + if (mpireturn != MPI_SUCCESS) { + status = NC_EWRITE; + } + + status = ncx_get_size_t((const void **)&pos, &nrecs); + ncp->numrecs = nrecs; + + free(buf); + + return status; +} + +#else /* Following interface modified as above by Jianwei Li */ + +int +read_numrecs(NC *ncp) +{ + int status = NC_NOERR; + const void *xp; + size_t nrecs = NC_get_numrecs(ncp); + + assert(!NC_indef(ncp)); + + status = ncp->nciop->get(ncp->nciop, + NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, 0, (void **)&xp); + /* cast away const */ + if(status != NC_NOERR) + return status; + + status = ncx_get_size_t(&xp, &nrecs); + + (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, 0); + + if(status == NC_NOERR) + { + NC_set_numrecs(ncp, nrecs); + fClr(ncp->flags, NC_NDIRTY); + } + + return status; +} + +#endif + +/* + * Write out just the numrecs member. + * (A relatively expensive way to do things.) + */ +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +/* + * Collective operation implicit + */ + +int +write_numrecs(NC *ncp) { + int status = NC_NOERR, mpireturn; + size_t nrecs; + void *buf, *pos; + MPI_Status mpistatus; + MPI_Comm comm; + int rank; + + assert(!NC_readonly(ncp)); + assert(!NC_indef(ncp)); + + comm = ncp->nciop->comm; + MPI_Comm_rank(comm, &rank); + + nrecs = ncp->numrecs; + pos = buf = (void *)malloc(X_SIZEOF_SIZE_T); + status = ncx_put_size_t(&pos, &nrecs); + + if(NC_indep(ncp) && NC_independentFhOpened(ncp->nciop)) { + MPI_File_sync(ncp->nciop->independent_fh); + MPI_Barrier(comm); + } + + /* reset the file view */ + MPI_File_set_view(ncp->nciop->collective_fh, 0, MPI_BYTE, + MPI_BYTE, "native", ncp->nciop->mpiinfo); + + if (rank == 0) { + mpireturn = MPI_File_write_at(ncp->nciop->collective_fh, NC_NUMRECS_OFFSET, + buf, X_SIZEOF_SIZE_T, MPI_BYTE, &mpistatus); + } + + MPI_Bcast(&mpireturn, 1, MPI_INT, 0, comm); + + if (mpireturn != MPI_SUCCESS) { + status = NC_EWRITE; + } else { + MPI_File_sync(ncp->nciop->collective_fh); + MPI_Barrier(comm); + fClr(ncp->flags, NC_NDIRTY); + } + + free(buf); + + return status; +} + +#else /* Following interface modified as above by Jianwei Li */ + +int +write_numrecs(NC *ncp) +{ + int status = NC_NOERR; + void *xp; + + assert(!NC_readonly(ncp)); + assert(!NC_indef(ncp)); + + status = ncp->nciop->get(ncp->nciop, + NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, RGN_WRITE, &xp); + if(status != NC_NOERR) + return status; + + { + const size_t nrecs = NC_get_numrecs(ncp); + status = ncx_put_size_t(&xp, &nrecs); + } + + (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED); + + if(status == NC_NOERR) + fClr(ncp->flags, NC_NDIRTY); + + return status; +} + +#endif /* USE_MPIO */ + +/* + * Read in the header + * It is expensive. + */ +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +read_NC(NC *ncp) { + int status = NC_NOERR; + + free_NC_dimarrayV(&ncp->dims); + free_NC_attrarrayV(&ncp->attrs); + free_NC_vararrayV(&ncp->vars); + + status = hdr_get_NC(ncp); + + if(status == NC_NOERR) + fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY); + + return status; +} + +#else /* Following interface modified as above by Jianwei Li */ + +/* static */ +int +read_NC(NC *ncp) +{ + int status = NC_NOERR; + + free_NC_dimarrayV(&ncp->dims); + free_NC_attrarrayV(&ncp->attrs); + free_NC_vararrayV(&ncp->vars); + + status = nc_get_NC(ncp); + + if(status == NC_NOERR) + fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY); + + return status; +} + +#endif /* USE_MPIO */ + +/* + * Write out the header + */ +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +write_NC(NC *ncp) +{ + int status = NC_NOERR, mpireturn; + void *buf; + MPI_Status mpistatus; + int rank; + + assert(!NC_readonly(ncp)); + + MPI_Comm_rank(ncp->nciop->comm, &rank); + + buf = (void *)malloc(ncp->xsz); + status = hdr_put_NC(ncp, buf); + if(status != NC_NOERR) { + free(buf); + return status; + } + status = NC_check_def(ncp->nciop->comm, buf, ncp->xsz); + if (status != NC_NOERR) { + free(buf); + return status; + } + + /* reset the file view */ + MPI_File_set_view(ncp->nciop->collective_fh, 0, MPI_BYTE, + MPI_BYTE, "native", ncp->nciop->mpiinfo); + + if (rank == 0) { + mpireturn = MPI_File_write_at(ncp->nciop->collective_fh, 0, buf, + ncp->xsz, MPI_BYTE, &mpistatus); + } + + fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY); + free(buf); + + return status; +} + +#else /* Following interface modified as above by Jianwei Li */ + +static int +write_NC(NC *ncp) +{ + int status = NC_NOERR; + + assert(!NC_readonly(ncp)); + + status = ncx_put_NC(ncp, NULL, 0, 0); + + if(status == NC_NOERR) + fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY); + + return status; +} + +#endif /* USE_MPIO */ + +/* + * Write the header or the numrecs if necessary. + */ +int +NC_sync(NC *ncp) +{ + int mynumrecs, numrecs; + + assert(!NC_readonly(ncp)); + + /* collect and set the max numrecs due to difference by independent write */ + + mynumrecs = ncp->numrecs; + MPI_Allreduce(&mynumrecs, &numrecs, 1, MPI_INT, MPI_MAX, ncp->nciop->comm); + if (numrecs > ncp->numrecs) { + ncp->numrecs = numrecs; + set_NC_ndirty(ncp); + } + + if(NC_hdirty(ncp)) { + return write_NC(ncp); + } + /* else */ + + if(NC_ndirty(ncp)) { + return write_numrecs(ncp); + } + /* else */ + + return NC_NOERR; +} + + +#ifndef USE_MPIO /* out-of-date code removed by Jianwei Li */ + +/* + * Initialize the 'non-record' variables. + */ +static int +fillerup(NC *ncp) +{ + int status = NC_NOERR; + size_t ii; + NC_var **varpp; + + assert(!NC_readonly(ncp)); + assert(NC_dofill(ncp)); + + /* loop thru vars */ + varpp = ncp->vars.value; + for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++) + { + if(IS_RECVAR(*varpp)) + { + /* skip record variables */ + continue; + } + + status = fill_NC_var(ncp, *varpp, 0); + if(status != NC_NOERR) + break; + } + return status; +} + +/* Begin endef */ + +/* + */ +static int +fill_added_recs(NC *gnu, NC *old) +{ + NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value; + + const int old_nrecs = (int) NC_get_numrecs(old); + int recno = 0; + for(; recno < old_nrecs; recno++) + { + int varid = (int)old->vars.nelems; + for(; varid < (int)gnu->vars.nelems; varid++) + { + const NC_var *const gnu_varp = *(gnu_varpp + varid); + if(!IS_RECVAR(gnu_varp)) + { + /* skip non-record variables */ + continue; + } + /* else */ + { + const int status = fill_NC_var(gnu, gnu_varp, recno); + if(status != NC_NOERR) + return status; + } + } + } + + return NC_NOERR; +} + +/* + */ +static int +fill_added(NC *gnu, NC *old) +{ + NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value; + int varid = (int)old->vars.nelems; + + for(; varid < (int)gnu->vars.nelems; varid++) + { + const NC_var *const gnu_varp = *(gnu_varpp + varid); + if(IS_RECVAR(gnu_varp)) + { + /* skip record variables */ + continue; + } + /* else */ + { + const int status = fill_NC_var(gnu, gnu_varp, 0); + if(status != NC_NOERR) + return status; + } + } + + return NC_NOERR; +} + +#endif /* USE_MPIO */ + +/* + * Move the records "out". + * Fill as needed. + */ +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +move_data_r(NC *ncp, NC *old) { + /* no new variable inserted, move the whole contiguous data part */ + ncp->numrecs = old->numrecs; + return ncio_move(ncp->nciop, ncp->begin_var, old->begin_var, + old->begin_rec - old->begin_var + old->recsize * old->numrecs); +} + +int +move_recs_r(NC *ncp, NC *old) { + int status; + int recno; + const size_t old_nrecs = old->numrecs; + const size_t ncp_recsize = ncp->recsize; + const size_t old_recsize = old->recsize; + const off_t ncp_off = ncp->begin_rec; + const off_t old_off = old->begin_rec; + + assert(ncp_recsize >= old_recsize); + + if (ncp_recsize == old_recsize) { + + /* No new rec var inserted, move all rec vars as a whole */ + + status = ncio_move(ncp->nciop, ncp_off, old_off, + old_recsize * old_nrecs); + if(status != NC_NOERR) + return status; + } else { + + /* else, new rec var inserted, to be moved one record at a time */ + + for (recno = (int)old_nrecs -1; recno >= 0; recno--) { + status = ncio_move(ncp->nciop, + ncp_off+recno*ncp_recsize, + old_off+recno*old_recsize, + old_recsize); + if(status != NC_NOERR) + return status; + } + } + + ncp->numrecs = old_nrecs; + + return NC_NOERR; +} + +#else /* Following interface modified as above by Jianwei Li */ + +/* static */ +int +move_recs_r(NC *gnu, NC *old) +{ + int status; + int recno; + int varid; + NC_var **gnu_varpp = (NC_var **)gnu->vars.value; + NC_var **old_varpp = (NC_var **)old->vars.value; + NC_var *gnu_varp; + NC_var *old_varp; + off_t gnu_off; + off_t old_off; + const size_t old_nrecs = NC_get_numrecs(old); + + /* Don't parallelize this loop */ + for(recno = (int)old_nrecs -1; recno >= 0; recno--) + { + /* Don't parallelize this loop */ + for(varid = (int)old->vars.nelems -1; varid >= 0; varid--) + { + gnu_varp = *(gnu_varpp + varid); + if(!IS_RECVAR(gnu_varp)) + { + /* skip non-record variables on this pass */ + continue; + } + /* else */ + + /* else, a pre-existing variable */ + old_varp = *(old_varpp + varid); + gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno); + old_off = old_varp->begin + (off_t)(old->recsize * recno); + + if(gnu_off == old_off) + continue; /* nothing to do */ + + assert(gnu_off > old_off); + + status = gnu->nciop->move(gnu->nciop, gnu_off, old_off, + old_varp->len, 0); + + if(status != NC_NOERR) + return status; + + } + } + + NC_set_numrecs(gnu, old_nrecs); + + return NC_NOERR; +} + +#endif /* USE_MPIO */ + +/* + * Move the "non record" variables "out". + * Fill as needed. + */ +#ifdef USE_MPIO /* Following interface rewritten by Jianwei Li */ + +int +move_vars_r(NC *ncp, NC *old) { + return ncio_move(ncp->nciop, ncp->begin_var, old->begin_var, + old->begin_rec - old->begin_var); +} + +#else /* Following interface modified as above by Jianwei Li */ + +/* static */ +int +move_vars_r(NC *gnu, NC *old) +{ + int status; + int varid; + NC_var **gnu_varpp = (NC_var **)gnu->vars.value; + NC_var **old_varpp = (NC_var **)old->vars.value; + NC_var *gnu_varp; + NC_var *old_varp; + off_t gnu_off; + off_t old_off; + + /* Don't parallelize this loop */ + for(varid = (int)old->vars.nelems -1; + varid >= 0; varid--) + { + gnu_varp = *(gnu_varpp + varid); + if(IS_RECVAR(gnu_varp)) + { + /* skip record variables on this pass */ + continue; + } + /* else */ + + old_varp = *(old_varpp + varid); + gnu_off = gnu_varp->begin; + old_off = old_varp->begin; + + if(gnu_off == old_off) + continue; /* nothing to do */ + + assert(gnu_off > old_off); + + status = gnu->nciop->move(gnu->nciop, gnu_off, old_off, + old_varp->len, 0); + + if(status != NC_NOERR) + return status; + + } + + return NC_NOERR; +} + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* function below added by Jianwei Li */ + +int +NC_enddef(NC *ncp) { + int status = NC_NOERR; + MPI_Comm comm; + + assert(!NC_readonly(ncp)); + assert(NC_indef(ncp)); + + comm = ncp->nciop->comm; + + NC_begins(ncp, 0, 1, 0, 1); + + /* To be updated */ + if(ncp->old != NULL) { + /* a plain redef, not a create */ + assert(!NC_IsNew(ncp)); + assert(fIsSet(ncp->flags, NC_INDEF)); + assert(ncp->begin_rec >= ncp->old->begin_rec); + assert(ncp->begin_var >= ncp->old->begin_var); + assert(ncp->vars.nelems >= ncp->old->vars.nelems); + + MPI_File_sync(ncp->nciop->collective_fh); + /* + * Barrier needed switching between read and write + * Important, MPI_File_sync doesn't ensure barrier + */ + MPI_Barrier(comm); + + if(ncp->vars.nelems != 0) { + if(ncp->begin_rec > ncp->old->begin_rec) { + if (ncp->vars.nelems == ncp->old->vars.nelems) { + status = move_data_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } else { + status = move_recs_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + if(ncp->begin_var > ncp->old->begin_var) { + status = move_vars_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } + } + } else { + /* Even if (ncp->begin_rec == ncp->old->begin_rec) + * and (ncp->begin_var == ncp->old->begin_var) + * might still have added a new record variable + */ + if(ncp->recsize > ncp->old->recsize) { + status = move_recs_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } + } + } + } + + status = write_NC(ncp); + if (status != NC_NOERR) + return status; + + if(ncp->old != NULL) { + free_NC(ncp->old); + ncp->old = NULL; + } + + fClr(ncp->flags, NC_CREAT | NC_INDEF); + MPI_File_sync(ncp->nciop->collective_fh); + MPI_Barrier(comm); + + return NC_NOERR; +} + + +int +enddef(NC *ncp) +{ + assert(!NC_readonly(ncp)); + if(!NC_indef(ncp)) + return(NC_ENOTINDEFINE); + + NC_begins(ncp, 0, 1, 0, 1); + + if(ncp->old != NULL) + { + free_NC(ncp->old); + ncp->old = NULL; + } + + fClr(ncp->flags, NC_CREAT | NC_INDEF); + + return NC_NOERR; +} + +#endif + +/* + * End define mode. + * Common code for ncendef, ncclose(endef) + * Flushes I/O buffers. + */ +static int +NC_endef(NC *ncp, + size_t h_minfree, size_t v_align, + size_t v_minfree, size_t r_align) +{ + int status = NC_NOERR; + + assert(!NC_readonly(ncp)); + assert(NC_indef(ncp)); + + NC_begins(ncp, h_minfree, v_align, v_minfree, r_align); + + if(ncp->old != NULL) + { + /* a plain redef, not a create */ + assert(!NC_IsNew(ncp)); + assert(fIsSet(ncp->flags, NC_INDEF)); + assert(ncp->begin_rec >= ncp->old->begin_rec); + assert(ncp->begin_var >= ncp->old->begin_var); + + if(ncp->vars.nelems != 0) + { + if(ncp->begin_rec > ncp->old->begin_rec) + { + status = move_recs_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + if(ncp->begin_var > ncp->old->begin_var) + { + status = move_vars_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } + /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */ + } + else + { /* Even if (ncp->begin_rec == ncp->old->begin_rec) + and (ncp->begin_var == ncp->old->begin_var) + might still have added a new record variable */ + if(ncp->recsize > ncp->old->recsize) + { + status = move_recs_r(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } + } + } + } + + status = write_NC(ncp); + if(status != NC_NOERR) + return status; + +#ifndef USE_MPIO /* out-of-date code removed by Jianwei Li */ + + if(NC_dofill(ncp)) + { + if(NC_IsNew(ncp)) + { + status = fillerup(ncp); + if(status != NC_NOERR) + return status; + + } + else if(ncp->vars.nelems > ncp->old->vars.nelems) + { + status = fill_added(ncp, ncp->old); + if(status != NC_NOERR) + return status; + status = fill_added_recs(ncp, ncp->old); + if(status != NC_NOERR) + return status; + } + } + +#endif /* USE_MPIO */ + + if(ncp->old != NULL) + { + free_NC(ncp->old); + ncp->old = NULL; + } + + fClr(ncp->flags, NC_CREAT | NC_INDEF); + + return ncp->nciop->sync(ncp->nciop); +} + +#ifdef LOCKNUMREC +static int +NC_init_pe(NC *ncp, int basepe) { + if (basepe < 0 || basepe >= _num_pes()) { + return NC_EINVAL; /* invalid base pe */ + } + /* initialize common values */ + ncp->lock[LOCKNUMREC_VALUE] = 0; + ncp->lock[LOCKNUMREC_LOCK] = 0; + ncp->lock[LOCKNUMREC_SERVING] = 0; + ncp->lock[LOCKNUMREC_BASEPE] = basepe; + return NC_NOERR; +} +#endif + +/* Public */ + +#ifdef USE_MPIO /* This section is added by Jianwei Li */ + +int +NC_close(NC *ncp) { + int status = NC_NOERR; + + if(NC_indef(ncp)) { + status = NC_enddef(ncp); /* TODO: defaults */ + if(status != NC_NOERR ) { + /* To do: Abort new definition, if any */ + if (ncp->old != NULL) { + free_NC(ncp->old); + ncp->old = NULL; + fClr(ncp->flags, NC_INDEF); + } + } + } + else if(!NC_readonly(ncp)) { + status = NC_sync(ncp); + if (status != NC_NOERR) + return status; + } + + (void) ncio_close(ncp->nciop, 0); + ncp->nciop = NULL; + + del_from_NCList(ncp); + + free_NC(ncp); + + return status; +} + +#else + +int +nc_close(int ncid) +{ + int status = NC_NOERR; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + { + status = NC_endef(ncp, 0, 1, 0, 1); /* TODO: defaults */ + if(status != NC_NOERR ) + { + (void) nc_abort(ncid); + return status; + } + } + else if(!NC_readonly(ncp)) + { + status = NC_sync(ncp); + } + + (void) ncio_close(ncp->nciop, 0); + ncp->nciop = NULL; + + del_from_NCList(ncp); + + free_NC(ncp); + + return status; +} +#endif /* #ifdef USE_MPI */ + +int +nc_inq(int ncid, + int *ndimsp, + int *nvarsp, + int *nattsp, + int *xtendimp) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(ndimsp != NULL) + *ndimsp = (int) ncp->dims.nelems; + if(nvarsp != NULL) + *nvarsp = (int) ncp->vars.nelems; + if(nattsp != NULL) + *nattsp = (int) ncp->attrs.nelems; + if(xtendimp != NULL) + *xtendimp = find_NC_Udim(&ncp->dims, NULL); + + return NC_NOERR; +} + +int +nc_inq_ndims(int ncid, int *ndimsp) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(ndimsp != NULL) + *ndimsp = (int) ncp->dims.nelems; + + return NC_NOERR; +} + +int +nc_inq_nvars(int ncid, int *nvarsp) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(nvarsp != NULL) + *nvarsp = (int) ncp->vars.nelems; + + return NC_NOERR; +} + +int +nc_inq_natts(int ncid, int *nattsp) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(nattsp != NULL) + *nattsp = (int) ncp->attrs.nelems; + + return NC_NOERR; +} + +int +nc_inq_unlimdim(int ncid, int *xtendimp) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(xtendimp != NULL) + *xtendimp = find_NC_Udim(&ncp->dims, NULL); + + return NC_NOERR; +} + + +int +nc_sync(int ncid) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + if(NC_readonly(ncp)) + { + return read_NC(ncp); + } + /* else, read/write */ + + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + + return ncp->nciop->sync(ncp->nciop); +} + + +int +nc_set_fill(int ncid, + int fillmode, int *old_mode_ptr) +{ + int status; + NC *ncp; + int oldmode; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL; + + if(fillmode == NC_NOFILL) + { + fSet(ncp->flags, NC_NOFILL); + } + else if(fillmode == NC_FILL) + { + if(fIsSet(ncp->flags, NC_NOFILL)) + { + /* + * We are changing back to fill mode + * so do a sync + */ + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + fClr(ncp->flags, NC_NOFILL); + } + else + { + return NC_EINVAL; /* Invalid fillmode */ + } + + if(old_mode_ptr != NULL) + *old_mode_ptr = oldmode; + + return NC_NOERR; +} + +#ifdef LOCKNUMREC + +/* create function versions of the NC_*_numrecs macros */ +size_t NC_get_numrecs(const NC *ncp) { + shmem_t numrec; + shmem_short_get(&numrec, (shmem_t *) ncp->lock + LOCKNUMREC_VALUE, 1, + ncp->lock[LOCKNUMREC_BASEPE]); + return (size_t) numrec; +} + +void NC_set_numrecs(NC *ncp, size_t nrecs) { + shmem_t numrec = (shmem_t) nrecs; + /* update local value too */ + ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrec; + shmem_short_put((shmem_t *) ncp->lock + LOCKNUMREC_VALUE, &numrec, 1, + ncp->lock[LOCKNUMREC_BASEPE]); +} + +void NC_increase_numrecs(NC *ncp, size_t nrecs) { + /* this is only called in one place that's already protected + * by a lock ... so don't worry about it */ + if (nrecs > NC_get_numrecs(ncp)) + NC_set_numrecs(ncp, nrecs); +} + +#endif /* LOCKNUMREC */ + +/* everyone in communicator group will be executing this */ +/*ARGSUSED*/ +int +nc_set_base_pe(int ncid, int pe) +{ +#if _CRAYMPP && defined(LOCKNUMREC) + int status; + NC *ncp; + shmem_t numrecs; + + if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) { + return status; + } + if (pe < 0 || pe >= _num_pes()) { + return NC_EINVAL; /* invalid base pe */ + } + + numrecs = (shmem_t) NC_get_numrecs(ncp); + + ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrecs; + + /* update serving & lock values for a "smooth" transition */ + /* note that the "real" server will being doing this as well */ + /* as all the rest in the group */ + /* must have syncronization before & after this step */ + shmem_short_get( + (shmem_t *) ncp->lock + LOCKNUMREC_SERVING, + (shmem_t *) ncp->lock + LOCKNUMREC_SERVING, + 1, ncp->lock[LOCKNUMREC_BASEPE]); + + shmem_short_get( + (shmem_t *) ncp->lock + LOCKNUMREC_LOCK, + (shmem_t *) ncp->lock + LOCKNUMREC_LOCK, + 1, ncp->lock[LOCKNUMREC_BASEPE]); + + /* complete transition */ + ncp->lock[LOCKNUMREC_BASEPE] = (ushmem_t) pe; + +#endif /* _CRAYMPP && LOCKNUMREC */ + return NC_NOERR; +} + +/*ARGSUSED*/ +int +nc_inq_base_pe(int ncid, int *pe) +{ +#if _CRAYMPP && defined(LOCKNUMREC) + int status; + NC *ncp; + + if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) { + return status; + } + + *pe = (int) ncp->lock[LOCKNUMREC_BASEPE]; +#else + /* + * !_CRAYMPP, only pe 0 is valid + */ + *pe = 0; +#endif /* _CRAYMPP && LOCKNUMREC */ + return NC_NOERR; +} Index: /branches/SDM_SciDAC/src/lib/nc.h =================================================================== --- /branches/SDM_SciDAC/src/lib/nc.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/nc.h (revision 2) @@ -0,0 +1,417 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ +#ifndef _NC_H_ +#define _NC_H_ + +/* + * netcdf library 'private' data structures, objects and interfaces + */ + +#include "ncconfig.h" +#include /* size_t */ +#include /* off_t */ +#include "netcdf.h" +#include "ncio.h" /* ncio */ +#include "fbits.h" + + +#ifndef NC_ARRAY_GROWBY +#define NC_ARRAY_GROWBY 4 +#endif + +/* + * The extern size of an empty + * netcdf version 1 file. + * The initial value of ncp->xsz. + */ +#define MIN_NC_XSZ 32 + +typedef struct NC NC; /* forward reference */ + +/* + * The internal data types + */ +typedef enum { + NC_UNSPECIFIED = 0, +/* future NC_BITFIELD = 7, */ +/* NC_STRING = 8, */ + NC_DIMENSION = 10, + NC_VARIABLE = 11, + NC_ATTRIBUTE = 12 +} NCtype; + + +/* + * Counted string for names and such + */ +typedef struct { + /* all xdr'd */ + size_t nchars; + char *cp; +} NC_string; + +extern NC * +new_NC(const size_t *chunkp); + +extern NC * +dup_NC(const NC *ref); + +/* Begin defined in string.c */ +extern void +free_NC_string(NC_string *ncstrp); + +extern int +NC_check_name(const char *name); + +extern NC_string * +new_NC_string(size_t slen, const char *str); + +extern int +set_NC_string(NC_string *ncstrp, const char *str); + +/* End defined in string.c */ + +/* + * NC dimension stucture + */ +typedef struct { + /* all xdr'd */ + NC_string *name; + size_t size; +} NC_dim; + +typedef struct NC_dimarray { + size_t nalloc; /* number allocated >= nelems */ + /* below gets xdr'd */ + /* NCtype type = NC_DIMENSION */ + size_t nelems; /* length of the array */ + NC_dim **value; +} NC_dimarray; + +/* Begin defined in dim.c */ + +extern void +free_NC_dim(NC_dim *dimp); + +extern NC_dim * +new_x_NC_dim(NC_string *name); + +extern int +find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp); + +/* dimarray */ + +extern void +free_NC_dimarrayV0(NC_dimarray *ncap); + +extern void +free_NC_dimarrayV(NC_dimarray *ncap); + +extern int +dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref); + +extern NC_dim * +elem_NC_dimarray(const NC_dimarray *ncap, size_t elem); + +/* End defined in dim.c */ + +/* + * NC attribute + */ +typedef struct { + size_t xsz; /* amount of space at xvalue */ + /* below gets xdr'd */ + NC_string *name; + nc_type type; /* the discriminant */ + size_t nelems; /* length of the array */ + void *xvalue; /* the actual data, in external representation */ +} NC_attr; + +typedef struct NC_attrarray { + size_t nalloc; /* number allocated >= nelems */ + /* below gets xdr'd */ + /* NCtype type = NC_ATTRIBUTE */ + size_t nelems; /* length of the array */ + NC_attr **value; +} NC_attrarray; + +/* Begin defined in attr.c */ + +extern void +free_NC_attr(NC_attr *attrp); + +extern NC_attr * +new_x_NC_attr( + NC_string *strp, + nc_type type, + size_t nelems); + +extern NC_attr ** +NC_findattr(const NC_attrarray *ncap, const char *name); + +/* attrarray */ + +extern void +free_NC_attrarrayV0(NC_attrarray *ncap); + +extern void +free_NC_attrarrayV(NC_attrarray *ncap); + +extern int +dup_NC_attrarrayV(NC_attrarray *ncap, const NC_attrarray *ref); + +extern NC_attr * +elem_NC_attrarray(const NC_attrarray *ncap, size_t elem); + +/* End defined in attr.c */ + + +/* + * NC variable: description and data + */ +typedef struct { + size_t xsz; /* xszof 1 element */ + size_t *shape; /* compiled info: dim->size of each dim */ + size_t *dsizes; /* compiled info: the right to left product of shape */ + /* below gets xdr'd */ + NC_string *name; + /* next two: formerly NC_iarray *assoc */ /* user definition */ + size_t ndims; /* assoc->count */ + int *dimids; /* assoc->value */ + NC_attrarray attrs; + nc_type type; /* the discriminant */ + size_t len; /* the total length originally allocated */ + off_t begin; +} NC_var; + +typedef struct NC_vararray { + size_t nalloc; /* number allocated >= nelems */ + /* below gets xdr'd */ + /* NCtype type = NC_VARIABLE */ + size_t nelems; /* length of the array */ + NC_var **value; +} NC_vararray; + +/* Begin defined in var.c */ + +extern void +free_NC_var(NC_var *varp); + +extern NC_var * +new_x_NC_var( + NC_string *strp, + size_t ndims); + +/* vararray */ + +extern void +free_NC_vararrayV0(NC_vararray *ncap); + +extern void +free_NC_vararrayV(NC_vararray *ncap); + +extern int +dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref); + +extern int +NC_var_shape(NC_var *varp, const NC_dimarray *dims); + +extern int +NC_findvar(const NC_vararray *ncap, const char *name, NC_var **varpp); + +extern NC_var * +NC_lookupvar(NC *ncp, int varid); + +/* End defined in var.c */ + +#define IS_RECVAR(vp) \ + ((vp)->shape != NULL ? (*(vp)->shape == NC_UNLIMITED) : 0 ) + +#ifdef LOCKNUMREC +/* + * typedef SHMEM type + * for whenever the SHMEM functions can handle other than shorts + */ +typedef unsigned short int ushmem_t; +typedef short int shmem_t; +#endif + +struct NC { + /* links to make list of open netcdf's */ + struct NC *next; + struct NC *prev; + /* contains the previous NC during redef. */ + struct NC *old; + /* flags */ +#define NC_INDEP 1 /* in independent data mode, cleared by endindep */ +#define NC_CREAT 2 /* in create phase, cleared by ncendef */ +#define NC_INDEF 8 /* in define mode, cleared by ncendef */ +#define NC_NSYNC 0x10 /* synchronise numrecs on change */ +#define NC_HSYNC 0x20 /* synchronise whole header on change */ +#define NC_NDIRTY 0x40 /* numrecs has changed */ +#define NC_HDIRTY 0x80 /* header info has changed */ +/* NC_NOFILL in netcdf.h, historical interface */ + int flags; + ncio *nciop; + size_t chunk; /* largest extent this layer will request from ncio->get() */ + size_t xsz; /* external size of this header, <= var[0].begin */ + off_t begin_var; /* postion of the first (non-record) var */ + off_t begin_rec; /* postion of the first 'record' */ + size_t recsize; /* length of 'record' */ + /* below gets xdr'd */ + size_t numrecs; /* number of 'records' allocated */ + NC_dimarray dims; + NC_attrarray attrs; + NC_vararray vars; +}; + +#define NC_readonly(ncp) \ + (!fIsSet(ncp->nciop->ioflags, NC_WRITE)) + +#define NC_IsNew(ncp) \ + fIsSet((ncp)->flags, NC_CREAT) + +#define NC_indep(ncp) \ + fIsSet((ncp)->flags, NC_INDEP) + +#define NC_indef(ncp) \ + (NC_IsNew(ncp) || fIsSet((ncp)->flags, NC_INDEF)) + +#define set_NC_ndirty(ncp) \ + fSet((ncp)->flags, NC_NDIRTY) + +#define NC_ndirty(ncp) \ + fIsSet((ncp)->flags, NC_NDIRTY) + +#define set_NC_hdirty(ncp) \ + fSet((ncp)->flags, NC_HDIRTY) + +#define NC_hdirty(ncp) \ + fIsSet((ncp)->flags, NC_HDIRTY) + +#define NC_dofill(ncp) \ + (!fIsSet((ncp)->flags, NC_NOFILL)) + +#define NC_doHsync(ncp) \ + fIsSet((ncp)->flags, NC_HSYNC) + +#define NC_doNsync(ncp) \ + fIsSet((ncp)->flags, NC_NSYNC) + +#ifndef LOCKNUMREC +# define NC_get_numrecs(ncp) \ + ((ncp)->numrecs) + +# define NC_set_numrecs(ncp, nrecs) \ + {((ncp)->numrecs = (nrecs));} + +# define NC_increase_numrecs(ncp, nrecs) \ + {if((nrecs) > (ncp)->numrecs) ((ncp)->numrecs = (nrecs));} +#else + size_t NC_get_numrecs(const NC *ncp); + void NC_set_numrecs(NC *ncp, size_t nrecs); + void NC_increase_numrecs(NC *ncp, size_t nrecs); +#endif + +/* Begin defined in nc.c */ + +extern int +NC_check_id(int ncid, NC **ncpp); + +extern int +nc_cktype(nc_type datatype); + +extern size_t +ncx_howmany(nc_type type, size_t xbufsize); + +extern int +read_numrecs(NC *ncp); + +extern int +write_numrecs(NC *ncp); + +extern int +NC_sync(NC *ncp); + +/* End defined in nc.c */ +/* Begin defined in v1hpg.c */ + +extern size_t +ncx_len_NC(const NC *ncp); + +extern int +ncx_put_NC(const NC *ncp, void **xpp, off_t offset, size_t extent); + +extern int +nc_get_NC( NC *ncp); + +/* End defined in v1hpg.c */ +/* Begin defined in putget.c */ + +extern int +fill_NC_var(NC *ncp, const NC_var *varp, size_t recno); + +extern int +nc_inq_rec(int ncid, size_t *nrecvars, int *recvarids, size_t *recsizes); + +extern int +nc_get_rec(int ncid, size_t recnum, void **datap); + +extern int +nc_put_rec(int ncid, size_t recnum, void *const *datap); + +/* End defined in putget.c */ + +/* + * These functions are used to support + * interface version 2 backward compatiblity. + * N.B. these are tested in ../nc_test even though they are + * not public. So, be careful to change the declarations in + * ../nc_test/tests.h if you change these. + */ + +extern int +nc_put_att(int ncid, int varid, const char *name, nc_type datatype, + size_t len, const void *value); + +extern int +nc_get_att(int ncid, int varid, const char *name, void *value); + +extern int +nc_put_var1(int ncid, int varid, const size_t *index, const void *value); + +extern int +nc_get_var1(int ncid, int varid, const size_t *index, void *value); + +extern int +nc_put_vara(int ncid, int varid, + const size_t *start, const size_t *count, const void *value); + +extern int +nc_get_vara(int ncid, int varid, + const size_t *start, const size_t *count, void *value); + +extern int +nc_put_vars(int ncid, int varid, + const size_t *start, const size_t *count, const ptrdiff_t *stride, + const void * value); + +extern int +nc_get_vars(int ncid, int varid, + const size_t *start, const size_t *count, const ptrdiff_t *stride, + void * value); + +extern int +nc_put_varm(int ncid, int varid, + const size_t *start, const size_t *count, const ptrdiff_t *stride, + const ptrdiff_t * map, const void *value); + +extern int +nc_get_varm(int ncid, int varid, + const size_t *start, const size_t *count, const ptrdiff_t *stride, + const ptrdiff_t * map, void *value); + +#endif /* _NC_H_ */ Index: /branches/SDM_SciDAC/src/lib/string.c =================================================================== --- /branches/SDM_SciDAC/src/lib/string.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/string.c (revision 2) @@ -0,0 +1,120 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include +#include "ncx.h" +#include "rnd.h" + + +/* + * Free string, and, if needed, its values. + * Formerly +NC_free_string() + */ +void +free_NC_string(NC_string *ncstrp) +{ + if(ncstrp==NULL) + return; + free(ncstrp); +} + + +/* + * Verify that a name string is valid + * CDL syntax, eg, all the characters are + * alphanumeric, '-', '_', or '.'. + */ +int +NC_check_name(const char *name) +{ + const char *cp = name; + assert(name != NULL); + + if(*name == 0) + return NC_EBADNAME; /* empty names disallowed */ + + for(; *cp != 0; cp++) + { + int ch = *cp; + if(!isalnum(ch)) + { + if(ch != '_' && ch != '-' && ch != '.') + return NC_EBADNAME; + } + } + if(cp - name > NC_MAX_NAME) + return NC_EMAXNAME; + + return NC_NOERR; +} + + +/* + * Allocate a NC_string structure large enough + * to hold slen characters. + * Formerly +NC_new_string(count, str) + */ +NC_string * +new_NC_string(size_t slen, const char *str) +{ + NC_string *ncstrp; + size_t sz = M_RNDUP(sizeof(NC_string)) + slen + 1; + +#if 0 + sz = _RNDUP(sz, X_ALIGN); +#endif + + ncstrp = (NC_string *)malloc(sz); + if( ncstrp == NULL ) + return NULL; + (void) memset(ncstrp, 0, sz); + + ncstrp->nchars = sz - M_RNDUP(sizeof(NC_string)) - 1; + assert(ncstrp->nchars + 1 > slen); + ncstrp->cp = (char *)ncstrp + M_RNDUP(sizeof(NC_string)); + + if(str != NULL && *str != 0) + { + (void) strncpy(ncstrp->cp, str, ncstrp->nchars +1); + ncstrp->cp[ncstrp->nchars] = 0; + } + + return(ncstrp); +} + + +/* + * If possible, change the value of an NC_string to 'str'. + * + * Formerly +NC_re_string() + */ +int +set_NC_string(NC_string *ncstrp, const char *str) +{ + size_t slen; + size_t diff; + + assert(str != NULL && *str != 0); + + slen = strlen(str); + + if(ncstrp->nchars < slen) + return NC_ENOTINDEFINE; + + (void) memcpy(ncstrp->cp, str, slen); + diff = ncstrp->nchars - slen; + if(diff != 0) + (void) memset(ncstrp->cp + slen, 0, diff); + + return NC_NOERR; +} Index: /branches/SDM_SciDAC/src/lib/onstack.h =================================================================== --- /branches/SDM_SciDAC/src/lib/onstack.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/onstack.h (revision 2) @@ -0,0 +1,72 @@ +/* + * Copyright 1997, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#ifndef _ONSTACK_H_ +#define _ONSTACK_H_ +/* include after ncconfig.h */ +/** + * This file provides definitions which allow us to + * "allocate" arrays on the stack where possible. + * (Where not possible, malloc and free are used.) + * + * The macro ALLOC_ONSTACK(name, type, nelems) is used to declare + * an array of 'type' named 'name' which is 'nelems' long. + * FREE_ONSTACK(name) is placed at the end of the scope of 'name' + * to call 'free' if necessary. + * + * The macro ALLOC_ONSTACK wraps a call to alloca() on most systems. + */ + +#if HAVE_ALLOCA +/* + * Implementation based on alloca() + */ + +#if defined(__GNUC__) +# if !defined(alloca) +# define alloca __builtin_alloca +# endif +#else +# if HAVE_ALLOCA_H +# include +# elif defined(_AIX) +# pragma alloca +# endif /* HAVE_ALLOCA_H */ +#endif /* __GNUC__ */ + +# if !defined(ALLOCA_ARG_T) +# define ALLOCA_ARG_T int /* the usual type of the alloca argument */ +# endif + +# define ALLOC_ONSTACK(name, type, nelems) \ + type *const name = (type *) alloca((ALLOCA_ARG_T)((nelems) * sizeof(type))) + +# define FREE_ONSTACK(name) + +#elif defined(_CRAYC) && !__cplusplus && __STDC__ > 1 +/* + * Cray C allows sizing of arrays with non-constant values. + */ + +# define ALLOC_ONSTACK(name, type, nelems) \ + type name[nelems] + +# define FREE_ONSTACK(name) + +#else +/* + * Default implementation. When all else fails, use malloc/free. + */ + +# define ALLOC_ONSTACK(name, type, nelems) \ + type *const name = (type *) malloc((nelems) * sizeof(type)) + +# define FREE_ONSTACK(name) \ + free(name) + +#endif + +#endif /* _ONSTACK_H_ */ Index: /branches/SDM_SciDAC/src/lib/netcdf.h =================================================================== --- /branches/SDM_SciDAC/src/lib/netcdf.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/netcdf.h (revision 2) @@ -0,0 +1,1075 @@ +/* + * Copyright 1993-1996 University Corporation for Atmospheric Research/Unidata + * + * Portions of this software were developed by the Unidata Program at the + * University Corporation for Atmospheric Research. + * + * Access and use of this software shall impose the following obligations + * and understandings on the user. The user is granted the right, without + * any fee or cost, to use, copy, modify, alter, enhance and distribute + * this software, and any derivative works thereof, and its supporting + * documentation for any purpose whatsoever, provided that this entire + * notice appears in all copies of the software, derivative works and + * supporting documentation. Further, UCAR requests that the user credit + * UCAR/Unidata in any publications that result from the use of this + * software or in any product that includes this software. The names UCAR + * and/or Unidata, however, may not be used in any advertising or publicity + * to endorse or promote any products or commercial entity unless specific + * written permission is obtained from UCAR/Unidata. The user also + * understands that UCAR/Unidata is not obligated to provide the user with + * any support, consulting, training or assistance of any kind with regard + * to the use, operation and performance of this software nor to provide + * the user with any updates, revisions, new versions or "bug fixes." + * + * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* "$Id$" */ + +#ifndef _NETCDF_ +#define _NETCDF_ + +#include /* size_t, ptrdiff_t */ +#include /* netcdf functions sometimes return system errors */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * The netcdf external data types + */ +typedef enum { + NC_NAT = 0, /* NAT = 'Not A Type' (c.f. NaN) */ + NC_BYTE = 1, /* signed 1 byte integer */ + NC_CHAR = 2, /* ISO/ASCII character */ + NC_SHORT = 3, /* signed 2 byte integer */ + NC_INT = 4, /* signed 4 byte integer */ + NC_FLOAT = 5, /* single precision floating point number */ + NC_DOUBLE = 6 /* double precision floating point number */ +} nc_type; + + +/* + * Default fill values, used unless _FillValue attribute is set. + * These values are stuffed into newly allocated space as appropriate. + * The hope is that one might use these to notice that a particular datum + * has not been set. + */ +#define NC_FILL_BYTE ((signed char)-127) +#define NC_FILL_CHAR ((char)0) +#define NC_FILL_SHORT ((short)-32767) +#define NC_FILL_INT (-2147483647L) +#define NC_FILL_FLOAT (9.9692099683868690e+36f) /* near 15 * 2^119 */ +#define NC_FILL_DOUBLE (9.9692099683868690e+36) + + +/* + * The above values are defaults. + * If you wish a variable to use a different value than the above + * defaults, create an attribute with the same type as the variable + * and the following reserved name. The value you give the attribute + * will be used as the fill value for that variable. + */ +#define _FillValue "_FillValue" + + +/* + * 'mode' flags for nccreate and ncopen + */ +#define NC_NOWRITE 0 /* default is read only */ +#define NC_WRITE 0x1 /* read & write */ +#define NC_CLOBBER 0 +#define NC_NOCLOBBER 0x4 /* Don't destroy existing file on create */ +#define NC_FILL 0 /* argument to ncsetfill to clear NC_NOFILL */ +#define NC_NOFILL 0x100 /* Don't fill data section an records */ +#define NC_LOCK 0x0400 /* Use locking if available */ +#define NC_SHARE 0x0800 /* Share updates, limit cacheing */ + +/* + * Let nc__create() or nc__open() figure out + * as suitable chunk size. + */ +#define NC_SIZEHINT_DEFAULT 0 + +/* + * In nc__enddef(), align to the chunk size. + */ +#define NC_ALIGN_CHUNK ((size_t)(-1)) + +/* + * 'size' argument to ncdimdef for an unlimited dimension + */ +#define NC_UNLIMITED 0L + +/* + * attribute id to put/get a global attribute + */ +#define NC_GLOBAL -1 + + +/* + * These maximums are enforced by the interface, to facilitate writing + * applications and utilities. However, nothing is statically allocated to + * these sizes internally. + */ +#define NC_MAX_DIMS 100 /* max dimensions per file */ +#define NC_MAX_ATTRS 2000 /* max global or per variable attributes */ +#define NC_MAX_VARS 2000 /* max variables per file */ +#define NC_MAX_NAME 128 /* max length of a name */ +#define NC_MAX_VAR_DIMS NC_MAX_DIMS /* max per variable dimensions */ + + +/* + * The netcdf version 3 functions all return integer error status. + * These are the possible values, in addition to certain + * values from the system errno.h. + */ + +#define NC_ISSYSERR(err) ((err) > 0) + +#define NC_NOERR 0 /* No Error */ + +#define NC_ENOTINDEP (-26) /* Operation not allowed in collective data mode */ +#define NC_EINDEP (-27) /* Operation not allowed in independent data mode */ +#define NC_EREAD (-29) /* Unknown error in reading file */ +#define NC_EWRITE (-30) /* Unknown error in writting to file */ +#define NC_EMULTIDEFINE (-31) /* NC definations on multiprocesses conflict */ +#define NC_EOFILE (-32) /* file open/creation failed */ +#define NC_EBADID (-33) /* Not a netcdf id */ +#define NC_ENFILE (-34) /* Too many netcdfs open */ +#define NC_EEXIST (-35) /* netcdf file exists && NC_NOCLOBBER */ +#define NC_EINVAL (-36) /* Invalid Argument */ +#define NC_EPERM (-37) /* Write to read only */ +#define NC_ENOTINDEFINE (-38) /* Operation not allowed in data mode */ +#define NC_EINDEFINE (-39) /* Operation not allowed in define mode */ +#define NC_EINVALCOORDS (-40) /* Index exceeds dimension bound */ +#define NC_EMAXDIMS (-41) /* NC_MAX_DIMS exceeded */ +#define NC_ENAMEINUSE (-42) /* String match to name in use */ +#define NC_ENOTATT (-43) /* Attribute not found */ +#define NC_EMAXATTS (-44) /* NC_MAX_ATTRS exceeded */ +#define NC_EBADTYPE (-45) /* Not a netcdf data type */ +#define NC_EBADDIM (-46) /* Invalid dimension id or name */ +#define NC_EUNLIMPOS (-47) /* NC_UNLIMITED in the wrong index */ +#define NC_EMAXVARS (-48) /* NC_MAX_VARS exceeded */ +#define NC_ENOTVAR (-49) /* Variable not found */ +#define NC_EGLOBAL (-50) /* Action prohibited on NC_GLOBAL varid */ +#define NC_ENOTNC (-51) /* Not a netcdf file */ +#define NC_ESTS (-52) /* In Fortran, string too short */ +#define NC_EMAXNAME (-53) /* NC_MAX_NAME exceeded */ +#define NC_EUNLIMIT (-54) /* NC_UNLIMITED size already in use */ +#define NC_ENORECVARS (-55) /* nc_rec op when there are no record vars */ +#define NC_ECHAR (-56) /* Attempt to convert between text & numbers */ +#define NC_EEDGE (-57) /* Edge+start exceeds dimension bound */ +#define NC_ESTRIDE (-58) /* Illegal stride */ +#define NC_EBADNAME (-59) /* Attribute or variable name + contains illegal characters */ +/* N.B. following must match value in ncx.h */ +#define NC_ERANGE (-60) /* Math result not representable */ +#define NC_ENOMEM (-61) /* Memory allocation (malloc) failure */ + +/* + * The Interface + */ + +/* Declaration modifiers for DLL support (MSC et al) */ + +#if defined(DLL_NETCDF) /* define when library is a DLL */ +# if defined(DLL_EXPORT) /* define when building the library */ +# define MSC_EXTRA __declspec(dllexport) +# else +# define MSC_EXTRA __declspec(dllimport) +# endif +#else +#define MSC_EXTRA +#endif /* defined(DLL_NETCDF) */ + +# define EXTERNL extern MSC_EXTRA + +#ifndef USE_MPIO /* interfaces below removed by Jianwei Li */ + +/* Begin v2.4 backward compatiblity */ +/* + * defining NO_NETCDF_2 to the preprocessor + * turns off backward compatiblity declarations. + */ +#ifndef NO_NETCDF_2 + +/* + * Backward compatible aliases + */ +#define FILL_BYTE NC_FILL_BYTE +#define FILL_CHAR NC_FILL_CHAR +#define FILL_SHORT NC_FILL_SHORT +#define FILL_LONG NC_FILL_INT +#define FILL_FLOAT NC_FILL_FLOAT +#define FILL_DOUBLE NC_FILL_DOUBLE + +#define MAX_NC_DIMS NC_MAX_DIMS +#define MAX_NC_ATTRS NC_MAX_ATTRS +#define MAX_NC_VARS NC_MAX_VARS +#define MAX_NC_NAME NC_MAX_NAME +#define MAX_VAR_DIMS NC_MAX_VAR_DIMS + +/* + * If and when 64 integer types become ubiquitous, + * we would like to use NC_LONG for that. + * For now, define for backward compatibility. + */ +#define NC_LONG NC_INT + +/* + * Global error status + */ +EXTERNL int ncerr; + +#define NC_ENTOOL NC_EMAXNAME /* Backward compatibility */ +#define NC_EXDR (-32) /* */ +#define NC_SYSERR (-31) + +/* + * Avoid use of this meaningless macro + * Use sysconf(_SC_OPEN_MAX). + */ +#ifndef MAX_NC_OPEN +#define MAX_NC_OPEN 32 +#endif + +/* + * Global options variable. + * Used to determine behavior of error handler. + */ +#define NC_FATAL 1 +#define NC_VERBOSE 2 + +EXTERNL int ncopts; /* default is (NC_FATAL | NC_VERBOSE) */ + +EXTERNL void +nc_advise(const char *cdf_routine_name, int err, const char *fmt,...); + +/* + * C data type corresponding to a netCDF NC_LONG argument, + * a signed 32 bit object. + * + * This is the only thing in this file which architecture dependent. + */ +typedef int nclong; + +EXTERNL int +nctypelen(nc_type datatype); + +EXTERNL int +nccreate(const char* path, int cmode); + +EXTERNL int +ncopen(const char* path, int mode); + +EXTERNL int +ncsetfill(int ncid, int fillmode); + +EXTERNL int +ncredef(int ncid); + +EXTERNL int +ncendef(int ncid); + +EXTERNL int +ncsync(int ncid); + +EXTERNL int +ncabort(int ncid); + +EXTERNL int +ncclose(int ncid); + +EXTERNL int +ncinquire(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimp); + +EXTERNL int +ncdimdef(int ncid, const char *name, long len); + +EXTERNL int +ncdimid(int ncid, const char *name); + +EXTERNL int +ncdiminq(int ncid, int dimid, char *name, long *lenp); + +EXTERNL int +ncdimrename(int ncid, int dimid, const char *name); + +EXTERNL int +ncattput(int ncid, int varid, const char *name, nc_type xtype, + int len, const void *op); + +EXTERNL int +ncattinq(int ncid, int varid, const char *name, nc_type *xtypep, int *lenp); + +EXTERNL int +ncattget(int ncid, int varid, const char *name, void *ip); + +EXTERNL int +ncattcopy(int ncid_in, int varid_in, const char *name, int ncid_out, + int varid_out); + +EXTERNL int +ncattname(int ncid, int varid, int attnum, char *name); + +EXTERNL int +ncattrename(int ncid, int varid, const char *name, const char *newname); + +EXTERNL int +ncattdel(int ncid, int varid, const char *name); + +EXTERNL int +ncvardef(int ncid, const char *name, nc_type xtype, + int ndims, const int *dimidsp); + +EXTERNL int +ncvarid(int ncid, const char *name); + +EXTERNL int +ncvarinq(int ncid, int varid, char *name, nc_type *xtypep, + int *ndimsp, int *dimidsp, int *nattsp); + +EXTERNL int +ncvarput1(int ncid, int varid, const long *indexp, const void *op); + +EXTERNL int +ncvarget1(int ncid, int varid, const long *indexp, void *ip); + +EXTERNL int +ncvarput(int ncid, int varid, const long *startp, const long *countp, + const void *op); + +EXTERNL int +ncvarget(int ncid, int varid, const long *startp, const long *countp, + void *ip); + +EXTERNL int +ncvarputs(int ncid, int varid, const long *startp, const long *countp, + const long *stridep, const void *op); + +EXTERNL int +ncvargets(int ncid, int varid, const long *startp, const long *countp, + const long *stridep, void *ip); + +EXTERNL int +ncvarputg(int ncid, int varid, const long *startp, const long *countp, + const long *stridep, const long *imapp, const void *op); + +EXTERNL int +ncvargetg(int ncid, int varid, const long *startp, const long *countp, + const long *stridep, const long *imapp, void *ip); + +EXTERNL int +ncvarrename(int ncid, int varid, const char *name); + +EXTERNL int +ncrecinq(int ncid, int *nrecvarsp, int *recvaridsp, long *recsizesp); + +EXTERNL int +ncrecget(int ncid, long recnum, void **datap); + +EXTERNL int +ncrecput(int ncid, long recnum, void *const *datap); + +/* End v2.4 backward compatiblity */ +#endif /*!NO_NETCDF_2*/ + +#endif /* USE_MPIO */ + +#if defined(__cplusplus) +} +#endif + +#ifdef USE_MPIO /* interface implemented by Jianwei Li */ + +#include + +EXTERNL +const char * +ncmpi_strerror(int err); + +/* Begin Dataset Functions */ + +EXTERNL +int +ncmpi_create(MPI_Comm comm, const char *path, int cmode, MPI_Info info, int *ncidp); + +EXTERNL +int +ncmpi_open(MPI_Comm comm, const char *path, int omode, MPI_Info info, int *ncidp); + +EXTERNL +int +ncmpi_enddef(int ncid); + +EXTERNL +int +ncmpi_redef(int ncid); + +EXTERNL +int +ncmpi_sync(int ncid); + +EXTERNL +int +ncmpi_abort(int ncid); + +EXTERNL +int +ncmpi_begin_indep_data(int ncid); + +EXTERNL +int +ncmpi_end_indep_data(int ncid); + +EXTERNL +int +ncmpi_close(int ncid); + +/* End Dataset Functions */ + +/* Begin Define Mode Functions */ + +EXTERNL +int +ncmpi_def_dim(int ncid, const char *name, size_t len, int *idp); + +EXTERNL +int +ncmpi_def_var(int ncid, const char *name, nc_type xtype, + int ndims, const int *dimidsp, int *varidp); + +EXTERNL +int +ncmpi_rename_dim(int ncid, int dimid, const char *name); + +EXTERNL +int +ncmpi_rename_var(int ncid, int varid, const char *name); + +/* End Define Mode Functions */ + +/* Begin Inquiry Functions */ + +EXTERNL +int +ncmpi_inq(int ncid, int *ndimsp, int *nvarsp, + int *ngattsp, int *unlimdimidp); + +EXTERNL +int +ncmpi_inq_ndims(int ncid, int *ndimsp); + +EXTERNL +int +ncmpi_inq_nvars(int ncid, int *nvarsp); + +EXTERNL +int +ncmpi_inq_natts(int ncid, int *ngattsp); + +EXTERNL +int +ncmpi_inq_unlimdim(int ncid, int *unlimdimidp); + +EXTERNL +int +ncmpi_inq_dimid(int ncid, const char *name, int *idp); + +EXTERNL +int +ncmpi_inq_dim(int ncid, int dimid, char *name, size_t *lenp); + +EXTERNL +int +ncmpi_inq_dimname(int ncid, int dimid, char *name); + +EXTERNL +int +ncmpi_inq_dimlen(int ncid, int dimid, size_t *lenp); + +EXTERNL +int +ncmpi_inq_var(int ncid, int varid, char *name, + nc_type *xtypep, int *ndimsp, int *dimidsp, + int *nattsp); + +EXTERNL +int +ncmpi_inq_varid(int ncid, const char *name, int *varidp); + +EXTERNL +int +ncmpi_inq_varname(int ncid, int varid, char *name); + +EXTERNL +int +ncmpi_inq_vartype(int ncid, int varid, nc_type *xtypep); + +EXTERNL +int +ncmpi_inq_varndims(int ncid, int varid, int *ndimsp); + +EXTERNL +int +ncmpi_inq_vardimid(int ncid, int varid, int *dimidsp); + +EXTERNL +int +ncmpi_inq_varnatts(int ncid, int varid, int *nattsp); + +/* End Inquiry Functions */ + +/* Begin _att */ + +EXTERNL +int +ncmpi_inq_att(int ncid, int varid, const char *name, + nc_type *xtypep, size_t *lenp); + +EXTERNL +int +ncmpi_inq_attid(int ncid, int varid, const char *name, int *idp); + +EXTERNL +int +ncmpi_inq_atttype(int ncid, int varid, const char *name, + nc_type *xtypep); + +EXTERNL +int +ncmpi_inq_attlen(int ncid, int varid, const char *name, + size_t *lenp); + +EXTERNL +int +ncmpi_inq_attname(int ncid, int varid, int attnum, char *name); + +EXTERNL +int +ncmpi_copy_att(int ncid_in, int varid_in, const char *name, + int ncid_out, int varid_out); + +EXTERNL +int +ncmpi_rename_att(int ncid, int varid, const char *name, + const char *newname); + +EXTERNL +int +ncmpi_del_att(int ncid, int varid, const char *name); + +EXTERNL +int +ncmpi_put_att_text(int ncid, int varid, const char *name, size_t len, + const char *op); + +EXTERNL +int +ncmpi_get_att_text(int ncid, int varid, const char *name, char *ip); + +EXTERNL +int +ncmpi_put_att_uchar(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const unsigned char *op); + +EXTERNL +int +ncmpi_get_att_uchar(int ncid, int varid, const char *name, + unsigned char *ip); + +EXTERNL +int +ncmpi_put_att_schar(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const signed char *op); + +EXTERNL +int +ncmpi_get_att_schar(int ncid, int varid, const char *name, + signed char *ip); + +EXTERNL +int +ncmpi_put_att_short(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const short *op); + +EXTERNL +int +ncmpi_get_att_short(int ncid, int varid, const char *name, short *ip); + +EXTERNL +int +ncmpi_put_att_int(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const int *op); + +EXTERNL +int +ncmpi_get_att_int(int ncid, int varid, const char *name, int *ip); + +EXTERNL +int +ncmpi_put_att_long(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const long *op); + +EXTERNL +int +ncmpi_get_att_long(int ncid, int varid, const char *name, long *ip); + +EXTERNL +int +ncmpi_put_att_float(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const float *op); + +EXTERNL +int +ncmpi_get_att_float(int ncid, int varid, const char *name, float *ip); + +EXTERNL +int +ncmpi_put_att_double(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const double *op); + +EXTERNL +int +ncmpi_get_att_double(int ncid, int varid, const char *name, + double *ip); + +/* End _att */ + +/* Begin {put,get}_var1 */ + +EXTERNL +int +ncmpi_put_var1(int ncid, int varid, + const size_t index[], + const void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_var1(int ncid, int varid, + const size_t index[], + void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_var1_short(int ncid, int varid, + const size_t index[], + const short *op); + +EXTERNL +int +ncmpi_put_var1_int(int ncid, int varid, + const size_t index[], + const int *op); + +EXTERNL +int +ncmpi_put_var1_float(int ncid, int varid, + const size_t index[], + const float *op); + +EXTERNL +int +ncmpi_put_var1_double(int ncid, int varid, + const size_t index[], + const double *op); + +EXTERNL +int +ncmpi_get_var1_short(int ncid, int varid, + const size_t index[], + short *ip); + +EXTERNL +int +ncmpi_get_var1_int(int ncid, int varid, + const size_t index[], + int *ip); + +EXTERNL +int +ncmpi_get_var1_float(int ncid, int varid, + const size_t index[], + float *ip); + +EXTERNL +int +ncmpi_get_var1_double(int ncid, int varid, + const size_t index[], + double *ip); + +/* End {put,get}_var1 */ + +/* Begin {put,get}_var */ + +EXTERNL +int +ncmpi_put_var(int ncid, int varid, const void *buf, int bufcount, MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_var(int ncid, int varid, void *buf, int bufcount, MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_var_all(int ncid, int varid, void *buf, int bufcount, MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_var_short(int ncid, int varid, const short *op); + +EXTERNL +int +ncmpi_put_var_int(int ncid, int varid, const int *op); + +EXTERNL +int +ncmpi_put_var_float(int ncid, int varid, const float *op); + +EXTERNL +int +ncmpi_put_var_double(int ncid, int varid, const double *op); + +EXTERNL +int +ncmpi_get_var_short(int ncid, int varid, short *ip); + +EXTERNL +int +ncmpi_get_var_int(int ncid, int varid, int *ip); + +EXTERNL +int +ncmpi_get_var_float(int ncid, int varid, float *ip); + +EXTERNL +int +ncmpi_get_var_double(int ncid, int varid, double *ip); + +EXTERNL +int +ncmpi_get_var_short_all(int ncid, int varid, short *ip); + +EXTERNL +int +ncmpi_get_var_int_all(int ncid, int varid, int *ip); + +EXTERNL +int +ncmpi_get_var_float_all(int ncid, int varid, float *ip); + +EXTERNL +int +ncmpi_get_var_double_all(int ncid, int varid, double *ip); + +/* End {put,get}_var */ + +/* Begin {put,get}_vara */ + +EXTERNL +int +ncmpi_put_vara_all(int ncid, int varid, + const size_t start[], const size_t count[], + const void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_vara_all(int ncid, int varid, + const size_t start[], const size_t count[], + void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_vara(int ncid, int varid, + const size_t start[], const size_t count[], + const void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_vara(int ncid, int varid, + const size_t start[], const size_t count[], + void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_vara_short_all(int ncid, int varid, + const size_t start[], const size_t count[], + const short *op); + +EXTERNL +int +ncmpi_put_vara_short(int ncid, int varid, + const size_t start[], const size_t count[], + const short *op); + +EXTERNL +int +ncmpi_put_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op); + +EXTERNL +int +ncmpi_put_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op); + +EXTERNL +int +ncmpi_put_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op); + +EXTERNL +int +ncmpi_put_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op); + +EXTERNL +int +ncmpi_put_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op); + +EXTERNL +int +ncmpi_put_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op); + +EXTERNL +int +ncmpi_get_vara_short_all(int ncid, int varid, + const size_t start[], const size_t count[], + short *ip); + +EXTERNL +int +ncmpi_get_vara_short(int ncid, int varid, + const size_t start[], const size_t count[], + short *ip); + +EXTERNL +int +ncmpi_get_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip); + +EXTERNL +int +ncmpi_get_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip); + +EXTERNL +int +ncmpi_get_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip); + +EXTERNL +int +ncmpi_get_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip); + +EXTERNL +int +ncmpi_get_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip); + +EXTERNL +int +ncmpi_get_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip); + +/* End {put,get}_vara */ + +/* Begin {put,get}_vars */ + +EXTERNL +int +ncmpi_put_vars_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_vars_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_vars(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_get_vars(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + void *buf, int bufcount, + MPI_Datatype datatype); + +EXTERNL +int +ncmpi_put_vars_short_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const short *op); + +EXTERNL +int +ncmpi_put_vars_short(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const short *op); + +EXTERNL +int +ncmpi_put_vars_int_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const int *op); + +EXTERNL +int +ncmpi_put_vars_int(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const int *op); + +EXTERNL +int +ncmpi_put_vars_float_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const float *op); + +EXTERNL +int +ncmpi_put_vars_float(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const float *op); + +EXTERNL +int +ncmpi_put_vars_double_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const double *op); + +EXTERNL +int +ncmpi_put_vars_double(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const double *op); + +EXTERNL +int +ncmpi_get_vars_short_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + short *ip); + +EXTERNL +int +ncmpi_get_vars_short(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + short *ip); + +EXTERNL +int +ncmpi_get_vars_int_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + int *ip); + +EXTERNL +int +ncmpi_get_vars_int(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + int *ip); + +EXTERNL +int +ncmpi_get_vars_float_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + float *ip); + +EXTERNL +int +ncmpi_get_vars_float(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + float *ip); + +EXTERNL +int +ncmpi_get_vars_double_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + double *ip); + +EXTERNL +int +ncmpi_get_vars_double(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + double *ip); + +/* End {put,get}_vars */ + +#endif /* USE_MPIO */ + +#endif /* _NETCDF_ */ Index: /branches/SDM_SciDAC/src/lib/putget.c =================================================================== --- /branches/SDM_SciDAC/src/lib/putget.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/putget.c (revision 2) @@ -0,0 +1,11789 @@ +/* Do not edit this file. It is produced from the corresponding .m4 source */ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include "ncx.h" +#include "fbits.h" +#include "onstack.h" +#ifdef LOCKNUMREC +# include /* for SGI/Cray SHMEM routines */ +# ifdef LN_TEST +# include +# endif +#endif + +#undef MIN /* system may define MIN somewhere and complain */ +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +/* #define ODEBUG 1 */ + +#if ODEBUG +#include +/* + * Print the values of an array of size_t + */ +void +arrayp(const char *label, size_t count, const size_t *array) +{ + (void) fprintf(stderr, "%s", label); + (void) fputc('\t',stderr); + for(; count > 0; count--, array++) + (void) fprintf(stderr," %lu", (unsigned long)*array); + (void) fputc('\n',stderr); +} +#endif /* ODEBUG */ + + +/* Begin fill */ +/* + * This is tunable parameter. + * It essentially controls the tradeoff between the number of times + * memcpy() gets called to copy the external data to fill + * a large buffer vs the number of times its called to + * prepare the external data. + */ +#define NFILL 16 + + + +/* + * Next 6 type specific functions + * Fill a some memory with the default special value. + * Formerly +NC_arrayfill() + */ +static int +NC_fill_schar( + void **xpp, + size_t nelems) /* how many */ +{ + schar fillp[NFILL * sizeof(double)/X_SIZEOF_CHAR]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + schar *vp = fillp; /* lower bound of area to be filled */ + const schar *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_BYTE; + } + } + return ncx_putn_schar_schar(xpp, nelems, fillp); +} + +static int +NC_fill_char( + void **xpp, + size_t nelems) /* how many */ +{ + char fillp[NFILL * sizeof(double)/X_SIZEOF_CHAR]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + char *vp = fillp; /* lower bound of area to be filled */ + const char *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_CHAR; + } + } + return ncx_putn_char_char(xpp, nelems, fillp); +} + +static int +NC_fill_short( + void **xpp, + size_t nelems) /* how many */ +{ + short fillp[NFILL * sizeof(double)/X_SIZEOF_SHORT]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + short *vp = fillp; /* lower bound of area to be filled */ + const short *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_SHORT; + } + } + return ncx_putn_short_short(xpp, nelems, fillp); +} + + +#if (SIZEOF_INT >= X_SIZEOF_INT) +static int +NC_fill_int( + void **xpp, + size_t nelems) /* how many */ +{ + int fillp[NFILL * sizeof(double)/X_SIZEOF_INT]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + int *vp = fillp; /* lower bound of area to be filled */ + const int *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_INT; + } + } + return ncx_putn_int_int(xpp, nelems, fillp); +} + +#elif SIZEOF_LONG == X_SIZEOF_INT +static int +NC_fill_int( + void **xpp, + size_t nelems) /* how many */ +{ + long fillp[NFILL * sizeof(double)/X_SIZEOF_INT]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + long *vp = fillp; /* lower bound of area to be filled */ + const long *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_INT; + } + } + return ncx_putn_int_long(xpp, nelems, fillp); +} + +#else +#error "NC_fill_int implementation" +#endif + +static int +NC_fill_float( + void **xpp, + size_t nelems) /* how many */ +{ + float fillp[NFILL * sizeof(double)/X_SIZEOF_FLOAT]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + float *vp = fillp; /* lower bound of area to be filled */ + const float *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_FLOAT; + } + } + return ncx_putn_float_float(xpp, nelems, fillp); +} + +static int +NC_fill_double( + void **xpp, + size_t nelems) /* how many */ +{ + double fillp[NFILL * sizeof(double)/X_SIZEOF_DOUBLE]; + + assert(nelems <= sizeof(fillp)/sizeof(fillp[0])); + + { + double *vp = fillp; /* lower bound of area to be filled */ + const double *const end = vp + nelems; + while(vp < end) + { + *vp++ = NC_FILL_DOUBLE; + } + } + return ncx_putn_double_double(xpp, nelems, fillp); +} + + + +/* + * Fill the external space for variable 'varp' values at 'recno' + * with the appropriate value. If 'varp' is not a record + * variable, fill the whole thing. + * Formerly +xdr_NC_fill() + */ +int +fill_NC_var(NC *ncp, const NC_var *varp, size_t recno) +{ + char xfillp[NFILL * X_SIZEOF_DOUBLE]; + const size_t step = varp->xsz; + const size_t nelems = sizeof(xfillp)/step; + const size_t xsz = varp->xsz * nelems; + NC_attr **attrpp = NULL; + off_t offset; + size_t remaining = varp->len; + + void *xp; + int status = NC_NOERR; + + /* + * Set up fill value + */ + attrpp = NC_findattr(&varp->attrs, _FillValue); + if( attrpp != NULL ) + { + /* User defined fill value */ + if( (*attrpp)->type != varp->type || (*attrpp)->nelems != 1 ) + { + return NC_EBADTYPE; + } + else + { + /* Use the user defined value */ + char *cp = xfillp; + const char *const end = &xfillp[sizeof(xfillp)]; + + assert(step <= (*attrpp)->xsz); + + for( /*NADA*/; cp < end; cp += step) + { + (void) memcpy(cp, (*attrpp)->xvalue, step); + } + } + } + else + { + /* use the default */ + + assert(xsz % X_ALIGN == 0); + assert(xsz <= sizeof(xfillp)); + + xp = xfillp; + + switch(varp->type){ + case NC_BYTE : + status = NC_fill_schar(&xp, nelems); + break; + case NC_CHAR : + status = NC_fill_char(&xp, nelems); + break; + case NC_SHORT : + status = NC_fill_short(&xp, nelems); + break; + case NC_INT : + status = NC_fill_int(&xp, nelems); + break; + case NC_FLOAT : + status = NC_fill_float(&xp, nelems); + break; + case NC_DOUBLE : + status = NC_fill_double(&xp, nelems); + break; + default : + assert("fill_NC_var invalid type" == 0); + status = NC_EBADTYPE; + break; + } + if(status != NC_NOERR) + return status; + + assert(xp == xfillp + xsz); + } + + /* + * copyout: + * xfillp now contains 'nelems' elements of the fill value + * in external representation. + */ + + /* + * Copy it out. + */ + + offset = varp->begin; + if(IS_RECVAR(varp)) + { + offset += (off_t)ncp->recsize * recno; + } + + assert(remaining > 0); + for(;;) + { + const size_t chunksz = MIN(remaining, ncp->chunk); + size_t ii; + assert(chunksz % X_ALIGN == 0); + + status = ncp->nciop->get(ncp->nciop, offset, chunksz, + RGN_WRITE, &xp); + if(status != NC_NOERR) + { + return status; + } + + /* + * fill the chunksz buffer in units of xsz + */ + for(ii = 0; ii < chunksz/xsz; ii++) + { + (void) memcpy(xp, xfillp, xsz); + xp = (char *)xp + xsz; + } + /* + * Deal with any remainder + */ + { + const size_t rem = chunksz % xsz; + if(rem != 0) + { + (void) memcpy(xp, xfillp, rem); + /* xp = (char *)xp + xsz; */ + } + + } + + status = ncp->nciop->rel(ncp->nciop, offset, RGN_MODIFIED); + + if(status != NC_NOERR) + { + break; + } + + remaining -= chunksz; + if(remaining == 0) + break; /* normal loop exit */ + offset += chunksz; + + } + + return status; +} +/* End fill */ + + +/* + * Add a record containing the fill values. + */ +static int +NCfillrecord(NC *ncp, const NC_var *const *varpp, size_t recno) +{ + size_t ii = 0; + for(; ii < ncp->vars.nelems; ii++, varpp++) + { + if( !IS_RECVAR(*varpp) ) + { + continue; /* skip non-record variables */ + } + { + const int status = fill_NC_var(ncp, *varpp, recno); + if(status != NC_NOERR) + return status; + } + } + return NC_NOERR; +} + +/* + * It is advantageous to + * #define TOUCH_LAST + * when using memory mapped io. + */ +#if TOUCH_LAST +/* + * Grow the file to a size which can contain recno + */ +static int +NCtouchlast(NC *ncp, const NC_var *const *varpp, size_t recno) +{ + int status = NC_NOERR; + const NC_var *varp = NULL; + + { + size_t ii = 0; + for(; ii < ncp->vars.nelems; ii++, varpp++) + { + if( !IS_RECVAR(*varpp) ) + { + continue; /* skip non-record variables */ + } + varp = *varpp; + } + } + assert(varp != NULL); + assert( IS_RECVAR(varp) ); + { + const off_t offset = varp->begin + + (off_t)(recno-1) * (off_t)ncp->recsize + + (off_t)(varp->len - varp->xsz); + void *xp; + + + status = ncp->nciop->get(ncp->nciop, offset, varp->xsz, + RGN_WRITE, &xp); + if(status != NC_NOERR) + return status; + (void)memset(xp, 0, varp->xsz); + status = ncp->nciop->rel(ncp->nciop, offset, RGN_MODIFIED); + } + return status; +} +#endif /* TOUCH_LAST */ + + +/* + * Ensure that the netcdf file has 'numrecs' records, + * add records and fill as neccessary. + */ +static int +NCvnrecs(NC *ncp, size_t numrecs) +{ + int status = NC_NOERR; +#ifdef LOCKNUMREC + ushmem_t myticket = 0, nowserving = 0; + ushmem_t numpe = (ushmem_t) _num_pes(); + + /* get ticket and wait */ + myticket = shmem_short_finc((shmem_t *) ncp->lock + LOCKNUMREC_LOCK, + ncp->lock[LOCKNUMREC_BASEPE]); +#ifdef LN_TEST + fprintf(stderr,"%d of %d : ticket = %hu\n", + _my_pe(), _num_pes(), myticket); +#endif + do { + shmem_short_get((shmem_t *) &nowserving, + (shmem_t *) ncp->lock + LOCKNUMREC_SERVING, 1, + ncp->lock[LOCKNUMREC_BASEPE]); +#ifdef LN_TEST + fprintf(stderr,"%d of %d : serving = %hu\n", + _my_pe(), _num_pes(), nowserving); +#endif + /* work-around for non-unique tickets */ + if (nowserving > myticket && nowserving < myticket + numpe ) { + /* get a new ticket ... you've been bypassed */ + /* and handle the unlikely wrap-around effect */ + myticket = shmem_short_finc( + (shmem_t *) ncp->lock + LOCKNUMREC_LOCK, + ncp->lock[LOCKNUMREC_BASEPE]); +#ifdef LN_TEST + fprintf(stderr,"%d of %d : new ticket = %hu\n", + _my_pe(), _num_pes(), myticket); +#endif + } + } while(nowserving != myticket); + /* now our turn to check & update value */ +#endif + + if(numrecs > NC_get_numrecs(ncp)) + { + + +#if TOUCH_LAST + status = NCtouchlast(ncp, + (const NC_var *const*)ncp->vars.value, + numrecs); + if(status != NC_NOERR) + goto common_return; +#endif /* TOUCH_LAST */ + + set_NC_ndirty(ncp); + + if(!NC_dofill(ncp)) + { + /* Simply set the new numrecs value */ + NC_set_numrecs(ncp, numrecs); + } + else + { + /* Fill each record out to numrecs */ + size_t cur_nrecs; + while((cur_nrecs = NC_get_numrecs(ncp)) < numrecs) + { + status = NCfillrecord(ncp, + (const NC_var *const*)ncp->vars.value, + cur_nrecs); + if(status != NC_NOERR) + { + break; + } + NC_increase_numrecs(ncp, cur_nrecs +1); + } + if(status != NC_NOERR) + goto common_return; + } + + if(NC_doNsync(ncp)) + { + status = write_numrecs(ncp); + } + + } +common_return: +#ifdef LOCKNUMREC + /* finished with our lock - increment serving number */ + (void) shmem_short_finc((shmem_t *) ncp->lock + LOCKNUMREC_SERVING, + ncp->lock[LOCKNUMREC_BASEPE]); +#endif + return status; +} + + +/* + * Check whether 'coord' values are valid for the variable. + */ +static int +NCcoordck(NC *ncp, const NC_var *varp, const size_t *coord) +{ + const size_t *ip; + size_t *up; + + if(varp->ndims == 0) + return NC_NOERR; /* 'scalar' variable */ + + if(IS_RECVAR(varp)) + { + if(*coord > X_INT_MAX) + return NC_EINVALCOORDS; /* sanity check */ + if(NC_readonly(ncp) && *coord >= NC_get_numrecs(ncp)) + { + if(!NC_doNsync(ncp)) + return NC_EINVALCOORDS; + /* else */ + { + /* Update from disk and check again */ + const int status = read_numrecs(ncp); + if(status != NC_NOERR) + return status; + if(*coord >= NC_get_numrecs(ncp)) + return NC_EINVALCOORDS; + } + } + ip = coord + 1; + up = varp->shape + 1; + } + else + { + ip = coord; + up = varp->shape; + } + +#ifdef CDEBUG +fprintf(stderr," NCcoordck: coord %ld, count %d, ip %ld\n", + coord, varp->ndims, ip ); +#endif /* CDEBUG */ + + for(; ip < coord + varp->ndims; ip++, up++) + { + +#ifdef CDEBUG +fprintf(stderr," NCcoordck: ip %p, *ip %ld, up %p, *up %lu\n", + ip, *ip, up, *up ); +#endif /* CDEBUG */ + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) *ip >= (unsigned long) *up ) + return NC_EINVALCOORDS; + } + + return NC_NOERR; +} + + +/* + * Check whether 'edges' are valid for the variable and 'start' + */ +/*ARGSUSED*/ +static int +NCedgeck(const NC *ncp, const NC_var *varp, + const size_t *start, const size_t *edges) +{ + const size_t *const end = start + varp->ndims; + const size_t *shp = varp->shape; + + if(varp->ndims == 0) + return NC_NOERR; /* 'scalar' variable */ + + if(IS_RECVAR(varp)) + { + start++; + edges++; + shp++; + } + + for(; start < end; start++, edges++, shp++) + { + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) *edges > *shp || + (unsigned long) *start + (unsigned long) *edges > *shp) + { + return(NC_EEDGE); + } + } + return NC_NOERR; +} + + +/* + * Translate the (variable, coord) pair into a seek index + */ +static off_t +NC_varoffset(const NC *ncp, const NC_var *varp, const size_t *coord) +{ + if(varp->ndims == 0) /* 'scalar' variable */ + return varp->begin; + + if(varp->ndims == 1) + { + if(IS_RECVAR(varp)) + return varp->begin + + (off_t)(*coord) * (off_t)ncp->recsize; + /* else */ + return varp->begin + (off_t)(*coord) * (off_t)varp->xsz; + } + /* else */ + { + off_t lcoord = (off_t)coord[varp->ndims -1]; + + size_t *up = varp->dsizes +1; + const size_t *ip = coord; + const size_t *const end = varp->dsizes + varp->ndims; + + if(IS_RECVAR(varp)) + up++, ip++; + + for(; up < end; up++, ip++) + lcoord += *up * *ip; + + lcoord *= varp->xsz; + + if(IS_RECVAR(varp)) + lcoord += (off_t)(*coord) * ncp->recsize; + + lcoord += varp->begin; + return lcoord; + } +} + + + +static int +putNCvx_char_char(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const char *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_char_char(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + +static int +putNCvx_schar_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_schar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_uchar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_short(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_int(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_long(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_float(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_schar_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_schar_double(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + +static int +putNCvx_short_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_schar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_uchar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_short(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_int(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_long(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_float(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_short_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_short_double(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + +static int +putNCvx_int_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_schar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_uchar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_short(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_int(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_long(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_float(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_int_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_int_double(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + +static int +putNCvx_float_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_schar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_uchar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_short(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_int(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_long(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_float(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_float_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_float_double(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + +static int +putNCvx_double_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_schar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_uchar(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_short(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_int(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_long(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_float(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + +static int +putNCvx_double_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nput = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + RGN_WRITE, &xp); + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_putn_double_double(&xp, nput, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + { + /* not fatal to the loop */ + status = lstatus; + } + + (void) ncp->nciop->rel(ncp->nciop, offset, + RGN_MODIFIED); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nput; + + } + + return status; +} + + + + +static int +putNCv_text(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const char *value) +{ + if(varp->type != NC_CHAR) + return NC_ECHAR; + return putNCvx_char_char(ncp, varp, start, nelems, value); +} + +static int +putNCv_schar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const schar *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_schar(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_schar(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_schar(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_schar(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_schar(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_uchar(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const uchar *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_uchar(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_uchar(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_uchar(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_uchar(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_uchar(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_short(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const short *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_short(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_short(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_short(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_short(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_short(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_int(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const int *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_int(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_int(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_int(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_int(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_int(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_long(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const long *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_long(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_long(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_long(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_long(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_long(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_float(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const float *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_float(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_float(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_float(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_float(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_float(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +putNCv_double(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const double *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return putNCvx_schar_double(ncp, varp, start, nelems, + value); + case NC_SHORT: + return putNCvx_short_double(ncp, varp, start, nelems, + value); + case NC_INT: + return putNCvx_int_double(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return putNCvx_float_double(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return putNCvx_double_double(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + + + + +static int +getNCvx_char_char(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, char *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_char_char(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + +static int +getNCvx_schar_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_schar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_uchar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_short(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_int(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_long(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_float(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_schar_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_schar_double(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + +static int +getNCvx_short_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_schar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_uchar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_short(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_int(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_long(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_float(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_short_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_short_double(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + +static int +getNCvx_int_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_schar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_uchar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_short(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_int(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_long(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_float(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_int_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_int_double(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + +static int +getNCvx_float_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_schar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_uchar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_short(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_int(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_long(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_float(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_float_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_float_double(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + +static int +getNCvx_double_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_schar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_uchar(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_short(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_int(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_long(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_float(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + +static int +getNCvx_double_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + off_t offset = NC_varoffset(ncp, varp, start); + size_t remaining = varp->xsz * nelems; + int status = NC_NOERR; + const void *xp; + + if(nelems == 0) + return NC_NOERR; + + assert(value != NULL); + + for(;;) + { + size_t extent = MIN(remaining, ncp->chunk); + size_t nget = ncx_howmany(varp->type, extent); + + int lstatus = ncp->nciop->get(ncp->nciop, offset, extent, + 0, (void **)&xp); /* cast away const */ + if(lstatus != NC_NOERR) + return lstatus; + + lstatus = ncx_getn_double_double(&xp, nget, value); + if(lstatus != NC_NOERR && status == NC_NOERR) + status = lstatus; + + (void) ncp->nciop->rel(ncp->nciop, offset, 0); + + remaining -= extent; + if(remaining == 0) + break; /* normal loop exit */ + offset += extent; + value += nget; + } + + return status; +} + + + + +static int +getNCv_schar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, schar *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_schar(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_schar(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_schar(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_schar(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_schar(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_uchar(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, uchar *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_uchar(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_uchar(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_uchar(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_uchar(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_uchar(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_short(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, short *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_short(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_short(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_short(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_short(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_short(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_int(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, int *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_int(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_int(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_int(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_int(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_int(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_long(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, long *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_long(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_long(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_long(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_long(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_long(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_float(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, float *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_float(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_float(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_float(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_float(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_float(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + +static int +getNCv_double(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, double *value) +{ + switch(varp->type){ + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return getNCvx_schar_double(ncp, varp, start, nelems, + value); + case NC_SHORT: + return getNCvx_short_double(ncp, varp, start, nelems, + value); + case NC_INT: + return getNCvx_int_double(ncp, varp, start, nelems, + value); + case NC_FLOAT: + return getNCvx_float_double(ncp, varp, start, nelems, + value); + case NC_DOUBLE: + return getNCvx_double_double(ncp, varp, start, nelems, + value); + } + return NC_EBADTYPE; +} + + + +static int +getNCv_text(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, char *value) +{ + if(varp->type != NC_CHAR) + return NC_ECHAR; + return getNCvx_char_char(ncp, varp, start, nelems, value); +} + + +/* + * Copy 'nbytes' contiguous external values + * from ('inncp', invp', inncoord') + * to ('outncp', 'outvp', 'outcoord') + * 'inncp' shouldn't be the same as 'outncp'. + * Used only by ncvarcopy() + */ +static int +NCxvarcpy(NC *inncp, NC_var *invp, size_t *incoord, + NC *outncp, NC_var *outvp, size_t *outcoord, size_t nbytes) +{ + int status; + off_t inoffset = NC_varoffset(inncp, invp, incoord); + off_t outoffset = NC_varoffset(outncp, outvp, outcoord); + void *inxp; + void *outxp; + const size_t chunk = MIN(inncp->chunk, outncp->chunk); + + do { + const size_t extent = MIN(nbytes, chunk); + + status = inncp->nciop->get(inncp->nciop, inoffset, extent, + 0, &inxp); + if(status != NC_NOERR) + return status; + + status = outncp->nciop->get(outncp->nciop, outoffset, extent, + RGN_WRITE, &outxp); + if(status != NC_NOERR) + { + (void) inncp->nciop->rel(inncp->nciop, inoffset, 0); + break; + } + + (void) memcpy(outxp, inxp, extent); + + status = outncp->nciop->rel(outncp->nciop, outoffset, + RGN_MODIFIED); + (void) inncp->nciop->rel(inncp->nciop, inoffset, 0); + + nbytes -= extent; + if(nbytes == 0) + break; /* normal loop exit */ + inoffset += extent; + outoffset += extent; + + } while (status == NC_NOERR); + + return status; +} + + +/* + * For ncvar{put,get}, + * find the largest contiguous block from within 'edges'. + * returns the index to the left of this (which may be -1). + * Compute the number of contiguous elements and return + * that in *iocountp. + * The presence of "record" variables makes this routine + * overly subtle. + */ +static int +NCiocount(const NC *const ncp, const NC_var *const varp, + const size_t *const edges, + size_t *const iocountp) +{ + const size_t *edp0 = edges; + const size_t *edp = edges + varp->ndims; + const size_t *shp = varp->shape + varp->ndims; + + if(IS_RECVAR(varp)) + { + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only 'record' variable */ + *iocountp = *edges; + return(0); + } + /* else */ + edp0++; + } + + assert(edges != NULL); + + /* find max contiguous */ + while(edp > edp0) + { + shp--; edp--; + if(*edp < *shp ) + { + const size_t *zedp = edp; + while(zedp >= edp0) + { + if(*zedp == 0) + { + *iocountp = 0; + goto done; + } + /* Tip of the hat to segmented architectures */ + if(zedp == edp0) + break; + zedp--; + } + break; + } + assert(*edp == *shp); + } + + /* + * edp, shp reference rightmost index s.t. *(edp +1) == *(shp +1) + * + * Or there is only one dimension. + * If there is only one dimension and it is 'non record' dimension, + * edp is &edges[0] and we will return -1. + * If there is only one dimension and and it is a "record dimension", + * edp is &edges[1] (out of bounds) and we will return 0; + */ + assert(shp >= varp->shape + varp->ndims -1 + || *(edp +1) == *(shp +1)); + + /* now accumulate max count for a single io operation */ + for(*iocountp = 1, edp0 = edp; + edp0 < edges + varp->ndims; + edp0++) + { + *iocountp *= *edp0; + } + +done: + return((int)(edp - edges) - 1); +} + + +/* + * Set the elements of the array 'upp' to + * the sum of the corresponding elements of + * 'stp' and 'edp'. 'end' should be &stp[nelems]. + */ +static void +set_upper(size_t *upp, /* modified on return */ + const size_t *stp, + const size_t *edp, + const size_t *const end) +{ + while(upp < end) { + *upp++ = *stp++ + *edp++; + } +} + + +/* + * The infamous and oft-discussed odometer code. + * + * 'start[]' is the starting coordinate. + * 'upper[]' is the upper bound s.t. start[ii] < upper[ii]. + * 'coord[]' is the register, the current coordinate value. + * For some ii, + * upp == &upper[ii] + * cdp == &coord[ii] + * + * Running this routine increments *cdp. + * + * If after the increment, *cdp is equal to *upp + * (and cdp is not the leftmost dimension), + * *cdp is "zeroed" to the starting value and + * we need to "carry", eg, increment one place to + * the left. + * + * TODO: Some architectures hate recursion? + * Reimplement non-recursively. + */ +static void +odo1(const size_t *const start, const size_t *const upper, + size_t *const coord, /* modified on return */ + const size_t *upp, + size_t *cdp) +{ + assert(coord <= cdp && cdp <= coord + NC_MAX_DIMS); + assert(upper <= upp && upp <= upper + NC_MAX_DIMS); + assert(upp - upper == cdp - coord); + + assert(*cdp <= *upp); + + (*cdp)++; + if(cdp != coord && *cdp >= *upp) + { + *cdp = start[cdp - coord]; + odo1(start, upper, coord, upp -1, cdp -1); + } +} +#ifdef _CRAYC +#pragma _CRI noinline odo1 +#endif + + + + +/* Public */ + +#ifdef USE_MPIO /* function added by Jianwei Li */ + +/* + * This is how much space is required by the user, as in + * + * vals = malloc(nel * nctypelen(var.type)); + * ncvarget(cdfid, varid, cor, edg, vals); + */ +int +nctypelen(nc_type type) +{ + switch(type){ + case NC_BYTE : + case NC_CHAR : + return((int)sizeof(char)); + case NC_SHORT : + return(int)(sizeof(short)); + case NC_INT : + return((int)sizeof(int)); + case NC_FLOAT : + return((int)sizeof(float)); + case NC_DOUBLE : + return((int)sizeof(double)); + } + + return -1; +} + +#else /* interface below removed by Jianwei Li */ + +int +nc_put_var1_text(int ncid, int varid, const size_t *coord, + const char *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_text(ncp, varp, coord, 1, value); +} + + +int +nc_put_var1_uchar(int ncid, int varid, const size_t *coord, + const uchar *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_uchar(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_schar(int ncid, int varid, const size_t *coord, + const schar *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_schar(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_short(int ncid, int varid, const size_t *coord, + const short *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_short(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_int(int ncid, int varid, const size_t *coord, + const int *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_int(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_long(int ncid, int varid, const size_t *coord, + const long *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_long(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_float(int ncid, int varid, const size_t *coord, + const float *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_float(ncp, varp, coord, 1, value); +} + +int +nc_put_var1_double(int ncid, int varid, const size_t *coord, + const double *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *coord +1); + if(status != NC_NOERR) + return status; + } + + return putNCv_double(ncp, varp, coord, 1, value); +} + +/* deprecated, used to support the 2.x interface */ +int +nc_put_var1(int ncid, int varid, const size_t *coord, const void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + switch(varp->type){ + case NC_CHAR: + return nc_put_var1_text(ncid, varid, coord, + (const char *) value); + case NC_BYTE: + return nc_put_var1_schar(ncid, varid, coord, + (const schar *) value); + case NC_SHORT: + return nc_put_var1_short(ncid, varid, coord, + (const short *) value); + case NC_INT: + return nc_put_var1_int(ncid, varid, coord, + (const int *) value); + case NC_FLOAT: + return nc_put_var1_float(ncid, varid, coord, + (const float *) value); + case NC_DOUBLE: + return nc_put_var1_double(ncid, varid, coord, + (const double *) value); + } + return NC_EBADTYPE; +} + +int +nc_get_var1_text(int ncid, int varid, const size_t *coord, char *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_text(ncp, varp, coord, 1, value); +} + + +int +nc_get_var1_uchar(int ncid, int varid, const size_t *coord, uchar *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_uchar(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_schar(int ncid, int varid, const size_t *coord, schar *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_schar(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_short(int ncid, int varid, const size_t *coord, short *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_short(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_int(int ncid, int varid, const size_t *coord, int *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_int(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_long(int ncid, int varid, const size_t *coord, long *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_long(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_float(int ncid, int varid, const size_t *coord, float *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_float(ncp, varp, coord, 1, value); +} + +int +nc_get_var1_double(int ncid, int varid, const size_t *coord, double *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, coord); + if(status != NC_NOERR) + return status; + + return getNCv_double(ncp, varp, coord, 1, value); +} + + +/* deprecated, used to support the 2.x interface */ +int +nc_get_var1(int ncid, int varid, const size_t *coord, void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + switch(varp->type){ + case NC_CHAR: + return nc_get_var1_text(ncid, varid, coord, + (char *) value); + case NC_BYTE: + return nc_get_var1_schar(ncid, varid, coord, + (schar *) value); + case NC_SHORT: + return nc_get_var1_short(ncid, varid, coord, + (short *) value); + case NC_INT: + return nc_get_var1_int(ncid, varid, coord, + (int *) value); + case NC_FLOAT: + return nc_get_var1_float(ncid, varid, coord, + (float *) value); + case NC_DOUBLE: + return nc_get_var1_double(ncid, varid, coord, + (double *) value); + } + return NC_EBADTYPE; +} + + + +int +nc_put_vara_text(int ncid, int varid, + const size_t *start, const size_t *edges, const char *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_text(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_text(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_text(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_text(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + + +int +nc_put_vara_uchar(int ncid, int varid, + const size_t *start, const size_t *edges, const uchar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_uchar(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_uchar(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_uchar(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_uchar(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_schar(int ncid, int varid, + const size_t *start, const size_t *edges, const schar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_schar(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_schar(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_schar(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_schar(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_short(int ncid, int varid, + const size_t *start, const size_t *edges, const short *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_short(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_short(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_short(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_short(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_int(int ncid, int varid, + const size_t *start, const size_t *edges, const int *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_int(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_int(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_int(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_int(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_long(int ncid, int varid, + const size_t *start, const size_t *edges, const long *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_long(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_long(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_long(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_long(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_float(int ncid, int varid, + const size_t *start, const size_t *edges, const float *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_float(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_float(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_float(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_float(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_put_vara_double(int ncid, int varid, + const size_t *start, const size_t *edges, const double *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( putNCv_double(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + status = NCvnrecs(ncp, *start + *edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( putNCv_double(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( putNCv_double(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = putNCv_double(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +/* deprecated, used to support the 2.x interface */ +int +nc_put_vara(int ncid, int varid, + const size_t *start, const size_t *edges, const void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + switch(varp->type){ + case NC_CHAR: + return nc_put_vara_text(ncid, varid, start, edges, + (const char *) value); + case NC_BYTE: + return nc_put_vara_schar(ncid, varid, start, edges, + (const schar *) value); + case NC_SHORT: + return nc_put_vara_short(ncid, varid, start, edges, + (const short *) value); + case NC_INT: + return nc_put_vara_int(ncid, varid, start, edges, + (const int *) value); + case NC_FLOAT: + return nc_put_vara_float(ncid, varid, start, edges, + (const float *) value); + case NC_DOUBLE: + return nc_put_vara_double(ncid, varid, start, edges, + (const double *) value); + } + return NC_EBADTYPE; +} + +int +nc_get_vara_text(int ncid, int varid, + const size_t *start, const size_t *edges, char *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_text(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_text(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_text(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_text(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + + +int +nc_get_vara_uchar(int ncid, int varid, + const size_t *start, const size_t *edges, uchar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_uchar(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_uchar(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_uchar(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_uchar(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_schar(int ncid, int varid, + const size_t *start, const size_t *edges, schar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_schar(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_schar(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_schar(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_schar(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_short(int ncid, int varid, + const size_t *start, const size_t *edges, short *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_short(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_short(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_short(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_short(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_int(int ncid, int varid, + const size_t *start, const size_t *edges, int *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_int(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_int(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_int(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_int(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_long(int ncid, int varid, + const size_t *start, const size_t *edges, long *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_long(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_long(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_long(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_long(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_float(int ncid, int varid, + const size_t *start, const size_t *edges, float *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_float(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_float(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_float(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_float(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +int +nc_get_vara_double(int ncid, int varid, + const size_t *start, const size_t *edges, double *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + int ii; + size_t iocount; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + status = NCcoordck(ncp, varp, start); + if(status != NC_NOERR) + return status; + status = NCedgeck(ncp, varp, start, edges); + if(status != NC_NOERR) + return status; + + if(varp->ndims == 0) /* scalar variable */ + { + return( getNCv_double(ncp, varp, start, 1, value) ); + } + + if(IS_RECVAR(varp)) + { + if(*start + *edges > NC_get_numrecs(ncp)) + return NC_EEDGE; + if(varp->ndims == 1 && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return( getNCv_double(ncp, varp, start, *edges, value) ); + } + } + + /* + * find max contiguous + * and accumulate max count for a single io operation + */ + ii = NCiocount(ncp, varp, edges, &iocount); + + if(ii == -1) + { + return( getNCv_double(ncp, varp, start, iocount, value) ); + } + + assert(ii >= 0); + + + { /* inline */ + ALLOC_ONSTACK(coord, size_t, varp->ndims); + ALLOC_ONSTACK(upper, size_t, varp->ndims); + const size_t index = ii; + + /* copy in starting indices */ + (void) memcpy(coord, start, varp->ndims * sizeof(size_t)); + + /* set up in maximum indices */ + set_upper(upper, start, edges, &upper[varp->ndims]); + + /* ripple counter */ + while(*coord < *upper) + { + const int lstatus = getNCv_double(ncp, varp, coord, iocount, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += iocount; + odo1(start, upper, coord, &upper[index], &coord[index]); + } + + FREE_ONSTACK(upper); + FREE_ONSTACK(coord); + } /* end inline */ + + return status; +} + +/* deprecated, used to support the 2.x interface */ +int +nc_get_vara(int ncid, int varid, + const size_t *start, const size_t *edges, void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + switch(varp->type){ + case NC_CHAR: + return nc_get_vara_text(ncid, varid, start, edges, + (char *) value); + case NC_BYTE: + return nc_get_vara_schar(ncid, varid, start, edges, + (schar *) value); + case NC_SHORT: + return nc_get_vara_short(ncid, varid, start, edges, + (short *) value); + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + return nc_get_vara_int(ncid, varid, start, edges, + (int *) value); +#elif SIZEOF_LONG == X_SIZEOF_INT + return nc_get_vara_long(ncid, varid, start, edges, + (long *) value); +#else +#error "nc_get_vara implementation" +#endif + case NC_FLOAT: + return nc_get_vara_float(ncid, varid, start, edges, + (float *) value); + case NC_DOUBLE: + return nc_get_vara_double(ncid, varid, start, edges, + (double *) value); + } + return NC_EBADTYPE; +} + +#if defined(__cplusplus) +/* C++ consts default to internal linkage and must be initialized */ +const size_t coord_zero[NC_MAX_VAR_DIMS] = {0}; +#else +static const size_t coord_zero[NC_MAX_VAR_DIMS]; +#endif + +int +nc_put_var_text(int ncid, int varid, const char *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_text(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_text(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_text(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_text(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + + +int +nc_put_var_uchar(int ncid, int varid, const uchar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_uchar(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_uchar(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_uchar(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_uchar(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_schar(int ncid, int varid, const schar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_schar(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_schar(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_schar(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_schar(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_short(int ncid, int varid, const short *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_short(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_short(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_short(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_short(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_int(int ncid, int varid, const int *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_int(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_int(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_int(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_int(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_long(int ncid, int varid, const long *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_long(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_long(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_long(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_long(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_float(int ncid, int varid, const float *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_float(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_float(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_float(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_float(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_put_var_double(int ncid, int varid, const double *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( putNCv_double(ncp, varp, &zed, 1, value) ); + } + + if(!IS_RECVAR(varp)) + { + return(putNCv_double(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(putNCv_double(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = putNCv_double(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + + + + +int +nc_get_var_text(int ncid, int varid, char *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_text(ncp, varp, &zed, 1, value) ); + } + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_text(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_text(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_text(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + + +int +nc_get_var_uchar(int ncid, int varid, uchar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_uchar(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_uchar(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_uchar(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_uchar(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_schar(int ncid, int varid, schar *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_schar(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_schar(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_schar(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_schar(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_short(int ncid, int varid, short *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_short(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_short(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_short(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_short(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_int(int ncid, int varid, int *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_int(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_int(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_int(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_int(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_long(int ncid, int varid, long *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_long(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_long(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_long(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_long(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_float(int ncid, int varid, float *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_float(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_float(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_float(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_float(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + +int +nc_get_var_double(int ncid, int varid, double *value) +{ + int status = NC_NOERR; + NC *ncp; + const NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */ + + if(varp->ndims == 0) /* scalar variable */ + { + const size_t zed = 0; + return( getNCv_double(ncp, varp, &zed, 1, value) ); + } + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + + if(!IS_RECVAR(varp)) + { + return(getNCv_double(ncp, varp, coord_zero, *varp->dsizes, value)); + } + /* else */ + + if(varp->ndims == 1 + && ncp->recsize <= varp->len) + { + /* one dimensional && the only record variable */ + return(getNCv_double(ncp, varp, coord_zero, NC_get_numrecs(ncp), + value)); + } + /* else */ + + { + ALLOC_ONSTACK(coord, size_t, varp->ndims); + size_t elemsPerRec = 1; + const size_t nrecs = NC_get_numrecs(ncp); + (void) memset(coord, 0, varp->ndims * sizeof(size_t)); + /* TODO: fix dsizes to avoid this nonsense */ + if(varp->ndims > 1) + elemsPerRec = varp->dsizes[1]; + while(*coord < nrecs) + { + const int lstatus = getNCv_double(ncp, varp, coord, elemsPerRec, + value); + if(lstatus != NC_NOERR) + { + if(lstatus != NC_ERANGE) + { + status = lstatus; + /* fatal for the loop */ + break; + } + /* else NC_ERANGE, not fatal for the loop */ + if(status == NC_NOERR) + status = lstatus; + } + value += elemsPerRec; + (*coord)++; + } + FREE_ONSTACK(coord); + } /* elemsPerRec */ + + return status; +} + + + +/* Begin putgetg.c */ + + + +int +nc_get_vars_text ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + char *value) +{ + return nc_get_varm_text (ncid, varid, start, edges, + stride, 0, value); +} + + +int +nc_get_vars_uchar ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + uchar *value) +{ + return nc_get_varm_uchar (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_schar ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + schar *value) +{ + return nc_get_varm_schar (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_short ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + short *value) +{ + return nc_get_varm_short (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_int ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + int *value) +{ + return nc_get_varm_int (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_long ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + long *value) +{ + return nc_get_varm_long (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_float ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + float *value) +{ + return nc_get_varm_float (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_get_vars_double ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + double *value) +{ + return nc_get_varm_double (ncid, varid, start, edges, + stride, 0, value); +} + + +int +nc_get_vars ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + void *value) +{ + return nc_get_varm (ncid, varid, start, edges, + stride, 0, value); +} + + + +int +nc_put_vars_text ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const char *value) +{ + return nc_put_varm_text (ncid, varid, start, edges, + stride, 0, value); +} + + +int +nc_put_vars_uchar ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const uchar *value) +{ + return nc_put_varm_uchar (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_schar ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const schar *value) +{ + return nc_put_varm_schar (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_short ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const short *value) +{ + return nc_put_varm_short (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_int ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const int *value) +{ + return nc_put_varm_int (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_long ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const long *value) +{ + return nc_put_varm_long (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_float ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const float *value) +{ + return nc_put_varm_float (ncid, varid, start, edges, + stride, 0, value); +} + +int +nc_put_vars_double ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const double *value) +{ + return nc_put_varm_double (ncid, varid, start, edges, + stride, 0, value); +} + + +int +nc_put_vars ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const void *value) +{ + return nc_put_varm (ncid, varid, start, edges, + stride, 0, value); +} + + +/* + * Generalized hyperslab input. + */ + +int +nc_get_varm_text(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + char *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_text (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_text() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_text (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + + +int +nc_get_varm_uchar(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + uchar *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_uchar (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_uchar() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_uchar (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_schar(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + schar *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_schar (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_schar() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_schar (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_short(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + short *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_short (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_short() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_short (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_int(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + int *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_int (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_int() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_int (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_long(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + long *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_long (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_long() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_long (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_float(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + float *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_float (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_float() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_float (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_get_varm_double(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, + const ptrdiff_t *map, + double *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return getNCv_double (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = maxidim; idim >= 0; --idim) + { + size_t dimlen = + idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) + : varp->shape[idim]; + if (mystart[idim] >= dimlen) + { + status = NC_EINVALCOORDS; + goto done; + } + + if (mystart[idim] + myedges[idim] > dimlen) + { + status = NC_EEDGE; + goto done; + } + + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_get_vara_double() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_get_vara_double (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +/* deprecated, used to support the 2.x interface */ +int +nc_get_varm ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const ptrdiff_t * map, + void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + ptrdiff_t *cvtmap = NULL; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + if(map != NULL && varp->ndims != 0) + { + /* + * convert map units from bytes to units of sizeof(type) + */ + size_t ii; + const ptrdiff_t szof = (ptrdiff_t) nctypelen(varp->type); + cvtmap = (ptrdiff_t *)calloc(varp->ndims, sizeof(ptrdiff_t)); + if(cvtmap == NULL) + return NC_ENOMEM; + for(ii = 0; ii < varp->ndims; ii++) + { + if(map[ii] % szof != 0) + { + free(cvtmap); + return NC_EINVAL; + } + cvtmap[ii] = map[ii] / szof; + } + map = cvtmap; + } + + switch(varp->type){ + case NC_CHAR: + status = nc_get_varm_text(ncid, varid, start, edges, + stride, map, + (char *) value); + break; + case NC_BYTE: + status = nc_get_varm_schar(ncid, varid, start, edges, + stride, map, + (schar *) value); + break; + case NC_SHORT: + status = nc_get_varm_short(ncid, varid, start, edges, + stride, map, + (short *) value); + break; + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + status = nc_get_varm_int(ncid, varid, start, edges, + stride, map, + (int *) value); +#elif SIZEOF_LONG == X_SIZEOF_INT + status = nc_get_varm_long(ncid, varid, start, edges, + stride, map, + (long *) value); +#else +#error "nc_get_varm implementation" +#endif + break; + case NC_FLOAT: + status = nc_get_varm_float(ncid, varid, start, edges, + stride, map, + (float *) value); + break; + case NC_DOUBLE: + status = nc_get_varm_double(ncid, varid, start, edges, + stride, map, + (double *) value); + break; + default: + status = NC_EBADTYPE; + break; + } + + if(cvtmap != NULL) + { + free(cvtmap); + } + return status; +} + +/* + * Generalized hyperslab output. + */ + +int +nc_put_varm_text(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const char *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type != NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_text (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_text() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_text (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + + +int +nc_put_varm_uchar(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const uchar *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_uchar (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_uchar() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_uchar (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_schar(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const schar *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_schar (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_schar() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_schar (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_short(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const short *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_short (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_short() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_short (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_int(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const int *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_int (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_int() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_int (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_long(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const long *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_long (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_long() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_long (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_float(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const float *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_float (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_float() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_float (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + +int +nc_put_varm_double(int ncid, int varid, + const size_t *start, const size_t *edges, + const ptrdiff_t *stride, const ptrdiff_t *map, + const double *value) +{ + int status = ENOERR; + NC *ncp; + NC_var *varp; + int maxidim; /* maximum dimensional index */ + + status = NC_check_id (ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indef (ncp)) + { + return NC_EINDEFINE; + } + + if (NC_readonly (ncp)) + return NC_EPERM; + varp = NC_lookupvar (ncp, varid); + if (varp == NULL) + return NC_ENOTVAR; + + if(varp->type == NC_CHAR) + return NC_ECHAR; + + maxidim = (int) varp->ndims - 1; + + if (maxidim < 0) + { + /* + * The variable is a scalar; consequently, + * there s only one thing to get and only one place to put it. + * (Why was I called?) + */ + return putNCv_double (ncp, varp, start, 1, value); + } + + /* + * else + * The variable is an array. + */ + { + int idim; + size_t *mystart = NULL; + size_t *myedges; + size_t *iocount; /* count vector */ + size_t *stop; /* stop indexes */ + size_t *length; /* edge lengths in bytes */ + ptrdiff_t *mystride; + ptrdiff_t *mymap; + + /* + * Verify stride argument. + */ + for (idim = 0; idim <= maxidim; ++idim) + { + if (stride != NULL + && (stride[idim] == 0 + /* cast needed for braindead systems with signed size_t */ + || (unsigned long) stride[idim] >= X_INT_MAX)) + { + return NC_ESTRIDE; + } + } + + /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */ + mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t)); + if(mystart == NULL) + return NC_ENOMEM; + myedges = mystart + varp->ndims; + iocount = myedges + varp->ndims; + stop = iocount + varp->ndims; + length = stop + varp->ndims; + mystride = (ptrdiff_t *)(length + varp->ndims); + mymap = mystride + varp->ndims; + + /* + * Initialize I/O parameters. + */ + for (idim = maxidim; idim >= 0; --idim) + { + mystart[idim] = start != NULL + ? start[idim] + : 0; + + if (edges[idim] == 0) + { + status = NC_NOERR; /* read/write no data */ + goto done; + } + + myedges[idim] = edges != NULL + ? edges[idim] + : idim == 0 && IS_RECVAR (varp) + ? NC_get_numrecs(ncp) - mystart[idim] + : varp->shape[idim] - mystart[idim]; + mystride[idim] = stride != NULL + ? stride[idim] + : 1; + mymap[idim] = map != NULL + ? map[idim] + : idim == maxidim + ? 1 + : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1]; + + iocount[idim] = 1; + length[idim] = mymap[idim] * myedges[idim]; + stop[idim] = mystart[idim] + myedges[idim] * mystride[idim]; + } + + /* + * Check start, edges + */ + for (idim = IS_RECVAR (varp); idim < maxidim; ++idim) + { + if (mystart[idim] >= varp->shape[idim]) + { + status = NC_EINVALCOORDS; + goto done; + } + if (mystart[idim] + myedges[idim] > varp->shape[idim]) + { + status = NC_EEDGE; + goto done; + } + } + /* + * As an optimization, adjust I/O parameters when the fastest + * dimension has unity stride both externally and internally. + * In this case, the user could have called a simpler routine + * (i.e. ncvarnc_put_vara_double() + */ + if (mystride[maxidim] == 1 + && mymap[maxidim] == 1) + { + iocount[maxidim] = myedges[maxidim]; + mystride[maxidim] = (ptrdiff_t) myedges[maxidim]; + mymap[maxidim] = (ptrdiff_t) length[maxidim]; + } + + /* + * Perform I/O. Exit when done. + */ + for (;;) + { + /* TODO: */ + int lstatus = nc_put_vara_double (ncid, varid, mystart, iocount, + value); + if (lstatus != NC_NOERR + && (status == NC_NOERR || lstatus != NC_ERANGE)) + status = lstatus; + + /* + * The following code permutes through the variable s + * external start-index space and it s internal address + * space. At the UPC, this algorithm is commonly + * called "odometer code". + */ + idim = maxidim; + carry: + value += mymap[idim]; + mystart[idim] += mystride[idim]; + if (mystart[idim] == stop[idim]) + { + mystart[idim] = start[idim]; + value -= length[idim]; + if (--idim < 0) + break; /* normal return */ + goto carry; + } + } /* I/O loop */ + done: + free(mystart); + } /* variable is array */ + return status; + +} + + +/* deprecated, used to support the 2.x interface */ +int +nc_put_varm ( + int ncid, + int varid, + const size_t * start, + const size_t * edges, + const ptrdiff_t * stride, + const ptrdiff_t * map, + const void *value) +{ + int status; + NC *ncp; + const NC_var *varp; + ptrdiff_t *cvtmap = NULL; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + if(map != NULL && varp->ndims != 0) + { + /* + * convert map units from bytes to units of sizeof(type) + */ + size_t ii; + const ptrdiff_t szof = (ptrdiff_t) nctypelen(varp->type); + cvtmap = (ptrdiff_t *)calloc(varp->ndims, sizeof(ptrdiff_t)); + if(cvtmap == NULL) + return NC_ENOMEM; + for(ii = 0; ii < varp->ndims; ii++) + { + if(map[ii] % szof != 0) + { + free(cvtmap); + return NC_EINVAL; + } + cvtmap[ii] = map[ii] / szof; + } + map = cvtmap; + } + + switch(varp->type){ + case NC_CHAR: + status = nc_put_varm_text(ncid, varid, start, edges, + stride, map, + (const char *) value); + break; + case NC_BYTE: + status = nc_put_varm_schar(ncid, varid, start, edges, + stride, map, + (const schar *) value); + break; + case NC_SHORT: + status = nc_put_varm_short(ncid, varid, start, edges, + stride, map, + (const short *) value); + break; + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + status = nc_put_varm_int(ncid, varid, start, edges, + stride, map, + (const int *) value); +#elif SIZEOF_LONG == X_SIZEOF_INT + status = nc_put_varm_long(ncid, varid, start, edges, + stride, map, + (const long *) value); +#else +#error "nc_put_varm implementation" +#endif + break; + case NC_FLOAT: + status = nc_put_varm_float(ncid, varid, start, edges, + stride, map, + (const float *) value); + break; + case NC_DOUBLE: + status = nc_put_varm_double(ncid, varid, start, edges, + stride, map, + (const double *) value); + break; + default: + status = NC_EBADTYPE; + break; + } + + if(cvtmap != NULL) + { + free(cvtmap); + } + return status; +} + +#endif /* USE_MPIO */ + +/* Begin recio, deprecated */ + +/* + * input 'nelems' items of contiguous data of 'varp' at 'start' + * N.B. this function deprecated. + */ +static int +getNCvdata(const NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, void *value) +{ + switch(varp->type){ + case NC_CHAR: + return getNCvx_char_char(ncp, varp, start, nelems, + (char *) value); + case NC_BYTE: + return getNCvx_schar_schar(ncp, varp, start, nelems, + (schar *) value); + case NC_SHORT: + return getNCvx_short_short(ncp, varp, start, nelems, + (short *) value); + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + return getNCvx_int_int(ncp, varp, start, nelems, + (int *) value); +#elif SIZEOF_LONG == X_SIZEOF_INT + return getNCvx_int_long(ncp, varp, start, nelems, + (long *) value); +#else +#error "getNCvdata implementation" +#endif + case NC_FLOAT: + return getNCvx_float_float(ncp, varp, start, nelems, + (float *) value); + case NC_DOUBLE: + return getNCvx_double_double(ncp, varp, start, nelems, + (double *) value); + } + return NC_EBADTYPE; +} + + +/* + * output 'nelems' items of contiguous data of 'varp' at 'start' + * N.B. this function deprecated. + */ +static int +putNCvdata(NC *ncp, const NC_var *varp, + const size_t *start, size_t nelems, const void *value) +{ + switch(varp->type){ + case NC_CHAR: + return putNCvx_char_char(ncp, varp, start, nelems, + (const char *) value); + case NC_BYTE: + return putNCvx_schar_schar(ncp, varp, start, nelems, + (const schar *) value); + case NC_SHORT: + return putNCvx_short_short(ncp, varp, start, nelems, + (const short *) value); + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + return putNCvx_int_int(ncp, varp, start, nelems, + (const int *) value); +#elif SIZEOF_LONG == X_SIZEOF_INT + return putNCvx_long_int(ncp, varp, start, nelems, + (const long *) value); +#else +#error "putNCvdata implementation" +#endif + case NC_FLOAT: + return putNCvx_float_float(ncp, varp, start, nelems, + (const float *) value); + case NC_DOUBLE: + return putNCvx_double_double(ncp, varp, start, nelems, + (const double *) value); + } + return NC_EBADTYPE; +} + + +static size_t +NCelemsPerRec( + const NC_var *varp) +{ + size_t nelems = 1; + size_t jj; + for(jj = 1; jj < varp->ndims; jj++) + nelems *= varp->shape[jj]; + return nelems; +} + + +/* + * Retrieves the number of record variables, the record variable ids, and the + * record size of each record variable. If any pointer to info to be returned + * is null, the associated information is not returned. Returns -1 on error. + */ +int +nc_inq_rec( + int ncid, + size_t *nrecvars, + int *recvarids, + size_t *recsizes) +{ + NC *ncp; + + { + const int status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + } + + { + size_t nrvars = 0; + size_t ii = 0; + for(; ii < ncp->vars.nelems; ii++) + { + const NC_var *const varp = ncp->vars.value[ii]; + if(!IS_RECVAR(varp)) + continue; + + if(recvarids != NULL) + recvarids[nrvars] = (int) ii; + if(recsizes != NULL) + { + *recsizes++ = nctypelen(varp->type) + * NCelemsPerRec(varp); + } + nrvars++; + } + + if(nrecvars != NULL) + *nrecvars = nrvars; + } + + return NC_NOERR; +} + + +static int +NCrecput( + NC *ncp, + size_t recnum, + void *const *datap) +{ + int status = NC_NOERR; + size_t nrvars = 0; + NC_var *varp; + size_t ii; + size_t iocount; + ALLOC_ONSTACK(coord, size_t, ncp->dims.nelems); + + assert(ncp->dims.nelems != 0); + + (void) memset(coord, 0, ncp->dims.nelems * sizeof(size_t)); + coord[0] = recnum; + for(ii = 0; ii < ncp->vars.nelems; ii++) + { + varp = ncp->vars.value[ii]; + if(!IS_RECVAR(varp)) + continue; + /* else */ + nrvars++; + if(*datap == NULL) + { + datap++; + continue; + } + /* else */ + iocount = NCelemsPerRec(varp); + status = putNCvdata(ncp, varp, coord, iocount, *datap++); + if(status != NC_NOERR) + break; + } + if(nrvars == 0 && status == NC_NOERR) + { + status = NC_ENORECVARS; + } + + FREE_ONSTACK(coord); + return status; +} + + +static int +NCrecget( + NC *ncp, + size_t recnum, + void **datap) +{ + int status = NC_NOERR; + size_t nrvars = 0; + NC_var *varp; + size_t ii; + size_t iocount; + ALLOC_ONSTACK(coord, size_t, ncp->dims.nelems); + + assert(ncp->dims.nelems != 0); + + (void) memset(coord, 0, ncp->dims.nelems * sizeof(size_t)); + coord[0] = recnum; + for(ii = 0; ii < ncp->vars.nelems; ii++) + { + varp = ncp->vars.value[ii]; + if(!IS_RECVAR(varp)) + continue; + /* else */ + nrvars++; + if(*datap == NULL) + { + datap++; + continue; + } + /* else */ + iocount = NCelemsPerRec(varp); + status = getNCvdata(ncp, varp, coord, iocount, *datap++); + if(status != NC_NOERR) + break; + } + if(nrvars == 0 && status == NC_NOERR) + { + status = NC_ENORECVARS; + } + + FREE_ONSTACK(coord); + return status; +} + + +/* + * Write one record's worth of data, except don't write to variables for which + * the address of the data to be written is null. Return -1 on error. + */ +int +nc_put_rec( + int ncid, + size_t recnum, + void * const *datap) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + { + return NC_EPERM; + } + + if(NC_indef(ncp)) + { + return NC_EINDEFINE; + } + + status = NCvnrecs(ncp, recnum +1); + if(status != NC_NOERR) + return status; + + return( NCrecput(ncp, recnum, datap) ); +} + + +/* + * Read one record's worth of data, except don't read from variables for which + * the address of the data to be read is null. Return -1 on error; + */ +int +nc_get_rec( + int ncid, + size_t recnum, + void **datap) +{ + int status; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + { + return NC_EINDEFINE; + } + + if(recnum >= NC_get_numrecs(ncp)) + { + return NC_EINVALCOORDS; + } + + return( NCrecget(ncp, recnum, datap) ); +} + + +/* + * Copy the values of a variable from an input netCDF to an output netCDF. + * Input and output var assummed to have the same shape. + * return -1 on error. + */ +int +nc_copy_var(int ncid_in, int varid, int ncid_out) +{ + int status = NC_NOERR; + NC *inncp, *outncp; + NC_var *invp, *outvp; + + status = NC_check_id(ncid_in, &inncp); + if(status != NC_NOERR) + return status; + + + if(NC_indef(inncp)) + { + return NC_EINDEFINE; + } + + status = NC_check_id(ncid_out, &outncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(outncp)) + { + /* output file isn't writable */ + return NC_EPERM; + } + + if(NC_indef(outncp)) + { + return NC_EINDEFINE; + } + + /* find the variable in the input cdf */ + invp = NC_lookupvar(inncp, varid); + if(invp == NULL) + { + return NC_ENOTVAR; + } + + /* find the variable in the output cdf */ + if(NC_findvar(&outncp->vars, invp->name->cp, &outvp) == -1) + { + return NC_ENOTVAR; + } + + /* can we even attempt to copy without conversion? */ + if(outvp->type != invp->type) + { + return NC_EINVAL; + } + + if( (invp->ndims == 0 && outvp->ndims != 0) + || (invp->ndims != 0 && outvp->ndims == 0) + || (IS_RECVAR(invp) && !IS_RECVAR(outvp)) + || (!IS_RECVAR(invp) && IS_RECVAR(outvp)) + || (invp->len != outvp->len) + ) + { + return NC_EINVAL; + } + + /* + * Check coordinates + */ + { + ALLOC_ONSTACK(coord, size_t, invp->ndims); + const size_t nrecs = NC_get_numrecs(inncp); + (void) memcpy(coord, invp->shape, invp->ndims * sizeof(size_t)); + if(IS_RECVAR(invp)) + *coord = nrecs; + + { + size_t ii = 0; + for(; ii < invp->ndims; ii++) + coord[ii] --; + } + /* at this point, coord is the largest valid coord of invp */ + + if(NCcoordck(outncp, outvp, coord) != NC_NOERR) + { + return NC_EINVAL; + } + /* else */ + + (void) memset(coord, 0, invp->ndims * sizeof(size_t)); + + if(!IS_RECVAR(invp)) + { + status = NCxvarcpy(inncp, invp, coord, + outncp, outvp, coord, + invp->len); + goto done; + } + /* else */ + + status = NCvnrecs(outncp, nrecs); + if(status != NC_NOERR) + goto done; + + for( /*NADA*/; *coord < nrecs; (*coord)++) + { + status = NCxvarcpy(inncp, invp, coord, + outncp, outvp, coord, + invp->len); + if(status != NC_NOERR) + break; + } +done: + FREE_ONSTACK(coord); + } + return status; +} Index: /branches/SDM_SciDAC/src/lib/mpinetcdf.c =================================================================== --- /branches/SDM_SciDAC/src/lib/mpinetcdf.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/mpinetcdf.c (revision 2) @@ -0,0 +1,3963 @@ +/********************************************************************************* + * + * This file is written by Northwestern University and Argonne National Laboratory + * + ********************************************************************************/ + +#include +#include "nc.h" +#include "ncx.h" +#include +#include +#include + +const char * +ncmpi_inq_libvers(void) { + return "version = 3.5.0 of Aug 30 2002 13:00:00 $"; +} + +/* to be updated */ +const char * +ncmpi_strerror(int err) { + return nc_strerror(err); +} + +/* Begin Of Dataset Functions */ + +int +ncmpi_create(MPI_Comm comm, const char *path, int cmode, MPI_Info info, int *ncidp) { + int status = NC_NOERR; + NC *ncp; + + ncp = new_NC(NULL); + if(ncp == NULL) + return NC_ENOMEM; + + assert(ncp->xsz = ncx_len_NC(ncp)); + + fSet(ncp->flags, NC_NOFILL); + + status = ncio_create(comm, path, cmode, info, &ncp->nciop); + if(status != NC_NOERR) { + free_NC(ncp); + return status; + } + + assert(ncp->flags == 0); + fSet(ncp->flags, NC_CREAT); + + if(fIsSet(ncp->nciop->ioflags, NC_SHARE)) { + /* + * NC_SHARE implies sync up the number of records as well. + * (File format version one.) + * Note that other header changes are not shared + * automatically. Some sort of IPC (external to this package) + * would be used to trigger a call to ncmpi_sync(). + */ + fSet(ncp->flags, NC_NSYNC); + } + + add_to_NCList(ncp); + *ncidp = ncp->nciop->fd; + + return status; +} + +int +ncmpi_open(MPI_Comm comm, const char *path, int omode, MPI_Info info, int *ncidp) { + int status = NC_NOERR; + NC *ncp; + + ncp = new_NC(NULL); + if(ncp == NULL) + return NC_ENOMEM; + + status = ncio_open(comm, path, omode, info, &ncp->nciop); + if(status != NC_NOERR) { + free_NC(ncp); + return status; + } + + assert(ncp->flags == 0); + + if(fIsSet(ncp->nciop->ioflags, NC_SHARE)) { + /* + * NC_SHARE implies sync up the number of records as well. + * (File format version one.) + * Note that other header changes are not shared + * automatically. Some sort of IPC (external to this package) + * would be used to trigger a call to ncmpi_sync(). + */ + fSet(ncp->flags, NC_NSYNC); + } + + status = hdr_get_NC(ncp); + if (status != NC_NOERR) { + free_NC(ncp); + return status; + } + + add_to_NCList(ncp); + + *ncidp = ncp->nciop->fd; + + return status; +} + +int +ncmpi_redef(int ncid) { + int status; + NC *ncp; + int mynumrecs, numrecs; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* ensure exiting define mode always entering collective data mode */ + if(NC_indep(ncp)) + ncmpi_end_indep_data(ncid); + + if(fIsSet(ncp->nciop->ioflags, NC_SHARE)) { + /* read in from disk */ + status = read_NC(ncp); + if(status != NC_NOERR) + return status; + } else { + + /* collect and set the max numrecs */ + + mynumrecs = ncp->numrecs; + MPI_Allreduce(&mynumrecs, &numrecs, 1, MPI_INT, MPI_MAX, ncp->nciop->comm); + if (numrecs > ncp->numrecs) { + ncp->numrecs = numrecs; + set_NC_ndirty(ncp); + } + } + + ncp->old = dup_NC(ncp); + if(ncp->old == NULL) + return NC_ENOMEM; + + fSet(ncp->flags, NC_INDEF); + + return NC_NOERR; +} + +int +ncmpi_begin_indep_data(int ncid) { + int status = NC_NOERR; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (NC_indep(ncp)) + return NC_EINDEP; + + if(!NC_readonly(ncp) && NC_collectiveFhOpened(ncp->nciop)) + MPI_File_sync(ncp->nciop->collective_fh); /* collective */ + + fSet(ncp->flags, NC_INDEP); + + MPI_Barrier(ncp->nciop->comm); + + return status; +} + +int +ncmpi_end_indep_data(int ncid) { + int status = NC_NOERR; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if (status != NC_NOERR) + return status; + + if (!NC_indep(ncp)) + return NC_ENOTINDEP; + + if(!NC_readonly(ncp) && NC_independentFhOpened(ncp->nciop)) + MPI_File_sync(ncp->nciop->independent_fh); /* independent */ + + fClr(ncp->flags, NC_INDEP); + + MPI_Barrier(ncp->nciop->comm); + + return status; +} + +int +ncmpi_enddef(int ncid) { + int status = NC_NOERR; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(!NC_indef(ncp)) + return(NC_ENOTINDEFINE); + + return NC_enddef(ncp); +} + +int +ncmpi_sync(int ncid) { + int status = NC_NOERR; + NC *ncp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + if(NC_readonly(ncp)) + return read_NC(ncp); + + /* else, read/write */ + + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + + return ncio_sync(ncp->nciop); +} + +int +ncmpi_abort(int ncid) { + /* + * In data mode, same as ncio_close. + * In define mode, descard new definition. + * In create, remove the file. + */ + int status; + NC *ncp; + int doUnlink = 0; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + doUnlink = NC_IsNew(ncp); + + if (ncp->old != NULL) { + /* a plain redef, not a create */ + assert(!NC_IsNew(ncp)); + assert(fIsSet(ncp->flags, NC_INDEF)); + free_NC(ncp->old); + ncp->old = NULL; + fClr(ncp->flags, NC_INDEF); + } + else if (!NC_readonly(ncp) && !NC_indef(ncp)) { + /* data mode, write */ + status = NC_sync(ncp); + if (status != NC_NOERR) + return status; + } + + (void) ncio_close(ncp->nciop, doUnlink); + ncp->nciop = NULL; + + del_from_NCList(ncp); + + free_NC(ncp); + + return NC_NOERR; +} + +int +ncmpi_close(int ncid) { + int status = NC_NOERR; + NC *ncp; + + NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + /* release NC object, close the file and write Dirty numrecs if necessary */ + + return NC_close(ncp); +} + +/* End Of Dataset Functions */ + +/* Begin Of Define Mode Functions */ + +int +ncmpi_def_dim(int ncid, const char *name, size_t len, int *idp) { + return nc_def_dim(ncid, name, len, idp); +} + +int +ncmpi_def_var(int ncid, const char *name, nc_type xtype, + int ndims, const int *dimidsp, int *varidp) { + return nc_def_var(ncid, name, xtype, ndims, dimidsp, varidp); +} + +int +ncmpi_rename_dim(int ncid, int dimid, const char *name) { + return nc_rename_dim(ncid, dimid, name); +} + +int +ncmpi_rename_var(int ncid, int varid, const char *name) { + return nc_rename_var(ncid, varid, name); +} + +/* End Of Define Mode Functions */ + +/* Begin Of Inquiry Functions */ + +int +ncmpi_inq(int ncid, int *ndimsp, int *nvarsp, + int *ngattsp, int *unlimdimidp) { + return nc_inq(ncid, ndimsp, nvarsp, ngattsp, unlimdimidp); +} + +int +ncmpi_inq_ndims(int ncid, int *ndimsp) { + return nc_inq_ndims(ncid, ndimsp); +} + +int +ncmpi_inq_nvars(int ncid, int *nvarsp) { + return nc_inq_nvars(ncid, nvarsp); +} + +int +ncmpi_inq_natts(int ncid, int *ngattsp) { + return nc_inq_natts(ncid, ngattsp); +} + +int +ncmpi_inq_unlimdim(int ncid, int *unlimdimidp) { + return nc_inq_unlimdim(ncid, unlimdimidp); +} + +int +ncmpi_inq_dimid(int ncid, const char *name, int *idp) { + return nc_inq_dimid(ncid, name, idp); +} + +int +ncmpi_inq_dim(int ncid, int dimid, char *name, size_t *lenp) { + return nc_inq_dim(ncid, dimid, name, lenp); +} + +int +ncmpi_inq_dimname(int ncid, int dimid, char *name) { + return nc_inq_dimname(ncid, dimid, name); +} + +int +ncmpi_inq_dimlen(int ncid, int dimid, size_t *lenp) { + return nc_inq_dimlen(ncid, dimid, lenp); +} + +int +ncmpi_inq_var(int ncid, int varid, char *name, + nc_type *xtypep, int *ndimsp, int *dimidsp, + int *nattsp) { + return nc_inq_var(ncid, varid, name, xtypep, ndimsp, dimidsp, nattsp); +} + +int +ncmpi_inq_varid(int ncid, const char *name, int *varidp) { + return nc_inq_varid(ncid, name, varidp); +} + +int +ncmpi_inq_varname(int ncid, int varid, char *name) { + return nc_inq_varname(ncid, varid, name); +} + +int +ncmpi_inq_vartype(int ncid, int varid, nc_type *xtypep) { + return nc_inq_vartype(ncid, varid, xtypep); +} + +int +ncmpi_inq_varndims(int ncid, int varid, int *ndimsp) { + return nc_inq_varndims(ncid, varid, ndimsp); +} + +int +ncmpi_inq_vardimid(int ncid, int varid, int *dimidsp) { + return nc_inq_vardimid(ncid, varid, dimidsp); +} + +int +ncmpi_inq_varnatts(int ncid, int varid, int *nattsp) { + return nc_inq_varnatts(ncid, varid, nattsp); +} + +/* End Of Inquiry Functions */ + +/* Begin Of Attribute Functions */ + +/* +int +ncmpi_inq_att(int ncid, int varid, const char *name, + nc_type *xtypep, size_t *lenp) { + return nc_inq_att(ncid, varid, name, xtypep, lenp); +} + +int +ncmpi_inq_attid(int ncid, int varid, const char *name, int *idp) { + return nc_inq_attid(ncid, varid, name, idp); +} + +int +ncmpi_inq_atttype(int ncid, int varid, const char *name, + nc_type *xtypep) { + return nc_inq_atttype(ncid, varid, name, xtypep); +} + +int +ncmpi_inq_attlen(int ncid, int varid, const char *name, + size_t *lenp) { + return nc_inq_attlen(ncid, varid, name, lenp); +} + +int +ncmpi_inq_attname(int ncid, int varid, int attnum, char *name) { + return nc_inq_attname(ncid, varid, attnum, name); +} + +int +ncmpi_copy_att(int ncid_in, int varid_in, const char *name, + int ncid_out, int varid_out) { + return nc_copy_att(ncid_in, varid_in, name, ncid_out, varid_out); +} + +int +ncmpi_rename_att(int ncid, int varid, const char *name, + const char *newname) { + return nc_rename_att(ncid, varid, name, newname); +} + +int +ncmpi_del_att(int ncid, int varid, const char *name) { + return nc_del_att(ncid, varid, name); +} + +int +ncmpi_put_att_text(int ncid, int varid, const char *name, size_t len, + const char *op) { + return nc_put_att_text(ncid, varid, name, len, op); +} + +int +ncmpi_get_att_text(int ncid, int varid, const char *name, char *ip) { + return nc_get_att_text(ncid, varid, name, ip); +} + +int +ncmpi_put_att_uchar(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const unsigned char *op) { + return nc_put_att_uchar(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_uchar(int ncid, int varid, const char *name, + unsigned char *ip) { + return nc_get_att_uchar(ncid, varid, name, ip); +} + +int +ncmpi_put_att_schar(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const signed char *op) { + return nc_put_att_schar(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_schar(int ncid, int varid, const char *name, + signed char *ip) { + return nc_get_att_schar(ncid, varid, name, ip); +} + +int +ncmpi_put_att_short(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const short *op) { + return nc_put_att_short(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_short(int ncid, int varid, const char *name, short *ip) { + return nc_get_att_short(ncid, varid, name, ip); +} + +int +ncmpi_put_att_int(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const int *op) { + return nc_put_att_int(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_int(int ncid, int varid, const char *name, int *ip) { + return nc_get_att_int(ncid, varid, name, ip); +} + +int +ncmpi_put_att_long(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const long *op) { + return nc_put_att_long(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_long(int ncid, int varid, const char *name, long *ip) { + return nc_get_att_long(ncid, varid, name, ip); +} + +int +ncmpi_put_att_float(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const float *op) { + return nc_put_att_float(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_float(int ncid, int varid, const char *name, float *ip) { + return nc_get_att_float(ncid, varid, name, ip); +} + +int +ncmpi_put_att_double(int ncid, int varid, const char *name, + nc_type xtype, size_t len, const double *op) { + return nc_put_att_double(ncid, varid, name, xtype, len, op); +} + +int +ncmpi_get_att_double(int ncid, int varid, const char *name, + double *ip) { + return nc_get_att_double(ncid, varid, name, ip); +} + +*/ + +/* End Of Attribute Functions */ + +/* Begin {put,get}_att */ + +/* to be updated */ +int +ncmpi_put_att_text(int ncid, int varid, const char *name, + size_t len, const char *op) { + int status = NC_NOERR; +/* + int rank; + MPI_Comm_rank(comm, &rank); +*/ + status = nc_put_att_text(ncid, varid, name, len, op); + + return status; +} + +/* End {put,get}_att */ + +/* Begin {put,get}_var */ + +/* + * MAPPING: MPI DATATYPE <---> NETCDF DATATYPE + * MPI_BYTE NC_BYTE + * MPI_CHAR NC_CHAR + * MPI_SHORT NC_SHORT + * MPI_INT NC_INT + * MPI_FLOAT NC_FLOAT + * MPI_DOUBLE NC_DOUBLE + * + * + * Assume: MPI_Datatype and nc_type are both enumerable types + */ + +int +length_of_mpitype(MPI_Datatype datatype) { + switch(datatype) { + case MPI_BYTE: + case MPI_CHAR: + return ((int)sizeof(char)); + case MPI_SHORT: + return (int)(sizeof(short)); + case MPI_INT: + return((int)sizeof(int)); + case MPI_FLOAT: + return((int)sizeof(float)); + case MPI_DOUBLE: + return((int)sizeof(double)); + } + + return -1; +} + +static void +swapn(void *dst, const void *src, size_t nn, int xsize) +{ + int i; + char *op = dst; + const char *ip = src; + while (nn-- != 0) { + for (i=0; inciop) + || !collective && !NC_independentFhOpened(ncp->nciop)) { + + int mpireturn; + mpireturn = MPI_File_open(comm, (char *)ncp->nciop->path, ncp->nciop->mpiomode, + ncp->nciop->mpiinfo, mpifh); + if (mpireturn != MPI_SUCCESS) { + char errorString[512]; + int errorStringLen; + MPI_Error_string(mpireturn, errorString, &errorStringLen); + printf("NC_check_mpifh() calliing MPI_File_open error = %s\n", errorString); + return NC_ENFILE; + /* To be determined the return error code ???????????? */ + } + + if (collective) + set_NC_collectiveFh(ncp->nciop); + else + set_NC_independentFh(ncp->nciop); + + } + + return NC_NOERR; +} + +/* + * Check whether 'coord' values (indices) are valid for the variable. + */ +int +NCcoordck(NC *ncp, const NC_var *varp, const size_t *coord) +{ + const size_t *ip; + size_t *up; + + if(varp->ndims == 0) + return NC_NOERR; /* 'scalar' variable */ + + if(IS_RECVAR(varp)) + { + if(*coord > X_INT_MAX) + return NC_EINVALCOORDS; /* sanity check */ + if(NC_readonly(ncp) && *coord >= ncp->numrecs) + { + if(!NC_doNsync(ncp)) + return NC_EINVALCOORDS; + /* else */ + { + /* Update from disk and check again */ + const int status = read_numrecs(ncp); + if(status != NC_NOERR) + return status; + if(*coord >= ncp->numrecs) + return NC_EINVALCOORDS; + } + } + ip = coord + 1; + up = varp->shape + 1; + } + else + { + ip = coord; + up = varp->shape; + } + + for(; ip < coord + varp->ndims; ip++, up++) + { + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) *ip >= (unsigned long) *up ) + return NC_EINVALCOORDS; + } + + return NC_NOERR; } + +int +NC_set_var1_fileview(NC* ncp, MPI_File *mpifh, NC_var* varp, const size_t index[]) { + MPI_Offset offset; + int status; + int dim, ndims; + + status = NCcoordck(ncp, varp, index); + if (status != NC_NOERR) + return status; + + offset = varp->begin; + + ndims = varp->ndims; + + if (IS_RECVAR(varp)) + offset += index[0] * ncp->recsize; + else + offset += index[ndims-1] * varp->xsz; + + if (ndims > 1) { + if (IS_RECVAR(varp)) + offset += index[ndims - 1] * varp->xsz; + else + offset += index[0] * varp->dsizes[1] * varp->xsz; + + for (dim = 1; dim < ndims - 1; dim++) + offset += index[dim] * varp->dsizes[dim+1] * varp->xsz; + } + + MPI_File_set_view(*mpifh, offset, MPI_BYTE, MPI_BYTE, "native", ncp->nciop->mpiinfo); + + return NC_NOERR; +} + +int +NC_set_var_fileview(NC* ncp, MPI_File *mpifh, NC_var* varp) { + MPI_Offset offset; + int status; + + offset = varp->begin; + + if (!IS_RECVAR(varp)) { + /* Contiguous file view */ + MPI_File_set_view(*mpifh, offset, MPI_BYTE, MPI_BYTE, "native", ncp->nciop->mpiinfo); + } else { + /* Record variable, Strided file view */ + int dim, ndims; + MPI_Datatype filetype; + MPI_Aint stride; + int blocklen; + + ndims = varp->ndims; + if (ndims > 1) + blocklen = varp->dsizes[1] * varp->xsz; + else + blocklen = varp->xsz; + + stride = ncp->recsize; + +#if (MPI_VERSION < 2) + MPI_Type_hvector(ncp->numrecs, blocklen, stride, MPI_BYTE, &filetype); +#else + MPI_Type_create_hvector(ncp->numrecs, blocklen, stride, MPI_BYTE, &filetype); +#endif + MPI_Type_commit(&filetype); + + MPI_File_set_view(*mpifh, offset, MPI_BYTE, filetype, "native", ncp->nciop->mpiinfo); + + MPI_Type_free(&filetype); + } + + return NC_NOERR; +} + +int +NC_set_vara_fileview(NC* ncp, MPI_File *mpifh, NC_var* varp, const size_t start[], const size_t count[]) { + + MPI_Offset offset; + int status; + int dim, ndims; + int *shape, *subcount, *substart; /* all in bytes */ + size_t *end; + MPI_Datatype rectype; + MPI_Datatype filetype; + + offset = varp->begin; + + ndims = varp->ndims; + end = (size_t *)malloc(sizeof(size_t) * ndims); + shape = (int *)malloc(sizeof(int) * ndims); + subcount = (int *)malloc(sizeof(int) * ndims); + substart = (int *)malloc(sizeof(int) * ndims); + + for (dim = 0; dim < ndims; dim++) + end[dim] = start[dim] + count[dim] - 1; + status = NCcoordck(ncp, varp, end); + if (status != NC_NOERR) + return status; + + if (IS_RECVAR(varp)) { + subcount[0] = count[0]; + substart[0] = 0; + shape[0] = subcount[0]; + + if (ncp->recsize <= varp->len) { + + /* the only record variable */ + + if (varp->ndims == 1) { + shape[0] *= varp->xsz; + subcount[0] *= varp->xsz; + } else { + for (dim = 1; dim < ndims-1; dim++) { + shape[dim] = varp->shape[dim]; + subcount[dim] = count[dim]; + substart[dim] = start[dim]; + } + shape[dim] = varp->xsz * varp->shape[dim]; + subcount[dim] = varp->xsz * count[dim]; + substart[dim] = varp->xsz * start[dim]; + } + offset += start[0] * ncp->recsize; + + MPI_Type_create_subarray(ndims, shape, subcount, substart, + MPI_ORDER_C, MPI_BYTE, &filetype); + + MPI_Type_commit(&filetype); + } else { + + /* more than one record variables */ + + offset += start[0] * ncp->recsize; + if (varp->ndims == 1) { +#if (MPI_VERSION < 2) + MPI_Type_vector(subcount[0], varp->xsz, ncp->recsize, + MPI_BYTE, &filetype); +#else + MPI_Type_create_vector(subcount[0], varp->xsz, ncp->recsize, + MPI_BYTE, &filetype); +#endif + MPI_Type_commit(&filetype); + + } else { + for (dim = 1; dim < ndims-1; dim++) { + shape[dim] = varp->shape[dim]; + subcount[dim] = count[dim]; + substart[dim] = start[dim]; + } + shape[dim] = varp->xsz * varp->shape[dim]; + subcount[dim] = varp->xsz * count[dim]; + substart[dim] = varp->xsz * start[dim]; + + MPI_Type_create_subarray(ndims-1, shape+1, subcount+1, substart+1, + MPI_ORDER_C, MPI_BYTE, &rectype); + MPI_Type_commit(&rectype); +#if (MPI_VERSION < 2) + MPI_Type_hvector(subcount[0], 1, ncp->recsize, rectype, &filetype); +#else + MPI_Type_create_hvector(subcount[0], 1, ncp->recsize, rectype, &filetype); +#endif + MPI_Type_commit(&filetype); + MPI_Type_free(&rectype); + } + } + + } else { + + /* non record variable */ + + for (dim = 0; dim < ndims-1; dim++ ) { + shape[dim] = varp->shape[dim]; + subcount[dim] = count[dim]; + substart[dim] = start[dim]; + } + shape[dim] = varp->xsz * varp->shape[dim]; + subcount[dim] = varp->xsz * count[dim]; + substart[dim] = varp->xsz * start[dim]; + + MPI_Type_create_subarray(ndims, shape, subcount, substart, + MPI_ORDER_C, MPI_BYTE, &filetype); + + MPI_Type_commit(&filetype); + } + + MPI_File_set_view(*mpifh, offset, MPI_BYTE, + filetype, "native", ncp->nciop->mpiinfo); + + MPI_Type_free(&filetype); + + free(shape); + free(subcount); + free(substart); + + return NC_NOERR; +} + +int +NC_set_vars_fileview(NC* ncp, MPI_File *mpifh, NC_var* varp, + const size_t start[], const size_t count[], + const size_t stride[]) { + MPI_Offset offset; + int status; + int dim, ndims; + MPI_Datatype *subtypes, *filetype; + size_t *blocklens, *blockstride, *blockcount, *end; + + offset = varp->begin; + + ndims = varp->ndims; + subtypes = (MPI_Datatype *)malloc((ndims+1) * sizeof(MPI_Datatype)); + filetype = subtypes; + subtypes[ndims] = MPI_BYTE; + + end = (size_t *) malloc(ndims * sizeof(size_t)); + for (dim = 0; dim < ndims; dim++) + end[dim] = start[dim] + (count[dim] - 1) * stride[dim]; + status = NCcoordck(ncp, varp, end); + if (status != NC_NOERR) + return status; + + blocklens = (size_t *) malloc(ndims * sizeof(size_t)); + blockstride = (size_t *) malloc(ndims * sizeof(size_t)); + blockcount = (size_t *) malloc(ndims * sizeof(size_t)); + blocklens[ndims - 1] = varp->xsz; + blockcount[ndims - 1] = count[ndims - 1]; + if (ndims == 1 && IS_RECVAR(varp)) { + blockstride[ndims - 1] = stride[ndims - 1] * ncp->recsize; + offset += start[ndims - 1] * ncp->recsize; + } else { + blockstride[ndims - 1] = stride[ndims - 1] * varp->xsz; + offset += start[ndims - 1] * varp->xsz; + } + + for (dim = ndims - 1; dim >= 0; dim--) { +#if (MPI_VERSION < 2) + MPI_Type_hvector(blockcount[dim], blocklens[dim], blockstride[dim], + subtypes[dim + 1], subtypes + dim); +#else + MPI_Type_create_hvector(blockcount[dim], blocklens[dim], blockstride[dim], + subtypes[dim + 1], subtypes + dim); +#endif + MPI_Type_commit(subtypes + dim); + + if (dim - 1 >= 0) { + blocklens[dim - 1] = 1; + blockcount[dim - 1] = count[dim - 1]; + if (dim - 1 == 0 && IS_RECVAR(varp)) { + blockstride[dim - 1] = stride[dim - 1] * ncp->recsize; + offset += start[dim-1] * ncp->recsize; + } else { + blockstride[dim - 1] = stride[dim - 1] * varp->dsizes[dim] * varp->xsz; + offset += start[dim-1] * varp->dsizes[dim] * varp->xsz; + } + } + } + + MPI_File_set_view(*mpifh, offset, MPI_BYTE, + *filetype, "native", ncp->nciop->mpiinfo); + + for (dim= 0; dim < ndims; dim++ ) + MPI_Type_free(subtypes + dim); + + free(blocklens); + free(blockstride); + free(blockcount); + + return NC_NOERR; +} + +int +ncmpi_put_var1(int ncid, int varid, + const size_t index[], + const void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int nbytes; + MPI_Status mpistatus; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_var1_fileview(ncp, &(ncp->nciop->independent_fh), varp, index); + if(status != NC_NOERR) + return status; + + nbytes = varp->xsz; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, 1, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, 1, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, 1, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, 1, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, 1, ncx_len_nctype(varp->type)); + + } + + MPI_File_write(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + /* update the number of records in NC */ + + int newnumrecs; + newnumrecs = index[0] + 1; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + } + + return status; +} + +int +ncmpi_get_var1(int ncid, int varid, + const size_t index[], + void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_var1_fileview(ncp, &(ncp->nciop->independent_fh), varp, index); + if(status != NC_NOERR) + return status; + + nbytes = varp->xsz; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, 1, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, 1, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, 1, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, 1, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, 1, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_get_var_all(int ncid, int varid, void *buf, int bufcount, MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->collective_fh), ncp->nciop->comm, 1); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = bufcount/length_of_mpitype(datatype); + nbytes = nelems * varp->xsz; + + /* set the mpi file view */ + + status = NC_set_var_fileview(ncp, &(ncp->nciop->collective_fh), varp); + if(status != NC_NOERR) + return status; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read_all(ncp->nciop->collective_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_var(int ncid, int varid, const void *buf, int bufcount, MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + MPI_Status mpistatus; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = bufcount/length_of_mpitype(datatype); + nbytes = nelems * varp->xsz; + + /* set the mpi file view */ + + status = NC_set_var_fileview(ncp, &(ncp->nciop->independent_fh), varp); + if(status != NC_NOERR) + return status; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, nelems, ncx_len_nctype(varp->type)); + + } + + MPI_File_write(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + /* update the number of records in NC */ + + int newnumrecs; + if (varp->ndims > 1) + newnumrecs = nelems / varp->dsizes[1]; + else + newnumrecs = nelems; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + } + + return status; +} + +int +ncmpi_get_var(int ncid, int varid, void *buf, int bufcount, MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = bufcount/length_of_mpitype(datatype); + nbytes = nelems * varp->xsz; + + /* set the mpi file view */ + + status = NC_set_var_fileview(ncp, &(ncp->nciop->independent_fh), varp); + if(status != NC_NOERR) + return status; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_vara_all(int ncid, int varid, + const size_t start[], const size_t count[], + const void *buf, int bufcount, + MPI_Datatype datatype) { + + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + MPI_Status mpistatus; + MPI_Comm comm; + int rank; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + comm = ncp->nciop->comm; + MPI_Comm_rank(comm, &rank); + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->collective_fh), comm, 1); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vara_fileview(ncp, &(ncp->nciop->collective_fh), varp, start, count); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, nelems, ncx_len_nctype(varp->type)); + + } + + MPI_File_write_all(ncp->nciop->collective_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + + /* update the number of records in NC + and write it back to file header, if necessary + */ + int newnumrecs, max_numrecs; + newnumrecs = start[0] + count[0]; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + if (NC_doNsync(ncp)) { + MPI_Allreduce( &newnumrecs, &max_numrecs, 1, MPI_INT, MPI_MAX, comm ); + + if (ncp->numrecs < max_numrecs) { + ncp->numrecs = max_numrecs; + if (rank == 0) { + status = write_numrecs(ncp); /* call subroutine from nc.c */ + if(status != NC_NOERR) + return status; + } + } + } + } + + return status; +} + + +int +ncmpi_get_vara_all(int ncid, int varid, + const size_t start[], const size_t count[], + void *buf, int bufcount, + MPI_Datatype datatype) { + + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->collective_fh), ncp->nciop->comm, 1); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vara_fileview(ncp, &(ncp->nciop->collective_fh), varp, start, count); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read_all(ncp->nciop->collective_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_vara(int ncid, int varid, + const size_t start[], const size_t count[], + const void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + MPI_Status mpistatus; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vara_fileview(ncp, &(ncp->nciop->independent_fh), varp, start, count); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, nelems, ncx_len_nctype(varp->type)); + + } + + MPI_File_write(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + /* update the number of records in NC */ + + int newnumrecs; + newnumrecs = start[0] + count[0]; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + } + + return status; +} + +int +ncmpi_get_vara(int ncid, int varid, + const size_t start[], const size_t count[], + void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vara_fileview(ncp, &(ncp->nciop->independent_fh), varp, start, count); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_vars_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + MPI_Status mpistatus; + MPI_Comm comm; + int rank; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + comm = ncp->nciop->comm; + MPI_Comm_rank(comm, &rank); + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->collective_fh), comm, 1); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vars_fileview(ncp, &(ncp->nciop->collective_fh), + varp, start, count, stride); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, nelems, ncx_len_nctype(varp->type)); + + } + + MPI_File_write_all(ncp->nciop->collective_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + + /* update the number of records in NC + and write it back to file header, if necessary + */ + int newnumrecs, max_numrecs; + newnumrecs = start[0] + (count[0] - 1) * stride[0] + 1; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + if (NC_doNsync(ncp)) { + MPI_Allreduce( &newnumrecs, &max_numrecs, 1, MPI_INT, MPI_MAX, comm ); + + if (ncp->numrecs < max_numrecs) { + ncp->numrecs = max_numrecs; + if (rank == 0) { + status = write_numrecs(ncp); /* call subroutine from nc.c */ + if(status != NC_NOERR) + return status; + } + } + } + } + + return status; +} + + +int +ncmpi_get_vars_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + void *buf, int bufcount, + MPI_Datatype datatype) { + + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->collective_fh), ncp->nciop->comm, 1); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vars_fileview(ncp, &(ncp->nciop->collective_fh), + varp, start, count, stride); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read_all(ncp->nciop->collective_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_vars(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + MPI_Status mpistatus; + int words_bigendian = 0; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vars_fileview(ncp, &(ncp->nciop->independent_fh), + varp, start, count, stride); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = (void *)buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + switch( varp->type ) { + case NC_SHORT: + x_putn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_putn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_putn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_putn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + + } else if (!words_bigendian) { + + swapn(xbuf, buf, nelems, ncx_len_nctype(varp->type)); + + } + + MPI_File_write(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + if (xbuf != buf) + free(xbuf); + + if (IS_RECVAR(varp)) { + /* update the number of records in NC */ + + int newnumrecs; + newnumrecs = start[0] + (count[0] - 1) * stride[0] + 1; + if (ncp->numrecs < newnumrecs) { + ncp->numrecs = newnumrecs; + set_NC_ndirty(ncp); + } + } + + return status; +} + +int +ncmpi_get_vars(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + void *buf, int bufcount, + MPI_Datatype datatype) { + NC_var *varp; + NC *ncp; + void *xbuf; + int status; + int dim; + int nelems, nbytes; + int words_bigendian = 0; + MPI_Status mpistatus; + +#if WORDS_BIGENDIAN + words_bigendian = 1; +#endif + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_indef(ncp)) + return NC_EINDEFINE; + + /* check to see that the desired mpi file handle is opened */ + + status = NC_check_mpifh(ncp, &(ncp->nciop->independent_fh), MPI_COMM_SELF, 0); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + /* set the mpi file view */ + + status = NC_set_vars_fileview(ncp, &(ncp->nciop->independent_fh), + varp, start, count, stride); + if(status != NC_NOERR) + return status; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = varp->xsz * nelems; + + /* assign or allocate MPI read buffer */ + + if ( words_bigendian && + ncx_len_nctype(varp->type) == length_of_mpitype(datatype) ) + /* Just assign MPI read buffer */ + xbuf = buf; + else + /* else, allocate new buffer */ + xbuf = (void *)malloc(nbytes); + + MPI_File_read(ncp->nciop->independent_fh, xbuf, nbytes, MPI_BYTE, &mpistatus); + + /* automatic datatype conversion */ + + if ( ncx_len_nctype(varp->type) != length_of_mpitype(datatype) ) { + + switch( varp->type ) { + case NC_SHORT: + x_getn_short(xbuf, buf, nelems, datatype); + break; + case NC_INT: + x_getn_int(xbuf, buf, nelems, datatype); + break; + case NC_FLOAT: + x_getn_float(xbuf, buf, nelems, datatype); + break; + case NC_DOUBLE: + x_getn_double(xbuf, buf, nelems, datatype); + break; + case NC_CHAR: + break; + default: + break; + } + free(xbuf); + + } else if (!words_bigendian) { + + swapn(buf, xbuf, nelems, ncx_len_nctype(varp->type)); + free(xbuf); + + } + + return status; +} + +int +ncmpi_put_var1_short(int ncid, int varid, + const size_t index[], + const short *op) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_put_var1(ncid, varid, index, + (const void *)op, sizeof(short), MPI_SHORT); +} + +int +ncmpi_put_var1_int(int ncid, int varid, + const size_t index[], + const int *op) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_put_var1(ncid, varid, index, + (const void *)op, sizeof(int), MPI_INT); +} + +int +ncmpi_put_var1_float(int ncid, int varid, + const size_t index[], + const float *op) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_put_var1(ncid, varid, index, + (const void *)op, sizeof(float), MPI_FLOAT); +} + +int +ncmpi_put_var1_double(int ncid, int varid, + const size_t index[], + const double *op) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_put_var1(ncid, varid, index, + (const void *)op, sizeof(double), MPI_DOUBLE); +} + +int +ncmpi_get_var1_short(int ncid, int varid, + const size_t index[], + short *ip) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_get_var1(ncid, varid, index, + (void *)ip, sizeof(short), MPI_SHORT); +} + +int +ncmpi_get_var1_int(int ncid, int varid, + const size_t index[], + int *ip) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_get_var1(ncid, varid, index, + (void *)ip, sizeof(int), MPI_INT); +} + +int +ncmpi_get_var1_float(int ncid, int varid, + const size_t index[], + float *ip) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_get_var1(ncid, varid, index, + (void *)ip, sizeof(float), MPI_FLOAT); +} + +int +ncmpi_get_var1_double(int ncid, int varid, + const size_t index[], + double *ip) { + NC_var *varp; + NC *ncp; + int status; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + return ncmpi_get_var1(ncid, varid, index, + (void *)ip, sizeof(double), MPI_DOUBLE); +} + +int +ncmpi_put_var_short(int ncid, int varid, const short *op) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(short); + + return ncmpi_put_var(ncid, varid, (const void *)op, nbytes, MPI_SHORT); +} + +int +ncmpi_put_var_int(int ncid, int varid, const int *op) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(int); + + return ncmpi_put_var(ncid, varid, (const void *)op, nbytes, MPI_INT); +} + +int +ncmpi_put_var_float(int ncid, int varid, const float *op) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(float); + + return ncmpi_put_var(ncid, varid, (const void *)op, nbytes, MPI_FLOAT); +} + +int +ncmpi_put_var_double(int ncid, int varid, const double *op) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(double); + + return ncmpi_put_var(ncid, varid, (const void *)op, nbytes, MPI_DOUBLE); +} + +int +ncmpi_get_var_short(int ncid, int varid, short *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(short); + + return ncmpi_get_var(ncid, varid, (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_var_int(int ncid, int varid, int *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(int); + + return ncmpi_get_var(ncid, varid, (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_var_float(int ncid, int varid, float *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(float); + + return ncmpi_get_var(ncid, varid, (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_var_double(int ncid, int varid, double *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(double); + + return ncmpi_get_var(ncid, varid, (void *)ip, nbytes, MPI_DOUBLE); +} + +int +ncmpi_get_var_short_all(int ncid, int varid, short *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(short); + + return ncmpi_get_var_all(ncid, varid, (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_var_int_all(int ncid, int varid, int *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(int); + + return ncmpi_get_var_all(ncid, varid, (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_var_float_all(int ncid, int varid, float *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(float); + + return ncmpi_get_var_all(ncid, varid, (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_var_double_all(int ncid, int varid, double *ip) { + NC_var *varp; + NC *ncp; + int status; + int ndims; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + ndims = varp->ndims; + + if (ndims > 1) + nelems = varp->dsizes[1]; + else + nelems = 1; + if (IS_RECVAR(varp)) + nelems *= ncp->numrecs; + else + nelems *= varp->shape[0]; + + nbytes = nelems * sizeof(double); + + return ncmpi_get_var_all(ncid, varid, (void *)ip, nbytes, MPI_DOUBLE); +} + +int +ncmpi_put_vara_short_all(int ncid, int varid, + const size_t start[], const size_t count[], + const short *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_put_vara_all(ncid, varid, start, count, + (const void *)op, nbytes, MPI_SHORT); +} + +int +ncmpi_put_vara_short(int ncid, int varid, + const size_t start[], const size_t count[], + const short *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_put_vara(ncid, varid, start, count, + (const void *)op, nbytes, MPI_SHORT); +} + +int +ncmpi_put_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_put_vara_all(ncid, varid, start, count, + (const void *)op, nbytes, MPI_INT); +} + +int +ncmpi_put_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_put_vara(ncid, varid, start, count, + (const void *)op, nbytes, MPI_INT); +} + +int +ncmpi_put_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_put_vara_all(ncid, varid, start, count, + (const void *)op, nbytes, MPI_FLOAT); +} + +int +ncmpi_put_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_put_vara(ncid, varid, start, count, + (const void *)op, nbytes, MPI_FLOAT); +} + +int +ncmpi_put_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_put_vara_all(ncid, varid, start, count, + (const void *)op, nbytes, MPI_DOUBLE); +} + +int +ncmpi_put_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_put_vara(ncid, varid, start, count, + (const void *)op, nbytes, MPI_DOUBLE); +} + +int +ncmpi_get_vara_short_all(int ncid, int varid, + const size_t start[], const size_t count[], + short *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vara_all(ncid, varid, start, count, + (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_vara_short(int ncid, int varid, + const size_t start[], const size_t count[], + short *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vara(ncid, varid, start, count, + (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vara_all(ncid, varid, start, count, + (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vara(ncid, varid, start, count, + (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_get_vara_all(ncid, varid, start, count, + (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_get_vara(ncid, varid, start, count, + (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_get_vara_all(ncid, varid, start, count, + (void *)ip, nbytes, MPI_DOUBLE); +} + +int +ncmpi_get_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_get_vara(ncid, varid, start, count, + (void *)ip, nbytes, MPI_DOUBLE); +} + +int +ncmpi_put_vars_short_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const short *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_put_vars_all(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_SHORT); +} + +int +ncmpi_put_vars_short(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const short *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_put_vars(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_SHORT); +} + +int +ncmpi_put_vars_int_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const int *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_put_vars_all(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_INT); +} + +int +ncmpi_put_vars_int(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const int *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_put_vars(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_INT); +} + +int +ncmpi_put_vars_float_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const float *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_put_vars_all(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_FLOAT); +} + +int +ncmpi_put_vars_float(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const float *op) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_put_vars(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_FLOAT); +} + +int +ncmpi_put_vars_double_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const double *op) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_put_vars_all(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_DOUBLE); + +} + +int +ncmpi_put_vars_double(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + const double *op) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_put_vars(ncid, varid, start, count, stride, + (const void *)op, nbytes, MPI_DOUBLE); + +} + +int +ncmpi_get_vars_short_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + short *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_get_vars_all(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_vars_short(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + short *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(short) * nelems; + + return ncmpi_get_vars(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_SHORT); +} + +int +ncmpi_get_vars_int_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + int *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vars_all(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_vars_int(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + int *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(int) * nelems; + + return ncmpi_get_vars(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_INT); +} + +int +ncmpi_get_vars_float_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + float *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_get_vars_all(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_vars_float(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + float *ip) { + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(float) * nelems; + + return ncmpi_get_vars(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_FLOAT); +} + +int +ncmpi_get_vars_double_all(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + double *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_get_vars_all(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_DOUBLE); +} + +int +ncmpi_get_vars_double(int ncid, int varid, + const size_t start[], + const size_t count[], + const size_t stride[], + double *ip) { + + NC_var *varp; + NC *ncp; + int status; + int dim; + int nelems, nbytes; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + return NC_ENOTVAR; + + nelems = 1; + for (dim = 0; dim < varp->ndims; dim++) + nelems *= count[dim]; + nbytes = (int)sizeof(double) * nelems; + + return ncmpi_get_vars(ncid, varid, start, count, stride, + (void *)ip, nbytes, MPI_DOUBLE); +} + +/* End {put,get}_var */ Index: /branches/SDM_SciDAC/src/lib/dim.c =================================================================== --- /branches/SDM_SciDAC/src/lib/dim.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/dim.c (revision 2) @@ -0,0 +1,520 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include "ncx.h" +#include "fbits.h" + +/* + * Free dim + * Formerly +NC_free_dim(dim) + */ +void +free_NC_dim(NC_dim *dimp) +{ + if(dimp == NULL) + return; + free_NC_string(dimp->name); + free(dimp); +} + + +NC_dim * +new_x_NC_dim(NC_string *name) +{ + NC_dim *dimp; + + dimp = (NC_dim *) malloc(sizeof(NC_dim)); + if(dimp == NULL) + return NULL; + + dimp->name = name; + dimp->size = 0; + + return(dimp); +} + + +/* + * Formerly +NC_new_dim(const char *name, long size) + */ +static NC_dim * +new_NC_dim(const char *name, size_t size) +{ + NC_string *strp; + NC_dim *dimp; + + strp = new_NC_string(strlen(name), name); + if(strp == NULL) + return NULL; + + dimp = new_x_NC_dim(strp); + if(dimp == NULL) + { + free_NC_string(strp); + return NULL; + } + + dimp->size = size; + + return(dimp); +} + + +static NC_dim * +dup_NC_dim(const NC_dim *dimp) +{ + return new_NC_dim(dimp->name->cp, dimp->size); +} + +/* + * Step thru NC_DIMENSION array, seeking the UNLIMITED dimension. + * Return dimid or -1 on not found. + * *dimpp is set to the appropriate NC_dim. + * The loop structure is odd. In order to parallelize, + * we moved a clearer 'break' inside the loop body to the loop test. + */ +int +find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp) +{ + assert(ncap != NULL); + + if(ncap->nelems == 0) + return -1; + + { + int dimid = 0; + NC_dim **loc = ncap->value; + + for(; (size_t) dimid < ncap->nelems + && (*loc)->size != NC_UNLIMITED; dimid++, loc++) + { + /*EMPTY*/ + } + if(dimid >= ncap->nelems) + return(-1); /* not found */ + /* else, normal return */ + if(dimpp != NULL) + *dimpp = *loc; + return dimid; + } +} + + +/* + * Step thru NC_DIMENSION array, seeking match on name. + * Return dimid or -1 on not found. + * *dimpp is set to the appropriate NC_dim. + * The loop structure is odd. In order to parallelize, + * we moved a clearer 'break' inside the loop body to the loop test. + */ +static int +NC_finddim(const NC_dimarray *ncap, const char *name, NC_dim **dimpp) +{ + + assert(ncap != NULL); + + if(ncap->nelems == 0) + return -1; + + { + size_t slen = strlen(name); + int dimid = 0; + NC_dim **loc = (NC_dim **) ncap->value; + + for(; (size_t) dimid < ncap->nelems + && (strlen((*loc)->name->cp) != slen + || strncmp((*loc)->name->cp, name, slen) != 0); + dimid++, loc++) + { + /*EMPTY*/ + } + if(dimid >= ncap->nelems) + return(-1); /* not found */ + /* else, normal return */ + if(dimpp != NULL) + *dimpp = *loc; + return(dimid); + } +} + + +/* dimarray */ + + +/* + * Free the stuff "in" (referred to by) an NC_dimarray. + * Leaves the array itself allocated. + */ +void +free_NC_dimarrayV0(NC_dimarray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nelems == 0) + return; + + assert(ncap->value != NULL); + + { + NC_dim **dpp = ncap->value; + NC_dim *const *const end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) + { + free_NC_dim(*dpp); + *dpp = NULL; + } + } + ncap->nelems = 0; +} + + +/* + * Free NC_dimarray values. + * formerly +NC_free_array() + */ +void +free_NC_dimarrayV(NC_dimarray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nalloc == 0) + return; + + assert(ncap->value != NULL); + + free_NC_dimarrayV0(ncap); + + free(ncap->value); + ncap->value = NULL; + ncap->nalloc = 0; +} + + +int +dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref) +{ + int status = NC_NOERR; + + assert(ref != NULL); + assert(ncap != NULL); + + if(ref->nelems != 0) + { + const size_t sz = ref->nelems * sizeof(NC_dim *); + ncap->value = (NC_dim **) malloc(sz); + if(ncap->value == NULL) + return NC_ENOMEM; + (void) memset(ncap->value, 0, sz); + ncap->nalloc = ref->nelems; + } + + ncap->nelems = 0; + { + NC_dim **dpp = ncap->value; + const NC_dim **drpp = (const NC_dim **)ref->value; + NC_dim *const *const end = &dpp[ref->nelems]; + for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++) + { + *dpp = dup_NC_dim(*drpp); + if(*dpp == NULL) + { + status = NC_ENOMEM; + break; + } + } + } + + if(status != NC_NOERR) + { + free_NC_dimarrayV(ncap); + return status; + } + + assert(ncap->nelems == ref->nelems); + + return NC_NOERR; +} + + +/* + * Add a new handle on the end of an array of handles + * Formerly +NC_incr_array(array, tail) + */ +static int +incr_NC_dimarray(NC_dimarray *ncap, NC_dim *newelemp) +{ + NC_dim **vp; + + assert(ncap != NULL); + + if(ncap->nalloc == 0) + { + assert(ncap->nelems == 0); + vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *)); + if(vp == NULL) + return NC_ENOMEM; + ncap->value = vp; + ncap->nalloc = NC_ARRAY_GROWBY; + } + else if(ncap->nelems +1 > ncap->nalloc) + { + vp = (NC_dim **) realloc(ncap->value, + (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *)); + if(vp == NULL) + return NC_ENOMEM; + ncap->value = vp; + ncap->nalloc += NC_ARRAY_GROWBY; + } + + if(newelemp != NULL) + { + ncap->value[ncap->nelems] = newelemp; + ncap->nelems++; + } + return NC_NOERR; +} + + +NC_dim * +elem_NC_dimarray(const NC_dimarray *ncap, size_t elem) +{ + assert(ncap != NULL); + /* cast needed for braindead systems with signed size_t */ + if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems) + return NULL; + + assert(ncap->value != NULL); + + return ncap->value[elem]; +} + + +/* Public */ + +int +nc_def_dim(int ncid, const char *name, size_t size, int *dimidp) +{ + int status; + NC *ncp; + int dimid; + NC_dim *dimp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) size > X_INT_MAX) /* Backward compat */ + return NC_EINVAL; + + if(size == NC_UNLIMITED) + { + dimid = find_NC_Udim(&ncp->dims, &dimp); + if(dimid != -1) + { + assert(dimid != -1); + return NC_EUNLIMIT; + } + } + + if(ncp->dims.nelems >= NC_MAX_DIMS) + return NC_EMAXDIMS; + + dimid = NC_finddim(&ncp->dims, name, &dimp); + if(dimid != -1) + return NC_ENAMEINUSE; + + dimp = new_NC_dim(name, size); + if(dimp == NULL) + return NC_ENOMEM; + status = incr_NC_dimarray(&ncp->dims, dimp); + if(status != NC_NOERR) + { + free_NC_dim(dimp); + return status; + } + + if(dimidp != NULL) + *dimidp = (int)ncp->dims.nelems -1; + return NC_NOERR; +} + + +int +nc_inq_dimid(int ncid, const char *name, int *dimid_ptr) +{ + int status; + NC *ncp; + int dimid; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + dimid = NC_finddim(&ncp->dims, name, NULL); + + if(dimid == -1) + return NC_EBADDIM; + + *dimid_ptr = dimid; + return NC_NOERR; +} + + +int +nc_inq_dim(int ncid, int dimid, char *name, size_t *sizep) +{ + int status; + NC *ncp; + NC_dim *dimp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); + if(dimp == NULL) + return NC_EBADDIM; + + if(name != NULL) + { + (void)strncpy(name, dimp->name->cp, + dimp->name->nchars); + name[dimp->name->nchars] = 0; + } + if(sizep != 0) + { + if(dimp->size == NC_UNLIMITED) + *sizep = NC_get_numrecs(ncp); + else + *sizep = dimp->size; + } + return NC_NOERR; +} + + +int +nc_inq_dimname(int ncid, int dimid, char *name) +{ + int status; + NC *ncp; + NC_dim *dimp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); + if(dimp == NULL) + return NC_EBADDIM; + + if(name != NULL) + { + (void)strncpy(name, dimp->name->cp, + dimp->name->nchars); + name[dimp->name->nchars] = 0; + } + + return NC_NOERR; +} + + +int +nc_inq_dimlen(int ncid, int dimid, size_t *lenp) +{ + int status; + NC *ncp; + NC_dim *dimp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); + if(dimp == NULL) + return NC_EBADDIM; + + if(lenp != 0) + { + if(dimp->size == NC_UNLIMITED) + *lenp = NC_get_numrecs(ncp); + else + *lenp = dimp->size; + } + return NC_NOERR; +} + + +int +nc_rename_dim( int ncid, int dimid, const char *newname) +{ + int status; + NC *ncp; + int existid; + NC_dim *dimp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + status = NC_check_name(newname); + if(status != NC_NOERR) + return status; + + existid = NC_finddim(&ncp->dims, newname, &dimp); + if(existid != -1) + return NC_ENAMEINUSE; + + dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid); + if(dimp == NULL) + return NC_EBADDIM; + + if(NC_indef(ncp)) + { + NC_string *old = dimp->name; + NC_string *newStr = new_NC_string(strlen(newname), newname); + if(newStr == NULL) + return NC_ENOMEM; + dimp->name = newStr; + free_NC_string(old); + return NC_NOERR; + } + + /* else, not in define mode */ + + status = set_NC_string(dimp->name, newname); + if(status != NC_NOERR) + return status; + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + + return NC_NOERR; +} Index: /branches/SDM_SciDAC/src/lib/ncconfig.in =================================================================== --- /branches/SDM_SciDAC/src/lib/ncconfig.in (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncconfig.in (revision 2) @@ -0,0 +1,81 @@ +/* libsrc/ncconfig.in. Generated automatically from configure.in by autoheader. */ +/* $Id$ */ +#ifndef _NCCONFIG_H_ +#define _NCCONFIG_H_ + +/* Define if you're on an HP-UX system. */ +#undef _HPUX_SOURCE + +/* 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 doesn't define. */ +#undef off_t + +/* Define to `unsigned' if 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 . */ +#undef NO_STDLIB_H + +/* Define if you don't have the . */ +#undef NO_SYS_TYPES_H + +/* Define if you have the ftruncate function */ +#undef HAVE_FTRUNCATE + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you don't have the strerror function */ +#undef NO_STRERROR + +/* The number of bytes in a size_t */ +#undef SIZEOF_SIZE_T + +/* The number of bytes in a off_t */ +#undef SIZEOF_OFF_T + +/* 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 + +/* Define if the system does not use IEEE floating point representation */ +#undef NO_IEEE_FLOAT + +/* The number of bytes in a double. */ +#undef SIZEOF_DOUBLE + +/* The number of bytes in a float. */ +#undef SIZEOF_FLOAT + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT + +#endif /* !_NCCONFIG_H_ */ Index: /branches/SDM_SciDAC/src/lib/attr.c =================================================================== --- /branches/SDM_SciDAC/src/lib/attr.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/attr.c (revision 2) @@ -0,0 +1,2253 @@ +/* Do not edit this file. It is produced from the corresponding .m4 source */ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include "ncx.h" +#include "fbits.h" +#include "rnd.h" + + +/* + * Free attr + * Formerly +NC_free_attr() + */ +void +free_NC_attr(NC_attr *attrp) +{ + + if(attrp == NULL) + return; + free_NC_string(attrp->name); + free(attrp); +} + + +/* + * How much space will 'nelems' of 'type' take in + * external representation (as the values of an attribute)? + */ +static size_t +ncx_len_NC_attrV(nc_type type, size_t nelems) +{ + switch(type) { + case NC_BYTE: + case NC_CHAR: + return ncx_len_char(nelems); + case NC_SHORT: + return ncx_len_short(nelems); + case NC_INT: + return ncx_len_int(nelems); + case NC_FLOAT: + return ncx_len_float(nelems); + case NC_DOUBLE: + return ncx_len_double(nelems); + } + /* default */ + assert("ncx_len_NC_attr bad type" == 0); + return 0; +} + + +NC_attr * +new_x_NC_attr( + NC_string *strp, + nc_type type, + size_t nelems) +{ + NC_attr *attrp; + const size_t xsz = ncx_len_NC_attrV(type, nelems); + size_t sz = M_RNDUP(sizeof(NC_attr)); + + assert(!(xsz == 0 && nelems != 0)); + + sz += xsz; + + attrp = (NC_attr *) malloc(sz); + if(attrp == NULL ) + return NULL; + + attrp->xsz = xsz; + + attrp->name = strp; + attrp->type = type; + attrp->nelems = nelems; + if(xsz != 0) + attrp->xvalue = (char *)attrp + M_RNDUP(sizeof(NC_attr)); + else + attrp->xvalue = NULL; + + return(attrp); +} + + +/* + * Formerly +NC_new_attr(name,type,count,value) + */ +static NC_attr * +new_NC_attr( + const char *name, + nc_type type, + size_t nelems) +{ + NC_string *strp; + NC_attr *attrp; + + assert(name != NULL && *name != 0); + + strp = new_NC_string(strlen(name), name); + if(strp == NULL) + return NULL; + + attrp = new_x_NC_attr(strp, type, nelems); + if(attrp == NULL) + { + free_NC_string(strp); + return NULL; + } + + return(attrp); +} + + +static NC_attr * +dup_NC_attr(const NC_attr *rattrp) +{ + NC_attr *attrp = new_NC_attr(rattrp->name->cp, + rattrp->type, rattrp->nelems); + if(attrp == NULL) + return NULL; + (void) memcpy(attrp->xvalue, rattrp->xvalue, rattrp->xsz); + return attrp; +} + +/* attrarray */ + +/* + * Free the stuff "in" (referred to by) an NC_attrarray. + * Leaves the array itself allocated. + */ +void +free_NC_attrarrayV0(NC_attrarray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nelems == 0) + return; + + assert(ncap->value != NULL); + + { + NC_attr **app = ncap->value; + NC_attr *const *const end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) + { + free_NC_attr(*app); + *app = NULL; + } + } + ncap->nelems = 0; +} + + +/* + * Free NC_attrarray values. + * formerly +NC_free_array() + */ +void +free_NC_attrarrayV(NC_attrarray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nalloc == 0) + return; + + assert(ncap->value != NULL); + + free_NC_attrarrayV0(ncap); + + free(ncap->value); + ncap->value = NULL; + ncap->nalloc = 0; +} + + +int +dup_NC_attrarrayV(NC_attrarray *ncap, const NC_attrarray *ref) +{ + int status = NC_NOERR; + + assert(ref != NULL); + assert(ncap != NULL); + + if(ref->nelems != 0) + { + const size_t sz = ref->nelems * sizeof(NC_attr *); + ncap->value = (NC_attr **) malloc(sz); + if(ncap->value == NULL) + return NC_ENOMEM; + + (void) memset(ncap->value, 0, sz); + ncap->nalloc = ref->nelems; + } + + ncap->nelems = 0; + { + NC_attr **app = ncap->value; + const NC_attr **drpp = (const NC_attr **)ref->value; + NC_attr *const *const end = &app[ref->nelems]; + for( /*NADA*/; app < end; drpp++, app++, ncap->nelems++) + { + *app = dup_NC_attr(*drpp); + if(*app == NULL) + { + status = NC_ENOMEM; + break; + } + } + } + + if(status != NC_NOERR) + { + free_NC_attrarrayV(ncap); + return status; + } + + assert(ncap->nelems == ref->nelems); + + return NC_NOERR; +} + + +/* + * Add a new handle on the end of an array of handles + * Formerly +NC_incr_array(array, tail) + */ +static int +incr_NC_attrarray(NC_attrarray *ncap, NC_attr *newelemp) +{ + NC_attr **vp; + + assert(ncap != NULL); + + if(ncap->nalloc == 0) + { + assert(ncap->nelems == 0); + vp = (NC_attr **) malloc(NC_ARRAY_GROWBY * sizeof(NC_attr *)); + if(vp == NULL) + return NC_ENOMEM; + + ncap->value = vp; + ncap->nalloc = NC_ARRAY_GROWBY; + } + else if(ncap->nelems +1 > ncap->nalloc) + { + vp = (NC_attr **) realloc(ncap->value, + (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_attr *)); + if(vp == NULL) + return NC_ENOMEM; + + ncap->value = vp; + ncap->nalloc += NC_ARRAY_GROWBY; + } + + if(newelemp != NULL) + { + ncap->value[ncap->nelems] = newelemp; + ncap->nelems++; + } + return NC_NOERR; +} + + +NC_attr * +elem_NC_attrarray(const NC_attrarray *ncap, size_t elem) +{ + assert(ncap != NULL); + /* cast needed for braindead systems with signed size_t */ + if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems) + return NULL; + + assert(ncap->value != NULL); + + return ncap->value[elem]; +} + +/* End attarray per se */ + +/* + * Given ncp and varid, return ptr to array of attributes + * else NULL on error + */ +static NC_attrarray * +NC_attrarray0( NC *ncp, int varid) +{ + NC_attrarray *ap; + + if(varid == NC_GLOBAL) /* Global attribute, attach to cdf */ + { + ap = &ncp->attrs; + } + else if(varid >= 0 && (size_t) varid < ncp->vars.nelems) + { + NC_var **vpp; + vpp = (NC_var **)ncp->vars.value; + vpp += varid; + ap = &(*vpp)->attrs; + } else { + ap = NULL; + } + return(ap); +} + + +/* + * Step thru NC_ATTRIBUTE array, seeking match on name. + * return match or NULL if Not Found. + */ +NC_attr ** +NC_findattr(const NC_attrarray *ncap, const char *name) +{ + NC_attr **attrpp; + size_t attrid; + size_t slen; + + assert(ncap != NULL); + + if(ncap->nelems == 0) + return NULL; + + attrpp = (NC_attr **) ncap->value; + + slen = strlen(name); + + for(attrid = 0; attrid < ncap->nelems; attrid++, attrpp++) + { + if(strlen((*attrpp)->name->cp) == slen && + strncmp((*attrpp)->name->cp, name, slen) == 0) + { + return(attrpp); /* Normal return */ + } + } + return(NULL); +} + + +/* + * Look up by ncid, varid and name, return NULL if not found + */ +static int +NC_lookupattr(int ncid, + int varid, + const char *name, /* attribute name */ + NC_attr **attrpp) /* modified on return */ +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **tmp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + tmp = NC_findattr(ncap, name); + if(tmp == NULL) + return NC_ENOTATT; + + if(attrpp != NULL) + *attrpp = *tmp; + + return ENOERR; +} + +/* Public */ + +int +nc_inq_attname(int ncid, int varid, int attnum, char *name) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + attrp = elem_NC_attrarray(ncap, (size_t)attnum); + if(attrp == NULL) + return NC_ENOTATT; + + (void) strncpy(name, attrp->name->cp, attrp->name->nchars); + name[attrp->name->nchars] = 0; + + return NC_NOERR; +} + + +int +nc_inq_attid(int ncid, int varid, const char *name, int *attnump) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + + attrpp = NC_findattr(ncap, name); + if(attrpp == NULL) + return NC_ENOTATT; + + if(attnump != NULL) + *attnump = (int)(attrpp - ncap->value); + + return NC_NOERR; +} + +int +nc_inq_atttype(int ncid, int varid, const char *name, nc_type *datatypep) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(datatypep != NULL) + *datatypep = attrp->type; + + return NC_NOERR; +} + +int +nc_inq_attlen(int ncid, int varid, const char *name, size_t *lenp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(lenp != NULL) + *lenp = attrp->nelems; + + return NC_NOERR; +} + +int +nc_inq_att(int ncid, + int varid, + const char *name, /* input, attribute name */ + nc_type *datatypep, + size_t *lenp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(datatypep != NULL) + *datatypep = attrp->type; + if(lenp != NULL) + *lenp = attrp->nelems; + + return NC_NOERR; +} + + +int +nc_rename_att( int ncid, int varid, const char *name, const char *newname) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **tmp; + NC_attr *attrp; + NC_string *newStr, *old; + + /* sortof inline clone of NC_lookupattr() */ + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + +/* bugs found by Jianwei Li + status = NC_check_name(name); +*/ + status = NC_check_name(newname); + if(status != NC_NOERR) + return status; + + tmp = NC_findattr(ncap, name); + if(tmp == NULL) + return NC_ENOTATT; + attrp = *tmp; + /* end inline clone NC_lookupattr() */ + + if(NC_findattr(ncap, newname) != NULL) + { + /* name in use */ + return NC_ENAMEINUSE; + } + + old = attrp->name; + if(NC_indef(ncp)) + { + newStr = new_NC_string(strlen(newname), newname); + if( newStr == NULL) + return NC_ENOMEM; + attrp->name = newStr; + free_NC_string(old); + return NC_NOERR; + } + /* else */ + status = set_NC_string(old, newname); + if( status != NC_NOERR) + return status; + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + + return NC_NOERR; +} + + +int +nc_copy_att(int ncid_in, int varid_in, const char *name, int ncid_out, int ovarid) +{ + int status; + NC_attr *iattrp; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_lookupattr(ncid_in, varid_in, name, &iattrp); + if(status != NC_NOERR) + return status; + + status = NC_check_id(ncid_out, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, ovarid); + if(ncap == NULL) + return NC_ENOTVAR; + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + attrp = *attrpp; /* convenience */ + + if(iattrp->xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = iattrp->xsz; + attrp->type = iattrp->type; + attrp->nelems = iattrp->nelems; + + (void) memcpy(attrp->xvalue, iattrp->xvalue, + iattrp->xsz); + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + + return NC_NOERR; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + attrp = new_NC_attr(name, iattrp->type, iattrp->nelems); + if(attrp == NULL) + return NC_ENOMEM; + + (void) memcpy(attrp->xvalue, iattrp->xvalue, + iattrp->xsz); + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + status = incr_NC_attrarray(ncap, attrp); + if(status != NC_NOERR) + { + free_NC_attr(attrp); + return status; + } + } + + return NC_NOERR; +} + + +int +nc_del_att(int ncid, int varid, const char *name) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + int attrid; + size_t slen; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + /* sortof inline NC_findattr() */ + slen = strlen(name); + + attrpp = (NC_attr **) ncap->value; + for(attrid = 0; (size_t) attrid < ncap->nelems; attrid++, attrpp++) + { + if( slen == (*attrpp)->name->nchars && + strncmp(name, (*attrpp)->name->cp, slen) == 0) + { + old = *attrpp; + break; + } + } + if( (size_t) attrid == ncap->nelems ) + return NC_ENOTATT; + /* end inline NC_findattr() */ + + /* shuffle down */ + for(attrid++; (size_t) attrid < ncap->nelems; attrid++) + { + *attrpp = *(attrpp + 1); + attrpp++; + } + *attrpp = NULL; + /* decrement count */ + ncap->nelems--; + + free_NC_attr(old); + + return NC_NOERR; +} + + +static int +ncx_pad_putn_Iuchar(void **xpp, size_t nelems, const uchar *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_uchar(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_uchar(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_uchar(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_uchar(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_uchar(xpp, nelems, tp); + } + assert("ncx_pad_putn_Iuchar invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Iuchar(const void **xpp, size_t nelems, uchar *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_uchar(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_uchar(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_uchar(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_uchar(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_uchar(xpp, nelems, tp); + } + assert("ncx_pad_getn_Iuchar invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Ischar(void **xpp, size_t nelems, const schar *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_schar(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_schar(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_schar(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_schar(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_schar(xpp, nelems, tp); + } + assert("ncx_pad_putn_Ischar invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Ischar(const void **xpp, size_t nelems, schar *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_schar(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_schar(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_schar(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_schar(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_schar(xpp, nelems, tp); + } + assert("ncx_pad_getn_Ischar invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Ishort(void **xpp, size_t nelems, const short *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_short(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_short(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_short(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_short(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_short(xpp, nelems, tp); + } + assert("ncx_pad_putn_Ishort invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Ishort(const void **xpp, size_t nelems, short *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_short(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_short(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_short(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_short(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_short(xpp, nelems, tp); + } + assert("ncx_pad_getn_Ishort invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Iint(void **xpp, size_t nelems, const int *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_int(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_int(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_int(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_int(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_int(xpp, nelems, tp); + } + assert("ncx_pad_putn_Iint invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Iint(const void **xpp, size_t nelems, int *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_int(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_int(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_int(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_int(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_int(xpp, nelems, tp); + } + assert("ncx_pad_getn_Iint invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Ilong(void **xpp, size_t nelems, const long *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_long(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_long(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_long(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_long(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_long(xpp, nelems, tp); + } + assert("ncx_pad_putn_Ilong invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Ilong(const void **xpp, size_t nelems, long *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_long(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_long(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_long(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_long(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_long(xpp, nelems, tp); + } + assert("ncx_pad_getn_Ilong invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Ifloat(void **xpp, size_t nelems, const float *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_float(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_float(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_float(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_float(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_float(xpp, nelems, tp); + } + assert("ncx_pad_putn_Ifloat invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Ifloat(const void **xpp, size_t nelems, float *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_float(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_float(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_float(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_float(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_float(xpp, nelems, tp); + } + assert("ncx_pad_getn_Ifloat invalid type" == 0); + return NC_EBADTYPE; +} + + +static int +ncx_pad_putn_Idouble(void **xpp, size_t nelems, const double *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_putn_schar_double(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_putn_short_double(xpp, nelems, tp); + case NC_INT: + return ncx_putn_int_double(xpp, nelems, tp); + case NC_FLOAT: + return ncx_putn_float_double(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_putn_double_double(xpp, nelems, tp); + } + assert("ncx_pad_putn_Idouble invalid type" == 0); + return NC_EBADTYPE; +} + +static int +ncx_pad_getn_Idouble(const void **xpp, size_t nelems, double *tp, nc_type type) +{ + switch(type) { + case NC_CHAR: + return NC_ECHAR; + case NC_BYTE: + return ncx_pad_getn_schar_double(xpp, nelems, tp); + case NC_SHORT: + return ncx_pad_getn_short_double(xpp, nelems, tp); + case NC_INT: + return ncx_getn_int_double(xpp, nelems, tp); + case NC_FLOAT: + return ncx_getn_float_double(xpp, nelems, tp); + case NC_DOUBLE: + return ncx_getn_double_double(xpp, nelems, tp); + } + assert("ncx_pad_getn_Idouble invalid type" == 0); + return NC_EBADTYPE; +} + + + +int +nc_put_att_text(int ncid, int varid, const char *name, + size_t nelems, const char *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(NC_CHAR, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = NC_CHAR; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_text(&xp, nelems, value); + if(status != NC_NOERR) + return status; + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + + return NC_NOERR; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + attrp = new_NC_attr(name, NC_CHAR, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_text(&xp, nelems, value); + if(status != NC_NOERR) + return status; + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + status = incr_NC_attrarray(ncap, attrp); + if(status != NC_NOERR) + { + free_NC_attr(attrp); + return status; + } + } + + return NC_NOERR; +} + + +int +nc_get_att_text(int ncid, int varid, const char *name, char *str) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type != NC_CHAR) + return NC_ECHAR; + + /* else */ + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_text(&xp, attrp->nelems, str); + } +} + + + + +int +nc_put_att_schar(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const signed char *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ischar(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ischar + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ischar(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ischar + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_schar(int ncid, int varid, const char *name, signed char *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Ischar(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_uchar(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const unsigned char *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Iuchar(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Iuchar + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Iuchar(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Iuchar + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Iuchar(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_short(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const short *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ishort(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ishort + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ishort(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ishort + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_short(int ncid, int varid, const char *name, short *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Ishort(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_int(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const int *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Iint(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Iint + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Iint(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Iint + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_int(int ncid, int varid, const char *name, int *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Iint(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_long(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const long *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ilong(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ilong + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ilong(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ilong + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_long(int ncid, int varid, const char *name, long *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Ilong(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_float(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const float *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ifloat(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ifloat + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Ifloat(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Ifloat + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_float(int ncid, int varid, const char *name, float *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Ifloat(&xp, attrp->nelems, tp, attrp->type); + } +} + + +int +nc_put_att_double(int ncid, int varid, const char *name, + nc_type type, size_t nelems, const double *value) +{ + int status; + NC *ncp; + NC_attrarray *ncap; + NC_attr **attrpp; + NC_attr *old = NULL; + NC_attr *attrp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + return NC_EPERM; + + ncap = NC_attrarray0(ncp, varid); + if(ncap == NULL) + return NC_ENOTVAR; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + if(type == NC_CHAR) + return NC_ECHAR; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) nelems > X_INT_MAX) /* backward compat */ + return NC_EINVAL; /* Invalid nelems */ + + if(nelems != 0 && value == NULL) + return NC_EINVAL; /* Null arg */ + + attrpp = NC_findattr(ncap, name); + if(attrpp != NULL) /* name in use */ + { + if(!NC_indef(ncp) ) + { + const size_t xsz = ncx_len_NC_attrV(type, nelems); + attrp = *attrpp; /* convenience */ + + if(xsz > attrp->xsz) + return NC_ENOTINDEFINE; + /* else, we can reuse existing without redef */ + + attrp->xsz = xsz; + attrp->type = type; + attrp->nelems = nelems; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Idouble(&xp, nelems, + value, type); + } + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + const int lstatus = NC_sync(ncp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Idouble + */ + if(lstatus != ENOERR) + return lstatus; + } + + return status; + } + /* else, redefine using existing array slot */ + old = *attrpp; + } + else + { + if(!NC_indef(ncp)) + return NC_ENOTINDEFINE; + + if(ncap->nelems >= NC_MAX_ATTRS) + return NC_EMAXATTS; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + attrp = new_NC_attr(name, type, nelems); + if(attrp == NULL) + return NC_ENOMEM; + + if(nelems != 0) + { + void *xp = attrp->xvalue; + status = ncx_pad_putn_Idouble(&xp, nelems, + value, type); + } + + if(attrpp != NULL) + { + assert(old != NULL); + *attrpp = attrp; + free_NC_attr(old); + } + else + { + const int lstatus = incr_NC_attrarray(ncap, attrp); + /* + * N.B.: potentially overrides NC_ERANGE + * set by ncx_pad_putn_Idouble + */ + if(lstatus != NC_NOERR) + { + free_NC_attr(attrp); + return lstatus; + } + } + + return status; +} + +int +nc_get_att_double(int ncid, int varid, const char *name, double *tp) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + if(attrp->nelems == 0) + return NC_NOERR; + + if(attrp->type == NC_CHAR) + return NC_ECHAR; + + { + const void *xp = attrp->xvalue; + return ncx_pad_getn_Idouble(&xp, attrp->nelems, tp, attrp->type); + } +} + + + +/* deprecated, used to support the 2.x interface */ +int +nc_put_att( + int ncid, + int varid, + const char *name, + nc_type type, + size_t nelems, + const void *value) +{ + switch (type) { + case NC_BYTE: + return nc_put_att_schar(ncid, varid, name, type, nelems, + (schar *)value); + case NC_CHAR: + return nc_put_att_text(ncid, varid, name, nelems, + (char *)value); + case NC_SHORT: + return nc_put_att_short(ncid, varid, name, type, nelems, + (short *)value); + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + return nc_put_att_int(ncid, varid, name, type, nelems, + (int *)value); +#elif SIZEOF_LONG == X_SIZEOF_INT + return nc_put_att_long(ncid, varid, name, type, nelems, + (long *)value); +#endif + case NC_FLOAT: + return nc_put_att_float(ncid, varid, name, type, nelems, + (float *)value); + case NC_DOUBLE: + return nc_put_att_double(ncid, varid, name, type, nelems, + (double *)value); + } + return NC_EBADTYPE; +} + + +/* deprecated, used to support the 2.x interface */ +int +nc_get_att(int ncid, int varid, const char *name, void *value) +{ + int status; + NC_attr *attrp; + + status = NC_lookupattr(ncid, varid, name, &attrp); + if(status != NC_NOERR) + return status; + + switch (attrp->type) { + case NC_BYTE: + return nc_get_att_schar(ncid, varid, name, + (schar *)value); + case NC_CHAR: + return nc_get_att_text(ncid, varid, name, + (char *)value); + case NC_SHORT: + return nc_get_att_short(ncid, varid, name, + (short *)value); + case NC_INT: +#if (SIZEOF_INT >= X_SIZEOF_INT) + return nc_get_att_int(ncid, varid, name, + (int *)value); +#elif SIZEOF_LONG == X_SIZEOF_INT + return nc_get_att_long(ncid, varid, name, + (long *)value); +#endif + case NC_FLOAT: + return nc_get_att_float(ncid, varid, name, + (float *)value); + case NC_DOUBLE: + return nc_get_att_double(ncid, varid, name, + (double *)value); + } + return NC_EBADTYPE; +} Index: /branches/SDM_SciDAC/src/lib/fbits.h =================================================================== --- /branches/SDM_SciDAC/src/lib/fbits.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/fbits.h (revision 2) @@ -0,0 +1,26 @@ +/* + * Copyright 1995, University Corporation for Atmospheric Research + * See top level COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#ifndef _FBITS_H_ +#define _FBITS_H_ + +/* + * Macros for dealing with flag bits. + */ +#define fSet(t, f) ((t) |= (f)) +#define fClr(t, f) ((t) &= ~(f)) +#define fIsSet(t, f) ((t) & (f)) +#define fMask(t, f) ((t) & ~(f)) + +/* + * Propositions + */ +/* a implies b */ +#define pIf(a,b) (!(a) || (b)) +/* a if and only if b, use == when it makes sense */ +#define pIff(a,b) (((a) && (b)) || (!(a) && !(b))) + +#endif /*!FBITS_H_*/ Index: /branches/SDM_SciDAC/src/lib/mpinetcdf.h =================================================================== --- /branches/SDM_SciDAC/src/lib/mpinetcdf.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/mpinetcdf.h (revision 2) @@ -0,0 +1,94 @@ +#include +#include "nc.h" + +int +ncmpi_create(MPI_Comm comm, const char *path, int cmode, MPI_Info info, int *ncidp); + +int +ncmpi_open(MPI_Comm comm, const char *path, int omode, MPI_Info info, int *ncidp); + + +int +ncmpi_enddef(int ncid); + + + +int +ncmpi_close(int ncid); + +/* Begin _dim */ + + +/* End _dim */ +/* Begin {put,get}_att */ + + +/* End {put,get}_att */ +/* Begin _var */ + + +/* End _var */ +/* Begin {put,get}_vara */ + +int +ncmpi_put_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op); + +int +ncmpi_put_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + const int *op); + +int +ncmpi_put_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op); + +int +ncmpi_put_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + const float *op); + +int +ncmpi_put_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op); + +int +ncmpi_put_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + const double *op); + +int +ncmpi_get_vara_int_all(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip); + +int +ncmpi_get_vara_int(int ncid, int varid, + const size_t start[], const size_t count[], + int *ip); + +int +ncmpi_get_vara_float_all(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip); + +int +ncmpi_get_vara_float(int ncid, int varid, + const size_t start[], const size_t count[], + float *ip); + +int +ncmpi_get_vara_double_all(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip); + +int +ncmpi_get_vara_double(int ncid, int varid, + const size_t start[], const size_t count[], + double *ip); + + +/* End {put,get}_vara */ Index: /branches/SDM_SciDAC/src/lib/depend =================================================================== --- /branches/SDM_SciDAC/src/lib/depend (revision 2) +++ /branches/SDM_SciDAC/src/lib/depend (revision 2) @@ -0,0 +1,50 @@ +validator: validator.c +header.o: header.c +header.o: nc.h +header.o: ncx.h +mpincio.o: mpincio.c +mpincio.o: ncio.h +mpincio.o: ncconfig.h +mpincio.o: fbits.h +mpincio.o: rnd.h +mpinetcdf.o: mpinetcdf.c +mpinetcdf.o: nc.h +mpinetcdf.o: ncx.h +attr.o: attr.c +attr.o: fbits.h +attr.o: nc.h +attr.o: ncconfig.h +attr.o: ncio.h +attr.o: ncx.h +attr.o: netcdf.h +attr.o: rnd.h +dim.o: dim.c +dim.o: fbits.h +dim.o: nc.h +dim.o: ncconfig.h +dim.o: ncio.h +dim.o: ncx.h +dim.o: netcdf.h +dim.o: rnd.h +error.o: error.c +error.o: netcdf.h +nc.o: fbits.h +nc.o: nc.c +nc.o: nc.h +nc.o: ncconfig.h +nc.o: ncio.h +nc.o: ncx.h +nc.o: netcdf.h +nc.o: rnd.h +ncx.o: ncconfig.h +ncx.o: ncx.c +ncx.o: ncx.h +ncx.o: rnd.h +var.o: fbits.h +var.o: nc.h +var.o: ncconfig.h +var.o: ncio.h +var.o: ncx.h +var.o: netcdf.h +var.o: rnd.h +var.o: var.c Index: /branches/SDM_SciDAC/src/lib/ffio.c =================================================================== --- /branches/SDM_SciDAC/src/lib/ffio.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/ffio.c (revision 2) @@ -0,0 +1,743 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ +/* addition by O. Heudecker, AWI-Bremerhaven, 12.3.1998 */ +/* added correction by John Sheldon and Hans Vahlenkamp 15.4.1998*/ + +#include "ncconfig.h" +#include +#include +#include /* DEBUG */ +#include +#ifndef ENOERR +#define ENOERR 0 +#endif +#include +#include +#include +#include +/* Insertion by O. R. Heudecker, AWI-Bremerhaven 12.3.98 (1 line)*/ +#include + +#include "ncio.h" +#include "fbits.h" +#include "rnd.h" + +#if !defined(NDEBUG) && !defined(X_INT_MAX) +#define X_INT_MAX 2147483647 +#endif +#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */ +#define X_ALIGN 4 +#endif + +#define ALWAYS_NC_SHARE 0 /* DEBUG */ + +/* Begin OS */ + +/* + * What is the preferred I/O block size? + * (This becomes the default *sizehint == ncp->chunk in the higher layers.) + * TODO: What is the the best answer here? + */ +static size_t +blksize(int fd) +{ + struct ffc_stat_s sb; + struct ffsw sw; + if (fffcntl(fd, FC_STAT, &sb, &sw) > -1) + { + if(sb.st_oblksize > 0) + return (size_t) sb.st_oblksize; + } + /* else, silent in the face of error */ + return (size_t) 32768; +} + +/* + * Sortof like ftruncate, except won't make the + * file shorter. + */ +static int +fgrow(const int fd, const off_t len) +{ + struct ffc_stat_s sb; + struct ffsw sw; + if (fffcntl(fd, FC_STAT, &sb, &sw) < 0) + return errno; + if (len < sb.st_size) + return ENOERR; + { + const long dumb = 0; + /* cache current position */ + const off_t pos = ffseek(fd, 0, SEEK_CUR); + if(pos < 0) + return errno; + if (ffseek(fd, len-sizeof(dumb), SEEK_SET) < 0) + return errno; + if(ffwrite(fd, (void *)&dumb, sizeof(dumb)) < 0) + return errno; + if (ffseek(fd, pos, SEEK_SET) < 0) + return errno; + } + /* else */ + return ENOERR; +} + +/* End OS */ +/* Begin ffio */ + +static int +ffio_pgout(ncio *const nciop, + off_t const offset, const size_t extent, + const void *const vp, off_t *posp) +{ +#ifdef X_ALIGN + assert(offset % X_ALIGN == 0); + assert(extent % X_ALIGN == 0); +#endif + + if(*posp != offset) + { + if(ffseek(nciop->fd, offset, SEEK_SET) != offset) + { + return errno; + } + *posp = offset; + } + if(ffwrite(nciop->fd, vp, extent) != extent) + { + return errno; + } + *posp += extent; + + return ENOERR; +} + + +static int +ffio_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; + +#ifdef X_ALIGN + assert(offset % X_ALIGN == 0); + assert(extent % X_ALIGN == 0); +#endif + + if(*posp != offset) + { + if(ffseek(nciop->fd, offset, SEEK_SET) != offset) + { + status = errno; + return status; + } + *posp = offset; + } + + errno = 0; + nread = ffread(nciop->fd, vp, extent); + if(nread != 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_ffio { + off_t pos; + /* buffer */ + off_t bf_offset; + size_t bf_extent; + size_t bf_cnt; + void *bf_base; +} ncio_ffio; + + +static int +ncio_ffio_rel(ncio *const nciop, off_t offset, int rflags) +{ + ncio_ffio *ffp = (ncio_ffio *)nciop->pvt; + int status = ENOERR; + + assert(ffp->bf_offset <= offset); + assert(ffp->bf_cnt != 0); + assert(ffp->bf_cnt <= ffp->bf_extent); +#ifdef X_ALIGN + assert(offset < ffp->bf_offset + X_ALIGN); + assert(ffp->bf_cnt % X_ALIGN == 0 ); +#endif + + if(fIsSet(rflags, RGN_MODIFIED)) + { + if(!fIsSet(nciop->ioflags, NC_WRITE)) + return EPERM; /* attempt to write readonly file */ + + status = ffio_pgout(nciop, ffp->bf_offset, + ffp->bf_cnt, + ffp->bf_base, &ffp->pos); + /* if error, invalidate buffer anyway */ + } + ffp->bf_offset = OFF_NONE; + ffp->bf_cnt = 0; + return status; +} + + +static int +ncio_ffio_get(ncio *const nciop, + off_t offset, size_t extent, + int rflags, + void **const vpp) +{ + ncio_ffio *ffp = (ncio_ffio *)nciop->pvt; + int status = ENOERR; +#ifdef X_ALIGN + size_t rem; +#endif + + 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(ffp->bf_cnt == 0); + +#ifdef X_ALIGN + /* round to seekable boundaries */ + rem = 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); +#endif + + if(ffp->bf_extent < extent) + { + if(ffp->bf_base != NULL) + { + free(ffp->bf_base); + ffp->bf_base = NULL; + ffp->bf_extent = 0; + } + assert(ffp->bf_extent == 0); + ffp->bf_base = malloc(extent); + if(ffp->bf_base == NULL) + return ENOMEM; + ffp->bf_extent = extent; + } + + status = ffio_pgin(nciop, offset, + extent, + ffp->bf_base, + &ffp->bf_cnt, &ffp->pos); + if(status != ENOERR) + return status; + + ffp->bf_offset = offset; + + if(ffp->bf_cnt < extent) + { + (void) memset((char *)ffp->bf_base + ffp->bf_cnt, 0, + extent - ffp->bf_cnt); + ffp->bf_cnt = extent; + } + + +#ifdef X_ALIGN + *vpp = (char *)ffp->bf_base + rem; +#else + *vpp = (char *)ffp->bf_base; +#endif + return ENOERR; +} + + +static int +ncio_ffio_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 = 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 = upper - lower; + extent = diff + nbytes; + + status = ncio_ffio_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_ffio_rel(nciop, lower, RGN_MODIFIED); + + return status; +} + +#ifdef NOFFFLUSH +/* ncio_ffio_sync_noffflush is only needed if the FFIO global layer is + * used, because it currently has a bug that causes the PEs to hang + * RKO 06/26/98 + */ +static int +ncio_ffio_sync_noffflush(ncio *const nciop) +{ + struct ffc_stat_s si; /* for call to fffcntl() */ + struct ffsw ffstatus; /* to return ffsw.sw_error */ + /* run some innocuous ffio routine to get if any errno */ + if(fffcntl(nciop->fd, FC_STAT, &si, &ffstatus) < 0) + return ffstatus.sw_error; + return ENOERR; +} +/* this tests to see if the global FFIO layer is being called for + * returns ~0 if it is, else returns 0 + */ +static int +ncio_ffio_global_test(const char *ControlString) +{ + if (strstr(ControlString,"global") != (char *) NULL) { + return ~0; + } else { + return 0; + } +} +#endif + +static int +ncio_ffio_sync(ncio *const nciop) +{ + if(ffflush(nciop->fd) < 0) + return errno; + return ENOERR; +} + +static void +ncio_ffio_free(void *const pvt) +{ + ncio_ffio *ffp = (ncio_ffio *)pvt; + if(ffp == NULL) + return; + + if(ffp->bf_base != NULL) + { + free(ffp->bf_base); + ffp->bf_base = NULL; + ffp->bf_offset = OFF_NONE; + ffp->bf_extent = 0; + ffp->bf_cnt = 0; + } +} + + +static int +ncio_ffio_init2(ncio *const nciop, size_t *sizehintp) +{ + ncio_ffio *ffp = (ncio_ffio *)nciop->pvt; + + assert(nciop->fd >= 0); + + ffp->bf_extent = *sizehintp; + + assert(ffp->bf_base == NULL); + + /* this is separate allocation because it may grow */ + ffp->bf_base = malloc(ffp->bf_extent); + if(ffp->bf_base == NULL) + { + ffp->bf_extent = 0; + return ENOMEM; + } + /* else */ + return ENOERR; +} + + +static void +ncio_ffio_init(ncio *const nciop) +{ + ncio_ffio *ffp = (ncio_ffio *)nciop->pvt; + + *((ncio_relfunc **)&nciop->rel) = ncio_ffio_rel; /* cast away const */ + *((ncio_getfunc **)&nciop->get) = ncio_ffio_get; /* cast away const */ + *((ncio_movefunc **)&nciop->move) = ncio_ffio_move; /* cast away const */ + *((ncio_syncfunc **)&nciop->sync) = ncio_ffio_sync; /* cast away const */ + *((ncio_freefunc **)&nciop->free) = ncio_ffio_free; /* cast away const */ + + ffp->pos = -1; + ffp->bf_offset = OFF_NONE; + ffp->bf_extent = 0; + ffp->bf_cnt = 0; + ffp->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)) + fprintf(stderr, "NC_SHARE not implemented for ffio\n"); + + sz_ncio_pvt = sizeof(ncio_ffio); + + 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); + + ncio_ffio_init(nciop); + + return nciop; +} + +/* put all the FFIO assign specific code here + * returns a pointer to an internal static char location + * which may change when the function is called again + * if the returned pointer is NULL this indicates that an error occured + * check errno for the netCDF error value + */ +/* prototype fortran subroutines */ +void ASNQFILE(_fcd filename, _fcd attribute, int *istat); +void ASNFILE(_fcd filename, _fcd attribute, int *istat); + +#define BUFLEN 256 +static const char * +ncio_ffio_assign(const char *filename) { + static char buffer[BUFLEN]; + int istat; + _fcd fnp, fbp; + char *envstr; + char *xtra_assign; + char emptystr='\0'; + +/* put things into known states */ + memset(buffer,'\0',BUFLEN); + errno = ENOERR; + +/* set up Fortran character pointers */ + fnp = _cptofcd((char *)filename, strlen(filename)); + fbp = _cptofcd(buffer, BUFLEN); + +/* see if the user has "assigned" to this file */ + ASNQFILE(fnp, fbp, &istat); + if (istat == 0) { /* user has already specified an assign */ + return buffer; + } else if (istat > 0 || istat < -1) { /* error occured */ + errno = NC_EINVAL; /* as good as any */ + return (const char *) NULL; + } /* istat = -1 -> no assign for file */ + envstr = getenv("NETCDF_FFIOSPEC"); + if(envstr == (char *) NULL) { + envstr = "bufa:336:2"; /* this should be macroized */ + } + + /* Insertion by Olaf Heudecker, AWI-Bremerhaven, 12.8.1998 + to allow more versatile FFIO-assigns */ + /* this is unnecessary and could have been included + * into the NETCDF_FFIOSPEC environment variable */ + xtra_assign = getenv("NETCDF_XFFIOSPEC"); + if(xtra_assign == (char *) NULL) { + xtra_assign=&emptystr; + } + if (strlen(envstr)+strlen(xtra_assign) + 4 > BUFLEN) { + /* Error: AssignCommand too long */ + errno=E2BIG; + return (const char *) NULL; + } + (void) sprintf(buffer,"-F %s %s", envstr,xtra_assign); + fbp = _cptofcd(buffer, strlen(buffer)); + ASNFILE(fnp, fbp, &istat); + if (istat == 0) { /* success */ + return buffer; + } else { /* error */ + errno = NC_EINVAL; + return (const char *) NULL; + } +} + +/* Public below this point */ + +/* TODO: Is this reasonable for this platform? */ +static const size_t NCIO_MINBLOCKSIZE = 256; +static const size_t NCIO_MAXBLOCKSIZE = 268435456; /* sanity check, about X_SIZE_T_MAX/8 */ + +int +ncio_create(const char *path, int ioflags, + size_t initialsz, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp) +{ + ncio *nciop; + const char *ControlString; + int oflags = (O_RDWR|O_CREAT|O_TRUNC); + int fd; + int status; + struct ffsw stat; + + if(initialsz < (size_t)igeto + igetsz) + initialsz = (size_t)igeto + igetsz; + + fSet(ioflags, NC_WRITE); + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) { + /* an error occured - just punt */ + status = errno; + goto unwind_new; + } +#ifdef NOFFFLUSH + /* test whether the global layer is being called for + * this file ... if so then can't call FFIO ffflush() + * RKO 06/26/98 + */ + if (strstr(ControlString,"global") != (char *) NULL) { + /* use no ffflush version */ + *((ncio_syncfunc **)&nciop->sync) + = ncio_ffio_sync_noffflush; + } +#endif + if(fIsSet(ioflags, NC_NOCLOBBER)) + fSet(oflags, O_EXCL); + + /* Orig: fd = ffopens(path, oflags, 0666, 0, &stat, ControlString); */ + fd = ffopen(path, oflags, 0666, 0, &stat); + if(fd < 0) + { + status = errno; + goto unwind_new; + } + *((int *)&nciop->fd) = fd; /* cast away const */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + status = ncio_ffio_init2(nciop, sizehintp); + 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) ffclose(fd); + /* ?? unlink */ + /*FALLTHRU*/ +unwind_new: + ncio_free(nciop); + return status; +} + + +int +ncio_open(const char *path, + int ioflags, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp) +{ + ncio *nciop; + const char *ControlString; + int oflags = fIsSet(ioflags, NC_WRITE) ? O_RDWR : O_RDONLY; + int fd; + int status; + struct ffsw stat; + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + if ((ControlString = ncio_ffio_assign(path)) == (const char *)NULL) { + /* an error occured - just punt */ + status = errno; + goto unwind_new; + } +#ifdef NOFFFLUSH + /* test whether the global layer is being called for + * this file ... if so then can't call FFIO ffflush() + * RKO 06/26/98 + */ + if (strstr(ControlString,"global") != (char *) NULL) { + /* use no ffflush version */ + *((ncio_syncfunc **)&nciop->sync) + = ncio_ffio_sync_noffflush; + } +#endif + + /* Orig: fd = ffopens(path, oflags, 0, 0, &stat, ControlString); */ + fd = ffopen(path, oflags, 0, 0, &stat); + + if(fd < 0) + { + status = errno; + goto unwind_new; + } + *((int *)&nciop->fd) = fd; /* cast away const */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + status = ncio_ffio_init2(nciop, sizehintp); + 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) ffclose(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) ffclose(nciop->fd); + + if(doUnlink) + (void) unlink(nciop->path); + + ncio_free(nciop); + + return status; +} Index: /branches/SDM_SciDAC/src/lib/netcdf.3 =================================================================== --- /branches/SDM_SciDAC/src/lib/netcdf.3 (revision 2) +++ /branches/SDM_SciDAC/src/lib/netcdf.3 (revision 2) @@ -0,0 +1,1043 @@ +.TH NETCDF 3 "18 April 1997" "Printed: \n(yr.\n(mo.\n(dy" "UNIDATA LIBRARY FUNCTIONS" +.SH NAME +netcdf \- Unidata Network Common Data Form (netCDF) library, version 3 interface +.SH SYNOPSIS +.ft B +.na +.nh +#include "netcdf.h" +.sp + +cc ... -lnetcdf + +.ad +.hy +.SH "LIBRARY VERSION" +.LP +This document describes version 3 of Unidata netCDF data-access interface +for the C programming language. +.HP +\fBconst char* ncmpi_inq_libvers()\fR +.sp +Returns a string identifying the version of the netCDF library, and +when it was built, like: "3.1a of Aug 22 1996 12:57:47 $". +.LP +The RCS \fBident(1)\fP command will find a string like +"$\|Id: @\|(#) netcdf library version 3.1a of Sep 6 1996 15:56:26 $" +in the library. The SCCS \fBwhat(1)\fP command will find a string like +"netcdf library version 3.1a of Aug 23 1996 16:07:40 $". +.SH "RETURN VALUES" +.LP +All netCDF functions (except +\fBncmpi_inq_libvers(\|)\fR and \fBncmpi_strerror(\|)\fR) return an integer status. +This behavior replaces the +\fBncerr()\fR function +used in previous versions of the library. +If this returned status value is not equal to +\fBNC_NOERR\fR (zero), it +indicates that an error occurred. The possible status values are defined in +system include file and in "netcdf.h". +.HP +\fBconst char* ncmpi_strerror(int \fIstatus\fP)\fR +.sp +Returns a string textual translation of the \fIstatus\fP +value, like "Attribute or variable name contains illegal characters" +or "No such file or directory". +.HP +\fBint ncmpi_create( \fIcomm\fP, const char \fIpath\fP[], int \fIcmode\fP, \fIinfo\fP, +int* \fIncid\fP)\fR +.sp +(Corresponds to \fBnccreate(\|)\fR in version 2) +.sp +Creates a new netCDF dataset at \fIpath\fP, +returning a netCDF ID in \fIncid\fP. +The argument \fIcmode\fP may include the bitwise-or +of the following flags: +\fBNC_NOCLOBBER\fR +to protect existing datasets (default +silently blows them away), +\fBNC_SHARE\fR +for synchronous dataset updates +(default is to buffer accesses), and +\fBNC_LOCK\fR +(not yet implemented). +When a netCDF dataset is created, is is opened +\fBNC_WRITE\fR. +The new netCDF dataset is in define mode. +.HP +\fBint ncmpi__create(const char \fIpath\fP[], int \fIcmode\fP, size_t \fIinitialsize\fP, size_t* \fIchunksize\fP, int* \fIncid\fP)\fR +.sp +Like \fBncmpi_create(\|)\fR but has additional performance tuning parameters. +.sp +The argument \fIinitialsize\fP sets the initial size of the file at +creation time. +.sp +See \fBncmpi__open(\|)\fR below for an explanation of the \fIchunksize\fP +parameter. +.HP +\fBint ncmpi_open( \fIcomm\fP, const char \fIpath\fP[], int \fImode\fP, \fIinfo\fP, int* \fIncid\fP)\fR +.sp +(Corresponds to \fBncopen(\|)\fR in version 2) +.sp +Opens a existing netCDF dataset at \fIpath\fP +returning a netCDF ID +in \fIncid\fP. +The type of access is described by the \fImode\fP parameter, +which may include the bitwise-or +of the following flags: +\fBNC_WRITE\fR +for read-write access (default +read-only), +\fBNC_SHARE\fR +for synchronous dataset updates (default is +to buffer accesses), and +\fBNC_LOCK\fR +(not yet implemented). +.HP +\fBint ncmpi__open(const char \fIpath\fP[], int \fImode\fP, size_t* \fIchunksize\fP, int* \fIncid\fP)\fR +.sp +Like \fBncmpi_open(\|)\fR but has an additional performance tuning parameter. +.sp +The argument referenced by \fIchunksize\fP controls a space versus time +tradeoff, memory allocated in the netcdf library versus number of system +calls. +Because of internal requirements, the value may not be set to exactly +the value requested. +The actual value chosen is returned by reference. +Using the value \fBNC_SIZEHINT_DEFAULT\fR causes the library to choose a +default. +How the system choses the default depends on the system. +On many systems, the "preferred I/O block size" is available from the +\fBstat()\fR system call, \fBstruct stat\fR member \fBst_blksize\fR. +If this is available it is used. Lacking that, twice the system pagesize +is used. +Lacking a call to discover the system pagesize, we just set default +chunksize to 8192. +.sp +The chunksize is a property of a given open netcdf descriptor +\fIncid\fP, it is not a persistent property of the netcdf dataset. +.HP +\fBint ncmpi_redef(int \fIncid\fP)\fR +.sp +(Corresponds to \fBncredef(\|)\fR in version 2) +.sp +Puts an open netCDF dataset into define mode, +so dimensions, variables, and attributes can be added or renamed and +attributes can be deleted. +.HP +\fBint ncmpi_enddef(int \fIncid\fP)\fR +.sp +(Corresponds to \fBncendef(\|)\fR in version 2) +.sp +Takes an open netCDF dataset out of define mode. +The changes made to the netCDF dataset +while it was in define mode are checked and committed to disk if no +problems occurred. Some data values may be written as well, +see "VARIABLE PREFILLING" below. +After a successful call, variable data can be read or written to the dataset. +.HP +\fBint ncmpi__enddef(int \fIncid\fP, size_t \fIh_minfree\fP, size_t \fIv_align\fP, size_t \fIv_minfree\fP, size_t \fIr_align\fP)\fR +.sp +Like \fBncmpi_enddef(\|)\fR but has additional performance tuning parameters. +.sp +Caution: this function exposes internals of the netcdf version 1 file +format. +It may not be available on future netcdf implementations. +.sp +The current netcdf file format has three sections, +the "header" section, the data section for fixed size variables, and +the data section for variables which have an unlimited dimension (record +variables). +The header begins at the beginning of the file. The index +(offset) of the beginning of the other two sections is contained in the +header. Typically, there is no space between the sections. This causes +copying overhead to accrue if one wishes to change the size of the +sections, +as may happen when changing names of things, text attribute values, +adding +attributes or adding variables. Also, for buffered i/o, there may be +advantages +to aligning sections in certain ways. +.sp +The minfree parameters allow one to control costs of future calls +to \fBncmpi_redef(\|)\fR, \fBncmpi_enddef(\|)\fR by requesting that \fIminfree\fP bytes be +available at the end of the section. +The \fIh_minfree\fP parameter sets the pad +at the end of the "header" section. The \fIv_minfree\fP parameter sets +the pad at the end of the data section for fixed size variables. +.sp +The align parameters allow one to set the alignment of the beginning of +the corresponding sections. The beginning of the section is rounded up +to an index which is a multiple of the align parameter. The flag value +\fBNC_ALIGN_CHUNK\fR tells the library to use the chunksize (see above) +as the align parameter. +The \fIv_align\fP parameter controls the alignment of the beginning of +the data section for fixed size variables. +The \fIr_align\fP parameter controls the alignment of the beginning of +the data section for variables which have an unlimited dimension (record +variables). +.sp +The file format requires mod 4 alignment, so the align parameters +are silently rounded up to multiples of 4. The usual call, +\fBncmpi_enddef(\fIncid\fP)\fR +is equivalent to +\fBncmpi__enddef(\fIncid\fP, 0, 4, 0, 4)\fR. +.sp +The file format does not contain a "record size" value, this is +calculated from the sizes of the record variables. This unfortunate fact +prevents us from providing minfree and alignment control of the +"records" +in a netcdf file. If you add a variable which has an unlimited +dimension, +the third section will always be copied with the new variable added. +.HP +\fBint ncmpi_sync(int \fIncid\fP)\fR +.sp +(Corresponds to \fBncsync(\|)\fR in version 2) +.sp +Unless the +\fBNC_SHARE\fR +bit is set in +\fBncmpi_open(\|)\fR or \fBncmpi_create(\|)\fR, +accesses to the underlying netCDF dataset are +buffered by the library. This function synchronizes the state of +the underlying dataset and the library. +This is done automatically by +\fBncmpi_close(\|)\fR and \fBncmpi_enddef(\|)\fR. +.HP +\fBint ncmpi_abort(int \fIncid\fP)\fR +.sp +(Corresponds to \fBncabort(\|)\fR in version 2) +.sp +You don't need to call this function. +This function is called automatically by +\fBncmpi_close(\|)\fR +if the netCDF was in define mode and something goes wrong with the commit. +If the netCDF dataset isn't in define mode, then this function is equivalent to +\fBncmpi_close(\|)\fR. +If it is called after +\fBncmpi_redef(\|)\fR, +but before +\fBncmpi_enddef(\|)\fR, +the new definitions are not committed and the dataset is closed. +If it is called after +\fBncmpi_create(\|)\fR +but before +\fBncmpi_enddef(\|)\fR, +the dataset disappears. +.HP +\fBint ncmpi_close(int \fIncid\fP)\fR +.sp +(Corresponds to +\fBncclose(\|)\fR in version 2) +.sp +Closes an open netCDF dataset. +If the dataset is in define mode, +\fBncmpi_enddef(\|)\fR +will be called before closing. +After a dataset is closed, its ID may be reassigned to another dataset. +.HP +\fBint ncmpi_inq(int \fIncid\fP, int* \fIndims\fP, int* \fInvars\fP, +int* \fInatts\fP, int* \fIunlimdimid\fP)\fR +.HP +\fBint ncmpi_inq_ndims(int \fIncid\fP, int* \fIndims\fP)\fR +.HP +\fBint ncmpi_inq_nvars(int \fIncid\fP, int* \fInvars\fP)\fR +.HP +\fBint ncmpi_inq_natts(int \fIncid\fP, int* \fInatts\fP)\fR +.HP +\fBint ncmpi_inq_unlimdim(int \fIncid\fP, int* \fIunlimdimid\fP)\fR +.sp +(Replace \fBncinquire(\|)\fR in version 2) +.sp +Use these functions to find out what is in a netCDF dataset. +Upon successful return, +\fIndims\fP will contain the +number of dimensions defined for this netCDF dataset, +\fInvars\fP will contain the number of variables, +\fInatts\fP will contain the number of attributes, and +\fIunlimdimid\fP will contain the +dimension ID of the unlimited dimension if one exists, or +-1 otherwise. +If any of the +return parameters is a \fBNULL\fR pointer, then the corresponding information +will not be returned; hence, no space need be allocated for it. +.HP +\fBint ncmpi_def_dim(int \fIncid\fP, const char \fIname\fP[], size_t \fIlen\fP, int* \fIdimid\fP)\fR +.sp +(Corresponds to \fBncdimdef(\|)\fR in version 2) +.sp +Adds a new dimension to an open netCDF dataset, which must be +in define mode. +\fIname\fP is the dimension name. +If \fIdimid\fP is not a \fBNULL\fR pointer then upon successful completion \fIdimid\fP will contain the dimension ID of the newly created dimension. +.HP +\fBint ncmpi_inq_dimid(int \fIncid\fP, const char \fIname\fP[], int* \fIdimid\fP)\fR +.sp +(Corresponds to \fBncdimid(\|)\fR in version 2) +.sp +Given a dimension name, returns the ID of a netCDF dimension in \fIdimid\fP. +.HP +\fBint ncmpi_inq_dim(int \fIncid\fP, int \fIdimid\fP, char \fIname\fP[], size_t* \fIlen\fP)\fR +.HP +\fBint ncmpi_inq_dimname(int \fIncid\fP, int \fIdimid\fP, char \fIname\fP[])\fR +.HP +\fBint ncmpi_inq_dimlen(int \fIncid\fP, int \fIdimid\fP, size_t* \fIlen\fP)\fR +.sp +(Replace \fBncdiminq(\|)\fR in version 2) +.sp +Use these functions to find out about a dimension. +If either the \fIname\fP +argument or \fIlen\fP argument is a \fBNULL\fR pointer, then +the associated information will not be returned. Otherwise, +\fIname\fP should be big enough (\fBNC_MAX_NAME\fR) +to hold the dimension name as the name will be copied into your storage. +The length return parameter, \fIlen\fP +will contain the size of the dimension. +For the unlimited dimension, the returned length is the current +maximum value used for writing into any of the variables which use +the dimension. +.HP +\fBint ncmpi_rename_dim(int \fIncid\fP, int \fIdimid\fP, const char \fIname\fP[])\fR +.sp +(Corresponds to \fBncdimrename(\|)\fR in version 2) +.sp +Renames an existing dimension in an open netCDF dataset. +If the new name is longer than the old name, the netCDF dataset must be in +define mode. +You cannot rename a dimension to have the same name as another dimension. +.HP +\fBint ncmpi_def_var(int \fIncid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, int \fIndims\fP, const int \fIdimids\fP[], int* \fIvarid\fP)\fR +.sp +(Corresponds to \fBncvardef(\|)\fR in version 2) +.sp +Adds a new variable to a netCDF dataset. The netCDF must be in define mode. +If not \fBNULL\fR, then \fIvarid\fP will be set to the netCDF variable ID. +.HP +\fBint ncmpi_inq_varid(int \fIncid\fP, const char \fIname\fP[], int* \fIvarid\fP)\fR +.sp +(Corresponds to \fBncvarid(\|)\fR in version 2) +.sp +Returns the ID of a netCDF variable in \fIvarid\fP given its name. +.HP +\fBint ncmpi_inq_var(int \fIncid\fP, int \fIvarid\fP, char \fIname\fP[], nc_type* \fIxtype\fP, int* \fIndims\fP, int \fIdimids\fP[], +int* \fInatts\fP)\fR +.HP +\fBint ncmpi_inq_varname(int \fIncid\fP, int \fIvarid\fP, char \fIname\fP[])\fR +.HP +\fBint ncmpi_inq_vartype(int \fIncid\fP, int \fIvarid\fP, nc_type* \fIxtype\fP)\fR +.HP +\fBint ncmpi_inq_varndims(int \fIncid\fP, int \fIvarid\fP, int* \fIndims\fP)\fR +.HP +\fBint ncmpi_inq_vardimid(int \fIncid\fP, int \fIvarid\fP, int \fIdimids\fP[])\fR +.HP +\fBint ncmpi_inq_varnatts(int \fIncid\fP, int \fIvarid\fP, int* \fInatts\fP)\fR +.sp +(Replace \fBncvarinq(\|)\fR in version 2) +.sp +Returns information about a netCDF variable, given its ID. +If any of the +return parameters (\fIname\fP, \fIxtype\fP, \fIndims\fP, \fIdimids\fP, or +\fInatts\fP) is a \fBNULL\fR pointer, then the corresponding information +will not be returned; hence, no space need be allocated for it. +.HP +\fBint ncmpi_rename_var(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[])\fR +.sp +(Corresponds to \fBncvarrename(\|)\fR in version 2) +.sp +Changes the name of a netCDF variable. +If the new name is longer than the old name, the netCDF must be in define mode. +You cannot rename a variable to have the name of any existing variable. +.HP +\fBint ncmpi_put_var_text(int \fIncid\fP, int \fIvarid\fP, const char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_uchar(int \fIncid\fP, int \fIvarid\fP, const unsigned char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_schar(int \fIncid\fP, int \fIvarid\fP, const signed char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_short(int \fIncid\fP, int \fIvarid\fP, const short \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_int(int \fIncid\fP, int \fIvarid\fP, const int \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_long(int \fIncid\fP, int \fIvarid\fP, const long \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_float(int \fIncid\fP, int \fIvarid\fP, const float \fIout\fP[])\fR +.HP +\fBint ncmpi_put_var_double(int \fIncid\fP, int \fIvarid\fP, const double \fIout\fP[])\fR +.sp +(Replace \fBncvarput(\|)\fR in version 2) +.sp +Writes an entire netCDF variable (i.e. all the values). +The netCDF dataset must be open and in data mode. The type of the data is +specified in the function name, and it is converted to the external type +of the specified variable, if possible, otherwise an +\fBNC_ERANGE\fR error is returned. +.HP +\fBint ncmpi_get_var_text(int \fIncid\fP, int \fIvarid\fP, char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_uchar(int \fIncid\fP, int \fIvarid\fP, unsigned char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_schar(int \fIncid\fP, int \fIvarid\fP, signed char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_short(int \fIncid\fP, int \fIvarid\fP, short \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_int(int \fIncid\fP, int \fIvarid\fP, int \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_long(int \fIncid\fP, int \fIvarid\fP, long \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_float(int \fIncid\fP, int \fIvarid\fP, float \fIin\fP[])\fR +.HP +\fBint ncmpi_get_var_double(int \fIncid\fP, int \fIvarid\fP, double \fIin\fP[])\fR +.sp +(Replace \fBncvarget(\|)\fR in version 2) +.sp +Reads an entire netCDF variable (i.e. all the values). +The netCDF dataset must be open and in data mode. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an \fBNC_ERANGE\fR error is returned. +.HP +\fBint ncmpi_put_var1_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], char \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], unsigned char \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], signed char \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], short \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], int \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], long \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], float \fI*out\fP)\fR +.HP +\fBint ncmpi_put_var1_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], double \fI*out\fP)\fR +.sp +(Replace \fBncvarput1(\|)\fR in version 2) +.sp +Puts a single data value into a variable at the position \fIindex\fP of an +open netCDF dataset that is in data mode. The type of the data is +specified in the function name, and it is converted to the external type +of the specified variable, if possible, otherwise an \fBNC_ERANGE\fR +error is returned. +.HP +\fBint ncmpi_get_var1_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], char* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], unsigned char* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], signed char* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], short* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], int* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], long* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], float* \fIin\fP)\fR +.HP +\fBint ncmpi_get_var1_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIindex\fP[], double* \fIin\fP)\fR +.sp +(Replace \fBncvarget1(\|)\fR in version 2) +.sp +Gets a single data value from a variable at the position \fIindex\fP +of an open netCDF dataset that is in data mode. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an \fBNC_ERANGE\fR error is returned. +.HP +\fBint ncmpi_put_vara_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const unsigned char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const signed char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const short \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const int \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const long \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const float \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vara_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const double \fIout\fP[])\fR +.sp +(Replace \fBncvarput(\|)\fR in version 2) +.sp +Writes an array section of values into a netCDF variable of an open +netCDF dataset, which must be in data mode. The array section is specified +by the \fIstart\fP and \fIcount\fP vectors, which give the starting index +and count of values along each dimension of the specified variable. +The type of the data is +specified in the function name and is converted to the external type +of the specified variable, if possible, otherwise an \fBNC_ERANGE\fR +error is returned. +.HP +\fBint ncmpi_get_vara_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], unsigned char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], signed char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], short \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], int \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], long \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], float \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vara_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], double \fIin\fP[])\fR +.sp +(Corresponds to \fBncvarget(\|)\fR in version 2) +.sp +Reads an array section of values from a netCDF variable of an open +netCDF dataset, which must be in data mode. The array section is specified +by the \fIstart\fP and \fIcount\fP vectors, which give the starting index +and count of values along each dimension of the specified variable. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an \fBNC_ERANGE\fR error is returned. +.HP +\fBint ncmpi_put_vars_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const unsigned char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const signed char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const short \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const int \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const long \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const float \fIout\fP[])\fR +.HP +\fBint ncmpi_put_vars_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], const double \fIout\fP[])\fR +.sp +(Corresponds to \fBncvarputg(\|)\fR in version 2) +.sp +These functions are used for \fIstrided output\fP, which is like the +array section output described above, except that +the sampling stride (the interval between accessed values) is +specified for each dimension. +For an explanation of the sampling stride +vector, see COMMON ARGUMENTS DESCRIPTIONS below. +.HP +\fBint ncmpi_get_vars_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], unsigned char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], signed char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], short \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], int \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], long \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], float \fIin\fP[])\fR +.HP +\fBint ncmpi_get_vars_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], double \fIin\fP[])\fR +.sp +(Corresponds to \fBncvargetg(\|)\fR in version 2) +.sp +These functions are used for \fIstrided input\fP, which is like the +array section input described above, except that +the sampling stride (the interval between accessed values) is +specified for each dimension. +For an explanation of the sampling stride +vector, see COMMON ARGUMENTS DESCRIPTIONS below. +.HP +\fBint ncmpi_put_varm_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const unsigned char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const signed char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const short \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const int \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const long \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const float \fIout\fP[])\fR +.HP +\fBint ncmpi_put_varm_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, const double \fIout\fP[])\fR +.sp +(Corresponds to \fBncvarputg(\|)\fR in version 2) +.sp +These functions are used for \fImapped output\fP, which is like +strided output described above, except that an additional index mapping +vector is provided to specify the in-memory arrangement of the data +values. +For an explanation of the index +mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below. +.HP +\fBint ncmpi_get_varm_text(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_uchar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, unsigned char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_schar(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, signed char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_short(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, short \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_int(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, int \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_long(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, long \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_float(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, float \fIin\fP[])\fR +.HP +\fBint ncmpi_get_varm_double(int \fIncid\fP, int \fIvarid\fP, const size_t \fIstart\fP[], const size_t \fIcount\fP[], const size_t \fIstride\fP[], \fIimap\fP, double \fIin\fP[])\fR +.sp +(Corresponds to \fBncvargetg(\|)\fR in version 2) +.sp +These functions are used for \fImapped input\fP, which is like +strided input described above, except that an additional index mapping +vector is provided to specify the in-memory arrangement of the data +values. +For an explanation of the index +mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below. +.HP +\fBint ncmpi_put_att_text(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_uchar(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const unsigned char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_schar(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const signed char \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_short(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const short \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_int(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const int \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_long(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const long \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_float(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const float \fIout\fP[])\fR +.HP +\fBint ncmpi_put_att_double(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type \fIxtype\fP, size_t \fIlen\fP, const double \fIout\fP[])\fR +.sp +(Replace \fBncattput(\|)\fR in version 2) +.sp +Unlike variables, attributes do not have +separate functions for defining and writing values. +This family of functions defines a new attribute with a value or changes +the value of an existing attribute. +If the attribute is new, or if the space required to +store the attribute value is greater than before, +the netCDF dataset must be in define mode. +The parameter \fIlen\fP is the number of values from \fIout\fP to transfer. +It is often one, except that for +\fBncmpi_put_att_text(\|)\fR it will usually be +\fBstrlen(\fIout\fP)\fR. +.sp +For these functions, the type component of the function name refers to +the in-memory type of the value, whereas the \fIxtype\fP argument refers to the +external type for storing the value. An \fBNC_ERANGE\fR +error results if +a conversion between these types is not possible. In this case the value +is represented with the appropriate fill-value for the associated +external type. +.HP +\fBint ncmpi_inq_attname(int \fIncid\fP, int \fIvarid\fP, int \fIattnum\fP, char \fIname\fP[])\fR +.sp +(Corresponds to \fBncattname(\|)\fR in version 2) +.sp +Gets the +name of an attribute, given its variable ID and attribute number. +This function is useful in generic applications that +need to get the names of all the attributes associated with a variable, +since attributes are accessed by name rather than number in all other +attribute functions. The number of an attribute is more volatile than +the name, since it can change when other attributes of the same variable +are deleted. The attributes for each variable are numbered +from 0 (the first attribute) to +\fInvatts\fP-1, +where \fInvatts\fP is +the number of attributes for the variable, as returned from a call to +\fBncmpi_inq_varnatts(\|)\fR. +If the \fIname\fP parameter is a \fBNULL\fR pointer, no name will be +returned and no space need be allocated. +.HP +\fBint ncmpi_inq_att(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type* \fIxtype\fP, size_t* \fIlen\fP)\fR +.HP +\fBint ncmpi_inq_attid(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], int* \fIattnum\fP)\fR +.HP +\fBint ncmpi_inq_atttype(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], nc_type* \fIxtype\fP)\fR +.HP +\fBint ncmpi_inq_attlen(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], size_t* \fIlen\fP)\fR +.sp +(Corresponds to \fBncattinq(\|)\fR in version 2) +.sp +These functions return information about a netCDF attribute, +given its variable ID and name. The information returned is the +external type in \fIxtype\fP +and the number of elements in the attribute as \fIlen\fP. +If any of the return arguments is a \fBNULL\fR pointer, +the specified information will not be returned. +.HP +\fBint ncmpi_copy_att(int \fIncid\fP, int \fIvarid_in\fP, const char \fIname\fP[], int \fIncid_out\fP, int \fIvarid_out\fP)\fR +.sp +(Corresponds to \fBncattcopy(\|)\fR in version 2) +.sp +Copies an +attribute from one netCDF dataset to another. It can also be used to +copy an attribute from one variable to another within the same netCDF. +\fIncid_in\fP is the netCDF ID of an input netCDF dataset from which the +attribute will be copied. +\fIvarid_in\fP +is the ID of the variable in the input netCDF dataset from which the +attribute will be copied, or \fBNC_GLOBAL\fR +for a global attribute. +\fIname\fP +is the name of the attribute in the input netCDF dataset to be copied. +\fIncid_out\fP +is the netCDF ID of the output netCDF dataset to which the attribute will be +copied. +It is permissible for the input and output netCDF ID's to be the same. The +output netCDF dataset should be in define mode if the attribute to be +copied does not already exist for the target variable, or if it would +cause an existing target attribute to grow. +\fIvarid_out\fP +is the ID of the variable in the output netCDF dataset to which the attribute will +be copied, or \fBNC_GLOBAL\fR to copy to a global attribute. +.HP +\fBint ncmpi_rename_att(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], const char \fInewname\fP[])\fR +.sp +(Corresponds to \fBncattrename(\|)\fR +.sp +Changes the +name of an attribute. If the new name is longer than the original name, +the netCDF must be in define mode. You cannot rename an attribute to +have the same name as another attribute of the same variable. +\fIname\fP is the original attribute name. +\fInewname\fP +is the new name to be assigned to the specified attribute. If the new name +is longer than the old name, the netCDF dataset must be in define mode. +.HP +\fBint ncmpi_del_att(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[])\fR +.sp +(Corresponds to \fBncattdel(\|)\fR in version 2) +.sp +Deletes an attribute from a netCDF dataset. The dataset must be in +define mode. +.HP +\fBint ncmpi_get_att_text(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_uchar(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], unsigned char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_schar(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], signed char \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_short(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], short \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_int(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], int \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_long(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], long \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_float(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], float \fIin\fP[])\fR +.HP +\fBint ncmpi_get_att_double(int \fIncid\fP, int \fIvarid\fP, const char \fIname\fP[], double \fIin\fP[])\fR +.sp +(Replace \fBncattget(\|)\fR in version 2) +.sp +Gets the value(s) of a netCDF attribute, given its +variable ID and name. Converts from the external type to the type +specified in +the function name, if possible, otherwise returns an \fBNC_ERANGE\fR +error. +All elements of the vector of attribute +values are returned, so you must allocate enough space to hold +them. If you don't know how much space to reserve, call +\fBncmpi_inq_attlen(\|)\fR +first to find out the length of the attribute. +.SH "COMMON ARGUMENT DESCRIPTIONS" +.LP +In this section we define some common arguments which are used in the +"FUNCTION DESCRIPTIONS" section. +.TP +int \fIncid\fP +is the netCDF ID returned from a previous, successful call to +\fBncmpi_open(\|)\fR or \fBncmpi_create(\|)\fR +.TP +char \fIname\fP[] +is the name of a dimension, variable, or attribute. +It shall begin with an alphabetic character, followed by +zero or more alphanumeric characters including the underscore +(`_') or hyphen (`-'). Case is significant. +As an input argument, +it shall be a pointer to a 0-terminated string; as an output argument, it +shall be the address of a buffer in which to hold such a string. +The maximum allowable number of characters +(excluding the terminating 0) is \fBNC_MAX_NAME\fR. +Names that begin with an underscore (`_') are reserved for use +by the netCDF interface. +.TP +nc_type \fIxtype\fP +specifies the external data type of a netCDF variable or attribute and +is one of the following: +\fBNC_BYTE\fR, \fBNC_CHAR\fR, \fBNC_SHORT\fR, \fBNC_INT\fR, +\fBNC_FLOAT\fR, or \fBNC_DOUBLE\fR. +These are used to specify 8-bit integers, +characters, 16-bit integers, 32-bit integers, 32-bit IEEE floating point +numbers, and 64-bit IEEE floating-point numbers, respectively. +(\fBNC_INT\fR corresponds to \fBNC_LONG\fR in version 2, to specify a +32-bit integer). +.TP +int \fIdimids\fP[] +is a vector of dimension ID's and defines the shape of a netCDF variable. +The size of the vector shall be greater than or equal to the +rank (i.e. the number of dimensions) of the variable (\fIndims\fP). +The vector shall be ordered by the speed with which a dimension varies: +\fIdimids\fP[\fIndims\fP-1] +shall be the dimension ID of the most rapidly +varying dimension and +\fIdimids\fP[0] +shall be the dimension ID of the most slowly +varying dimension. +The maximum possible number of +dimensions for a variable is given by the symbolic constant +\fBNC_MAX_VAR_DIMS\fR. +.TP +int \fIdimid\fP +is the ID of a netCDF dimension. +netCDF dimension ID's are allocated sequentially from the +non-negative +integers beginning with 0. +.TP +int \fIndims\fP +is either the total number of dimensions in a netCDF dataset or the rank +(i.e. the number of dimensions) of a netCDF variable. +The value shall not be negative or greater than the symbolic constant +\fBNC_MAX_VAR_DIMS\fR. +.TP +int \fIvarid\fP +is the ID of a netCDF variable or (for the attribute-access functions) +the symbolic constant +\fBNC_GLOBAL\fR, +which is used to reference global attributes. +netCDF variable ID's are allocated sequentially from the +non-negative +integers beginning with 0. +.TP +int* \fInatts\fP +is the number of global attributes in a netCDF dataset for the +\fBncmpi_inquire(\|)\fR +function or the number +of attributes associated with a netCDF variable for the +\fBncmpi_varinq(\|)\fR +function. +.TP +const size_t \fIindex\fP[] +specifies the indicial coordinates of the netCDF data value to be accessed. +The indices start at 0; +thus, for example, the first data value of a +two-dimensional variable is (0,0). +The size of the vector shall be at least the rank of the associated +netCDF variable and its elements shall correspond, in order, to the +variable's dimensions. +.TP +const size_t \fIstart\fP[] +specifies the starting point +for accessing a netCDF variable's data values +in terms of the indicial coordinates of +the corner of the array section. +The indices start at 0; +thus, the first data +value of a variable is (0, 0, ..., 0). +The size of the vector shall be at least the rank of the associated +netCDF variable and its elements shall correspond, in order, to the +variable's dimensions. +.TP +const size_t \fIcount\fP[] +specifies the number of indices selected along each dimension of the +array section. +Thus, to access a single value, for example, specify \fIcount\fP as +(1, 1, ..., 1). +Note that, for strided I/O, this argument must be adjusted +to be compatible with the \fIstride\fP and \fIstart\fP arguments so that +the interaction of the +three does not attempt to access an invalid data co-ordinate. +The elements of the +\fIcount\fP vector correspond, in order, to the variable's dimensions. +.TP +const size_t \fIstride\fP[] +specifies the sampling interval along each dimension of the netCDF +variable. The elements of the stride vector correspond, in order, +to the netCDF variable's dimensions (\fIstride\fP[0]) +gives the sampling interval along the most slowly +varying dimension of the netCDF variable). Sampling intervals are +specified in type-independent units of elements (a value of 1 selects +consecutive elements of the netCDF variable along the corresponding +dimension, a value of 2 selects every other element, etc.). +A \fBNULL\fR stride argument is treated as (1, 1, ... , 1). +.TP +\fIimap\fP +specifies the mapping between the dimensions of a netCDF variable and +the in-memory structure of the internal data array. The elements of +the index mapping vector correspond, in order, to the netCDF variable's +dimensions (\fIimap\fP[0] gives the distance +between elements of the internal array corresponding to the most +slowly varying dimension of the netCDF variable). +Distances between elements are specified in type-independent units of +elements (the distance between internal elements that occupy adjacent +memory locations is 1 and not the element's byte-length as in netCDF 2). +A \fBNULL\fR pointer means the memory-resident values have +the same structure as the associated netCDF variable. +.SH "VARIABLE PREFILLING" +.LP +By default, the netCDF interface sets the values of +all newly-defined variables of finite length (i.e. those that do not have +an unlimited, dimension) to the type-dependent fill-value associated with each +variable. This is done when \fBncmpi_enddef(\|)\fR +is called. The +fill-value for a variable may be changed from the default value by +defining the attribute `\fB_FillValue\fR' for the variable. This +attribute must have the same type as the variable and be of length one. +.LP +Variables with an unlimited dimension are also prefilled, but on +an `as needed' basis. For example, if the first write of such a +variable is to position 5, then +positions +0 through 4 +(and no others) +would be set to the fill-value at the same time. +.LP +This default prefilling of data values may be disabled by +or'ing the +\fBNC_NOFILL\fR +flag into the mode parameter of \fBncmpi_open(\|)\fR or \fBncmpi_create(\|)\fR, +or, by calling the function \fBncmpi_set_fill(\|)\fR +with the argument \fBNC_NOFILL\fR. +For variables that do not use the unlimited dimension, +this call must +be made before +\fBncmpi_enddef(\|)\fR. +For variables that +use the unlimited dimension, this call +may be made at any time. +.LP +One can obtain increased performance of the netCDF interface by using +this feature, but only at the expense of requiring the application to set +every single data value. The performance +enhancing behavior of this function is dependent on the particulars of +the implementation and dataset format. +The flag value controlled by \fBncmpi_set_fill(\|)\fR +is per netCDF ID, +not per variable or per write. +Allowing this to change affects the degree to which +a program can be effectively parallelized. +Given all of this, we state that the use +of this feature may not be available (or even needed) in future +releases. Programmers are cautioned against heavy reliance upon this +feature. +.HP +\fBint ncmpi_setfill(int \fIncid\fP, int \fIfillmode\fP, int* \fIold_fillemode\fP)\fR +.sp +(Corresponds to \fBncsetfill(\|)\fR in version 2) +.sp +Determines whether or not variable prefilling will be done (see +above). +The netCDF dataset shall be writable. +\fIfillmode\fP is either \fBNC_FILL\fR +to enable prefilling (the +default) or \fBNC_NOFILL\fR +to disable prefilling. +This function returns the previous setting in \fIold_fillmode\fP. +.SH "MPP FUNCTION DESCRIPTIONS" +.LP +Additional functions for use on SGI/Cray MPP machines (_CRAYMPP). +These are used to set and inquire which PE is the base for MPP +for a particular netCDF. These are only relevant when +using the SGI/Cray ``global'' +Flexible File I/O layer and desire to have +only a subset of PEs to open the specific netCDF file. +For technical reasons, these functions are available on all platforms. +On a platform other than SGI/Cray MPP, it is as if +only processor available were processor 0. +.LP +To use this feature, you need to specify a communicator group and call +\fBglio_group_mpi(\|)\fR or \fBglio_group_shmem(\|)\fR prior to the netCDF +\fBncmpi_open(\|)\fR and \fBncmpi_create(\|)\fR calls. +.HP +\fBint ncmpi__create_mp(const char \fIpath\fP[], int \fIcmode\fP, size_t \fIinitialsize\fP, int \fIpe\fP, size_t* \fIchunksize\fP, int* \fIncid\fP)\fR +.sp +Like \fBncmpi__create(\|)\fR but allows the base PE to be set. +.sp +The argument \fIpe\fP sets the base PE at creation time. In the MPP +environment, \fBncmpi__create(\|)\fR and \fBncmpi_create(\|)\fR set the base PE to processor +zero by default. +.HP +\fBint ncmpi__open_mp(const char \fIpath\fP[], int \fImode\fP, int \fIpe\fP, size_t* \fIchunksize\fP, int* \fIncid\fP)\fR +.sp +Like \fBncmpi__open(\|)\fR but allows the base PE to be set. +The argument \fIpe\fP sets the base PE at creation time. In the MPP +environment, \fBncmpi__open(\|)\fR and \fBncmpi_open(\|)\fR set the base PE to processor +zero by default. +.HP +\fBint ncmpi_inq_base_pe(int \fIncid\fP, int* \fIpe\fP)\fR +.sp +Inquires of the netCDF dataset which PE is being used as the base for MPP use. +This is safe to use at any time. +.HP +\fBint ncmpi_set_base_pe(int \fIncid\fP, int \fIpe\fP)\fR +.sp +Resets the base PE for the netCDF dataset. +Only perform this operation when the affected communicator group +synchronizes before and after the call. +This operation is very risky and should only be contemplated +under only the most extreme cases. +.SH "ENVIRONMENT VARIABLES" +.TP 4 +.B NETCDF_FFIOSPEC +Specifies the Flexible File I/O buffers for netCDF I/O when executing +under the UNICOS operating system (the variable is ignored on other +operating systems). +An appropriate specification can greatly increase the efficiency of +netCDF I/O -- to the extent that it can actually surpass FORTRAN binary +I/O. +This environment variable has been made a little more generalized, +such that other FFIO option specifications can now be added. +The default specification is \fBbufa:336:2\fP, +unless a current FFIO specification is in operation, +which will be honored. +See UNICOS Flexible File I/O for more information. +.SH "MAILING-LISTS" +.LP +Both a mailing list and a digest are available for +discussion of the netCDF interface and announcements about netCDF bugs, +fixes, and enhancements. +To begin or change your subscription to either the mailing-list or the +digest, send one of the following in the body (not +the subject line) of an email message to "majordomo@unidata.ucar.edu". +Use your email address in place of \fIjdoe@host.inst.domain\fP. +.sp +To subscribe to the netCDF mailing list: +.RS +\fBsubscribe netcdfgroup \fIjdoe@host.inst.domain\fR +.RE +To unsubscribe from the netCDF mailing list: +.RS +\fBunsubscribe netcdfgroup \fIjdoe@host.inst.domain\fR +.RE +To subscribe to the netCDF digest: +.RS +\fBsubscribe netcdfdigest \fIjdoe@host.inst.domain\fR +.RE +To unsubscribe from the netCDF digest: +.RS +\fBunsubscribe netcdfdigest \fIjdoe@host.inst.domain\fR +.RE +To retrieve the general introductory information for the mailing list: +.RS +\fBinfo netcdfgroup\fR +.RE +To get a synopsis of other majordomo commands: +.RS +\fBhelp\fR +.RE +.SH "SEE ALSO" +.LP +.BR ncdump (1), +.BR ncgen (1), +.BR netcdf (3). +.LP +\fInetCDF User's Guide\fP, published +by the Unidata Program Center, University Corporation for Atmospheric +Research, located in Boulder, Colorado. Index: /branches/SDM_SciDAC/src/lib/v1hpg.c =================================================================== --- /branches/SDM_SciDAC/src/lib/v1hpg.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/v1hpg.c (revision 2) @@ -0,0 +1,1322 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include "rnd.h" +#include "ncx.h" + +/* + * This module defines the external representation + * of the "header" of a netcdf version one file. + * For each of the components of the NC structure, + * There are (static) ncx_len_XXX(), ncx_put_XXX() + * and v1h_get_XXX() functions. These define the + * external representation of the components. + * The exported entry points for the whole NC structure + * are built up from these. + */ + + +/* + * "magic number" at beginning of file: 0x43444601 (big endian) + * assert(sizeof(ncmagic) % X_ALIGN == 0); + */ +static const schar ncmagic[] = {'C', 'D', 'F', 0x01}; + + +/* + * v1hs == "Version 1 Header Stream" + * + * The netcdf file version 1 header is + * of unknown and potentially unlimited size. + * So, we don't know how much to get() on + * the initial read. We build a stream, 'v1hs' + * on top of ncio to do the header get. + */ +typedef struct v1hs { + ncio *nciop; + off_t offset; /* argument to nciop->get() */ + size_t extent; /* argument to nciop->get() */ + int flags; /* set to RGN_WRITE for write */ + void *base; /* beginning of current buffer */ + void *pos; /* current position in buffer */ + void *end; /* end of current buffer = base + extent */ +} v1hs; + + +/* + * Release the stream, invalidate buffer + */ +static int +rel_v1hs(v1hs *gsp) +{ + int status; + if(gsp->offset == OFF_NONE || gsp->base == NULL) + return ENOERR; + status = gsp->nciop->rel(gsp->nciop, gsp->offset, + gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0); + gsp->end = NULL; + gsp->pos = NULL; + gsp->base = NULL; + return status; +} + + +/* + * Release the current chunk and get the next one. + * Also used for initialization when gsp->base == NULL. + */ +static int +fault_v1hs(v1hs *gsp, size_t extent) +{ + int status; + + if(gsp->base != NULL) + { + const size_t incr = (char *)gsp->pos - (char *)gsp->base; + status = rel_v1hs(gsp); + if(status) + return status; + gsp->offset += incr; + } + + if(extent > gsp->extent) + gsp->extent = extent; + + status = gsp->nciop->get(gsp->nciop, + gsp->offset, gsp->extent, + gsp->flags, &gsp->base); + if(status) + return status; + + gsp->pos = gsp->base; + gsp->end = (char *)gsp->base + gsp->extent; + + return ENOERR; +} + + +/* + * Ensure that 'nextread' bytes are available. + */ +static int +check_v1hs(v1hs *gsp, size_t nextread) +{ + +#if 0 /* DEBUG */ +fprintf(stderr, "nextread %lu, remaining %lu\n", + (unsigned long)nextread, + (unsigned long)((char *)gsp->end - (char *)gsp->pos)); +#endif + + if((char *)gsp->pos + nextread <= (char *)gsp->end) + return ENOERR; + return fault_v1hs(gsp, nextread); +} + +/* End v1hs */ + +static int +v1h_put_size_t(v1hs *psp, const size_t *sp) +{ + int status = check_v1hs(psp, X_SIZEOF_SIZE_T); + if(status != ENOERR) + return status; + return ncx_put_size_t(&psp->pos, sp); +} + + +static int +v1h_get_size_t(v1hs *gsp, size_t *sp) +{ + int status = check_v1hs(gsp, X_SIZEOF_SIZE_T); + if(status != ENOERR) + return status; + return ncx_get_size_t((const void **)(&gsp->pos), sp); +} + + +/* Begin nc_type */ + +#define X_SIZEOF_NC_TYPE X_SIZEOF_INT + +static int +v1h_put_nc_type(v1hs *psp, const nc_type *typep) +{ + const int itype = (int) *typep; + int status = check_v1hs(psp, X_SIZEOF_INT); + if(status != ENOERR) + return status; + status = ncx_put_int_int(psp->pos, &itype); + psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT); + return status; +} + + +static int +v1h_get_nc_type(v1hs *gsp, nc_type *typep) +{ + int type = 0; + int status = check_v1hs(gsp, X_SIZEOF_INT); + if(status != ENOERR) + return status; + status = ncx_get_int_int(gsp->pos, &type); + gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT); + if(status != ENOERR) + return status; + + assert(type == NC_BYTE + || type == NC_CHAR + || type == NC_SHORT + || type == NC_INT + || type == NC_FLOAT + || type == NC_DOUBLE); + + /* else */ + *typep = (nc_type) type; + + return ENOERR; +} + +/* End nc_type */ +/* Begin NCtype (internal tags) */ + +#define X_SIZEOF_NCTYPE X_SIZEOF_INT + +static int +v1h_put_NCtype(v1hs *psp, NCtype type) +{ + const int itype = (int) type; + int status = check_v1hs(psp, X_SIZEOF_INT); + if(status != ENOERR) + return status; + status = ncx_put_int_int(psp->pos, &itype); + psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT); + return status; +} + +static int +v1h_get_NCtype(v1hs *gsp, NCtype *typep) +{ + int type = 0; + int status = check_v1hs(gsp, X_SIZEOF_INT); + if(status != ENOERR) + return status; + status = ncx_get_int_int(gsp->pos, &type); + gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT); + if(status != ENOERR) + return status; + /* else */ + *typep = (NCtype) type; + return ENOERR; +} + +/* End NCtype */ +/* Begin NC_string */ + +/* + * How much space will the xdr'd string take. + * Formerly +NC_xlen_string(cdfstr) + */ +static size_t +ncx_len_NC_string(const NC_string *ncstrp) +{ + size_t sz = X_SIZEOF_SIZE_T; /* nchars */ + + assert(ncstrp != NULL); + + if(ncstrp->nchars != 0) + { +#if 0 + assert(ncstrp->nchars % X_ALIGN == 0); + sz += ncstrp->nchars; +#else + sz += _RNDUP(ncstrp->nchars, X_ALIGN); +#endif + } + return sz; +} + + +static int +v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp) +{ + int status; + +#if 0 + assert(ncstrp->nchars % X_ALIGN == 0); +#endif + + status = v1h_put_size_t(psp, &ncstrp->nchars); + if(status != ENOERR) + return status; + status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN)); + if(status != ENOERR) + return status; + status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp); + if(status != ENOERR) + return status; + + return ENOERR; +} + + +static int +v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp) +{ + int status; + size_t nchars = 0; + NC_string *ncstrp; + + status = v1h_get_size_t(gsp, &nchars); + if(status != ENOERR) + return status; + + ncstrp = new_NC_string(nchars, NULL); + if(ncstrp == NULL) + { + return NC_ENOMEM; + } + + +#if 0 +/* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */ + assert(ncstrp->nchars % X_ALIGN == 0); + status = check_v1hs(gsp, ncstrp->nchars); +#else + + status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN)); +#endif + if(status != ENOERR) + goto unwind_alloc; + + status = ncx_pad_getn_text((const void **)(&gsp->pos), + nchars, ncstrp->cp); + if(status != ENOERR) + goto unwind_alloc; + + *ncstrpp = ncstrp; + + return ENOERR; + +unwind_alloc: + free_NC_string(ncstrp); + return status; + +} + +/* End NC_string */ +/* Begin NC_dim */ + +/* + * How much space will the xdr'd dim take. + * Formerly +NC_xlen_dim(dpp) + */ +static size_t +ncx_len_NC_dim(const NC_dim *dimp) +{ + size_t sz; + + assert(dimp != NULL); + + sz = ncx_len_NC_string(dimp->name); + sz += X_SIZEOF_SIZE_T; + + return(sz); +} + + +static int +v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp) +{ + int status; + + status = v1h_put_NC_string(psp, dimp->name); + if(status != ENOERR) + return status; + + status = v1h_put_size_t(psp, &dimp->size); + if(status != ENOERR) + return status; + + return ENOERR; +} + +static int +v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp) +{ + int status; + NC_string *ncstrp; + NC_dim *dimp; + + status = v1h_get_NC_string(gsp, &ncstrp); + if(status != ENOERR) + return status; + + dimp = new_x_NC_dim(ncstrp); + if(dimp == NULL) + { + status = NC_ENOMEM; + goto unwind_name; + } + + status = v1h_get_size_t(gsp, &dimp->size); + if(status != ENOERR) + { + free_NC_dim(dimp); /* frees name */ + return status; + } + + *dimpp = dimp; + + return ENOERR; + +unwind_name: + free_NC_string(ncstrp); + return status; +} + + +static size_t +ncx_len_NC_dimarray(const NC_dimarray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_dim **dpp = (const NC_dim **)ncap->value; + const NC_dim *const *const end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) + { + xlen += ncx_len_NC_dim(*dpp); + } + } + return xlen; +} + + +static int +v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap) +{ + int status; + + assert(psp != NULL); + + if(ncap == NULL +#if 1 + /* Backward: + * This clause is for 'byte for byte' + * backward compatibility. + * Strickly speaking, it is 'bug for bug'. + */ + || ncap->nelems == 0 +#endif + ) + { + /* + * Handle empty netcdf + */ + const size_t nosz = 0; + + status = v1h_put_NCtype(psp, NC_UNSPECIFIED); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &nosz); + if(status != ENOERR) + return status; + return ENOERR; + } + /* else */ + + status = v1h_put_NCtype(psp, NC_DIMENSION); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &ncap->nelems); + if(status != ENOERR) + return status; + + { + const NC_dim **dpp = (const NC_dim **)ncap->value; + const NC_dim *const *const end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) + { + status = v1h_put_NC_dim(psp, *dpp); + if(status) + return status; + } + } + return ENOERR; +} + + +static int +v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap) +{ + int status; + NCtype type = NC_UNSPECIFIED; + + assert(gsp != NULL && gsp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = v1h_get_NCtype(gsp, &type); + if(status != ENOERR) + return status; + + status = v1h_get_size_t(gsp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) + return ENOERR; + /* else */ + if(type != NC_DIMENSION) + return EINVAL; + + ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + { + NC_dim **dpp = ncap->value; + NC_dim *const *const end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) + { + status = v1h_get_NC_dim(gsp, dpp); + if(status) + { + ncap->nelems = dpp - ncap->value; + free_NC_dimarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + + +/* End NC_dim */ +/* Begin NC_attr */ + + +/* + * How much space will 'attrp' take in external representation? + * Formerly +NC_xlen_attr(app) + */ +static size_t +ncx_len_NC_attr(const NC_attr *attrp) +{ + size_t sz; + + assert(attrp != NULL); + + sz = ncx_len_NC_string(attrp->name); + sz += X_SIZEOF_NC_TYPE; /* type */ + sz += X_SIZEOF_SIZE_T; /* nelems */ + sz += attrp->xsz; + + return(sz); +} + + +#undef MIN +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +/* + * Put the values of an attribute + * The loop is necessary since attrp->nelems + * could potentially be quite large. + */ +static int +v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp) +{ + int status; + const size_t perchunk = psp->extent; + size_t remaining = attrp->xsz; + void *value = attrp->xvalue; + size_t nbytes; + + assert(psp->extent % X_ALIGN == 0); + + do { + nbytes = MIN(perchunk, remaining); + + status = check_v1hs(psp, nbytes); + if(status != ENOERR) + return status; + + (void) memcpy(psp->pos, value, nbytes); + + psp->pos = (void *)((char *)psp->pos + nbytes); + value = (void *)((char *)value + nbytes); + remaining -= nbytes; + + } while(remaining != 0); + + return ENOERR; +} + +static int +v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp) +{ + int status; + + status = v1h_put_NC_string(psp, attrp->name); + if(status != ENOERR) + return status; + + status = v1h_put_nc_type(psp, &attrp->type); + if(status != ENOERR) + return status; + + status = v1h_put_size_t(psp, &attrp->nelems); + if(status != ENOERR) + return status; + + status = v1h_put_NC_attrV(psp, attrp); + if(status != ENOERR) + return status; + + return ENOERR; +} + + +/* + * Get the values of an attribute + * The loop is necessary since attrp->nelems + * could potentially be quite large. + */ +static int +v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp) +{ + int status; + const size_t perchunk = gsp->extent; + size_t remaining = attrp->xsz; + void *value = attrp->xvalue; + size_t nget; + + assert(gsp->extent % X_ALIGN == 0); + + do { + nget = MIN(perchunk, remaining); + + status = check_v1hs(gsp, nget); + if(status != ENOERR) + return status; + + (void) memcpy(value, gsp->pos, nget); + + gsp->pos = (void *)((char *)gsp->pos + nget); + value = (void *)((char *)value + nget); + remaining -= nget; + + } while(remaining != 0); + + return ENOERR; +} + + +static int +v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp) +{ + NC_string *strp; + int status; + nc_type type; + size_t nelems; + NC_attr *attrp; + + status = v1h_get_NC_string(gsp, &strp); + if(status != ENOERR) + return status; + + status = v1h_get_nc_type(gsp, &type); + if(status != ENOERR) + goto unwind_name; + + status = v1h_get_size_t(gsp, &nelems); + if(status != ENOERR) + goto unwind_name; + + attrp = new_x_NC_attr(strp, type, nelems); + if(attrp == NULL) + { + status = NC_ENOMEM; + goto unwind_name; + } + + status = v1h_get_NC_attrV(gsp, attrp); + if(status != ENOERR) + { + free_NC_attr(attrp); /* frees strp */ + return status; + } + + *attrpp = attrp; + + return ENOERR; + +unwind_name: + free_NC_string(strp); + return status; +} + + +static size_t +ncx_len_NC_attrarray(const NC_attrarray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_attr **app = (const NC_attr **)ncap->value; + const NC_attr *const *const end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) + { + xlen += ncx_len_NC_attr(*app); + } + } + return xlen; +} + + +static int +v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap) +{ + int status; + + assert(psp != NULL); + + if(ncap == NULL +#if 1 + /* Backward: + * This clause is for 'byte for byte' + * backward compatibility. + * Strickly speaking, it is 'bug for bug'. + */ + || ncap->nelems == 0 +#endif + ) + { + /* + * Handle empty netcdf + */ + const size_t nosz = 0; + + status = v1h_put_NCtype(psp, NC_UNSPECIFIED); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &nosz); + if(status != ENOERR) + return status; + return ENOERR; + } + /* else */ + + status = v1h_put_NCtype(psp, NC_ATTRIBUTE); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &ncap->nelems); + if(status != ENOERR) + return status; + + { + const NC_attr **app = (const NC_attr **)ncap->value; + const NC_attr *const *const end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) + { + status = v1h_put_NC_attr(psp, *app); + if(status) + return status; + } + } + return ENOERR; +} + + +static int +v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap) +{ + int status; + NCtype type = NC_UNSPECIFIED; + + assert(gsp != NULL && gsp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = v1h_get_NCtype(gsp, &type); + if(status != ENOERR) + return status; + status = v1h_get_size_t(gsp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) + return ENOERR; + /* else */ + if(type != NC_ATTRIBUTE) + return EINVAL; + + ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + { + NC_attr **app = ncap->value; + NC_attr *const *const end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) + { + status = v1h_get_NC_attr(gsp, app); + if(status) + { + ncap->nelems = app - ncap->value; + free_NC_attrarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +/* End NC_attr */ +/* Begin NC_var */ + +/* + * How much space will the xdr'd var take. + * Formerly +NC_xlen_var(vpp) + */ +static size_t +ncx_len_NC_var(const NC_var *varp) +{ + size_t sz; + + assert(varp != NULL); + + sz = ncx_len_NC_string(varp->name); + sz += X_SIZEOF_SIZE_T; /* ndims */ + sz += ncx_len_int(varp->ndims); /* dimids */ + sz += ncx_len_NC_attrarray(&varp->attrs); + sz += X_SIZEOF_NC_TYPE; /* type */ + sz += X_SIZEOF_SIZE_T; /* len */ + sz += X_SIZEOF_OFF_T; /* begin */ + + return(sz); +} + + +static int +v1h_put_NC_var(v1hs *psp, const NC_var *varp) +{ + int status; + + status = v1h_put_NC_string(psp, varp->name); + if(status != ENOERR) + return status; + + status = v1h_put_size_t(psp, &varp->ndims); + if(status != ENOERR) + return status; + + status = check_v1hs(psp, ncx_len_int(varp->ndims)); + if(status != ENOERR) + return status; + status = ncx_putn_int_int(&psp->pos, + varp->ndims, varp->dimids); + if(status != ENOERR) + return status; + + status = v1h_put_NC_attrarray(psp, &varp->attrs); + if(status != ENOERR) + return status; + + status = v1h_put_nc_type(psp, &varp->type); + if(status != ENOERR) + return status; + + status = v1h_put_size_t(psp, &varp->len); + if(status != ENOERR) + return status; + + status = check_v1hs(psp, X_SIZEOF_OFF_T); + if(status != ENOERR) + return status; + status = ncx_put_off_t(&psp->pos, &varp->begin); + if(status != ENOERR) + return status; + + return ENOERR; +} + + +static int +v1h_get_NC_var(v1hs *gsp, NC_var **varpp) +{ + NC_string *strp; + int status; + size_t ndims; + NC_var *varp; + + status = v1h_get_NC_string(gsp, &strp); + if(status != ENOERR) + return status; + + status = v1h_get_size_t(gsp, &ndims); + if(status != ENOERR) + goto unwind_name; + + varp = new_x_NC_var(strp, ndims); + if(varp == NULL) + { + status = NC_ENOMEM; + goto unwind_name; + } + + status = check_v1hs(gsp, ncx_len_int(ndims)); + if(status != ENOERR) + goto unwind_alloc; + status = ncx_getn_int_int((const void **)(&gsp->pos), + ndims, varp->dimids); + if(status != ENOERR) + goto unwind_alloc; + + status = v1h_get_NC_attrarray(gsp, &varp->attrs); + if(status != ENOERR) + goto unwind_alloc; + + status = v1h_get_nc_type(gsp, &varp->type); + if(status != ENOERR) + goto unwind_alloc; + + status = v1h_get_size_t(gsp, &varp->len); + if(status != ENOERR) + goto unwind_alloc; + + status = check_v1hs(gsp, X_SIZEOF_OFF_T); + if(status != ENOERR) + goto unwind_alloc; + status = ncx_get_off_t((const void **)&gsp->pos, + &varp->begin); + if(status != ENOERR) + goto unwind_alloc; + + *varpp = varp; + return ENOERR; + +unwind_alloc: + free_NC_var(varp); /* frees name */ + return status; + +unwind_name: + free_NC_string(strp); + return status; +} + + +static size_t +ncx_len_NC_vararray(const NC_vararray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_var **vpp = (const NC_var **)ncap->value; + const NC_var *const *const end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) + { + xlen += ncx_len_NC_var(*vpp); + } + } + return xlen; +} + + +static int +v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap) +{ + int status; + + assert(psp != NULL); + + if(ncap == NULL +#if 1 + /* Backward: + * This clause is for 'byte for byte' + * backward compatibility. + * Strickly speaking, it is 'bug for bug'. + */ + || ncap->nelems == 0 +#endif + ) + { + /* + * Handle empty netcdf + */ + const size_t nosz = 0; + + status = v1h_put_NCtype(psp, NC_UNSPECIFIED); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &nosz); + if(status != ENOERR) + return status; + return ENOERR; + } + /* else */ + + status = v1h_put_NCtype(psp, NC_VARIABLE); + if(status != ENOERR) + return status; + status = v1h_put_size_t(psp, &ncap->nelems); + if(status != ENOERR) + return status; + + { + const NC_var **vpp = (const NC_var **)ncap->value; + const NC_var *const *const end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) + { + status = v1h_put_NC_var(psp, *vpp); + if(status) + return status; + } + } + return ENOERR; +} + + +static int +v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap) +{ + int status; + NCtype type = NC_UNSPECIFIED; + + assert(gsp != NULL && gsp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = v1h_get_NCtype(gsp, &type); + if(status != ENOERR) + return status; + + status = v1h_get_size_t(gsp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) + return ENOERR; + /* else */ + if(type != NC_VARIABLE) + return EINVAL; + + ncap->value = (NC_var **) malloc(ncap->nelems * sizeof(NC_var *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + { + NC_var **vpp = ncap->value; + NC_var *const *const end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) + { + status = v1h_get_NC_var(gsp, vpp); + if(status) + { + ncap->nelems = vpp - ncap->value; + free_NC_vararrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + + +/* End NC_var */ +/* Begin NC */ + + +/* + * Recompute the shapes of all variables + * Sets ncp->begin_var to start of first variable. + * Sets ncp->begin_rec to start of first record variable. + * Returns -1 on error. The only possible error is an reference + * to a non existent dimension, which would occur for a corrupt + * netcdf file. + */ +static int +NC_computeshapes(NC *ncp) +{ + NC_var **vpp = (NC_var **)ncp->vars.value; + NC_var *const *const end = &vpp[ncp->vars.nelems]; + NC_var *first_var = NULL; /* first "non-record" var */ + NC_var *first_rec = NULL; /* first "record" var */ + int status; + + ncp->begin_var = (off_t) ncp->xsz; + ncp->begin_rec = (off_t) ncp->xsz; + ncp->recsize = 0; + + if(ncp->vars.nelems == 0) + return(0); + + for( /*NADA*/; vpp < end; vpp++) + { + status = NC_var_shape(*vpp, &ncp->dims); + if(status != ENOERR) + return(status); + + if(IS_RECVAR(*vpp)) + { + if(first_rec == NULL) + first_rec = *vpp; + ncp->recsize += (*vpp)->len; + } + else if(first_var == NULL) + { + first_var = *vpp; + /* + * Overwritten each time thru. + * Usually overwritten in first_rec != NULL clause. + */ + ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len; + } + } + + if(first_rec != NULL) + { + assert(ncp->begin_rec <= first_rec->begin); + ncp->begin_rec = first_rec->begin; + /* + * for special case of exactly one record variable, pack value + */ + if(ncp->recsize == first_rec->len) + ncp->recsize = *first_rec->dsizes * first_rec->xsz; + } + + if(first_var != NULL) + { + ncp->begin_var = first_var->begin; + } + else + { + ncp->begin_var = ncp->begin_rec; + } + + assert(ncp->begin_var > 0); + assert(ncp->xsz <= (size_t)ncp->begin_var); + assert(ncp->begin_rec > 0); + assert(ncp->begin_var <= ncp->begin_rec); + + return(ENOERR); +} + + +size_t +ncx_len_NC(const NC *ncp) +{ + size_t xlen = sizeof(ncmagic); + + assert(ncp != NULL); + + xlen += X_SIZEOF_SIZE_T; /* numrecs */ + xlen += ncx_len_NC_dimarray(&ncp->dims); + xlen += ncx_len_NC_attrarray(&ncp->attrs); + xlen += ncx_len_NC_vararray(&ncp->vars); + + return xlen; +} + + +int +ncx_put_NC(const NC *ncp, void **xpp, off_t offset, size_t extent) +{ + int status = ENOERR; + v1hs ps; /* the get stream */ + + assert(ncp != NULL); + + /* Initialize stream ps */ + + ps.nciop = ncp->nciop; + ps.flags = RGN_WRITE; + + if(xpp == NULL) + { + /* + * Come up with a reasonable stream read size. + */ + extent = ncp->xsz; + if(extent <= MIN_NC_XSZ) + { + /* first time read */ + extent = ncp->chunk; + /* Protection for when ncp->chunk is huge; + * no need to read hugely. */ + if(extent > 4096) + extent = 4096; + } + else if(extent > ncp->chunk) + { + extent = ncp->chunk; + } + + ps.offset = 0; + ps.extent = extent; + ps.base = NULL; + ps.pos = ps.base; + + status = fault_v1hs(&ps, extent); + if(status) + return status; + } + else + { + ps.offset = offset; + ps.extent = extent; + ps.base = *xpp; + ps.pos = ps.base; + ps.end = (char *)ps.base + ps.extent; + } + + status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic); + if(status != ENOERR) + goto release; + + { + const size_t nrecs = NC_get_numrecs(ncp); + status = ncx_put_size_t(&ps.pos, &nrecs); + if(status != ENOERR) + goto release; + } + + assert((char *)ps.pos < (char *)ps.end); + + status = v1h_put_NC_dimarray(&ps, &ncp->dims); + if(status != ENOERR) + goto release; + + status = v1h_put_NC_attrarray(&ps, &ncp->attrs); + if(status != ENOERR) + goto release; + + status = v1h_put_NC_vararray(&ps, &ncp->vars); + if(status != ENOERR) + goto release; + +release: + (void) rel_v1hs(&ps); + + return status; +} + + +int +nc_get_NC(NC *ncp) +{ + int status; + v1hs gs; /* the get stream */ + + assert(ncp != NULL); + + /* Initialize stream gs */ + + gs.nciop = ncp->nciop; + gs.offset = 0; /* beginning of file */ + gs.extent = 0; + gs.flags = 0; + gs.base = NULL; + gs.pos = gs.base; + + { + /* + * Come up with a reasonable stream read size. + */ + size_t extent = ncp->xsz; + if(extent <= MIN_NC_XSZ) + { + /* first time read */ + extent = ncp->chunk; + /* Protection for when ncp->chunk is huge; + * no need to read hugely. */ + if(extent > 4096) + extent = 4096; + } + else if(extent > ncp->chunk) + { + extent = ncp->chunk; + } + + status = fault_v1hs(&gs, extent); + if(status) + return status; + } + + /* get the header from the stream gs */ + + { + /* Get & check magic number */ + schar magic[sizeof(ncmagic)]; + (void) memset(magic, 0, sizeof(magic)); + + status = ncx_getn_schar_schar( + (const void **)(&gs.pos), sizeof(magic), magic); + if(status != ENOERR) + goto unwind_get; + + if(memcmp(magic, ncmagic, sizeof(ncmagic)) != 0) + { + status = NC_ENOTNC; + goto unwind_get; + } + } + + { + size_t nrecs = 0; + status = ncx_get_size_t((const void **)(&gs.pos), &nrecs); + if(status != ENOERR) + goto unwind_get; + NC_set_numrecs(ncp, nrecs); + } + + assert((char *)gs.pos < (char *)gs.end); + + status = v1h_get_NC_dimarray(&gs, &ncp->dims); + if(status != ENOERR) + goto unwind_get; + + status = v1h_get_NC_attrarray(&gs, &ncp->attrs); + if(status != ENOERR) + goto unwind_get; + + status = v1h_get_NC_vararray(&gs, &ncp->vars); + if(status != ENOERR) + goto unwind_get; + + ncp->xsz = ncx_len_NC(ncp); + + status = NC_computeshapes(ncp); + +unwind_get: + (void) rel_v1hs(&gs); + return status; +} Index: /branches/SDM_SciDAC/src/lib/validator.c =================================================================== --- /branches/SDM_SciDAC/src/lib/validator.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/validator.c (revision 2) @@ -0,0 +1,722 @@ +/********************************************************************************* + * + * This file is written by Northwestern University and Argonne National Laboratory + * + ********************************************************************************/ +#include +#include +#include +#include +#include +#include +#include "nc.h" +#include "ncx.h" + +#undef MAX /* system may define MAX somewhere and complain */ +#undef MIN /* system may define MIN somewhere and complain */ +#define MAX(mm,nn) (((mm) > (nn)) ? (mm) : (nn)) +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +/* + * "magic number" at beginning of file: 0x43444601 (big endian) + */ +static const schar ncmagic[] = {'C', 'D', 'F', 0x01}; + +typedef struct bufferinfo { + ncio *nciop; + MPI_Offset offset; /* current read/write offset in the file */ + void *base; /* beginning of read/write buffer */ + void *pos; /* current position in buffer */ + size_t size; /* size of the buffer */ +} bufferinfo; + +/* Begin Of get NC */ + +/* + * Fetch the next header chunk. + */ +int +val_fetch(bufferinfo *gbp, size_t fsize) { + int status; + char *buf; + ssize_t nn = 0, bufsize = 0; + + assert(gbp->base != NULL); + + fsize = _RNDUP(fsize, X_ALIGN); + (void) memset(gbp->base, 0, gbp->size); + buf = gbp->pos = gbp->base; + + lseek(gbp->nciop->fd, gbp->offset, SEEK_SET); + while ( (bufsize < gbp->size) && (nn = read(gbp->nciop->fd, buf, gbp->size-bufsize)) > 0 ) { + buf += nn; + bufsize += nn; + } + gbp->offset += bufsize; + + if (bufsize < fsize) { + printf("Error @ [0x%8.8x]: \n\tUnexpected EOF, while ", gbp->offset); + return -1; + } + + gbp->size = bufsize; + + return ENOERR; +} + +/* + * Ensure that 'nextread' bytes are available. + */ +int +val_check_buffer(bufferinfo *gbp, size_t nextread) { + if ((char *)gbp->pos + nextread <= (char *)gbp->base + gbp->size) + return ENOERR; + return val_fetch(gbp, MIN(gbp->size, nextread)); +} + +int +val_get_NCtype(bufferinfo *gbp, NCtype *typep) { + int type = 0; + int status = val_check_buffer(gbp, X_SIZEOF_INT); + if (status != ENOERR) { + printf("NC component type is expected for "); + return status; + } + + status = ncx_get_int_int(gbp->pos, &type); + gbp->pos = (void *)((char *)gbp->pos + X_SIZEOF_INT); + if (status != ENOERR) + return status; + *typep = (NCtype) type; + return ENOERR; +} + +int +val_get_size_t(bufferinfo *gbp, size_t *sp) { + int status = val_check_buffer(gbp, X_SIZEOF_SIZE_T); + if (status != ENOERR) { + printf("size is expected for "); + return status; + } + return ncx_get_size_t((const void **)(&gbp->pos), sp); +} + +int +val_get_NC_string(bufferinfo *gbp, NC_string **ncstrpp) { + int status; + size_t nchars = 0, padding, bufremain, strcount; + NC_string *ncstrp; + char *cpos; + char pad[X_ALIGN-1]; + + status = val_get_size_t(gbp, &nchars); + if (status != ENOERR) { + printf("the name string of "); + return status; + } + + ncstrp = new_NC_string(nchars, NULL); + if (ncstrp == NULL) + return NC_ENOMEM; + + padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN) + - X_SIZEOF_CHAR * ncstrp->nchars; + bufremain = gbp->size - (size_t)((char *)gbp->pos - (char *)gbp->base); + cpos = ncstrp->cp; + + while (nchars > 0) { + if (bufremain > 0) { + strcount = MIN(bufremain, X_SIZEOF_CHAR * nchars); + (void) memcpy(cpos, gbp->pos, strcount); + nchars -= strcount/X_SIZEOF_CHAR; + gbp->pos = (void *)((char *)gbp->pos + strcount); + cpos += strcount; + bufremain -= strcount; + } else { + status = val_fetch(gbp, MIN(gbp->size, X_SIZEOF_CHAR * nchars)); + if(status != ENOERR) { + printf("fetching the name string of "); + free_NC_string(ncstrp); + return status; + } + bufremain = gbp->size; + } + } + + memset(pad, 0, X_ALIGN-1); + status = val_check_buffer(gbp, padding); + if(status != ENOERR) { + printf("fetching padding for the name string of "); + free_NC_string(ncstrp); + return status; + } + if (memcmp(gbp->pos, pad, padding) != 0) { + printf("Error @ [0x%8.8x]: \n\tPadding should be 0x00 for the name string alignment of ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size); + free_NC_string(ncstrp); + return EINVAL; + } + gbp->pos = (void *)((char *)gbp->pos + padding); + + *ncstrpp = ncstrp; + + return ENOERR; +} + +int +val_get_NC_dim(bufferinfo *gbp, NC_dim **dimpp) { + int status; + NC_string *ncstrp; + NC_dim *dimp; + + status = val_get_NC_string(gbp, &ncstrp); + if (status != ENOERR) + return status; + + dimp = new_x_NC_dim(ncstrp); + if(dimp == NULL) + return NC_ENOMEM; + + status = val_get_size_t(gbp, &dimp->size); + if(status != ENOERR) { + printf("\"%s\" - ", ncstrp->cp); + free_NC_dim(dimp); /* frees name */ + return status; + } + + *dimpp = dimp; + + return ENOERR; +} + +int +val_get_NC_dimarray(bufferinfo *gbp, NC_dimarray *ncap) { + int status; + NCtype type = NC_UNSPECIFIED; + NC_dim **dpp, **end; + int dim; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = val_get_NCtype(gbp, &type); + if(status != ENOERR) { + printf("preamble of "); + return status; + } + + status = val_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) { + printf("the length of "); + return status; + } + + if(ncap->nelems == 0) { + if (type != NC_DIMENSION && type != NC_UNSPECIFIED) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_DIMENSION or NC_UNSPECIFIED is expected for "); + return EINVAL; + } + } else { + if(type != NC_DIMENSION) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_DIMENSION is expected since number of dimensions is %d for ", ncap->nelems); + return EINVAL; + } + + ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + dpp = ncap->value; + end = &dpp[ncap->nelems]; + for( /*NADA*/ dim = 0; dpp < end; dpp++, dim++) { + status = val_get_NC_dim(gbp, dpp); + if (status != ENOERR) { + printf("dimension[%d] in ", dim); + ncap->nelems = dpp - ncap->value; + free_NC_dimarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +val_get_nc_type(bufferinfo *gbp, nc_type *typep) { + int type = 0; + int status = val_check_buffer(gbp, X_SIZEOF_INT); + if(status != ENOERR) { + printf("data type is expected for the values of "); + return status; + } + + status = ncx_get_int_int(gbp->pos, &type); + if(status != ENOERR) + return status; + gbp->pos = (void *)((char *)gbp->pos + X_SIZEOF_INT); + + if ( type != NC_BYTE + && type != NC_CHAR + && type != NC_SHORT + && type != NC_INT + && type != NC_FLOAT + && type != NC_DOUBLE) { + printf("Error @ [0x%8.8x]: \n\tUnknown data type for the values of ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - X_SIZEOF_INT); + return EINVAL; + } + + *typep = (nc_type) type; + + return ENOERR; +} + +/* + * Get the values of an attribute + */ +int +val_get_NC_attrV(bufferinfo *gbp, NC_attr *attrp) { + int status; + void *value = attrp->xvalue; + char pad[X_ALIGN-1]; + size_t nvalues = attrp->nelems, esz, padding, bufremain, attcount; + + esz = ncx_len_nctype(attrp->type); + padding = attrp->xsz - esz * nvalues; + bufremain = gbp->size - (size_t)((char *)gbp->pos - (char *)gbp->base); + + while (nvalues > 0) { + if (bufremain > 0) { + attcount = MIN(bufremain, esz * nvalues); + (void) memcpy(value, gbp->pos, attcount); + nvalues -= attcount/esz; + gbp->pos = (void *)((char *)gbp->pos + attcount); + value = (void *)((char *)value + attcount); + bufremain -= attcount; + } else { + status = val_fetch(gbp, MIN(gbp->size, esz * nvalues)); + if(status != ENOERR) { + printf("fetching the values of "); + return status; + } + bufremain = gbp->size; + } + } + + memset(pad, 0, X_ALIGN-1); + if (memcmp(gbp->pos, pad, padding) != 0) { + printf("Error @ [0x%8.8x]: \n\tPadding should be 0x00 for the values alignment of ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size); + return EINVAL; + } + gbp->pos = (void *)((char *)gbp->pos + padding); + + return ENOERR; +} + +int +val_get_NC_attr(bufferinfo *gbp, NC_attr **attrpp) { + NC_string *strp; + int status; + nc_type type; + size_t nelems; + NC_attr *attrp; + + status = val_get_NC_string(gbp, &strp); + if(status != ENOERR) + return status; + + status = val_get_nc_type(gbp, &type); + if(status != ENOERR) { + printf("\"%s\" - ", strp->cp); + free_NC_string(strp); + return status; + } + + status = val_get_size_t(gbp, &nelems); + if(status != ENOERR) { + printf("the values of \"%s\" - ", strp->cp); + free_NC_string(strp); + return status; + } + + attrp = new_x_NC_attr(strp, type, nelems); + if(attrp == NULL) { + free_NC_string(strp); + return status; + } + + status = val_get_NC_attrV(gbp, attrp); + if(status != ENOERR) { + printf("\"%s\" - ", strp->cp); + free_NC_attr(attrp); /* frees strp */ + return status; + } + + *attrpp = attrp; + + return ENOERR; +} + +int +val_get_NC_attrarray(bufferinfo *gbp, NC_attrarray *ncap){ + int status; + NCtype type = NC_UNSPECIFIED; + NC_attr **app, **end; + int att; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = val_get_NCtype(gbp, &type); + if(status != ENOERR) { + printf("preamble of "); + return status; + } + + status = val_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) { + printf("the length of "); + return status; + } + + if(ncap->nelems == 0) { + if (type != NC_ATTRIBUTE && type != NC_UNSPECIFIED) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_ATTRIBUTE or NC_UNSPECIFIED is expected for "); + return EINVAL; + } + } else { + if(type != NC_ATTRIBUTE) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_ATTRIBUTE is expected since number of attributes is %d for ", ncap->nelems); + return EINVAL; + } + + ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + app = ncap->value; + end = &app[ncap->nelems]; + for( /*NADA*/ att = 0; app < end; app++, att++) { + status = val_get_NC_attr(gbp, app); + if (status != ENOERR) { + printf("attribute[%d] of ", att); + ncap->nelems = app - ncap->value; + free_NC_attrarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +val_get_NC_var(bufferinfo *gbp, NC_var **varpp) { + NC_string *strp; + int status; + size_t ndims, dim; + NC_var *varp; + + status = val_get_NC_string(gbp, &strp); + if(status != ENOERR) + return status; + + status = val_get_size_t(gbp, &ndims); + if(status != ENOERR) { + printf("the dimid list of \"%s\" - ", strp->cp); + free_NC_string(strp); + return status; + } + + varp = new_x_NC_var(strp, ndims); + if(varp == NULL) { + free_NC_string(strp); + return NC_ENOMEM; + } + + for (dim = 0; dim < ndims; dim++ ) { + status = val_check_buffer(gbp, X_SIZEOF_INT); + if(status != ENOERR) { + printf("the dimid[%d] is expected for \"%s\" - ", dim, strp->cp); + free_NC_var(varp); + return status; + } + status = ncx_getn_int_int((const void **)(&gbp->pos), + 1, varp->dimids + dim); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + } + + status = val_get_NC_attrarray(gbp, &varp->attrs); + if(status != ENOERR) { + printf("ATTRIBUTE list of \"%s\" - ", strp->cp); + free_NC_var(varp); + return status; + } + + status = val_get_nc_type(gbp, &varp->type); + if(status != ENOERR) { + printf("\"%s\" - ", strp->cp); + free_NC_var(varp); + return status; + } + + status = val_get_size_t(gbp, &varp->len); + if(status != ENOERR) { + printf("the data of \"%s\" - ", strp->cp); + free_NC_var(varp); + return status; + } + + status = val_check_buffer(gbp, X_SIZEOF_OFF_T); + if(status != ENOERR) { + printf("offset is expected for the data of \"%s\" - ", strp->cp); + free_NC_var(varp); + return status; + } + status = ncx_get_off_t((const void **)&gbp->pos, + &varp->begin); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + + *varpp = varp; + return ENOERR; +} + +int +val_get_NC_vararray(bufferinfo *gbp, NC_vararray *ncap) { + int status; + NCtype type = NC_UNSPECIFIED; + NC_var **vpp, **end; + int var; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = val_get_NCtype(gbp, &type); + if(status != ENOERR) { + printf("preamble of "); + return status; + } + + status = val_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) { + printf("the length of "); + return status; + } + + if(ncap->nelems == 0) { + if (type != NC_VARIABLE && type != NC_UNSPECIFIED) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_VARIABLE or NC_UNSPECIFIED is expected for "); + return EINVAL; + } + } else { + if(type != NC_VARIABLE) { + printf("Error @ [0x%8.8x]: \n\tInvalid NC component type, while ", + (size_t)(gbp->pos - gbp->base) + gbp->offset - gbp->size - 2 * X_SIZEOF_SIZE_T); + printf("NC_VARIABLE is expected since number of variables is %d for ", ncap->nelems); + return EINVAL; + } + + ncap->value = (NC_var **) malloc(ncap->nelems * sizeof(NC_var *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + vpp = ncap->value; + end = &vpp[ncap->nelems]; + for( /*NADA*/ var = 0; vpp < end; vpp++, var++) { + status = val_get_NC_var(gbp, vpp); + if (status != ENOERR) { + printf("variable[%d] in ", var); + ncap->nelems = vpp - ncap->value; + free_NC_vararrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +val_get_NC(NC *ncp) { + int status; + bufferinfo getbuf; + schar magic[sizeof(ncmagic)]; + size_t nrecs = 0; + + assert(ncp != NULL); + + /* Initialize the get buffer */ + + getbuf.nciop = ncp->nciop; + getbuf.offset = 0; /* read from start of the file */ + getbuf.size = _RNDUP( MAX(MIN_NC_XSZ, ncp->chunk), X_ALIGN ); + if (getbuf.size > 4096) + getbuf.size = 4096; + getbuf.pos = getbuf.base = (void *)malloc(getbuf.size); + + status = val_fetch(&getbuf, sizeof(magic)); + if(status != ENOERR) { + printf("magic number (C D F \\001) is expected!\n"); + return status; + } + + /* Get the header from get buffer */ + + (void) memset(magic, 0, sizeof(magic)); + status = ncx_getn_schar_schar( + (const void **)(&getbuf.pos), sizeof(magic), magic); + if(memcmp(magic, ncmagic, sizeof(ncmagic)) != 0) { + printf("Error @ [0x%8.8x]: \n\tUnknow magic number, while (C D F \\001) is expected!\n", 0); + free(getbuf.base); + return NC_ENOTNC; + } + + status = val_check_buffer(&getbuf, X_SIZEOF_SIZE_T); + if(status != ENOERR) { + printf("number of records is expected!\n"); + free(getbuf.base); + return status; + } + status = ncx_get_size_t((const void **)(&getbuf.pos), &nrecs); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + ncp->numrecs = nrecs; + + assert((char *)getbuf.pos < (char *)getbuf.base + getbuf.size); + + status = val_get_NC_dimarray(&getbuf, &ncp->dims); + if(status != ENOERR) { + printf("DIMENSION list!\n"); + free(getbuf.base); + return status; + } + + status = val_get_NC_attrarray(&getbuf, &ncp->attrs); + if(status != ENOERR) { + printf("GLOBAL ATTRIBUTE list!\n"); + free(getbuf.base); + return status; + } + + status = val_get_NC_vararray(&getbuf, &ncp->vars); + if(status != ENOERR) { + printf("VARIABLE list!\n"); + free(getbuf.base); + return status; + } + + ncp->xsz = hdr_len_NC(ncp); + status = NC_computeshapes(ncp); + free(getbuf.base); + + return status; +} + +/* End Of get NC */ + +int +main(int argc, char **argv) { + + char *ncfile; + int status; + NC *ncp; + struct stat ncfilestat; + + if (argc < 2) { + printf("Missing ncfile name. Usage:\n\t ncvalid \n"); + exit(1); + } + + if (argc > 2) { + printf("Too many arguments. Usage:\n\t ncvalid \n"); + exit(1); + } + + ncfile = argv[1]; + + /* open the netCDF file */ + + ncp = new_NC(NULL); + if(ncp == NULL) { + printf("Not enough memory!\n"); + return 0; + } + + ncp->nciop = ncio_new(ncfile, NC_NOWRITE); + if(ncp->nciop == NULL) { + free_NC(ncp); + printf("Not enough memory!\n"); + return 0; + } + + if ( (*((int *)&ncp->nciop->fd) = open(ncfile, O_RDONLY)) < 0 ) { + printf("Can not open file: %s\n", ncfile); + ncio_free(ncp->nciop); + free_NC(ncp); + return 0; + } + + /* read to validate the header */ + + status = val_get_NC(ncp); + if (status != 0) { + close(ncp->nciop->fd); + ncio_free(ncp->nciop); + free_NC(ncp); + return 0; + } + + /* check data size */ + + fstat(ncp->nciop->fd, &ncfilestat); + if ( ncp->begin_rec + ncp->recsize * ncp->numrecs < ncfilestat.st_size ) { + printf("Error: \n\tData size is larger than defined!\n"); + close(ncp->nciop->fd); + ncio_free(ncp->nciop); + free_NC(ncp); + return 0; + } else if ( ncp->begin_rec + ncp->recsize * (ncp->numrecs - 1) >= ncfilestat.st_size ) { + printf("Error: \n\tData size is less than expected!\n"); + close(ncp->nciop->fd); + ncio_free(ncp->nciop); + free_NC(ncp); + return 0; + } + + + /* close the file */ + + close(ncp->nciop->fd); + ncio_free(ncp->nciop); + free_NC(ncp); + + printf("The netCDF file is validated!\n"); + + return 0; +} Index: /branches/SDM_SciDAC/src/lib/ncio.c =================================================================== --- /branches/SDM_SciDAC/src/lib/ncio.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncio.c (revision 2) @@ -0,0 +1,9 @@ +/* + * $Id$ + */ + +#if defined(_CRAY) +# include "ffio.c" +#else +# include "posixio.c" +#endif Index: /branches/SDM_SciDAC/src/lib/header.c =================================================================== --- /branches/SDM_SciDAC/src/lib/header.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/header.c (revision 2) @@ -0,0 +1,1066 @@ +/********************************************************************************* + * + * This file is written by Northwestern University and Argonne National Laboratory + * + ********************************************************************************/ + +#include +#include +#include "nc.h" +#include "ncx.h" + +#undef MAX /* system may define MAX somewhere and complain */ +#undef MIN /* system may define MIN somewhere and complain */ +#define MAX(mm,nn) (((mm) > (nn)) ? (mm) : (nn)) +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +/* + * "magic number" at beginning of file: 0x43444601 (big endian) + */ +static const schar ncmagic[] = {'C', 'D', 'F', 0x01}; + +typedef struct bufferinfo { + ncio *nciop; + MPI_Offset offset; /* current read/write offset in the file */ + void *base; /* beginning of read/write buffer */ + void *pos; /* current position in buffer */ + size_t size; /* size of the buffer */ +} bufferinfo; + +/* + * Recompute the shapes of all variables + * Sets ncp->begin_var to start of first variable. + * Sets ncp->begin_rec to start of first record variable. + * Returns -1 on error. The only possible error is an reference + * to a non existent dimension, which would occur for a corrupt + * netcdf file. + */ +int +NC_computeshapes(NC *ncp) +{ + NC_var **vpp = (NC_var **)ncp->vars.value; + NC_var *const *const end = &vpp[ncp->vars.nelems]; + NC_var *first_var = NULL; /* first "non-record" var */ + NC_var *first_rec = NULL; /* first "record" var */ + int status; + + ncp->begin_var = (off_t) ncp->xsz; + ncp->begin_rec = (off_t) ncp->xsz; + ncp->recsize = 0; + + if(ncp->vars.nelems == 0) + return(0); + + for( /*NADA*/; vpp < end; vpp++) + { + status = NC_var_shape(*vpp, &ncp->dims); + if(status != ENOERR) + return(status); + + if(IS_RECVAR(*vpp)) + { + if(first_rec == NULL) + first_rec = *vpp; + ncp->recsize += (*vpp)->len; + } + else if(first_var == NULL) + { + first_var = *vpp; + /* + * Overwritten each time thru. + * Usually overwritten in first_rec != NULL clause. + */ + ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len; + } + } + + if(first_rec != NULL) + { + assert(ncp->begin_rec <= first_rec->begin); + ncp->begin_rec = first_rec->begin; + /* + * for special case of exactly one record variable, pack value + */ + if(ncp->recsize == first_rec->len) + ncp->recsize = *first_rec->dsizes * first_rec->xsz; + } + + if(first_var != NULL) + { + ncp->begin_var = first_var->begin; + } + else + { + ncp->begin_var = ncp->begin_rec; + } + + assert(ncp->begin_var > 0); + assert(ncp->xsz <= (size_t)ncp->begin_var); + assert(ncp->begin_rec > 0); + assert(ncp->begin_var <= ncp->begin_rec); + + return(ENOERR); +} + +/* + * To compute how much space will the xdr'd header take + */ + +#define X_SIZEOF_NC_TYPE X_SIZEOF_INT +#define X_SIZEOF_NCTYPE X_SIZEOF_INT + +size_t +hdr_len_NC_string(const NC_string *ncstrp) +{ + size_t sz = X_SIZEOF_SIZE_T; /* nchars */ + + assert(ncstrp != NULL); + + if(ncstrp->nchars != 0) + sz += _RNDUP(ncstrp->nchars, X_ALIGN); + + return sz; +} + +size_t +hdr_len_NC_dim(const NC_dim *dimp) +{ + size_t sz; + + assert(dimp != NULL); + + sz = hdr_len_NC_string(dimp->name); + sz += X_SIZEOF_SIZE_T; + + return(sz); +} + +size_t +hdr_len_NC_dimarray(const NC_dimarray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_dim **dpp = (const NC_dim **)ncap->value; + const NC_dim *const *const end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) + { + xlen += hdr_len_NC_dim(*dpp); + } + } + return xlen; +} + +size_t +hdr_len_NC_attr(const NC_attr *attrp) +{ + size_t sz; + + assert(attrp != NULL); + + sz = hdr_len_NC_string(attrp->name); + sz += X_SIZEOF_NC_TYPE; /* type */ + sz += X_SIZEOF_SIZE_T; /* nelems */ + sz += attrp->xsz; + + return(sz); +} + +size_t +hdr_len_NC_attrarray(const NC_attrarray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_attr **app = (const NC_attr **)ncap->value; + const NC_attr *const *const end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) + { + xlen += hdr_len_NC_attr(*app); + } + } + return xlen; +} + +size_t +hdr_len_NC_var(const NC_var *varp) +{ + size_t sz; + + assert(varp != NULL); + + sz = hdr_len_NC_string(varp->name); + sz += X_SIZEOF_SIZE_T; /* ndims */ + sz += ncx_len_int(varp->ndims); /* dimids */ + sz += hdr_len_NC_attrarray(&varp->attrs); + sz += X_SIZEOF_NC_TYPE; /* type */ + sz += X_SIZEOF_SIZE_T; /* len */ + sz += X_SIZEOF_OFF_T; /* begin */ + + return(sz); +} + +size_t +hdr_len_NC_vararray(const NC_vararray *ncap) +{ + size_t xlen = X_SIZEOF_NCTYPE; /* type */ + xlen += X_SIZEOF_SIZE_T; /* count */ + if(ncap == NULL) + return xlen; + /* else */ + { + const NC_var **vpp = (const NC_var **)ncap->value; + const NC_var *const *const end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) + { + xlen += hdr_len_NC_var(*vpp); + } + } + return xlen; +} + +size_t +hdr_len_NC(const NC *ncp) +{ + size_t xlen = sizeof(ncmagic); + + assert(ncp != NULL); + + xlen += X_SIZEOF_SIZE_T; /* numrecs */ + xlen += hdr_len_NC_dimarray(&ncp->dims); + xlen += hdr_len_NC_attrarray(&ncp->attrs); + xlen += hdr_len_NC_vararray(&ncp->vars); + + return xlen; +} + +/* Begin Of put NC */ + +int +hdr_put_NCtype(bufferinfo *pbp, NCtype type) { + int status; + const int itype = (int)type; + + status = ncx_put_int_int(pbp->pos, &itype); + if (status != ENOERR) + return status; + pbp->pos = (void *)((char *)pbp->pos + X_SIZEOF_INT); + return status; +} + +int +hdr_put_nc_type(bufferinfo *pbp, const nc_type *typep) { + int status; + const int itype = (int) *typep; + + status = ncx_put_int_int(pbp->pos, &itype); + if (status != ENOERR) + return status; + pbp->pos = (void *)((char *)pbp->pos + X_SIZEOF_INT); + + return status; +} + +int +hdr_put_NC_string(bufferinfo *pbp, const NC_string *ncstrp) { + int status; + + status = ncx_put_size_t(&pbp->pos, &ncstrp->nchars); + if (status != ENOERR) + return status; + + status = ncx_pad_putn_text(&pbp->pos, ncstrp->nchars, ncstrp->cp); + if (status != ENOERR) + return status; + + return ENOERR; +} + +/* + * Put the values of an attribute + */ +int +hdr_put_NC_attrV(bufferinfo *pbp, const NC_attr *attrp) { + int status; + void *value = attrp->xvalue; + + assert(pbp->size % XALIGN == 0); + + (void) memcpy(pbp->pos, value, attrp->xsz); + pbp->pos = (void *)((char *)pbp->pos + attrp->xsz); + + return ENOERR; +} + +int +hdr_put_NC_dim(bufferinfo *pbp, const NC_dim *dimp) { + int status; + + status = hdr_put_NC_string(pbp, dimp->name); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &dimp->size); + if (status != ENOERR) + return status; + + return ENOERR; +} + +int +hdr_put_NC_attr(bufferinfo *pbp, const NC_attr *attrp) { + int status; + + status = hdr_put_NC_string(pbp, attrp->name); + if (status != ENOERR) + return status; + + status = hdr_put_nc_type(pbp, &attrp->type); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &attrp->nelems); + if (status != ENOERR) + return status; + + status = hdr_put_NC_attrV(pbp, attrp); + if (status != ENOERR) + return status; + + return ENOERR; +} + +int +hdr_put_NC_var(bufferinfo *pbp, const NC_var *varp) { + int status; + + status = hdr_put_NC_string(pbp, varp->name); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &varp->ndims); + if (status != ENOERR) + return status; + + status = ncx_putn_int_int(&pbp->pos, + varp->ndims, varp->dimids); + if (status != ENOERR) + return status; + + status = hdr_put_NC_attrarray(pbp, &varp->attrs); + if (status != ENOERR) + return status; + + status = hdr_put_nc_type(pbp, &varp->type); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &varp->len); + if (status != ENOERR) + return status; + + status = ncx_put_off_t(&pbp->pos, &varp->begin); + if (status != ENOERR) + return status; + + return ENOERR; +} + +int +hdr_put_NC_dimarray(bufferinfo *pbp, const NC_dimarray *ncap) { + int status; + + assert(pbp != NULL); + + if (ncap == NULL || ncap->nelems == 0) { + /* ABSENT */ + const size_t nosz = 0; + status = hdr_put_NCtype(pbp, NC_UNSPECIFIED); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &nosz); + if (status != ENOERR) + return status; + } else { + const NC_dim **dpp = (const NC_dim **)ncap->value; + const NC_dim *const *const end = &dpp[ncap->nelems]; + + status = hdr_put_NCtype(pbp, NC_DIMENSION); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &ncap->nelems); + if (status != ENOERR) + return status; + + for ( /*NADA*/; dpp < end; dpp++) { + status = hdr_put_NC_dim(pbp, *dpp); + if (status != ENOERR) + return status; + } + } + + return ENOERR; +} + +int +hdr_put_NC_attrarray(bufferinfo *pbp, const NC_attrarray *ncap) { + int status; + + assert(pbp != NULL); + + if (ncap == NULL || ncap->nelems == 0) { + /* ABSENT */ + const size_t nosz = 0; + status = hdr_put_NCtype(pbp, NC_UNSPECIFIED); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &nosz); + if (status != ENOERR) + return status; + } else { + const NC_attr **app = (const NC_attr **)ncap->value; + const NC_attr *const *const end = &app[ncap->nelems]; + + status = hdr_put_NCtype(pbp, NC_ATTRIBUTE); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &ncap->nelems); + if (status != ENOERR) + return status; + + for ( /*NADA*/; app < end; app++) { + status = hdr_put_NC_attr(pbp, *app); + if (status != ENOERR) + return status; + } + } + + return ENOERR; +} + +int +hdr_put_NC_vararray(bufferinfo *pbp, const NC_vararray *ncap){ + int status; + + assert(pbp != NULL); + + if (ncap == NULL || ncap->nelems == 0) { + /* ABSENT */ + const size_t nosz = 0; + status = hdr_put_NCtype(pbp, NC_UNSPECIFIED); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &nosz); + if (status != ENOERR) + return status; + } else { + const NC_var **vpp = (const NC_var **)ncap->value; + const NC_var *const *const end = &vpp[ncap->nelems]; + + status = hdr_put_NCtype(pbp, NC_VARIABLE); + if (status != ENOERR) + return status; + + status = ncx_put_size_t(&pbp->pos, &ncap->nelems); + if (status != ENOERR) + return status; + + for( /*NADA*/; vpp < end; vpp++) { + status = hdr_put_NC_var(pbp, *vpp); + if (status != ENOERR) + return status; + } + } + + return ENOERR; +} + +int +hdr_put_NC(NC *ncp, void *buf) { + int status; + bufferinfo putbuf; + size_t nrecs; + + putbuf.nciop = NULL; + putbuf.offset = 0; + putbuf.pos = putbuf.base = buf; + putbuf.size = ncp->xsz; + + status = ncx_putn_schar_schar(&putbuf.pos, sizeof(ncmagic), ncmagic); + + nrecs = ncp->numrecs; + status = ncx_put_size_t(&putbuf.pos, &nrecs); + if (status != ENOERR) + return status; + + assert((char *)putbuf.pos < (char *)putbuf.base + putbuf.size); + + status = hdr_put_NC_dimarray(&putbuf, &ncp->dims); + if (status != ENOERR) + return status; + + status = hdr_put_NC_attrarray(&putbuf, &ncp->attrs); + if (status != ENOERR) + return status; + + status = hdr_put_NC_vararray(&putbuf, &ncp->vars); + if (status != ENOERR) + return status; + + return status; +} + +/* End Of put NC */ + +/* Begin Of get NC */ + +/* + * Fetch the next header chunk. + */ +int +hdr_fetch(bufferinfo *gbp) { + int status; + int rank; + MPI_Comm comm; + + assert(gbp->base != NULL); + + comm = gbp->nciop->comm; + MPI_Comm_rank(comm, &rank); + + (void) memset(gbp->base, 0, gbp->size); + gbp->pos = gbp->base; + MPI_File_set_view(gbp->nciop->collective_fh, 0, MPI_BYTE, MPI_BYTE, + "native", gbp->nciop->mpiinfo); + if (rank == 0) { + MPI_Status mpistatus; + MPI_File_read_at(gbp->nciop->collective_fh, gbp->offset, gbp->base, + gbp->size, MPI_BYTE, &mpistatus); + } + gbp->offset += gbp->size; + + MPI_Bcast(gbp->base, gbp->size, MPI_BYTE, 0, comm); + + return ENOERR; +} + +/* + * Ensure that 'nextread' bytes are available. + */ +int +hdr_check_buffer(bufferinfo *gbp, size_t nextread) { + if ((char *)gbp->pos + nextread <= (char *)gbp->base + gbp->size) + return ENOERR; + return hdr_fetch(gbp); +} + +int +hdr_get_NCtype(bufferinfo *gbp, NCtype *typep) { + int type = 0; + int status = hdr_check_buffer(gbp, X_SIZEOF_INT); + if (status != ENOERR) + return status; + + status = ncx_get_int_int(gbp->pos, &type); + gbp->pos = (void *)((char *)gbp->pos + X_SIZEOF_INT); + if (status != ENOERR) + return status; + *typep = (NCtype) type; + return ENOERR; +} + +int +hdr_get_size_t(bufferinfo *gbp, size_t *sp) { + int status = hdr_check_buffer(gbp, X_SIZEOF_SIZE_T); + if (status != ENOERR) + return status; + return ncx_get_size_t((const void **)(&gbp->pos), sp); +} + +int +hdr_get_NC_string(bufferinfo *gbp, NC_string **ncstrpp) { + int status; + size_t nchars = 0, padding, bufremain, strcount; + NC_string *ncstrp; + char *cpos; + char pad[X_ALIGN-1]; + + status = hdr_get_size_t(gbp, &nchars); + if (status != ENOERR) + return status; + + ncstrp = new_NC_string(nchars, NULL); + if (ncstrp == NULL) + return NC_ENOMEM; + + padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN) + - X_SIZEOF_CHAR * ncstrp->nchars; + bufremain = gbp->size - (size_t)((char *)gbp->pos - (char *)gbp->base); + cpos = ncstrp->cp; + + while (nchars > 0) { + if (bufremain > 0) { + strcount = MIN(bufremain, X_SIZEOF_CHAR * nchars); + (void) memcpy(cpos, gbp->pos, strcount); + nchars -= strcount/X_SIZEOF_CHAR; + gbp->pos = (void *)((char *)gbp->pos + strcount); + cpos += strcount; + bufremain -= strcount; + } else { + status = hdr_fetch(gbp); + if(status != ENOERR) { + free_NC_string(ncstrp); + return status; + } + bufremain = gbp->size; + } + } + + memset(pad, 0, X_ALIGN-1); + if (memcmp(gbp->pos, pad, padding) != 0) { + free_NC_string(ncstrp); + return EINVAL; + } + gbp->pos = (void *)((char *)gbp->pos + padding); + + *ncstrpp = ncstrp; + + return ENOERR; +} + +int +hdr_get_NC_dim(bufferinfo *gbp, NC_dim **dimpp) { + int status; + NC_string *ncstrp; + NC_dim *dimp; + + status = hdr_get_NC_string(gbp, &ncstrp); + if (status != ENOERR) + return status; + + dimp = new_x_NC_dim(ncstrp); + if(dimp == NULL) + return NC_ENOMEM; + + status = hdr_get_size_t(gbp, &dimp->size); + if(status != ENOERR) { + free_NC_dim(dimp); /* frees name */ + return status; + } + + *dimpp = dimp; + + return ENOERR; +} + +int +hdr_get_NC_dimarray(bufferinfo *gbp, NC_dimarray *ncap) { + int status; + NCtype type = NC_UNSPECIFIED; + NC_dim **dpp, **end; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = hdr_get_NCtype(gbp, &type); + if(status != ENOERR) + return status; + + status = hdr_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) { + if (type != NC_DIMENSION && type != NC_UNSPECIFIED) + return EINVAL; + } else { + if(type != NC_DIMENSION) + return EINVAL; + + ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + dpp = ncap->value; + end = &dpp[ncap->nelems]; + for( /*NADA*/; dpp < end; dpp++) { + status = hdr_get_NC_dim(gbp, dpp); + if (status != ENOERR) { + ncap->nelems = dpp - ncap->value; + free_NC_dimarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +hdr_get_nc_type(bufferinfo *gbp, nc_type *typep) { + int type = 0; + int status = hdr_check_buffer(gbp, X_SIZEOF_INT); + if(status != ENOERR) + return status; + + status = ncx_get_int_int(gbp->pos, &type); + gbp->pos = (void *)((char *)gbp->pos + X_SIZEOF_INT); + if(status != ENOERR) + return status; + + if ( type != NC_BYTE + && type != NC_CHAR + && type != NC_SHORT + && type != NC_INT + && type != NC_FLOAT + && type != NC_DOUBLE) + return EINVAL; + + *typep = (nc_type) type; + + return ENOERR; +} + +size_t +ncx_len_nctype(nc_type type) { + switch(type) { + case NC_BYTE: + case NC_CHAR: + return X_SIZEOF_CHAR; + case NC_SHORT: + return X_SIZEOF_SHORT; + case NC_INT: + return X_SIZEOF_INT; + case NC_FLOAT: + return X_SIZEOF_FLOAT; + case NC_DOUBLE: + return X_SIZEOF_DOUBLE; + } + /* default */ + assert("ncx_len_nctype bad type" == 0); + return 0; +} + +/* + * Get the values of an attribute + */ +int +hdr_get_NC_attrV(bufferinfo *gbp, NC_attr *attrp) { + int status; + void *value = attrp->xvalue; + char pad[X_ALIGN-1]; + size_t nvalues = attrp->nelems, esz, padding, bufremain, attcount; + + esz = ncx_len_nctype(attrp->type); + padding = attrp->xsz - esz * nvalues; + bufremain = gbp->size - (size_t)((char *)gbp->pos - (char *)gbp->base); + + while (nvalues > 0) { + if (bufremain > 0) { + attcount = MIN(bufremain, esz * nvalues); + (void) memcpy(value, gbp->pos, attcount); + nvalues -= attcount/esz; + gbp->pos = (void *)((char *)gbp->pos + attcount); + value = (void *)((char *)value + attcount); + bufremain -= attcount; + } else { + status = hdr_fetch(gbp); + if(status != ENOERR) + return status; + bufremain = gbp->size; + } + } + + memset(pad, 0, X_ALIGN-1); + if (memcmp(gbp->pos, pad, padding) != 0) + return EINVAL; + gbp->pos = (void *)((char *)gbp->pos + padding); + + return ENOERR; +} + +int +hdr_get_NC_attr(bufferinfo *gbp, NC_attr **attrpp) { + NC_string *strp; + int status; + nc_type type; + size_t nelems; + NC_attr *attrp; + + status = hdr_get_NC_string(gbp, &strp); + if(status != ENOERR) + return status; + + status = hdr_get_nc_type(gbp, &type); + if(status != ENOERR) { + free_NC_string(strp); + return status; + } + + status = hdr_get_size_t(gbp, &nelems); + if(status != ENOERR) { + free_NC_string(strp); + return status; + } + + attrp = new_x_NC_attr(strp, type, nelems); + if(attrp == NULL) { + free_NC_string(strp); + return status; + } + + status = hdr_get_NC_attrV(gbp, attrp); + if(status != ENOERR) { + free_NC_attr(attrp); /* frees strp */ + return status; + } + + *attrpp = attrp; + + return ENOERR; +} + +int +hdr_get_NC_attrarray(bufferinfo *gbp, NC_attrarray *ncap){ + int status; + NCtype type = NC_UNSPECIFIED; + NC_attr **app, **end; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = hdr_get_NCtype(gbp, &type); + if(status != ENOERR) + return status; + + status = hdr_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) { + if (type != NC_ATTRIBUTE && type != NC_UNSPECIFIED) + return EINVAL; + } else { + if(type != NC_ATTRIBUTE) + return EINVAL; + + ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + app = ncap->value; + end = &app[ncap->nelems]; + for( /*NADA*/; app < end; app++) { + status = hdr_get_NC_attr(gbp, app); + if (status != ENOERR) { + ncap->nelems = app - ncap->value; + free_NC_attrarrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +hdr_get_NC_var(bufferinfo *gbp, NC_var **varpp) { + NC_string *strp; + int status; + size_t ndims, dim; + NC_var *varp; + + status = hdr_get_NC_string(gbp, &strp); + if(status != ENOERR) + return status; + + status = hdr_get_size_t(gbp, &ndims); + if(status != ENOERR) { + free_NC_string(strp); + return status; + } + + varp = new_x_NC_var(strp, ndims); + if(varp == NULL) { + free_NC_string(strp); + return NC_ENOMEM; + } + + for (dim = 0; dim < ndims; dim++ ) { + status = hdr_check_buffer(gbp, X_SIZEOF_INT); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + status = ncx_getn_int_int((const void **)(&gbp->pos), + 1, varp->dimids + dim); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + } + + status = hdr_get_NC_attrarray(gbp, &varp->attrs); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + + status = hdr_get_nc_type(gbp, &varp->type); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + + status = hdr_get_size_t(gbp, &varp->len); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + + status = hdr_check_buffer(gbp, X_SIZEOF_OFF_T); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + status = ncx_get_off_t((const void **)&gbp->pos, + &varp->begin); + if(status != ENOERR) { + free_NC_var(varp); + return status; + } + + *varpp = varp; + return ENOERR; +} + +int +hdr_get_NC_vararray(bufferinfo *gbp, NC_vararray *ncap) { + int status; + NCtype type = NC_UNSPECIFIED; + NC_var **vpp, **end; + + assert(gbp != NULL && gbp->pos != NULL); + assert(ncap != NULL); + assert(ncap->value == NULL); + + status = hdr_get_NCtype(gbp, &type); + if(status != ENOERR) + return status; + + status = hdr_get_size_t(gbp, &ncap->nelems); + if(status != ENOERR) + return status; + + if(ncap->nelems == 0) { + if (type != NC_VARIABLE && type != NC_UNSPECIFIED) + return EINVAL; + } else { + if(type != NC_VARIABLE) + return EINVAL; + + ncap->value = (NC_var **) malloc(ncap->nelems * sizeof(NC_var *)); + if(ncap->value == NULL) + return NC_ENOMEM; + ncap->nalloc = ncap->nelems; + + vpp = ncap->value; + end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) { + status = hdr_get_NC_var(gbp, vpp); + if (status != ENOERR) { + ncap->nelems = vpp - ncap->value; + free_NC_vararrayV(ncap); + return status; + } + } + } + + return ENOERR; +} + +int +hdr_get_NC(NC *ncp) { + int status; + bufferinfo getbuf; + schar magic[sizeof(ncmagic)]; + size_t nrecs = 0; + + assert(ncp != NULL); + + /* Initialize the get buffer */ + + getbuf.nciop = ncp->nciop; + getbuf.offset = 0; /* read from start of the file */ + getbuf.size = _RNDUP( MAX(MIN_NC_XSZ, ncp->chunk), X_ALIGN ); + if (getbuf.size > 4096) + getbuf.size = 4096; + getbuf.pos = getbuf.base = (void *)malloc(getbuf.size); + + status = hdr_fetch(&getbuf); + + /* Get the header from get buffer */ + + (void) memset(magic, 0, sizeof(magic)); + status = ncx_getn_schar_schar( + (const void **)(&getbuf.pos), sizeof(magic), magic); + if(memcmp(magic, ncmagic, sizeof(ncmagic)) != 0) { + free(getbuf.base); + return NC_ENOTNC; + } + + status = hdr_check_buffer(&getbuf, X_SIZEOF_SIZE_T); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + status = ncx_get_size_t((const void **)(&getbuf.pos), &nrecs); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + ncp->numrecs = nrecs; + + assert((char *)getbuf.pos < (char *)getbuf.base + getbuf.size); + + status = hdr_get_NC_dimarray(&getbuf, &ncp->dims); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + + status = hdr_get_NC_attrarray(&getbuf, &ncp->attrs); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + + status = hdr_get_NC_vararray(&getbuf, &ncp->vars); + if(status != ENOERR) { + free(getbuf.base); + return status; + } + + ncp->xsz = hdr_len_NC(ncp); + status = NC_computeshapes(ncp); + free(getbuf.base); + + return status; +} + +/* End Of get NC */ Index: /branches/SDM_SciDAC/src/lib/ncx.c =================================================================== --- /branches/SDM_SciDAC/src/lib/ncx.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncx.c (revision 2) @@ -0,0 +1,4154 @@ +/* Do not edit this file. It is produced from the corresponding .m4 source */ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + * + * This file contains some routines derived from code + * which is copyrighted by Sun Microsystems, Inc. + * The "#ifdef vax" versions of + * ncx_put_float_float() + * ncx_get_float_float() + * ncx_put_double_double() + * ncx_get_double_double() + * ncx_putn_float_float() + * ncx_getn_float_float() + * ncx_putn_double_double() + * ncx_getn_double_double() + * are derived from xdr_float() and xdr_double() routines + * in the freely available, copyrighted Sun RPCSRC 3.9 + * distribution, xdr_float.c. + * Our "value added" is that these are always memory to memory, + * they handle IEEE subnormals properly, and their "n" versions + * operate speedily on arrays. + */ +/* $Id$ */ + +/* + * An external data representation interface. + */ + +#include "ncx.h" +#include +#include +/* alias poorly named limits.h macros */ +#define SHORT_MAX SHRT_MAX +#define SHORT_MIN SHRT_MIN +#define USHORT_MAX USHRT_MAX +#include +#ifndef FLT_MAX /* This POSIX macro missing on some systems */ +# ifndef NO_IEEE_FLOAT +# define FLT_MAX 3.40282347e+38f +# else +# error "You will need to define FLT_MAX" +# endif +#endif +#include + +/* + * If the machine's float domain is "smaller" than the external one + * use the machine domain + */ +#if defined(FLT_MAX_EXP) && FLT_MAX_EXP < 128 /* 128 is X_FLT_MAX_EXP */ +#undef X_FLOAT_MAX +# define X_FLOAT_MAX FLT_MAX +#undef X_FLOAT_MIN +# define X_FLOAT_MIN (-X_FLOAT_MAX) +#endif + +#if _SX /* NEC SUPER UX */ +#if _INT64 +#undef INT_MAX /* workaround cpp bug */ +#define INT_MAX X_INT_MAX +#undef INT_MIN /* workaround cpp bug */ +#define INT_MIN X_INT_MIN +#undef LONG_MAX /* workaround cpp bug */ +#define LONG_MAX X_INT_MAX +#undef LONG_MIN /* workaround cpp bug */ +#define LONG_MIN X_INT_MIN +#elif _LONG64 +#undef LONG_MAX /* workaround cpp bug */ +#define LONG_MAX 4294967295L +#undef LONG_MIN /* workaround cpp bug */ +#define LONG_MIN -4294967295L +#endif +#endif /* _SX */ + +static const char nada[X_ALIGN] = {0, 0, 0, 0}; + +#ifndef WORDS_BIGENDIAN +/* LITTLE_ENDIAN: DEC and intel */ +/* + * Routines to convert to BIGENDIAN. + * Optimize the swapn?b() and swap?b() routines aggressivly. + */ + +#define SWAP2(a) ( (((a) & 0xff) << 8) | \ + (((a) >> 8) & 0xff) ) + +#define SWAP4(a) ( ((a) << 24) | \ + (((a) << 8) & 0x00ff0000) | \ + (((a) >> 8) & 0x0000ff00) | \ + (((a) >> 24) & 0x000000ff) ) + +static void +swapn2b(void *dst, const void *src, size_t nn) +{ + char *op = dst; + const char *ip = src; + while(nn-- != 0) + { + *op++ = *(++ip); + *op++ = *(ip++ -1); + } +} + +# ifndef vax +static void +swap4b(void *dst, const void *src) +{ + char *op = dst; + const char *ip = src; + op[0] = ip[3]; + op[1] = ip[2]; + op[2] = ip[1]; + op[3] = ip[0]; +} +# endif /* !vax */ + +static void +swapn4b(void *dst, const void *src, size_t nn) +{ + char *op = dst; + const char *ip = src; + while(nn-- != 0) + { + op[0] = ip[3]; + op[1] = ip[2]; + op[2] = ip[1]; + op[3] = ip[0]; + op += 4; + ip += 4; + } +} + +# ifndef vax +static void +swap8b(void *dst, const void *src) +{ + char *op = dst; + const char *ip = src; + op[0] = ip[7]; + op[1] = ip[6]; + op[2] = ip[5]; + op[3] = ip[4]; + op[4] = ip[3]; + op[5] = ip[2]; + op[6] = ip[1]; + op[7] = ip[0]; +} +# endif /* !vax */ + +# ifndef vax +static void +swapn8b(void *dst, const void *src, size_t nn) +{ + char *op = dst; + const char *ip = src; + while(nn-- != 0) + { + op[0] = ip[7]; + op[1] = ip[6]; + op[2] = ip[5]; + op[3] = ip[4]; + op[4] = ip[3]; + op[5] = ip[2]; + op[6] = ip[1]; + op[7] = ip[0]; + op += 8; + ip += 8; + } +} +# endif /* !vax */ + +#endif /* LITTLE_ENDIAN */ + + +/* + * Primitive numeric conversion functions. + */ + +/* x_schar */ + + /* We don't implement and x_schar primitives. */ + + +/* x_short */ + +#if SHORT_MAX == X_SHORT_MAX +typedef short ix_short; +#define SIZEOF_IX_SHORT SIZEOF_SHORT +#define IX_SHORT_MAX SHORT_MAX +#elif INT_MAX >= X_SHORT_MAX +typedef int ix_short; +#define SIZEOF_IX_SHORT SIZEOF_INT +#define IX_SHORT_MAX INT_MAX +#elif LONG_MAX >= X_SHORT_MAX +typedef long ix_short; +#define SIZEOF_IX_SHORT SIZEOF_LONG +#define IX_SHORT_MAX LONG_MAX +#else +#error "ix_short implementation" +#endif + +static void +get_ix_short(const void *xp, ix_short *ip) +{ + const uchar *cp = (const uchar *) xp; + *ip = *cp++ << 8; +#if SIZEOF_IX_SHORT > X_SIZEOF_SHORT + if(*ip & 0x8000) + { + /* extern is negative */ + *ip |= (~(0xffff)); /* N.B. Assumes "twos complement" */ + } +#endif + *ip |= *cp; +} + +static void +put_ix_short(void *xp, const ix_short *ip) +{ + uchar *cp = (uchar *) xp; + *cp++ = (*ip) >> 8; + *cp = (*ip) & 0xff; +} + + +int +ncx_get_short_schar(const void *xp, schar *ip) +{ + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; + if(xx > SCHAR_MAX || xx < SCHAR_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_short_uchar(const void *xp, uchar *ip) +{ + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; + if(xx > UCHAR_MAX || xx < 0) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_short_short(const void *xp, short *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_SHORT && IX_SHORT_MAX == SHORT_MAX + get_ix_short(xp, (ix_short *)ip); + return ENOERR; +#else + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; +# if IX_SHORT_MAX > SHORT_MAX + if(xx > SHORT_MAX || xx < SHORT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_get_short_int(const void *xp, int *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_INT && IX_SHORT_MAX == INT_MAX + get_ix_short(xp, (ix_short *)ip); + return ENOERR; +#else + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; +# if IX_SHORT_MAX > INT_MAX + if(xx > INT_MAX || xx < INT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_get_short_long(const void *xp, long *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_LONG && IX_SHORT_MAX == LONG_MAX + get_ix_short(xp, (ix_short *)ip); + return ENOERR; +#else + /* assert(LONG_MAX >= X_SHORT_MAX); */ + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; + return ENOERR; +#endif +} + +int +ncx_get_short_float(const void *xp, float *ip) +{ + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; +#if 0 /* TODO: determine when necessary */ + if(xx > FLT_MAX || xx < (-FLT_MAX)) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_get_short_double(const void *xp, double *ip) +{ + /* assert(DBL_MAX >= X_SHORT_MAX); */ + ix_short xx; + get_ix_short(xp, &xx); + *ip = xx; + return ENOERR; +} + +int +ncx_put_short_schar(void *xp, const schar *ip) +{ + uchar *cp = (uchar *) xp; + if(*ip & 0x80) + *cp++ = 0xff; + else + *cp++ = 0; + *cp = (uchar)*ip; + return ENOERR; +} + +int +ncx_put_short_uchar(void *xp, const uchar *ip) +{ + uchar *cp = (uchar *) xp; + *cp++ = 0; + *cp = *ip; + return ENOERR; +} + +int +ncx_put_short_short(void *xp, const short *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_SHORT && X_SHORT_MAX == SHORT_MAX + put_ix_short(xp, (const ix_short *)ip); + return ENOERR; +#else + ix_short xx = (ix_short)*ip; + put_ix_short(xp, &xx); +# if X_SHORT_MAX < SHORT_MAX + if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_short_int(void *xp, const int *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_INT && X_SHORT_MAX == INT_MAX + put_ix_short(xp, (const ix_short *)ip); + return ENOERR; +#else + ix_short xx = (ix_short)*ip; + put_ix_short(xp, &xx); +# if X_SHORT_MAX < INT_MAX + if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_short_long(void *xp, const long *ip) +{ +#if SIZEOF_IX_SHORT == SIZEOF_LONG && X_SHORT_MAX == LONG_MAX + put_ix_short(xp, (const ix_short *)ip); + return ENOERR; +#else + ix_short xx = (ix_short)*ip; + put_ix_short(xp, &xx); +# if X_SHORT_MAX < LONG_MAX + if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_short_float(void *xp, const float *ip) +{ + ix_short xx = *ip; + put_ix_short(xp, &xx); + if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_put_short_double(void *xp, const double *ip) +{ + ix_short xx = *ip; + put_ix_short(xp, &xx); + if(*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + return NC_ERANGE; + return ENOERR; +} + +/* x_int */ + +#if SHORT_MAX == X_INT_MAX +typedef short ix_int; +#define SIZEOF_IX_INT SIZEOF_SHORT +#define IX_INT_MAX SHORT_MAX +#elif INT_MAX >= X_INT_MAX +typedef int ix_int; +#define SIZEOF_IX_INT SIZEOF_INT +#define IX_INT_MAX INT_MAX +#elif LONG_MAX >= X_INT_MAX +typedef long ix_int; +#define SIZEOF_IX_INT SIZEOF_LONG +#define IX_INT_MAX LONG_MAX +#else +#error "ix_int implementation" +#endif + + +static void +get_ix_int(const void *xp, ix_int *ip) +{ + const uchar *cp = (const uchar *) xp; + + *ip = *cp++ << 24; +#if SIZEOF_IX_INT > X_SIZEOF_INT + if(*ip & 0x80000000) + { + /* extern is negative */ + *ip |= (~(0xffffffff)); /* N.B. Assumes "twos complement" */ + } +#endif + *ip |= (*cp++ << 16); + *ip |= (*cp++ << 8); + *ip |= *cp; +} + +static void +put_ix_int(void *xp, const ix_int *ip) +{ + uchar *cp = (uchar *) xp; + + *cp++ = (*ip) >> 24; + *cp++ = ((*ip) & 0x00ff0000) >> 16; + *cp++ = ((*ip) & 0x0000ff00) >> 8; + *cp = ((*ip) & 0x000000ff); +} + + +int +ncx_get_int_schar(const void *xp, schar *ip) +{ + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; + if(xx > SCHAR_MAX || xx < SCHAR_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_int_uchar(const void *xp, uchar *ip) +{ + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; + if(xx > UCHAR_MAX || xx < 0) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_int_short(const void *xp, short *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_SHORT && IX_INT_MAX == SHORT_MAX + get_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; +# if IX_INT_MAX > SHORT_MAX + if(xx > SHORT_MAX || xx < SHORT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_get_int_int(const void *xp, int *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_INT && IX_INT_MAX == INT_MAX + get_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; +# if IX_INT_MAX > INT_MAX + if(xx > INT_MAX || xx < INT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_get_int_long(const void *xp, long *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_LONG && IX_INT_MAX == LONG_MAX + get_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; +# if IX_INT_MAX > LONG_MAX /* unlikely */ + if(xx > LONG_MAX || xx < LONG_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_get_int_float(const void *xp, float *ip) +{ + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; +#if 0 /* TODO: determine when necessary */ + if(xx > FLT_MAX || xx < (-FLT_MAX)) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_get_int_double(const void *xp, double *ip) +{ + /* assert((DBL_MAX >= X_INT_MAX); */ + ix_int xx; + get_ix_int(xp, &xx); + *ip = xx; + return ENOERR; +} + +int +ncx_put_int_schar(void *xp, const schar *ip) +{ + uchar *cp = (uchar *) xp; + if(*ip & 0x80) + { + *cp++ = 0xff; + *cp++ = 0xff; + *cp++ = 0xff; + } + else + { + *cp++ = 0x00; + *cp++ = 0x00; + *cp++ = 0x00; + } + *cp = (uchar)*ip; + return ENOERR; +} + +int +ncx_put_int_uchar(void *xp, const uchar *ip) +{ + uchar *cp = (uchar *) xp; + *cp++ = 0x00; + *cp++ = 0x00; + *cp++ = 0x00; + *cp = *ip; + return ENOERR; +} + +int +ncx_put_int_short(void *xp, const short *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_SHORT && IX_INT_MAX == SHORT_MAX + put_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx = (ix_int)(*ip); + put_ix_int(xp, &xx); +# if IX_INT_MAX < SHORT_MAX + if(*ip > X_INT_MAX || *ip < X_INT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_int_int(void *xp, const int *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_INT && IX_INT_MAX == INT_MAX + put_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx = (ix_int)(*ip); + put_ix_int(xp, &xx); +# if IX_INT_MAX < INT_MAX + if(*ip > X_INT_MAX || *ip < X_INT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_int_long(void *xp, const long *ip) +{ +#if SIZEOF_IX_INT == SIZEOF_LONG && IX_INT_MAX == LONG_MAX + put_ix_int(xp, (ix_int *)ip); + return ENOERR; +#else + ix_int xx = (ix_int)(*ip); + put_ix_int(xp, &xx); +# if IX_INT_MAX < LONG_MAX + if(*ip > X_INT_MAX || *ip < X_INT_MIN) + return NC_ERANGE; +# endif + return ENOERR; +#endif +} + +int +ncx_put_int_float(void *xp, const float *ip) +{ + ix_int xx = (ix_int)(*ip); + put_ix_int(xp, &xx); + if(*ip > (double)X_INT_MAX || *ip < (double)X_INT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_put_int_double(void *xp, const double *ip) +{ + ix_int xx = (ix_int)(*ip); + put_ix_int(xp, &xx); + if(*ip > X_INT_MAX || *ip < X_INT_MIN) + return NC_ERANGE; + return ENOERR; +} + + +/* x_float */ + +#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT) + +static void +get_ix_float(const void *xp, float *ip) +{ +#ifdef WORDS_BIGENDIAN + (void) memcpy(ip, xp, sizeof(float)); +#else + swap4b(ip, xp); +#endif +} + +static void +put_ix_float(void *xp, const float *ip) +{ +#ifdef WORDS_BIGENDIAN + (void) memcpy(xp, ip, X_SIZEOF_FLOAT); +#else + swap4b(xp, ip); +#endif +} + +#elif vax + +/* What IEEE single precision floating point looks like on a Vax */ +struct ieee_single { + unsigned int exp_hi : 7; + unsigned int sign : 1; + unsigned int mant_hi : 7; + unsigned int exp_lo : 1; + unsigned int mant_lo_hi : 8; + unsigned int mant_lo_lo : 8; +}; + +/* Vax single precision floating point */ +struct vax_single { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; +}; + +#define VAX_SNG_BIAS 0x81 +#define IEEE_SNG_BIAS 0x7f + +static struct sgl_limits { + struct vax_single s; + struct ieee_single ieee; +} max = { + { 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */ + { 0x7f, 0x0, 0x0, 0x1, 0x0, 0x0 } /* Max IEEE */ +}; +static struct sgl_limits min = { + { 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */ + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } /* Min IEEE */ +}; + +static void +get_ix_float(const void *xp, float *ip) +{ + struct vax_single *const vsp = (struct vax_single *) ip; + const struct ieee_single *const isp = + (const struct ieee_single *) xp; + unsigned exp = isp->exp_hi << 1 | isp->exp_lo; + + switch(exp) { + case 0 : + /* ieee subnormal */ + if(isp->mant_hi == min.ieee.mant_hi + && isp->mant_lo_hi == min.ieee.mant_lo_hi + && isp->mant_lo_lo == min.ieee.mant_lo_lo) + { + *vsp = min.s; + } + else + { + unsigned mantissa = (isp->mant_hi << 16) + | isp->mant_lo_hi << 8 + | isp->mant_lo_lo; + unsigned tmp = mantissa >> 20; + if(tmp >= 4) { + vsp->exp = 2; + } else if (tmp >= 2) { + vsp->exp = 1; + } else { + *vsp = min.s; + break; + } /* else */ + tmp = mantissa - (1 << (20 + vsp->exp )); + tmp <<= 3 - vsp->exp; + vsp->mantissa2 = tmp; + vsp->mantissa1 = (tmp >> 16); + } + break; + case 0xfe : + case 0xff : + *vsp = max.s; + break; + default : + vsp->exp = exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; + vsp->mantissa2 = isp->mant_lo_hi << 8 | isp->mant_lo_lo; + vsp->mantissa1 = isp->mant_hi; + } + + vsp->sign = isp->sign; + +} + + +static void +put_ix_float(void *xp, const float *ip) +{ + const struct vax_single *const vsp = + (const struct vax_single *)ip; + struct ieee_single *const isp = (struct ieee_single *) xp; + + switch(vsp->exp){ + case 0 : + /* all vax float with zero exponent map to zero */ + *isp = min.ieee; + break; + case 2 : + case 1 : + { + /* These will map to subnormals */ + unsigned mantissa = (vsp->mantissa1 << 16) + | vsp->mantissa2; + mantissa >>= 3 - vsp->exp; + mantissa += (1 << (20 + vsp->exp)); + isp->mant_lo_lo = mantissa; + isp->mant_lo_hi = mantissa >> 8; + isp->mant_hi = mantissa >> 16; + isp->exp_lo = 0; + isp->exp_hi = 0; + } + break; + case 0xff : /* max.s.exp */ + if( vsp->mantissa2 == max.s.mantissa2 + && vsp->mantissa1 == max.s.mantissa1) + { + /* map largest vax float to ieee infinity */ + *isp = max.ieee; + break; + } /* else, fall thru */ + default : + { + unsigned exp = vsp->exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; + isp->exp_hi = exp >> 1; + isp->exp_lo = exp; + isp->mant_lo_lo = vsp->mantissa2; + isp->mant_lo_hi = vsp->mantissa2 >> 8; + isp->mant_hi = vsp->mantissa1; + } + } + + isp->sign = vsp->sign; + +} + + /* vax */ +#elif defined(_CRAY) + +/* + * Return the number of bytes until the next "word" boundary + * N.B. This is based on the very wierd YMP address structure, + * which puts the address within a word in the leftmost 3 bits + * of the address. + */ +static size_t +word_align(const void *vp) +{ + const size_t rem = ((size_t)vp >> (64 - 3)) & 0x7; + return (rem != 0); +} + +struct ieee_single_hi { + unsigned int sign : 1; + unsigned int exp : 8; + unsigned int mant :23; + unsigned int pad :32; +}; +typedef struct ieee_single_hi ieee_single_hi; + +struct ieee_single_lo { + unsigned int pad :32; + unsigned int sign : 1; + unsigned int exp : 8; + unsigned int mant :23; +}; +typedef struct ieee_single_lo ieee_single_lo; + +static const int ieee_single_bias = 0x7f; + +struct ieee_double { + unsigned int sign : 1; + unsigned int exp :11; + unsigned int mant :52; +}; +typedef struct ieee_double ieee_double; + +static const int ieee_double_bias = 0x3ff; + +#if defined(NO_IEEE_FLOAT) + +struct cray_single { + unsigned int sign : 1; + unsigned int exp :15; + unsigned int mant :48; +}; +typedef struct cray_single cray_single; + +static const int cs_ieis_bias = 0x4000 - 0x7f; + +static const int cs_id_bias = 0x4000 - 0x3ff; + + +static void +get_ix_float(const void *xp, float *ip) +{ + + if(word_align(xp) == 0) + { + const ieee_single_hi *isp = (const ieee_single_hi *) xp; + cray_single *csp = (cray_single *) ip; + + if(isp->exp == 0) + { + /* ieee subnormal */ + *ip = (double)isp->mant; + if(isp->mant != 0) + { + csp->exp -= (ieee_single_bias + 22); + } + } + else + { + csp->exp = isp->exp + cs_ieis_bias + 1; + csp->mant = isp->mant << (48 - 1 - 23); + csp->mant |= (1 << (48 - 1)); + } + csp->sign = isp->sign; + + + } + else + { + const ieee_single_lo *isp = (const ieee_single_lo *) xp; + cray_single *csp = (cray_single *) ip; + + if(isp->exp == 0) + { + /* ieee subnormal */ + *ip = (double)isp->mant; + if(isp->mant != 0) + { + csp->exp -= (ieee_single_bias + 22); + } + } + else + { + csp->exp = isp->exp + cs_ieis_bias + 1; + csp->mant = isp->mant << (48 - 1 - 23); + csp->mant |= (1 << (48 - 1)); + } + csp->sign = isp->sign; + + + } +} + +static void +put_ix_float(void *xp, const float *ip) +{ + if(word_align(xp) == 0) + { + ieee_single_hi *isp = (ieee_single_hi*)xp; + const cray_single *csp = (const cray_single *) ip; + int ieee_exp = csp->exp - cs_ieis_bias -1; + + isp->sign = csp->sign; + + if(ieee_exp >= 0xff) + { + /* NC_ERANGE => ieee Inf */ + isp->exp = 0xff; + isp->mant = 0x0; + } + else if(ieee_exp > 0) + { + /* normal ieee representation */ + isp->exp = ieee_exp; + /* assumes cray rep is in normal form */ + assert(csp->mant & 0x800000000000); + isp->mant = (((csp->mant << 1) & + 0xffffffffffff) >> (48 - 23)); + } + else if(ieee_exp > -23) + { + /* ieee subnormal, right */ + const int rshift = (48 - 23 - ieee_exp); + + isp->mant = csp->mant >> rshift; + +#if 0 + if(csp->mant & (1 << (rshift -1))) + { + /* round up */ + isp->mant++; + } +#endif + + isp->exp = 0; + } + else + { + /* smaller than ieee can represent */ + isp->exp = 0; + isp->mant = 0; + } + + } + else + { + ieee_single_lo *isp = (ieee_single_lo*)xp; + const cray_single *csp = (const cray_single *) ip; + int ieee_exp = csp->exp - cs_ieis_bias -1; + + isp->sign = csp->sign; + + if(ieee_exp >= 0xff) + { + /* NC_ERANGE => ieee Inf */ + isp->exp = 0xff; + isp->mant = 0x0; + } + else if(ieee_exp > 0) + { + /* normal ieee representation */ + isp->exp = ieee_exp; + /* assumes cray rep is in normal form */ + assert(csp->mant & 0x800000000000); + isp->mant = (((csp->mant << 1) & + 0xffffffffffff) >> (48 - 23)); + } + else if(ieee_exp > -23) + { + /* ieee subnormal, right */ + const int rshift = (48 - 23 - ieee_exp); + + isp->mant = csp->mant >> rshift; + +#if 0 + if(csp->mant & (1 << (rshift -1))) + { + /* round up */ + isp->mant++; + } +#endif + + isp->exp = 0; + } + else + { + /* smaller than ieee can represent */ + isp->exp = 0; + isp->mant = 0; + } + + } +} + +#else + /* IEEE Cray with only doubles */ +static void +get_ix_float(const void *xp, float *ip) +{ + + ieee_double *idp = (ieee_double *) ip; + + if(word_align(xp) == 0) + { + const ieee_single_hi *isp = (const ieee_single_hi *) xp; + if(isp->exp == 0 && isp->mant == 0) + { + idp->exp = 0; + idp->mant = 0; + } + else + { + idp->exp = isp->exp + (ieee_double_bias - ieee_single_bias); + idp->mant = isp->mant << (52 - 23); + } + idp->sign = isp->sign; + } + else + { + const ieee_single_lo *isp = (const ieee_single_lo *) xp; + if(isp->exp == 0 && isp->mant == 0) + { + idp->exp = 0; + idp->mant = 0; + } + else + { + idp->exp = isp->exp + (ieee_double_bias - ieee_single_bias); + idp->mant = isp->mant << (52 - 23); + } + idp->sign = isp->sign; + } +} + +static void +put_ix_float(void *xp, const float *ip) +{ + const ieee_double *idp = (const ieee_double *) ip; + if(word_align(xp) == 0) + { + ieee_single_hi *isp = (ieee_single_hi*)xp; + if(idp->exp > (ieee_double_bias - ieee_single_bias)) + isp->exp = idp->exp - (ieee_double_bias - ieee_single_bias); + else + isp->exp = 0; + isp->mant = idp->mant >> (52 - 23); + isp->sign = idp->sign; + } + else + { + ieee_single_lo *isp = (ieee_single_lo*)xp; + if(idp->exp > (ieee_double_bias - ieee_single_bias)) + isp->exp = idp->exp - (ieee_double_bias - ieee_single_bias); + else + isp->exp = 0; + isp->mant = idp->mant >> (52 - 23); + isp->sign = idp->sign; + } +} +#endif + +#elif _SX && _FLOAT2 +static void +get_ix_float(const void *xp, float *ip) +{ + const int ncnv = ie3_fl2(xp, ip, 4, 8, 1); +} + +static void +put_ix_float(void *xp, const float *ip) +{ + const int ncnv = fl2_ie3(ip, xp, 8, 4, 1); +} +#else +#error "ix_float implementation" +#endif + + +int +ncx_get_float_schar(const void *xp, schar *ip) +{ + float xx; + get_ix_float(xp, &xx); + *ip = (schar) xx; + if(xx > SCHAR_MAX || xx < SCHAR_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_float_uchar(const void *xp, uchar *ip) +{ + float xx; + get_ix_float(xp, &xx); + *ip = (uchar) xx; + if(xx > UCHAR_MAX || xx < 0) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_float_short(const void *xp, short *ip) +{ + float xx; + get_ix_float(xp, &xx); + *ip = (short) xx; + if(xx > SHORT_MAX || xx < SHORT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_float_int(const void *xp, int *ip) +{ + float xx; + get_ix_float(xp, &xx); + *ip = (int) xx; + if(xx > (double)INT_MAX || xx < (double)INT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_float_long(const void *xp, long *ip) +{ + float xx; + get_ix_float(xp, &xx); + *ip = (long) xx; + if(xx > LONG_MAX || xx < LONG_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_float_float(const void *xp, float *ip) +{ + /* TODO */ + get_ix_float(xp, ip); + return ENOERR; +} + +int +ncx_get_float_double(const void *xp, double *ip) +{ + /* TODO */ + float xx; + get_ix_float(xp, &xx); + *ip = xx; + return ENOERR; +} + + +int +ncx_put_float_schar(void *xp, const schar *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); + return ENOERR; +} + +int +ncx_put_float_uchar(void *xp, const uchar *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); + return ENOERR; +} + +int +ncx_put_float_short(void *xp, const short *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); +#if 0 /* TODO: figure this out */ + if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_float_int(void *xp, const int *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); +#if 1 /* TODO: figure this out */ + if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_float_long(void *xp, const long *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); +#if 1 /* TODO: figure this out */ + if((float)(*ip) > X_FLOAT_MAX || (float)(*ip) < X_FLOAT_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_float_float(void *xp, const float *ip) +{ + put_ix_float(xp, ip); +#ifdef NO_IEEE_FLOAT + if(*ip > X_FLOAT_MAX || *ip < X_FLOAT_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_float_double(void *xp, const double *ip) +{ + float xx = (float) *ip; + put_ix_float(xp, &xx); + if(*ip > X_FLOAT_MAX || *ip < X_FLOAT_MIN) + return NC_ERANGE; + return ENOERR; +} + +/* x_double */ + +#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE && !defined(NO_IEEE_FLOAT) + +static void +get_ix_double(const void *xp, double *ip) +{ +#ifdef WORDS_BIGENDIAN + (void) memcpy(ip, xp, sizeof(double)); +#else + swap8b(ip, xp); +#endif +} + +static void +put_ix_double(void *xp, const double *ip) +{ +#ifdef WORDS_BIGENDIAN + (void) memcpy(xp, ip, X_SIZEOF_DOUBLE); +#else + swap8b(xp, ip); +#endif +} + +#elif vax + +/* What IEEE double precision floating point looks like on a Vax */ +struct ieee_double { + unsigned int exp_hi : 7; + unsigned int sign : 1; + unsigned int mant_6 : 4; + unsigned int exp_lo : 4; + unsigned int mant_5 : 8; + unsigned int mant_4 : 8; + + unsigned int mant_lo : 32; +}; + +/* Vax double precision floating point */ +struct vax_double { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; + unsigned int mantissa3 : 16; + unsigned int mantissa4 : 16; +}; + +#define VAX_DBL_BIAS 0x81 +#define IEEE_DBL_BIAS 0x3ff +#define MASK(nbits) ((1 << nbits) - 1) + +static const struct dbl_limits { + struct vax_double d; + struct ieee_double ieee; +} dbl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */ + { 0x7f, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0}}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */ + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, /* Min IEEE */ +}; + + +static void +get_ix_double(const void *xp, double *ip) +{ + struct vax_double *const vdp = + (struct vax_double *)ip; + const struct ieee_double *const idp = + (const struct ieee_double *) xp; + { + const struct dbl_limits *lim; + int ii; + for (ii = 0, lim = dbl_limits; + ii < sizeof(dbl_limits)/sizeof(struct dbl_limits); + ii++, lim++) + { + if ((idp->mant_lo == lim->ieee.mant_lo) + && (idp->mant_4 == lim->ieee.mant_4) + && (idp->mant_5 == lim->ieee.mant_5) + && (idp->mant_6 == lim->ieee.mant_6) + && (idp->exp_lo == lim->ieee.exp_lo) + && (idp->exp_hi == lim->ieee.exp_hi) + ) + { + *vdp = lim->d; + goto doneit; + } + } + } + { + unsigned exp = idp->exp_hi << 4 | idp->exp_lo; + vdp->exp = exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; + } + { + unsigned mant_hi = ((idp->mant_6 << 16) + | (idp->mant_5 << 8) + | idp->mant_4); + unsigned mant_lo = SWAP4(idp->mant_lo); + vdp->mantissa1 = (mant_hi >> 13); + vdp->mantissa2 = ((mant_hi & MASK(13)) << 3) + | (mant_lo >> 29); + vdp->mantissa3 = (mant_lo >> 13); + vdp->mantissa4 = (mant_lo << 3); + } + doneit: + vdp->sign = idp->sign; + +} + + +static void +put_ix_double(void *xp, const double *ip) +{ + const struct vax_double *const vdp = + (const struct vax_double *)ip; + struct ieee_double *const idp = + (struct ieee_double *) xp; + + if ((vdp->mantissa4 > (dbl_limits[0].d.mantissa4 - 3)) && + (vdp->mantissa3 == dbl_limits[0].d.mantissa3) && + (vdp->mantissa2 == dbl_limits[0].d.mantissa2) && + (vdp->mantissa1 == dbl_limits[0].d.mantissa1) && + (vdp->exp == dbl_limits[0].d.exp)) + { + *idp = dbl_limits[0].ieee; + goto shipit; + } + if ((vdp->mantissa4 == dbl_limits[1].d.mantissa4) && + (vdp->mantissa3 == dbl_limits[1].d.mantissa3) && + (vdp->mantissa2 == dbl_limits[1].d.mantissa2) && + (vdp->mantissa1 == dbl_limits[1].d.mantissa1) && + (vdp->exp == dbl_limits[1].d.exp)) + { + *idp = dbl_limits[1].ieee; + goto shipit; + } + + { + unsigned exp = vdp->exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; + + unsigned mant_lo = ((vdp->mantissa2 & MASK(3)) << 29) | + (vdp->mantissa3 << 13) | + ((vdp->mantissa4 >> 3) & MASK(13)); + + unsigned mant_hi = (vdp->mantissa1 << 13) + | (vdp->mantissa2 >> 3); + + if((vdp->mantissa4 & 7) > 4) + { + /* round up */ + mant_lo++; + if(mant_lo == 0) + { + mant_hi++; + if(mant_hi > 0xffffff) + { + mant_hi = 0; + exp++; + } + } + } + + idp->mant_lo = SWAP4(mant_lo); + idp->mant_6 = mant_hi >> 16; + idp->mant_5 = (mant_hi & 0xff00) >> 8; + idp->mant_4 = mant_hi; + idp->exp_hi = exp >> 4; + idp->exp_lo = exp; + } + + shipit: + idp->sign = vdp->sign; + +} + + /* vax */ +#elif defined(_CRAY) + +static void +get_ix_double(const void *xp, double *ip) +{ + const ieee_double *idp = (const ieee_double *) xp; + cray_single *csp = (cray_single *) ip; + + if(idp->exp == 0) + { + /* ieee subnormal */ + *ip = (double)idp->mant; + if(idp->mant != 0) + { + csp->exp -= (ieee_double_bias + 51); + } + } + else + { + csp->exp = idp->exp + cs_id_bias + 1; + csp->mant = idp->mant >> (52 - 48 + 1); + csp->mant |= (1 << (48 - 1)); + } + csp->sign = idp->sign; +} + +static void +put_ix_double(void *xp, const double *ip) +{ + ieee_double *idp = (ieee_double *) xp; + const cray_single *csp = (const cray_single *) ip; + + int ieee_exp = csp->exp - cs_id_bias -1; + + idp->sign = csp->sign; + + if(ieee_exp >= 0x7ff) + { + /* NC_ERANGE => ieee Inf */ + idp->exp = 0x7ff; + idp->mant = 0x0; + } + else if(ieee_exp > 0) + { + /* normal ieee representation */ + idp->exp = ieee_exp; + /* assumes cray rep is in normal form */ + assert(csp->mant & 0x800000000000); + idp->mant = (((csp->mant << 1) & + 0xffffffffffff) << (52 - 48)); + } + else if(ieee_exp >= (-(52 -48))) + { + /* ieee subnormal, left */ + const int lshift = (52 - 48) + ieee_exp; + idp->mant = csp->mant << lshift; + idp->exp = 0; + } + else if(ieee_exp >= -52) + { + /* ieee subnormal, right */ + const int rshift = (- (52 - 48) - ieee_exp); + + idp->mant = csp->mant >> rshift; + +#if 0 + if(csp->mant & (1 << (rshift -1))) + { + /* round up */ + idp->mant++; + } +#endif + + idp->exp = 0; + } + else + { + /* smaller than ieee can represent */ + idp->exp = 0; + idp->mant = 0; + } +} +#elif _SX && _FLOAT2 +static void +get_ix_double(const void *xp, double *ip) +{ + const int ncnv = ie3_fl2(xp, ip, 8, 8, 1); +} + +static void +put_ix_double(void *xp, const double *ip) +{ + const int ncnv = fl2_ie3(ip, xp, 8, 8, 1); +} +#else +#error "ix_double implementation" +#endif + +int +ncx_get_double_schar(const void *xp, schar *ip) +{ + double xx; + get_ix_double(xp, &xx); + *ip = (schar) xx; + if(xx > SCHAR_MAX || xx < SCHAR_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_double_uchar(const void *xp, uchar *ip) +{ + double xx; + get_ix_double(xp, &xx); + *ip = (uchar) xx; + if(xx > UCHAR_MAX || xx < 0) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_double_short(const void *xp, short *ip) +{ + double xx; + get_ix_double(xp, &xx); + *ip = (short) xx; + if(xx > SHORT_MAX || xx < SHORT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_double_int(const void *xp, int *ip) +{ + double xx; + get_ix_double(xp, &xx); + *ip = (int) xx; + if(xx > INT_MAX || xx < INT_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_double_long(const void *xp, long *ip) +{ + double xx; + get_ix_double(xp, &xx); + *ip = (long) xx; + if(xx > LONG_MAX || xx < LONG_MIN) + return NC_ERANGE; + return ENOERR; +} + +int +ncx_get_double_float(const void *xp, float *ip) +{ + double xx; + get_ix_double(xp, &xx); + if(xx > FLT_MAX || xx < (-FLT_MAX)) + { + *ip = FLT_MAX; + return NC_ERANGE; + } + if(xx < (-FLT_MAX)) + { + *ip = (-FLT_MAX); + return NC_ERANGE; + } + *ip = (float) xx; + return ENOERR; +} + +int +ncx_get_double_double(const void *xp, double *ip) +{ + /* TODO */ + get_ix_double(xp, ip); + return ENOERR; +} + + +int +ncx_put_double_schar(void *xp, const schar *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); + return ENOERR; +} + +int +ncx_put_double_uchar(void *xp, const uchar *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); + return ENOERR; +} + +int +ncx_put_double_short(void *xp, const short *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); +#if 0 /* TODO: figure this out */ + if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_double_int(void *xp, const int *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); +#if 0 /* TODO: figure this out */ + if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_double_long(void *xp, const long *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); +#if 1 /* TODO: figure this out */ + if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_double_float(void *xp, const float *ip) +{ + double xx = (double) *ip; + put_ix_double(xp, &xx); +#if 1 /* TODO: figure this out */ + if((double)(*ip) > X_DOUBLE_MAX || (double)(*ip) < X_DOUBLE_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + +int +ncx_put_double_double(void *xp, const double *ip) +{ + put_ix_double(xp, ip); +#ifdef NO_IEEE_FLOAT + if(*ip > X_DOUBLE_MAX || *ip < X_DOUBLE_MIN) + return NC_ERANGE; +#endif + return ENOERR; +} + + +/* x_size_t */ + +#if SIZEOF_SIZE_T < X_SIZEOF_SIZE_T +#error "x_size_t implementation" +/* netcdf requires size_t which can hold a values from 0 to 2^31 -1 */ +#endif + +int +ncx_put_size_t(void **xpp, const size_t *ulp) +{ + /* similar to put_ix_int() */ + uchar *cp = (uchar *) *xpp; + /* sizes limited to 2^31 -1 in netcdf */ + assert(*ulp <= X_SIZE_MAX && (long) (*ulp) >= 0); + + *cp++ = (uchar)((*ulp) >> 24); + *cp++ = (uchar)(((*ulp) & 0x00ff0000) >> 16); + *cp++ = (uchar)(((*ulp) & 0x0000ff00) >> 8); + *cp = (uchar)((*ulp) & 0x000000ff); + + *xpp = (void *)((char *)(*xpp) + X_SIZEOF_SIZE_T); + return ENOERR; +} + +int +ncx_get_size_t(const void **xpp, size_t *ulp) +{ + /* similar to get_ix_int */ + const uchar *cp = (const uchar *) *xpp; + assert((*cp & 0x80) == 0); /* sizes limited to 2^31 -1 in netcdf */ + + *ulp = *cp++ << 24; + *ulp |= (*cp++ << 16); + *ulp |= (*cp++ << 8); + *ulp |= *cp; + + *xpp = (const void *)((const char *)(*xpp) + X_SIZEOF_SIZE_T); + return ENOERR; +} + +/* x_off_t */ + +#if SIZEOF_OFF_T < X_SIZEOF_OFF_T +#error "x_off_t implementation" +/* netcdf requires size_t which can hold a values from 0 to 2^31 -1 */ +#endif + +int +ncx_put_off_t(void **xpp, const off_t *lp) +{ + /* similar to put_ix_int() */ + uchar *cp = (uchar *) *xpp; + /* No negative offsets stored in netcdf */ + assert(*lp >= 0 && *lp <= X_OFF_MAX); + + *cp++ = (uchar)((*lp) >> 24); + *cp++ = (uchar)(((*lp) & 0x00ff0000) >> 16); + *cp++ = (uchar)(((*lp) & 0x0000ff00) >> 8); + *cp = (uchar)((*lp) & 0x000000ff); + + *xpp = (void *)((char *)(*xpp) + X_SIZEOF_OFF_T); + return ENOERR; +} + +int +ncx_get_off_t(const void **xpp, off_t *lp) +{ + /* similar to get_ix_int() */ + const uchar *cp = (const uchar *) *xpp; + assert((*cp & 0x80) == 0); /* No negative offsets stored in netcdf */ + + *lp = *cp++ << 24; + *lp |= (*cp++ << 16); + *lp |= (*cp++ << 8); + *lp |= *cp; + + *xpp = (const void *)((const char *)(*xpp) + X_SIZEOF_OFF_T); + return ENOERR; +} + + +/* + * Aggregate numeric conversion functions. + */ + + + +/* schar */ + +int +ncx_getn_schar_schar(const void **xpp, size_t nelems, schar *tp) +{ + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + return ENOERR; + +} +int +ncx_getn_schar_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + return ENOERR; + +} +int +ncx_getn_schar_short(const void **xpp, size_t nelems, short *tp) +{ + schar *xp = (schar *)(*xpp); + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (const void *)xp; + return ENOERR; +} + +int +ncx_getn_schar_int(const void **xpp, size_t nelems, int *tp) +{ + schar *xp = (schar *)(*xpp); + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (const void *)xp; + return ENOERR; +} + +int +ncx_getn_schar_long(const void **xpp, size_t nelems, long *tp) +{ + schar *xp = (schar *)(*xpp); + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (const void *)xp; + return ENOERR; +} + +int +ncx_getn_schar_float(const void **xpp, size_t nelems, float *tp) +{ + schar *xp = (schar *)(*xpp); + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (const void *)xp; + return ENOERR; +} + +int +ncx_getn_schar_double(const void **xpp, size_t nelems, double *tp) +{ + schar *xp = (schar *)(*xpp); + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (const void *)xp; + return ENOERR; +} + + +int +ncx_pad_getn_schar_schar(const void **xpp, size_t nelems, schar *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems + rndup); + + return ENOERR; + +} +int +ncx_pad_getn_schar_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems + rndup); + + return ENOERR; + +} +int +ncx_pad_getn_schar_short(const void **xpp, size_t nelems, short *tp) +{ + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (void *)(xp + rndup); + return ENOERR; +} + +int +ncx_pad_getn_schar_int(const void **xpp, size_t nelems, int *tp) +{ + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (void *)(xp + rndup); + return ENOERR; +} + +int +ncx_pad_getn_schar_long(const void **xpp, size_t nelems, long *tp) +{ + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (void *)(xp + rndup); + return ENOERR; +} + +int +ncx_pad_getn_schar_float(const void **xpp, size_t nelems, float *tp) +{ + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (void *)(xp + rndup); + return ENOERR; +} + +int +ncx_pad_getn_schar_double(const void **xpp, size_t nelems, double *tp) +{ + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + *tp++ = *xp++; + } + + *xpp = (void *)(xp + rndup); + return ENOERR; +} + + +int +ncx_putn_schar_schar(void **xpp, size_t nelems, const schar *tp) +{ + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + return ENOERR; + +} +int +ncx_putn_schar_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + return ENOERR; + +} +int +ncx_putn_schar_short(void **xpp, size_t nelems, const short *tp) +{ + int status = ENOERR; + schar *xp = (schar *) *xpp; + + while(nelems-- != 0) + { + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_schar_int(void **xpp, size_t nelems, const int *tp) +{ + int status = ENOERR; + schar *xp = (schar *) *xpp; + + while(nelems-- != 0) + { + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_schar_long(void **xpp, size_t nelems, const long *tp) +{ + int status = ENOERR; + schar *xp = (schar *) *xpp; + + while(nelems-- != 0) + { + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_schar_float(void **xpp, size_t nelems, const float *tp) +{ + int status = ENOERR; + schar *xp = (schar *) *xpp; + + while(nelems-- != 0) + { + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_schar_double(void **xpp, size_t nelems, const double *tp) +{ + int status = ENOERR; + schar *xp = (schar *) *xpp; + + while(nelems-- != 0) + { + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + *xpp = (void *)xp; + return status; +} + + +int +ncx_pad_putn_schar_schar(void **xpp, size_t nelems, const schar *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + if(rndup) + { + (void) memcpy(*xpp, nada, rndup); + *xpp = (void *)((char *)(*xpp) + rndup); + } + + return ENOERR; + +} +int +ncx_pad_putn_schar_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + if(rndup) + { + (void) memcpy(*xpp, nada, rndup); + *xpp = (void *)((char *)(*xpp) + rndup); + } + + return ENOERR; + +} +int +ncx_pad_putn_schar_short(void **xpp, size_t nelems, const short *tp) +{ + int status = ENOERR; + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + /* N.B. schar as signed */ + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + + if(rndup) + { + (void) memcpy(xp, nada, rndup); + xp += rndup; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_schar_int(void **xpp, size_t nelems, const int *tp) +{ + int status = ENOERR; + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + /* N.B. schar as signed */ + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + + if(rndup) + { + (void) memcpy(xp, nada, rndup); + xp += rndup; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_schar_long(void **xpp, size_t nelems, const long *tp) +{ + int status = ENOERR; + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + /* N.B. schar as signed */ + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + + if(rndup) + { + (void) memcpy(xp, nada, rndup); + xp += rndup; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_schar_float(void **xpp, size_t nelems, const float *tp) +{ + int status = ENOERR; + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + /* N.B. schar as signed */ + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + + if(rndup) + { + (void) memcpy(xp, nada, rndup); + xp += rndup; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_schar_double(void **xpp, size_t nelems, const double *tp) +{ + int status = ENOERR; + size_t rndup = nelems % X_ALIGN; + schar *xp = (schar *) *xpp; + + if(rndup) + rndup = X_ALIGN - rndup; + + while(nelems-- != 0) + { + /* N.B. schar as signed */ + if(*tp > X_SCHAR_MAX || *tp < X_SCHAR_MIN) + status = NC_ERANGE; + *xp++ = (schar) *tp++; + } + + + if(rndup) + { + (void) memcpy(xp, nada, rndup); + xp += rndup; + } + + *xpp = (void *)xp; + return status; +} + + + +/* short */ + +int +ncx_getn_short_schar(const void **xpp, size_t nelems, schar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_short_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#if X_SIZEOF_SHORT == SIZEOF_SHORT +/* optimized version */ +int +ncx_getn_short_short(const void **xpp, size_t nelems, short *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(tp, *xpp, nelems * sizeof(short)); +# else + swapn2b(tp, *xpp, nelems); +# endif + *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_SHORT); + return ENOERR; +} +#else +int +ncx_getn_short_short(const void **xpp, size_t nelems, short *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#endif +int +ncx_getn_short_int(const void **xpp, size_t nelems, int *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_short_long(const void **xpp, size_t nelems, long *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_short_float(const void **xpp, size_t nelems, float *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_short_double(const void **xpp, size_t nelems, double *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + + +int +ncx_pad_getn_short_schar(const void **xpp, size_t nelems, schar *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_short(const void **xpp, size_t nelems, short *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_int(const void **xpp, size_t nelems, int *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_long(const void **xpp, size_t nelems, long *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_float(const void **xpp, size_t nelems, float *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_getn_short_double(const void **xpp, size_t nelems, double *tp) +{ + const size_t rndup = nelems % 2; + + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + const int lstatus = ncx_get_short_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + xp += X_SIZEOF_SHORT; + + *xpp = (void *)xp; + return status; +} + + +int +ncx_putn_short_schar(void **xpp, size_t nelems, const schar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_short_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#if X_SIZEOF_SHORT == SIZEOF_SHORT +/* optimized version */ +int +ncx_putn_short_short(void **xpp, size_t nelems, const short *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(*xpp, tp, nelems * X_SIZEOF_SHORT); +# else + swapn2b(*xpp, tp, nelems); +# endif + *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_SHORT); + return ENOERR; +} +#else +int +ncx_putn_short_short(void **xpp, size_t nelems, const short *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#endif +int +ncx_putn_short_int(void **xpp, size_t nelems, const int *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_short_long(void **xpp, size_t nelems, const long *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_short_float(void **xpp, size_t nelems, const float *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_short_double(void **xpp, size_t nelems, const double *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + + +int +ncx_pad_putn_short_schar(void **xpp, size_t nelems, const schar *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_short(void **xpp, size_t nelems, const short *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_int(void **xpp, size_t nelems, const int *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_long(void **xpp, size_t nelems, const long *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_float(void **xpp, size_t nelems, const float *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_pad_putn_short_double(void **xpp, size_t nelems, const double *tp) +{ + const size_t rndup = nelems % 2; + + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_SHORT, tp++) + { + int lstatus = ncx_put_short_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + if(rndup != 0) + { + (void) memcpy(xp, nada, X_SIZEOF_SHORT); + xp += X_SIZEOF_SHORT; + } + + *xpp = (void *)xp; + return status; +} + + + +/* int */ + +int +ncx_getn_int_schar(const void **xpp, size_t nelems, schar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_int_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_int_short(const void **xpp, size_t nelems, short *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#if X_SIZEOF_INT == SIZEOF_INT +/* optimized version */ +int +ncx_getn_int_int(const void **xpp, size_t nelems, int *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(tp, *xpp, nelems * sizeof(int)); +# else + swapn4b(tp, *xpp, nelems); +# endif + *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_INT); + return ENOERR; +} +#else +int +ncx_getn_int_int(const void **xpp, size_t nelems, int *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#endif +#if X_SIZEOF_INT == SIZEOF_LONG +/* optimized version */ +int +ncx_getn_int_long(const void **xpp, size_t nelems, long *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(tp, *xpp, nelems * sizeof(long)); +# else + swapn4b(tp, *xpp, nelems); +# endif + *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_INT); + return ENOERR; +} +#else +int +ncx_getn_int_long(const void **xpp, size_t nelems, long *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#endif +int +ncx_getn_int_float(const void **xpp, size_t nelems, float *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_int_double(const void **xpp, size_t nelems, double *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + const int lstatus = ncx_get_int_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + + +int +ncx_putn_int_schar(void **xpp, size_t nelems, const schar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_int_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_int_short(void **xpp, size_t nelems, const short *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#if X_SIZEOF_INT == SIZEOF_INT +/* optimized version */ +int +ncx_putn_int_int(void **xpp, size_t nelems, const int *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(*xpp, tp, nelems * X_SIZEOF_INT); +# else + swapn4b(*xpp, tp, nelems); +# endif + *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_INT); + return ENOERR; +} +#else +int +ncx_putn_int_int(void **xpp, size_t nelems, const int *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#endif +#if X_SIZEOF_INT == SIZEOF_LONG +/* optimized version */ +int +ncx_putn_int_long(void **xpp, size_t nelems, const long *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(*xpp, tp, nelems * X_SIZEOF_INT); +# else + swapn4b(*xpp, tp, nelems); +# endif + *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_INT); + return ENOERR; +} +#else +int +ncx_putn_int_long(void **xpp, size_t nelems, const long *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#endif +int +ncx_putn_int_float(void **xpp, size_t nelems, const float *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_int_double(void **xpp, size_t nelems, const double *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_INT, tp++) + { + int lstatus = ncx_put_int_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + + + +/* float */ + +int +ncx_getn_float_schar(const void **xpp, size_t nelems, schar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_float_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_float_short(const void **xpp, size_t nelems, short *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_float_int(const void **xpp, size_t nelems, int *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_float_long(const void **xpp, size_t nelems, long *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT) +/* optimized version */ +int +ncx_getn_float_float(const void **xpp, size_t nelems, float *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(tp, *xpp, nelems * sizeof(float)); +# else + swapn4b(tp, *xpp, nelems); +# endif + *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_FLOAT); + return ENOERR; +} +#elif vax +int +ncx_getn_float_float(const void **xpp, size_t nfloats, float *ip) +{ + float *const end = ip + nfloats; + + while(ip < end) + { + struct vax_single *const vsp = (struct vax_single *) ip; + const struct ieee_single *const isp = + (const struct ieee_single *) (*xpp); + unsigned exp = isp->exp_hi << 1 | isp->exp_lo; + + switch(exp) { + case 0 : + /* ieee subnormal */ + if(isp->mant_hi == min.ieee.mant_hi + && isp->mant_lo_hi == min.ieee.mant_lo_hi + && isp->mant_lo_lo == min.ieee.mant_lo_lo) + { + *vsp = min.s; + } + else + { + unsigned mantissa = (isp->mant_hi << 16) + | isp->mant_lo_hi << 8 + | isp->mant_lo_lo; + unsigned tmp = mantissa >> 20; + if(tmp >= 4) { + vsp->exp = 2; + } else if (tmp >= 2) { + vsp->exp = 1; + } else { + *vsp = min.s; + break; + } /* else */ + tmp = mantissa - (1 << (20 + vsp->exp )); + tmp <<= 3 - vsp->exp; + vsp->mantissa2 = tmp; + vsp->mantissa1 = (tmp >> 16); + } + break; + case 0xfe : + case 0xff : + *vsp = max.s; + break; + default : + vsp->exp = exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; + vsp->mantissa2 = isp->mant_lo_hi << 8 | isp->mant_lo_lo; + vsp->mantissa1 = isp->mant_hi; + } + + vsp->sign = isp->sign; + + + ip++; + *xpp = (char *)(*xpp) + X_SIZEOF_FLOAT; + } + return ENOERR; +} +#elif _SX && _FLOAT2 +int +ncx_getn_float_float(const void **xpp, size_t nelems, float *tp) +{ + const char *const xp = *xpp; + + const int ncnv = ie3_fl2(xp, tp, 4, 8, nelems); + + *xpp = xp + nelems * X_SIZEOF_FLOAT; + return (nelems == ncnv ? ENOERR : NC_ERANGE); +} +#else +int +ncx_getn_float_float(const void **xpp, size_t nelems, float *tp) +{ + const char *xp = *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#endif +int +ncx_getn_float_double(const void **xpp, size_t nelems, double *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + const int lstatus = ncx_get_float_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + + +int +ncx_putn_float_schar(void **xpp, size_t nelems, const schar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_float_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_float_short(void **xpp, size_t nelems, const short *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_float_int(void **xpp, size_t nelems, const int *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_float_long(void **xpp, size_t nelems, const long *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#if X_SIZEOF_FLOAT == SIZEOF_FLOAT && !defined(NO_IEEE_FLOAT) +/* optimized version */ +int +ncx_putn_float_float(void **xpp, size_t nelems, const float *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(*xpp, tp, nelems * X_SIZEOF_FLOAT); +# else + swapn4b(*xpp, tp, nelems); +# endif + *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_FLOAT); + return ENOERR; +} +#elif vax +int +ncx_putn_float_float(void **xpp, size_t nfloats, const float *ip) +{ + const float *const end = ip + nfloats; + + while(ip < end) + { + const struct vax_single *const vsp = + (const struct vax_single *)ip; + struct ieee_single *const isp = (struct ieee_single *) (*xpp); + + switch(vsp->exp){ + case 0 : + /* all vax float with zero exponent map to zero */ + *isp = min.ieee; + break; + case 2 : + case 1 : + { + /* These will map to subnormals */ + unsigned mantissa = (vsp->mantissa1 << 16) + | vsp->mantissa2; + mantissa >>= 3 - vsp->exp; + mantissa += (1 << (20 + vsp->exp)); + isp->mant_lo_lo = mantissa; + isp->mant_lo_hi = mantissa >> 8; + isp->mant_hi = mantissa >> 16; + isp->exp_lo = 0; + isp->exp_hi = 0; + } + break; + case 0xff : /* max.s.exp */ + if( vsp->mantissa2 == max.s.mantissa2 + && vsp->mantissa1 == max.s.mantissa1) + { + /* map largest vax float to ieee infinity */ + *isp = max.ieee; + break; + } /* else, fall thru */ + default : + { + unsigned exp = vsp->exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; + isp->exp_hi = exp >> 1; + isp->exp_lo = exp; + isp->mant_lo_lo = vsp->mantissa2; + isp->mant_lo_hi = vsp->mantissa2 >> 8; + isp->mant_hi = vsp->mantissa1; + } + } + + isp->sign = vsp->sign; + + + ip++; + *xpp = (char *)(*xpp) + X_SIZEOF_FLOAT; + } + return ENOERR; +} +#elif _SX && _FLOAT2 +int +ncx_putn_float_float(void **xpp, size_t nelems, const float *tp) +{ + char *const xp = *xpp; + + const int ncnv = fl2_ie3(tp, xp, 8, 4, nelems); + + *xpp = xp + nelems * X_SIZEOF_FLOAT; + return (nelems == ncnv ? ENOERR : NC_ERANGE); +} +#else +int +ncx_putn_float_float(void **xpp, size_t nelems, const float *tp) +{ + char *xp = *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#endif +int +ncx_putn_float_double(void **xpp, size_t nelems, const double *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_FLOAT, tp++) + { + int lstatus = ncx_put_float_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + + + +/* double */ + +int +ncx_getn_double_schar(const void **xpp, size_t nelems, schar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_double_uchar(const void **xpp, size_t nelems, uchar *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_double_short(const void **xpp, size_t nelems, short *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_double_int(const void **xpp, size_t nelems, int *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_double_long(const void **xpp, size_t nelems, long *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +int +ncx_getn_double_float(const void **xpp, size_t nelems, float *tp) +{ + const char *xp = (const char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE && !defined(NO_IEEE_FLOAT) +/* optimized version */ +int +ncx_getn_double_double(const void **xpp, size_t nelems, double *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(tp, *xpp, nelems * sizeof(double)); +# else + swapn8b(tp, *xpp, nelems); +# endif + *xpp = (const void *)((const char *)(*xpp) + nelems * X_SIZEOF_DOUBLE); + return ENOERR; +} +#elif vax +int +ncx_getn_double_double(const void **xpp, size_t ndoubles, double *ip) +{ + double *const end = ip + ndoubles; + + while(ip < end) + { + struct vax_double *const vdp = + (struct vax_double *)ip; + const struct ieee_double *const idp = + (const struct ieee_double *) (*xpp); + { + const struct dbl_limits *lim; + int ii; + for (ii = 0, lim = dbl_limits; + ii < sizeof(dbl_limits)/sizeof(struct dbl_limits); + ii++, lim++) + { + if ((idp->mant_lo == lim->ieee.mant_lo) + && (idp->mant_4 == lim->ieee.mant_4) + && (idp->mant_5 == lim->ieee.mant_5) + && (idp->mant_6 == lim->ieee.mant_6) + && (idp->exp_lo == lim->ieee.exp_lo) + && (idp->exp_hi == lim->ieee.exp_hi) + ) + { + *vdp = lim->d; + goto doneit; + } + } + } + { + unsigned exp = idp->exp_hi << 4 | idp->exp_lo; + vdp->exp = exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; + } + { + unsigned mant_hi = ((idp->mant_6 << 16) + | (idp->mant_5 << 8) + | idp->mant_4); + unsigned mant_lo = SWAP4(idp->mant_lo); + vdp->mantissa1 = (mant_hi >> 13); + vdp->mantissa2 = ((mant_hi & MASK(13)) << 3) + | (mant_lo >> 29); + vdp->mantissa3 = (mant_lo >> 13); + vdp->mantissa4 = (mant_lo << 3); + } + doneit: + vdp->sign = idp->sign; + + ip++; + *xpp = (char *)(*xpp) + X_SIZEOF_DOUBLE; + } + return ENOERR; +} + /* vax */ +#elif _SX && _FLOAT2 +int +ncx_getn_double_double(const void **xpp, size_t nelems, double *tp) +{ + const char *const xp = *xpp; + + const int ncnv = ie3_fl2(xp, tp, 8, 8, nelems); + + *xpp = xp + nelems * X_SIZEOF_DOUBLE; + return (nelems == ncnv ? ENOERR : NC_ERANGE); +} +#else +int +ncx_getn_double_double(const void **xpp, size_t nelems, double *tp) +{ + const char *xp = *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + const int lstatus = ncx_get_double_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (const void *)xp; + return status; +} + +#endif + +int +ncx_putn_double_schar(void **xpp, size_t nelems, const schar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_schar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_double_uchar(void **xpp, size_t nelems, const uchar *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_uchar(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_double_short(void **xpp, size_t nelems, const short *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_short(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_double_int(void **xpp, size_t nelems, const int *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_int(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_double_long(void **xpp, size_t nelems, const long *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_long(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +int +ncx_putn_double_float(void **xpp, size_t nelems, const float *tp) +{ + char *xp = (char *) *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_float(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#if X_SIZEOF_DOUBLE == SIZEOF_DOUBLE && !defined(NO_IEEE_FLOAT) +/* optimized version */ +int +ncx_putn_double_double(void **xpp, size_t nelems, const double *tp) +{ +# if WORDS_BIGENDIAN + (void) memcpy(*xpp, tp, nelems * X_SIZEOF_DOUBLE); +# else + swapn8b(*xpp, tp, nelems); +# endif + *xpp = (void *)((char *)(*xpp) + nelems * X_SIZEOF_DOUBLE); + return ENOERR; +} +#elif vax +int +ncx_putn_double_double(void **xpp, size_t ndoubles, const double *ip) +{ + const double *const end = ip + ndoubles; + + while(ip < end) + { + const struct vax_double *const vdp = + (const struct vax_double *)ip; + struct ieee_double *const idp = + (struct ieee_double *) (*xpp); + + if ((vdp->mantissa4 > (dbl_limits[0].d.mantissa4 - 3)) && + (vdp->mantissa3 == dbl_limits[0].d.mantissa3) && + (vdp->mantissa2 == dbl_limits[0].d.mantissa2) && + (vdp->mantissa1 == dbl_limits[0].d.mantissa1) && + (vdp->exp == dbl_limits[0].d.exp)) + { + *idp = dbl_limits[0].ieee; + goto shipit; + } + if ((vdp->mantissa4 == dbl_limits[1].d.mantissa4) && + (vdp->mantissa3 == dbl_limits[1].d.mantissa3) && + (vdp->mantissa2 == dbl_limits[1].d.mantissa2) && + (vdp->mantissa1 == dbl_limits[1].d.mantissa1) && + (vdp->exp == dbl_limits[1].d.exp)) + { + *idp = dbl_limits[1].ieee; + goto shipit; + } + + { + unsigned exp = vdp->exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; + + unsigned mant_lo = ((vdp->mantissa2 & MASK(3)) << 29) | + (vdp->mantissa3 << 13) | + ((vdp->mantissa4 >> 3) & MASK(13)); + + unsigned mant_hi = (vdp->mantissa1 << 13) + | (vdp->mantissa2 >> 3); + + if((vdp->mantissa4 & 7) > 4) + { + /* round up */ + mant_lo++; + if(mant_lo == 0) + { + mant_hi++; + if(mant_hi > 0xffffff) + { + mant_hi = 0; + exp++; + } + } + } + + idp->mant_lo = SWAP4(mant_lo); + idp->mant_6 = mant_hi >> 16; + idp->mant_5 = (mant_hi & 0xff00) >> 8; + idp->mant_4 = mant_hi; + idp->exp_hi = exp >> 4; + idp->exp_lo = exp; + } + + shipit: + idp->sign = vdp->sign; + + ip++; + *xpp = (char *)(*xpp) + X_SIZEOF_DOUBLE; + } + return ENOERR; +} + /* vax */ +#elif _SX && _FLOAT2 +int +ncx_putn_double_double(void **xpp, size_t nelems, const double *tp) +{ + char *const xp = *xpp; + + const int ncnv = fl2_ie3(tp, xp, 8, 8, nelems); + + *xpp = xp + nelems * X_SIZEOF_DOUBLE; + return (nelems == ncnv ? ENOERR : NC_ERANGE); +} +#else +int +ncx_putn_double_double(void **xpp, size_t nelems, const double *tp) +{ + char *xp = *xpp; + int status = ENOERR; + + for( ; nelems != 0; nelems--, xp += X_SIZEOF_DOUBLE, tp++) + { + int lstatus = ncx_put_double_double(xp, tp); + if(lstatus != ENOERR) + status = lstatus; + } + + *xpp = (void *)xp; + return status; +} + +#endif + + +/* + * Other aggregate conversion functions. + */ + +/* text */ + +int +ncx_getn_text(const void **xpp, size_t nelems, char *tp) +{ + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + return ENOERR; + +} + +int +ncx_pad_getn_text(const void **xpp, size_t nelems, char *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems + rndup); + + return ENOERR; + +} + +int +ncx_putn_text(void **xpp, size_t nelems, const char *tp) +{ + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + return ENOERR; + +} + +int +ncx_pad_putn_text(void **xpp, size_t nelems, const char *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + if(rndup) + { + (void) memcpy(*xpp, nada, rndup); + *xpp = (void *)((char *)(*xpp) + rndup); + } + + return ENOERR; + +} + + +/* opaque */ + +int +ncx_getn_void(const void **xpp, size_t nelems, void *tp) +{ + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + return ENOERR; + +} + +int +ncx_pad_getn_void(const void **xpp, size_t nelems, void *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(tp, *xpp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems + rndup); + + return ENOERR; + +} + +int +ncx_putn_void(void **xpp, size_t nelems, const void *tp) +{ + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + return ENOERR; + +} + +int +ncx_pad_putn_void(void **xpp, size_t nelems, const void *tp) +{ + size_t rndup = nelems % X_ALIGN; + + if(rndup) + rndup = X_ALIGN - rndup; + + (void) memcpy(*xpp, tp, nelems); + *xpp = (void *)((char *)(*xpp) + nelems); + + if(rndup) + { + (void) memcpy(*xpp, nada, rndup); + *xpp = (void *)((char *)(*xpp) + rndup); + } + + return ENOERR; + +} + Index: /branches/SDM_SciDAC/src/lib/rnd.h =================================================================== --- /branches/SDM_SciDAC/src/lib/rnd.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/rnd.h (revision 2) @@ -0,0 +1,17 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ +#ifndef _RNDUP + +/* useful for aligning memory */ +#define _RNDUP(x, unit) ((((x) + (unit) - 1) / (unit)) \ + * (unit)) +#define _RNDDOWN(x, unit) ((x) - ((x)%(unit))) + +#define M_RND_UNIT (sizeof(double)) +#define M_RNDUP(x) _RNDUP(x, M_RND_UNIT) +#define M_RNDDOWN(x) __RNDDOWN(x, M_RND_UNIT) + +#endif Index: /branches/SDM_SciDAC/src/lib/var.c =================================================================== --- /branches/SDM_SciDAC/src/lib/var.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/var.c (revision 2) @@ -0,0 +1,785 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "nc.h" +#include +#include +#include +#include "ncx.h" +#include "rnd.h" + + +/* + * Free var + * Formerly +NC_free_var(var) + */ +void +free_NC_var(NC_var *varp) +{ + if(varp == NULL) + return; + free_NC_attrarrayV(&varp->attrs); + free_NC_string(varp->name); + free(varp); +} + + +/* + * Common code for new_NC_var() + * and ncx_get_NC_var() + */ +NC_var * +new_x_NC_var( + NC_string *strp, + size_t ndims) +{ + NC_var *varp; + const size_t o1 = M_RNDUP(ndims * sizeof(int)); + const size_t o2 = M_RNDUP(ndims * sizeof(size_t)); + const size_t sz = M_RNDUP(sizeof(NC_var)) + + o1 + o2 + ndims * sizeof(size_t); + + varp = (NC_var *) malloc(sz); + if(varp == NULL ) + return NULL; + (void) memset(varp, 0, sz); + + varp->name = strp; + varp->ndims = ndims; + + if(ndims != 0) + { + /* + * NOTE: lint may complain about the next 3 lines: + * "pointer cast may result in improper alignment". + * We use the M_RNDUP() macro to get the proper alignment. + */ + varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var))); + varp->shape = (size_t *)((char *)varp->dimids + o1); + varp->dsizes = (size_t *)((char *)varp->shape + o2); + } + + varp->xsz = 0; + varp->len = 0; + varp->begin = 0; + + return varp; +} + + +/* + * Formerly +NC_new_var() + */ +static NC_var * +new_NC_var(const char *name, nc_type type, + size_t ndims, const int *dimids) +{ + NC_string *strp; + NC_var *varp; + + strp = new_NC_string(strlen(name), name); + if(strp == NULL) + return NULL; + + varp = new_x_NC_var(strp, ndims); + if(varp == NULL ) + { + free_NC_string(strp); + return NULL; + } + + varp->type = type; + + if( ndims != 0 && dimids != NULL) + (void) memcpy(varp->dimids, dimids, ndims * sizeof(int)); + + return(varp); +} + + +static NC_var * +dup_NC_var(const NC_var *rvarp) +{ + NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type, + rvarp->ndims, rvarp->dimids); + if(varp == NULL) + return NULL; + + + if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR) + { + free_NC_var(varp); + return NULL; + } + + (void) memcpy(varp->shape, rvarp->shape, + rvarp->ndims * sizeof(size_t)); + (void) memcpy(varp->dsizes, rvarp->dsizes, + rvarp->ndims * sizeof(size_t)); + varp->xsz = rvarp->xsz; + varp->len = rvarp->len; + varp->begin = rvarp->begin; + + return varp; +} + + +/* vararray */ + + +/* + * Free the stuff "in" (referred to by) an NC_vararray. + * Leaves the array itself allocated. + */ +void +free_NC_vararrayV0(NC_vararray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nelems == 0) + return; + + assert(ncap->value != NULL); + + { + NC_var **vpp = ncap->value; + NC_var *const *const end = &vpp[ncap->nelems]; + for( /*NADA*/; vpp < end; vpp++) + { + free_NC_var(*vpp); + *vpp = NULL; + } + } + ncap->nelems = 0; +} + + +/* + * Free NC_vararray values. + * formerly +NC_free_array() + */ +void +free_NC_vararrayV(NC_vararray *ncap) +{ + assert(ncap != NULL); + + if(ncap->nalloc == 0) + return; + + assert(ncap->value != NULL); + + free_NC_vararrayV0(ncap); + + free(ncap->value); + ncap->value = NULL; + ncap->nalloc = 0; +} + + +int +dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref) +{ + int status = NC_NOERR; + + assert(ref != NULL); + assert(ncap != NULL); + + if(ref->nelems != 0) + { + const size_t sz = ref->nelems * sizeof(NC_var *); + ncap->value = (NC_var **) malloc(sz); + if(ncap->value == NULL) + return NC_ENOMEM; + (void) memset(ncap->value, 0, sz); + ncap->nalloc = ref->nelems; + } + + ncap->nelems = 0; + { + NC_var **vpp = ncap->value; + const NC_var **drpp = (const NC_var **)ref->value; + NC_var *const *const end = &vpp[ref->nelems]; + for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++) + { + *vpp = dup_NC_var(*drpp); + if(*vpp == NULL) + { + status = NC_ENOMEM; + break; + } + } + } + + if(status != NC_NOERR) + { + free_NC_vararrayV(ncap); + return status; + } + + assert(ncap->nelems == ref->nelems); + + return NC_NOERR; +} + + +/* + * Add a new handle on the end of an array of handles + * Formerly +NC_incr_array(array, tail) + */ +static int +incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp) +{ + NC_var **vp; + + assert(ncap != NULL); + + if(ncap->nalloc == 0) + { + assert(ncap->nelems == 0); + vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *)); + if(vp == NULL) + return NC_ENOMEM; + ncap->value = vp; + ncap->nalloc = NC_ARRAY_GROWBY; + } + else if(ncap->nelems +1 > ncap->nalloc) + { + vp = (NC_var **) realloc(ncap->value, + (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *)); + if(vp == NULL) + return NC_ENOMEM; + ncap->value = vp; + ncap->nalloc += NC_ARRAY_GROWBY; + } + + if(newelemp != NULL) + { + ncap->value[ncap->nelems] = newelemp; + ncap->nelems++; + } + return NC_NOERR; +} + + +static NC_var * +elem_NC_vararray(const NC_vararray *ncap, size_t elem) +{ + assert(ncap != NULL); + /* cast needed for braindead systems with signed size_t */ + if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems) + return NULL; + + assert(ncap->value != NULL); + + return ncap->value[elem]; +} + + +/* End vararray per se */ + + +/* + * Step thru NC_VARIABLE array, seeking match on name. + * Return varid or -1 on not found. + * *varpp is set to the appropriate NC_var. + * Formerly (sort of) +NC_hvarid + */ +int +NC_findvar(const NC_vararray *ncap, const char *name, NC_var **varpp) +{ + NC_var **loc; + size_t slen; + int varid; + + assert(ncap != NULL); + + if(ncap->nelems == 0) + return -1; + + loc = (NC_var **) ncap->value; + + slen = strlen(name); + + for(varid = 0; (size_t) varid < ncap->nelems; varid++, loc++) + { + if(strlen((*loc)->name->cp) == slen && + strncmp((*loc)->name->cp, name, slen) == 0) + { + if(varpp != NULL) + *varpp = *loc; + return(varid); /* Normal return */ + } + } + return(-1); /* not found */ +} + +/* + * For a netcdf type + * return the size of one element in the external representation. + * Note that arrays get rounded up to X_ALIGN boundaries. + * Formerly +NC_xtypelen + * See also ncx_len() + */ +size_t +ncx_szof(nc_type type) +{ + switch(type){ + case NC_BYTE: + case NC_CHAR: + return(1); + case NC_SHORT : + return(2); + case NC_INT: + return X_SIZEOF_INT; + case NC_FLOAT: + return X_SIZEOF_FLOAT; + case NC_DOUBLE : + return X_SIZEOF_DOUBLE; + } + /* default */ + assert("ncx_szof invalid type" == 0); + return 0; +} + + +/* + * 'compile' the shape and len of a variable + * Formerly +NC_var_shape(var, dims) + */ +int +NC_var_shape(NC_var *varp, const NC_dimarray *dims) +{ + size_t *shp, *dsp, *op; + int *ip; + const NC_dim *dimp; + size_t product = 1; + + varp->xsz = ncx_szof(varp->type); + + if(varp->ndims == 0) + { + goto out; + } + + /* + * use the user supplied dimension indices + * to determine the shape + */ + for(ip = varp->dimids, op = varp->shape + ; ip < &varp->dimids[varp->ndims]; ip++, op++) + { + if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) ) + return NC_EBADDIM; + + dimp = elem_NC_dimarray(dims, (size_t)*ip); + *op = dimp->size; + if(*op == NC_UNLIMITED && ip != varp->dimids) + return NC_EUNLIMPOS; + } + + /* + * Compute the dsizes + */ + /* ndims is > 0 here */ + for(shp = varp->shape + varp->ndims -1, + dsp = varp->dsizes + varp->ndims -1; + shp >= varp->shape; + shp--, dsp--) + { + if(!(shp == varp->shape && IS_RECVAR(varp))) + product *= *shp; + *dsp = product; + } + + +out : + varp->len = product * varp->xsz; + switch(varp->type) { + case NC_BYTE : + case NC_CHAR : + case NC_SHORT : + if( varp->len%4 != 0 ) + { + varp->len += 4 - varp->len%4; /* round up */ + /* *dsp += 4 - *dsp%4; */ + } + break; + default: + /* already aligned */ + break; + } +#if 0 + arrayp("\tshape", varp->ndims, varp->shape); + arrayp("\tdsizes", varp->ndims, varp->dsizes); +#endif + return NC_NOERR; +} + + +/* + * Given valid ncp and varid, return var + * else NULL on error + * Formerly +NC_hlookupvar() + */ +NC_var * +NC_lookupvar(NC *ncp, int varid) +{ + NC_var *varp; + + if(varid == NC_GLOBAL) + { + /* Global is error in this context */ + return(NULL); + } + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + { + return NULL; + } + + assert(varp != NULL); + + return(varp); +} + + +/* Public */ + +int +nc_def_var( int ncid, const char *name, nc_type type, + int ndims, const int *dimids, int *varidp) +{ + int status; + NC *ncp; + int varid; + NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(!NC_indef(ncp)) + { + return NC_ENOTINDEFINE; + } + + status = NC_check_name(name); + if(status != NC_NOERR) + return status; + + status = nc_cktype(type); + if(status != NC_NOERR) + return status; + + /* cast needed for braindead systems with signed size_t */ + if((unsigned long) ndims > X_INT_MAX) /* Backward compat */ + { + return NC_EINVAL; + } + + if(ncp->vars.nelems >= NC_MAX_VARS) + { + return NC_EMAXVARS; + } + + varid = NC_findvar(&ncp->vars, name, &varp); + if(varid != -1) + { + return NC_ENAMEINUSE; + } + + varp = new_NC_var(name, type, ndims, dimids); + if(varp == NULL) + return NC_ENOMEM; + + status = NC_var_shape(varp, &ncp->dims); + if(status != NC_NOERR) + { + free_NC_var(varp); + return status; + } + + status = incr_NC_vararray(&ncp->vars, varp); + if(status != NC_NOERR) + { + free_NC_var(varp); + return status; + } + + if(varidp != NULL) + *varidp = (int)ncp->vars.nelems -1; /* varid */ + return NC_NOERR; +} + + +int +nc_inq_varid(int ncid, const char *name, int *varid_ptr) +{ + int status; + NC *ncp; + NC_var *varp; + int varid; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varid = NC_findvar(&ncp->vars, name, &varp); + if(varid == -1) + { + return NC_ENOTVAR; + } + + *varid_ptr = varid; + return NC_NOERR; +} + + +int +nc_inq_var(int ncid, + int varid, + char *name, + nc_type *typep, + int *ndimsp, + int *dimids, + int *nattsp) +{ + int status; + NC *ncp; + NC_var *varp; + size_t ii; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; + + if(name != NULL) + { + (void) strncpy(name, varp->name->cp, varp->name->nchars); + name[varp->name->nchars] = 0; + } + + if(typep != 0) + *typep = varp->type; + if(ndimsp != 0) + { + *ndimsp = (int) varp->ndims; + } + if(dimids != 0) + { + for(ii = 0; ii < varp->ndims; ii++) + { + dimids[ii] = varp->dimids[ii]; + } + } + if(nattsp != 0) + { + *nattsp = (int) varp->attrs.nelems; + } + + return NC_NOERR; +} + + +int +nc_inq_varname(int ncid, int varid, char *name) +{ + int status; + NC *ncp; + NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; + + if(name != NULL) + { + (void) strncpy(name, varp->name->cp, varp->name->nchars); + name[varp->name->nchars] = 0; + } + + return NC_NOERR; +} + +int +nc_inq_vartype(int ncid, int varid, nc_type *typep) +{ + int status; + NC *ncp; + NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; + + if(typep != 0) + *typep = varp->type; + + return NC_NOERR; +} + +int +nc_inq_varndims(int ncid, int varid, int *ndimsp) +{ + int status; + NC *ncp; + NC_var *varp; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: is this the right error code? */ + + if(ndimsp != 0) + { + *ndimsp = (int) varp->ndims; + } + + return NC_NOERR; +} + + +int +nc_inq_vardimid(int ncid, int varid, int *dimids) +{ + int status; + NC *ncp; + NC_var *varp; + size_t ii; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: is this the right error code? */ + + if(dimids != 0) + { + for(ii = 0; ii < varp->ndims; ii++) + { + dimids[ii] = varp->dimids[ii]; + } + } + + return NC_NOERR; +} + + +int +nc_inq_varnatts(int ncid, int varid, int *nattsp) +{ + int status; + NC *ncp; + NC_var *varp; + + if(varid == NC_GLOBAL) + return nc_inq_natts(ncid, nattsp); + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + varp = elem_NC_vararray(&ncp->vars, (size_t)varid); + if(varp == NULL) + return NC_ENOTVAR; /* TODO: is this the right error code? */ + + if(nattsp != 0) + { + *nattsp = (int) varp->attrs.nelems; + } + + return NC_NOERR; +} + +int +nc_rename_var(int ncid, int varid, const char *newname) +{ + int status; + NC *ncp; + NC_var *varp; + NC_string *old, *newStr; + int other; + + status = NC_check_id(ncid, &ncp); + if(status != NC_NOERR) + return status; + + if(NC_readonly(ncp)) + { + return NC_EPERM; + } + + status = NC_check_name(newname); + if(status != NC_NOERR) + return status; + + /* check for name in use */ + other = NC_findvar(&ncp->vars, newname, &varp); + if(other != -1) + { + return NC_ENAMEINUSE; + } + + varp = NC_lookupvar(ncp, varid); + if(varp == NULL) + { + /* invalid varid */ + return NC_ENOTVAR; /* TODO: is this the right error code? */ + } + + old = varp->name; + if(NC_indef(ncp)) + { + newStr = new_NC_string(strlen(newname),newname); + if(newStr == NULL) + return(-1); + varp->name = newStr; + free_NC_string(old); + return NC_NOERR; + } + + /* else, not in define mode */ + status = set_NC_string(varp->name, newname); + if(status != NC_NOERR) + return status; + + set_NC_hdirty(ncp); + + if(NC_doHsync(ncp)) + { + status = NC_sync(ncp); + if(status != NC_NOERR) + return status; + } + + return NC_NOERR; +} Index: /branches/SDM_SciDAC/src/lib/error.c =================================================================== --- /branches/SDM_SciDAC/src/lib/error.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/error.c (revision 2) @@ -0,0 +1,167 @@ +/* + * Copyright 1993, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id: error.c,v 1.14 90/02/23 16:08:55 davis Exp */ + +/*LINTLIBRARY*/ + +#include "ncconfig.h" +#include +#include +#include +#include "netcdf.h" + + +#ifndef NO_STRERROR +#include /* contains prototype for ansi libc function strerror() */ +#else +/* provide a strerror function for older unix systems */ +static char * +strerror(int errnum) +{ + extern int sys_nerr; + extern char *sys_errlist[]; + + if(errnum < 0 || errnum >= sys_nerr) return NULL; + /* else */ + return sys_errlist[errnum]; +} +#endif /* NO_STRERROR */ + + +#ifdef vms +/* UNTESTED */ +/* + * On the vms system, when a system error occurs which is not + * mapped into the unix styled errno values, errno is set EVMSERR + * and a VMS error code is set in vaxc$errno. + * This routine prints the systems message associated with status return + * from a system services call. + */ + +#include +#include +#include + +static const char * +vms_strerror( int status ) +{ + short msglen; + static char msgbuf[256]; + $DESCRIPTOR(message, msgbuf); + register ret; + + msgbuf[0] = 0; + ret = SYS$GETMSG(status, &msglen, &message, 15, 0); + + if(ret != SS$_BUFFEROVF && ret != SS$_NORMAL) { + (void) strcpy(msgbuf, "EVMSERR"); + } + return(msgbuf); +} +#endif /* vms */ + + +static char unknown[] = "Unknown Error"; + + +const char * +nc_strerror(int err) +{ + +#ifdef vms + if(err == EVMSERR) + { + return vms_strerror(err); + } + /* else */ +#endif /* vms */ + + if(NC_ISSYSERR(err)) + { + const char *cp = (const char *) strerror(err); + if(cp == NULL) + return unknown; + /* else */ + return cp; + } + /* else */ + + switch (err) { + case NC_NOERR: + return "No error"; + case NC_ENOTINDEP: + return "Operation not allowed in collective data mode"; + case NC_EINDEP: + return "Operation not allowed in independent data mode"; + case NC_EREAD: + return "Unknow error occurs in reading file"; + case NC_EWRITE: + return "Unknow error occurs in writting file"; + case NC_EMULTIDEFINE: + return "NC definations on multiprocesses conflict"; + case NC_EOFILE: + return "Can not open/create file"; + case NC_EBADID: + return "Not a netCDF id"; + case NC_ENFILE: + return "Too many netCDF files open"; + case NC_EEXIST: + return "netCDF file exists && NC_NOCLOBBER"; + case NC_EINVAL: + return "Invalid argument"; + case NC_EPERM: + return "Write to read only"; + case NC_ENOTINDEFINE: + return "Operation not allowed in data mode"; + case NC_EINDEFINE: + return "Operation not allowed in define mode"; + case NC_EINVALCOORDS: + return "Index exceeds dimension bound"; + case NC_EMAXDIMS: + return "NC_MAX_DIMS exceeded"; + case NC_ENAMEINUSE: + return "String match to name in use"; + case NC_ENOTATT: + return "Attribute not found"; + case NC_EMAXATTS: + return "NC_MAX_ATTRS exceeded"; + case NC_EBADTYPE: + return "Not a netCDF data type or _FillValue type mismatch"; + case NC_EBADDIM: + return "Invalid dimension id or name"; + case NC_EUNLIMPOS: + return "NC_UNLIMITED in the wrong index"; + case NC_EMAXVARS: + return "NC_MAX_VARS exceeded"; + case NC_ENOTVAR: + return "Variable not found"; + case NC_EGLOBAL: + return "Action prohibited on NC_GLOBAL varid"; + case NC_ENOTNC: + return "Not a netCDF file"; + case NC_ESTS: + return "In Fortran, string too short"; + case NC_EMAXNAME: + return "NC_MAX_NAME exceeded"; + case NC_EUNLIMIT: + return "NC_UNLIMITED size already in use"; + case NC_ENORECVARS: + return "nc_rec op when there are no record vars"; + case NC_ECHAR: + return "Attempt to convert between text & numbers"; + case NC_EEDGE: + return "Edge+start exceeds dimension bound"; + case NC_ESTRIDE: + return "Illegal stride"; + case NC_EBADNAME: + return "Attribute or variable name contains illegal characters"; + case NC_ERANGE: + return "Numeric conversion not representable"; + case NC_ENOMEM: + return "Memory allocation (malloc) failure"; + } + /* default */ + return unknown; +} Index: /branches/SDM_SciDAC/src/lib/posixio.c =================================================================== --- /branches/SDM_SciDAC/src/lib/posixio.c (revision 2) +++ /branches/SDM_SciDAC/src/lib/posixio.c (revision 2) @@ -0,0 +1,1337 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#include "ncconfig.h" +#include +#include +#include +#ifndef ENOERR +#define ENOERR 0 +#endif +#include +#include +#include +#include +#ifdef _MSC_VER /* Microsoft Compilers */ +#include +#else +#include +#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" + +/* #define INSTRUMENT 1 */ +#if INSTRUMENT /* debugging */ +#undef NDEBUG +#include +#include "instr.h" +#endif + +#undef MIN /* system may define MIN somewhere and complain */ +#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) + +#if !defined(NDEBUG) && !defined(X_INT_MAX) +#define X_INT_MAX 2147483647 +#endif + +#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */ +#define X_ALIGN 4 +#else +#undef X_ALIGN +#endif + +/* + * Define the following for debugging. + */ +/* #define ALWAYS_NC_SHARE 1 */ + +/* Begin OS */ + +static int ncio_px_sync(ncio *const nciop); + +#ifndef POSIXIO_DEFAULT_PAGESIZE +#define POSIXIO_DEFAULT_PAGESIZE 4096 +#endif +/* + * What is the system pagesize? + */ +static size_t +pagesize(void) +{ +/* Hmm, aren't standards great? */ +#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE) +#define _SC_PAGESIZE _SC_PAGE_SIZE +#endif + +#ifdef _SC_PAGESIZE + { + const long pgsz = sysconf(_SC_PAGESIZE); + if(pgsz > 0) + return (size_t) pgsz; + /* else, silent in the face of error */ + } +#elif defined(HAVE_GETPAGESIZE) + return (size_t) getpagesize(); +#endif + return (size_t) POSIXIO_DEFAULT_PAGESIZE; +} + +/* + * 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) + { + if(sb.st_blksize >= 8192) + return (size_t) sb.st_blksize; + return 8192; + } + /* else, silent in the face of error */ +#endif + return (size_t) 2 * pagesize(); +} + + +/* + * 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) +{ +#ifdef X_ALIGN + assert(offset % X_ALIGN == 0); +#endif + + assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR)); + + 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; + +#ifdef X_ALIGN + assert(offset % X_ALIGN == 0); + assert(extent % X_ALIGN == 0); +#endif + + assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR)); + + 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 less than asked for */ + (void) memset((char *)vp + nread, 0, (ssize_t)extent - nread); + } + *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; + /* chain for double buffering in px_move */ + struct ncio_px *slave; +} ncio_px; + + +/*ARGSUSED*/ +static int +px_rel(ncio_px *const pxp, off_t offset, int rflags) +{ + 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 ENOERR; +} + +static int +ncio_px_rel(ncio *const nciop, off_t offset, int rflags) +{ + ncio_px *const pxp = (ncio_px *)nciop->pvt; + + if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE)) + return EPERM; /* attempt to write readonly file */ + + return px_rel(pxp, offset, rflags); +} + +static int +px_get(ncio *const nciop, ncio_px *const pxp, + off_t offset, size_t extent, + int rflags, + void **const vpp) +{ + int status = ENOERR; + + const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz); + size_t diff = (size_t)(offset - blkoffset); + size_t blkextent = _RNDUP(diff + extent, pxp->blksz); + + assert(extent != 0); + assert(extent < X_INT_MAX); /* sanity check */ + assert(offset >= 0); /* sanity check */ + assert(offset < X_INT_MAX); /* sanity check */ + + if(2 * pxp->blksz < blkextent) + return E2BIG; /* TODO: temporary kludge */ + if(pxp->bf_offset == OFF_NONE) + { + /* Uninitialized */ + if(pxp->bf_base == NULL) + { + assert(pxp->bf_extent == 0); + assert(blkextent <= 2 * pxp->blksz); + pxp->bf_base = malloc(2 * pxp->blksz); + if(pxp->bf_base == NULL) + return ENOMEM; + } + goto pgin; + } + /* else */ + assert(blkextent <= 2 * pxp->blksz); + + if(blkoffset == pxp->bf_offset) + { + /* hit */ + if(blkextent > pxp->bf_extent) + { + /* page in upper */ + void *const middle = + (void *)((char *)pxp->bf_base + pxp->blksz); + assert(pxp->bf_extent == pxp->blksz); + status = px_pgin(nciop, + pxp->bf_offset + (off_t)pxp->blksz, + pxp->blksz, + middle, + &pxp->bf_cnt, + &pxp->pos); + if(status != ENOERR) + return status; + pxp->bf_extent = 2 * pxp->blksz; + pxp->bf_cnt += pxp->blksz; + } + goto done; + } + /* else */ + + if(pxp->bf_extent > pxp->blksz + && blkoffset == pxp->bf_offset + pxp->blksz) + { + /* hit in upper half */ + if(blkextent == pxp->blksz) + { + /* all in upper half, no fault needed */ + diff += pxp->blksz; + goto done; + } + /* else */ + if(pxp->bf_cnt > pxp->blksz) + { + /* data in upper half */ + void *const middle = + (void *)((char *)pxp->bf_base + pxp->blksz); + assert(pxp->bf_extent == 2 * pxp->blksz); + if(fIsSet(pxp->bf_rflags, RGN_MODIFIED)) + { + /* page out lower half */ + assert(pxp->bf_refcount <= 0); + status = px_pgout(nciop, + pxp->bf_offset, + pxp->blksz, + pxp->bf_base, + &pxp->pos); + if(status != ENOERR) + return status; + } + pxp->bf_cnt -= pxp->blksz; + /* copy upper half into lower half */ + (void) memcpy(pxp->bf_base, middle, pxp->bf_cnt); + } + pxp->bf_offset = blkoffset; + /* pxp->bf_extent = pxp->blksz; */ + + assert(blkextent == 2 * pxp->blksz); + { + /* page in upper */ + void *const middle = + (void *)((char *)pxp->bf_base + pxp->blksz); + status = px_pgin(nciop, + pxp->bf_offset + (off_t)pxp->blksz, + pxp->blksz, + middle, + &pxp->bf_cnt, + &pxp->pos); + if(status != ENOERR) + return status; + pxp->bf_extent = 2 * pxp->blksz; + pxp->bf_cnt += pxp->blksz; + } + goto done; + } + /* else */ + + if(blkoffset == pxp->bf_offset - pxp->blksz) + { + /* wants the page below */ + void *const middle = + (void *)((char *)pxp->bf_base + pxp->blksz); + size_t upper_cnt = 0; + if(pxp->bf_cnt > pxp->blksz) + { + /* data in upper half */ + assert(pxp->bf_extent == 2 * pxp->blksz); + if(fIsSet(pxp->bf_rflags, RGN_MODIFIED)) + { + /* page out upper half */ + assert(pxp->bf_refcount <= 0); + status = px_pgout(nciop, + pxp->bf_offset + (off_t)pxp->blksz, + pxp->bf_cnt - pxp->blksz, + middle, + &pxp->pos); + if(status != ENOERR) + return status; + } + pxp->bf_cnt = pxp->blksz; + pxp->bf_extent = pxp->blksz; + } + if(pxp->bf_cnt > 0) + { + /* copy lower half into upper half */ + (void) memcpy(middle, pxp->bf_base, pxp->blksz); + upper_cnt = pxp->bf_cnt; + } + /* read page below into lower half */ + status = px_pgin(nciop, + blkoffset, + pxp->blksz, + pxp->bf_base, + &pxp->bf_cnt, + &pxp->pos); + if(status != ENOERR) + return status; + pxp->bf_offset = blkoffset; + if(upper_cnt != 0) + { + pxp->bf_extent = 2 * pxp->blksz; + pxp->bf_cnt = pxp->blksz + upper_cnt; + } + else + { + pxp->bf_extent = pxp->blksz; + } + goto done; + } + /* else */ + + /* no overlap */ + 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; + } + +pgin: + status = px_pgin(nciop, + blkoffset, + blkextent, + pxp->bf_base, + &pxp->bf_cnt, + &pxp->pos); + if(status != ENOERR) + return status; + pxp->bf_offset = blkoffset; + pxp->bf_extent = blkextent; + +done: + extent += diff; + if(pxp->bf_cnt < extent) + pxp->bf_cnt = extent; + assert(pxp->bf_cnt <= pxp->bf_extent); + + pxp->bf_rflags |= rflags; + pxp->bf_refcount++; + + *vpp = (char *)pxp->bf_base + diff; + return ENOERR; +} + +static int +ncio_px_get(ncio *const nciop, + off_t offset, size_t extent, + int rflags, + void **const vpp) /* NULL => force read */ +{ + ncio_px *const pxp = (ncio_px *)nciop->pvt; + + if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE)) + return EPERM; /* attempt to write readonly file */ + + /* + * If the base of the stream buffer is NULL, then a read is forced + * for synchronization purposes (see fault_v1hs() in v1hpg.c). The + * implementation is based on ncio_spx_rel() in this file. + */ + if (*vpp == NULL) + { + ncio_px_sync(nciop); + pxp->bf_offset = OFF_NONE; + pxp->bf_cnt = 0; + } + + /* reclaim space used in move */ + if(pxp->slave != NULL) + { + if(pxp->slave->bf_base != NULL) + { + free(pxp->slave->bf_base); + pxp->slave->bf_base = NULL; + pxp->slave->bf_extent = 0; + pxp->slave->bf_offset = OFF_NONE; + } + free(pxp->slave); + pxp->slave = NULL; + } + return px_get(nciop, pxp, offset, extent, rflags, vpp); +} + + +/* ARGSUSED */ +static int +px_double_buffer(ncio *const nciop, off_t to, off_t from, + size_t nbytes, int rflags) +{ + ncio_px *const pxp = (ncio_px *)nciop->pvt; + int status = ENOERR; + void *src; + void *dest; + +#if INSTRUMENT +fprintf(stderr, "\tdouble_buffr %ld %ld %ld\n", + (long)to, (long)from, (long)nbytes); +#endif + status = px_get(nciop, pxp, to, nbytes, RGN_WRITE, + &dest); + if(status != ENOERR) + return status; + + if(pxp->slave == NULL) + { + pxp->slave = (ncio_px *) malloc(sizeof(ncio_px)); + if(pxp->slave == NULL) + return ENOMEM; + + pxp->slave->blksz = pxp->blksz; + /* pos done below */ + pxp->slave->bf_offset = pxp->bf_offset; + pxp->slave->bf_extent = pxp->bf_extent; + pxp->slave->bf_cnt = pxp->bf_cnt; + pxp->slave->bf_base = malloc(2 * pxp->blksz); + if(pxp->slave->bf_base == NULL) + return ENOMEM; + (void) memcpy(pxp->slave->bf_base, pxp->bf_base, + pxp->bf_extent); + pxp->slave->bf_rflags = 0; + pxp->slave->bf_refcount = 0; + pxp->slave->slave = NULL; + } + + pxp->slave->pos = pxp->pos; + status = px_get(nciop, pxp->slave, from, nbytes, 0, + &src); + if(status != ENOERR) + return status; + if(pxp->pos != pxp->slave->pos) + { + /* position changed, sync */ + pxp->pos = pxp->slave->pos; + } + + (void) memcpy(dest, src, nbytes); + + (void)px_rel(pxp->slave, from, 0); + (void)px_rel(pxp, to, RGN_MODIFIED); + + return status; +} + +static int +ncio_px_move(ncio *const nciop, off_t to, off_t from, + size_t nbytes, int rflags) +{ + ncio_px *const pxp = (ncio_px *)nciop->pvt; + int status = ENOERR; + off_t lower; + off_t upper; + char *base; + size_t diff; + size_t extent; + + if(to == from) + return ENOERR; /* NOOP */ + + if(fIsSet(rflags, RGN_WRITE) && !fIsSet(nciop->ioflags, NC_WRITE)) + return EPERM; /* attempt to write readonly file */ + + rflags &= RGN_NOLOCK; /* filter unwanted flags */ + + if(to > from) + { + /* growing */ + lower = from; + upper = to; + } + else + { + /* shrinking */ + lower = to; + upper = from; + } + diff = (size_t)(upper - lower); + extent = diff + nbytes; + +#if INSTRUMENT +fprintf(stderr, "ncio_px_move %ld %ld %ld %ld %ld\n", + (long)to, (long)from, (long)nbytes, (long)lower, (long)extent); +#endif + if(extent > pxp->blksz) + { + size_t remaining = nbytes; + +if(to > from) +{ + off_t frm = from + nbytes; + off_t toh = to + nbytes; + for(;;) + { + size_t loopextent = MIN(remaining, pxp->blksz); + frm -= loopextent; + toh -= loopextent; + + status = px_double_buffer(nciop, toh, frm, + loopextent, rflags) ; + if(status != ENOERR) + return status; + remaining -= loopextent; + + if(remaining == 0) + break; /* normal loop exit */ + } +} +else +{ + for(;;) + { + size_t loopextent = MIN(remaining, pxp->blksz); + + status = px_double_buffer(nciop, to, from, + loopextent, rflags) ; + if(status != ENOERR) + return status; + remaining -= loopextent; + + if(remaining == 0) + break; /* normal loop exit */ + to += loopextent; + from += loopextent; + } +} + return ENOERR; + } + +#if INSTRUMENT +fprintf(stderr, "\tncio_px_move small\n"); +#endif + status = px_get(nciop, pxp, 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) px_rel(pxp, lower, RGN_MODIFIED); + + return status; +} + + +static int +ncio_px_sync(ncio *const nciop) +{ + ncio_px *const 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; + } + return status; +} + +static void +ncio_px_free(void *const pvt) +{ + ncio_px *const pxp = (ncio_px *)pvt; + if(pxp == NULL) + return; + + if(pxp->slave != NULL) + { + if(pxp->slave->bf_base != NULL) + { + free(pxp->slave->bf_base); + pxp->slave->bf_base = NULL; + pxp->slave->bf_extent = 0; + pxp->slave->bf_offset = OFF_NONE; + } + free(pxp->slave); + pxp->slave = NULL; + } + + 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, size_t *sizehintp, int isNew) +{ + ncio_px *const pxp = (ncio_px *)nciop->pvt; + const size_t bufsz = 2 * *sizehintp; + + assert(nciop->fd >= 0); + + pxp->blksz = *sizehintp; + + assert(pxp->bf_base == NULL); + + /* this is separate allocation because it may grow */ + pxp->bf_base = malloc(bufsz); + if(pxp->bf_base == NULL) + return ENOMEM; + /* else */ + pxp->bf_cnt = 0; + if(isNew) + { + /* save a read */ + pxp->pos = 0; + pxp->bf_offset = 0; + pxp->bf_extent = bufsz; + (void) memset(pxp->bf_base, 0, pxp->bf_extent); + } + return ENOERR; +} + + +static void +ncio_px_init(ncio *const nciop) +{ + ncio_px *const 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; + pxp->slave = 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 *const pxp = (ncio_spx *)nciop->pvt; + int status = ENOERR; + + assert(pxp->bf_offset <= offset); + assert(pxp->bf_cnt != 0); + assert(pxp->bf_cnt <= pxp->bf_extent); +#ifdef X_ALIGN + assert(offset < pxp->bf_offset + X_ALIGN); + assert(pxp->bf_cnt % X_ALIGN == 0 ); +#endif + + 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 *const pxp = (ncio_spx *)nciop->pvt; + int status = ENOERR; +#ifdef X_ALIGN + size_t rem; +#endif + + 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); + +#ifdef X_ALIGN + 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); +#endif + + 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) + return ENOMEM; + 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) + pxp->bf_cnt = extent; + +#ifdef X_ALIGN + *vpp = (char *)pxp->bf_base + rem; +#else + *vpp = pxp->bf_base; +#endif + return ENOERR; +} + + +#if 0 +/*ARGSUSED*/ +static int +strategy(ncio *const nciop, off_t to, off_t offset, + size_t extent, int rflags) +{ + static ncio_spx pxp[1]; + int status = ENOERR; +#ifdef X_ALIGN + size_t rem; +#endif + + assert(extent != 0); + assert(extent < X_INT_MAX); /* sanity check */ + assert(offset < X_INT_MAX); /* sanity check */ +#if INSTRUMENT +fprintf(stderr, "strategy %ld at %ld to %ld\n", + (long)extent, (long)offset, (long)to); +#endif + + +#ifdef X_ALIGN + 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); +#endif + + 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) + return ENOMEM; + 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 = to; /* TODO: XALIGN */ + + if(pxp->bf_cnt < extent) + pxp->bf_cnt = extent; + + 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; +} +#endif + +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 *const 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, const size_t *const sizehintp) +{ + ncio_spx *const pxp = (ncio_spx *)nciop->pvt; + + assert(nciop->fd >= 0); + + pxp->bf_extent = *sizehintp; + + 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 ENOMEM; + } + /* else */ + return ENOERR; +} + + +static void +ncio_spx_init(ncio *const nciop) +{ + ncio_spx *const 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 */ + +#define NCIO_MINBLOCKSIZE 256 +#define NCIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */ + +#ifdef S_IRUSR +#define NC_DEFAULT_CREAT_MODE \ + (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */ + +#else +#define NC_DEFAULT_CREAT_MODE 0666 +#endif + +int +ncio_create(const char *path, int ioflags, + size_t initialsz, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp) +{ + ncio *nciop; + int oflags = (O_RDWR|O_CREAT); + int fd; + int status; + + if(initialsz < (size_t)igeto + igetsz) + initialsz = (size_t)igeto + igetsz; + + fSet(ioflags, NC_WRITE); + + if(path == NULL || *path == 0) + return EINVAL; + + nciop = ncio_new(path, ioflags); + if(nciop == NULL) + return ENOMEM; + + if(fIsSet(ioflags, NC_NOCLOBBER)) + fSet(oflags, O_EXCL); + else + fSet(oflags, O_TRUNC); +#ifdef O_BINARY + fSet(oflags, O_BINARY); +#endif +#ifdef vms + fd = open(path, oflags, NC_DEFAULT_CREAT_MODE, "ctx=stm"); +#else + /* Should we mess with the mode based on NC_SHARE ?? */ + fd = open(path, oflags, NC_DEFAULT_CREAT_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 */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + if(fIsSet(nciop->ioflags, NC_SHARE)) + status = ncio_spx_init2(nciop, sizehintp); + else + status = ncio_px_init2(nciop, sizehintp, 1); + + 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, size_t *sizehintp, + 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 ENOMEM; + +#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 */ + + if(*sizehintp < NCIO_MINBLOCKSIZE || *sizehintp > NCIO_MAXBLOCKSIZE) + { + /* Use default */ + *sizehintp = blksize(fd); + } + else + { + *sizehintp = M_RNDUP(*sizehintp); + } + + if(fIsSet(nciop->ioflags, NC_SHARE)) + status = ncio_spx_init2(nciop, sizehintp); + else + status = ncio_px_init2(nciop, sizehintp, 0); + + 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; +} Index: /branches/SDM_SciDAC/src/lib/ncconfig.h =================================================================== --- /branches/SDM_SciDAC/src/lib/ncconfig.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncconfig.h (revision 2) @@ -0,0 +1,82 @@ +/* src/lib/ncconfig.h. Generated automatically by configure. */ +/* libsrc/ncconfig.in. Generated automatically from configure.in by autoheader. */ +/* $Id$ */ +#ifndef _NCCONFIG_H_ +#define _NCCONFIG_H_ + +/* Define if you're on an HP-UX system. */ +/* #undef _HPUX_SOURCE */ + +/* 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. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* 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 . */ +/* #undef NO_STDLIB_H */ + +/* Define if you don't have the . */ +/* #undef NO_SYS_TYPES_H */ + +/* Define if you have the ftruncate function */ +#define HAVE_FTRUNCATE 1 + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have and it should be used (not on Ultrix). */ +#define HAVE_ALLOCA_H 1 + +/* 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 8 + +/* 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. */ +#define uchar unsigned char + +/* 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 + +#endif /* !_NCCONFIG_H_ */ Index: /branches/SDM_SciDAC/src/lib/Makefile =================================================================== --- /branches/SDM_SciDAC/src/lib/Makefile (revision 2) +++ /branches/SDM_SciDAC/src/lib/Makefile (revision 2) @@ -0,0 +1,109 @@ +# $Id$ +# +# Makefile for netcdf libsrc +# + +include ../../macros.make + +INCLUDES = -I. -DUSE_MPIO + +LIBRARY = libnetcdf.a +PROGRAM = ncvalid +ld_netcdf = -L. -lnetcdf + +HEADER = netcdf.h + +MANUAL = netcdf.3 + +LIB_CSRCS = \ + mpinetcdf.c \ + header.c \ + mpincio.c \ + attr.c \ + dim.c \ + error.c \ + nc.c \ + ncx.c \ + string.c \ + var.c +# v1hpg.c +# ncio.c \ +# putget.c \ + +PACKING_LIST = \ + $(LIB_CSRCS) \ + depend \ + fbits.h \ + Makefile \ + nc.h \ + ncconfig.in \ + ncio.h \ + ncx.h \ + netcdf.3 \ + netcdf.h \ + rnd.h +# ffio.c \ +# mpinetcdf.h \ +# onstack.h \ +# posixio.c \ + +LIB_OBJS = $(LIB_CSRCS:.c=.o) + +PROG_CSRCS = \ + validator.c \ + header.c \ + mpincio.c \ + attr.c \ + dim.c \ + nc.c \ + ncx.c \ + string.c \ + var.c + +PROG_OBJS = $(PROG_CSRCS:.c=.o) + +GARBAGE = + +DIST_GARBAGE = ncconfig.h + + +all: $(LIBRARY) $(MANUAL) $(PROGRAM) + +install: $(LIBDIR)/$(LIBRARY) \ + $(INCDIR)/$(HEADER) \ + $(MANDIR)/man3/$(MANUAL)\ + $(BINDIR)/$(PROGRAM) + +uninstall: + -rm -f $(LIBDIR)/$(LIBRARY) + -rm -f $(INCDIR)/$(HEADER) + -rm -f $(MANDIR)/man3/$(MANUAL) + -rm -f $(BINDIR)/$(PROGRAM) + + + +# The rule for generating the manual page is here for completeness only. +# The manual page is actually part of the distribution so that we don't +# have to depend on the non-POSIX utility m4(1). +# +$(MANUAL): ../../man/netcdf.m4 + $(M4) $(M4FLAGS) -DAPI=C $? >$@ || rm $@ + +$(PROGRAM): $(PROG_OBJS) + $(LINK.c) $(PROG_OBJS) $(LIBS) + +include ../..//rules.make + +.SUFFIXES: .ln +LINT = lint +LINT.c = $(LINT) $(LINTFLAGS) $(CPPFLAGS) +.c.ln: + $(LINT.c) -c $< + +llib-lnetcdf.ln: $(LIB_CSRCS) + $(LINT.c) $(LIB_CSRCS) -y -o netcdf + +lint: llib-lnetcdf.ln + $(LINT.c) t_nc.c llib-lnetcdf.ln + +include depend Index: /branches/SDM_SciDAC/src/lib/ncio.h =================================================================== --- /branches/SDM_SciDAC/src/lib/ncio.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncio.h (revision 2) @@ -0,0 +1,192 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* $Id$ */ + +#ifndef _NCIO_H_ +#define _NCIO_H_ + +#include /* size_t */ +#include /* off_t */ +#include "netcdf.h" + +#ifdef USE_MPIO /* for mpio, added by Jianwei Li */ +#include +#endif + +typedef struct ncio ncio; /* forward reference */ + +/* + * A value which is an invalid off_t + */ +#define OFF_NONE ((off_t)(-1)) + +/* + * Flags used by the region layer, + * 'rflags' argument to ncio.rel() and ncio.get(). + */ +#define RGN_NOLOCK 0x1 /* Don't lock region. + * Used when contention control handled + * elsewhere. + */ +#define RGN_NOWAIT 0x2 /* return immediate if can't lock, else wait */ + +#define RGN_WRITE 0x4 /* we intend to modify, else read only */ + +#define RGN_MODIFIED 0x8 /* we did modify, else, discard */ + + +/* + * The next four typedefs define the signatures + * of function pointers in struct ncio below. + * They are not used outside of this file and ncio.h, + * They just some casts in the ncio.c more readable. + */ + /* + * Indicate that you are done with the region which begins + * at offset. Only reasonable flag value is RGN_MODIFIED. + */ +typedef int ncio_relfunc(ncio *const nciop, + off_t offset, int rflags); + + /* + * Request that the region (offset, extent) + * be made available through *vpp. + */ +typedef int ncio_getfunc(ncio *const nciop, + off_t offset, size_t extent, + int rflags, + void **const vpp); + + /* + * Like memmove(), safely move possibly overlapping data. + * Only reasonable flag value is RGN_NOLOCK. + */ +typedef int ncio_movefunc(ncio *const nciop, off_t to, off_t from, + size_t nbytes, int rflags); + + /* + * Write out any dirty buffers to disk and + * ensure that next read will get data from disk. + */ +typedef int ncio_syncfunc(ncio *const nciop); + + /* + * Don't call this. + * Internal function called at close to + * free up anything hanging off pvt; + */ +typedef void ncio_freefunc(void *const pvt); + +/* Get around cplusplus "const xxx in class ncio without constructor" error */ +#if defined(__cplusplus) +#define NCIO_CONST +#else +#define NCIO_CONST const +#endif + +/* + * netcdf i/o abstraction + */ +struct ncio { + /* + * A copy of the ioflags argument passed in to ncio_open() + * or ncio_create(). + */ + int ioflags; + + /* + * The file descriptor of the netcdf file. + * This gets handed to the user as the netcdf id. + */ + NCIO_CONST int fd; + +#ifdef USE_MPIO /* added by Jianwei Li */ + /* + * The MPI File handle and the communicator + * Added by Jianwei Li + */ +#define MPI_COLLECTIVE_FH 2 +#define MPI_INDEPENDENT_FH 8 + +#define NC_collectiveFhOpened(nciop) \ + (fIsSet(nciop->mpioflags, MPI_COLLECTIVE_FH)) + +#define NC_independentFhOpened(nciop) \ + (fIsSet(nciop->mpioflags, MPI_INDEPENDENT_FH)) + +#define set_NC_collectiveFh(nciop) \ + fSet((nciop)->mpioflags, MPI_COLLECTIVE_FH) + +#define set_NC_independentFh(nciop) \ + fSet((nciop)->mpioflags, MPI_INDEPENDENT_FH) + + char* filename; + MPI_File collective_fh; + MPI_File independent_fh; + int mpiomode; + MPI_Comm comm; + MPI_Info mpiinfo; + int mpioflags; +#endif + + /* member functions do the work */ + + ncio_relfunc *NCIO_CONST rel; + + ncio_getfunc *NCIO_CONST get; + + ncio_movefunc *NCIO_CONST move; + + ncio_syncfunc *NCIO_CONST sync; + + ncio_freefunc *NCIO_CONST free; /* Implementation private */ + + /* + * A copy of the 'path' argument passed in to ncio_open() + * or ncio_create(). Used by ncabort() to remove (unlink) + * the file and by error messages. + */ + const char *path; + + /* implementation private stuff */ + void *NCIO_CONST pvt; +}; + +#undef NCIO_CONST + +extern ncio * +ncio_new(const char *path, int ioflags); + +extern void +ncio_free(ncio *nciop); + +#ifdef USE_MPIO /* Following interface changed by Jianwei Li */ + +#else + +extern int +ncio_create(const char *path, int ioflags, + size_t initialsz, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp); + +#endif /* USE_MPIO */ + +#ifdef USE_MPIO /* Following interface changed by Jianwei Li */ + +#else + +extern int +ncio_open(const char *path, + int ioflags, + off_t igeto, size_t igetsz, size_t *sizehintp, + ncio **nciopp, void **const igetvpp); + +#endif /* USE_MPIO */ + +extern int +ncio_close(ncio *nciop, int doUnlink); + +#endif /* _NCIO_H_ */ Index: /branches/SDM_SciDAC/src/lib/ncx.h =================================================================== --- /branches/SDM_SciDAC/src/lib/ncx.h (revision 2) +++ /branches/SDM_SciDAC/src/lib/ncx.h (revision 2) @@ -0,0 +1,661 @@ +/* + * Copyright 1996, University Corporation for Atmospheric Research + * See netcdf/COPYRIGHT file for copying and redistribution conditions. + */ +/* "$Id$" */ + +#ifndef _NCX_H_ +#define _NCX_H_ + +/* + * An external data representation interface. + * + * This started out as a general replacement for ONC XDR, + * specifically, the xdrmem family of functions. + * + * We eventually realized that we could write more portable + * code if we decoupled any association between the 'C' types + * and the external types. (XDR has this association between the 'C' + * types and the external representations, like xdr_int() takes + * an int argument and goes to an external int representation.) + * So, now there is a matrix of functions. + * + */ + +#include "ncconfig.h" /* output of 'configure' */ +#include "rnd.h" +#include /* size_t */ +#include +#include /* off_t */ + +#if defined(_CRAY) && !defined(_CRAYIEEE) +#define CRAYFLOAT 1 /* CRAY Floating point */ +#elif defined(_SX) && defined(_FLOAT2) /* NEC SUPER-UX in CRAY mode */ +#define CRAYFLOAT 1 /* CRAY Floating point */ +#endif + +/* + * The integer return code for the conversion routines + * is 0 (ENOERR) when no error occured, or NC_ERANGE as appropriate + * for an overflow conversion. + */ +#ifndef ENOERR +#define ENOERR 0 +#endif +#ifndef NC_ERANGE +#define NC_ERANGE (-60) /* N.B. must match value in netcdf.h */ +#endif +#ifndef NC_ENOMEM +#define NC_ENOMEM (-61) /* N.B. must match value in netcdf.h */ +#endif + + +/* + * External sizes of the primitive elements. + */ +#define X_SIZEOF_CHAR 1 +#define X_SIZEOF_SHORT 2 +#define X_SIZEOF_INT 4 /* xdr_int */ +#if 0 +#define X_SIZEOF_LONG 8 */ /* xdr_long_long */ +#endif +#define X_SIZEOF_FLOAT 4 +#define X_SIZEOF_DOUBLE 8 + +/* + * For now, netcdf is limited to 32 bit offsets and sizes, + * see also X_SIZE_MAX, X_OFF_MAX below + */ +#define X_SIZEOF_OFF_T X_SIZEOF_INT +#define X_SIZEOF_SIZE_T X_SIZEOF_INT + +/* + * limits of the external representation + */ +#define X_SCHAR_MIN (-128) +#define X_SCHAR_MAX 127 +#define X_UCHAR_MAX 255U +#define X_SHORT_MIN (-32768) +#define X_SHRT_MIN X_SHORT_MIN /* alias compatible with limits.h */ +#define X_SHORT_MAX 32767 +#define X_SHRT_MAX X_SHORT_MAX /* alias compatible with limits.h */ +#define X_USHORT_MAX 65535U +#define X_USHRT_MAX X_USHORT_MAX /* alias compatible with limits.h */ +#define X_INT_MIN (-2147483647-1) +#define X_INT_MAX 2147483647 +#define X_UINT_MAX 4294967295U +#if 0 +#define X_LONG_MIN (-2147483647-1) +#define X_LONG_MAX 2147483647 +#define X_ULONG_MAX 4294967295U +#endif +#define X_FLOAT_MAX 3.40282347e+38f +#define X_FLOAT_MIN (-X_FLOAT_MAX) +#define X_FLT_MAX X_FLOAT_MAX /* alias compatible with limits.h */ +#if CRAYFLOAT +/* ldexp(1. - ldexp(.5 , -46), 1024) */ +#define X_DOUBLE_MAX 1.79769313486230e+308 +#else +/* scalb(1. - scalb(.5 , -52), 1024) */ +#define X_DOUBLE_MAX 1.7976931348623157e+308 +#endif +#define X_DOUBLE_MIN (-X_DOUBLE_MAX) +#define X_DBL_MAX X_DOUBLE_MAX /* alias compatible with limits.h */ + +#define X_SIZE_MAX X_INT_MAX /* N.B., just uses the signed range */ +#define X_OFF_MAX X_INT_MAX + + +/* Begin ncx_len */ + +/* + * ncx_len_xxx() interfaces are defined as macros below, + * These give the length of an array of nelems of the type. + * N.B. The 'char' and 'short' interfaces give the X_ALIGNED length. + */ +#define X_ALIGN 4 /* a.k.a. BYTES_PER_XDR_UNIT */ + +#define ncx_len_char(nelems) \ + _RNDUP((nelems), X_ALIGN) + +#define ncx_len_short(nelems) \ + (((nelems) + (nelems)%2) * X_SIZEOF_SHORT) + +#define ncx_len_int(nelems) \ + ((nelems) * X_SIZEOF_INT) + +#define ncx_len_long(nelems) \ + ((nelems) * X_SIZEOF_LONG) + +#define ncx_len_float(nelems) \ + ((nelems) * X_SIZEOF_FLOAT) + +#define ncx_len_double(nelems) \ + ((nelems) * X_SIZEOF_DOUBLE) + +/* End ncx_len */ + +#if __CHAR_UNSIGNED__ + /* 'char' is unsigned, declare ncbyte as 'signed char' */ +typedef signed char schar; + +#else + /* 'char' is signed */ +typedef signed char schar; + +#endif /* __CHAR_UNSIGNED__ */ + +/* + * Primitive numeric conversion functions. + * The `put' functions convert from native internal + * type to the external type, while the `get' functions + * convert from the external to the internal. + * + * These take the form + * int ncx_get_{external_type}_{internal_type}( + * const void *xp, + * internal_type *ip + * ); + * int ncx_put_{external_type}_{internal_type}( + * void *xp, + * const internal_type *ip + * ); + * where + * `external_type' and `internal_type' chosen from + schar + uchar + short + ushort + int + uint + long + ulong + float + double + * + * Not all combinations make sense. + * We may not implement all combinations that make sense. + * The netcdf functions that use this ncx interface don't + * use these primitive conversion functions. They use the + * aggregate conversion functions declared below. + * + * Storage for a single element of external type is at the `void * xp' + * argument. + * + * Storage for a single element of internal type is at `ip' argument. + * + * These functions return 0 (ENOERR) when no error occured, + * or NC_ERANGE when the value being converted is too large. + * When NC_ERANGE occurs, an undefined (implementation dependent) + * conversion may have occured. + * + * Note that loss of precision may occur silently. + * + */ + +#if 0 +extern int +ncx_get_schar_schar(const void *xp, schar *ip); +extern int +ncx_get_schar_uchar(const void *xp, uchar *ip); +extern int +ncx_get_schar_short(const void *xp, short *ip); +extern int +ncx_get_schar_int(const void *xp, int *ip); +extern int +ncx_get_schar_long(const void *xp, long *ip); +extern int +ncx_get_schar_float(const void *xp, float *ip); +extern int +ncx_get_schar_double(const void *xp, double *ip); + +extern int +ncx_put_schar_schar(void *xp, const schar *ip); +extern int +ncx_put_schar_uchar(void *xp, const uchar *ip); +extern int +ncx_put_schar_short(void *xp, const short *ip); +extern int +ncx_put_schar_int(void *xp, const int *ip); +extern int +ncx_put_schar_long(void *xp, const long *ip); +extern int +ncx_put_schar_float(void *xp, const float *ip); +extern int +ncx_put_schar_double(void *xp, const double *ip); +#endif + + +extern int +ncx_get_short_schar(const void *xp, schar *ip); +extern int +ncx_get_short_uchar(const void *xp, uchar *ip); +extern int +ncx_get_short_short(const void *xp, short *ip); +extern int +ncx_get_short_int(const void *xp, int *ip); +extern int +ncx_get_short_long(const void *xp, long *ip); +extern int +ncx_get_short_float(const void *xp, float *ip); +extern int +ncx_get_short_double(const void *xp, double *ip); + +extern int +ncx_put_short_schar(void *xp, const schar *ip); +extern int +ncx_put_short_uchar(void *xp, const uchar *ip); +extern int +ncx_put_short_short(void *xp, const short *ip); +extern int +ncx_put_short_int(void *xp, const int *ip); +extern int +ncx_put_short_long(void *xp, const long *ip); +extern int +ncx_put_short_float(void *xp, const float *ip); +extern int +ncx_put_short_double(void *xp, const double *ip); + + +extern int +ncx_get_int_schar(const void *xp, schar *ip); +extern int +ncx_get_int_uchar(const void *xp, uchar *ip); +extern int +ncx_get_int_short(const void *xp, short *ip); +extern int +ncx_get_int_int(const void *xp, int *ip); +extern int +ncx_get_int_long(const void *xp, long *ip); +extern int +ncx_get_int_float(const void *xp, float *ip); +extern int +ncx_get_int_double(const void *xp, double *ip); + +extern int +ncx_put_int_schar(void *xp, const schar *ip); +extern int +ncx_put_int_uchar(void *xp, const uchar *ip); +extern int +ncx_put_int_short(void *xp, const short *ip); +extern int +ncx_put_int_int(void *xp, const int *ip); +extern int +ncx_put_int_long(void *xp, const long *ip); +extern int +ncx_put_int_float(void *xp, const float *ip); +extern int +ncx_put_int_double(void *xp, const double *ip); + + +extern int +ncx_get_float_schar(const void *xp, schar *ip); +extern int +ncx_get_float_uchar(const void *xp, uchar *ip); +extern int +ncx_get_float_short(const void *xp, short *ip); +extern int +ncx_get_float_int(const void *xp, int *ip); +extern int +ncx_get_float_long(const void *xp, long *ip); +extern int +ncx_get_float_float(const void *xp, float *ip); +extern int +ncx_get_float_double(const void *xp, double *ip); + +extern int +ncx_put_float_schar(void *xp, const schar *ip); +extern int +ncx_put_float_uchar(void *xp, const uchar *ip); +extern int +ncx_put_float_short(void *xp, const short *ip); +extern int +ncx_put_float_int(void *xp, const int *ip); +extern int +ncx_put_float_long(void *xp, const long *ip); +extern int +ncx_put_float_float(void *xp, const float *ip); +extern int +ncx_put_float_double(void *xp, const double *ip); + + +extern int +ncx_get_double_schar(const void *xp, schar *ip); +extern int +ncx_get_double_uchar(const void *xp, uchar *ip); +extern int +ncx_get_double_short(const void *xp, short *ip); +extern int +ncx_get_double_int(const void *xp, int *ip); +extern int +ncx_get_double_long(const void *xp, long *ip); +extern int +ncx_get_double_float(const void *xp, float *ip); +extern int +ncx_get_double_double(const void *xp, double *ip); + +extern int +ncx_put_double_schar(void *xp, const schar *ip); +extern int +ncx_put_double_uchar(void *xp, const uchar *ip); +extern int +ncx_put_double_short(void *xp, const short *ip); +extern int +ncx_put_double_int(void *xp, const int *ip); +extern int +ncx_put_double_long(void *xp, const long *ip); +extern int +ncx_put_double_float(void *xp, const float *ip); +extern int +ncx_put_double_double(void *xp, const double *ip); + + +/* + * Other primitive conversion functions + * N.B. slightly different interface + * Used by netcdf. + */ + +/* ncx_get_int_size_t */ +extern int +ncx_get_size_t(const void **xpp, size_t *ulp); +/* ncx_get_int_off_t */ +extern int +ncx_get_off_t(const void **xpp, off_t *lp); + +/* ncx_put_int_size_t */ +extern int +ncx_put_size_t(void **xpp, const size_t *ulp); +/* ncx_put_int_off_t */ +extern int +ncx_put_off_t(void **xpp, const off_t *lp); + + +/* + * Aggregate numeric conversion functions. + * Convert an array. Replaces xdr_array(...). + * These functions are used by netcdf. Unlike the xdr + * interface, we optimize for aggregate conversions. + * This functions should be implemented to take advantage + * of multiple processor / parallel hardware where available. + * + * These take the form + * int ncx_getn_{external_type}_{internal_type}( + * const void *xpp, + * size_t nelems, + * internal_type *ip + * ); + * int ncx_putn_{external_type}_{internal_type}( + * void **xpp, + * size_t nelems, + * const internal_type *ip + * ); + * Where the types are as in the primitive numeric conversion functions. + * + * The value of the pointer to pointer argument, *xpp, is + * expected to reference storage for `nelems' of the external + * type. On return, it modified to reference just past the last + * converted external element. + * + * The types whose external size is less than X_ALIGN also have `pad' + * interfaces. These round (and zero fill on put) *xpp up to X_ALIGN + * boundaries. (This is the usual xdr behavior.) + * + * The `ip' argument should point to an array of `nelems' of + * internal_type. + * + * Range errors (NC_ERANGE) for a individual values in the array + * DO NOT terminate the array conversion. All elements are converted, + * with some having undefined values. + * If any range error occurs, the function returns NC_ERANGE. + * + */ + +extern int +ncx_getn_schar_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_getn_schar_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_getn_schar_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_getn_schar_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_getn_schar_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_getn_schar_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_getn_schar_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_pad_getn_schar_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_pad_getn_schar_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_pad_getn_schar_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_pad_getn_schar_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_pad_getn_schar_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_pad_getn_schar_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_pad_getn_schar_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_putn_schar_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_putn_schar_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_putn_schar_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_putn_schar_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_putn_schar_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_putn_schar_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_putn_schar_double(void **xpp, size_t nelems, const double *ip); + +extern int +ncx_pad_putn_schar_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_pad_putn_schar_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_pad_putn_schar_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_pad_putn_schar_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_pad_putn_schar_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_pad_putn_schar_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_pad_putn_schar_double(void **xpp, size_t nelems, const double *ip); + + +extern int +ncx_getn_short_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_getn_short_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_getn_short_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_getn_short_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_getn_short_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_getn_short_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_getn_short_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_pad_getn_short_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_pad_getn_short_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_pad_getn_short_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_pad_getn_short_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_pad_getn_short_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_pad_getn_short_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_pad_getn_short_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_putn_short_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_putn_short_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_putn_short_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_putn_short_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_putn_short_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_putn_short_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_putn_short_double(void **xpp, size_t nelems, const double *ip); + +extern int +ncx_pad_putn_short_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_pad_putn_short_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_pad_putn_short_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_pad_putn_short_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_pad_putn_short_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_pad_putn_short_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_pad_putn_short_double(void **xpp, size_t nelems, const double *ip); + + +extern int +ncx_getn_int_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_getn_int_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_getn_int_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_getn_int_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_getn_int_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_getn_int_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_getn_int_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_putn_int_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_putn_int_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_putn_int_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_putn_int_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_putn_int_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_putn_int_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_putn_int_double(void **xpp, size_t nelems, const double *ip); + + +extern int +ncx_getn_float_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_getn_float_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_getn_float_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_getn_float_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_getn_float_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_getn_float_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_getn_float_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_putn_float_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_putn_float_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_putn_float_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_putn_float_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_putn_float_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_putn_float_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_putn_float_double(void **xpp, size_t nelems, const double *ip); + + +extern int +ncx_getn_double_schar(const void **xpp, size_t nelems, schar *ip); +extern int +ncx_getn_double_uchar(const void **xpp, size_t nelems, uchar *ip); +extern int +ncx_getn_double_short(const void **xpp, size_t nelems, short *ip); +extern int +ncx_getn_double_int(const void **xpp, size_t nelems, int *ip); +extern int +ncx_getn_double_long(const void **xpp, size_t nelems, long *ip); +extern int +ncx_getn_double_float(const void **xpp, size_t nelems, float *ip); +extern int +ncx_getn_double_double(const void **xpp, size_t nelems, double *ip); + +extern int +ncx_putn_double_schar(void **xpp, size_t nelems, const schar *ip); +extern int +ncx_putn_double_uchar(void **xpp, size_t nelems, const uchar *ip); +extern int +ncx_putn_double_short(void **xpp, size_t nelems, const short *ip); +extern int +ncx_putn_double_int(void **xpp, size_t nelems, const int *ip); +extern int +ncx_putn_double_long(void **xpp, size_t nelems, const long *ip); +extern int +ncx_putn_double_float(void **xpp, size_t nelems, const float *ip); +extern int +ncx_putn_double_double(void **xpp, size_t nelems, const double *ip); + + +/* + * Other aggregate conversion functions. + */ + +/* read ASCII characters */ +extern int +ncx_getn_text(const void **xpp, size_t nchars, char *cp); +extern int +ncx_pad_getn_text(const void **xpp, size_t nchars, char *cp); + +/* write ASCII characters */ +extern int +ncx_putn_text(void **xpp, size_t nchars, const char *cp); +extern int +ncx_pad_putn_text(void **xpp, size_t nchars, const char *cp); + +/* for symmetry */ +#define ncx_getn_char_char(xpp, nelems, fillp) ncx_getn_text(xpp, nelems, fillp) +#define ncx_putn_char_char(xpp, nelems, fillp) ncx_putn_text(xpp, nelems, fillp) + +/* read opaque data */ +extern int +ncx_getn_void(const void **xpp, size_t nchars, void *vp); +extern int +ncx_pad_getn_void(const void **xpp, size_t nchars, void *vp); + +/* write opaque data */ +extern int +ncx_putn_void(void **xpp, size_t nchars, const void *vp); +extern int +ncx_pad_putn_void(void **xpp, size_t nchars, const void *vp); + +#endif /* _NCX_H_ */ Index: /branches/SDM_SciDAC/src/Makefile =================================================================== --- /branches/SDM_SciDAC/src/Makefile (revision 2) +++ /branches/SDM_SciDAC/src/Makefile (revision 2) @@ -0,0 +1,9 @@ +all: + cd lib && $(MAKE) + +distclean: clean +clean: + cd lib && $(MAKE) clean + +install: + cd lib && $(MAKE) install Index: /branches/SDM_SciDAC/man/netcdf.m4 =================================================================== --- /branches/SDM_SciDAC/man/netcdf.m4 (revision 2) +++ /branches/SDM_SciDAC/man/netcdf.m4 (revision 2) @@ -0,0 +1,1207 @@ +divert(-1) + +changequote(<<,>>) +define(<>, defn(index)) + +define(<>, <<\fB$1\fR>>) + +define(<>, <<\fI$1\fP>>) + +define(<>, + <>) + +define(<>, + <> "HEADER_FILE($1)", + <<<>>> HEADER_FILE($1))>>) + +define(<>, + <>) + +define(<>, + <>) + +define(<>, + <>) + +define(<>, + <>) + +define(<>, + <>) + +define(<>, + <>) + +dnl AQUAL(io, rank) +define(<>, <>)>>)>>) + +dnl CTYPE(type) +define(<>, + <>)>>)>>)>>)>>)>>)>>)>>)>>)>>)>>) + +dnl CSTAR(io, rank) +define(<>, <>)>>) + +dnl FTYPE(type, rank) +define(<>, + <>, + <>)>>)>>)>>)>>)>>)>>)>>)>>)>>) + +dnl ATYPE(io,rank,type) +define(<>, <>CSTAR($1,$2)>>, + <>)>>) + +dnl AID(name, rank, type) +define(<>, <>ifelse(API,C, + <>, + <>)>>)>>) + +dnl ADECL(io, rank, type, name) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) + +dnl CCOMP(type) +define(<>, + <>)>>)>>)>>)>>)>>)>>)>>) + +dnl FCOMP(type) +define(<>, + <>)>>)>>)>>)>>)>>) + +dnl COMP(type) +define(<>, <>,<>)>>) + +define(<>, + <>) + +dnl DECL(return-type, name, argument-list) +define(<>, <>) + +dnl FDECL(name, argument-list) +define(<>, <>) + +dnl IODECL(name, type, argument-list) +define(<>, <>COMP($2), $3)>>) + +dnl FREF(name) +define(<>, <>) + +dnl FOLD(cname, fname) +define(<>, <>) + +dnl Function Input Arguments: +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>)>>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, ITEXTV(path)) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, <>) +define(<>, <>) + +dnl Function Output Arguments: +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>)>>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +dnl Argument References: +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>)>>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>>>)>>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) +define(<>, <>) + +define(<>, +<>) + +dnl Variable "Put" Functions: +define(<>, <>UPCASE($1)<<>>ifelse($2,1,,V)(ifelse($2,1,*)out)>>) +define(<>, <>) +define(<>, <>) +define(<>,<>)>>) +define(<>,<>)>>) +define(<>,<>)>>) +define(<>,<>)>>) + +dnl Variable "Get" Functions: +define(<>, <>UPCASE($1)<<>>ifelse($2,1,,V)(in)>>) +define(<>, <>) +define(<>, <>) +define(<>,<>)>>) +define(<>,<>)>>) +define(<>,<>)>>) +define(<>,<>)>>) + +dnl Attribute "Put" Functions: +define(<>, <>UPCASE($1)<<>>V(out)>>) +define(<>,<>) + +dnl Attribute "Get" Functions: +define(<>, <>UPCASE($1)<<>>V(in)>>) +define(<>,<>) + +dnl Function Family Listing: +define(<>, +<<.HP +$1(text) +ifelse(API,C, +<<.HP +$1(uchar)>>) +.HP +$1(schar) +.HP +$1(short) +.HP +$1(int) +ifelse(API,C, +<<.HP +$1(long)>>) +.HP +$1(float) +.HP +$1(double)>>) + +divert(0)dnl +.TH NETCDF 3 "18 April 1997" "Printed: \n(yr.\n(mo.\n(dy" "UNIDATA LIBRARY FUNCTIONS" +.SH N<<>>AME +netcdf \- Unidata Network Common Data Form (netCDF) library, version 3 interface +.SH SYNOPSIS +.ft B +.na +.nh +INCLUDE(netcdf) +.sp +ifelse(API,C,, +.SS Most Systems:) +COMPILER() ... -lnetcdf +ifelse(API,C,, +.sp +.SS CRAY PVP Systems: +f90 -dp -i64 ... -lnetcdf +) +.ad +.hy +.SH "LIBRARY VERSION" +.LP +This document describes version 3 of Unidata netCDF data-access interface +for the LANGUAGE() programming language. +.HP +DECL(RETSTR(), inq_libvers, (VOID_ARG)) +.sp +Returns a string identifying the version of the netCDF library, and +when it was built, like: "3.1a of Aug 22 1996 12:57:47 $". +.LP +The RCS \fBident(1)\fP command will find a string like +"$\|Id: @\|(#) netcdf library version 3.1a of Sep 6 1996 15:56:26 $" +in the library. The SCCS \fBwhat(1)\fP command will find a string like +"netcdf library version 3.1a of Aug 23 1996 16:07:40 $". +.SH "RETURN VALUES" +.LP +All netCDF functions (except +FREF(inq_libvers) and FREF(strerror)) return an integer status. +This behavior replaces the +ifelse(API,C, <>, <> argument) +used in previous versions of the library. +If this returned status value is not equal to +MACRO(NOERR) (zero), it +indicates that an error occurred. The possible status values are defined in +ifelse(API,C, system <<<>>> file and in )<<>>dnl +ifelse(API,C,")HEADER_FILE(netcdf)<<>>ifelse(API,C,"). +.HP +DECL(RETSTR(), strerror, (ISTATUS())) +.sp +Returns a string textual translation of the \fIstatus\fP +value, like "Attribute or variable name contains illegal characters" +or "No such file or directory". +.HP +FDECL(create, (ICOMM(), IPATH(), ICMODE(), IINFO(), +ONCID())) +.sp +(Corresponds to FOLD(create, cre) in version 2) +.sp +Creates a new netCDF dataset at ARG(path), +returning a netCDF ID in ARG(ncid). +The argument ARG(cmode) may <> the bitwise-or +of the following flags: +MACRO(NOCLOBBER) +to protect existing datasets (default +silently blows them away), +MACRO(SHARE) +for synchronous dataset updates +(default is to buffer accesses), and +MACRO(LOCK) +(not yet implemented). +When a netCDF dataset is created, is is opened +MACRO(WRITE). +The new netCDF dataset is in <> mode. +.HP +FDECL(_create, (IPATH(), ICMODE(), IINITSIZE(), OCHUNKSIZE(), ONCID())) +.sp +Like FREF(create) but has additional performance tuning parameters. +.sp +The argument ARG(initialsize) sets the initial size of the file at +creation time. +.sp +See FREF(_open) below for an explanation of the ARG(chunksize) +parameter. +.HP +FDECL(open, (ICOMM(), IPATH(), IMODE(), IINFO(), ONCID())) +.sp +(Corresponds to FOLD(open, opn) in version 2) +.sp +Opens a existing netCDF dataset at ARG(path) +returning a netCDF ID +in ARG(ncid). +The type of access is described by the ARG(mode) parameter, +which may <> the bitwise-or +of the following flags: +MACRO(WRITE) +for read-write access (default +read-only), +MACRO(SHARE) +for synchronous dataset updates (default is +to buffer accesses), and +MACRO(LOCK) +(not yet implemented). +.HP +FDECL(_open, (IPATH(), IMODE(), OCHUNKSIZE(), ONCID())) +.sp +Like FREF(open) but has an additional performance tuning parameter. +.sp +The argument referenced by ARG(chunksize) controls a space versus time +tradeoff, memory allocated in the netcdf library versus number of system +calls. +Because of internal requirements, the value may not be set to exactly +the value requested. +The actual value chosen is returned by reference. +Using the value MACRO(SIZEHINT_DEFAULT) causes the library to choose a +default. +How the system choses the default depends on the system. +On many systems, the "preferred I/O block size" is available from the +CODE(stat()) system call, CODE(struct stat) member CODE(st_blksize). +If this is available it is used. Lacking that, twice the system pagesize +is used. +Lacking a call to discover the system pagesize, we just set default +chunksize to 8192. +.sp +The chunksize is a property of a given open netcdf descriptor +ARG(ncid), it is not a persistent property of the netcdf dataset. +.HP +FDECL(redef, (INCID())) +.sp +(Corresponds to FOLD(redef, redf) in version 2) +.sp +Puts an open netCDF dataset into <> mode, +so dimensions, variables, and attributes can be added or renamed and +attributes can be deleted. +.HP +FDECL(enddef, (INCID())) +.sp +(Corresponds to FOLD(endef, endf) in version 2) +.sp +Takes an open netCDF dataset out of <> mode. +The changes made to the netCDF dataset +while it was in <> mode are checked and committed to disk if no +problems occurred. Some data values may be written as well, +see "VARIABLE PREFILLING" below. +After a successful call, variable data can be read or written to the dataset. +.HP +FDECL(_enddef, (INCID(), IH_MINFREE(), IV_ALIGN(), IV_MINFREE(), IR_ALIGN())) +.sp +Like FREF(enddef) but has additional performance tuning parameters. +.sp +Caution: this function exposes internals of the netcdf version 1 file +<>. +It may not be available on future netcdf implementations. +.sp +The current netcdf file <> has three sections, +the "header" section, the data section for fixed size variables, and +the data section for variables which have an unlimited dimension (record +variables). +The header begins at the beginning of the file. The index +(offset) of the beginning of the other two sections is contained in the +header. Typically, there is no space between the sections. This causes +copying overhead to accrue if one wishes to change the size of the +sections, +as may happen when changing names of things, text attribute values, +adding +attributes or adding variables. Also, for buffered i/o, there may be +advantages +to aligning sections in certain ways. +.sp +The minfree parameters allow one to control costs of future calls +to FREF(redef), FREF(enddef) by requesting that ARG(minfree) bytes be +available at the end of the section. +The ARG(h_minfree) parameter sets the pad +at the end of the "header" section. The ARG(v_minfree) parameter sets +the pad at the end of the data section for fixed size variables. +.sp +The align parameters allow one to set the alignment of the beginning of +the corresponding sections. The beginning of the section is rounded up +to an index which is a multiple of the align parameter. The flag value +MACRO(ALIGN_CHUNK) tells the library to use the chunksize (see above) +as the align parameter. +The ARG(v_align) parameter controls the alignment of the beginning of +the data section for fixed size variables. +The ARG(r_align) parameter controls the alignment of the beginning of +the data section for variables which have an unlimited dimension (record +variables). +.sp +The file <> requires mod 4 alignment, so the align parameters +are silently rounded up to multiples of 4. The usual call, +CODE(FNAME(enddef)(NCID())) +is equivalent to +CODE(FNAME(_enddef)(NCID(), 0, 4, 0, 4)). +.sp +The file <> does not contain a "record size" value, this is +calculated from the sizes of the record variables. This unfortunate fact +prevents us from providing minfree and alignment control of the +"records" +in a netcdf file. If you add a variable which has an unlimited +dimension, +the third section will always be copied with the new variable added. +.HP +FDECL(sync, (INCID())) +.sp +(Corresponds to FOLD(sync, snc) in version 2) +.sp +Unless the +MACRO(SHARE) +bit is set in +FREF(open) or FREF(create), +accesses to the underlying netCDF dataset are +buffered by the library. This function synchronizes the state of +the underlying dataset and the library. +This is done automatically by +FREF(close) and FREF(enddef). +.HP +FDECL(abort, (INCID())) +.sp +(Corresponds to FOLD(abort, abor) in version 2) +.sp +You don't need to call this function. +This function is called automatically by +FREF(close) +if the netCDF was in <> mode and something goes wrong with the commit. +If the netCDF dataset isn't in <> mode, then this function is equivalent to +FREF(close). +If it is called after +FREF(redef), +but before +FREF(enddef), +the new definitions are not committed and the dataset is closed. +If it is called after +FREF(create) +but before +FREF(enddef), +the dataset disappears. +.HP +FDECL(close, (INCID())) +.sp +(Corresponds to +FOLD(close, clos) in version 2) +.sp +Closes an open netCDF dataset. +If the dataset is in <> mode, +FREF(enddef) +will be called before closing. +After a dataset is closed, its ID may be reassigned to another dataset. +.HP +FDECL(inq, (INCID(), ONDIMS(), ONVARS(), +ONATTS(), OUNLIMDIMID())) +.HP +FDECL(inq_ndims, (INCID(), ONDIMS())) +.HP +FDECL(inq_nvars, (INCID(), ONVARS())) +.HP +FDECL(inq_natts, (INCID(), ONATTS())) +.HP +FDECL(inq_unlimdim, (INCID(), OUNLIMDIMID())) +.sp +(Replace FOLD(inquire, inq) in version 2) +.sp +Use these functions to find out what is in a netCDF dataset. +Upon successful return, +NDIMS() will contain the +number of dimensions defined for this netCDF dataset, +NVARS() will contain the number of variables, +NATTS() will contain the number of attributes, and +UNLIMDIMID() will contain the +dimension ID of the unlimited dimension if one exists, or +ifelse(API,C, <<-1>>, <<0>>) otherwise. +ifelse(API,C, +<>) +.HP +FDECL(def_dim, (INCID(), INAME(), ILEN(), ODIMID())) +.sp +(Corresponds to FOLD(dimdef, ddef) in version 2) +.sp +Adds a new dimension to an open netCDF dataset, which must be +in <> mode. +NAME() is the dimension name. +ifelse(API,C,dnl +<>)<<>>dnl +DIMID() will contain the dimension ID of the newly created dimension. +.HP +FDECL(inq_dimid, (INCID(), INAME(), ODIMID())) +.sp +(Corresponds to FOLD(dimid, did) in version 2) +.sp +Given a dimension name, returns the ID of a netCDF dimension in DIMID(). +.HP +FDECL(inq_dim, (INCID(), IDIMID(), ONAME(), OLEN())) +.HP +FDECL(inq_dimname, (INCID(), IDIMID(), ONAME())) +.HP +FDECL(inq_dimlen, (INCID(), IDIMID(), OLEN())) +.sp +(Replace FOLD(diminq, dinq) in version 2) +.sp +Use these functions to find out about a dimension. +ifelse(API,C, +<>) +NAME() should be big enough (MACRO(MAX_NAME)) +to hold the dimension name as the name will be copied into your storage. +The length return parameter, LEN() +will contain the size of the dimension. +For the unlimited dimension, the returned length is the current +maximum value used for writing into any of the variables which use +the dimension. +.HP +FDECL(rename_dim, (INCID(), IDIMID(), INAME())) +.sp +(Corresponds to FOLD(dimrename, dren) in version 2) +.sp +Renames an existing dimension in an open netCDF dataset. +If the new name is longer than the old name, the netCDF dataset must be in +<> mode. +You cannot rename a dimension to have the same name as another dimension. +.HP +FDECL(def_var, (INCID(), INAME(), IXTYPE(), INDIMS(), IDIMIDS(), OVARID())) +.sp +(Corresponds to FOLD(vardef, vdef) in version 2) +.sp +Adds a new variable to a netCDF dataset. The netCDF must be in <> mode. +ifelse(API,C, <>)dnl +VARID() will be set to the netCDF variable ID. +.HP +FDECL(inq_varid, (INCID(), INAME(), OVARID())) +.sp +(Corresponds to FOLD(varid, vid) in version 2) +.sp +Returns the ID of a netCDF variable in VARID() given its name. +.HP +FDECL(inq_var, (INCID(), IVARID(), ONAME(), OXTYPE(), ONDIMS(), ODIMIDS(), +ONATTS())) +.HP +FDECL(inq_varname, (INCID(), IVARID(), ONAME())) +.HP +FDECL(inq_vartype, (INCID(), IVARID(), OXTYPE())) +.HP +FDECL(inq_varndims, (INCID(), IVARID(), ONDIMS())) +.HP +FDECL(inq_vardimid, (INCID(), IVARID(), ODIMIDS())) +.HP +FDECL(inq_varnatts, (INCID(), IVARID(), ONATTS())) +.sp +(Replace FOLD(varinq, vinq) in version 2) +.sp +Returns information about a netCDF variable, given its ID. +ifelse(API,C, +<>) +.HP +FDECL(rename_var, (INCID(), IVARID(), INAME())) +.sp +(Corresponds to FOLD(varrename, vren) in version 2) +.sp +Changes the name of a netCDF variable. +If the new name is longer than the old name, the netCDF must be in <> mode. +You cannot rename a variable to have the name of any existing variable. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(varput, vpt) in version 2) +.sp +Writes an entire netCDF variable (i.e. all the values). +The netCDF dataset must be open and in data mode. The type of the data is +specified in the function name, and it is converted to the external type +of the specified variable, if possible, otherwise an +MACRO(ERANGE) error is returned. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(varget, vgt) in version 2) +.sp +Reads an entire netCDF variable (i.e. all the values). +The netCDF dataset must be open and in data mode. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an MACRO(ERANGE) error is returned. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(varput1, vpt1) in version 2) +.sp +Puts a single data value into a variable at the position INDEX() of an +open netCDF dataset that is in data mode. The type of the data is +specified in the function name, and it is converted to the external type +of the specified variable, if possible, otherwise an MACRO(ERANGE) +error is returned. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(varget1, vgt1) in version 2) +.sp +Gets a single data value from a variable at the position INDEX() +of an open netCDF dataset that is in data mode. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an MACRO(ERANGE) error is returned. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(varput, vpt) in version 2) +.sp +Writes an array section of values into a netCDF variable of an open +netCDF dataset, which must be in data mode. The array section is specified +by the START() and COUNT() vectors, which give the starting <> +and count of values along each dimension of the specified variable. +The type of the data is +specified in the function name and is converted to the external type +of the specified variable, if possible, otherwise an MACRO(ERANGE) +error is returned. +FUNC_FAMILY(<>) +.sp +(Corresponds to FOLD(varget, vgt) in version 2) +.sp +Reads an array section of values from a netCDF variable of an open +netCDF dataset, which must be in data mode. The array section is specified +by the START() and COUNT() vectors, which give the starting <> +and count of values along each dimension of the specified variable. +The data is converted from the external type of the specified variable, +if necessary, to the type specified in the function name. If conversion is +not possible, an MACRO(ERANGE) error is returned. +FUNC_FAMILY(<>) +.sp +(Corresponds to FOLD(varputg, vptg) in version 2) +.sp +These functions are used for \fIstrided output\fP, which is like the +array section output described above, except that +the sampling stride (the interval between accessed values) is +specified for each dimension. +For an explanation of the sampling stride +vector, see COMMON ARGUMENTS DESCRIPTIONS below. +FUNC_FAMILY(<>) +.sp +(Corresponds to FOLD(vargetg, vgtg) in version 2) +.sp +These functions are used for \fIstrided input\fP, which is like the +array section input described above, except that +the sampling stride (the interval between accessed values) is +specified for each dimension. +For an explanation of the sampling stride +vector, see COMMON ARGUMENTS DESCRIPTIONS below. +FUNC_FAMILY(<>) +.sp +(Corresponds to FOLD(varputg, vptg) in version 2) +.sp +These functions are used for \fImapped output\fP, which is like +strided output described above, except that an additional <> mapping +vector is provided to specify the in-memory arrangement of the data +values. +For an explanation of the <> +mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below. +FUNC_FAMILY(<>) +.sp +(Corresponds to FOLD(vargetg, vgtg) in version 2) +.sp +These functions are used for \fImapped input\fP, which is like +strided input described above, except that an additional <> mapping +vector is provided to specify the in-memory arrangement of the data +values. +For an explanation of the <> +mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(attput, apt) in version 2) +.sp +Unlike variables, attributes do not have +separate functions for defining and writing values. +This family of functions defines a new attribute with a value or changes +the value of an existing attribute. +If the attribute is new, or if the space required to +store the attribute value is greater than before, +the netCDF dataset must be in <> mode. +The parameter LEN() is the number of values from OUT() to transfer. +It is often one, except that for +FREF(put_att_text) it will usually be +ifelse(API,C, <>, <>) +.sp +For these functions, the type component of the function name refers to +the in-memory type of the value, whereas the XTYPE() argument refers to the +external type for storing the value. An MACRO(ERANGE) +error results if +a conversion between these types is not possible. In this case the value +is represented with the appropriate fill-value for the associated +external type. +.HP +FDECL(inq_attname, (INCID(), IVARID(), IATTNUM(), ONAME())) +.sp +(Corresponds to FOLD(attname, anam) in version 2) +.sp +Gets the +name of an attribute, given its variable ID and attribute number. +This function is useful in generic applications that +need to get the names of all the attributes associated with a variable, +since attributes are accessed by name rather than number in all other +attribute functions. The number of an attribute is more volatile than +the name, since it can change when other attributes of the same variable +are deleted. The attributes for each variable are numbered +from ifelse(API,C,0,1) (the first attribute) to +NVATTS()<<>>ifelse(API,C,-1), +where NVATTS() is +the number of attributes for the variable, as returned from a call to +FREF(inq_varnatts). +ifelse(API,C, +<>) +.HP +FDECL(inq_att, (INCID(), IVARID(), INAME(), OXTYPE(), OLEN())) +.HP +FDECL(inq_attid, (INCID(), IVARID(), INAME(), OATTNUM())) +.HP +FDECL(inq_atttype, (INCID(), IVARID(), INAME(), OXTYPE())) +.HP +FDECL(inq_attlen, (INCID(), IVARID(), INAME(), OLEN())) +.sp +(Corresponds to FOLD(attinq, ainq) in version 2) +.sp +These functions return information about a netCDF attribute, +given its variable ID and name. The information returned is the +external type in XTYPE() +and the number of elements in the attribute as LEN(). +ifelse(API,C, +<>) +.HP +FDECL(copy_att, (INCID(), IVARIDIN(), INAME(), INCIDOUT(), IVARIDOUT())) +.sp +(Corresponds to FOLD(attcopy, acpy) in version 2) +.sp +Copies an +attribute from one netCDF dataset to another. It can also be used to +copy an attribute from one variable to another within the same netCDF. +NCIDIN() is the netCDF ID of an input netCDF dataset from which the +attribute will be copied. +VARIDIN() +is the ID of the variable in the input netCDF dataset from which the +attribute will be copied, or MACRO(GLOBAL) +for a global attribute. +NAME() +is the name of the attribute in the input netCDF dataset to be copied. +NCIDOUT() +is the netCDF ID of the output netCDF dataset to which the attribute will be +copied. +It is permissible for the input and output netCDF ID's to be the same. The +output netCDF dataset should be in <> mode if the attribute to be +copied does not already exist for the target variable, or if it would +cause an existing target attribute to grow. +VARIDOUT() +is the ID of the variable in the output netCDF dataset to which the attribute will +be copied, or MACRO(GLOBAL) to copy to a global attribute. +.HP +FDECL(rename_att, (INCID(), IVARID(), INAME(), INEWNAME())) +.sp +(Corresponds to FOLD(attrename, aren) +.sp +Changes the +name of an attribute. If the new name is longer than the original name, +the netCDF must be in <> mode. You cannot rename an attribute to +have the same name as another attribute of the same variable. +NAME() is the original attribute name. +NEWNAME() +is the new name to be assigned to the specified attribute. If the new name +is longer than the old name, the netCDF dataset must be in <> mode. +.HP +FDECL(del_att, (INCID(), IVARID(), INAME())) +.sp +(Corresponds to FOLD(attdel, adel) in version 2) +.sp +Deletes an attribute from a netCDF dataset. The dataset must be in +<> mode. +FUNC_FAMILY(<>) +.sp +(Replace FOLD(attget, agt) in version 2) +.sp +Gets the value(s) of a netCDF attribute, given its +variable ID and name. Converts from the external type to the type +specified in +the function name, if possible, otherwise returns an MACRO(ERANGE) +error. +All elements of the vector of attribute +values are returned, so you must allocate enough space to hold +them. If you don't know how much space to reserve, call +FREF(inq_attlen) +first to find out the length of the attribute. +.SH "COMMON ARGUMENT DESCRIPTIONS" +.LP +In this section we <> some common arguments which are used in the +"FUNCTION DESCRIPTIONS" section. +.TP +INCID() +is the netCDF ID returned from a previous, successful call to +FREF(open) or FREF(create) +.TP +ONAME() +is the name of a dimension, variable, or attribute. +It shall begin with an alphabetic character, followed by +zero or more alphanumeric characters including the underscore +(`_') or hyphen (`-'). Case is significant. +ifelse(API,C,<>) +The maximum allowable number of characters +ifelse(API,C,(excluding the terminating 0)) is MACRO(MAX_NAME). +Names that begin with an underscore (`_') are reserved for use +by the netCDF interface. +.TP +IXTYPE() +specifies the external data type of a netCDF variable or attribute and +is one of the following: +MACRO(BYTE), MACRO(CHAR), MACRO(SHORT), MACRO(INT), +MACRO(FLOAT), or MACRO(DOUBLE). +These are used to specify 8-bit integers, +characters, 16-bit integers, 32-bit integers, 32-bit IEEE floating point +numbers, and 64-bit IEEE floating-point numbers, respectively. +ifelse(API,C, +<<(MACRO(INT) corresponds to MACRO(LONG) in version 2, to specify a +32-bit integer).>>) +.TP +ODIMIDS() +is a vector of dimension ID's and defines the shape of a netCDF variable. +The size of the vector shall be greater than or equal to the +rank (i.e. the number of dimensions) of the variable (NDIMS()). +The vector shall be ordered by the speed with which a dimension varies: +DIMIDS()<<>>ifelse(API,C,<<[NDIMS()-1]>>,<<(1)>>) +shall be the dimension ID of the most rapidly +varying dimension and +DIMIDS()<<>>ifelse(API,C,<<[0]>>,<<(NDIMS())>>) +shall be the dimension ID of the most slowly +varying dimension. +The maximum possible number of +dimensions for a variable is given by the symbolic constant +MACRO(MAX_VAR_DIMS). +.TP +IDIMID() +is the ID of a netCDF dimension. +netCDF dimension ID's are allocated sequentially from the +ifelse(API,C,non-negative, positive) +integers beginning with ifelse(API,C,0,1). +.TP +INDIMS() +is either the total number of dimensions in a netCDF dataset or the rank +(i.e. the number of dimensions) of a netCDF variable. +The value shall not be negative or greater than the symbolic constant +MACRO(MAX_VAR_DIMS). +.TP +IVARID() +is the ID of a netCDF variable or (for the attribute-access functions) +the symbolic constant +MACRO(GLOBAL), +which is used to reference global attributes. +netCDF variable ID's are allocated sequentially from the +ifelse(API,C,non-negative,positive) +integers beginning with ifelse(API,C,0,1). +.TP +ONATTS() +is the number of global attributes in a netCDF dataset for the +FREF(inquire) +function or the number +of attributes associated with a netCDF variable for the +FREF(varinq) +function. +.TP +IINDEX() +specifies the indicial coordinates of the netCDF data value to be accessed. +The indices start at ifelse(API,C,0,1); +thus, for example, the first data value of a +two-dimensional variable is ifelse(API,C,(0,0),(1,1)). +The size of the vector shall be at least the rank of the associated +netCDF variable and its elements shall correspond, in order, to the +variable's dimensions. +.TP +ISTART() +specifies the starting point +for accessing a netCDF variable's data values +in terms of the indicial coordinates of +the corner of the array section. +The indices start at ifelse(API,C,0,1); +thus, the first data +value of a variable is ifelse(API,C,(0, 0, ..., 0),(1, 1, ..., 1)). +The size of the vector shall be at least the rank of the associated +netCDF variable and its elements shall correspond, in order, to the +variable's dimensions. +.TP +ICOUNT() +specifies the number of indices selected along each dimension of the +array section. +Thus, to access a single value, for example, specify COUNT() as +(1, 1, ..., 1). +Note that, for strided I/O, this argument must be adjusted +to be compatible with the STRIDE() and START() arguments so that +the interaction of the +three does not attempt to access an invalid data co-ordinate. +The elements of the +COUNT() vector correspond, in order, to the variable's dimensions. +.TP +ISTRIDE() +specifies the sampling interval along each dimension of the netCDF +variable. The elements of the stride vector correspond, in order, +to the netCDF variable's dimensions (ARG(stride)<<>>ifelse(API,C,[0],<<(1)>>)) +gives the sampling interval along the most ifelse(API,C,slowly,rapidly) +varying dimension of the netCDF variable). Sampling intervals are +specified in type-independent units of elements (a value of 1 selects +consecutive elements of the netCDF variable along the corresponding +dimension, a value of 2 selects every other element, etc.). +ifelse(API,C,<>) +.TP +IMAP() +specifies the mapping between the dimensions of a netCDF variable and +the in-memory structure of the internal data array. The elements of +the <> mapping vector correspond, in order, to the netCDF variable's +dimensions (ARG(imap)<<>>ifelse(API,C,[0],<<(1)>>) gives the distance +between elements of the internal array corresponding to the most +ifelse(API,C,slowly,rapidly) varying dimension of the netCDF variable). +Distances between elements are specified in type-independent units of +elements (the distance between internal elements that occupy adjacent +memory locations is 1 and not the element's byte-length as in netCDF 2). +ifelse(API,C,<>) +.SH "VARIABLE PREFILLING" +.LP +By default, the netCDF interface sets the values of +all newly-defined variables of finite length (i.e. those that do not have +an unlimited, dimension) to the type-dependent fill-value associated with each +variable. This is done when FREF(enddef) +is called. The +fill-value for a variable may be changed from the default value by +defining the attribute `CODE(_FillValue)' for the variable. This +attribute must have the same type as the variable and be of length one. +.LP +Variables with an unlimited dimension are also prefilled, but on +an `as needed' basis. For example, if the first write of such a +variable is to position 5, then +positions +ifelse(API,C,0 through 4, 1 through 4) +(and no others) +would be set to the fill-value at the same time. +.LP +This default prefilling of data values may be disabled by +or'ing the +MACRO(NOFILL) +flag into the mode parameter of FREF(open) or FREF(create), +or, by calling the function FREF(set_fill) +with the argument MACRO(NOFILL). +For variables that do not use the unlimited dimension, +this call must +be made before +FREF(enddef). +For variables that +use the unlimited dimension, this call +may be made at any time. +.LP +One can obtain increased performance of the netCDF interface by using +this feature, but only at the expense of requiring the application to set +every single data value. The performance +enhancing behavior of this function is dependent on the particulars of +the implementation and dataset <>. +The flag value controlled by FREF(set_fill) +is per netCDF ID, +not per variable or per write. +Allowing this to change affects the degree to which +a program can be effectively parallelized. +Given all of this, we state that the use +of this feature may not be available (or even needed) in future +releases. Programmers are cautioned against heavy reliance upon this +feature. +.HP +FDECL(setfill, (INCID(), IFILLMODE(), OOLDFILLMODE())) +ifelse(API,C, +<<.sp +(Corresponds to FOLD(setfill) in version 2)>>) +.sp +Determines whether or not variable prefilling will be done (see +above). +The netCDF dataset shall be writable. +FILLMODE() is either MACRO(FILL) +to enable prefilling (the +default) or MACRO(NOFILL) +to disable prefilling. +This function returns the previous setting in OLDFILLMODE(). +.SH "MPP FUNCTION DESCRIPTIONS" +.LP +Additional functions for use on SGI/Cray MPP machines (_CRAYMPP). +These are used to set and inquire which PE is the base for MPP +for a particular netCDF. These are only relevant when +using the SGI/Cray ``global'' +Flexible File I/O layer and desire to have +only a subset of PEs to open the specific netCDF file. +For technical reasons, these functions are available on all platforms. +On a platform other than SGI/Cray MPP, it is as if +only processor available were processor 0. +.LP +To use this feature, you need to specify a communicator group and call +CODE(glio_group_mpi(\|)) or CODE(glio_group_shmem(\|)) prior to the netCDF +FREF(open) and FREF(create) calls. +.HP +FDECL(_create_mp, (IPATH(), ICMODE(), IINITSIZE(), IPE(), OCHUNKSIZE(), ONCID())) +.sp +Like FREF(_create) but allows the base PE to be set. +.sp +The argument ARG(pe) sets the base PE at creation time. In the MPP +environment, FREF(_create) and FREF(create) set the base PE to processor +zero by default. +.HP +FDECL(_open_mp, (IPATH(), IMODE(), IPE(), OCHUNKSIZE(), ONCID())) +.sp +Like FREF(_open) but allows the base PE to be set. +The argument ARG(pe) sets the base PE at creation time. In the MPP +environment, FREF(_open) and FREF(open) set the base PE to processor +zero by default. +.HP +FDECL(inq_base_pe, (INCID(), OPE())) +.sp +Inquires of the netCDF dataset which PE is being used as the base for MPP use. +This is safe to use at any time. +.HP +FDECL(set_base_pe, (INCID(), IPE())) +.sp +Resets the base PE for the netCDF dataset. +Only perform this operation when the affected communicator group +synchronizes before and after the call. +This operation is very risky and should only be contemplated +under only the most extreme cases. +.SH "ENVIRONMENT VARIABLES" +.TP 4 +.B NETCDF_FFIOSPEC +Specifies the Flexible File I/O buffers for netCDF I/O when executing +under the UNICOS operating system (the variable is ignored on other +operating systems). +An appropriate specification can greatly increase the efficiency of +netCDF I/O -- to the extent that it can actually surpass FORTRAN binary +I/O. +This environment variable has been made a little more generalized, +such that other FFIO option specifications can now be added. +The default specification is \fBbufa:336:2\fP, +unless a current FFIO specification is in operation, +which will be honored. +See UNICOS Flexible File I/O for more information. +.SH "MAILING-LISTS" +.LP +Both a mailing list and a digest are available for +discussion of the netCDF interface and announcements about netCDF bugs, +fixes, and enhancements. +To begin or change your subscription to either the mailing-list or the +digest, send one of the following in the body (not +the subject line) of an email message to "majordomo@unidata.ucar.edu". +Use your email address in place of \fIjdoe@host.inst.domain\fP. +.sp +To subscribe to the netCDF mailing list: +.RS +\fBsubscribe netcdfgroup \fIjdoe@host.inst.domain\fR +.RE +To unsubscribe from the netCDF mailing list: +.RS +\fBunsubscribe netcdfgroup \fIjdoe@host.inst.domain\fR +.RE +To subscribe to the netCDF digest: +.RS +\fBsubscribe netcdfdigest \fIjdoe@host.inst.domain\fR +.RE +To unsubscribe from the netCDF digest: +.RS +\fBunsubscribe netcdfdigest \fIjdoe@host.inst.domain\fR +.RE +To retrieve the general introductory information for the mailing list: +.RS +\fBinfo netcdfgroup\fR +.RE +To get a synopsis of other majordomo commands: +.RS +\fBhelp\fR +.RE +.SH "SEE ALSO" +.LP +.BR ncdump (1), +.BR ncgen (1), +.BR netcdf (3<<>>ifelse(API,C,,f)). +.LP +\fInetCDF User's Guide\fP, published +by the Unidata Program Center, University Corporation for Atmospheric +Research, located in Boulder, Colorado. Index: /branches/SDM_SciDAC/man/Makefile =================================================================== --- /branches/SDM_SciDAC/man/Makefile (revision 2) +++ /branches/SDM_SciDAC/man/Makefile (revision 2) @@ -0,0 +1,19 @@ +# $Id$ +# +# Makefile for netcdf man +# + +include ../macros.make + +PACKING_LIST = Makefile \ + netcdf.m4 + +all: + +test: + +install: + +uninstall: + +include ../rules.make Index: /branches/SDM_SciDAC/Makefile =================================================================== --- /branches/SDM_SciDAC/Makefile (revision 2) +++ /branches/SDM_SciDAC/Makefile (revision 2) @@ -0,0 +1,145 @@ +# $Id$ + + +include macros.make + + +PACKAGE = parallel-netcdf +SUBDIRS = src/lib man +DIST_GARBAGE = \ + config.cache \ + config.status +PACKING_LIST = \ + Makefile \ + aclocal.m4 \ + configure \ + configure.in \ + macros.make.in \ + macros.make.def \ + rules.make + + +all: src/lib/all + +install: src/lib/install + +uninstall: src/lib/uninstall + +clean: src/lib/clean + +distclean: src/lib/distclean \ + clean_macros + +clean_macros: + -cp macros.make.def macros.make + +src/lib/all \ +src/lib/test \ +src/lib/install \ +src/lib/uninstall \ +src/lib/clean \ +src/lib/distclean \ +: + @subdir=`echo $@ | sed 's,/.*,,'`; \ + target=`echo $@ | sed 's,.*/,,'`; \ + $(MAKE) SUBDIR=$$subdir TGET=$$target subdir_target + +subdir_target: + @echo "" + @cd $(SUBDIR) && \ + echo "Making \`$(TGET)' in directory `pwd`" && \ + echo "" && \ + $(MAKE) $(TGET) || exit 1 + @echo "" + @echo "Returning to directory `pwd`" + @echo "" + +install: whatis +whatis: $(MANDIR)/$(WHATIS) +$(MANDIR)/$(WHATIS): $(MANDIR) + $(MAKEWHATIS_CMD) +uninstall: + rm -f $(MANDIR)/$(WHATIS) + + +################################################################################ +# Distribution: + +# The following rule checks to see that were on the right system. If we're +# not, then the distribution mightn't contain the intended ncgen(1) (not +# to mention that dvips(1) is necessary for building the C++ User's Guide). +# +check_system: FORCE + @case "$(OVERRIDE)" in \ + '') case `uname -sr` in \ + 'SunOS 5'*) \ + exit 0;; \ + *) echo 1>&2 "Error: Not on a SunOS 5 system."; \ + echo 1>&2 "Set macro OVERRIDE to override."; \ + exit 1;; \ + esac;; \ + *) exit 0;; \ + esac + +# Make a compressed, tar(1) file of the source distribution in the current +# directory. +# +tar.Z: check_system FORCE + @version=`cat VERSION`; \ + $(MAKE) $(MFLAGS) $(PACKAGE)-$$version.tar.Z VERSION=$$version + +$(PACKAGE)-$(VERSION).tar.Z: ensure_manifest MANIFEST + id=$(PACKAGE)-$(VERSION) \ + && rm -rf $$id \ + && mkdir $$id \ + && ln -s .. $$id/src \ + && tar $(TARFLAGS) - `sed "s|^|$$id/src/|" MANIFEST` | compress > $@ \ + && rm -r $$id + +MANIFEST: FORCE + $(MAKE) MANIFEST.echo >$@ + +# Make a compressed, tar(1) file of the source distribution in the +# appropriate FTP directory. +# +# NOTE: Making "ftp" will cause the "tar.Z" file to be made even if it +# already exists. This is because the MANIFEST file upon which it +# depends must be remade every time. This is not a waste of time, +# however, if the "tar.Z" target is made in private directories and the +# "ftp" target is made in the "/upc/$(PACKAGE)/build/" directory. +# +ftp: check_system FORCE + version=`cat VERSION`; \ + $(MAKE) $(MFLAGS) $(FTPDIR)/$(PACKAGE)-$$version.tar.Z \ + VERSION=$$version; \ + test -r $(FTPDIR)/$(PACKAGE).tar.Z || exit 0; \ + cd $(FTPDIR) || exit 1; + +$(FTPDIR)/$(PACKAGE)-$(VERSION).tar.Z: $(PACKAGE)-$(VERSION).tar.Z + rm -f $@ + cp $(PACKAGE)-$(VERSION).tar.Z $@ + chmod u+rw,g+rw,o=r $@ + +# Make a compressed, tar(1) file of the binary distribution in the +# appropriate FTP directory. +# +binftp: FORCE + version=`cat VERSION`; \ + $(MAKE) $(MFLAGS) $(FTPBINDIR)/$(PACKAGE)-$$version.tar.Z \ + VERSION=$$version +ftpbin: binftp + +$(FTPBINDIR)/$(PACKAGE)-$(VERSION).tar.Z: + rm -f $@ + id=$(PACKAGE)-$(VERSION) \ + && rm -f $$id \ + && ln -s $(prefix) $$id \ + && tar $(TARFLAGS) - README $$id/bin $$id/include \ + $$id/lib $$id/man | compress > $@ \ + && rm $$id + chmod u+rw,g+rw,o=r $@ + test -r $(FTPBINDIR)/$(PACKAGE).tar.Z || exit 0; \ + cd $(FTPBINDIR) || exit 1; + + +include rules.make Index: /branches/SDM_SciDAC/aclocal.m4 =================================================================== --- /branches/SDM_SciDAC/aclocal.m4 (revision 2) +++ /branches/SDM_SciDAC/aclocal.m4 (revision 2) @@ -0,0 +1,1291 @@ +dnl $Id$ +dnl UD macros for netcdf configure + + +dnl Convert a string to all uppercase. +dnl +define([uppercase], +[translit($1, abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ)]) + +dnl +dnl Check for an m4(1) preprocessor utility. +dnl +AC_DEFUN(UD_PROG_M4, +[ + AC_CHECKING(for m4 preprocessor) + case "${M4-unset}" in + unset) AC_CHECK_PROGS(M4, m4 gm4, m4) ;; + *) AC_CHECK_PROGS(M4, $M4 m4 gm4, m4) ;; + esac + AC_MSG_CHECKING(m4 flags) + case "${M4FLAGS-unset}" in + unset) M4FLAGS=-B10000 ;; + esac + AC_MSG_RESULT($M4FLAGS) + AC_SUBST(M4FLAGS) +]) + +dnl +dnl Check for an ar(1) utility. +dnl +AC_DEFUN(UD_PROG_AR, +[ + AC_CHECKING(for ar utility) + case "${AR-unset}" in + unset) AC_CHECK_PROGS(AR, ar, ar) ;; + *) AC_CHECK_PROGS(AR, $AR ar, ar) ;; + esac + AC_MSG_CHECKING(ar flags) + case "${ARFLAGS-unset}" in + unset) ARFLAGS=cru ;; + esac + AC_MSG_RESULT($ARFLAGS) + AC_SUBST(ARFLAGS) +]) + +dnl +dnl Check for an nm(1) utility. +dnl +AC_DEFUN(UD_PROG_NM, +[ + AC_CHECKING(for nm utility) + case "${NM-unset}" in + unset) AC_CHECK_PROGS(NM, nm, nm) ;; + *) AC_CHECK_PROGS(NM, $NM nm, nm) ;; + esac + AC_MSG_CHECKING(nm flags) + case "${NMFLAGS-unset}" in + unset) NMFLAGS= ;; + esac + AC_MSG_RESULT($NMFLAGS) + AC_SUBST(NMFLAGS) +]) + +dnl +dnl Set the top-level source-directory. +dnl +AC_DEFUN(UD_SRCDIR, +[ + AC_CHECKING(for top-level source-directory) + SRCDIR=`(cd $srcdir && pwd)` + AC_MSG_RESULT($SRCDIR) + AC_SUBST(SRCDIR) +]) + +dnl +dnl Check for a Standard C compiler. Prefer a native one over the +dnl GNU one to reduce the chance that the environment variable LIBS +dnl will have to be set to reference the GNU C runtime library. +dnl +AC_DEFUN(UD_PROG_CC, +[ + # Because we must have a C compiler, we treat an unset CC + # the same as an empty CC. + case "${CC}" in + '') + case `uname` in + ULTRIX) + # The native ULTRIX C compiler isn't standard. + ccs='gcc cc' + ;; + *) + # xlc is before c89 because AIX's sizeof(long long) + # differs between the two. + # + ccs='xlc c89 acc cc gcc' + ;; + esac + for cc in $ccs; do + AC_CHECK_PROG(CC, $cc, $cc) + case "$CC" in + '') ;; + *) break + ;; + esac + done + case "${CC}" in + '') + AC_MSG_ERROR("Could not find C compiler") + ;; + esac + ;; + esac + # + # On some systems, a discovered compiler nevertheless won't + # work (due to licensing, for example); thus, we check the + # compiler with a test program. + # + AC_MSG_CHECKING(C compiler \"$CC\") + AC_TRY_COMPILE(, , + AC_MSG_RESULT(works), + AC_MSG_RESULT(failed to compile test program)) + AC_SUBST(CC) + case "$CC" in + *gcc*) + GCC=yes # Expected by autoconf(1) macros + ;; + esac + case `uname -sr` in + 'HP-UX A.09'*) + AC_DEFINE(_HPUX_SOURCE) + ;; + esac +]) + +dnl +dnl Check for a C++ compiler. Prefer a native one over the +dnl GNU one to reduce the chance that the environment variable LIBS +dnl will have to be set to reference the GNU C runtime library. +dnl +AC_DEFUN(UD_PROG_CXX, +[ + case "${CXX-unset}" in + unset) + case `uname` in + AIX) + preferred_cxx='xlC' + ;; + esac + possible_cxxs="${preferred_cxx} CC cxx c++ g++ gcc" + ;; + '') AC_MSG_WARN("Empty CXX variable") + possible_cxxs= + ;; + *) possible_cxxs=$CXX + ;; + esac + case "${possible_cxxs}" in + '') CXX= + ;; + *) AC_LANG_SAVE() + AC_LANG_CPLUSPLUS() + for cxx in $possible_cxxs; do + AC_CHECK_PROG(CXX, $cxx, $cxx) + case "$CXX" in + '') ;; + *) # On some systems, a discovered compiler nevertheless + # won't work (because it's a script to a non-existant + # executable, for example); thus, we check the + # compiler with a test program. We also test + # for and the standard C++ library + # because we need these to work. + # + AC_MSG_CHECKING(C++ compiler \"$CXX\") + AC_TRY_RUN( + [ + #include + int main() { + cout << ""; + return 0; + } + ], + [ + AC_MSG_RESULT(works) + break + ], + [ + AC_MSG_WARN($CXX failed on test program) + CXX= + unset ac_cv_prog_CXX + ]) + ;; + esac + done + AC_LANG_RESTORE() + case "${CXX}" in + '') AC_MSG_WARN("Could not find working C++ compiler") + AC_MSG_WARN(Setting CXX to the empty string) + ;; + esac + ;; + esac + case "${CXX}" in + '') AC_MSG_WARN(The C++ interface will not be built) + ;; + esac + AC_SUBST(CXX) + case `uname` in + 'HP-UX A.09'*) + AC_DEFINE(_HPUX_SOURCE) + ;; + esac +]) + + +dnl +dnl like AC_LONG_DOUBLE, except checks for 'long long' +dnl +AC_DEFUN(UD_C_LONG_LONG, +[AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(ac_cv_c_long_long, +[if test "$GCC" = yes; then + ac_cv_c_long_long=yes +else +AC_TRY_RUN([int main() { +long long foo = 0; +exit(sizeof(long long) < sizeof(long)); }], +ac_cv_c_long_long=yes, ac_cv_c_long_long=no, :) +fi])dnl +AC_MSG_RESULT($ac_cv_c_long_long) +if test $ac_cv_c_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG) +fi +]) + +dnl UD_CHECK_SIZEOF(TYPE) +AC_DEFUN(UD_CHECK_SIZEOF, +[changequote(<<, >>)dnl +dnl The name to #define. +define(<>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl +dnl The cache variable name. +define(<>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl +changequote([, ])dnl +AC_MSG_CHECKING(size of $1) +AC_CACHE_VAL(AC_CV_NAME, +[AC_TRY_RUN([#include +#include +#if STDC_HEADERS +#include +#endif +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof($1)); + exit(0); +}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, AC_CV_NAME=0)])dnl +AC_MSG_RESULT($AC_CV_NAME) +AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME) +undefine([AC_TYPE_NAME])dnl +undefine([AC_CV_NAME])dnl +]) + + +dnl +dnl UD_CHECK_IEEE +dnl If the 'double' is not an IEEE double +dnl or the 'float' is not and IEEE single, +dnl define NO_IEEE_FLOAT +dnl +AC_DEFUN(UD_CHECK_IEEE, +[ +AC_MSG_CHECKING(for IEEE floating point format) +AC_TRY_RUN([#ifndef NO_FLOAT_H +#include +#endif + +#define EXIT_NOTIEEE 1 +#define EXIT_MAYBEIEEE 0 + +int +main() +{ +#if defined(FLT_RADIX) && FLT_RADIX != 2 + return EXIT_NOTIEEE; +#elif defined(DBL_MAX_EXP) && DBL_MAX_EXP != 1024 + return EXIT_NOTIEEE; +#elif defined(DBL_MANT_DIG) && DBL_MANT_DIG != 53 + return EXIT_NOTIEEE; +#elif defined(FLT_MAX_EXP) && !(FLT_MAX_EXP == 1024 || FLT_MAX_EXP == 128) + return EXIT_NOTIEEE; +#elif defined(FLT_MANT_DIG) && !(FLT_MANT_DIG == 53 || FLT_MANT_DIG == 24) + return EXIT_NOTIEEE; +#else + /* (assuming eight bit char) */ + if(sizeof(double) != 8) + return EXIT_NOTIEEE; + if(!(sizeof(float) == 4 || sizeof(float) == 8)) + return EXIT_NOTIEEE; + + return EXIT_MAYBEIEEE; +#endif +}],ac_cv_c_ieeefloat=yes, ac_cv_c_ieeefloat=no, :) +AC_MSG_RESULT($ac_cv_c_ieeefloat) +if test $ac_cv_c_ieeefloat = no; then + AC_DEFINE(NO_IEEE_FLOAT) +fi +]) + +dnl Check for utility for generating makefile dependencies. +dnl Should only be used at the UPC. +dnl +AC_DEFUN(UD_PROG_CC_MAKEDEPEND, +[ + AC_MSG_CHECKING(how to make dependencies) + case `uname -s` in + IRIX*|OSF1) + CC_MAKEDEPEND='cc -M' + ;; + SunOS) + case `uname -r` in + 4*) + CC_MAKEDEPEND='cc -M' + ;; + 5*|*) + CC_MAKEDEPEND='cc -xM' + ;; + esac + ;; + ULTRIX) + case `uname -m` in + RISC) + CC_MAKEDEPEND='cc -M' + ;; + VAX) # Can't handle prototypes in netcdf.h + ;; + esac + ;; + AIX) # Writes to .u files rather than standard out + ;; + HP-UX) # Writes escaped newlines to standard error + ;; + esac + case "${CC_MAKEDEPEND}" in + '') + CC_MAKEDEPEND=false + ;; + esac + AC_MSG_RESULT($CC_MAKEDEPEND) + AC_SUBST(CC_MAKEDEPEND) +]) + + +dnl Check for Fortran-90 compiler. +dnl +AC_DEFUN(UD_PROG_F90, +[ + case "${F90+set}" in + set) + AC_MSG_CHECKING(user-defined Fortran-90 compiler \"$F90\") + cat <conftest.f90 + subroutine foo(bar) + integer, intent(in) :: bar + end subroutine foo +EOF + doit='$F90 -c ${F90FLAGS} conftest.f90' + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT(works) + else + AC_MSG_RESULT(failed to compile test program) + unset F90 + fi + rm -f conftest.* + ;; + *) + case "${FC+set}" in + set) + F90=$FC + F90FLAGS="${F90FLAGS-${FFLAGS--O}}" + F90LIBS="${F90LIBS-${FLIBS}}" + cat <conftest.f90 + program foo + call bar(1) + end program foo + subroutine bar(bof) + integer, intent(in) :: bof + end subroutine bar +EOF + AC_MSG_CHECKING(\"$F90\" as Fortran-90 compiler) + doit='$F90 -o conftest ${F90FLAGS} conftest.f90 ${F90LIBS}' + if AC_TRY_EVAL(doit); then + doit=./conftest + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT(works) + else + AC_MSG_RESULT(failed to build executable program) + unset F90 + fi + else + AC_MSG_RESULT(failed to build test program) + unset F90 + fi + rm -f conftest* + ;; + esac + case "${F90-unset}" in + unset) + cat <conftest.f90 + program foo + call bar(1) + end program foo + subroutine bar(bof) + integer, intent(in) :: bof + end subroutine bar +EOF + for f90 in xlf90 f90; do + AC_CHECK_PROG(F90, $f90, $f90) + case "${F90}" in + '') + ;; + *) + AC_MSG_CHECKING(Fortran-90 compiler \"$F90\") + doit='$F90 -o conftest ${F90FLAGS} conftest.f90 ${F90LIBS}' + if AC_TRY_EVAL(doit); then + doit=./conftest + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT(works) + break; + else + AC_MSG_RESULT( + failed to build executable program) + unset F90 + unset ac_cv_prog_F90 + fi + else + AC_MSG_RESULT(failed to build test program) + unset F90 + unset ac_cv_prog_F90 + fi + ;; + esac + done + rm -f conftest* + case "${F90}" in + '') AC_MSG_WARN( + "Could not find working Fortran-90 compiler") + ;; + esac + ;; + esac + ;; + esac + case "${F90}" in + '') + AC_MSG_WARN("The Fortran-90 interface will not be built") + ;; + *f90*) + case `uname -s` in + IRIX*) + NETCDF_MOD=NETCDF.mod + ;; + *) + NETCDF_MOD=netcdf.mod + ;; + esac + AC_SUBST(NETCDF_MOD) + ;; + esac + AC_SUBST(F90) + AC_SUBST(F90FLAGS) + AC_SUBST(F90LIBS) +]) + +dnl Check for Fortran-77 compiler. +dnl +AC_DEFUN(UD_PROG_FC, +[ + AC_BEFORE([UD_FORTRAN_TYPES]) + case "${FC+set}" in + set) + case "$FC" in + '') + AC_MSG_WARN(Fortran-77 compiler is explicitly null) + ;; + *) + AC_MSG_CHECKING(user-defined Fortran-77 compiler \"$FC\") + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT(works) + else + AC_MSG_RESULT(failed to compile test program) + FC= + fi + rm -f conftest.* + ;; + esac + ;; + *) + case "${F90+set}" in + set) + FC=$F90 + FFLAGS="${FFLAGS-${F90FLAGS--O}}" + FLIBS="${FLIBS-${F90LIBS-}}" + AC_MSG_CHECKING(\"$FC\" as Fortran-77 compiler) + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT(works) + else + AC_MSG_RESULT(failed to compile test program) + unset FC + fi + rm -f conftest.* + ;; + esac + case "${FC-unset}" in + unset) + case `uname -sr` in + AIX*) + # xlf90(1) thinks fortran/ftest.F has bad syntax. + forts="xlf f77" + ;; + BSD/OS*|FreeBSD*) + forts="f77 fort77 g77" + ;; + HP-UX*) + # f77(1) doesn't have the -L option. + forts=fort77 + FLIBS=-lU77 + ;; + IRIX*) + # f90(1) can't link with c89(1)-compiled objects + forts=f77 + ;; + IRIX64*) + forts='f77 g77 fort77' + ;; + Linux*) + forts="f77 fort77 g77" + ;; + OSF1*) + # The use of f90(1) results in the following for + # an unknown reason (`make' works in the fortran/ + # directory): + # f90 -c -I../libsrc ftest.F + # Last chance handler: pc = 0xa971b8, + # sp = 0x3fece0, ra = 0xa971b8 + # Last chance handler: internal exception: unwinding + forts="f77" + ;; + 'SunOS 4'*) + forts='f77 g77 fort77' + ;; + 'SunOS 5'*) + # SunOS's f90(1) has problems passing a C `char' + # as a Fortran `integer*1' => use f77(1) + forts="f77" + ;; + sn*|UNICOS*|unicos*) + forts="fort77 cf77 f77 g77 f90" + ;; + *) + forts="xlf fort77 ghf77 f77 cf77 g77 xlf90 f90" + ;; + esac + for fc in $forts; do + AC_CHECK_PROG(FC, $fc, $fc) + case "${FC}" in + '') + ;; + *) + # + # On some systems, a discovered compiler + # nevertheless won't work (due to licensing, + # for example); thus, we check the compiler + # with a test program. + # + cat <conftest.f + CALL FOO + END +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if AC_TRY_EVAL(doit); then + break + else + AC_MSG_RESULT( + failed to compile test program) + unset FC + unset ac_cv_prog_FC + fi + ;; + esac + done + rm -f conftest.* + case "${FC}" in + '') AC_MSG_WARN( + "Could not find working Fortran-77 compiler") + ;; + esac + ;; + esac + ;; + esac + case "${FC}" in + '') AC_MSG_WARN("The Fortran-77 interface will not be built") + ;; + esac + AC_SUBST(FC) + AC_SUBST(FFLAGS) + AC_SUBST(FLIBS) + # + # Set the make(1) macro for compiling a .F file. + # + case "${FPP-}" in + '') + AC_MSG_CHECKING(for Fortran .F compiler) + AC_MSG_RESULT($COMPILE_F) + case "${COMPILE_F-unset}" in + unset) + case "${FC}" in + '') + COMPILE_F= + ;; + *) + AC_MSG_CHECKING(if Fortran-77 compiler handles *.F files) + cat >conftest.h <<\EOF +#define J 1 +EOF + cat >conftest.F <<\EOF +#include "conftest.h" +#define N 5 + real r(J,N) + end +EOF + doit='$FC -o conftest ${FFLAGS} conftest.F ${FLIBS}' + if AC_TRY_EVAL(doit); then + COMPILE_F='$(COMPILE.f) $(FPPFLAGS)' + AC_MSG_RESULT(yes) + else + COMPILE_F= + AC_MSG_RESULT(no) + fi + rm -f conftest* + ;; + esac + ;; + esac + ;; + *) + unset COMPILE_F + ;; + esac + case "${COMPILE_F-}" in + '') UD_PROG_FPP;; + esac + AC_SUBST(COMPILE_F) + FPPFLAGS=${FPPFLAGS-} + AC_SUBST(FPPFLAGS) +]) + + +dnl Check for Fortran preprocessor. +dnl +AC_DEFUN(UD_PROG_FPP, +[ + AC_MSG_CHECKING(for Fortran preprocessor) + case "$FPP" in + '') + AC_REQUIRE([AC_PROG_CPP]) + FPP="$CPP" + ;; + esac + AC_MSG_RESULT($FPP) + AC_SUBST(FPP) +]) + + +dnl Check for a Fortran type equivalent to a netCDF type. +dnl +dnl UD_CHECK_FORTRAN_NCTYPE(forttype, possibs, nctype) +dnl +AC_DEFUN(UD_CHECK_FORTRAN_NCTYPE, +[ + AC_MSG_CHECKING(for Fortran-equivalent to netCDF \"$3\") + for type in $2; do + cat >conftest.f <conftest.f <conftest.c < +#include +void main() +{ +$3 values[[]] = {0, $4, 0, $5, 0}; +$3 minval, maxval; +void $FCALLSCSUB($3*, $3*, $3*); +$FCALLSCSUB(values, &minval, &maxval); +exit(!(minval == $4 && maxval == $5)); +} +EOF + doit='$CC -o conftest ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} conftest.c conftestf.o ${LIBS}' + if AC_TRY_EVAL(doit); then + doit=./conftest + if AC_TRY_EVAL(doit); then + AC_MSG_RESULT($2) + $1=$2 + AC_DEFINE_UNQUOTED($1,$2) + else + AC_MSG_RESULT(no equivalent type) + unset $1 + fi + else + AC_MSG_ERROR(Could not compile-and-link conftest.c and conftestf.o) + fi + else + AC_MSG_ERROR(Could not compile conftest.f) + fi + rm -f conftest* +]) + + +dnl Check for a Fortran data type. +dnl +dnl UD_CHECK_FORTRAN_TYPE(varname, ftypes) +dnl +AC_DEFUN(UD_CHECK_FORTRAN_TYPE, +[ + for ftype in $2; do + AC_MSG_CHECKING(for Fortran \"$ftype\") + cat >conftest.f <conftest.f <<\EOF + call sub() + end +EOF + doit='$FC -c ${FFLAGS} conftest.f' + if AC_TRY_EVAL(doit); then + FCALLSCSUB=`$NM $NMFLAGS conftest.o | awk ' + /SUB_/{print "SUB_";exit} + /SUB/ {print "SUB"; exit} + /sub_/{print "sub_";exit} + /sub/ {print "sub"; exit}'` + case "$FCALLSCSUB" in + '') AC_MSG_ERROR(not found) + ;; + *) AC_MSG_RESULT($FCALLSCSUB) + ;; + esac + else + AC_MSG_ERROR(Could not compile conftest.f) + fi + rm -f conftest* + ;; + esac +]) + + +dnl Check for a C type equivalent to a Fortran type. +dnl +dnl UD_CHECK_CTYPE_FORTRAN(ftype, ctypes, fmacro_root) +dnl +AC_DEFUN(UD_CHECK_CTYPE_FORTRAN, +[ + cat >conftestf.f <conftest.c < +#include +#include +#include +#include +main() +{ + char* path = tmpnam(NULL); + int exitStatus = 1; + + if (path != NULL) + { + int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); + + if (fd != -1) + { + if (write(fd, "0", 1) == 1) + { + off_t pos = lseek(fd, 0, SEEK_CUR); + + if (pos != (off_t)-1) + { + if (ftruncate(fd, 512) != -1) + { + if (pos == lseek(fd, 0, SEEK_CUR)) + { + if (lseek(fd, 0, SEEK_SET) == 0) + { + char buf[[512]]; + + if (read(fd, buf, 512) == 512) + exitStatus = 0; + } + } + } + } + } + close(fd); + unlink(path); + } + } + + return exitStatus; +} + , + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_FTRUNCATE) + , + AC_MSG_RESULT(no) + ) +]) + + +dnl Set the binary distribution directory. +dnl +AC_DEFUN([UD_FTPBINDIR], [dnl + AC_MSG_CHECKING([binary distribution directory]) + case ${FTPBINDIR-unset} in + unset) + system=`(system) 2>/dev/null || echo dummy_system` + FTPBINDIR=${FTPDIR-/home/ftp}/pub/binary/$system + ;; + esac + AC_SUBST(FTPBINDIR)dnl + AC_MSG_RESULT($FTPBINDIR) +]) + + +dnl +dnl +dnl + +dnl +dnl These headers won't get C style comments +dnl +dnl UD_CONFIG_HEADER(HEADER-TO-CREATE ...) +AC_DEFUN(UD_CONFIG_HEADER, +[define(UD_LIST_HEADER, $1)]) + +dnl The big finish. +dnl Just like AC_OUTPUT except it calls UD_OUTPUT_HEADER for UD_LIST_HEADER. +dnl Produce config.status, config.h, and links, and configure subdirs. +dnl UD_OUTPUT([FILE...] [, EXTRA-CMDS] [, INIT-CMDS]) +define(UD_OUTPUT, +[trap '' 1 2 15 +AC_CACHE_SAVE +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then +changequote(, )dnl + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +changequote([, ])dnl +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +ifdef([AC_LIST_HEADER], [DEFS=-DHAVE_CONFIG_H], [AC_OUTPUT_MAKE_DEFS()]) + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +[#] [$]0 [$]ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +changequote(, )dnl +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +changequote([, ])dnl +for ac_option +do + case "[\$]ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion" + exec [\$]{CONFIG_SHELL-/bin/sh} [$]0 [$]ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version AC_ACVERSION" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "[\$]ac_cs_usage"; exit 0 ;; + *) echo "[\$]ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ifdef([AC_PROVIDE_AC_PROG_INSTALL], [ac_given_INSTALL="$INSTALL" +])dnl + +changequote(<<, >>)dnl +ifdef(<>, +<>, +<>) +changequote([, ])dnl +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF]) +$2 +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 +dnl config.status should not do recursion. +ifdef([AC_LIST_SUBDIRS], [AC_OUTPUT_SUBDIRS(AC_LIST_SUBDIRS)])dnl +])dnl + + +dnl This is a subroutine of UD_OUTPUT. +dnl Acts just like AC_OUTPUT_HEADER except that no C style comments are +dnl produced. +dnl UD_OUTPUT_HEADER(HEADER-FILE...) +define(UD_OUTPUT_HEADER, +[changequote(<<, >>)dnl +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='<<$>>%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' +changequote([, ])dnl + +UDCONFIG_HEADERS=${UDCONFIG_HEADERS-"$1"} +for ac_file in .. $UDCONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo udcreating $ac_file + + rm -f conftest.frag conftest.in conftest.out + cp $ac_given_srcdir/$ac_file_in conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +dnl Using a here document instead of a string reduces the quoting nightmare. +dnl Putting comments in sed scripts is not portable. +cat > conftest.hdr <<\EOF +changequote(<<, >>)dnl +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%<<#define>> \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +changequote([, ])dnl +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. +# Maximum number of lines to put in a single here document. +ac_max_here_lines=12 + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +dnl Now back to your regularly scheduled config.status. +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + case "$ac_file" in + *.h|*.hh|*.H) + echo "/* $ac_file. Generated automatically by configure. */" \ + > conftest.h + ;; + esac + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +]) Index: /branches/SDM_SciDAC/macros.make.def =================================================================== --- /branches/SDM_SciDAC/macros.make.def (revision 2) +++ /branches/SDM_SciDAC/macros.make.def (revision 2) @@ -0,0 +1,88 @@ +# $Id$ + +# The purpose of this file is to contain common make(1) macros. +# It should be processed by every execution of that utility. + + +# POSIX shell. Shouldn't be necessary -- but is under IRIX 5.3. +SHELL = /bin/sh + + +# Installation Directories: +prefix = /opt/netcdf +exec_prefix = $(prefix) +INCDIR = $(exec_prefix)/include +LIBDIR = $(exec_prefix)/lib +BINDIR = $(exec_prefix)/bin +MANDIR = $(prefix)/man + + +# Preprocessing: +M4 = m4 +M4FLAGS = -B10000 +CPP = c89 -E +CPPFLAGS = $(INCLUDES) $(DEFINES) @CPPFLAGS@ +FPP = +FPPFLAGS = $(CPPFLAGS) +CXXCPPFLAGS = $(CPPFLAGS) + + +# Compilation: +CC = c89 +CXX = CC +FC = f77 +CFLAGS = -g +CXXFLAGS = $(CFLAGS) @CXXFLAGS@ +FFLAGS = -g +CC_MAKEDEPEND = : +COMPILE.c = $(CC) -c $(CFLAGS) $(CPPFLAGS) +COMPILE.cxx = $(CXX) -c $(CXXFLAGS) $(CXXCPPFLAGS) +COMPILE.f = $(FC) -c $(FFLAGS) +# The following command isn't available on some systems; therefore, the +# `.F.o' rule is relatively complicated. +COMPILE.F = $(COMPILE.f) + + +# Linking: +MATHLIB = +FLIBS = +LIBS = +LINK.c = $(CC) -o $@ $(CFLAGS) $(LDFLAGS) +LINK.cxx = $(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) +LINK.F = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) +LINK.f = $(FC) -o $@ $(FFLAGS) $(FLDFLAGS) + + +# NetCDF files: +NCDUMP = ncdump +NCGEN = ncgen + + +# Manual pages: +WHATIS = +# The following macro should be empty on systems that don't +# allow users to create their own manual-page indexes. +MAKEWHATIS_CMD = + + +# Misc. Utilities: +AR = ar +ARFLAGS = cru # NB: SunOS 4 doesn't like `-' option prefix +RANLIB = +TARFLAGS = -chf + + +# Dummy macros: used only as placeholders to silence GNU make. They are +# redefined, as necessary, in subdirectory makefiles. +HEADER = dummy_header +HEADER1 = dummy_header1 +HEADER2 = dummy_header2 +LIBRARY = dummy_library.a +MANUAL = dummy_manual +PROGRAM = dummy_program + + +# Distribution macros: +FTPDIR = /home/ftp/pub/$(PACKAGE) +FTPBINDIR = +VERSION = dummy_version