./nco-4.4.2/0000755000674300045400000000000012301476035011756 5ustar zendercgdcsm./nco-4.4.2/m4/0000755000674300045400000000000012301476035012276 5ustar zendercgdcsm./nco-4.4.2/m4/ltsugar.m40000644000674300045400000001042411173424717014230 0ustar zendercgdcsm# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) ./nco-4.4.2/m4/ltoptions.m40000644000674300045400000003007311765477264014620 0ustar zendercgdcsm# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) ./nco-4.4.2/m4/libtool.m40000644000674300045400000106043411765477264014236 0ustar zendercgdcsm# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS ./nco-4.4.2/m4/ltversion.m40000644000674300045400000000126211765477264014610 0ustar zendercgdcsm# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) ./nco-4.4.2/m4/lt~obsolete.m40000644000674300045400000001375611765477264015150 0ustar zendercgdcsm# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) ./nco-4.4.2/config.h.in0000644000674300045400000003711212243254450014005 0ustar zendercgdcsm/* config.h.in. Generated from configure.ac by autoheader. */ /* Compatibility pvmgetarch token for AIX on IBM RS6000 */ #undef AIX /* Compatibility pvmgetarch token for UNICOS on DEC Alpha */ #undef CRAY /* Compile operators with DAP support */ #undef ENABLE_DAP /* DAP support is from libnetcdf */ #undef ENABLE_DAP_NETCDF /* Custom debugging: Pedantic, bounds checking (slowest execution) */ #undef ENABLE_DEBUG_CUSTOM /* Debugging symbols: Produce symbols for debuggers (e.g., dbx, gdb) */ #undef ENABLE_DEBUG_SYMBOLS /* Compile operators with GSL support */ #undef ENABLE_GSL /* Enable Large File Support (LFS) */ #undef ENABLE_LARGEFILE /* Define to 1 if libnetcdf.a contains netCDF4 functions */ #undef ENABLE_NETCDF4 /* Fastest possible execution (slowest compilation) */ #undef ENABLE_OPTIMIZE_CUSTOM /* Enable shared libraries */ #undef ENABLE_SHARED /* Enable static libraries */ #undef ENABLE_STATIC /* Compile operators with UDUnits2 support */ #undef ENABLE_UDUNITS /* Compatibility pvmgetarch token for FreeBSD on Intel x86 */ #undef FREEBSD /* Autoconf-generated architecture \"triplet\" */ #undef GNU_TRP /* Define to 1 if compiler finds external `acosf' function */ #undef HAVE_ACOSF /* Define to 1 if compiler finds external `acoshf' function */ #undef HAVE_ACOSHF /* Define to 1 if compiler finds external `asinf' function */ #undef HAVE_ASINF /* Define to 1 if compiler finds external `asinhf' function */ #undef HAVE_ASINHF /* Define to 1 if compiler finds external `atan2' function */ #undef HAVE_ATAN2 /* Define to 1 if compiler finds external `atan2f' function */ #undef HAVE_ATAN2F /* Define to 1 if compiler finds external `atanf' function */ #undef HAVE_ATANF /* Define to 1 if compiler finds external `atanhf' function */ #undef HAVE_ATANHF /* Define to 1 if you have the `canonicalize_file_name' function. */ #undef HAVE_CANONICALIZE_FILE_NAME /* Define to 1 if compiler finds external `ceilf' function */ #undef HAVE_CEILF /* Define to 1 if compiler finds external `cosf' function */ #undef HAVE_COSF /* Define to 1 if compiler finds external `coshf' function */ #undef HAVE_COSHF /* Define to 1 if you have the header file. */ #undef HAVE_CSTDLIB /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if compiler finds external `erfcf' function */ #undef HAVE_ERFCF /* Define to 1 if compiler finds external `erff' function */ #undef HAVE_ERFF /* Define to 1 if compiler finds external `expf' function */ #undef HAVE_EXPF /* Define to 1 if compiler finds external `fabsf' function */ #undef HAVE_FABSF /* Define to 1 if you have the `floor' function. */ #undef HAVE_FLOOR /* Define to 1 if compiler finds external `floorf' function */ #undef HAVE_FLOORF /* Define to 1 if compiler finds external `fmodf' function */ #undef HAVE_FMODF /* Define to 1 if compiler finds external `gammaf' function */ #undef HAVE_GAMMAF /* Define to 1 if you have the `gethostname' function. */ #undef HAVE_GETHOSTNAME /* Define to 1 if compiler finds external `getopt' function */ #undef HAVE_GETOPT /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if compiler finds external `getopt_long' function */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE /* Define to 1 if you have the `getrusage' function. */ #undef HAVE_GETRUSAGE /* Define to 1 if is present */ #undef HAVE_GSL_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `ccmalloc' library (-lccmalloc). */ #undef HAVE_LIBCCMALLOC /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `expat' library (-lexpat). */ #undef HAVE_LIBEXPAT /* Define to 1 if you have the `f95' library (-lf95). */ #undef HAVE_LIBF95 /* Define to 1 if you have the `gsl' library (-lgsl). */ #undef HAVE_LIBGSL /* Define to 1 if you have the `intl' library (-lintl). */ #undef HAVE_LIBINTL /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `netcdf' library (-lnetcdf). */ #undef HAVE_LIBNETCDF /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `sunmath' library (-lsunmath). */ #undef HAVE_LIBSUNMATH /* Define to 1 if you have the `thread' library (-lthread). */ #undef HAVE_LIBTHREAD /* Define to 1 if you have the `udunits2' library (-ludunits2). */ #undef HAVE_LIBUDUNITS2 /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if compiler finds external `log10f' function */ #undef HAVE_LOG10F /* Define to 1 if compiler finds external `logf' function */ #undef HAVE_LOGF /* Define to 1 if you have the `memchr' function. */ #undef HAVE_MEMCHR /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkstemp' function. */ #undef HAVE_MKSTEMP /* Define if C++ compiler implements namespaces */ #undef HAVE_NAMESPACES /* Define to 1 if compiler finds external `nc_inq_format' function */ #undef HAVE_NC_INQ_FORMAT /* Define to 1 if compiler finds external `nearbyint' function */ #undef HAVE_NEARBYINT /* Define to 1 if compiler finds external `nearbyintf' function */ #undef HAVE_NEARBYINTF /* Define to 1 if netcdf.h contains netCDF4 definitions */ #undef HAVE_NETCDF4_H /* Define to 1 if you have the header file. */ #undef HAVE_NETCDF_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* Define to 1 if compiler finds external `powf' function */ #undef HAVE_POWF /* Define to 1 if the system has the type `ptrdiff_t'. */ #undef HAVE_PTRDIFF_T /* Define to 1 if you have the `readlink' function. */ #undef HAVE_READLINK /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if 'regcomp()' is present */ #undef HAVE_REGCOMP /* Define to 1 if 'regexec()' is present */ #undef HAVE_REGEXEC /* Define to 1 if is present */ #undef HAVE_REGEX_H /* Define to 1 if 'regfree()' is present */ #undef HAVE_REGFREE /* Define to 1 if compiler finds external `rint' function */ #undef HAVE_RINT /* Define to 1 if compiler finds external `rintf' function */ #undef HAVE_RINTF /* Define to 1 if compiler finds external `round' function */ #undef HAVE_ROUND /* Define to 1 if compiler finds external `roundf' function */ #undef HAVE_ROUNDF /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if compiler finds external `sinf' function */ #undef HAVE_SINF /* Define to 1 if compiler finds external `sinhf' function */ #undef HAVE_SINHF /* Define to 1 if you have the `sqrt' function. */ #undef HAVE_SQRT /* Define to 1 if compiler finds external `sqrtf' function */ #undef HAVE_SQRTF /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if compiler finds external `strcasecmp' function */ #undef HAVE_STRCASECMP /* Define to 1 if compiler finds external `strcasestr' function */ #undef HAVE_STRCASESTR /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if compiler finds external `strdup' function */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strpbrk' function. */ #undef HAVE_STRPBRK /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if is present */ #undef HAVE_SYS_TYPES_H /* Define to 1 if compiler finds external `tanf' function */ #undef HAVE_TANF /* Define to 1 if compiler finds external `tanhf' function */ #undef HAVE_TANHF /* Define to 1 if compiler finds external `trunc' function */ #undef HAVE_TRUNC /* Define to 1 if compiler finds external `truncf' function */ #undef HAVE_TRUNCF /* Define to 1 if is present */ #undef HAVE_UDUNITS2_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define if C++ compiler has working valarray */ #undef HAVE_VALARRAY /* Hostname */ #undef HOST /* Hostname alias */ #undef HOSTNAME /* Compatibility pvmgetarch token for HPUX on PA RISC */ #undef HPUX /* i18n support requested */ #undef I18N /* Compatibility pvmgetarch token for Linux on Intel x86 */ #undef LINUX /* Compatibility pvmgetarch token for Linux on DEC Alpha */ #undef LINUXALPHA /* Compatibility pvmgetarch token for Linux on AMD x86_64 */ #undef LINUXAMD64 /* Compatibility pvmgetarch token for Linux on PowerPC */ #undef LINUXPPC /* Compatibility pvmgetarch token for Linux on Sun Sparc */ #undef LINUXSPARC64 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Compatibility pvmgetarch token for Apple Mac OSX */ #undef MACOSX /* GSL minor version number */ #undef NCO_GSL_MINOR_VERSION /* POSIX extended regular expressions available */ #undef NCO_HAVE_REGEX_FUNCTIONALITY /* Compatibility pvmgetarch token for SuperUX on NEC SX */ #undef NECSX /* Define to 1 if compiler needs external `acosf' function */ #undef NEED_ACOSF /* Define to 1 if compiler needs external `acoshf' function */ #undef NEED_ACOSHF /* Define to 1 if compiler needs external `asinf' function */ #undef NEED_ASINF /* Define to 1 if compiler needs external `asinhf' function */ #undef NEED_ASINHF /* Define to 1 if compiler needs external `atan2' function */ #undef NEED_ATAN2 /* Define to 1 if compiler needs external `atan2f' function */ #undef NEED_ATAN2F /* Define to 1 if compiler needs external `atanf' function */ #undef NEED_ATANF /* Define to 1 if compiler needs external `atanhf' function */ #undef NEED_ATANHF /* Define to 1 if compiler needs external `ceilf' function */ #undef NEED_CEILF /* Define to 1 if compiler needs external `cosf' function */ #undef NEED_COSF /* Define to 1 if compiler needs external `coshf' function */ #undef NEED_COSHF /* Define to 1 if compiler needs external `erfcf' function */ #undef NEED_ERFCF /* Define to 1 if compiler needs external `erff' function */ #undef NEED_ERFF /* Define to 1 if compiler needs external `expf' function */ #undef NEED_EXPF /* Define to 1 if compiler needs external `fabsf' function */ #undef NEED_FABSF /* Define to 1 if compiler needs external `floorf' function */ #undef NEED_FLOORF /* Define to 1 if compiler needs external `fmodf' function */ #undef NEED_FMODF /* Define to 1 if compiler needs external `gammaf' function */ #undef NEED_GAMMAF /* Define to 1 if compiler needs external `getopt' function */ #undef NEED_GETOPT /* Define to 1 if compiler needs external `getopt_long' function */ #undef NEED_GETOPT_LONG /* Define to 1 if compiler needs external `log10f' function */ #undef NEED_LOG10F /* Define to 1 if compiler needs external `logf' function */ #undef NEED_LOGF /* Define to 1 if compiler needs external `nc_inq_format' function */ #undef NEED_NC_INQ_FORMAT /* Define to 1 if compiler needs external `nearbyint' function */ #undef NEED_NEARBYINT /* Define to 1 if compiler needs external `nearbyintf' function */ #undef NEED_NEARBYINTF /* Define to 1 if compiler needs external `powf' function */ #undef NEED_POWF /* Define to 1 if compiler needs external `rint' function */ #undef NEED_RINT /* Define to 1 if compiler needs external `rintf' function */ #undef NEED_RINTF /* Define to 1 if compiler needs external `round' function */ #undef NEED_ROUND /* Define to 1 if compiler needs external `roundf' function */ #undef NEED_ROUNDF /* Define to 1 if compiler needs external `sinf' function */ #undef NEED_SINF /* Define to 1 if compiler needs external `sinhf' function */ #undef NEED_SINHF /* Define to 1 if compiler needs external `sqrtf' function */ #undef NEED_SQRTF /* Define to 1 if compiler needs external `strcasecmp' function */ #undef NEED_STRCASECMP /* Define to 1 if compiler needs external `strcasestr' function */ #undef NEED_STRCASESTR /* Define to 1 if compiler needs external `strdup' function */ #undef NEED_STRDUP /* Define to 1 if compiler needs external `tanf' function */ #undef NEED_TANF /* Define to 1 if compiler needs external `tanhf' function */ #undef NEED_TANHF /* Define to 1 if compiler needs external `trunc' function */ #undef NEED_TRUNC /* Define to 1 if compiler needs external `truncf' function */ #undef NEED_TRUNCF /* No netCDF version 2.x API */ #undef NO_NETCDF_2 /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Compatibility pvmgetarch token for IRIX on SGI MIPS */ #undef SGIMP64 /* The size of `int*', as computed by sizeof. */ #undef SIZEOF_INTP /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Compatibility pvmgetarch token for Solaris 2.x on Sun Sparc */ #undef SUNMP /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Location of UDUnits2 data file */ #undef UDUNITS2_PATH /* User */ #undef USER /* Use Fortran arithmetic */ #undef USE_FORTRAN_ARITHMETIC /* Version number of package */ #undef VERSION /* Compatibility pvmgetarch token for Windows on Intel-compatible x86_64 */ #undef WIN32 /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `int' if does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t ./nco-4.4.2/bld/0000755000674300045400000000000012301476017012517 5ustar zendercgdcsm./nco-4.4.2/bld/libnco_c++_tst.cc0000644000674300045400000000267410261164017015624 0ustar zendercgdcsm/* Purpose: Test NCO library libnco_c++ Usage: cd ~/nco/bld Linux: g++ -I../src/nco_c++ -o libnco_c++_tst libnco_c++_tst.cc -L${MY_LIB_DIR} -lnco_c++ AIX: All at once: xlC_r -bnoquiet -I../src/nco_c++ -I/usr/local/include -o libnco_c++_tst libnco_c++_tst.cc -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco_c++ -lnetcdf xlC_r -bnoquiet -I../src/nco_c++ -I/usr/local/include -o libnco_c++_tst -Wl,-blibpath:${MY_LIB_DIR}:/usr/lpp/xlopt:/usr/lib/threads:/usr/lib:/lib libnco_c++_tst.cc -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco_c++ -lnetcdf xlC_r -c -I../src/nco_c++ -I/usr/local/include -o libnco_c++_tst.o libnco_c++_tst.cc xlC_r -bnoquiet -o libnco_c++_tst libnco_c++_tst.o -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco_c++ -lnetcdf xlC_r -bnoquiet -o libnco_c++_tst libnco_c++_tst.o -L${NETCDF_LIB} -lnco_c++ -lnetcdf ld -o libnco_c++_tst libnco_c++_tst.o -L${MY_LIB_DIR},-lnco_c++ ld -o libnco_c++_tst libnco_c++_tst.o -L${MY_LIB_DIR},-lnco_c++ -L/usr/lpp/xlopt,-lxlopt,-lc libnco_c++_tst.o /lib/crt0_64.o */ #include // Standard C++ I/O streams cout, cin #include // Standard C++ string class #include // netCDF C interface #include // C++ interface to netCDF C library int main() { const nc_type nco_xtyp(nco_get_xtype(static_cast(1.0))); // [enm] External netCDF type std::cout << "INFO External netCDF type of prc_cmp variables will be " << nco_typ_sng(nco_xtyp) << std::endl; } ./nco-4.4.2/bld/nco.spec0000644000674300045400000002330512301475713014157 0ustar zendercgdcsm# Fedora RPMs are up-to-date! # http://cvs.fedoraproject.org/viewvc/devel/nco/nco.spec?view=co Name: nco Version: 4.4.2 Release: 1%{?dist} Summary: Programs that manipulate netCDF files Group: Applications/Engineering License: GPL3 URL: http://nco.sf.net/ # Obtain NCO version 4.4.2-1 tar.gz from Sourceforge using CVS: # cvs -d:pserver:anonymous@nco.cvs.sf.net:/cvsroot/nco login # cvs -z3 -d:pserver:anonymous@nco.cvs.sf.net:/cvsroot/nco co -r nco-4.4.2-1 -d nco-%{version} nco # tar czf nco-%{version}.tar.gz --exclude='nco-4.4.2/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude='ncap_yacc.[ch]' ./nco-%{version} Source0: nco-%{version}.tar.gz #Patch0: nco_install_C_headers.patch #Patch1: nco_find_udunits-dat.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: automake, autoconf, libtool BuildRequires: netcdf, netcdf-devel BuildRequires: udunits, udunits-devel # Required for ncap: BuildRequires: bison, flex # Required for ncap2: BuildRequires: gsl, gsl-devel #BuildRequires: antlr antlr-c++-devel # Following libraries required to DAP-enable NCO: BuildRequires: curl, curl-devel BuildRequires: libxml2, libxml2-devel BuildRequires: libdap, libdap-devel, libnc-dap, libnc-dap-devel %package devel Summary: Development files for NCO Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description NCO is a suite of programs known as operators. The operators are stand-alone, command-line programs executable in a POSIX shell. Operators take one or more netCDF files as input, perform operations (e.g., averaging, hyperslabbing), and produce a netCDF output file. NCO was originally designed to manipulate and analyze climate data, though it works on any netCDF format datasets. %description devel This package contains NCO header files and static libraries. %prep %setup -q #%patch0 -p1 #%patch1 -p1 %build aclocal autoheader automake --foreign autoconf # Explicitly set system netCDF directories to override development netCDF # installations in, e.g., /usr/local export CPPFLAGS=-I%{_includedir}/netcdf-3 # Always put netcdf-3 on path and, for x86_64, add -L/usr/lib64, when present, to correctly resolve 32/64-bit libraries export LDFLAGS="-L%{_libdir}/netcdf-3 %( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo '-L/usr/lib64' )" export CFLAGS="$RPM_OPT_FLAGS -fPIC" export CXXFLAGS="$RPM_OPT_FLAGS -fpermissive -fPIC" %configure --includedir=%{_includedir}/nco make %{?_smp_mflags} unset CPPFLAGS LDFLAGS CFLAGS CXXFLAGS %install rm -rf ${RPM_BUILD_ROOT} mkdir ${RPM_BUILD_ROOT} mkdir -p ${RPM_BUILD_ROOT}%{_includedir}/nco make install DESTDIR=${RPM_BUILD_ROOT} rm -f ${RPM_BUILD_ROOT}%{_libdir}/*.la rm -f ${RPM_BUILD_ROOT}%{_infodir}/dir rm -f ${RPM_BUILD_ROOT}%{_bindir}/mpnc* %clean rm -rf ${RPM_BUILD_ROOT} %post /sbin/ldconfig /sbin/install-info %{_infodir}/nco.info.gz \ %{_infodir}/dir 2>/dev/null || : %postun /sbin/ldconfig if [ "$1" = 0 ]; then /sbin/install-info --delete %{_infodir}/nco.info.gz \ %{_infodir}/dir 2>/dev/null || : fi %files %defattr(-,root,root,-) %doc doc/README doc/LICENSE doc/rtfm.txt %{_bindir}/* %{_mandir}/*/* %{_infodir}/* %{_libdir}/libnco*[0-9]*.so %files devel %defattr(-,root,root,-) %{_includedir}/nco %{_libdir}/libnco*.a %{_libdir}/libnco.so %{_libdir}/libnco_c++.so # %{_libdir}/libnco++.so %changelog * Thu Feb 20 2014 Charlie Zender - 4.4.1-1 - new upstream 4.4.2 * Thu Jan 29 2014 Charlie Zender - 4.4.1-1 - new upstream 4.4.1 * Thu Jan 09 2014 Charlie Zender - 4.4.0-1 - new upstream 4.4.0 * Wed Dec 06 2013 Charlie Zender - 4.3.9-1 - new upstream 4.3.9 * Wed Nov 06 2013 Charlie Zender - 4.3.8-1 - new upstream 4.3.8 * Thu Oct 17 2013 Charlie Zender - 4.3.7-1 - new upstream 4.3.7 * Fri Sep 27 2013 Charlie Zender - 4.3.6-1 - new upstream 4.3.6 * Fri Sep 20 2013 Charlie Zender - 4.3.5-1 - new upstream 4.3.5 * Thu Aug 01 2013 Charlie Zender - 4.3.4-1 - new upstream 4.3.4 * Wed Jul 24 2013 Charlie Zender - 4.3.3-1 - new upstream 4.3.3 * Fri Jul 05 2013 Charlie Zender - 4.3.2-1 - new upstream 4.3.2 * Wed May 01 2013 Charlie Zender - 4.3.1-1 - new upstream 4.3.1 * Thu Mar 28 2013 Charlie Zender - 4.3.0-1 - new upstream 4.3.0 * Tue Mar 19 2013 Charlie Zender - 4.2.6-1 - new upstream 4.2.6 * Mon Jan 28 2013 Charlie Zender - 4.2.5-1 - new upstream 4.2.5 * Mon Jan 21 2013 Charlie Zender - 4.2.4-1 - new upstream 4.2.4 * Tue Nov 13 2012 Charlie Zender - 4.2.3-1 - new upstream 4.2.3 * Mon Oct 29 2012 Charlie Zender - 4.2.2-1 - new upstream 4.2.2 * Thu Aug 02 2012 Charlie Zender - 4.2.1-1 - new upstream 4.2.1 * Mon Jun 11 2012 Charlie Zender - 4.2.0-1 - new upstream 4.2.0 * Thu Mar 29 2012 Charlie Zender - 4.1.0-1 - new upstream 4.1.0 * Mon Feb 13 2012 Charlie Zender - 4.0.9-1 - new upstream 4.0.9 * Fri Mar 21 2011 Charlie Zender - 4.0.8-1 - new upstream 4.0.8 * Fri Jan 21 2011 Charlie Zender - 4.0.7-1 - new upstream 4.0.7 * Fri Jan 14 2011 Charlie Zender - 4.0.6-1 - new upstream 4.0.6 * Thu Oct 13 2010 Charlie Zender - 4.0.5-1 - new upstream 4.0.5 * Fri Sep 24 2010 Charlie Zender - 4.0.4-1 - new upstream 4.0.4 * Thu Sep 02 2010 Charlie Zender - 4.0.3-1 - new upstream 4.0.3 * Sun Jun 27 2010 Charlie Zender - 4.0.2-1 - new upstream 4.0.2 * Mon Apr 05 2010 Charlie Zender - 4.0.1-1 - new upstream 4.0.1 * Tue Jan 05 2010 Charlie Zender - 4.0.0-1 - new upstream 4.0.0 * Tue Jul 14 2009 Charlie Zender - 3.9.9-1 - new upstream 3.9.9 * Mon Mar 23 2009 Charlie Zender - 3.9.8-1 - new upstream 3.9.8 * Wed Mar 18 2009 Charlie Zender - 3.9.7-1 - new upstream 3.9.7 * Thu Jan 22 2009 Charlie Zender - 3.9.6-1 - new upstream 3.9.6 * Thu Oct 30 2008 Charlie Zender - 3.9.5-2 - buildrequire GSL * Sun May 11 2008 Charlie Zender - 3.9.5-1 - new upstream 3.9.5 * Mon Mar 03 2008 Charlie Zender - 3.9.4-1 - new upstream 3.9.4 * Sat Dec 08 2007 Charlie Zender - 3.9.3-1 - new upstream 3.9.3 * Wed Aug 29 2007 Charlie Zender - 3.9.2-1 - new upstream 3.9.2 * Fri Jun 29 2007 Charlie Zender - 3.9.1-1 - new upstream 3.9.1 * Tue Jun 19 2007 Daniel L. Wang - 3.9.0-1 - fix LDFLAGS to detect lib64 usage (workaround buggy libtool) * Fri May 25 2007 Charlie Zender - 3.9.0-1 - new upstream 3.9.0 * Fri Apr 20 2007 Charlie Zender - 3.2.0-1 - new upstream 3.2.0 (includes rmssdn arithmetic bugfix) * Sat Mar 10 2007 Charlie Zender - 3.1.9-1 - new 3.1.9 to synchronize upstream, debs, and RPMs * Sat Mar 10 2007 Charlie Zender - 3.1.8-1 - clean up nco.spec - verify ncap2 is built and distributed - buildrequire libdap, libdap-devel, libnc-dap, libnc-dap-devel - new upstream 3.1.8 * Sat Nov 11 2006 Charlie Zender - 3.1.7-1 - Merge Fedora nco.spec UDUnits patch into upstream configure.in - new upstream 3.1.7 * Sat Sep 2 2006 Ed Hill - 3.1.5-3 - br bison as well * Sat Sep 2 2006 Ed Hill - 3.1.5-2 - buildrequire flex * Sat Sep 2 2006 Ed Hill - 3.1.5-1 - new upstream 3.1.5 * Fri Apr 21 2006 Ed Hill - 3.1.2-1 - update to new upstream 3.1.2 * Thu Feb 16 2006 Ed Hill - 3.0.2-2 - rebuild for new gcc * Mon Sep 5 2005 Ed Hill - 3.0.2-1 - update to new upstream 3.0.2 * Wed Aug 3 2005 Ed Hill - 3.0.1-4 - remove (hopefully only temporarily) opendap support * Thu Jul 21 2005 Ed Hill - 3.0.1-3 - add LICENSE file * Sat Jul 9 2005 Ed Hill - 3.0.1-2 - add BuildRequires: opendap-devel * Sun Jun 19 2005 Ed Hill - 3.0.1-1 - update to upstream 3.0.1 - comment & fixes for BuildRequires * Sat Apr 23 2005 Ed Hill - 3.0.0-2 - add BuildRequires and fix CXXFLAGS per Tom Callaway - add udunits patch per Tom Callaway * Sat Apr 16 2005 Ed Hill - 3.0.0-1 - update to ver 3.0.0 - devel package fixes per D.M. Kaplan and M. Schwendt - fix info post/postun * Sun Dec 5 2004 Ed Hill - 0:2.9.9-0.fdr.4 - sync with netcdf-3.6.0beta6-0.fdr.0 - split into devel and non-devel * Wed Dec 1 2004 Ed Hill - 0:2.9.9-0.fdr.3 - sync with netcdf-0:3.5.1-0.fdr.11 - added '-fpermissive' for GCC 3.4.2 warnings - added "Provides:nco-devel" for the headers and libs * Mon Oct 4 2004 Ed Hill - 0:2.9.9-0.fdr.2 - Add some of Michael Schwendts suggested INC/LIB path fixes and sync with the netcdf-3.5.1-0.fdr.10 dependency. * Thu Sep 23 2004 Ed Hill - 0:2.9.9-0.fdr.1 - add NETCDF_INC and NETCDF_LIB to work on systems where old versions of netcdf may exist in /usr/local * Wed Sep 8 2004 Ed Hill - 0:2.9.9-0.fdr.0 - updated to ver 2.9.9 * Sat Aug 7 2004 Ed Hill - 0:2.9.8-0.fdr.0 - updated to ver 2.9.8 * Sat Jul 17 2004 Ed Hill - 0:2.9.7-0.fdr.2 - removed unneeded %ifarch * Sat Jul 17 2004 Ed Hill - 0:2.9.7-0.fdr.1 - Add %post,%postun * Sat Jul 17 2004 Ed Hill - 0:2.9.7-0.fdr.0 - Initial working version * Wed Mar 1 2000 Charlie Zender - 1.1.45-1 - Added original nco.spec to bld directory ./nco-4.4.2/bld/ddd_mpd.py0000755000674300045400000001377110316100242014464 0ustar zendercgdcsm#!/usr/bin/env python # spawns a ddd session for each one found in mpilistjobs # nco-specific: sends SIGUSR1 to nodeid>0 processes # $Id: ddd_mpd.py,v 1.2 2005/09/26 23:13:38 wangd Exp $ # Usage: # ./ddd_mpd.py # -- spawn ddd sessions for each MPI process found via # mpdlistjobs for a particular MPI job. Before spawning, send SIGUSR1 # to the processes of rank > 0 (the non-manager nodes) to reduce user # tedium. If multiple jobs are found on MPD, prompt user to select # one of jobs. # -- If no jobs owned by the current user are found in mpd, # complain and exit. # # Prefer something else than ddd? Try changing the argument at the # call to mainthing(...). Support hasn't been checked for # command-line arguments other than ddd/gdb, so you may have to hack # spawnDebugger(...) as a short-term solution. # # Please direct feedback to the sourceforge forums for NCO. Thanks, -Daniel from os import environ, getuid, getpid, path, getcwd, popen3 import os class Job: pass def newJob(jid, username, host, pid, sid, rank, path): job = Job() job.jobid = jid job.username = username job.host = host job.pid = pid job.sid = sid job.rank = rank job.pgm = path return job def readJobInfo(jobtext): job = Job() #print "got job ", jobtext lines = jobtext.split("\n") for line in lines: pair = line.split("=") if len(pair) > 1: key,value = pair #print key.strip(),value.strip() exec "job."+key.strip()+"="+"\""+value.strip()+"\"" return job; def readJobListMPD(): joblist = [] jobI, jobO, jobE = popen3("mpdlistjobs") allinfo = jobO.read() for jobtext in allinfo.split("\n\n"): joblist.append(readJobInfo(jobtext)) return joblist def makeSampleJobList(): ## dummy for testing joblist = [] joblist.append(newJob( "21@dirt_3734", "wangd", "dirt", "11931", "11926", "0", "/home/wangd/nco/nco/mpi_bin/mpncwa")) joblist.append(newJob( "21@dirt_3734", "wangd", "dirt", "11929", "11927", "1", "/home/wangd/nco/nco/mpi_bin/mpncwa")) joblist.append(newJob( "21@dirt_3734", "wangd", "dirt", "11930", "11928", "2", "/home/wangd/nco/nco/mpi_bin/mpncwa")) # next two jobs should be culled joblist.append(newJob( "10@dirt_3734", "somebody", "dirt", "112", "110", "0", "/badpath/mpncbo")) joblist.append(newJob( "10@dirt_3734", "somebody", "dirt", "119", "111", "1", "/badpath/mpncbo")) joblist.append(newJob( "24@dirt_3734", "wangd", "dirt", "11951", "11946", "0", "/home/wangd/nco/nco/mpi_bin/mpncbo")) joblist.append(newJob( "24@dirt_3734", "wangd", "dirt", "11949", "11947", "1", "/home/wangd/nco/nco/mpi_bin/mpncbo")) joblist.append(newJob( "24@dirt_3734", "wangd", "dirt", "11950", "11948", "2", "/home/wangd/nco/nco/mpi_bin/mpncbo")) return joblist def cutoutJobs(joblist, jobids, paths): print "There seems to be more than one job in MPD. Which would you like?" pick = "" index = -1 while not pick in jobids: for i in range(len(jobids)): print i,jobids[i], paths[i] print "which would you like(0..",len(jobids)-1,")?", typed = raw_input() try: index = int(typed) except ValueError: pass if index not in range(len(jobids)): print "Sorry, bad choice: ",typed, " Try another." else: pick = jobids[index] print "Chose id:", pick, " path:",paths[index] # remove job objects that do not match joblist = filter((lambda j: j.jobid == pick), joblist) return joblist def spawnDebugger(progname, joblist, debug): shI, shO, shE = popen3("sh") children = filter(lambda j: j.rank != "0", joblist) for c in children: # resume the children first s = "kill -USR1 %s\n" % (c.pid) if not debug: shI.write(s) else: print s, print "Node 0 is pid:",filter(lambda j: j.rank == "0",joblist)[0].pid shI.write("\n") for job in joblist: try: #print job.jobid, job.pid, job.rank, job.pgm dummy = job.pgm dummy = job.pid s = "%s %s %s &\n" % (progname, job.pgm, job.pid) if not debug: shI.write(s) #else: print s, except AttributeError: continue shI.close() print shO.read().strip() print shE.read().strip() def mainthing(dbgprogname): joblist = readJobListMPD() #joblist = makeSampleJobList() # for simple testing # now, go ahead and spawn ddd jobs. # for now, just spit out the command line so we don't have to deal # with the process management. *sigh* ####print len(joblist) jobids = [] paths = [] joblist = filter(lambda j: hasattr(j, "jobid"), joblist) myname = os.popen("whoami").read().strip() joblist = filter(lambda j: j.username == myname, joblist) if len(joblist) < 1: print "No acceptable jobs found." return for job in joblist: ## check to see how many jobs there are if not job.jobid in jobids: jobids.append( job.jobid ) paths.append( job.pgm ) if len(jobids) > 1: joblist = cutoutJobs(joblist, jobids, paths) spawnDebugger(dbgprogname, joblist, False) #False for no debug ## ----------------- ## main program body ## ----------------- mainthing("ddd") # if you like gdb or dbx, you may wish to try something like: # # mainthing ("xterm -e gdb") # # You will probably want to spawn xterms for each gdb to avoid # managing multiple gdb sessions from a single terminal window. ./nco-4.4.2/bld/pvmgetarch0000755000674300045400000001602512243250225014605 0ustar zendercgdcsm#!/bin/sh # $Id: pvmgetarch,v 1.9 2013/11/21 00:15:17 pvicente Exp $ # Purpose: Generate PVM architecture string # Usage: # cp ~/sh/pvmgetarch ~/nco/bld/pvmgetarch # cp ~/sh/pvmgetarch ~/aer/pvmgetarch # scp ~/sh/pvmgetarch dust.ess.uci.edu:/var/www/html/dead/pvmgetarch # This is a heuristic thing that may need to be tuned from time # to time. I don't know of a real solution to determining the # machine type. # Notes: # 1. Local people mess with things. # 2. It's good to try a few things for robustness. # 3. Don't use test -x # 08 Apr 1993 Robert Manchek manchek@CS.UTK.EDU. # 24 Aug 1994 last revision # 28 Jul 1995 release 3.3.8 # # begin section that may need to be tuned ARCH=UNKNOWN # # determine the machine type from scratch # if [ -f /bin/uname -o -f /usr/bin/uname \ -o -f /bin/uname.exe -o -f /usr/bin/uname.exe ]; then if [ -f /bin/uname ]; then os="`/bin/uname -s`" ht="`/bin/uname -m`" ov="`/bin/uname -v`" elif [ -f /usr/bin/uname ]; then os="`/usr/bin/uname -s`" ht="`/usr/bin/uname -m`" ov="`/usr/bin/uname -v`" elif [ -f /bin/uname.exe ]; then os="`/bin/uname.exe -s`" ht="`/bin/uname.exe -m`" ov="`/bin/uname.exe -v`" else os="`/usr/bin/uname.exe -s`" ht="`/usr/bin/uname.exe -m`" ov="`/usr/bin/uname.exe -v`" fi case "$os,$ht" in SunOS,sun3* ) ARCH=SUN3 ;; SunOS,sun4* ) ARCH=SUN4 ;; SunOS,i86pc ) ARCH=X86SOL2 ;; ULTRIX,RISC ) ARCH=PMAX ;; ULTRIX,VAX ) ARCH=UVAX ;; AIX*,* ) ARCH=RS6K ;; *HP*,9000/[2345]* ) ARCH=HP300 ;; *HP*,9000/[78]* ) ARCH=HPPA ;; IRIX,* ) ARCH=SGI ;; IRIX64,* ) ARCH=SGI64 ;; *OSF*,alpha ) ARCH=ALPHA ;; # 20031116 csz++ Implement AMD Linux,x86_64 ) ARCH=LINUXAMD64 ;; # csz-- Linux,alpha ) ARCH=LINUXALPHA ;; CRSOS,smp ) ARCH=CRAYSMP ;; *,paragon ) ARCH=PGON ;; dgux,AViiON ) ARCH=DGAV ;; *,88k ) ARCH=E88K ;; *,mips ) ARCH=MIPS ;; *,CRAY-2 ) ARCH=CRAY2 ;; Linux,i[3456]86 ) ARCH=LINUX ;; Linux,sparc) ARCH=LINUXSPARC ;; BSD/OS,i[3456]86 ) ARCH=BSD386 ;; FreeBSD,i386 ) ARCH=FREEBSD ;; # 20020812 csz++ Implement MACOSX Darwin,Power* ) ARCH=MACOSX ;; # csz-- # 20100705 csz++ Implement OS X on PC chips Darwin,x86_64 ) ARCH=MACOSX ;; # csz-- # 20020812 csz++ deprecate SX3 in favor of NECSX # SUPER-UX,SX-3 ) ARCH=SX3 ;; SUPER-UX,SX-* ) ARCH=NECSX ;; # csz-- uts,* ) ARCH=UTS2 ;; realix,M88* ) ARCH=M88K ;; DomainOS,DN* ) ARCH=APOLLO ;; OS/2,i[3456]86 ) ARCH=OS2 ;; esac fi if [ "$ARCH" = UNKNOWN ]; then if [ -f /bin/arch ]; then case "`/bin/arch`" in ksr1 ) ARCH=KSR1 ;; sun2 ) ARCH=SUN2 ;; sun3 ) ARCH=SUN3 ;; sun4 ) ARCH=SUN4 ;; esac fi fi if [ "$ARCH" = UNKNOWN ]; then if [ -f /usr/etc/RELDEF ]; then ARCH=ATT; fi if [ -f /ultrixboot ]; then if [ -f /pcs750.bin ]; then ARCH=UVAX else ARCH=PMAX fi else if [ -f /pcs750.bin ]; then ARCH=VAX; fi fi if [ -d /usr/alliant ]; then ARCH=AFX8; fi if [ -f /usr/bin/cluster ]; then ARCH=BFLY; fi if [ -d /usr/convex ]; then ARCH=CNVX; fi #++csz # if [ -f /unicos ]; then ARCH=CRAY; fi #--csz if [ -f /hp-ux ]; then ARCH=HP300; fi if [ -f /usr/bin/getcube ]; then ARCH=I860; fi if [ -f /usr/bin/asm56000 ]; then ARCH=NEXT; fi if [ -f /etc/vg ]; then ARCH=RS6K; fi if [ -d /usr/include/caif ]; then ARCH=RT; fi #++csz # Move check for /unicos to after /bin/4d because Ouray=Unicos 10.0.0 has both if [ -f /bin/4d ]; then ARCH=SGI; fi if [ -f /unicos ]; then ARCH=CRAY; fi #--csz if [ -f /dynix ]; then ARCH=SYMM; fi if [ -f /bin/titan ]; then ARCH=TITN; fi if [ -f /netbsd ]; then case "`/usr/bin/machine`" in i386) ARCH=NETBSDI386 ;; amiga) ARCH=NETBSDAMIGA ;; hp300) ARCH=NETBSDHP300 ;; mac68k) ARCH=NETBSDMAC68K ;; pmax) ARCH=NETBSDPMAX ;; sparc) ARCH=NETBSDSPARC ;; sun3) ARCH=NETBSDSUN3 ;; esac elif [ -f /usr/bin/machine ]; then case "`/usr/bin/machine`" in i386 ) ARCH=BSD386 ;; esac fi if [ -f /usr/bin/uxpm ] && /usr/bin/uxpm ; then ARCH=UXPM fi if [ -f /usr/bin/uxpv ] && /usr/bin/uxpv ; then ARCH=UXPV fi fi if [ "$ARCH" = UNKNOWN ]; then if [ -f /bin/uname -o -f /usr/bin/uname ]; then if [ -f /bin/uname ]; then os="`/bin/uname -s`" ht="`/bin/uname -m`" rv="`/bin/uname -r`" else os="`/usr/bin/uname -s`" ht="`/usr/bin/uname -m`" rv="`/usr/bin/uname -r`" fi case "$os,$ht" in CYGWIN*,x86_64) ARCH=WIN32 ;; esac case "$os,$ht" in *,i[3456]86 ) case "$rv" in 4.*) ARCH=UWARE ;; #csz++ # 20020708: Change SCO to WIN32 # *) ARCH=SCO ;; *) ARCH=WIN32 ;; #csz-- esac esac fi fi # # update the machine type to derive subclasses # if [ "$ARCH" = SUN4 ]; then rel="`/bin/uname -r`" case "$rel" in 5.* ) ARCH=SUN4SOL2 ;; esac fi if [ "$ARCH" = SUN4SOL2 ]; then #++csz nproc="`/bin/mpstat | /bin/wc -l`" # nproc="`/bin/mpstat | wc -l`" # Omit requirement that PVM_SHMEM be set to return SUNMP # Keep requirement that /bin/mpstat return multiple lines # if [ $nproc -gt 2 -a "$PVM_SHMEM" = ON ]; if [ $nproc -gt 2 ]; #--csz then ARCH=SUNMP; fi fi if [ "$ARCH" = ALPHA ]; then rel="`/usr/bin/uname -r`" case "$rel" in *[34].*) nproc="`/usr/sbin/sizer -p`" if [ $nproc -gt 1 -a "$PVM_SHMEM" = ON ]; then ARCH=ALPHAMP; fi ;; esac fi if [ "$ARCH" = SGI ]; then rel="`/bin/uname -r`" case "$rel" in 5.* ) ARCH=SGI5 ;; 6.* ) ARCH=SGI6 ;; esac fi if [ "$ARCH" = SGI64 ]; then #++csz nproc="`/usr/sbin/mpadmin -n | /bin/wc -w`" # Omit requirement that PVM_SHMEM be set to return SGIMP64 # Do require that /bin/mpadmin return more procs than winterpark # if [ $nproc -gt 1 -a "$PVM_SHMEM" = ON ]; # if [ $nproc -gt 9 ]; # 20020606: Only require 4 processors so utefe qualifies if [ $nproc -gt 4 ]; then ARCH=SGIMP64; fi fi if [ "$ARCH" = SGI5 ]; then nproc="`/usr/sbin/mpadmin -n | /bin/wc -w`" if [ $nproc -gt 1 -a "$PVM_SHMEM" = ON ]; then ARCH=SGIMP; fi fi if [ "$ARCH" = SGI6 ]; then nproc="`/usr/sbin/mpadmin -n | wc -w`" if [ $nproc -gt 1 -a "$PVM_SHMEM" = ON ]; then ARCH=SGIMP6; fi fi if [ "$ARCH" = SUN4 -a -f /dev/cm ]; then ARCH=CM2; fi if [ "$ARCH" = SUN4 -a -f /dev/cmni ]; then ARCH=CM5; fi if [ "$ARCH" = CNVX ]; then if /usr/convex/getsysinfo -f native_default; then ARCH=CNVXN fi fi if [ "$ARCH" = PMAX -a -d /usr/maspar ]; then ARCH=MASPAR; fi if [ "$ARCH" = RS6K ]; then # csz++ # case "$os,$ov" in case "$os" in # AIX*,4 ) nproc="`/usr/sbin/lsdev -C -c processor | wc -l`" AIX ) nproc="`/usr/sbin/lsdev -C -c processor | wc -l`" if [ $nproc -gt 1 -a "$PVM_SHMEM" = ON ]; then ARCH=AIX4MP; else # Make ACD machines (e.g., gss1.acd.ucar.edu) return plain old AIX # ARCH=AIX46K; ARCH=AIX; # csz-- fi ;; esac fi if [ "$ARCH" = HPPA -a -f /bin/sysinfo ]; then ARCH=CSPP; fi if [ "$ARCH" = HPPA ]; then nproc="`/usr/bin/vmstat -n | wc -l`" if [ $nproc -gt 8 -a "$PVM_SHMEM" = ON ]; then ARCH=HPPAMP; fi fi # # ugh, done. # echo $ARCH exit ./nco-4.4.2/bld/pbuilder-sid0000755000674300045400000000165010651265263015037 0ustar zendercgdcsm#!/bin/sh # Purpose: Use pbuilder to build packages in a chroot environment # Script from Jamin W. Collins BTS: #255165 # Name this script 'pbuilder-woody', 'pbuilder-sid', 'pbuilder-sarge', 'pbuilder-experimental' etc. OPERATION=$1 DISTRIBUTION=`basename $0 | cut -f2 -d '-'` PROCEED=false BASE_DIR="/chroot/pbuilder" case $OPERATION in create|update|build|clean|login|execute|dumpconfig ) PROCEED=true ;; esac if ( $PROCEED == true ) then shift pbuilder $OPERATION --distribution $DISTRIBUTION --debootstrap debootstrap --basetgz $BASE_DIR/$DISTRIBUTION/$DISTRIBUTION-base.tgz --override-config --configfile $BASE_DIR/$DISTRIBUTION/pbuilderrc --buildresult $BASE_DIR/$DISTRIBUTION/result $@ else echo "Invalid command..." echo "Valid commands are:" echo " create" echo " update" echo " build" echo " clean" echo " login" echo " execute" echo " dumpconfig" exit 1 fi ./nco-4.4.2/bld/nco_dst.pl0000755000674300045400000005015612274525123014521 0ustar zendercgdcsm#!/usr/bin/perl # Purpose: Perform NCO distributions # Script relies heavily on SSH connectivity between ${HOST}, ${CVSROOT}, and $www_mch # Usage: # Export tagged, public versions # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln nco-4_4_2 # Build, do not release on SF # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --sf nco-4_4_2 # Build, release on SF # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --nst_all nco-4_4_2 # Install, do not build # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --bld --cln --nst_all nco-4_4_2 # Build and install # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_cnt nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --acd_prs nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cgd_cnt nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --cray_prs nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --bbl_cnt nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --blk_cnt nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --dat_cnt nco-4_4_2 # ${HOME}/nco/bld/nco_dst.pl --dbg=2 --cln --ute_prs nco-4_4_2 # Export daily snapshot # ${HOME}/nco/bld/nco_dst.pl --dbg=2 # ${HOME}/nco/bld/nco_dst.pl --dbg=1 --cln --nst # Machines requiring interactive builds # cd ${HOME}/nco;cvs update;cd bld;make;make tst # scp ${HOME}/nco/bld/nco_dst.pl dust.ess.uci.edu:/home/zender/nco/bld/nco_dst.pl BEGIN{ unshift @INC,$ENV{'HOME'}.'/perl'; # Location of csz.pl and DBG.pm HaS98 p. 170 } # end BEGIN my $CVS_Header='$Header: /cvsroot/nco/nco/bld/nco_dst.pl,v 1.212 2014/02/05 21:17:07 zender Exp $'; # Specify modules use strict; # Protect all namespaces use Getopt::Long; # GNU-style getopt use File::Basename; # For parsing filenames # Personal modules use DBG; # Debugging constants require 'csz.pl'; # Contains date_time() # Set output flushing to help debugging on hard crashes # These options update filehandle after every output statement select((select(STDOUT),$|=1)[0]); # Camel book, p. 110 select((select(STDERR),$|=1)[0]); # Camel book, p. 110 # Timing information my ($lcl_date_time,$srt_usr_tm,$srt_sys_tm,$srt_child_usr_tm,$srt_child_sys_tm); ($lcl_date_time,$srt_usr_tm,$srt_sys_tm,$srt_child_usr_tm,$srt_child_sys_tm)=time_srt(); printf STDOUT ("Start user time %f\n",$srt_usr_tm); # Declare local variables my ($idx,$rcd); my ($prg_nm,$prg_dsc,$prg_vrs,$prg_date); my ($pth_in,$fl_sfx); my ($dst_vrs,$dst_fl,$doc_fl); my ($dst_fl_chg,$dst_fl_deb,$dst_fl_doc,$dst_fl_dsc,$dst_fl_tgz); my ($nco_vrs,$nco_vrs_mjr,$nco_vrs_mnr,$nco_vrs_pch); my ($dly_snp); my ($mk_cmd,$tar_cmd,$rmt_mch); my ($rsh_cmd,$rcp_cmd,$cp_cmd,$rm_cmd,$mkdir_cmd,$cvs_cmd); # Set defaults my $False=0; my $True=1; my $CVS_Date='$Date: 2014/02/05 21:17:07 $'; my $CVS_Id='$Id: nco_dst.pl,v 1.212 2014/02/05 21:17:07 zender Exp $'; my $CVS_Revision='$Revision: 1.212 $'; my $CVSROOT='zender@nco.cvs.sf.net:/cvsroot/nco'; # CVS repository my $DATA=$ENV{'DATA'}; my $HOME=$ENV{'HOME'}; my $HOST=$ENV{'HOST'}; my $PVM_ARCH=$ENV{'PVM_ARCH'}; my $bld=$False; # Option bld; Whether to rebuild netCDF distribution my $cp_cmd='cp -p -f'; # Command that behaves like cp my $cvs_cmd='cvs'; # Command that behaves like cvs (Use cvs -t for verbose output) my $data_nm=$ENV{'DATA'}; my $main_trunk_tag='nco'; my $mkdir_cmd='mkdir -p'; # Command that behaves like mkdir my $mdl_sng='nco'; # Base of module name my $rm_cmd='rm -f'; # Command that behaves like rm my $rcp_cmd='scp -p'; # Command that behaves like rcp my $rcp_cmd_no_prs_prm='scp'; # Command that behaves like rcp and does not try to preserve permissions my $rsh_cmd='ssh'; # Command that behaves like rsh my $usr_nm=$ENV{'USER'}; my $vrs_tag=''; my $www_mch='dust.ess.uci.edu'; # WWW machine for package my $www_drc='/var/www/html/nco'; # WWW directory for package my $www_mch_mrr='web.sf.net'; # WWW machine for package mirror my $www_drc_mrr='/home/project-web/nco/htdocs'; # WWW directory for package mirror # Set defaults for command line arguments my $sf=$False; # Release tarball and update SourceForge my $cln=$True; # GNU standard Makefile option `clean' my $dbg_lvl=0; my $dst_cln=$False; # GNU standard Makefile option `distclean' my $nst_all=$False; # Option nst_all; Install version on all machines my $acd_cnt=$False; # Option acd_cnt; Install version in acd contrib my $acd_prs=$False; # Option acd_prs; Install version in acd personal my $bbl_cnt=$False; # Option bbl_cnt; Install version in babyblue contrib my $blk_cnt=$False; # Option blk_cnt; Install version in blackforest contrib my $bls_cnt=$False; # Option bls_cnt; Install version in bluesky contrib my $dat_cnt=$False; # Option dat_cnt; Install version in dataproc contrib my $ute_prs=$False; # Option ute_prs; Install version in ute personal my $cgd_cnt=$False; # Option cgd_cnt; Install version in CGD contrib my $cgd_prs=$False; # Option cgd_prs; Install version in CGD personal my $cray_prs=$False; # Option cray_prs; Install version in Cray personal # Derived fields if($PVM_ARCH =~ m/SUN/){ # See Camel p. 81 for =~ and m// $tar_cmd='gtar'; $mk_cmd='make'; }elsif($PVM_ARCH =~ m/CRAY/){ $tar_cmd='tar'; $mk_cmd='gnumake'; }else{ $tar_cmd='tar'; $mk_cmd='make'; } # endelse if($data_nm eq ''){$data_nm='/data/'.$usr_nm;} my $dst_pth_pfx=$data_nm; # Parent of build directory if($dst_pth_pfx eq $HOME){die "$prg_nm: ERROR \$dst_pth_pfx eq $dst_pth_pfx";} # This could be disastrous if($rm_cmd =~ m/( -r)|( -R)|( --recursive)/){die "$prg_nm: ERROR Dangerous setting \$rm_cmd eq $rm_cmd";} # This would be disastrous # $CVSROOT=':pserver:anonymous@nco.cvs.sf.net:/cvsroot/nco'; # CVS repository $prg_dsc='NCO distribution maker'; # Program description ($prg_nm,$prg_vrs)=$CVS_Id =~ /: (.+).pl,v ([\d.]+)/; # Program name and version $prg_vrs.='*' if length('$Locker: $ ') > 12; # Tack '*' if it is not checked in into CVS. ($prg_nm,$pth_in,$fl_sfx)=fileparse($0,''); # $0 is program name Camel p. 136 if(length($CVS_Date) > 6){($prg_date)=unpack '@7 a19',$CVS_Date;}else{$prg_date='Unknown';} # Parse command line arguments: '!' means Boolean, '|' is OR, '=' specifies required argument: 'i' is integer, 'f' is float, 's' is string $rcd=GetOptions( # man Getopt::GetoptLong 'acd_cnt!' => \$acd_cnt, 'acd_prs!' => \$acd_prs, 'bld!' => \$bld, 'sf!' => \$sf, 'bbl_cnt!' => \$bbl_cnt, 'blk_cnt!' => \$blk_cnt, 'cgd_cnt!' => \$cgd_cnt, 'cgd_prs!' => \$cgd_prs, 'clean!' => \$cln, 'cln!' => \$cln, 'cray_prs!' => \$cray_prs, 'dat_cnt!' => \$dat_cnt, 'dbg_lvl=i' => \$dbg_lvl, 'distclean!' => \$dst_cln, 'dst_cln!' => \$dst_cln, 'nst_all!' => \$nst_all, 'ute_prs!' => \$ute_prs, ); # end GetOptions arguments # Parse positional arguments, if present if($#ARGV > 0){die "$prg_nm: ERROR Called with $#ARGV+1 positional arguments, need no more than 1\n";} elsif($#ARGV == 0){$vrs_tag=$ARGV[0];} # Version name is first positional argument, if present. if($nst_all){ $cgd_prs=$True; $cgd_cnt=$True; $acd_prs=$True; $acd_cnt=$True; $ute_prs=$True; $bbl_cnt=$True; $blk_cnt=$True; $dat_cnt=$True; $cray_prs=$True; } # endif # Print initialization state if($dbg_lvl >= 1){print ("$prg_nm: $prg_dsc, version $prg_vrs of $prg_date\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$vrs_tag = $vrs_tag\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$dbg_lvl = $dbg_lvl\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$bld = $bld\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$sf = $sf\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$cln = $cln\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$dst_cln = $dst_cln\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$nst_all = $nst_all\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$mk_cmd = $mk_cmd\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$tar_cmd = $tar_cmd\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$acd_cnt = $acd_cnt\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$acd_prs = $acd_prs\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$cgd_cnt = $cgd_cnt\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$cgd_prs = $cgd_prs\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$cray_prs = $cray_prs\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$bbl_cnt = $bbl_cnt\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$blk_cnt = $blk_cnt\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$dat_cnt = $dat_cnt\n");} # endif dbg if($dbg_lvl >= 2){print ("$prg_nm: \$ute_prs = $ute_prs\n");} # endif dbg if($vrs_tag eq $main_trunk_tag || $vrs_tag eq ''){$dly_snp=$True;}else{$dly_snp=$False;} # NCO is distributed using the `cvs export' command, so version tag to be distributed must be supplied to this script if($dly_snp){ # The version tag is blank or of the form `nco' $nco_vrs=YYYYMMDD(); $dst_vrs=$mdl_sng.'-'.$nco_vrs; }else{ # The version tag is of the form `nco-1_2_0' my ($tag_sng); my ($nco_psn); $tag_sng=$vrs_tag; $tag_sng=~s/_/./g; # Use =~ to bind $tag_sng to s/// Camel p. 81 $nco_vrs=substr($tag_sng,length($mdl_sng)+1,length($tag_sng)-length($mdl_sng)-1); # The +/- 1 accounts for the dash '-' ($nco_vrs_mjr,$nco_vrs_mnr,$nco_vrs_pch)=split(/\./,$nco_vrs); $dst_vrs=$mdl_sng.'-'.$nco_vrs; if($nco_vrs_mjr < 1 || $nco_vrs_mjr > 4){die "$prg_nm: ERROR $nco_vrs_mjr < 1 || $nco_vrs_mjr > 3"}; } # endelse $doc_fl="$HOME/nco/doc/nco.dvi $HOME/nco/doc/nco.html $HOME/nco/doc/nco.ps $HOME/nco/doc/nco.pdf $HOME/nco/doc/nco.txt $HOME/nco/doc/nco.xml"; # Derived documentation $dst_fl=$dst_vrs.'.tar.gz'; # Standard tarball distribution $dst_fl_chg=$mdl_sng.'_'.$nco_vrs.'-1_*.changes'; # Debian changes $dst_fl_deb=$mdl_sng.'_'.$nco_vrs.'-1_*.deb'; # Debian executables and libraries $dst_fl_doc=$mdl_sng.'-doc_'.$nco_vrs.'-1_all.deb'; # Debian documentation (deprecated) $dst_fl_dsc=$mdl_sng.'_'.$nco_vrs.'-1.dsc'; # Debian description $dst_fl_tgz=$mdl_sng.'_'.$nco_vrs.'.orig.tar.gz'; # Debian tarball my $dst_pth_bld=$dst_pth_pfx.'/'.$dst_vrs; # Build directory if($dbg_lvl >= 1){ print STDOUT "$prg_nm: Version to release: $vrs_tag\n"; print STDOUT "$prg_nm: Distribution version: $dst_vrs\n"; print STDOUT "$prg_nm: Distribution file: $dst_fl\n"; print STDOUT "$prg_nm: NCO version: $nco_vrs\n"; print STDOUT "$prg_nm: NCO major version: $nco_vrs_mjr\n"; print STDOUT "$prg_nm: NCO minor version: $nco_vrs_mnr\n"; print STDOUT "$prg_nm: NCO patch version: $nco_vrs_pch\n"; } # end if dbg # Build distribution from scratch if($bld){ cmd_prc("$rm_cmd -r $dst_pth_bld"); # Remove contents of current directory, if any # cmd_prc("$mkdir_cmd $dst_pth_bld"); # Create directory chdir $dst_pth_pfx or die "$prg_nm: ERROR unable to chdir to $dst_pth_pfx: $!\n"; # $! is system error string if($CVSROOT =~ m/pserver/){cmd_prc("$cvs_cmd -d $CVSROOT login");} # Login first if($dly_snp){ cmd_prc("$cvs_cmd -d $CVSROOT export -kkv -D \"1 second ago\" -d $dst_vrs nco"); # Export }else{ cmd_prc("$cvs_cmd -d $CVSROOT export -kkv -r $vrs_tag -d $dst_vrs nco"); # Export } # endelse cmd_prc("printf $nco_vrs > $dst_pth_bld/doc/VERSION"); # Stamp version in VERSION file in exported files cmd_prc("printf $nco_vrs > $HOME/nco/doc/VERSION"); # Stamp version in VERSION file in development directory # cmd_prc("ln -s $dst_pth_bld/bld/nco.spec $dst_pth_bld/bld/nco-$nco_vrs.spec"); # Stamp version in VERSION file # Make sure documentation files are up to date my $bld_pth=$dst_pth_pfx.'/'."$dst_vrs".'/bld'; chdir $bld_pth or die "$prg_nm: ERROR unable to chdir to $bld_pth: $!\n"; # $! is system error string cmd_prc("$mk_cmd doc"); cmd_prc("$mk_cmd clean"); # Set up FTP server chdir $dst_pth_pfx or die "$prg_nm: ERROR unable to chdir to $dst_pth_pfx: $!\n"; # $! is system error string cmd_prc("$cp_cmd $doc_fl ./$dst_vrs/doc"); # Copy derived documentation to source directory cmd_prc("$tar_cmd cvzf $dst_fl --exclude='nco-4.4.2/debian*' --exclude='.cvsignore' --exclude=ncap_lex.c --exclude=ncap_yacc.[ch] ./$dst_vrs"); # Create gzipped tarfile cmd_prc("$rsh_cmd $www_mch $rm_cmd $www_drc/src/$dst_fl"); # Remove any distribution with same name if($dly_snp){cmd_prc("$rsh_cmd $www_mch $rm_cmd -r $www_drc/src/nco-????????.tar.gz");} # Remove previous daily snapshots from WWW server cmd_prc("$rcp_cmd $dst_fl $www_mch:$www_drc/src"); # Copy local tarfile to WWW server cmd_prc("$rcp_cmd $DATA/$dst_fl_chg $DATA/$dst_fl_deb $DATA/$dst_fl_dsc $DATA/$dst_fl_tgz $www_mch:$www_drc/src"); # Copy Debian files to WWW server # Full release procedure (public releases only) includes update Web pages if(!$dly_snp){ cmd_prc("$rsh_cmd $www_mch $rm_cmd $www_drc/nco.tar.gz"); cmd_prc("$rsh_cmd $www_mch \"cd $www_drc; ln -s -f ./src/$dst_fl nco.tar.gz\""); cmd_prc("$rcp_cmd $dst_pth_bld/doc/index.shtml $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/nco.png $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/nco_news.shtml $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/nco.html $dst_pth_bld/doc/nco.info* $dst_pth_bld/doc/nco.dvi $dst_pth_bld/doc/nco.pdf $dst_pth_bld/doc/nco.ps $dst_pth_bld/doc/nco.texi $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/README $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/TODO $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/VERSION $www_mch:$www_drc"); cmd_prc("$rcp_cmd $dst_pth_bld/doc/ChangeLog $www_mch:$www_drc"); } # endif # Update SourceForge mirror # Use rcp_cmd_no_prs_prm because scp appears to quit without notice if too many warnings errors occur copying first files # Usually scp_cmd includes -p switch to preserve permissions and times, but sourceforge server does not allow this # Hence it generates warnings when used with -p, and is not properly updated if($sf){ cmd_prc("$rcp_cmd_no_prs_prm $dst_pth_bld/doc/index.shtml $dst_pth_bld/doc/nco.png $dst_pth_bld/doc/nco_news.shtml $dst_pth_bld/doc/README $dst_pth_bld/doc/TODO $dst_pth_bld/doc/VERSION $dst_pth_bld/doc/ChangeLog $usr_nm,nco\@$www_mch_mrr:$www_drc_mrr"); cmd_prc("$rcp_cmd_no_prs_prm $dst_pth_bld/doc/nco.html $dst_pth_bld/doc/nco.info* $dst_pth_bld/doc/nco.dvi $dst_pth_bld/doc/nco.pdf $dst_pth_bld/doc/nco.ps $dst_pth_bld/doc/nco.ps $dst_pth_bld/doc/nco.texi $usr_nm,nco\@$www_mch_mrr:$www_drc_mrr"); cmd_prc("$rcp_cmd_no_prs_prm $dst_pth_pfx/$dst_fl $DATA/$dst_fl_chg $DATA/$dst_fl_deb $DATA/$dst_fl_dsc $DATA/$dst_fl_tgz $usr_nm,nco\@$www_mch_mrr:$www_drc_mrr/src"); # Copy Debian files to WWW server # Shell commands on SourceForge disabled 20081018 # cmd_prc("$rsh_cmd $www_mch_mrr \"cd $www_drc_mrr; ln -s -f ./src/$dst_fl nco.tar.gz\""); } # endif SourceForge # Housekeeping if($cln){cmd_prc("$rm_cmd $dst_pth_pfx/$dst_fl");} # Remove local tarfile if($dst_cln){cmd_prc("$rm_cmd -r $dst_pth_bld");} # Remove local distribution # Sanity check cmd_prc("$rsh_cmd $www_mch ls -l $www_drc"); } # endif bld if($acd_prs){ $rmt_mch='acd.ucar.edu'; print STDOUT "\n$prg_nm: Updating private NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"cd ~/nco;$cvs_cmd update\""); cmd_prc("$rsh_cmd $rmt_mch \"cd ~/nco/bld;make cln all tst\""); # Unfortunately, sudo does not work at all with rsh # cmd_prc("$rsh_cmd $rmt_mch \"sudo cp /gs/zender/bin/LINUX/nc* /usr/local/bin\""); print STDOUT "$prg_nm: Done updating private NCO binaries on $rmt_mch\n\n"; } # endif acd_prs if($acd_cnt){ $rmt_mch='garcia.acd.ucar.edu'; print STDOUT "\n$prg_nm: Updating private NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"cd ~/nco;/local/bin/$cvs_cmd update\""); cmd_prc("$rsh_cmd $rmt_mch \"cd ~/nco/bld;/local/bin/gmake cln all tst\""); # Unfortunately, sudo does not work at all with rsh # cmd_prc("$rsh_cmd $rmt_mch \"sudo cp /a1/zender/bin/ALPHA/nc* /usr/local/bin\""); print STDOUT "$prg_nm: Done updating private NCO binaries on $rmt_mch\n\n"; } # endif acd_cnt if($cgd_cnt){ $rmt_mch='sanitas.cgd.ucar.edu'; # $rsh_cmd $rmt_mch 'printf $PVM_ARCH' print STDOUT "\n$prg_nm: Updating contrib NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;gtar -xvzf nco.tar.gz;rm nco.tar.gz\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /contrib/nco-1.1/bin; setenv MY_LIB_DIR /contrib/nco-1.1/lib; setenv MY_OBJ_DIR /usr/tmp/$usr_nm/$dst_vrs/obj; gmake cln all test\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif cgd_cnt if($dat_cnt){ $rmt_mch='dataproc.ucar.edu'; # $rsh_cmd $rmt_mch 'printf $PVM_ARCH' print STDOUT "\n$prg_nm: Updating contrib NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;tar -xvzf nco.tar.gz;rm nco.tar.gz\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /contrib/nco-1.1/bin; setenv MY_LIB_DIR /contrib/nco-1.1/lib; setenv MY_OBJ_DIR /usr/tmp/$usr_nm/$dst_vrs/obj; gmake cln all tst\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif dat_cnt if($bbl_cnt){ $rmt_mch='babyblue.ucar.edu'; # $rsh_cmd $rmt_mch 'printf $PVM_ARCH' print STDOUT "\n$prg_nm: Updating contrib NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;gunzip nco.tar.gz;tar -xvf nco.tar;rm nco.tar\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /home/blackforest/$usr_nm/bin/AIX; setenv MY_LIB_DIR /home/blackforest/$usr_nm/lib/AIX; setenv MY_OBJ_DIR /home/blackforest/$usr_nm/obj/AIX; setenv NETCDF_INC /usr/local/include; setenv NETCDF_LIB /usr/local/lib32/r4i4; gmake cln all tst\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif bbl_cnt if($blk_cnt){ $rmt_mch='blackforest.ucar.edu'; # $rsh_cmd $rmt_mch 'printf $PVM_ARCH' print STDOUT "\n$prg_nm: Updating contrib NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;gunzip nco.tar.gz;tar -xvf nco.tar;rm nco.tar\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /home/blackforest/$usr_nm/bin/AIX; setenv MY_LIB_DIR /home/blackforest/$usr_nm/lib/AIX; setenv MY_OBJ_DIR /home/blackforest/$usr_nm/obj/AIX; setenv NETCDF_INC /usr/local/include; setenv NETCDF_LIB /usr/local/lib32/r4i4; gmake cln all tst\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif blk_cnt if($ute_prs){ $rmt_mch='utefe.ucar.edu'; # utefe and ute are cross-mounted, utefe is for interactive logins # $rsh_cmd $rmt_mch 'printf $PVM_ARCH' print STDOUT "\n$prg_nm: Updating personal NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;tar -xvzf nco.tar.gz;rm nco.tar.gz\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /home/ute/$usr_nm/bin/SGIMP64/bin; setenv MY_LIB_DIR /home/ute/$usr_nm/bin/SGIMP64/lib; setenv MY_OBJ_DIR /usr/tmp/$usr_nm/$dst_vrs/obj; gmake cln all tst\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif ute_prs if($cray_prs){ $rmt_mch='ouray.ucar.edu'; print STDOUT "\n$prg_nm: Updating private NCO on $rmt_mch...\n"; cmd_prc("$rsh_cmd $rmt_mch \"$rm_cmd -r /usr/tmp/$usr_nm/nco*\""); cmd_prc("$rsh_cmd $rmt_mch \"$mkdir_cmd /usr/tmp/$usr_nm/$dst_vrs/obj\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm;gunzip nco.tar.gz;tar -xvf nco.tar;rm nco.tar*\""); cmd_prc("$rsh_cmd $rmt_mch \"cd /usr/tmp/$usr_nm/$dst_vrs/bld; setenv MY_BIN_DIR /home/ouray0/$usr_nm/bin/CRAY; setenv MY_LIB_DIR /usr/tmp/$usr_nm/$dst_vrs/lib; setenv MY_OBJ_DIR /usr/tmp/$usr_nm/$dst_vrs/obj; gnumake cln all tst\""); print STDOUT "$prg_nm: Done updating contrib NCO on $rmt_mch\n\n"; } # endif cray_prs ./nco-4.4.2/bld/libnco_tst.c0000644000674300045400000000230210261164017015015 0ustar zendercgdcsm/* Purpose: Test NCO library libnco Usage: cd ~/nco/bld Linux: gcc -I../src/nco -o libnco_tst libnco_tst.c -L${MY_LIB_DIR} -lnco AIX: All at once: xlc_r -bnoquiet -I../src/nco -I/usr/local/include -o libnco_tst libnco_tst.c -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco -lnetcdf xlc_r -bnoquiet -I../src/nco -I/usr/local/include -o libnco_tst -Wl,-blibpath:${MY_LIB_DIR}:/usr/lpp/xlopt:/usr/lib/threads:/usr/lib:/lib libnco_tst.c -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco -lnetcdf xlc_r -c -I../src/nco -I/usr/local/include -o libnco_tst.o libnco_tst.c xlc_r -bnoquiet -o libnco_tst libnco_tst.o -L${MY_LIB_DIR} -L${NETCDF_LIB} -lnco -lnetcdf xlc_r -bnoquiet -o libnco_tst libnco_tst.o -L${NETCDF_LIB} -lnco -lnetcdf ld -o libnco_tst libnco_tst.o -L${MY_LIB_DIR},-lnco ld -o libnco_tst libnco_tst.o -L${MY_LIB_DIR},-lnco -L/usr/lpp/xlopt,-lxlopt,-lc libnco_tst.o /lib/crt0_64.o */ #include #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main() { const char * const CVS_Id="$Id: libnco_tst.c,v 1.3 2005/07/01 06:51:59 zender Exp $"; const char * const CVS_Revision="$Revision: 1.3 $"; (void)copyright_prn(CVS_Id,CVS_Revision); } ./nco-4.4.2/bld/Makefile0000644000674300045400000023527112301430252014160 0ustar zendercgdcsm# $Header: /cvsroot/nco/nco/bld/Makefile,v 1.691 2014/02/20 16:43:22 zender Exp $ -*-makefile-*- # Purpose: GNU Makefile for NCO module nco # Requires GNU Make---AT&T Make chokes on GNU syntax # Copyright (C) 1994--2014 Charlie Zender # License: GNU General Public License (GPL) Version 3 # See http://www.gnu.org/copyleft/gpl.html for full license text # Quickie test copies: # scp ~/nco/bld/Makefile tephra.ess.uci.edu:nco/bld # scp ~/nco/bld/Makefile dust.ess.uci.edu:nco/bld # scp ~/nco/bld/Makefile gplogin2.ps.uci.edu:nco/bld # Machine build parameters # givre.ess.uci.edu : Source: NCO + netCDF, Method: Makefile, Packages: All else # roulee.ess.uci.edu : Source: NCO + netCDF, Method: Makefile, Packages: All else # neige.ess.uci.edu : Source: NCO , Method: Makefile, Packages: All else # dust.ess.uci.edu : Source: - , Method: - , Packages: All # glace.ess.uci.edu : Source: NCO , Method: Configure, Packages: All else # grele.ess.uci.edu : Source: NCO , Method: Makefile, Packages: All else # tephra.ess.uci.edu : Source: NCO , Method: Makefile, Packages: All else # yellowstone.ucar.edu: Source: NCO , Method: Makefile, Packages: All else # Usage (testing): # make tst # Vanilla regression test # make FL_FMT=netcdf4 tst # netCDF4 regression test # make MPI_PRC=3 tst # MPI regression test # make MPI_PRC=3 bm # MPI benchmarks # make THR_NBR=2 tst # OpenMP regression test # make THR_NBR=2 bm # OpenMP benchmarks # make NETCDF4=Y # netCDF4 features # make PNETCDF=Y # pnetCDF features # make ZNETCDF=Y # znetCDF features # Usage (Compilation): # cd ~/nco/qt;qmake;make;cd - # Qt # cd ~/nco/bld;make;cd - # Default build # cd ~/nco/bld;make USR_TKN='-DNC_HAVE_RENAME_GRP';cd - # New API # cd ~/nco/bld;make UDUNITS_INC='/usr/include/udunits2';cd - # Fedora build # cd ~/nco/bld;make cln bin_cln;cd - # Clean all dependencies for fresh build # cd ~/nco/bld;make dir all; cd - # Create target directories then build # cd ~/nco/bld;make dbg;cd - # Print make diagnostics # cd ~/nco/bld;make DAP_OPENDAP=Y;cd - # DAP support via OPeNDAP # cd ~/nco/bld;make DPKG=Y;cd - # Debian hardening # cd ~/nco/bld;make GSL=Y;cd - # GSL support # cd ~/nco/bld;make I18N=Y;cd - # Internationalization # cd ~/nco/bld;make lib_cln;cd - # Clean libraries # cd ~/nco/bld;make MPI=Y;cd - # MPI support # cd ~/nco/bld;make MPI_FAKE=Y;cd - # Spoof MPI support # cd ~/nco/bld;make OMP=Y;cd - # OpenMP support # cd ~/nco/bld;make OPTS=D;cd - # "Debugging": Enough symbols for debugging (default) # cd ~/nco/bld;make OPTS=O;cd - # "Optimize": For production (includes symbols) # cd ~/nco/bld;make OPTS=R;cd - # "Regular": No optimization or debugging # cd ~/nco/bld;make OPTS=X;cd - # "eXtreme": All debugging switches available # cd ~/nco/bld;make sys;cd - # Install in /usr/local (must sudo) # cd ~/nco/bld;make SZ=Y;cd - # Szip support # cd ~/nco/bld;make UDUNITS=Y;cd - # UDUnits support # cd ~/nco/bld;make UDUNITS2=Y;cd - # UDUnits2 support # cd ~/nco/bld;make --jobs=4;cd - # Parallel make # Normal (Linux) developer systems: # cd ${HOME}/nco/bld;make cln all ncap2;cd - # New default for most machines # cd ${HOME}/nco/bld;make OMP=Y CUDA=Y OPTS=D NETCDF4=Y UDUNITS2=Y allinone;cd - # givre # cd ${HOME}/nco/bld;make OMP=Y OPTS=D NETCDF4=Y UDUNITS2=Y allinone;cd - # givre, neige # cd ${HOME}/nco/bld;make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS2=Y allinone;cd - # glace, virga # mpi-selector --set openmpi_gcc-1.3.3 # Then use /sopt/netcdf/netcdf3-gcc-serial serial libraries # mpi-selector --set mpich_pgi_1.2.7p1 # After compiling # cd ${HOME}/nco/bld;ANTLR_ROOT=/sopt/gfortran_g++ CNK=N NETCDF_ROOT=/sopt/gfortran_g++ SZ_LIB=/sopt/lib UDUNITS_INC=/sopt/include UDUNITS_LIB=/sopt/lib make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=Y SZ=Y UDUNITS2=N allinone;cd - # greenplanet gcc # cd ${HOME}/nco/bld;ANTLR=/home/pvicente/install/antlr-2.7.7/bin/antlr ANTLR_ROOT=/home/pvicente/install/antlr-2.7.7 NETCDF_ROOT=/home/pvicente/install/netcdf-4.3.0 UDUNITS_INC=/home/pvicente/install/udunits-2.1.24/include UDUNITS_LIB=/home/pvicente/install/udunits-2.1.24/lib make OPTS=D allinone;cd - # greenplanet gcc pedro # cd ${HOME}/nco/bld;ANTLR=/sopt/ifort_icpc/bin/antlr ANTLR_ROOT=/sopt/ifort_icpc CNK=N SZ_LIB=/sopt/lib UDUNITS_INC=/sopt/include UDUNITS_LIB=/sopt/lib make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=Y SZ=Y UDUNITS2=N allinone;cd - # greenplanet intel # cd ${HOME}/nco/bld;ANTLR=/sopt/pgf90_pgcc/bin/antlr ANTLR_ROOT=/sopt/pgf90_pgcc CNK=N SZ_LIB=/sopt/lib UDUNITS_INC=/sopt/include UDUNITS_LIB=/sopt/lib make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=N SZ=Y UDUNITS2=N allinone;cd - # greenplanet pgi # cd ${HOME}/nco/bld;make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS2=Y allinone;cd - # pbs # cd ${HOME}/nco/bld;make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS2=Y allinone;cd - # grele # cd ${HOME}/nco/bld;make NETCDF4=N all ncap2;cd - # tephra # cd ${HOME}/nco/bld;make OMP=Y DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS2=N allinone;cd - # silt, clay # cd ${HOME}/nco/bld;NETCDF_INC='/usr/include/netcdf-3' NETCDF_LIB='/usr/lib64' make GSL=N OMP=N DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS=N allinone;cd - # snow # cd ${HOME}/nco/bld;make OMP=N DAP_OPENDAP=Y OPTS=D NETCDF4=N UDUNITS2=N USR_TKN='-DNEED_NC_INQ_FORMAT' allinone;cd - # snow w/OPeNDAP # cd ${HOME}/nco/bld;make OPTS=D USR_TKN='-DNEED_NC_INQ_FORMAT' allinone;cd - # 64-bit ABI on UCI MPC: # cd ${HOME}/nco/bld;env ANTLR='/software/antlr/bin/antlr' ANTLR_ROOT='/software/antlr' UDUNITS_INC='/software/udunits/include' UDUNITS_LIB='/software/udunits/lib' make --jobs=1 ABI=64 allinone;cd - # 64-bit ABI on UCI IPCC: # cd ${HOME}/nco/bld;env ANTLR='/usr/local/pgi/bin/antlr' ANTLR_ROOT='/usr/local/pgi' make --jobs=1 ABI=64 allinone;cd - # 64-bit ABI netCDF3 on NCAR AIX systems (bluefire): # cd ~/nco/bld;ANTLR='/contrib/antlr-2.7.7/bin/antlr' ANTLR_ROOT='/contrib/antlr-2.7.7' GSL_INC='/contrib/gsl-1.12/include' GSL_LIB='/contrib/gsl-1.12/lib' NETCDF_LIB='/usr/local/lib64/r4i4' UDUNITS_INC='/contrib/udunits-1.12.9/include' UDUNITS_LIB='/contrib/udunits-1.12.9/lib' make --jobs=1 DAP_OPENDAP=N OPTS=D NETCDF4=N UDUNITS2=N allinone ABI=64;cd - # 64-bit ABI netCDF4 on NCAR AIX systems (bluefire): # cd ~/nco/bld;ANTLR='/contrib/antlr-2.7.7/bin/antlr' ANTLR_ROOT='/contrib/antlr-2.7.7' CURL_LIB='/contrib/curl/7.21.2/lib' GSL_INC='/contrib/gsl-1.12/include' GSL_LIB='/contrib/gsl-1.12/lib' HDF5_ROOT='/contrib/hdf5-1.8.7_seq' LDFLAGS='-lnetcdf -lhdf5_hl -lhdf5 -lz' NETCDF_ROOT='/contrib/netcdf/4.1.3_seq' SZ_LIB='/contrib/szip/lib' UDUNITS_LIB='/contrib/zlib/lib' make --jobs=1 OPTS=D SZ=Y allinone ABI=64;cd - # 64-bit ABI netCDF4 on NCAR AIX systems (bluefire): # cd ~/bin/AIX;/usr/local/bin/tar cvzf ~/nco-4.4.2.aix53.tar.gz nc*;scp ~/nco-4.4.2.aix53.tar.gz zender,nco@web.sf.net:/home/project-web/nco/htdocs/src # netCDF4 on NCAR Linux cluster systems (mirage): # cd ~/nco/bld;make OPTS=D allinone;cd - # netCDF4 on NCAR Linux cluster systems (yellowstone): # /ncar/opt/hpss/hsi # Starts HPSS session # export PATH=${PATH}\:/ncar/opt/hpss # GNU (works): # module swap intel gnu;module add gsl;module add netcdf/4.3.0-rc4; # export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}\:/glade/apps/opt/udunits/2.1.24/gnu/default/lib # cd ~/nco/bld;make NETCDF_ROOT='/glade/apps/opt/netcdf/4.3.0-rc4/gnu/default' UDUNITS_INC='/glade/apps/opt/udunits/2.1.24/gnu/default/include' UDUNITS_LIB='/glade/apps/opt/udunits/2.1.24/gnu/default/lib' OPTS=D allinone;cd - # Intel (works as of 20140129): # module add intel;module add gsl;module add netcdf/4.3.0-rc4; # export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}\:/glade/apps/opt/udunits/2.1.24/intel/12.1.4/lib # cd ~/nco/bld;make NETCDF_ROOT='/glade/apps/opt/netcdf/4.3.0-rc4/intel/default' UDUNITS_INC='/glade/apps/opt/udunits/2.1.24/intel/12.1.4/include' UDUNITS_LIB='/glade/apps/opt/udunits/2.1.24/intel/12.1.4/lib' OPTS=D allinone;cd - # Cygwin on Windows Vista systems: # cd ~/nco/bld;ANTLR='antlr' make --jobs=1 GSL=Y OPTS=D NETCDF4=Y UDUNITS2=Y allinone;cd - # cd ~/bin/WIN32;tar cvzf ~/nco-4.4.2.win32.cygwin.tar.gz nc* ; scp ~/nco-4.4.2.win32.cygwin.tar.gz zender,nco@web.sf.net:/home/project-web/nco/htdocs/src # Data files to dust # cd ~/nco/data;scp cmip5.nc obs.nc mdl.nc mdl2.nc in_grp*.nc in.nc dust.ess.uci.edu:/var/www/html/nco # Top-level tokens defining directory structure # These tokens may be over-ridden by environment variables or when invoking make, e.g., make DAP_OPENDAP=Y MY_BLD_DIR := ../bld ifndef PVM_ARCH PVM_ARCH := $(shell ${MY_BLD_DIR}/pvmgetarch) endif ifndef MY_BIN_DIR MY_BIN_DIR := ../bin endif ifndef MY_LIB_DIR MY_LIB_DIR := ../lib endif ifndef MY_MAN_DIR MY_MAN_DIR := ../man endif ifndef MY_OBJ_DIR MY_OBJ_DIR := ../obj endif MY_BM_DIR := ../bm MY_DAT_DIR := ../data MY_DBN_DIR := ../debian MY_DOC_DIR := ../doc MY_DPN_DIR := ${MY_OBJ_DIR} MY_QT_DIR := ../qt MY_SRC_DIR := ../src/nco MY_INC_DIR := ${MY_SRC_DIR} NCO_CXX_SRC_DIR := ${MY_SRC_DIR}/../nco_c++ NCOXX_SRC_DIR := ${MY_SRC_DIR}/../nco++ # Primary tokens which determine build options # Specify non-default when invoking make, e.g. make DAP_OPENDAP=Y ifndef ${ABI} # 32- vs. 64-bit ABI: 32=32-bit mode, 64=64-bit mode (default) if available ABI := 64 endif # endif ABI ifndef ${CCACHE} CCACHE := N endif # CCACHE ifndef CNK # Use newer netCDF4.1 chunking API CNK := Y endif # endif CNK ifndef ${CUDA} CUDA := N endif # CUDA ifndef DAP_NETCDF DAP_NETCDF := Y endif # DAP_NETCDF ifndef DAP_OPENDAP DAP_OPENDAP := N endif # DAP_OPENDAP ifndef ${DBG} # Debugging token N=No (default) Y=Yes DBG := N endif # endif DBG ifndef ${DPKG} # Debian hardening tokens DPKG := N endif # endif DPKG ifdef FL_FMT # Pass this netCDF4 argument to nco_bm.pl FL_FMT_SNG := "--fl_fmt=${FL_FMT}" else # endif FL_FMT FL_FMT_SNG := endif # endif FL_FMT ifndef GCC_RCH_ARG GCC_RCH_ARG := endif # endif GCC_RCH_ARG ifndef GSL # Use GSL functionality GSL := Y endif # endif GSL ifndef ICC_RCH_ARG ICC_RCH_ARG := endif # endif ICC_RCH_ARG ifndef I18N I18N := N endif ifndef NCO_YY_PFX NCO_YY_PFX := nco_yy endif ifndef MK_DPN MK_DPN = ${CPP} -M # NB: Recursive expansion required MK_DPN_CXX = ${CXX} -M # NB: Recursive expansion required endif # endif MK_DPN ifndef ${MPI} # MPI MPI := N endif # endif MPI ifndef ${MPI_FAKE} # MPI MPI_FAKE := N endif # endif MPI_FAKE ifndef NCO_VRS # Used for RPM building NCO_VRS := $(shell cat ${MY_DOC_DIR}/VERSION) endif ifndef ${NETCDF4} # netCDF4 support NETCDF4 := Y endif # endif NETCDF4 ifndef NETCDF_ROOT NETCDF_ROOT := /usr/local endif ifndef NETCDF4_ROOT NETCDF4_ROOT := ${NETCDF_ROOT} endif ifndef NETCDF_INC ifdef INC_NCAR NETCDF_INC := ${INC_NCAR} # NCAR module path else # endelse INC_NCAR NETCDF_INC := ${NETCDF_ROOT}/include # Directory containing netcdf.h endif # endif INC_NCAR endif # endif NETCDF_INC ifndef NETCDF_LIB ifdef LIB_NCAR NETCDF_LIB := ${LIB_NCAR} # NCAR module path else # endelse LIB_NCAR NETCDF_LIB := ${NETCDF_ROOT}/lib # Directory containing libnetcdf.a endif # endif LIB_NCAR endif ifndef ${OMP} # OpenMP OMP := Y endif # endif OMP ifndef OPTS OPTS := D endif ifndef PGI_RCH_ARG PGI_RCH_ARG := endif # endif PGI_RCH_ARG ifndef ${PNETCDF} # pnetCDF support PNETCDF := N endif # endif PNETCDF ifndef PSC_RCH_ARG PSC_RCH_ARG := endif # endif PSC_RCH_ARG ifndef RPM RPM := N endif # endif RPM ifndef STC # Created statically linked executable STC := N endif ifndef SZ # Link to Szip library SZ := N endif ifndef UDUNITS # Use UDUnits functionality UDUNITS := N endif ifndef UDUNITS2 # Use UDUnits2 functionality UDUNITS2 := Y endif ifndef UNAMES UNAMES := $(shell uname -s) endif ifndef USR_TKN USR_TKN := endif # endif USR_TKN ifndef VRS_SNG VRS_SNG := $(shell date +%Y%m%d) endif # endif VRS_SNG ifndef ${ZNETCDF} # znetcdf support ZNETCDF := N endif # endif ZNETCDF # Derived-tokens based on primary tokens # These tokens should not be altered by hand # NB: CPP_TKN is recursively expanded variable, define only when components are ready CPP_TKN = ${USR_TKN} -D${PVM_ARCH} -DNO_NETCDF_2 -DVERSION='${VRS_SNG}' -DHOSTNAME='${HOST}' -DUSER='${USER}' -DNCO_ABORT_ON_ERROR ifndef LFLAGS # Flags for Flex (Lex) LFLAGS := -P${NCO_YY_PFX} endif ifndef YFLAGS # Flags for Bison (Yacc) YFLAGS := -d --name-prefix=${NCO_YY_PFX} endif # Default NCO build: DAP_NETCDF, DAP_OPENDAP, NETCDF4, PNETCDF, and ZNETCDF clauses may overwrite this ifndef LIB_NCAR NC_LDFLAGS := -L${NETCDF_LIB} NC_LIBS := -lnetcdf else NC_LDFLAGS := ${LIB_NCAR} endif ifeq (${DAP_NETCDF},Y) # Build NCO as DAP-enabled clients with netCDF-provided DAP ifndef DAP_NETCDF_ROOT # Directory containing libcurl.a DAP_NETCDF_ROOT := /usr endif # DAP_NETCDF_ROOT NC_LDFLAGS := -L${DAP_NETCDF_ROOT}/lib # netCDF 4.0.1+: NC_LIBS += -lcurl endif # end DAP_NETCDF ifeq (${DAP_OPENDAP},Y) # Build NCO as DAP-enabled clients with OPe NDAP # fxm: OPeNDAP bloats executables, should automagically enable stripping? # http://www.opendap.org/user/guide-html/guide_28.html ifndef DAP_OPENDAP_ROOT # Directory containing libdap.a, libnc-dap.a DAP_OPENDAP_ROOT := /usr/local endif # DAP_OPENDAP_ROOT NC_LDFLAGS := -L${DAP_OPENDAP_ROOT}/lib # NB: nc-dods, dap++ prior to version 3.5.X must be linked twice! # Required libraries for # DODS 3.3-: # NC_LIBS := -lnc-dods -ldap++ -lnc-dods -ldap++ -lwww -lz -lrx # DODS 3.4.X: # NC_LIBS := -lnc-dods -ldap++ -lnc-dods -ldap++ -lxml2 -lcurl -lpthread -ldl -lz # OPeNDAP 3.5.0-3.5.1: # NC_LIBS := -lnc-dap -ldap++ -lxml2 -lcurl # OPeNDAP 3.5+: NC_LIBS += -lnc-dap -ldap -lxml2 -lcurl # In addition, AIX OPeNDAP requires these libraries... ifneq (${null},$(findstring AIX,${PVM_ARCH})) NC_LIBS += -lcrypto -liconv -lssl -lz endif # end AIX # Get netCDF from OPeNDAP version NETCDF_INC=${DAP_OPENDAP_ROOT}/include/libnc-dap NETCDF_LIB=${DAP_OPENDAP_ROOT}/lib endif # end DAP_OPENDAP # Internationalize NCO with i18n features ifeq (${I18N},Y) MY_SHR_DIR := ${HOME}/share MY_ES_DIR := ${MY_SHR_DIR}/locale/es/LC_MESSAGES MY_FR_DIR := ${MY_SHR_DIR}/locale/fr/LC_MESSAGES endif # Message Passing Interface (MPI) ifeq (${MPI_FAKE},Y) # MPI_FAKE instructs make to compile mpnc*.c operators without defining ENABLE_MPI # Resulting executables use UP or SMP code not MPI code # This tests compile, link, execution of MPI mpnc*.c code without using any MPI calls MPI := Y endif # !MPI_FAKE ifdef MPI_PRC # MPI_PRC tells test scripts how many MPI processes to spawn # Pass this MPI argument to nco_bm.pl MPI_PRC_SNG := "--mpi_prc=${MPI_PRC}" # MPI_PRC implies MPI MPI := Y else # !MPI_PRC MPI_PRC_SNG := endif # !MPI_PRC ifeq (${NETCDF4},Y) # Enable netCDF4 functionality ifndef HDF5_ROOT HDF5_ROOT := ${NETCDF4_ROOT} endif ifndef HDF5_INC HDF5_INC := ${HDF5_ROOT}/include # Directory containing hdf5.h endif ifndef HDF5_LIB HDF5_LIB := ${HDF5_ROOT}/lib # Directory containing libhdf5.a endif # fxm: Temporary kludge: Machines with MPI_ROOT set are assumed to have parallel filesystems for NCO builds ifdef MPI_ROOT HDF5_INC += -I${MPI_ROOT}/include # Directory containing mpi.h HDF5_LIB += ${MPI_ROOT}/lib64 # Directory containing libmpi.a endif # !MPI_ROOT NETCDF_INC := ${NETCDF4_ROOT}/include NETCDF_LIB := ${NETCDF4_ROOT}/lib NC_LDFLAGS := -L${NETCDF_LIB} $(addprefix -L,${HDF5_LIB}) # NC_LIBS := -lnetcdf -lhdf5_hl -lhdf5 -lz ${NC_LIBS} NC_LIBS := $(shell nc-config --libs) ${NC_LIBS} ifdef MPI_ROOT NC_LIBS += -lmpi endif # !MPI_ROOT ifdef CURL_LIB NC_LDFLAGS += -L${CURL_LIB} endif # end ifeq (${SZ},Y) ifndef SZ_LIB SZ_LIB := /usr/lib # Directory containing libsz.a endif NC_LDFLAGS += -L${SZ_LIB} NC_LIBS += -lsz endif # !SZ ifneq (${HDF5_INC},${NETCDF_INC}) NETCDF_INC += -I${HDF5_INC} endif # end endif # endif NETCDF4 ifeq (${PNETCDF},Y) # Enable pnetCDF functionality NC_LDFLAGS := -L${NETCDF_LIB} NC_LIBS += -lpnetcdf endif # endif PNETCDF ifeq (${ZNETCDF},Y) # Enable znetcdf functionality NC_LDFLAGS := -L${NETCDF_LIB} NC_LIBS += -lznetcdf endif # endif ZNETCDF ifneq (${null},$(findstring LINUX,${PVM_ARCH})) # Decide among the plethora of Linux compilers ifndef LINUX_CXX # C++ compiler for Linux LINUX_CXX := g++ #LINUX_CXX := clang #LINUX_CXX := como #LINUX_CXX := icpc #LINUX_CXX := insure #LINUX_CXX := pathCC #LINUX_CXX := pgCC endif # endif LINUX_CXX ifndef LINUX_CC # C compiler for Linux LINUX_CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE #LINUX_CC := clang #LINUX_CC := como --c99 #LINUX_CC := icc -std=c99 -D_BSD_SOURCE -D_POSIX_SOURCE #LINUX_CC := insure #LINUX_CC := nvcc #LINUX_CC := pathcc -std=c99 #LINUX_CC := pgcc -c9x endif # endif LINUX_CC ifndef LINUX_FC # Fortran compiler for Linux #LINUX_FC := g95 LINUX_FC := gfortran #LINUX_FC := ifort #LINUX_FC := lf95 #LINUX_FC := pathf95 #LINUX_FC := pgf90 endif # endif LINUX_CC endif # endif LINUX # OpenMP ifeq (${OMP},Y) ifdef THR_NBR # Pass this OpenMP argument to nco_bm.pl THR_NBR_SNG := "--thr_nbr=${THR_NBR}" else # endif THR_NBR THR_NBR_SNG := endif # endif THR_NBR endif # endif OMP ifeq (${RPM},Y) # rpm command, and thus RPM variables only guaranteed in RedHat Linux # Use recursive expansion so rpm command is not executed on non-RPM systems MDL_RPM_NST_NM = $(shell rpm -qa | grep nco-) # Name of installed package # MDL_RPM_PRV_NM = $(shell rpm -qp foo) # Name of package provided by specified RPM endif # endif RPM ifeq (${PVM_ARCH},WIN32) BNR_SFX := .exe else BNR_SFX := ${null} endif ifeq (${GSL},Y) # Build GSL-enabled NCO # Place GSL block after DAP blocks for both to work together ifdef GSL_INC GSL_INC := -I${GSL_INC} else GSL_INC := $(shell gsl-config --cflags) endif # endif GSL_INC ifdef GSL_LIB GSL_LIB := -L${GSL_LIB} else GSL_LIB := $(shell gsl-config --libs) endif # endif GSL_LIB NETCDF_INC += ${GSL_INC} NC_LDFLAGS += -L${GSL_LIB} NC_LIBS += -lgsl endif # end if GSL ifeq (${UDUNITS2},Y) UDUNITS := Y endif # end if UDUNITS ifeq (${UDUNITS},Y) # Build UDUnits-enabled NCO # Place UDUNITS block after DAP blocks for both to work together ifndef UDUNITS_INC UDUNITS_INC := /usr/local/include # Directory containing udunits.h endif ifndef UDUNITS_LIB UDUNITS_LIB := /usr/local/lib # Directory containing libudunits.a endif ifneq (${UDUNITS_INC},${NETCDF_INC}) NETCDF_INC += -I${UDUNITS_INC} endif # end ifneq (${UDUNITS_LIB},${NETCDF_LIB}) NC_LDFLAGS += -L${UDUNITS_LIB} endif # end if ifeq (${UDUNITS2},Y) # 20130607: -lexpat needed on .deb systems, not on RPM systems UDUNITS_RPM_DRC := /usr/include/udunits2 UDUNITS_RPM_TST := $(shell ls ${UDUNITS_RPM_DRC}/udunits2.h) ifeq (${UDUNITS_RPM_TST},${UDUNITS_RPM_DRC}/udunits2.h) NETCDF_INC += -I${UDUNITS_RPM_DRC} endif # end if ifneq (${UDUNITS_RPM_TST},${UDUNITS_RPM_DRC}/udunits2.h) NC_LIBS += -ludunits2 -lexpat else # end if UDUNITS2 Fedora NC_LIBS += -ludunits2 endif # end if UDUNITS2 Fedora else NC_LIBS += -ludunits endif # end if UDUNITS2 endif # end if UDUNITS # TMP_* and NCO_* are required to play nicely with DAP flags NCO_LDFLAGS := -L${MY_LIB_DIR} NCO_LIBS := -lnco TMP_LDFLAGS := ${NCO_LDFLAGS} ${NC_LDFLAGS} TMP_LIBS := ${NCO_LIBS} ${NC_LIBS} # NB: Do NOT add comment lines, e.g., # This is a comma, to character definitions null := space := ${null} ${null} comma := , newline := \n # '/' and '+' appear in filenames ('/' is directory separator) # Operating on these with Perl is problematic since they are special Rx characters # We replace `/' and '+' by non-special Rx's, call perl, then demangle # Unique character(s) to substitute for '/' and '+' before passing to perl Rx slash_rx := cszzsc plus_rx := xdikmj # Unique character(s) to replace by ${slash_rx} before passing to perl regex slash := / plus := + MY_OBJ_DIR_RX := $(subst ${slash},${slash_rx},${MY_OBJ_DIR}) MY_DPN_DIR_RX := $(subst ${slash},${slash_rx},${MY_DPN_DIR}) # Directories to search for source files MDL_PTH := ./ ${MY_SRC_DIR} # Find all C, C++, CUDA files in given directory FIND_FNC = $(wildcard ${dir}/*.cc ${dir}/*.c ${dir}/*.cu) # Assemble source files from all directories SRC_LST = $(foreach dir, ${MDL_PTH},$(FIND_FNC)) # Source file names with directories removed MDL_SRC := $(notdir $(SRC_LST)) # Dependency list for executable MDL_OBJ := $(addprefix ${MY_OBJ_DIR}/,$(addsuffix .o, $(basename ${MDL_SRC}))) # Dependency (make) file for each object file MDL_DPN := $(addprefix ${MY_DPN_DIR}/,$(addsuffix .d, $(basename ${MDL_SRC}))) # VPATH helps make find dependencies (which are not pathname qualified) in *.d file VPATH := $(subst ${space},:,${MDL_PTH}) # Prepend -I to use for compiler argument CPP_PTH := $(foreach dir,${MDL_PTH},-I${dir}) # Variables having to do with binary executables created by module MDL_BIN_TRG := ncap ncatted ncbo ncecat ncflint ncks ncpdq ncra ncrename ncwa # NCO binary targets MDL_BIN_SYM_LNK := ncdiff ncea nces ncrcat # Symbolic links ifeq (${MPI},Y) MDL_MPI_TRG := mpncbo mpncecat mpncflint mpncpdq mpncra mpncwa # MPI binary targets MDL_MPI_TRG_SMP := ncbo ncecat ncflint ncpdq ncra ncwa # MPI binary targets MDL_MPI_SYM_LNK := mpncdiff mpncea mpnces mpncrcat # MPI Symbolic links MDL_MPI_STB := ${MDL_MPI_TRG} ${MDL_MPI_SYM_LNK} # All MPI files in MY_BIN_DIR MDL_MPI_BIN := $(addprefix ${MY_BIN_DIR}/,${MDL_MPI_TRG}) # mpi_cln removes these files MDL_MPI_OBJ := $(addsuffix .o,$(addprefix ${MY_OBJ_DIR}/,${MDL_MPI_TRG})) # mpi_cln removes these files MDL_BIN_TRG += ${MDL_MPI_TRG} # NCO binary targets MDL_BIN_SYM_LNK += ${MDL_MPI_SYM_LNK} # Symbolic links endif # endif MPI MDL_BIN_STB := ${MDL_BIN_TRG} ${MDL_BIN_SYM_LNK} # All NCO files in MY_BIN_DIR MDL_BIN := $(addprefix ${MY_BIN_DIR}/,${MDL_BIN_STB}) # distclean removes these files # Variables having to do with header files created by module # List header targets alphabetically by "category": MDL_INC_TRG := # Raw (no functions) MDL_INC_TRG += libnco.h # libnco MDL_INC_SYM_LNK := # Symbolic links MDL_INC_STB = ${MDL_INC_TRG} ${MDL_INC_SYM_LNK} # All header files in ${MY_INC_DIR} MDL_INC = $(addprefix ${MY_INC_DIR}/,${MDL_INC_STB}) # dst_cln removes these files # Variables having to do with NCO data MDL_DAT_STB := 85 86 87 88 89 h0001 h0002 h0003 # Symbolic links to in.nc MDL_DAT_STB := $(addsuffix .nc,${MDL_DAT_STB}) # `make data' creates these files MDL_DAT := $(addprefix ${MY_DAT_DIR}/,${MDL_DAT_STB}) # `make distclean' removes these files # Variables having to do with NCO documentation MDL_DOC_SRC := $(addprefix ../,acinclude.m4 configure.ac configure.eg Makefile.am) $(addprefix ${MY_DOC_DIR}/,nco.texi ANNOUNCE MANIFEST NEWS README TODO VERSION beta.txt debian.txt dods.sh index.shtml xmp_cesm.html man_end.txt man_srt.txt ncap.txt nco_news.shtml nco_src_frg.txt opendap.sh) $(addprefix ${MY_DBN_DIR}/,changelog compat control copyright files info rules doc-base) # `make tags' includes these files MDL_DOC_TRG := nco.dvi nco.html nco.info nco.pdf nco.ps nco.txt nco.xml # `make doc' creates these files MDL_DOC := $(addprefix ${MY_DOC_DIR}/,${MDL_DOC_TRG}) # `make distclean' removes these files MDL_MAN := $(wildcard ${MY_MAN_DIR}/*.1) MDL_MAN := $(notdir ${MDL_MAN}) MDL_MAN := $(addprefix ${MY_MAN_DIR}/,${MDL_MAN}) # distclean removes these files # Variables having to do with NCO build MDL_BLD_SRC := $(addprefix ${MY_BLD_DIR}/,libnco_tst.c libnco_c++_tst.cc Makefile nco.spec nco_dst.pl) # `make tags' includes these files MDL_BLD_SRC += $(addprefix ${MY_BM_DIR}/,NCO_bm.pm NCO_benchmarks.pm NCO_rgr.pm nco_bm.pl nco_bm.sh mk_bm_plots.pl) # `make tags' includes these files MDL_BLD_SRC += $(addprefix ${MY_DAT_DIR}/,Makefile.am) $(addprefix ${MY_SRC_DIR}/,Makefile.am) $(addprefix ${MY_DOC_DIR}/,Makefile.am) $(addprefix ${NCO_CXX_SRC_DIR}/,Makefile.am) $(addprefix ${NCOXX_SRC_DIR}/,Makefile.am) # `make tags' includes these files # Files, if any, to exclude from tags # TAGS_FILTER_FILES := .//libnco_tst.c .//libnco_c++_tst.cc ../src/nco/lex.${NCO_YY_PFX}.c TAGS_FILTER_FILES := .//libnco_tst.c .//libnco_c++_tst.cc # Variables having to do with Qt build system MDL_QT_SRC := $(addprefix ${MY_QT_DIR}/,nco.pro libnco/libnco.pro ncatted/ncatted.pro ncbo/ncbo.pro ncecat/ncecat.pro ncflint/ncflint.pro ncks/ncks.pro ncpdq/ncpdq.pro ncra/ncra.pro ncrename/ncrename.pro ncwa/ncwa.pro tst_nco_c++/tst_nco_c++.pro) # `make tags' includes these files # Variables having to do with ncap MDL_NCAP_SRC := $(addprefix ${MY_SRC_DIR}/,ncap_yacc.y ncap_lex.l ncap.h) # `make tags' includes these files MDL_NCAP_TRG := ncap_yacc.c ncap_yacc.h ncap_lex.c # `make ncap' creates these files MDL_NCAP := $(addprefix ${MY_SRC_DIR}/,${MDL_NCAP_TRG}) # `make distclean' removes these files # Variables having to do with C++ source and documentation # fxm: auto-generate source code components of C++ lists MDL_CXX_SRC := $(addprefix ${NCOXX_SRC_DIR}/,libnco++.hh Makefile.am Makefile.old ncap2.cc ncap2.hh ncap2_utl.cc NcapVar.cc NcapVar.hh NcapVarVector.cc NcapVarVector.hh NcapVector.hh ncoGrammer.g nco_antlr_pst_prc.pl fmc_cls.cc fmc_cls.hh fmc_all_cls.cc fmc_all_cls.hh fmc_gsl_cls.cc fmc_gsl_cls.hh Invoke.cc Invoke.hh map_srt_tmp.hh nco_gsl.c nco_gsl.h prs_cls.cc prs_cls.hh sdo_utl.cc sdo_utl.hh sym_cls.cc sym_cls.hh VarOp.hh vtl_cls.hh) $(addprefix ${NCO_CXX_SRC_DIR}/,INSTALL libnco_c++.hh Makefile.am Makefile.old nco_att.cc nco_att.hh nco_dmn.cc nco_dmn.hh nco_fl.cc nco_fl.hh nco_hgh.cc nco_hgh.hh nco_utl.cc nco_utl.hh nco_var.cc nco_var.hh README TODO tst.cc) # `make tags' includes these files # Redefine default C and C++ pattern rules ${MY_OBJ_DIR}/%.o : %.c ${CC} ${CPPFLAGS} ${CFLAGS} -c $< -o ${MY_OBJ_DIR}/$(notdir $@) ${MY_OBJ_DIR}/%.o : %.cu nvcc -deviceemu ${CPPFLAGS} ${CFLAGS} -c $< -o ${MY_OBJ_DIR}/$(notdir $@) ${MY_OBJ_DIR}/%.o : %.cc ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c $< -o ${MY_OBJ_DIR}/$(notdir $@) # Default Fortran pattern rules: CRAY and RS6K must override these rules ${MY_OBJ_DIR}/%.o : %.F ${FC} ${CPPFLAGS} -c ${FFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< ${MY_OBJ_DIR}/%.o : %.f ${FC} -c ${FFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< # Rules for installing header files #${MY_INC_DIR}/%.h : %.h # cp -f -p $(notdir $@) $@ ${MY_INC_DIR}/%.hh : %.hh cp -f -p $(notdir $@) $@ # Rules for installing i18n files %.po : %.cc xgettext --default-domain=$* --join-existing $< ${MY_ES_DIR}/%.mo : %.po # Linux version accepts more arguments than Solaris version # msgfmt --output-file=$@ --statistics $< msgfmt -o $@ $< # Automatically generate a dependency file for each source file # $* is the stem, e.g., f # $@ is the filename of the target, e.g., f.d # Linux gcc may return an extra `.F' on Fortran names, e.g., `hello.F.o: hello.F' # (.F)? gets rid of this extra `.F' ${MY_DPN_DIR}/%.d : %.F # Following command makes, e.g., f.d begin "f.o f.d : f.F ..." # Since f.o is not preceded by ${MY_OBJ_DIR}, objects are not recompiled when sources are touched. # ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*\.F\.o/$*.o $@/g;' > $@ # Following command makes, e.g., f.d begin "/home/zender/obj/LINUX/f.o f.d : f.F ..." # This works fairly well, but is a hack # First pattern substitutes MY_OBJ_DIR_RX, which has placeholders for slashes # Second pattern substitutes slashes for the placeholders ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*(\.F)?\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' > $@ # Following command makes, e.g., f.d begin "${MY_OBJ_DIR}/f.o f.d : f.F ..." # This would be the ideal command but I can't get the dollar sign to show up # ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*\.F\.o/\${dollar}MY_OBJ_DIR\/$*.o $@/g;' > $@ ${MY_DPN_DIR}/%.d : %.c # ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*\.o/$*.o $@/g;' > $@ ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' > $@ ${MY_DPN_DIR}/%.d : %.cu nvcc -M ${CPPFLAGS} $< | perl -p -e 's/$*\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' > $@ ${MY_DPN_DIR}/%.d : %.cc # NB: Use ${CXX} rather than ${CPP} on C++ files for now because, e.g., SUNMP cpp does not pre-process .cc files quite correctly # Extra hack to allow C++ filenames to contain '+' character # $(subst ${plus},${plus_rx},${*}) is filename stub with an Rx in place of '+' ${MK_DPN_CXX} ${CXXCPPFLAGS} $< | perl -p -e 's/\${plus}/${plus_rx}/g;s/$(subst ${plus},${plus_rx},${*})\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g;s/${plus_rx}/\${plus}/g' > $@ # First LDFLAGS is for typical C programs with netCDF, math, and networking # Second LDFLAGS, when present, enables C/Fortran linking # Manually define autotools tokens normally defined with HAVE_CONFIG_H in config.h # Initialize OS-specific tokens to empty CPP_TKN_OS := -DHAVE_REGEX_H -DNCO_HAVE_REGEX_FUNCTIONALITY -DHAVE_GETPAGESIZE -DHAVE_GETRUSAGE -DNEED_STRCASESTR # gcc 4.7.3 finally includes strcasestr() in string.h iff _GNU_SOURCE token is defined # NB: C++ (or at least g++ 4.7.3) always includes strcasestr()---work around this with tokens in nco_sng_utl.[ch] ifneq (${PVM_ARCH},CRAY) CPP_TKN_OS += -DHAVE_MKSTEMP endif # CRAY ifneq (${null},$(findstring ${PVM_ARCH},FREEBSDLINUXALPHALINUXAMD64LINUXARMMACOSXWIN32)) CPP_TKN_OS += -DHAVE_GETOPT_H -DHAVE_GETOPT_LONG endif # !LINUX ifneq (${null},$(findstring ${PVM_ARCH},AIXSGIMP64)) CPP_TKN_OS += -DNEED_GETOPT_LONG endif # !(AIX || SGI) ifeq (${CNK},Y) CPP_TKN_OS += -DHAVE_NEW_CHUNKING_API endif # !CNK ifeq (${DAP_NETCDF},Y) CPP_TKN_OS += -DENABLE_DAP -DENABLE_DAP_NETCDF endif # !DAP_NETCDF ifeq (${DAP_OPENDAP},Y) CPP_TKN_OS += -DENABLE_DAP -DENABLE_DAP_OPENDAP endif # !DAP_OPENDAP ifeq (${GSL},Y) CPP_TKN_OS += -DENABLE_GSL -DHAVE_GSL_H endif # !GSL ifeq (${MPI},Y) ifneq (${MPI_FAKE},Y) CPP_TKN_OS += -DENABLE_MPI endif # MPI_FAKE endif # !MPI ifeq (${UDUNITS},Y) CPP_TKN_OS += -DENABLE_UDUNITS -DHAVE_UDUNITS_H ifeq (${UDUNITS2},Y) CPP_TKN_OS += -DHAVE_UDUNITS2_H endif # !UDUNITS2 endif # !UDUNITS # Assume strcasecmp() and strdup() routines are present (Comeau, Pathscale are exceptions) CPP_TKN_OS += # fxm: Define HAVE_LIBINTL, HAVE_LOCALE_H, HAVE_GETTEXT, HAVE_OMP_H # Works on AIX and AIX46K ifneq (${null},$(findstring AIX,${PVM_ARCH})) # 20030804: Always use re-entrant (_r) compilers---Jim Edwards NCAR/IBM CC := xlc_r -qlanglvl=extc99 #CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE CXX := xlC_r # CXX := g++ CPP := xlc -c -qlanglvl=extc99 -qsuppress=1501-245 -I/usr/lpp/ppe.poe/include FC := xlf95_r ifneq (${null},$(findstring xl,${CC})) # /usr/include headers must occur before Visual Age headers to prevent xlC pragma warnings # Visual Age compiler headers must occur before g++ headers CPP_TKN_OS += -I/usr/include -I/usr/vacpp/include endif # xlC compilers # Add /usr/local/include for libintl.h explicitly until netCDF is moved there CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} -DNEED_LOGF LD := ld # 20020422: -lC links to AIX C++ library which contains float intrinsics cosf()... # -bh:5 suppresses annoying messages from xlC linker WARNING: Duplicate symbol: ... LDFLAGS += -bh:5 ${TMP_LDFLAGS} ${TMP_LIBS} -lm -lC LEX := flex LINT := lint YACC := bison # AIX VA Compiler Collection ifneq (${null},$(findstring xl,${CC})) # Visual Age compiler defaults specified in /etc/vac.cfg # Additional switch to fix compiler warnings on csz.c # -qarch=auto : Automatically detect architecture of compiling machine and assume execution on same machine # -qlonglong allow long long integers (and strtoll(), strtoull()) (default on in C not C++). Redundant with -qlanglvl=extc99 # -qmaxmem=num Limit memory used by space intensive optimizations to kilobytes # -qspill=size Size in B of register allocation spill area, mie needs > 1040 B # -qsrcmsg prints transgressing source line with finger # -qsuppress=1501-245 : Suppress RLIM_INFINITY memory message due to ulimits # -qtune=auto : Optimize executable for architecture detected during compilation CFLAGS := -qmaxmem=8192 -qspill=2048 -qsrcmsg -qsuppress=1501-245 FFLAGS := -NS2000 -qfixed=132 -qsrcmsg # -bh:5 suppresses annoying messages from xlC linker WARNING: Duplicate symbol: ... LDFLAGS += -bh:5 -qsuppress=1501-245 #LDFLAGS += -lxlf90 # Required for linking Fortran objects ifeq (${OMP},Y) FC := xlf95_r # -qsmp=noauto : Turn on SMP/OMP code generation but do no automatic parallelization # -qsmp=omp : Use industry standard OMP without IBM extensions OMP_FLG := -qsmp=omp else CPP_DFN += -U_OPENMP FC := xlf95 endif # endif OMP ifeq (${OPTS},O) # -O : -O3 is safe, -O5 is dangerous # -qstrict: Ensure that -O3 optimizations do not alter program semantics # -Q : Inline all appropriate subprograms CFLAGS += -O3 -g -qstrict -Q FFLAGS += -O3 -g -qstrict -Q endif ifeq (${OPTS},D) CFLAGS += -g FFLAGS += -g endif ifeq (${OPTS},X) # -qflttrap generates instructions for floating point exceptions # -qidirfirst uses headers found in -I directories first # -qmakedep creates .d file # -qwarn64 check for possible long-to-integer or pointer-to-integer truncation # -qhalt=e stop compiler if error severity equals or exceeds i, w, e, s, u CFLAGS += -g -qflttrap -qidirfirst -qwarn64 -qcheck=all -qhalt=s FFLAGS += -g endif ifeq (${ABI},64) AR := ar -X 64 CFLAGS += -q64 FFLAGS += -q64 LDFLAGS += -q64 else CPPFLAGS += -D_LARGE_FILES endif # endif ABI # Additional flags for AIX: # -M Generate information to be included in a "make" description file; output goes to .u file # -c Do not send object files to the linkage editor # -P Preprocess but do not compile; output goes to .i file # Using -P causes additional warning messages about lm # Not using -P causes *.o files to be created twice ${MY_DPN_DIR}/%.d : %.c ${MK_DPN} ${CPPFLAGS} $< ;perl -p -e 's/$*\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' $*.u > $@ ; \ rm -f $*.i $*.o $*.u; ${MY_DPN_DIR}/%.d : %.cc ${MK_DPN_CXX} ${CPPFLAGS} $< ;perl -p -e 's/$*\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' $*.u > $@ ; \ rm -f $*.i $*.o $*.u; endif # endif AIX VA Compiler Collection # GNU Compiler Collection ifneq (${null},$(findstring gcc,${CC})) CFLAGS := -Wall -Werror=format-security -Wunused ifeq (${OPTS},O) CFLAGS += -O -g ${GCC_RCH_ARG} endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g -O LDFLAGS += /usr/local/lib/ccmalloc-g++.o -L/usr/local/lib -lccmalloc -ldl endif ifeq (${ABI},64) CC += -maix64 CXX += -maix64 endif # endif ABI CXXFLAGS := ${CFLAGS} endif # endif GNU Compiler Collection # -q64: Select 64-bit compiler mode (required for accessing large files) # -qwarn64: Warn on possible long-to-integer or pointer-to-integer truncation CXXFLAGS := ${CFLAGS} ifeq (${OMP},Y) CFLAGS += ${OMP_FLG} CXXFLAGS += ${OMP_FLG} FFLAGS += ${OMP_FLG} LDFLAGS := ${OMP_FLG} ${LDFLAGS} endif # endif OMP endif # endif AIX ifeq (${PVM_ARCH},ALPHA) ifeq (${OMP},Y) OMP_FLG := -omp endif # endif OMP CXX := cxx CC := cc CFLAGS := ${OMP_FLG} CPP := cpp CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f90 FFLAGS := -r8 -i4 -c ${OMP_FLG} -automatic FIXEDFLAGS := -extend_source ${OMP_FLG} -automatic FREEFLAGS := -DHIDE_SHR_MSG -free LD := ld LDFLAGS += ${OMP_FLG} ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O2 -g -ansi_alias FFLAGS += -O3 -g -inline speed endif ifeq (${OPTS},D) CFLAGS += -g -check_bounds -check -check_omp FFLAGS += -g3 -C endif ifeq (${OPTS},X) CFLAGS := -g -N 132 FFLAGS := -g -check bounds -check omp_bindings -check overflow -check underflow endif CXXFLAGS := ${CFLAGS} ${MY_OBJ_DIR}/%.o : %.F90 ${FC} -c ${FREEFLAGS} ${FFLAGS} ${CPPFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< ${MY_OBJ_DIR}/%.o : %.F ${FC} -c ${FIXEDFLAGS} ${FFLAGS} ${CPPFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< endif # endif ALPHA ifeq (${PVM_ARCH},CRAY) CXX := CC CC := cc CPP := cpp CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f90 # -F enables macro substitution # -dp enables DOUBLEPRECISION/double FFLAGS := -N 132 -F -dp LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -h rounddiv -h nofastmd -h nofastmodulus FFLAGS += -O2 -g endif ifeq (${OPTS},D) CFLAGS += -g -h indef -h rounddiv -h nofastmd -h nofastmodulus FFLAGS += -g -ei endif ifeq (${OPTS},X) CFLAGS += -g -h rounddiv -h indef -h bounds -h nofastmd -h nofastmodulus FFLAGS += -g -ei -Rabc endif # 19971021 Added -P to suppress #line # directives on Fortran files ${MY_OBJ_DIR}/%.o : %.F ${CPP} -P ${CPPFLAGS} $< > $(patsubst %.F,%.f,$(notdir $<)) ${FC} -c ${FFLAGS} $(patsubst %.F,%.f,$(notdir $<)) -mv -f $(notdir $@) ${MY_OBJ_DIR} rm -f $(patsubst %.F,%.f,$(notdir $<)) ${MY_OBJ_DIR}/%.o : %.f ${FC} -c ${FFLAGS} $< mv -f $(notdir $@) ${MY_OBJ_DIR} endif # endif CRAY ifeq (${PVM_ARCH},HPPA) CXX := g++ CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f77 LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lnsl -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O2 -g FFLAGS := -fast -eendif endif ifeq (${OPTS},D) CFLAGS += -g FFLAGS := -g -e endif ifeq (${OPTS},X) CFLAGS += -g FFLAGS := -g -e endif endif # endif HPPA # Works on LINUX, LINUXALPHA, LINUXAMD64, LINUXARM, and FREEBSD ifneq (${null},$(findstring ${PVM_ARCH},LINUXALPHALINUXAMD64LINUXARMFREEBSD)) CXX := ${LINUX_CXX} CC := ${LINUX_CC} CPP := ${CC} # NB: nameser.h needs -Di386, but gcc sends -Di586 (on pentiums) CPP_TKN_OS += -Di386 CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := ${LINUX_FC} LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison # Comeau C Compiler ifeq (${CXX},como) CFLAGS := CPPFLAGS += -DNEED_STRCASECMP CPPFLAGS += -DNEED_STRDUP LDFLAGS := ${COMOROOT}/libcomo/libcomo.a ${LDFLAGS} ifeq (${OPTS},O) CFLAGS += -O -g endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g endif CXXFLAGS := ${CFLAGS} endif # endif Comeau C Compiler # GNU Compiler Collection or LLVM # 20140204: gcc and clang should receive identical options ifeq (gcc,$(firstword ${CC})) GCC_OR_CLANG := Y endif ifeq (clang,$(firstword ${CC})) GCC_OR_CLANG := Y endif ifeq (${GCC_OR_CLANG},Y) CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE CFLAGS := -Wall -Wuninitialized # Compilation flags for numerical routines recommended by GSL 1.3 manual, p. 397 CFLAGS += -Werror=format-security -W -Wmissing-prototypes -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -fno-common -g # Compilation flags recommended by GSL and others that I like and use: # -D_BSD_SOURCE: Support 4.3 BSD Unix extensions to ANSI C (prevents nameser.h warnings) # -D_POSIX_SOURCE: Support POSIX.1 standard additions to ANSI C (prevents fileno warnings) # -pedantic: Disallow non-ISO constructs (including type long long) (sometimes useful) # -W: Extra warnings, including missing return values, comparison of signed with unsigned # -Wall: Warn about common programming problems # -Wcast-align: Warn if casting pointer to type of different size # -Wcast-qual: Warn if const qualifier removed from pointer # -Werror: Consider warnings as errors # -Werror=format-security: Consider this specific warning as errors # -Wmaybe-uninitialized: Warn on uninitialized variables. GCC has many false negatives, clang is better? Available on GCC 4.8.2+. Not available on GCC 4.6.3-. # -Wmissing-prototypes: Warn if missing prototypes # -Wpointer-arith: Warn if pointer arithmetic on types without size, e.g., void # -Wshadow: Warn if local variable has same name as other local variable # -Wsometimes-uninitialized: LLVM/clang uses this but GCC does not # -Wswitch: Warn if switch statement has enumerated index and case label outside enumeration range # -Wuninitialized: Warn on uninitialized variables. GCC has many false negatives, clang is better? # -Wunused: Warn on unused functions, labels, parameters, values, and variables # -Wwrite-strings: Apply const-qualifier to string constants, die if overwritten # -fno-common: Prevent global variables from being simultaneously defined in different files # -g: Put debugging symbols in executable # -pg: Enable profiling, generate gmon.out output files (also needed by linker) # -O4: Turn on optimization so uninitialized variables are flagged. Downside: optimizes-out many symblols useful for debugging # Compilation flags recommended by GSL that I do not like and do not use: # -ansi: Support only strict ANSI C. Equivalent to -std=c89, conflicts with -std=c99 # --no-alias? -fstrict-aliasing # -Waggregate-return: Warn if functions return aggregates like structures or unions # -Wconversion: Warn if converting signed to unsigned. Intended for obsolete, non-prototyped code. Triggers fabsf(), sqrtf(), warnings. # -Wnested-externs: Warn if extern is encountered within function. C only? # -Wstrict-prototypes: Warn if inconsistent prototypes. C only? # -Wtraditional: Warn if constructs differ between traditional and ANSI C. C only? # -Dinline=: inline is not an ANSI keyword, must undefine inline to work with -ansi # -fshort-enums: Make enums as short as possible, ususally non-int. Do not ever invoke this! This breaks ABI and causes subtle problems ifeq (${OMP},Y) OMP_FLG_C := -fopenmp OMP_FLG_F := -fopenmp LDFLAGS += -lgomp -lpthread endif # endif OMP ifeq (${OPTS},O) CFLAGS += -O4 -g ${GCC_RCH_ARG} endif ifeq (${OPTS},D) CFLAGS += -g -Wno-switch endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) # 20090715: https://wiki.ubuntu.com/CompilerFlags # -D_FORTIFY_SOURCE=2 : Compile-time libc checks, run-time buffer/memory checks # : NB: _FORTIFY_SOURCE macro requires -O switch # -fstack-protector : Enable run-time stack overflow verification # -Wformat-security : Warn about misuse of format strings # -Wl,-z,relro : Read-only relocation table area in final ELF CPPFLAGS += -D_FORTIFY_SOURCE=2 CFLAGS += -g -fstack-protector -Wformat-security -Wl,-z,relro # 20090715: -Werror triggers known nc_put_var?_string() and nco_def_var_chunking() errors # CFLAGS += -g -pg -fno-inline -Werror # CFLAGS += -g -O -pg -fno-inline CFLAGS += -g -pg -fno-inline LDFLAGS += -pg # LDFLAGS += /usr/local/lib/ccmalloc-gcc.o -L/usr/local/lib -lccmalloc -ldl endif ifneq (${null},$(findstring AMD64,${PVM_ARCH})) ifeq (${ABI},64) CFLAGS += -m64 FFLAGS += -m64 LDFLAGS += -m64 endif # endif ABI endif # endif LINUXAMD64 CXXFLAGS := ${CFLAGS} endif # endif GNU Compiler Collection # Intel (Kai) C Compiler ifeq (icc,$(firstword ${CC})) # -fast: enable -xP -O3 -ipo -static # -ipo[n]: enable multi-file IP optimizations (between files) # -no-gcc: do not define __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__ macros # -static: prevents linking with shared libraries # -std=c99: Enable C99 support for C programs # -xB: specialize code to run exclusively on Intel Pentium M and compatible Intel processors # -xK: specialize code to run exclusively on Intel Pentium III and compatible Intel processors # -xN: specialize code to run exclusively on Intel Pentium 4 and compatible Intel processors # -xP: specialize code to run exclusively on Intel Pentium 4 processors with SSE3 extensions # -Wall: enable all warnings # -Werror:force warnings to be reported as errors # -w0: display errors (same as -w) # -w1: display warnings and errors (DEFAULT) # -w2: display remarks, warnings, and errors # -wd[,,...] disable diagnostics L1 through LN # warning #274: declaration is not visible outside of function # remark #981: operands are evaluated in unspecified order # remark #810: conversion from "double" to "float" may lose significant bits # remark #1572: floating-point equality and inequality comparisons are unreliable CFLAGS := -w1 -wd274 CPPFLAGS += -no-gcc LDFLAGS += -lsvml OMP_FLG_C := -openmp -openmp_report0 ifeq (${OPTS},O) CFLAGS += -O3 -g ${ICC_RCH_ARG} endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g -Wall -wd810,981,1572 -inline_debug_info endif CXXFLAGS := ${CFLAGS} endif # endif Intel (Kai) C Compiler # Intel (Kai) Fortran Compiler ifeq (${FC},ifc) # -e95 issues warnings for non-standard fortran # -fpp2 necessary, but not sufficient, for OpenMP FFLAGS := -extend_source -implicitnone -vms -e95 -fpp2 # -lVaxlib needed for iargc_, getarg_ LDFLAGS += -lVaxlib OMP_FLG_C := -openmp ifeq (${PRC},D) FFLAGS += -i4 -r8 -doubletemps else FFLAGS += -i4 endif ifeq (${OPTS},O) FFLAGS += -O2 -g endif ifeq (${OPTS},D) FFLAGS += -g endif ifeq (${OPTS},R) FFLAGS += endif ifeq (${OPTS},X) FFLAGS += -g -C -e95 endif endif # endif Intel (Kai) Fortran Compiler # cd ~;nvcc -o libcuda_add.a -deviceemu -lib simpleTemplates.cu # cd ~;g++ -I/usr/local/cuda/include -c -o test.o test.c # cd ~;g++ -o ~/test test.o libcuda_add.a # NVidia C Compiler ifeq (nvcc,$(firstword ${CC})) CPPFLAGS += # -deviceemu: Emulate CUDA CPU # -lib: build static libraries CFLAGS := -deviceemu -lib ifeq (${OMP},Y) OMP_FLG_C := OMP_FLG_F := LDFLAGS += endif # endif OMP ifeq (${OPTS},O) CFLAGS += -O -g endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g LDFLAGS += endif ifneq (${null},$(findstring AMD64,${PVM_ARCH})) ifeq (${ABI},64) CFLAGS += FFLAGS += LDFLAGS += endif # endif ABI endif # endif LINUXAMD64 CXXFLAGS := ${CFLAGS} endif # endif NVidia C Compiler # Pathscale (QLogic) C Compiler ifeq (pathcc,$(firstword ${CC})) # pathcc -show-defaults # shows that pathcc automatically sets many hardware-specific options # man -k pathscale for full listing # -O2 = -O: Default optimization # -Ofast = -O3: CFLAGS := CPPFLAGS += -DNEED_STRCASECMP LDFLAGS += OMP_FLG_C := -apo -mp ifeq (${OPTS},O) CFLAGS += -O3 -g ${PSC_RCH_ARG} endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += -O2 endif ifeq (${OPTS},X) CFLAGS += -g endif CXXFLAGS := ${CFLAGS} endif # end Pathscale (QLogic) C++ Compiler # Portland Group C++ Compiler ifeq (pgcc,$(firstword ${CC})) # Enable Large File Support (LFS) by default CFLAGS := -Mlfs # Pass kludgy PGI identifier to flag for broken C99 designated initializers etc. CPPFLAGS := $(filter-out -DHAVE_C99,${CPPFLAGS}) CPPFLAGS := -DPGI_CC ${CPPFLAGS} LDFLAGS += -Mlfs OMP_FLG_C := -mp ifeq (${OPTS},O) CFLAGS += -fast ${PGI_RCH_ARG} endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g -Mbounds endif CXXFLAGS := ${CFLAGS} endif # endif Portland Group C++ Compiler # Portland Group Fortran Compiler ifeq (${FC},pgf90) FFLAGS := -Mextend -Mnosecond_underscore -byteswapio -Mrecursive -Mdalign -Ktrap=fp -Mlfs OMP_FLG_F := -mp ifeq (${PRC},D) FFLAGS += -Mr8 -Mi4 endif ifeq (${OPTS},O) FFLAGS += -fast endif ifeq (${OPTS},D) FFLAGS += -g endif ifeq (${OPTS},R) FFLAGS += endif ifeq (${OPTS},X) FFLAGS += -g -Mbounds endif endif # endif Portland Group Fortran Compiler # G77 Fortran compiler ifeq (${FC},g77) FFLAGS := -ffixed-line-length-132 -fno-second-underscore ifeq (${OPTS},O) FFLAGS += -O -g endif ifeq (${OPTS},D) FFLAGS += -g -fdebug-kludge endif ifeq (${OPTS},R) FFLAGS += -fdebug-kludge endif ifeq (${OPTS},X) FFLAGS := -g -O -fdebug-kludge -fbounds-check endif endif # endif G77 Fortran compiler ifeq (${DPKG},Y) CPPFLAGS+=$(shell dpkg-buildflags --get CPPFLAGS) CFLAGS+=$(shell dpkg-buildflags --get CFLAGS) CXXFLAGS+=$(shell dpkg-buildflags --get CXXFLAGS) LDFLAGS+=$(shell dpkg-buildflags --get LDFLAGS) endif # endif OMP ifeq (${OMP},Y) CFLAGS += ${OMP_FLG_C} CXXFLAGS += ${OMP_FLG_C} FFLAGS += ${OMP_FLG_C} # LD behavior assumes C source code LDFLAGS := ${OMP_FLG_C} ${LDFLAGS} endif # endif OMP endif # endif LINUX, LINUXALPHA, LINUXAMD64, LINUXARM, FREEBSD ifeq (${PVM_ARCH},MACOSX) CXX := c++ # NB: -D_POSIX_SOURCE breaks MACOSX build in nco_fl_utl.c, nco_mmr.c CC := cc -std=c99 -pedantic -D_BSD_SOURCE # -fno-common: Allows shared libraries to build CFLAGS := -Wall -Werror=format-security -fno-common CPP := ${CC} CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f90 LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lresolv -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},X) CFLAGS += -g -O LDFLAGS += /usr/local/lib/ccmalloc-gcc.o -L/usr/local/lib -lccmalloc -ldl endif CXXFLAGS := ${CFLAGS} ifeq (${OMP},Y) CFLAGS += ${OMP_FLG} FFLAGS += ${OMP_FLG} LDFLAGS := ${OMP_FLG} ${LDFLAGS} endif # endif OMP endif # endif MACOSX ifeq (${PVM_ARCH},NECSX) ifeq (${OMP},Y) OMP_FLG := -Popenmp endif # endif OMP CXX := c++ #CC := c++ -Xa CC := cc CPP := c++ -E #CPP := /usr/lib/cpp CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f90 LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -h2 -hmath vector -hxint # CFLAGS += -Cvopt -math vector -xint FFLAGS = -Cvopt -f3 endif ifeq (${OPTS},D) CFLAGS += -g FFLAGS = -g -f3 endif ifeq (${OPTS},X) CFLAGS += -g -h0 -hstack=nan # CFLAGS += -Cdebug -init stack=nan FFLAGS = -Cdebug -eR -f3 -Wf"-init stack=nan heap=nan" endif MK_DPN = /usr/local/bin/mkdep.perl /usr/lib/cpp # NECSX try this ${MY_DPN_DIR}/%.d : %.c ${MK_DPN} ${CPPFLAGS} $< | perl -p -e 's/$*\.o/${MY_OBJ_DIR_RX}\/$*.o ${MY_DPN_DIR_RX}\/$(notdir $@)/g;s/${slash_rx}/\${slash}/g' > $@ endif # endif NECSX ifeq (${PVM_ARCH},RS6K) CXX := g++ CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE CPP := /lib/cpp -P CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := xlf LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O2 CPP := ${CPP} ${CPPFLAGS} PREPROCESS.F := ${CPP} ${CPPFLAGS} FFLAGS := -O -g -NS2000 -qfixed=132 endif ifeq (${OPTS},D) CFLAGS += -g CPP := ${CPP} ${CPPFLAGS} PREPROCESS.F := ${CPP} ${CPPFLAGS} FFLAGS := -g -NS2000 -qfixed=132 endif ${MY_OBJ_DIR}/%.o : %.F ${CPP} ${CPPFLAGS} $< ${MY_OBJ_DIR}/$(basename $<).f ${FC} -c ${FFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) ${MY_OBJ_DIR}/$(basename $<).f ${MY_OBJ_DIR}/%.o : %.f ${FC} -c ${FFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< endif # endif RS6K # SGI6, SGI64, SGIMP64 ifneq (${null},$(findstring SGI,${PVM_ARCH})) ifeq (${OMP},Y) OMP_FLG := -mp -mpio endif # endif OMP CXX := CC -LANG:std CC := cc -c99 # 20000302: -w suppresses warnings which will swamp linker #CXX := g++ -w #CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} ifdef $(MIPSPRO_SGI) # SGIs like dataproc keep omp.h in special location determined by module MIPSpro CPPFLAGS := -I$(MIPSPRO_SGI)/usr/include ${CPPFLAGS} endif FC := f90 -cpp LD := ld LEX := flex LINT := lint YACC := bison ifeq (${PVM_ARCH},SGI6) GCC_ABI_FLG := -mabi=32 GCC_LDFLAGS_SZ_SPC := ${GCC_ABI_FLG} -mips3 SGI_ABI_FLG := -n32 -mips3 ${OMP_FLG} else # SGI64, SGIMP64 ifeq (${ABI},64) GCC_ABI_FLG := -mabi=64 GCC_LDFLAGS_SZ_SPC := ${GCC_ABI_FLG} -mips4 -L/usr/local/lib/mabi=64 SGI_ABI_FLG := -64 -mips4 ${OMP_FLG} else # ABI=32 GCC_ABI_FLG := -mabi=32 GCC_LDFLAGS_SZ_SPC := ${GCC_ABI_FLG} -mips4 SGI_ABI_FLG := -n32 -mips4 ${OMP_FLG} endif # endif ABI endif # endif SGI64, SGIMP64 ifeq (gcc,$(firstword ${CC})) LDFLAGS += ${GCC_LDFLAGS_SZ_SPC} ${TMP_LDFLAGS} ${TMP_LIBS} -lm CFLAGS := ${GCC_ABI_FLG} -Wall -Werror=format-security ifeq (${OPTS},O) CFLAGS += -O2 endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},X) CFLAGS += -g -O endif CXXFLAGS := ${CFLAGS} endif # endif CC=gcc ifeq (cc,$(firstword ${CC})) LDFLAGS += ${SGI_ABI_FLG} ${TMP_LDFLAGS} ${TMP_LIBS} -lm CFLAGS := ${SGI_ABI_FLG} ifeq (${OPTS},O) CFLAGS += -O2 endif ifeq (${OPTS},R) CFLAGS += endif ifeq (${OPTS},D) CFLAGS += -g endif ifeq (${OPTS},X) CFLAGS += -g -trapuv endif endif # endif CC=cc # Fortran flags FFLAGS := ${SGI_ABI_FLG} -extend_source ifeq (${OPTS},O) FFLAGS := -O2 -g endif ifeq (${OPTS},R) FFLAGS := endif ifeq (${OPTS},D) FFLAGS := -g endif ifeq (${OPTS},X) FFLAGS := -g -check_bounds -trapuv endif # end fortran flags endif # endif SGI6, SGI64, SGIMP64 ifeq (${UNAMES},SunOS) CXX := CC CC:= c99 -D_BSD_SOURCE CFLAGS := CPP := cc -E #CXX := g++ #CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE #CFLAGS := -Wall #CPP := cpp CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := f90 -DHIDE_SHR_MSG #FFLAGS := -xs -stackvar -e -Qoption f90comp -r8const FFLAGS := -xs -stackvar -e LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lsunmath -lresolv -lsocket -lnsl -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O2 -g FFLAGS += -fast endif ifeq (${OPTS},D) CFLAGS += -g FFLAGS += -g endif ifeq (${OPTS},X) CFLAGS += -g FFLAGS += -g # NB: 19980601 -C (range-checking) is not supported by Sun f90 ifeq (${FC},f77) FFLAGS += -C endif endif CXXFLAGS := ${CFLAGS} endif # endif SunOS=SUN4SOL2,SUNMP ifeq (${PVM_ARCH},WIN32) CXX := g++ CC := gcc -std=c99 -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE # NB: nameser.h needs -Di386, but gcc sends -Di586 (on pentiums) #CPP_TKN_OS += -Di386 -DNEED_STRCASECMP -DNEED_STRDUP -I/usr/include CPP_TKN_OS += -Di386 -DNEED_STRDUP -I/usr/include CPPFLAGS := ${CPP_TKN} ${CPP_TKN_OS} ${CPP_PTH} -I${NETCDF_INC} FC := g77 LD := ld LDFLAGS += ${TMP_LDFLAGS} ${TMP_LIBS} -lm LEX := flex LINT := lint YACC := bison ifeq (${OPTS},O) CFLAGS += -O -g endif ifeq (${OPTS},D) CFLAGS += -g endif ${MY_OBJ_DIR}/%.o : %.F ${FC} -c ${FFLAGS} ${CPPFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< ${MY_OBJ_DIR}/%.o : %.f ${FC} -c ${FFLAGS} -o ${MY_OBJ_DIR}/$(notdir $@) $< endif # endif WIN32 # Link to OPeNDAP libraries first, see OPeNDAP User's Guide # Currently this is invoked by using 'make DAP_OPENDAP=Y' ifeq (${DAP_OPENDAP},Y) # OPeNDAP >= 3.7.0 defines NC_64BIT_OFFSET correctly # CPPFLAGS += -DNC_64BIT_OFFSET=0 ifneq (${CC},g++) ifeq (${null},$(findstring xl,${CC})) # g++ automatically links to -lstdc++, other compilers may need help LDFLAGS := ${LDFLAGS} -lstdc++ endif # !xl* endif # !g++ endif # !DAP_OPENDAP # endif DAP_OPENDAP # Resolve nvcc CUDA run-time library functions ifeq (${CUDA},Y) CUDA_FLG_C := CUDA_FLG_F := LDFLAGS += -L/usr/local/cuda/lib -lcudart endif # endif CUDA # Internationalize NCO with i18n features ifeq (${I18N},Y) CPPFLAGS += -DI18N ifneq (${null},$(findstring SGI,${PVM_ARCH})) LDFLAGS += -lintl endif endif # endif I18N ifeq (${NETCDF4},Y) CPPFLAGS += -DENABLE_NETCDF4 -DHAVE_NETCDF4_H endif # endif NETCDF4 ifeq (${PNETCDF},Y) CPPFLAGS += -DENABLE_PNETCDF endif # endif PNETCDF ifeq (${ZNETCDF},Y) CPPFLAGS += -DENABLE_ZNETCDF endif # endif ZNETCDF # Default to MPICC, MPICXX to CC, CXX and cross your fingers MPICC := ${CC} MPICXX := ${CXX} # Manipulate CC, CPP, CXX as appropriate for MPI-enabled operators ifeq (${MPI},Y) ifneq (${null},$(findstring xl,${CC})) # NB: AIX is not debugged yet MPICC := $(subst xlc,mpcc,${CC}) MPICXX := $(subst xlC,mpCC,${CXX}) endif # endif AIX VA Compiler Collection ifneq (${null},$(findstring gcc,${CC})) MPICC := $(subst gcc,mpicc,${CC}) MPICXX := $(subst g++,mpicxx,${CXX}) endif # endif GNU Compiler Collection ifeq (icpc,$(firstword ${CXX})) MPICC := $(subst icc,mpicc,${CC}) MPICXX := $(subst icpc,mpicxx,${CXX}) endif # endif Intel (Kai) C++ Compiler ifneq (${null},$(findstring pathcc,${CC})) MPICC := $(subst pathcc,mpicc,${CC}) MPICXX := $(subst pathCC,mpicxx,${CXX}) endif # endif Pathscale (QLogic) Compilers CPP := ${MPICC} endif # endif MPI # Use MPI modifications, if any, to build all objects CC := ${MPICC} CXX := ${MPICXX} # Disable OpenMP on platforms which automatically support it ifneq (${OMP},Y) ifneq (${null},$(findstring SGI,${PVM_ARCH})) CFLAGS := $(filter-out -mp -mpio,${CFLAGS}) LDFLAGS := $(filter-out -mp -mpio,${LDFLAGS}) endif # endif SGI CPPFLAGS += -U_OPENMP endif # endif OMP ifneq (${null},$(findstring LINUX,${PVM_ARCH})) ifeq (${CCACHE},Y) # Prefix CC and CXX with ccache CC := ccache ${CC} CXX := ccache ${CXX} endif # !CCACHE endif # !LINUX ifeq (${STC},Y) # Created statically linked executable LDFLAGS := -static ${LDFLAGS} endif # endif STC # Define CPPCXXFLAGS after making all possible modifications to CPPFLAGS # Add nco_c++ to directory search path CXXCPPFLAGS := ${CPPFLAGS} -I${NCO_CXX_SRC_DIR} # Define any remaining variables libnco := ${MY_LIB_DIR}/libnco # Default targets all: dir lib ${MDL_BIN_TRG} data non_ncap: dir lib $(filter-out ncap,${MDL_BIN_TRG}) data # .PHONY tells make to remake the following non-file targets .PHONY: all cln dst_cln dbg ${MDL_BIN_TRG} # Delete default suffixes---this should increase speed .SUFFIXES: # Define suffixes that matter .SUFFIXES: .cc .c .cu .o .F .d # Delete targets that were not successfully made .DELETE_ON_ERROR: # Target directories which may not exist dir: bin_dir obj_dir lib_dir bin_dir: # Compaq ALPHA complains about -install # -install -d ${MY_BIN_DIR} -mkdir -p ${MY_BIN_DIR} lib_dir: # -install -d ${MY_BIN_DIR} -mkdir -p ${MY_LIB_DIR} obj_dir: # -install -d ${MY_BIN_DIR} -mkdir -p ${MY_OBJ_DIR} # The whole shebang allinone: all nco_c++ nco++ nco_c++: -cd ../src/nco_c++; ${MAKE} -f Makefile.old DBG=${DBG} NETCDF4=${NETCDF4} OMP=${OMP} OPTS=${OPTS} SZ=${SZ} lib dat all nco++: -cd ../src/nco++; ${MAKE} -f Makefile.old CNK=${CNK} DAP_NETCDF=${DAP_NETCDF} DAP_OPENDAP=${DAP_OPENDAP} DBG=${DBG} GSL=${GSL} NETCDF4=${NETCDF4} OMP=${OMP} OPTS=${OPTS} SZ=${SZ} UDUNITS2=${UDUNITS2} lib all # Targets in bin mpi: mpi_nco mpinco: mpi_nco mpnco: mpi_nco mpi_nco: ${MDL_MPI_TRG} -rm -f ${MY_BIN_DIR}/mpirun && ln -f -s `which mpirun` ${MY_BIN_DIR}/mpirun mpncbo: ${MY_BIN_DIR}/mpncbo ${MY_BIN_DIR}/mpncbo: ${MY_OBJ_DIR}/mpncbo.o lib ${MPICC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} cd ${MY_BIN_DIR}; rm -f mpncdiff; ln -s -f mpncbo mpncdiff # 20050710: icc 8.1 with -axW flag dies compiling ncecat # 20050915: Same problem occurs with MPI_FAKE version of mpncecat ifeq (icc,$(firstword ${LINUX_CC})) ncecat : CFLAGS := $(filter-out -axW,${CFLAGS}) ifeq (${MPI_FAKE},Y) mpncecat : CFLAGS := $(filter-out -axW,${CFLAGS}) endif # !MPI_FAKE endif # endif Intel (Kai) C Compiler mpncecat: ${MY_BIN_DIR}/mpncecat ${MY_BIN_DIR}/mpncecat: ${MY_OBJ_DIR}/mpncecat.o lib ${MPICC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} mpncflint: ${MY_BIN_DIR}/mpncflint ${MY_BIN_DIR}/mpncflint: ${MY_OBJ_DIR}/mpncflint.o lib ${MPICC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} mpncpdq: ${MY_BIN_DIR}/mpncpdq ${MY_BIN_DIR}/mpncpdq: ${MY_OBJ_DIR}/mpncpdq.o lib ${MPICC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} # cd ${MY_BIN_DIR}; rm -f mpncunpack; ln -s -f mpncpdq mpncunpack # cd ${MY_BIN_DIR}; rm -f mpncpack; ln -s -f mpncpdq mpncpack mpncra: ${MY_BIN_DIR}/mpncra ${MY_BIN_DIR}/mpncra: ${MY_OBJ_DIR}/mpncra.o lib ${MPICC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} cd ${MY_BIN_DIR}; rm -f mpncea; ln -s -f mpncra mpncea cd ${MY_BIN_DIR}; rm -f mpnces; ln -s -f mpncra mpnces cd ${MY_BIN_DIR}; rm -f mpncrcat; ln -s -f mpncra mpncrcat mpncwa: ${MY_BIN_DIR}/mpncwa ${MY_BIN_DIR}/mpncwa: ${MY_OBJ_DIR}/mpncwa.o ${MY_OBJ_DIR}/ncap_yacc.o ${MY_OBJ_DIR}/ncap_lex.o ${MY_OBJ_DIR}/ncap_utl.o lib ${MPICC} -o $@${BNR_SFX} $< ${MY_OBJ_DIR}/ncap_yacc.o ${MY_OBJ_DIR}/ncap_lex.o ${MY_OBJ_DIR}/ncap_utl.o ${LDFLAGS} chmod 755 $@${BNR_SFX} ncatted: ${MY_BIN_DIR}/ncatted ${MY_BIN_DIR}/ncatted: ${MY_OBJ_DIR}/ncatted.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} ncbo: ${MY_BIN_DIR}/ncbo ${MY_BIN_DIR}/ncbo: ${MY_OBJ_DIR}/ncbo.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} cd ${MY_BIN_DIR}; rm -f ncdiff; ln -s -f ncbo ncdiff ncecat: ${MY_BIN_DIR}/ncecat ${MY_BIN_DIR}/ncecat: ${MY_OBJ_DIR}/ncecat.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} ncflint: ${MY_BIN_DIR}/ncflint ${MY_BIN_DIR}/ncflint: ${MY_OBJ_DIR}/ncflint.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} ncks: ${MY_BIN_DIR}/ncks ${MY_BIN_DIR}/ncks: ${MY_OBJ_DIR}/ncks.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} ncpdq: ${MY_BIN_DIR}/ncpdq ${MY_BIN_DIR}/ncpdq: ${MY_OBJ_DIR}/ncpdq.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} cd ${MY_BIN_DIR}; rm -f ncunpack; ln -s -f ncpdq ncunpack cd ${MY_BIN_DIR}; rm -f ncpack; ln -s -f ncpdq ncpack ncra: ${MY_BIN_DIR}/ncra ${MY_BIN_DIR}/ncra: ${MY_OBJ_DIR}/ncra.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} cd ${MY_BIN_DIR}; rm -f ncea; ln -s -f ncra ncea cd ${MY_BIN_DIR}; rm -f nces; ln -s -f ncra nces cd ${MY_BIN_DIR}; rm -f ncrcat; ln -s -f ncra ncrcat ncrename: ${MY_BIN_DIR}/ncrename ${MY_BIN_DIR}/ncrename: ${MY_OBJ_DIR}/ncrename.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} ncwa: ${MY_BIN_DIR}/ncwa ${MY_BIN_DIR}/ncwa: ${MY_OBJ_DIR}/ncwa.o ${MY_OBJ_DIR}/ncap_yacc.o ${MY_OBJ_DIR}/ncap_lex.o ${MY_OBJ_DIR}/ncap_utl.o lib ifeq (${MSVC},TRUE) ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} else ${CC} -o $@${BNR_SFX} $< ${MY_OBJ_DIR}/ncap_yacc.o ${MY_OBJ_DIR}/ncap_lex.o ${MY_OBJ_DIR}/ncap_utl.o ${LDFLAGS} endif chmod 755 $@${BNR_SFX} bin: ${MDL_BIN_TRG} binclean: bin_cln bin_cln: rm -f ${MDL_BIN} mpiclean: mpi_cln mpi_cln: rm -f ${MDL_MPI_BIN} ${MDL_MPI_OBJ} mpi_fake_cp: ${MDL_MPI_TRG} - for fl in ${MDL_MPI_TRG_SMP}; do /bin/cp -f ${MY_BIN_DIR}/$$fl ${MY_BIN_DIR}/mp$$fl; done # 20050916 fxm: not sure why simpler substitution method does not work # - for fl in ${MDL_MPI_TRG}; do /bin/cp -f ${MY_BIN_DIR}/$$fl ${MY_BIN_DIR}/$(subst mp,,$$fl); done strip: - printf "Before stripping...\n";ls -l ${MDL_BIN};strip ${MDL_BIN};printf "After stripping...\n";ls -l ${MDL_BIN} # Targets in bld buildclean: bld_cln bld_cln: cd ${MY_BLD_DIR}; rm -f TAGS libtest: libtst libtst: libnco_tst libnco_c++_tst libnco_tst: ${MY_BLD_DIR}/libnco_tst ${MY_BLD_DIR}/libnco_tst: ${MY_BLD_DIR}/libnco_tst.o lib ${CC} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} libnco_c++_tst: ${MY_BLD_DIR}/libnco_c++_tst ${MY_BLD_DIR}/libnco_c++_tst: ${MY_BLD_DIR}/libnco_c++_tst.o lib ${CXX} -o $@${BNR_SFX} $< ${LDFLAGS} chmod 755 $@${BNR_SFX} rpm: ${MY_BLD_DIR}/nco.spec # Building rpm requires root priveleges, e.g., sudo make NCO_VRS=4.4.2 rpm # Building NCO RPM requires following packages # rpm -q bison flex netcdf-devel libtool automake autoconf udunits udunits-devel curl-devel libxml2 libxml2-devel librx-devel # sudo yum install bison flex netcdf-devel libtool automake autoconf udunits udunits-devel curl-devel libxml2 libxml2-devel librx-devel cd ${DATA}/tmp; \ /bin/rm -fr ${DATA}/tmp/nco*; \ cp -r ${HOME}/nco nco-${NCO_VRS}; \ tar cvzf nco-${NCO_VRS}.tar.gz ./nco-${NCO_VRS}; \ mv ${DATA}/tmp/nco-${NCO_VRS}.tar.gz /usr/src/redhat/SOURCES; \ /bin/rm -f /usr/src/redhat/SPECS/nco-${NCO_VRS}.spec; \ ln -s ${HOME}/nco/bld/nco.spec /usr/src/redhat/SPECS/nco-${NCO_VRS}.spec; \ cd /usr/src/redhat/SPECS; \ rpmbuild -ba --sign nco-${NCO_VRS}.spec; # Crypographically sign RPM packages with GPG: http://fedoranews.org/tchung/gpg # gpg --export -a 'Charlie Zender' > ~/GPG-zender # Export public key from key ring to text file # sudo rpm --import ~/GPG-zender # Import public key to RPM database # rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n' # Verify list of GPG public keys in RPM database # Verify ~/.rpmmacros file specifies _signature and gpg_name # sudo rpm --addsign /usr/src/redhat/SRPMS/nco-${NCO_VRS}-?.src.rpm /usr/src/redhat/RPMS/i386/nco-${NCO_VRS}-?.i386.rpm # Sign RPM packages # rpm --checksig /usr/src/redhat/SRPMS/nco-${NCO_VRS}-?.src.rpm /usr/src/redhat/RPMS/i386/nco-${NCO_VRS}-?.i386.rpm # Check signatures rpmnet: ${MY_BLD_DIR}/nco.spec # Building rpm requires root priveleges, e.g., sudo make NCO_VRS=3.1.8 rpmnet - if test -f /usr/src/redhat/SOURCES/nco-${NCO_VRS}.tar.gz; then printf "Using existing nco-${NCO_VRS}.tar.gz\n" ; else ${MY_BIN_DIR}/ncks -R -p ftp://dust.ess.uci.edu/pub/zender/nco -l /usr/src/redhat/SOURCES nco-${NCO_VRS}.tar.gz; fi /bin/rm -f /usr/src/redhat/SPECS/nco-${NCO_VRS}.spec; \ cd /usr/src/redhat/SOURCES; \ tar xvzf nco-${NCO_VRS}.tar.gz ./nco-${NCO_VRS}/bld/nco.spec; \ mv ./nco-${NCO_VRS}/bld/nco.spec /usr/src/redhat/SPECS/nco.spec; \ cd /usr/src/redhat/SPECS; \ rpmbuild -ba --sign nco.spec; \ scp /usr/src/redhat/SRPMS/nco-${NCO_VRS}-?.src.rpm /usr/src/redhat/RPMS/i386/nco-${NCO_VRS}-?.i386.rpm zender@dust.ess.uci.edu:/var/www/html/nco/src rpm_cln: rpm --erase ${MDL_RPM_NST_NM} # Targets in bm bench: bm bnch: bm bm: cd ${MY_BM_DIR}; \ env MY_BIN_DIR=${MY_BIN_DIR} ../bm/nco_bm.pl --dbg=0 --bench --udpreport ${FL_FMT_SNG} ${MPI_PRC_SNG} ${THR_NBR_SNG} file: fl fl: cd ${MY_BM_DIR}; \ env MY_BIN_DIR=${MY_BIN_DIR} ../bm/nco_bm.pl --dbg=0 --test_files=A --udpreport ${FL_FMT_SNG} ${MPI_PRC_SNG} ${THR_NBR_SNG} regression: tst rgr: tst test: tst tst: dat cd ${MY_BM_DIR}; \ env MY_BIN_DIR=${MY_BIN_DIR} ../bm/nco_bm.pl --dbg=0 --regress --udpreport ${FL_FMT_SNG} ${MPI_PRC_SNG} ${THR_NBR_SNG} # Targets in dat # ncgen rules to build netCDF4 files must be error-tolerant to build on netCDF3-only installations bug: ${MY_DAT_DIR}/buggy.nc ${MY_DAT_DIR}/buggy.nc: ${MY_DAT_DIR}/buggy.cdl -ncgen -k netCDF-4 -b -o $@ $< dap: data -cd ~/nco/data; scp in.nc in.cdl dust.ess.uci.edu:/var/www/html/dodsdata; scp in.nc in.cdl esmf.ess.uci.edu:/var/www/html/dodsdata; scp in.nc in.cdl esmf.ess.uci.edu:/data/dodsdata data: dat dat: ${MY_DAT_DIR}/cmip5.nc ${MY_DAT_DIR}/obs.nc ${MY_DAT_DIR}/dsm.nc ${MY_DAT_DIR}/hdn.nc ${MY_DAT_DIR}/hdf.hdf ${MY_DAT_DIR}/mdl.nc ${MY_DAT_DIR}/mdl2.nc ${MY_DAT_DIR}/in.nc ${MY_DAT_DIR}/in_grp.nc ${MY_DAT_DIR}/in_4.nc ${MY_DAT_DIR}/in_grp_1.nc ${MY_DAT_DIR}/in_grp_2.nc ${MY_DAT_DIR}/in_grp_3.nc ${MY_DAT_DIR}/in_rec_zero.nc -for fl in ${MDL_DAT_STB}; do cd ${MY_DAT_DIR}; ln -s -f in.nc $$fl; done ${MY_DAT_DIR}/in.nc: ${MY_DAT_DIR}/in.cdl ncgen -b -o $@ $< ${MY_DAT_DIR}/in_rec_zero.nc: ${MY_DAT_DIR}/in_rec_zero.cdl ncgen -b -o $@ $< ${MY_DAT_DIR}/in_grp.nc: ${MY_DAT_DIR}/in_grp.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_4.nc: ${MY_DAT_DIR}/in_4.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_grp_1.nc: ${MY_DAT_DIR}/in_grp_1.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_grp_2.nc: ${MY_DAT_DIR}/in_grp_2.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_1.nc: ${MY_DAT_DIR}/in_1.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_2.nc: ${MY_DAT_DIR}/in_2.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/in_grp_3.nc: ${MY_DAT_DIR}/in_grp_3.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/cmip5.nc: ${MY_DAT_DIR}/cmip5.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/hdn.nc: ${MY_DAT_DIR}/hdn.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/dsm.nc: ${MY_DAT_DIR}/dsm.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/obs.nc: ${MY_DAT_DIR}/obs.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/hdf.hdf: ${MY_DAT_DIR}/hdf.cdl -hncgen -b -o $@ $< ${MY_DAT_DIR}/mdl.nc: ${MY_DAT_DIR}/mdl.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/mdl2.nc: ${MY_DAT_DIR}/mdl2.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snd_ncwa.nc: ${MY_DAT_DIR}/snd_ncwa.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snc_ncwa.nc: ${MY_DAT_DIR}/snc_ncwa.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snd_grp.nc: ${MY_DAT_DIR}/snd_grp.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snc_grp.nc: ${MY_DAT_DIR}/snc_grp.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snc.nc: ${MY_DAT_DIR}/snc.cdl -ncgen -k netCDF-4 -b -o $@ $< ${MY_DAT_DIR}/snd.nc: ${MY_DAT_DIR}/snd.cdl -ncgen -k netCDF-4 -b -o $@ $< dataclean: dat_cln dat_cln: rm -f ${MDL_DAT} cd ${MY_DAT_DIR}; rm -f foo* tst_ftp: dat - if test -f ${MY_DAT_DIR}/nco_tst.nc; then printf "" ; else ${MY_BIN_DIR}/ncks -q -R -p ftp://dust.ess.uci.edu/pub/zender/nco -l ${MY_DAT_DIR} nco_tst.nc; if [ $? != 0 ]; then printf "WARNING: Unable to retrieve ftp://dust.ess.uci.edu/pub/zender/nco/nco_tst.nc required for self-test, possible problem with getting through your firewall? Manually download and install in directory ../data to continue self test...\n"; fi; fi cd ${MY_BLD_DIR}; \ env MY_BIN_DIR=${MY_BIN_DIR} MY_DAT_DIR=${MY_DAT_DIR} ./nco_tst.pl testclean: tst_cln tst_cln: cd ${MY_DAT_DIR}; rm -f foo* nco_tst.nc # Targets in doc # Each make directive line spawns a separate shell so must use `cd dir;cmd' format doc: ${MY_DOC_DIR}/nco.dvi ${MY_DOC_DIR}/nco.html ${MY_DOC_DIR}/nco.info ${MY_DOC_DIR}/nco.ps ${MY_DOC_DIR}/nco.pdf ${MY_DOC_DIR}/nco.txt ${MY_DOC_DIR}/nco.xml ${MY_DOC_DIR}/nco.dvi: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; texi2dvi --output=$@ $< ${MY_DOC_DIR}/nco.info: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; makeinfo --no-split --output=$@ $< ${MY_DOC_DIR}/nco.html: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; texi2html -monolithic -verbose $< # cd ${MY_DOC_DIR}; makeinfo --html --no-split --output=$@ $< ${MY_DOC_DIR}/nco.ps: ${MY_DOC_DIR}/nco.dvi cd ${MY_DOC_DIR}; dvips -o $@ nco.dvi ${MY_DOC_DIR}/nco.pdf: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; texi2dvi --pdf --output=$@ $< # cd ${MY_DOC_DIR}; ps2pdf -dMaxSubsetPct=100 -dCompatibilityLevel=1.2 -dSubsetFonts=true -dEmbedAllFonts=true nco.ps $@ ${MY_DOC_DIR}/nco.txt: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; makeinfo --no-headers --no-split --output=$@ $< # Neither of these xml formats seems to be viewable ${MY_DOC_DIR}/nco.xml: ${MY_DOC_DIR}/nco.texi cd ${MY_DOC_DIR}; makeinfo --xml --no-split --output=$@ $< # cd ${MY_DOC_DIR}; makeinfo --docbook --no-split --output=$@ $< docclean: doc_cln doc_cln: cd ${MY_DOC_DIR}; rm -f nco.info* nco.dvi nco.html* nco.ps nco.pdf *~ # Targets in dpn depend: dpn dpn: ${MDL_DPN} dpn_cln: rm -f ${MDL_DPN} # Targets in inc include: inc inc: ${MDL_INC} inc_cln: rm -f ${MDL_INC} love: echo "Not war?" # Targets in lib library: lib lib : inc ${libnco}.a ifeq (${PVM_ARCH},MACOSX) ranlib ${libnco}.a endif # endif LINUX # If not using glibc, build Sittler's getopt() and getopt_long() functions ifeq (${null},$(findstring ${PVM_ARCH},FREEBSDLINUXALPHALINUXAMD64LINUXARMMACOSXWIN32)) ${libnco}.a: ${libnco}.a(${MY_OBJ_DIR}/nco_getopt.o) endif # endif not glibc ${libnco}.a: ${libnco}.a(${MY_OBJ_DIR}/nco_att_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_aux.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_bnr.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cln_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cnf_dmn.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cnf_typ.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cnk.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cnv_arm.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_cnv_csm.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_ctl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_dbg.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_dmn_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_fl_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_grp_trv.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_grp_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_lmt.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_lst_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_md5.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_mmr.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_msa.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_mss_val.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_netcdf.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_omp.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_pck.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_prn.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_rec_var.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_rth_flt.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_rth_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_scl_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_scm.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_sng_utl.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_srm.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_var_avg.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_var_lst.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_var_rth.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_var_scv.o) \ ${libnco}.a(${MY_OBJ_DIR}/nco_var_utl.o) libclean: lib_cln lib_cln: rm -f ${libnco}.* ${libnco}*.* ${libnco}++.a ${libnco}_c++.a # Targets in man man: ${MDL_MAN} cd ../man;sudo cp -f *.1 ${MY_MAN_DIR}/man1 man_cln: rm -f ${MDL_MAN} # Targets in obj object: obj obj: ${MDL_OBJ} objclean: obj_cln obj_cln: rm -f ${MDL_OBJ} # Targets in root autotools: dst_cln - cd ..; aclocal;autoheader;automake --foreign;autoconf ; ./configure --enable-optimize-custom --prefix=${HOME} --bindir=${MY_BIN_DIR} --datadir=${HOME}/nco/data --libdir=${MY_LIB_DIR} --mandir=${HOME}/nco/man ; ${MAKE} install rootclean: root_cln root_cln: - cd ..; rm -f config.h config.guess config.log config.status config.sub libtool Makefile stamp-h1; rm -r -f autom4te.cache conftest # Targets in src src: ${MDL_NCAP} src_cln: rm -f ${MDL_NCAP} # Targets in /usr/local sys: ${MDL_BIN_TRG} - cd ${MY_BIN_DIR};sudo /bin/cp -f ${MDL_BIN_TRG} ncap2 /usr/local/bin; cd /usr/local/bin; sudo rm -f ncdiff ncea nces ncrcat ncunpack; sudo ln -s -f ncbo ncdiff; sudo ln -s -f ncra ncea; sudo ln -s -f ncra nces; sudo ln -s -f ncra ncrcat; sudo ln -s -f ncpdq ncunpack; sudo ln -s -f ncpdq ncpack; cd ${HOME}/nco/src/nco++; ${MAKE} -f Makefile.old OPTS=${OPTS} $@ sys_cln: - cd /usr/local/bin;rm -f ${MDL_BIN_TRG} # Housekeeping clean: cln cln: lib_cln dpn_cln obj_cln src_cln tst_cln cd ${MY_DOC_DIR}; rm -f nco.aux nco.cp nco.cps nco.fn nco.ky nco.log nco.pg nco.toc nco.tp nco.vr debug: dbg dbg: @printf "ABI = ${ABI}\n" @printf "AR = ${AR}\n" @printf "BNR_SFX = ${BNR_SFX}\n" @printf "CC = ${CC}\n" @printf "CCACHE = ${CCACHE}\n" @printf "CFLAGS = ${CFLAGS}\n" @printf "CNK = ${CNK}\n" @printf "CPP = ${CPP}\n" @printf "CPPFLAGS = ${CPPFLAGS}\n" @printf "CPP_PTH = ${CPP_PTH}\n" @printf "CPP_TKN = ${CPP_TKN}\n" @printf "CURL_LIB = ${CURL_LIB}\n" @printf "CXX = ${CXX}\n" @printf "CXXFLAGS = ${CXXFLAGS}\n" @printf "DAP_NETCDF = ${DAP_NETCDF}\n" @printf "DAP_NETCDF_ROOT = ${DAP_NETCDF_ROOT}\n" @printf "DAP_OPENDAP = ${DAP_OPENDAP}\n" @printf "DAP_OPENDAP_ROOT = ${DAP_OPENDAP_ROOT}\n" @printf "DBG = ${DBG}\n" @printf "FC = ${FC}\n" @printf "FFLAGS = ${FFLAGS}\n" @printf "FL_FMT = ${FL_FMT}\n" @printf "GCC_RCH_ARG = ${GCC_RCH_ARG}\n" @printf "GSL = $(GSL)\n" @printf "HDF5_ROOT = ${HDF5_ROOT}\n" @printf "HDF5_INC = ${HDF5_INC}\n" @printf "HDF5_LIB = ${HDF5_LIB}\n" @printf "HOST = ${HOST}\n" @printf "HOSTNAME = ${HOSTNAME}\n" @printf "ICC_RCH_ARG = ${ICC_RCH_ARG}\n" @printf "INC_NCAR = ${INC_NCAR}\n" @printf "LAMMPICC = ${LAMMPICC}\n" @printf "LAMMPICXX = ${LAMMPICXX}\n" @printf "LDFLAGS = ${LDFLAGS}\n" @printf "LEX = ${LEX}\n" @printf "LFLAGS = ${LFLAGS}\n" @printf "LIB_NCAR = ${LIB_NCAR}\n" @printf "LINUX_CC = $(LINUX_CC)\n" @printf "LINUX_CXX = $(LINUX_CXX)\n" @printf "MDL_BIN_TRG = ${MDL_BIN_TRG}\n" @printf "MDL_DPN = ${MDL_DPN}\n" @printf "MDL_MAN = ${MDL_MAN}\n" @printf "MDL_MPI_TRG = ${MDL_MPI_TRG}\n" @printf "MDL_OBJ = ${MDL_OBJ}\n" @printf "MDL_PTH = ${MDL_PTH}\n" @printf "MDL_RPM_NST_NM = ${MDL_RPM_NST_NM}\n" @printf "MDL_SRC = ${MDL_SRC}\n" @printf "MPICC = ${MPICC}\n" @printf "MPICH_CC = ${MPICH_CC}\n" @printf "MPICH_CXX = ${MPICH_CXX}\n" @printf "MPICXX = ${MPICXX}\n" @printf "MPI_PRC = ${MPI_PRC}\n" @printf "MPI_PRC_SNG = ${MPI_PRC_SNG}\n" @printf "MPI_ROOT = ${MPI_ROOT}\n" @printf "MY_BIN_DIR = ${MY_BIN_DIR}\n" @printf "MY_BLD_DIR = ${MY_BLD_DIR}\n" @printf "MY_BLD_DIR = ${MY_BLD_DIR}\n" @printf "MY_DAT_DIR = ${MY_DAT_DIR}\n" @printf "MY_DOC_DIR = ${MY_DOC_DIR}\n" @printf "MY_DPN_DIR = ${MY_DPN_DIR}\n" @printf "MY_INC_DIR = ${MY_INC_DIR}\n" @printf "MY_LIB_DIR = ${MY_LIB_DIR}\n" @printf "MY_MAN_DIR = ${MY_MAN_DIR}\n" @printf "MY_OBJ_DIR = ${MY_OBJ_DIR}\n" @printf "NCO_LDFLAGS = $(NCO_LDFLAGS)\n" @printf "NCO_LIBS = $(NCO_LIBS)\n" @printf "NCO_VRS = ${NCO_VRS}\n" @printf "NC_LDFLAGS = $(NC_LDFLAGS)\n" @printf "NC_LIBS = $(NC_LIBS)\n" @printf "NETCDF4 = ${NETCDF4}\n" @printf "NETCDF4_ROOT = ${NETCDF4_ROOT}\n" @printf "NETCDF_INC = ${NETCDF_INC}\n" @printf "NETCDF_LIB = ${NETCDF_LIB}\n" @printf "NETCDF_ROOT = ${NETCDF_ROOT}\n" @printf "OMP = ${OMP}\n" @printf "PGI_RCH_ARG = ${PGI_RCH_ARG}\n" @printf "PSC_RCH_ARG = ${PSC_RCH_ARG}\n" @printf "PNETCDF = ${PNETCDF}\n" @printf "PVM_ARCH = ${PVM_ARCH}\n" @printf "RPM = ${RPM}\n" @printf "SRC_LST = $(SRC_LST)\n" @printf "STC = ${STC}\n" @printf "SZ = ${SZ}\n" @printf "THR_NBR = ${THR_NBR}\n" @printf "THR_NBR_SNG = ${THR_NBR_SNG}\n" @printf "TMP_LDFLAGS = ${TMP_LDFLAGS}\n" @printf "TMP_LIBS = ${TMP_LIBS}\n" @printf "UDUNITS = $(UDUNITS)\n" @printf "UDUNITS2 = $(UDUNITS2)\n" @printf "UDUNITS_INC = $(UDUNITS_INC)\n" @printf "UDUNITS_LIB = $(UDUNITS_LIB)\n" @printf "VPATH = ${VPATH}\n" @printf "VRS_SNG = ${VRS_SNG}\n" @printf "YACC = ${YACC}\n" @printf "YFLAGS = ${YFLAGS}\n" @printf "ZNETCDF = ${ZNETCDF}\n" distclean: dst_cln dst_cln: cln bin_cln dat_cln doc_cln root_cln cd ${MY_BLD_DIR}; rm -f *~ cd ${MY_DAT_DIR}; rm -f buggy.nc cmip5.nc dsm.nc obs.nc hdf.hdf mdl.nc mdl2.nc in.nc in_4.nc in_grp.nc in_grp_1.nc in_grp_2.nc in_grp_3.nc in_rec_zero.nc *~ tags: etags ${MY_SRC_DIR}/*.h $(filter-out ${TAGS_FILTER_FILES},${SRC_LST}) ${MDL_DOC_SRC} ${MDL_MAN} ${MDL_BLD_SRC} ${MDL_CXX_SRC} ${MDL_NCAP_SRC} ${MDL_QT_SRC} # Reset internal YACC and LEX patterns %.c : %.y %.c : %.l # It is safest to do both YACC and LEX after either file changes # Otherwise only changing one and then switching, e.g., from bison to yacc, can cause problems # NB: Bison has problem when bison.simple declares yyparse() as int yyparse (void); # Solution is to comment out that definition in bison.simple ifeq (${YACC},bison) ${MY_SRC_DIR}/%_yacc.c ${MY_SRC_DIR}/%_yacc.h : ${MY_SRC_DIR}/%_yacc.y ${YACC} ${YFLAGS} --output=$(basename $<).c -d $< #${MY_SRC_DIR}/%_yacc.c ${MY_SRC_DIR}/%_yacc.h : ${MY_SRC_DIR}/%_yacc.y # ${YACC} ${YFLAGS} --file-prefix=$(notdir $($(basename $<))) -d $< #%_yacc.c %_yacc.h : %_yacc.y # ${YACC} ${YFLAGS} --file-prefix=$(notdir $($(basename $<))) -d $< endif ifeq (${YACC},yacc) %.tab.c %.tab.h : %.y ${YACC} ${YFLAGS} $< mv y.tab.c $(basename $<).c mv y.tab.h $(basename $<).h endif %_lex.c : %_lex.l ${LEX} ${LFLAGS} $< mv lex.${NCO_YY_PFX}.c $(basename $<).c # Target-specific variable values syntax TARGET ... : VARIABLE-ASSIGNMENT # Rules begin in leftmost column else interpreted as commands ifneq (${null},$(findstring ${PVM_ARCH},LINUXALPHALINUXAMD64LINUXARMFREEBSD)) ifeq (gcc,$(firstword ${CC})) ${MY_OBJ_DIR}/nco_grp_trv.o : CFLAGS := $(filter-out -Wcast-qual,${CFLAGS}) ${MY_OBJ_DIR}/nco_grp_trv.o : CXXFLAGS := $(filter-out -Wcast-qual,${CXXFLAGS}) endif # endif GCC endif # endif LINUX # ncap, and only ncap, requires AIX system C++ library ifneq (${null},$(findstring AIX,${PVM_ARCH})) ifneq (${null},$(findstring xl,${CC})) # Target-specific variable values syntax TARGET ... : VARIABLE-ASSIGNMENT # Rules begin in leftmost column else interpreted as commands ncap : LDFLAGS += -lC endif # endif AIX VA Compiler Collection endif # endif AIX # For some reason, ncap_lex.c is not remade when I expect it to be, so I explicitly remove the object file every time ncap: ${MY_OBJ_DIR}/ncap_yacc.o ${MY_OBJ_DIR}/ncap_lex.o ncap_yacc.h ${MY_OBJ_DIR}/ncap.o ${MY_OBJ_DIR}/ncap_utl.o ${libnco}.a # ${YACC} --name-prefix=nco_ ifneq (${null},$(findstring ${PVM_ARCH},LINUXALPHALINUXAMD64LINUXARMFREEBSDWIN32SGIMP64)) ${CC} ${CFLAGS} -o ${MY_BIN_DIR}/$@ ${MY_OBJ_DIR}/$@.o ${MY_OBJ_DIR}/ncap_utl.o ${MY_OBJ_DIR}/$@_yacc.o ${MY_OBJ_DIR}/$@_lex.o ${LDFLAGS} else ${CC} ${CFLAGS} -o ${MY_BIN_DIR}/$@ ${MY_OBJ_DIR}/$@.o ${MY_OBJ_DIR}/ncap_utl.o ${MY_OBJ_DIR}/$@_yacc.o ${MY_OBJ_DIR}/$@_lex.o -ll -ly ${LDFLAGS} endif chmod 755 ${MY_BIN_DIR}/$@${BNR_SFX} ncap2 : -cd ../src/nco++; ${MAKE} -f Makefile.old DAP_NETCDF=${DAP_NETCDF} DAP_OPENDAP=${DAP_OPENDAP} DBG=${DBG} GSL=${GSL} NETCDF4=${NETCDF4} OMP=${OMP} OPTS=${OPTS} SZ=${SZ} UDUNITS2=${UDUNITS2} all # /bin/rm -f ${MDL_NCAP} ${MY_OBJ_DIR}/$@_lex.o ${MY_OBJ_DIR}/ncap_yacc.h ${MY_OBJ_DIR}/ncap_yacc.c # Create dependency files only if they will not be immediately deleted INCLUDE_DPN := TRUE GOALS_WHICH_DELETE_DEPENDENCY_FILES := cln clean dir distclean dst_cln dpn_cln tags uninstall ifeq (${null},$(findstring $(MAKECMDGOALS),${GOALS_WHICH_DELETE_DEPENDENCY_FILES})) INCLUDE_DPN := TRUE else INCLUDE_DPN := FALSE endif ifeq (${INCLUDE_DPN},TRUE) -include ${MDL_DPN} endif ./nco-4.4.2/Makefile.am0000644000674300045400000000120011775420332014006 0ustar zendercgdcsm# $Header: /cvsroot/nco/nco/Makefile.am,v 1.17 2012/07/05 23:18:50 pvicente Exp $ -*-makefile-*- #SUBDIRS = data src man doc SUBDIRS = data src man @DOC_FOLDER@ # Separately add desired files from nco/bld/ to distribution # Autoconf does not know about the bld directory # In particular, nco/bld/Makefile was created manually, not by autoconf bld_extras = bld/Makefile bld/pvmgetarch bld/nco.spec EXTRA_DIST = $(bld_extras) ACLOCAL_AMFLAGS = -I m4 test: tst tst: $(MAKE) check cd bm && ./nco_bm.pl --regress regress: rgr rgr: cd bm && ./nco_bm.pl --regress regress-mpi: rgr_mpi rgr_mpi: cd bm && ./nco_bm.pl --regress --mpi_prc=2 ./nco-4.4.2/src/0000755000674300045400000000000012301476047012550 5ustar zendercgdcsm./nco-4.4.2/src/nco/0000755000674300045400000000000012301476045013325 5ustar zendercgdcsm./nco-4.4.2/src/nco/nco_mss_val.c0000644000674300045400000004365712260451232016006 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_mss_val.c,v 1.53 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Missing value utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_mss_val.h" /* Missing value utilities */ ptr_unn /* O [sct] Default missing value for type type */ nco_mss_val_mk /* [fnc] Return default missing value for type type */ (const nc_type type) /* I [enm] netCDF type of operand */ { /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Return pointer union containing default missing value for type type */ ptr_unn mss_val; mss_val.vp=(void *)nco_malloc(nco_typ_lng(type)); /* Typecast pointer to values before access */ (void)cast_void_nctype(type,&mss_val); switch(type){ case NC_FLOAT: *mss_val.fp=NC_FILL_FLOAT; break; case NC_DOUBLE: *mss_val.dp=NC_FILL_DOUBLE; break; case NC_INT: *mss_val.ip=NC_FILL_INT; break; case NC_SHORT: *mss_val.sp=NC_FILL_SHORT; break; case NC_CHAR: *mss_val.cp=NC_FILL_CHAR; break; case NC_BYTE: *mss_val.bp=NC_FILL_BYTE; break; case NC_UBYTE: *mss_val.ubp=NC_FILL_UBYTE; break; case NC_USHORT: *mss_val.usp=NC_FILL_USHORT; break; case NC_UINT: *mss_val.uip=NC_FILL_UINT; break; case NC_INT64: *mss_val.i64p=NC_FILL_INT64; break; case NC_UINT64: *mss_val.ui64p=NC_FILL_UINT64; break; case NC_STRING: *mss_val.sngp='\0'; break; /* fxm: NC_FILL_STRING? TODO nco839 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Un-typecast pointer to values after access */ (void)cast_nctype_void(type,&mss_val); return mss_val; } /* end nco_mss_val_mk() */ nco_bool /* O [flg] One or both operands have missing value */ nco_mss_val_cnf /* [fnc] Change missing_value of var2 to missing_value of var1 */ (var_sct * const var1, /* I [sct] Variable with template missing value to copy */ var_sct * const var2) /* I/O [sct] Variable with missing value to fill in/overwrite */ { /* Purpose: 1. Change missing_value of var2 to missing_value of var1 when both exist 2. Change missing_value of var1 to missing_value of var2 when only var2 has a missing_value 3. Change missing_value of var2 to missing_value of var1 when only var1 has a missing_value 4. Return false when neither operand has missing value */ int has_mss_val=False; /* [flg] One or both operands have missing value */ nco_bool MSS_VAL_EQL=False; /* [flg] Missing values of input operands are identical */ long idx; long var_sz=long_CEWI; nc_type var_typ=NC_NAT; /* CEWI [enm] Type of input values */ ptr_unn var_val; has_mss_val=var1->has_mss_val || var2->has_mss_val; /* No missing values */ if(!var1->has_mss_val && !var2->has_mss_val) return has_mss_val; if(var1->has_mss_val && var2->has_mss_val){ var_typ=var1->type; (void)cast_void_nctype(var_typ,&var1->mss_val); (void)cast_void_nctype(var_typ,&var2->mss_val); switch(var_typ){ case NC_FLOAT: MSS_VAL_EQL=(*var1->mss_val.fp == *var2->mss_val.fp); break; case NC_DOUBLE: MSS_VAL_EQL=(*var1->mss_val.dp == *var2->mss_val.dp); break; case NC_INT: MSS_VAL_EQL=(*var1->mss_val.ip == *var2->mss_val.ip); break; case NC_SHORT: MSS_VAL_EQL=(*var1->mss_val.sp == *var2->mss_val.sp); break; case NC_CHAR: MSS_VAL_EQL=(*var1->mss_val.cp == *var2->mss_val.cp); break; case NC_BYTE: MSS_VAL_EQL=(*var1->mss_val.bp == *var2->mss_val.bp); break; case NC_UBYTE: MSS_VAL_EQL=(*var1->mss_val.ubp == *var2->mss_val.ubp); break; case NC_USHORT: MSS_VAL_EQL=(*var1->mss_val.usp == *var2->mss_val.usp); break; case NC_UINT: MSS_VAL_EQL=(*var1->mss_val.uip == *var2->mss_val.uip); break; case NC_INT64: MSS_VAL_EQL=(*var1->mss_val.i64p == *var2->mss_val.i64p); break; case NC_UINT64: MSS_VAL_EQL=(*var1->mss_val.ui64p == *var2->mss_val.ui64p); break; case NC_STRING: MSS_VAL_EQL=(*var1->mss_val.sngp == *var2->mss_val.sngp); break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(!MSS_VAL_EQL){ /* World's most anally formatted warning message... */ char mss_val_1_sng[NCO_MAX_LEN_FMT_SNG]; char mss_val_2_sng[NCO_MAX_LEN_FMT_SNG]; const char *fmt_sng; fmt_sng=nco_typ_fmt_sng(var1->type); switch(var1->type){ case NC_FLOAT: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.fp[0]); break; case NC_DOUBLE: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.dp[0]); break; case NC_SHORT: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.sp[0]); break; case NC_INT: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.ip[0]); break; case NC_CHAR: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.cp[0]); break; case NC_BYTE: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.bp[0]); break; case NC_UBYTE: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.ubp[0]); break; case NC_USHORT: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.usp[0]); break; case NC_UINT: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.uip[0]); break; case NC_INT64: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.i64p[0]); break; case NC_UINT64: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.ui64p[0]); break; case NC_STRING: (void)sprintf(mss_val_1_sng,fmt_sng,var1->mss_val.sngp[0]); break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ fmt_sng=nco_typ_fmt_sng(var2->type); switch(var2->type){ case NC_FLOAT: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.fp[0]); break; case NC_DOUBLE: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.dp[0]); break; case NC_SHORT: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.sp[0]); break; case NC_INT: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.ip[0]); break; case NC_CHAR: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.cp[0]); break; case NC_BYTE: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.bp[0]); break; case NC_UBYTE: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.ubp[0]); break; case NC_USHORT: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.usp[0]); break; case NC_UINT: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.uip[0]); break; case NC_INT64: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.i64p[0]); break; case NC_UINT64: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.ui64p[0]); break; case NC_STRING: (void)sprintf(mss_val_2_sng,fmt_sng,var2->mss_val.sngp[0]); break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ (void)fprintf(stderr,"%s: WARNING Input variables have different NCO_MSS_VAL_SNG's:\nFile 1 variable %s has NCO_MSS_VAL_SNG type = %s, value = %s\nFile 2 variable %s has NCO_MSS_VAL_SNG type = %s, value = %s\nFile 3 variable %s will have NCO_MSS_VAL_SNG type = %s, value = %s\nWill translate values of var2 equaling mss_val2 to mss_val1 before arithmetic operation\n",nco_prg_nm_get(),var1->nm,nco_typ_sng(var1->type),mss_val_1_sng,var2->nm,nco_typ_sng(var2->type),mss_val_2_sng,var1->nm,nco_typ_sng(var1->type),mss_val_1_sng); } /* MSS_VAL_EQL */ (void)cast_nctype_void(var_typ,&var1->mss_val); (void)cast_nctype_void(var_typ,&var2->mss_val); /* Missing values are already equal */ if(MSS_VAL_EQL) return has_mss_val; /* If both files have missing_value's and they differ, must translate mss_val_2 in var2 to mss_val_1 before binary operation. Otherwise mss_val_2 would be treated as regular value in var_2 Unfixable bug is when var1 has mss_val1 and var2 does not have a missing_value Then var2 values that happen to equal mss_val1 are treated as missing_values A generic, satisfactory solution to this problem does not exist Picking missing_values that are nearly out-of-range is best workaround The user must be smart enough to do this, NCO cannot help */ /* Typecast pointer to values before access */ (void)cast_void_nctype(var_typ,&var1->mss_val); (void)cast_void_nctype(var_typ,&var2->mss_val); (void)cast_void_nctype(var_typ,&var2->val); /* Shortcuts to avoid indirection */ var_val=var2->val; var_sz=var2->sz; switch(var_typ){ case NC_FLOAT: { const float mss_val_1_flt=*var1->mss_val.fp; const float mss_val_2_flt=*var2->mss_val.fp; for(idx=0L;idxmss_val.dp; const double mss_val_2_dbl=*var2->mss_val.dp; for(idx=0L;idxmss_val.ip; const nco_int mss_val_2_ntg=*var2->mss_val.ip; for(idx=0L;idxmss_val.sp; const short mss_val_2_sht=*var2->mss_val.sp; for(idx=0L;idxmss_val.cp; const nco_char mss_val_2_chr=*var2->mss_val.cp; for(idx=0L;idxmss_val.bp; const nco_byte mss_val_2_byt=*var2->mss_val.bp; for(idx=0L;idxmss_val.ubp; const nco_ubyte mss_val_2_ubyte=*var2->mss_val.ubp; for(idx=0L;idxmss_val.usp; const nco_ushort mss_val_2_ushort=*var2->mss_val.usp; for(idx=0L;idxmss_val.uip; const nco_uint mss_val_2_uint=*var2->mss_val.uip; for(idx=0L;idxmss_val.i64p; const nco_int64 mss_val_2_int64=*var2->mss_val.i64p; for(idx=0L;idxmss_val.ui64p; const nco_uint64 mss_val_2_uint64=*var2->mss_val.ui64p; for(idx=0L;idxmss_val.sngp; const nco_string mss_val_2_string=*var2->mss_val.sngp; for(idx=0L;idxval); (void)cast_nctype_void(var_typ,&var1->mss_val); (void)cast_nctype_void(var_typ,&var2->mss_val); } /* end if both variables have missing values */ /* Handle cases where only one variable has missing value. First, if var2 has missing_value and var1 does not, then copy missing_value from var2 to var1 to ensure binary arithmetic (which uses var1's missing_value) handles missing_value's correctly Assume var1 and var2 already have same type */ if(!var1->has_mss_val && var2->has_mss_val) (void)nco_mss_val_cp(var2,var1); if(var1->has_mss_val && !var2->has_mss_val) (void)nco_mss_val_cp(var1,var2); return has_mss_val; } /* end nco_mss_val_cnf() */ void nco_mss_val_cp /* [fnc] Copy missing value from var1 to var2 */ (const var_sct * const var1, /* I [sct] Variable with template missing value to copy */ var_sct * const var2) /* I/O [sct] Variable with missing value to fill in/overwrite */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Copy missing value from var1 to var2 On exit, var2 contains has_mss_val, and mss_val identical to var1 Type of mss_val in var2 will agree with type of var2 This maintains assumed consistency between type of variable and type of mss_val in all var_sct's */ if(!var1->has_mss_val){ var2->has_mss_val=False; if(var2->mss_val.vp) free(var2->mss_val.vp); }else{ /* endif no mss_val in var1 */ var2->mss_val.vp=(void *)nco_realloc(var2->mss_val.vp,nco_typ_lng(var2->type)); (void)nco_val_cnf_typ(var1->type,var1->mss_val,var2->type,var2->mss_val); var2->has_mss_val=True; } /* endif var1 has mss_val */ } /* end nco_mss_val_cp() */ int /* O [flg] Variable has missing value on output */ nco_mss_val_get /* [fnc] Update number of attributes, missing_value of variable */ (const int nc_id, /* I [id] netCDF input-file ID */ var_sct * const var) /* I/O [sct] Variable with missing_value to update */ { /* Purpose: Update number of attributes and missing_value attribute of variable No matter what type missing_value is on disk, this routine ensures that copy of mss_val in var_sct is stored as same type as host variable. Routine does not allow output missing_value to have more than one element */ /* has_mss_val is typed as int not bool because it was sent to Fortran routines */ static nco_bool WRN_FIRST=True; /* [flg] No warnings yet for _FillValue/missing_value mismatch */ char att_nm[NC_MAX_NAME]; int idx; long att_sz; nco_bool has_fll_val=False; /* [flg] Has _FillValue attribute */ nc_type att_typ; ptr_unn mss_tmp; size_t att_lng; /* Refresh netCDF "mss_val" attribute for this variable */ var->has_mss_val=False; var->mss_val.vp=nco_free(var->mss_val.vp); /* Refresh number of attributes for variable */ (void)nco_inq_varnatts(nc_id,var->id,&var->nbr_att); for(idx=0;idxnbr_att;idx++){ (void)nco_inq_attname(nc_id,var->id,idx,att_nm); if(WRN_FIRST && !(int)strcasecmp(att_nm,nco_not_mss_val_sng_get())) has_fll_val=True; if((int)strcasecmp(att_nm,nco_mss_val_sng_get())) continue; (void)nco_inq_att(nc_id,var->id,att_nm,&att_typ,&att_sz); if(att_sz != 1L && att_typ != NC_CHAR){ (void)fprintf(stderr,"%s: WARNING the \"%s\" attribute for %s has %li elements and so will not be used\n",nco_prg_nm_get(),att_nm,var->nm,att_sz); continue; } /* end if */ /* if(att_typ != var->type) (void)fprintf(stderr,"%s: WARNING the \"%s\" attribute for %s will be typecast from %s to %s for arithmetic purposes\n",nco_prg_nm_get(),att_nm,var->nm,nco_typ_sng(att_typ),nco_typ_sng(var->type)); */ /* If we got this far then try to retrieve attribute and make sure it conforms to variable's type */ var->has_mss_val=True; /* Oddly, ARM uses NC_CHAR for type of missing_value, so make allowances for this */ att_lng=att_sz*nco_typ_lng(att_typ); mss_tmp.vp=(void *)nco_malloc(att_lng); (void)nco_get_att(nc_id,var->id,att_nm,mss_tmp.vp,att_typ); if(att_typ == NC_CHAR){ /* NUL-terminate missing value string */ if(mss_tmp.cp[att_lng-1] != '\0'){ att_lng++; mss_tmp.vp=(void *)nco_realloc(mss_tmp.vp,att_lng); mss_tmp.cp[att_lng-1]='\0'; /* Un-typecast pointer to values after access */ (void)cast_nctype_void(att_typ,&mss_tmp); } /* end if */ } /* end if */ /* Ensure mss_val in memory is stored as same type as variable */ var->mss_val.vp=(void *)nco_malloc(nco_typ_lng(var->type)); (void)nco_val_cnf_typ(att_typ,mss_tmp,var->type,var->mss_val); /* Release temporary memory */ mss_tmp.vp=nco_free(mss_tmp.vp); break; } /* end loop over att */ /* Always warn when NCO looks for _FillValue but file has missing_value, and/or always warn when NCO looks for missing_value but file has _FillValue. 20101129: This is a long warning, only print when nco_dbg_lvl > 0 */ if(nco_dbg_lvl_get() >= nco_dbg_std && has_fll_val && !var->has_mss_val && WRN_FIRST){ char sa[1000]; char sa1[1000]; char sa2[1000]; WRN_FIRST=False; (void)sprintf(sa,"%s: WARNING Variable %s has attribute \"%s\" but not \"%s\". To comply with netCDF conventions, NCO ignores values that equal the %s attribute when performing arithmetic.",nco_prg_nm_get(),var->nm,nco_not_mss_val_sng_get(), nco_mss_val_sng_get(),nco_mss_val_sng_get()); (void)sprintf(sa1," Confusingly, values equal to the missing_value should also be neglected. However, it is tedious and (possibly) computationally expensive to check each value against multiple missing values during arithmetic on large variables. So NCO thinks that processing variables with a \"%s\" attribute and no \"%s\" attribute may produce undesired arithmetic results (i.e., where values that were intended to be neglected were not, in fact, neglected).",nco_not_mss_val_sng_get(),nco_mss_val_sng_get()); (void)sprintf(sa2, " We suggest you rename all \"%s\" attributes to \"%s\" or include both \"%s\" and \"%s\" attributes (with the _same values_) for all variables that have either attribute. Because it is long, this message is only printed once per operator even though multiple variables may have the same attribute configuration. More information on missing values is given at:\nhttp://nco.sf.net/nco.html#mss_val\nExamples of renaming attributes are at:\nhttp://nco.sf.net/nco.html#xmp_ncrename\nExamples of creating and deleting attributes are at:\nhttp://nco.sf.net/nco.html#xmp_ncatted\n",nco_not_mss_val_sng_get(),nco_mss_val_sng_get(),nco_not_mss_val_sng_get(),nco_mss_val_sng_get()); (void)fprintf(stderr,"%s%s%s",sa,sa1,sa2); } /* endif missing_value is and _FillValue is not defined */ return var->has_mss_val; } /* end nco_mss_val_get() */ ./nco-4.4.2/src/nco/nco_scm.c0000644000674300045400000002135612260451232015114 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_scm.c,v 1.52 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Software configuration management */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_scm.h" /* Software configuration management */ char * /* O [sng] CVS version string */ cvs_vrs_prs(void) /* [fnc] Return CVS version string */ { /* Purpose: Return CVS version string */ nco_bool dly_snp; char *cvs_mjr_vrs_sng=NULL; char *cvs_mnr_vrs_sng=NULL; char *cvs_nm_ptr=NULL; char *cvs_nm_sng=NULL; char *cvs_pch_vrs_sng=NULL; char *cvs_vrs_sng=NULL; char *dsh_ptr=NULL; char *dlr_ptr=NULL; char *nco_sng_ptr=NULL; char *usc_1_ptr=NULL; char *usc_2_ptr=NULL; char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ /* Unexpanded cvs keywords in cvs_Name trigger GCC 4.0+ warning "./src/nco/nco_scm.c:81: warning: offset outside bounds of constant string" because routine looks for cvs_Name+7 later on */ char cvs_Name[]="$Name: nco-4_4_2 $"; const char dlr_nm_cln_spc[]="$Name: "; /* [sng] Dollar name colon space */ const char nco_sng[]="nco"; const char spc_dlr[]=" $"; /* [sng] Space dollar */ int cvs_nm_sng_len; int cvs_vrs_sng_len; int cvs_mjr_vrs_len; int cvs_mnr_vrs_len; int cvs_pch_vrs_len; int nco_sng_len; long cvs_mjr_vrs=-1L; long cvs_mnr_vrs=-1L; long cvs_pch_vrs=-1L; /* Is cvs_Name keyword expanded? */ dlr_ptr=(char *)strstr(cvs_Name,spc_dlr); if(dlr_ptr == NULL && nco_dbg_lvl_get() > 3)(void)fprintf(stderr,"%s: INFO cvs_vrs_prs() reports dlr_ptr == NULL\n%s: HINT Make sure CVS export uses -kkv\n",nco_prg_nm_get(),nco_prg_nm_get()); cvs_nm_ptr=(char *)strstr(cvs_Name,dlr_nm_cln_spc); if(cvs_nm_ptr == NULL && nco_dbg_lvl_get() > 3)(void)fprintf(stderr,"%s: INFO cvs_vrs_prs() reports cvs_nm_ptr == NULL\n%s: HINT Make sure CVS export uses -kkv\n",nco_prg_nm_get(),nco_prg_nm_get()); cvs_nm_sng_len=(int)(dlr_ptr-cvs_nm_ptr-strlen(dlr_nm_cln_spc)); /* 7 is strlen("$Name: ") */ if(cvs_nm_sng_len > 0) dly_snp=False; else dly_snp=True; if(dly_snp){ /* Presume this a daily snapshot, use YYYYMMDD date for version string */ int mth; int day; int yr; struct tm *gmt_tm; time_t time_crr_time_t; time_crr_time_t=time((time_t *)NULL); gmt_tm=gmtime(&time_crr_time_t); /* localtime() gives YYYYMMDD in e.g., PDT/MDT, but this conflicts with CVS, which uses GMT */ /* gmt_tm=localtime(&time_crr_time_t); */ mth=gmt_tm->tm_mon+1; day=gmt_tm->tm_mday; yr=gmt_tm->tm_year+1900; cvs_vrs_sng_len=4+2+2; cvs_vrs_sng=(char *)nco_malloc((size_t)cvs_vrs_sng_len+1); (void)sprintf(cvs_vrs_sng,"%04i%02i%02i",yr,mth,day); return cvs_vrs_sng; } /* endif dly_snp */ /* cvs_nm_sng is, e.g., "nco1_1" */ cvs_nm_sng=(char *)nco_malloc((size_t)cvs_nm_sng_len+1); cvs_nm_sng=strncpy(cvs_nm_sng,cvs_Name+strlen(dlr_nm_cln_spc),(size_t)cvs_nm_sng_len); /* strlen("$Name: ") = 7 */ cvs_nm_sng[cvs_nm_sng_len]='\0'; /* cvs_vrs_sng is, e.g., "1.1" */ nco_sng_len=strlen(nco_sng); nco_sng_ptr=strstr(cvs_nm_sng,nco_sng); if(nco_sng_ptr == NULL)(void)fprintf(stderr,"%s: WARNING cvs_vrs_prs() reports nco_sng_ptr == NULL\n",nco_prg_nm_get()); dsh_ptr=strstr(cvs_nm_sng,"-"); if(dsh_ptr == NULL)(void)fprintf(stderr,"%s: WARNING cvs_vrs_prs() reports dsh_ptr == NULL\n",nco_prg_nm_get()); usc_1_ptr=strstr(cvs_nm_sng,"_"); if(usc_1_ptr == NULL)(void)fprintf(stderr,"%s: WARNING cvs_vrs_prs() reports usc_1_ptr == NULL\n",nco_prg_nm_get()); cvs_mjr_vrs_len=(int)(usc_1_ptr-dsh_ptr)-1; /* NB: cast pointer to int before subtracting */ usc_2_ptr=strstr(usc_1_ptr+1,"_"); cvs_mjr_vrs_sng=(char *)nco_malloc((size_t)cvs_mjr_vrs_len+1); cvs_mjr_vrs_sng=strncpy(cvs_mjr_vrs_sng,cvs_nm_sng+nco_sng_len+1,(size_t)cvs_mjr_vrs_len); cvs_mjr_vrs_sng[cvs_mjr_vrs_len]='\0'; cvs_mjr_vrs=strtol(cvs_mjr_vrs_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(cvs_mjr_vrs_sng,"strtol",sng_cnv_rcd); if(usc_2_ptr == NULL){ cvs_mnr_vrs_len=cvs_nm_sng_len-cvs_mjr_vrs_len-1; cvs_pch_vrs_len=0; cvs_vrs_sng_len=cvs_mjr_vrs_len+1+cvs_mnr_vrs_len; }else{ cvs_mnr_vrs_len=usc_2_ptr-usc_1_ptr-1; cvs_pch_vrs_len=cvs_nm_sng_len-cvs_mjr_vrs_len-1-cvs_mnr_vrs_len-1; cvs_vrs_sng_len=cvs_mjr_vrs_len+1+cvs_mnr_vrs_len+1+cvs_pch_vrs_len; } /* end else */ cvs_mnr_vrs_sng=(char *)nco_malloc((size_t)cvs_mnr_vrs_len+1); cvs_mnr_vrs_sng=strncpy(cvs_mnr_vrs_sng,usc_1_ptr+1,(size_t)cvs_mnr_vrs_len); cvs_mnr_vrs_sng[cvs_mnr_vrs_len]='\0'; cvs_mnr_vrs=strtol(cvs_mnr_vrs_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(cvs_mnr_vrs_sng,"strtol",sng_cnv_rcd); cvs_pch_vrs_sng=(char *)nco_malloc((size_t)cvs_pch_vrs_len+1); cvs_pch_vrs_sng[cvs_pch_vrs_len]='\0'; cvs_vrs_sng=(char *)nco_malloc((size_t)cvs_vrs_sng_len+1); if(usc_2_ptr){ cvs_pch_vrs_sng=strncpy(cvs_pch_vrs_sng,usc_2_ptr+1,(size_t)cvs_pch_vrs_len); cvs_pch_vrs=strtol(cvs_pch_vrs_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(cvs_pch_vrs_sng,"strtol",sng_cnv_rcd); (void)sprintf(cvs_vrs_sng,"%li.%li.%li",cvs_mjr_vrs,cvs_mnr_vrs,cvs_pch_vrs); }else{ (void)sprintf(cvs_vrs_sng,"%li.%li",cvs_mjr_vrs,cvs_mnr_vrs); }/* end else */ if(nco_dbg_lvl_get() == 4){ (void)fprintf(stderr,"NCO version %s\n",cvs_vrs_sng); (void)fprintf(stderr,"cvs_nm_sng %s\n",cvs_nm_sng); (void)fprintf(stderr,"cvs_mjr_vrs_sng %s\n",cvs_mjr_vrs_sng); (void)fprintf(stderr,"cvs_mnr_vrs_sng %s\n",cvs_mnr_vrs_sng); (void)fprintf(stderr,"cvs_pch_vrs_sng %s\n",cvs_pch_vrs_sng); (void)fprintf(stderr,"cvs_mjr_vrs %li\n",cvs_mjr_vrs); (void)fprintf(stderr,"cvs_mnr_vrs %li\n",cvs_mnr_vrs); (void)fprintf(stderr,"cvs_pch_vrs %li\n",cvs_pch_vrs); } /* endif dbg */ cvs_mjr_vrs_sng=(char *)nco_free(cvs_mjr_vrs_sng); cvs_mnr_vrs_sng=(char *)nco_free(cvs_mnr_vrs_sng); cvs_pch_vrs_sng=(char *)nco_free(cvs_pch_vrs_sng); cvs_nm_sng=(char *)nco_free(cvs_nm_sng); return cvs_vrs_sng; } /* end cvs_vrs_prs() */ void nco_cpy_prn(void) /* [fnc] Print copyright notice */ { /* Purpose: Print copyright notice */ (void)fprintf(stderr,"Copyright (C) 1995--2014 Charlie Zender\n"); (void)fprintf(stdout,"NCO is free software and comes with a BIG FAT KISS and ABOLUTELY NO WARRANTY\nLicense: GNU General Public License (GPL) Version 3\n"); } /* end copyright_prn() */ void nco_vrs_prn /* [fnc] Print NCO version */ (const char * const CVS_Id, /* I [sng] CVS identification string */ const char * const CVS_Revision) /* I [sng] CVS revision string */ { /* Purpose: Print NCO version */ char *date_cvs; /* Date this file was last modified */ char *vrs_rcs; /* Version of this file, e.g., 1.213 */ char *vrs_cvs; /* Version according to CVS release tag */ int date_cvs_lng; int vrs_cvs_lng; const char date_cpp[]=__DATE__; /* [sng] Date from C pre-processor */ /* const char time_cpp[]=__TIME__; *//* [sng] Time from C pre-processor */ const char vrs_cpp[]=TKN2SNG(VERSION); /* [sng] Version from C pre-processor */ const char hst_cpp[]=TKN2SNG(HOSTNAME); /* [sng] Hostname from C pre-processor */ const char usr_cpp[]=TKN2SNG(USER); /* [sng] Hostname from C pre-processor */ if(strlen(CVS_Id) > strlen("*Id*")){ /* CVS_Id is defined */ date_cvs_lng=10; date_cvs=(char *)nco_malloc((date_cvs_lng+1)*sizeof(char)); (void)strncpy(date_cvs,strchr(CVS_Id,'/')-4,(size_t)date_cvs_lng); date_cvs[date_cvs_lng]='\0'; }else{ /* CVS_Id is undefined */ date_cvs=(char *)strdup("Current"); } /* endif */ if(strlen(CVS_Revision) > strlen("*Revision*") || strlen(CVS_Revision) < strlen("*Revision*")){ /* CVS_Revision is defined */ vrs_cvs_lng=strrchr(CVS_Revision,'$')-strchr(CVS_Revision,':')-3; vrs_rcs=(char *)nco_malloc((vrs_cvs_lng+1)*sizeof(char)); (void)strncpy(vrs_rcs,strchr(CVS_Revision,':')+2,(size_t)vrs_cvs_lng); vrs_rcs[vrs_cvs_lng]='\0'; }else{ /* CVS_Revision is undefined */ vrs_rcs=(char *)strdup("Current"); } /* endif */ vrs_cvs=cvs_vrs_prs(); if(strlen(CVS_Id) > strlen("*Id*")){ (void)fprintf(stderr,"NCO netCDF Operators version %s last modified %s built %s on %s by %s\n",vrs_cpp,date_cvs,date_cpp,hst_cpp,usr_cpp); }else{ (void)fprintf(stderr,"NCO netCDF Operators version %s built %s on %s by %s\n",vrs_cpp,date_cpp,hst_cpp,usr_cpp); } /* endif */ if(strlen(CVS_Id) > strlen("*Id*")){ (void)fprintf(stderr,"%s version %s\n",nco_prg_nm_get(),vrs_cvs); }else{ (void)fprintf(stderr,"%s version %s\n",nco_prg_nm_get(),vrs_cpp); } /* endif */ date_cvs=(char *)nco_free(date_cvs); vrs_rcs=(char *)nco_free(vrs_rcs); vrs_cvs=(char *)nco_free(vrs_cvs); } /* end nco_vrs_prn() */ ./nco-4.4.2/src/nco/nco_var_lst.c0000644000674300045400000017364312261451327016021 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_var_lst.c,v 1.166 2014/01/03 06:04:07 zender Exp $ */ /* Purpose: Variable list utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_var_lst.h" /* Variable list utilities */ nm_id_sct * /* O [sct] Variable extraction list */ nco_var_lst_mk /* [fnc] Create variable extraction list using regular expressions */ (const int nc_id, /* I [enm] netCDF file ID */ const int var_nbr_all, /* I [nbr] Number of variables in input file */ char * const * const var_lst_in, /* I [sng] User-specified list of variable names and rx's */ const nco_bool EXCLUDE_INPUT_LIST, /* I [flg] Exclude rather than extract */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ int * const var_xtr_nbr) /* I/O [nbr] Number of variables in current extraction list */ { /* Purpose: Create variable extraction list with or without regular expressions */ char *var_sng; /* User-specified variable name or regular expression */ char var_nm[NC_MAX_NAME]; /* [sng] Variable name */ int idx; int jdx; int var_nbr_tmp; #ifdef NCO_HAVE_REGEX_FUNCTIONALITY int rx_mch_nbr; #endif /* NCO_HAVE_REGEX_FUNCTIONALITY */ nm_id_sct *xtr_lst=NULL; /* xtr_lst may be alloc()'d from NULL with -c option */ nm_id_sct *var_lst_all=NULL; /* [sct] All variables in input file */ nco_bool *var_xtr_rqs=NULL; /* [flg] Variable specified in extraction list */ /* Create list of all variables in input file */ var_lst_all=(nm_id_sct *)nco_malloc(var_nbr_all*sizeof(nm_id_sct)); for(idx=0;idx+?|{}")){ /* ... and regular expression library is present */ #ifdef NCO_HAVE_REGEX_FUNCTIONALITY rx_mch_nbr=nco_lst_rx_search(var_nbr_all,var_lst_all,var_sng,var_xtr_rqs); if(rx_mch_nbr == 0) (void)fprintf(stdout,"%s: WARNING: Regular expression \"%s\" does not match any variables\nHINT: See regular expression syntax examples at http://nco.sf.net/nco.html#rx\n",nco_prg_nm_get(),var_sng); continue; #else /* !NCO_HAVE_REGEX_FUNCTIONALITY */ (void)fprintf(stdout,"%s: ERROR: Sorry, wildcarding (extended regular expression matches to variables) was not built into this NCO executable, so unable to compile regular expression \"%s\".\nHINT: Make sure libregex.a is on path and re-build NCO.\n",nco_prg_nm_get(),var_sng); nco_exit(EXIT_FAILURE); #endif /* !NCO_HAVE_REGEX_FUNCTIONALITY */ } /* end if regular expression */ /* Normal variable so search through variable array */ for(jdx=0;jdx= nco_dbg_var) (void)fprintf(stdout,"%s: INFO nco_var_lst_mk() reports explicitly excluded variable \"%s\" is not in input file anyway\n",nco_prg_nm_get(),var_sng); }else{ /* !EXCLUDE_INPUT_LIST */ /* Variable should be included but no matches found so die */ (void)fprintf(stdout,"%s: ERROR nco_var_lst_mk() reports user-specified variable \"%s\" is not in input file\n",nco_prg_nm_get(),var_sng); nco_exit(EXIT_FAILURE); } /* !EXCLUDE_INPUT_LIST */ } /* end else */ } /* end loop over var_lst_in */ /* Create final variable list using bool array */ /* malloc() xtr_lst to maximium size(var_nbr_all) */ xtr_lst=(nm_id_sct *)nco_malloc(var_nbr_all*sizeof(nm_id_sct)); var_nbr_tmp=0; /* var_nbr_tmp is incremented */ for(idx=0;idx 0){ dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); rcd+=nco_inq_vardimid(nc_id,xtr_lst[idx].id,dmn_id); /* netCDF3 requires record dimension to be first dimension */ if(dmn_id[0] == rec_dmn_id) flg_crr_var_rec=True; if(dmn_id) dmn_id=(int*)nco_free(dmn_id); } /* endif dmn_nbr > 0 */ if(flg_crr_var_rec){ /* Current variable is record variable */ (*rec_lst)[*rec_nbr]=xtr_lst+idx; ++*rec_nbr; }else{ /* Current variable is fixed-length */ (*fix_lst)[*fix_nbr]=xtr_lst+idx; ++*fix_nbr; } /* endif no record variable in file */ } /* end loop over variables */ *fix_lst=(nm_id_sct **)nco_realloc((void *)*fix_lst,*fix_nbr*sizeof(nm_id_sct *)); *rec_lst=(nm_id_sct **)nco_realloc((void *)*rec_lst,*rec_nbr*sizeof(nm_id_sct *)); } /* end nco_var_lst_fix_rec_dvd() */ nm_id_sct * /* O [sct] Extraction list */ nco_var_lst_crd_add /* [fnc] Add all coordinates to extraction list */ (const int nc_id, /* I [id] netCDF file ID */ const int nbr_dim, /* I [nbr] Number of dimensions in input file */ const int nbr_var, /* I [nbr] Number of variables in input file */ nm_id_sct *xtr_lst, /* I/O [sct] Current extraction list (destroyed) */ int * const xtr_nbr, /* I/O [nbr] Number of variables in current extraction list */ const nco_bool CNV_CCM_CCSM_CF) /* I [flg] file obeys CCM/CCSM/CF conventions */ { /* Purpose: Add all coordinates to extraction list Find all coordinates (dimensions which are also variables) and add them to the list if they are not already there. */ char crd_nm[NC_MAX_NAME]; int crd_id; int idx; int rcd=NC_NOERR; /* [rcd] Return code */ for(idx=0;idx 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ crd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_crd); /* ...for each coordinate in "coordinates" attribute... */ for(idx_crd=0;idx_crd= nco_dbg_var) (void)fprintf(stderr,"%s: INFO Variable %s, specified in the \"coordinates\" attribute of variable %s, is not present in the input file\n",nco_prg_nm_get(),crd_lst[idx_crd],xtr_lst[idx_var].nm); } /* end else named coordinate exists in input file */ } /* end loop over idx_crd */ /* Free allocated memory */ att_val=(char *)nco_free(att_val); crd_lst=nco_sng_lst_free(crd_lst,nbr_crd); } /* !coordinates */ } /* end loop over attributes */ } /* end loop over idx_var */ } /* !CNV_CCM_CCSM_CF for "coordinates" */ /* Detect coordinate boundaries specified by CF "bounds" convention http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.5/cf-conventions.html#cell-boundaries Algorithm copied with modification from "coordinates" algorithm above */ if(CNV_CCM_CCSM_CF){ const char dlm_sng[]=" "; /* [sng] Delimiter string */ const char fnc_nm[]="nco_var_lst_crd_add()"; /* [sng] Function name */ char **bnd_lst; /* [sng] 1D array of list elements */ char *att_val; char att_nm[NC_MAX_NAME]; int bnd_id; int idx_att; int idx_bnd; int idx_var; int idx_var2; int nbr_att; int nbr_bnd; /* [nbr] Number of coordinates specified in "bounds" attribute */ int var_id; long att_sz; nc_type att_typ; /* NB: Only difference between this algorithm and CF algorithm in nco_var_lst_crd_ass_add() is that this algorithm loops over all variables in file, not just over current extraction list. */ /* ...for each variable in file... */ for(idx_var=0;idx_var 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ bnd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_bnd); /* ...for each coordinate in "bounds" attribute... */ for(idx_bnd=0;idx_bnd= nco_dbg_var) (void)fprintf(stderr,"%s: INFO Variable %s, specified in the \"bounds\" attribute of variable %s, is not present in the input file\n",nco_prg_nm_get(),bnd_lst[idx_bnd],xtr_lst[idx_var].nm); } /* end else named coordinate exists in input file */ } /* end loop over idx_bnd */ /* Free allocated memory */ att_val=(char *)nco_free(att_val); bnd_lst=nco_sng_lst_free(bnd_lst,nbr_bnd); } /* !coordinates */ } /* end loop over attributes */ } /* end loop over idx_var */ } /* !CNV_CCM_CCSM_CF for "bounds" */ return xtr_lst; } /* end nco_var_lst_crd_add() */ nm_id_sct * /* O [sct] Extraction list */ nco_var_lst_crd_ass_add /* [fnc] Add to extraction list all coordinates associated with extracted variables */ (const int nc_id, /* I netCDF file ID */ nm_id_sct *xtr_lst, /* I/O current extraction list (destroyed) */ int * const xtr_nbr, /* I/O number of variables in current extraction list */ const nco_bool CNV_CCM_CCSM_CF) /* I [flg] file obeys CCM/CCSM/CF conventions */ { /* Purpose: Add coordinates associated with variables to extraction list */ char dmn_nm[NC_MAX_NAME]; int crd_id; int dmn_id[NC_MAX_DIMS]; int idx_dmn; int idx_var_dim; int idx_var; int nbr_dim; int nbr_var_dim; int rcd=NC_NOERR; /* [rcd] Return code */ /* Get number of dimensions */ rcd+=nco_inq(nc_id,&nbr_dim,(int *)NULL,(int *)NULL,(int *)NULL); /* 20101011: Dimension IDs in netCDF3 files will be 0..N-1 However, in netCDF4 files, dimension IDs may not enumerate consecutively Keep one code path and assume file may be netCDF4 in structure */ /* Create space for dimension IDs */ /* int dmn_id_all[NC_MAX_DIMS]; dmn_id_all=(int *)nco_malloc(nbr_dim*sizeof(int)); (void)nco_inq_dimid(nc_id,dmn_id_all); */ /* ...for each dimension in input file... */ for(idx_dmn=0;idx_dmn 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ crd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_crd); /* ...for each coordinate in "coordinates" attribute... */ for(idx_crd=0;idx_crd= nco_dbg_var) (void)fprintf(stderr,"%s: INFO Variable %s, specified in the \"coordinates\" attribute of variable %s, is not present in the input file\n",nco_prg_nm_get(),crd_lst[idx_crd],xtr_lst[idx_var].nm); } /* end else named coordinate exists in input file */ } /* end loop over idx_crd */ /* Free allocated memory */ att_val=(char *)nco_free(att_val); crd_lst=nco_sng_lst_free(crd_lst,nbr_crd); } /* !coordinates */ } /* end loop over attributes */ } /* end loop over idx_var */ } /* !CNV_CCM_CCSM_CF for "coordinates" */ /* Detect coordinate boundaries specified by CF "bounds" convention http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.5/cf-conventions.html#cell-boundaries Algorithm copied with modification from "coordinates" algorithm above */ if(CNV_CCM_CCSM_CF){ const char dlm_sng[]=" "; /* [sng] Delimiter string */ const char fnc_nm[]="nco_var_lst_crd_ass_add()"; /* [sng] Function name */ char **bnd_lst; /* [sng] 1D array of list elements */ char *att_val; char att_nm[NC_MAX_NAME]; int bnd_id; int idx_att; int idx_bnd; int idx_var2; int nbr_att; int nbr_bnd; /* [nbr] Number of coordinates specified in "bounds" attribute */ int var_id; long att_sz; nc_type att_typ; /* ...for each variable in extraction list... */ for(idx_var=0;idx_var<*xtr_nbr;idx_var++){ /* Eschew indirection */ var_id=xtr_lst[idx_var].id; /* Find number of attributes */ (void)nco_inq_varnatts(nc_id,var_id,&nbr_att); for(idx_att=0;idx_att 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ bnd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_bnd); /* ...for each coordinate in "bounds" attribute... */ for(idx_bnd=0;idx_bnd= nco_dbg_var) (void)fprintf(stderr,"%s: INFO Variable %s, specified in the \"bounds\" attribute of variable %s, is not present in the input file\n",nco_prg_nm_get(),bnd_lst[idx_bnd],xtr_lst[idx_var].nm); } /* end else named coordinate exists in input file */ } /* end loop over idx_bnd */ /* Free allocated memory */ att_val=(char *)nco_free(att_val); bnd_lst=nco_sng_lst_free(bnd_lst,nbr_bnd); } /* !coordinates */ } /* end loop over attributes */ } /* end loop over idx_var */ } /* !CNV_CCM_CCSM_CF for "bounds" */ return xtr_lst; } /* end nco_var_lst_crd_ass_add() */ nm_id_sct * /* O [sct] List with coordinate excluded */ nco_var_lst_crd_xcl /* [fnc] Exclude given coordinates from extraction list */ (const int nc_id, /* I [id] netCDF file ID */ const int dmn_id, /* I [id] Dimension ID of coordinate to remove from extraction list */ nm_id_sct *xtr_lst, /* I/O [sct] Current extraction list (destroyed) */ int * const xtr_nbr) /* I/O [nbr] Number of variables in extraction list */ { /* Purpose: Modify extraction list to exclude coordinate, if any, associated with given dimension ID */ char crd_nm[NC_MAX_NAME]; int idx; int crd_id=-1; int rcd=NC_NOERR; /* [rcd] Return code */ /* What is variable ID of record coordinate, if any? */ (void)nco_inq_dimname(nc_id,dmn_id,crd_nm); rcd=nco_inq_varid_flg(nc_id,crd_nm,&crd_id); if(rcd == NC_NOERR){ /* Is coordinate on extraction list? */ for(idx=0;idx<*xtr_nbr;idx++){ if(xtr_lst[idx].id == crd_id) break; } /* end loop over idx */ if(idx != *xtr_nbr){ nm_id_sct *var_lst_tmp; var_lst_tmp=(nm_id_sct *)nco_malloc(*xtr_nbr*sizeof(nm_id_sct)); /* Copy the extract list to the temporary extract list and reallocate the extract list */ (void)memcpy((void *)var_lst_tmp,(void *)xtr_lst,*xtr_nbr*sizeof(nm_id_sct)); (*xtr_nbr)--; xtr_lst=(nm_id_sct *)nco_realloc((void *)xtr_lst,*xtr_nbr*sizeof(nm_id_sct)); /* Collapse the temporary extract list into the permanent list by copying all but the coordinate. NB: the ordering of the list is conserved. */ (void)memcpy((void *)xtr_lst,(void *)var_lst_tmp,idx*sizeof(nm_id_sct)); (void)memcpy((void *)(xtr_lst+idx),(void *)(var_lst_tmp+idx+1),(*xtr_nbr-idx)*sizeof(nm_id_sct)); /* Free the memory for coordinate name in the extract list before losing the pointer */ var_lst_tmp[idx].nm=(char *)nco_free(var_lst_tmp[idx].nm); var_lst_tmp=(nm_id_sct *)nco_free(var_lst_tmp); } /* end if */ } /* end if */ return xtr_lst; } /* end nco_var_lst_crd_xcl() */ void nco_var_lst_convert /* [fnc] Make variable structure list from variable name ID list */ (const int nc_id, /* I [enm] netCDF file ID */ nm_id_sct *xtr_lst, /* I [sct] Current extraction list (destroyed) */ const int xtr_nbr, /* I [nbr] Number of variables in input file */ dmn_sct * const * const dim, /* I [sct] Dimensions associated with input variable list */ const int nbr_dmn_xtr, /* I [nbr] Number of dimensions in list */ var_sct *** const var_ptr, /* O [sct] Variable list (for input file) */ var_sct *** const var_out_ptr) /* O [sct] Duplicate variable list (for output file) */ { /* Purpose: Make var_sct list from nm_id list The var_sct lst is duplicated to be used for output list */ int idx; var_sct **var; var_sct **var_out; var=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); /* Fill-in variable structure list for all extracted variables */ for(idx=0;idxnm,var_2[idx_2]->nm)) { break; /* ...then search no further... */ } } /* end loop over idx_2 */ /* ...and if variable was not found in second list... */ if(idx_2 == *var_nbr_2){ (void)fprintf(stderr,"%s: ERROR %s variable \"%s\" is in file one and not in file two, i.e., the user is attempting to difference incommensurate sets of variables. %s allows the second file to have more process-able (e.g., differencable) variables than the first file, but disallows the reverse. All process-able variables in the first file must be in the second file (or manually excluded from the operation with the '-x' switch).\n",nco_prg_nm_get(),fnc_nm,var_1[idx_1]->nm,nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if variable was not found in second list */ /* ...otherwise assign variable to correct slot in output list */ var_out[idx_1]=var_2[idx_2]; } /* end loop over idx_1 */ /* Asymmetric lists */ if(*var_nbr_2 > *var_nbr_1){ if(nco_dbg_lvl_get() > nco_dbg_quiet){ const int orphan_nbr=*var_nbr_2-*var_nbr_1; int orphan_idx=0; (void)fprintf(stderr,"%s: INFO %s detects that file two contains %d more \"process-able\" (e.g., difference-able) variable%s than file one. Processable variables exclude those (often coordinates) that are intended to pass through an operator unchanged. The following variable%s present and/or process-able only in file two: ",nco_prg_nm_get(),fnc_nm,orphan_nbr,(orphan_nbr > 1) ? "s" : "",(orphan_nbr > 1) ? "s are" : " is"); for(idx_2=0;idx_2<*var_nbr_2;idx_2++){ for(idx_1=0;idx_1<*var_nbr_1;idx_1++) if(!strcmp(var_out[idx_1]->nm,var_2[idx_2]->nm)) break; /* Print name of variable in list two and not in var_out */ if(idx_1 == *var_nbr_1){ orphan_idx++; (void)fprintf(stderr,"%s%s",var_2[idx_2]->nm,(orphan_idx < orphan_nbr) ? ", " : "."); } /* end if orphan */ } /* end loop over idx_2 */ (void)fprintf(stderr," If %s in file one then this notice may be safely ignored. Otherwise, %s will do no harm and will not appear in the output file.\n",(orphan_nbr > 1) ? "these variables are all scalar averages of the coordinate variables with the same names" : "this variable is a scalar-average of the coordinate variable with the same name",(orphan_nbr > 1) ? "these variables appear to be orphans. They" : "this variable appears to be an orphan. It"); } /* endif dbg */ *var_nbr_2=*var_nbr_1; } /* end if asymmetric and debug */ /* Free un-merged list before overwriting with merged list */ var_2=(var_sct **)nco_free(var_2); *var_2_ptr=(var_sct **)nco_realloc(var_out,*var_nbr_2*sizeof(var_sct *)); return rcd; } /* end nco_var_lst_mrg() */ void nco_var_lst_dvd /* [fnc] Divide input lists into output lists */ (var_sct * const * const var, /* I [sct] Variable list (input file) */ var_sct * const * const var_out, /* I [sct] Variable list (output file) */ const int nbr_var, /* I [nbr] Number of variables */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ var_sct *** const var_fix_ptr, /* O [sct] Fixed-variables (input file) */ var_sct *** const var_fix_out_ptr, /* O [sct] Fixed-variables (output file) */ int * const nbr_var_fix, /* O [nbr] Number of fixed variables */ var_sct *** const var_prc_ptr, /* O [sct] Processed-variables (input file) */ var_sct *** const var_prc_out_ptr, /* O [sct] Processed-variables (output file) */ int * const nbr_var_prc, /* O [nbr] Number of processed variables */ const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { /* Purpose: Divide two input lists into output lists based on program type */ char *var_nm=NULL_CEWI; int idx; int nco_prg_id; /* Program key */ int idx_dmn; int idx_xcl; int var_op_typ[NC_MAX_VARS]; nco_bool is_sz_rnk_prv_rth_opr; /* [flg] Size- and rank-preserving operator */ nco_bool var_typ_fnk=False; /* [flg] Variable type is too funky for arithmetic */ /* CEWI */ nc_type var_typ=NC_NAT; /* NC_NAT present in netcdf.h version netCDF 3.5+ */ var_sct **var_fix; var_sct **var_fix_out; var_sct **var_prc; var_sct **var_prc_out; trv_sct *var_trv; /* [sct] GTT variable */ nco_prg_id=nco_prg_id_get(); /* Program key */ /* Allocate space for too many structures first then realloc() appropriately It is calling function's responsibility to free() this memory */ var_fix=(var_sct **)nco_malloc(NC_MAX_VARS*sizeof(var_sct *)); var_fix_out=(var_sct **)nco_malloc(NC_MAX_VARS*sizeof(var_sct *)); var_prc=(var_sct **)nco_malloc(NC_MAX_VARS*sizeof(var_sct *)); var_prc_out=(var_sct **)nco_malloc(NC_MAX_VARS*sizeof(var_sct *)); is_sz_rnk_prv_rth_opr=nco_is_sz_rnk_prv_rth_opr(nco_prg_id,nco_pck_plc); /* Find operation type for each variable: for now this is either fix or prc */ for(idx=0;idxnm; var_typ=var[idx]->type; /* Until 20131005, NCO default was to consider NC_BYTE and NC_UBYTE as funky, too */ if((var_typ == NC_CHAR) || (var_typ == NC_STRING)) var_typ_fnk=True; else var_typ_fnk=False; /* Many operators should not process coordinate variables, or auxiliary coordinate variables (lat, lon, time, latixy, longxy, ...) and bounds (lat_bnds, lon_bnds, ...) 20130112: As of today set is_crd_var true in nco_var_fll() when either of these conditions is true so no longer need to specify these conditions separately. Keep this old code here as a reminder that is_crd_var also incorporates these conditions is_spc_in_crd_att=nco_is_spc_in_crd_att(var[idx]->nc_id,var[idx]->id); is_spc_in_bnd_att=nco_is_spc_in_bnd_att(var[idx]->nc_id,var[idx]->id); */ /* Override operation type depending on variable properties and program */ switch(nco_prg_id){ case ncap: var_op_typ[idx]=fix_typ; break; case ncatted: /* Do nothing */ break; case ncbo: if(var[idx]->is_crd_var || var_typ_fnk) var_op_typ[idx]=fix_typ; break; case ncfe: if(var[idx]->is_crd_var || var_typ_fnk) var_op_typ[idx]=fix_typ; break; case ncecat: /* Allow ncecat to concatenate funky variables */ if(var[idx]->is_crd_var) var_op_typ[idx]=fix_typ; break; case ncflint: /* Allow ncflint to interpolate record coordinates, not fixed coordinates ... */ if((var[idx]->is_crd_var || var_typ_fnk) && !var[idx]->is_rec_var) var_op_typ[idx]=fix_typ; /* ...unless the --fix_rec_crd switch was used to fix record coordinates as well ... */ if((var[idx]->is_crd_var && var[idx]->is_rec_var && FIX_REC_CRD)) var_op_typ[idx]=fix_typ; break; case ncks: /* Do nothing */ break; case ncra: if(!var[idx]->is_rec_var) var_op_typ[idx]=fix_typ; break; case ncge: /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var[idx]->nm_fll,trv_tbl); /* If variable is template, mark as processed */ if(var_trv->flg_nsm_tpl && var_trv->nco_typ == nco_obj_typ_var){ assert(var_trv->flg_nsm_mbr == True); var_op_typ[idx]=prc_typ; } break; case ncrcat: if(!var[idx]->is_rec_var) var_op_typ[idx]=fix_typ; break; case ncpdq: case ncwa: if(nco_pck_plc != nco_pck_plc_nil){ /* Packing operation requested Variables are processed for packing/unpacking operator unless... */ if( /* ...packing coordinate variables has few benefits... */ (var[idx]->is_crd_var && !(nco_pck_plc == nco_pck_plc_upk) ) || /* unless if it's NOT a record variable and the policy is unpack 20120711. nco: ncpdq unpack coordinate variables */ /* ...unpacking requested for unpacked variable... */ (nco_pck_plc == nco_pck_plc_upk && !var[idx]->pck_ram) || /* ...or packing unpacked requested and variable is already packed... */ (nco_pck_plc == nco_pck_plc_all_xst_att && var[idx]->pck_ram) || /* ...or re-packing packed requested and variable is unpacked... */ (nco_pck_plc == nco_pck_plc_xst_new_att && !var[idx]->pck_ram) || /* ...or... */ ( /* ...any type of packing requested... */ (nco_pck_plc == nco_pck_plc_all_new_att || nco_pck_plc == nco_pck_plc_all_xst_att || nco_pck_plc == nco_pck_plc_xst_new_att) && /* ...yet map does not allow (re-)packing... */ !nco_pck_plc_typ_get(nco_pck_map,var[idx]->typ_upk,(nc_type *)NULL) ) ) var_op_typ[idx]=fix_typ; }else{ /* endif packing operation requested */ /* Process every variable containing an altered (averaged, re-ordered, reversed) dimension */ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ for(idx_xcl=0;idx_xcldim[idx_dmn]->id == dmn_xcl[idx_xcl]->id) break; } /* end loop over idx_xcl */ if(idx_xcl != nbr_dmn_xcl){ var_op_typ[idx]=prc_typ; break; } /* end if */ } /* end loop over idx_dmn */ /* Fix variables with no altered (averaged, re-ordered, reversed) dimensions */ if(idx_dmn == var[idx]->nbr_dim) var_op_typ[idx]=fix_typ; } /* endif averaging or re-ordering */ break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ /* Previous case-statement does not account for variables with no data */ if(nco_is_rth_opr(nco_prg_id)) if(var[idx]->sz == 0L) var_op_typ[idx]=fix_typ; if(CNV_CCM_CCSM_CF){ if(!strcmp(var_nm,"ntrm") || !strcmp(var_nm,"ntrn") || !strcmp(var_nm,"ntrk") || !strcmp(var_nm,"ndbase") || !strcmp(var_nm,"nsbase") || !strcmp(var_nm,"nbdate") || !strcmp(var_nm,"nbsec") || !strcmp(var_nm,"mdt") || !strcmp(var_nm,"mhisf")) var_op_typ[idx]=fix_typ; /* NB: all !strcmp()'s except "msk_" which uses strstr() */ if(is_sz_rnk_prv_rth_opr && (!strcmp(var_nm,"hyam") || !strcmp(var_nm,"hybm") || !strcmp(var_nm,"hyai") || !strcmp(var_nm,"hybi") || !strcmp(var_nm,"gw") || !strcmp(var_nm,"lon_bnds") || !strcmp(var_nm,"lat_bnds") || !strcmp(var_nm,"area") || !strcmp(var_nm,"ORO") || !strcmp(var_nm,"date") || !strcmp(var_nm,"datesec") || (strstr(var_nm,"msk_") == var_nm))) var_op_typ[idx]=fix_typ; /* Known "multi-dimensional coordinates" in CCSM-like model output: lat, lon, lev are normally 1-D coordinates Known exceptions: lat and lon are "2-D coordinates" in NARCCAP output NARCCAP specifies lat and lon in "coordinates" attribute of 2-D fields latixy and longxy are "2-D coordinates" in CLM output CLM does not specify latixy and longxy in "coordinates" attribute of any fields NARCCAP output gives all "coordinate-like" fields an "axis" attribute This includes the record coordinate (i.e., "time") which both ncra and ncwa _should_ process CLM does not give an "axis" attribute to any fields One method of chasing down all "coordinate-like" fields is to look for the field name in the "coordinates" attribute of any variable. However, this will miss (false-negative) the case when no variables use an N-D coordinate-like variable as a coordinate. And this may hit (false-positive) the record coordinate (often "time") which should be averaged by ncra, though perhaps not by nces. "coordinate-like" variables that should be "fixed", and not differenced, interpolated, or ensemble-averaged, include those satisfying these conditions: 0. Traditional coordinate (1-D variable same name as its dimension) 1. Present in a "coordinates" attribute (except "time" for ncra) 2. Present in a "bounds" attribute (except "time_bnds" for ncra) 3. Contain an "axis" attribute (except "time") fxm not done yet 4. Found in empirical list of variables NB: In the above algorithm discussion, "time" is my shorthand for "the record variable, if any" */ /* Conditions #1 and #2 are already implemented above in the case() statement */ /* Check condition #4 above: */ if(is_sz_rnk_prv_rth_opr && (!strcmp(var_nm,"lat") || !strcmp(var_nm,"lon") || !strcmp(var_nm,"lev") || !strcmp(var_nm,"longxy") || !strcmp(var_nm,"latixy") )) var_op_typ[idx]=fix_typ; } /* end if CNV_CCM_CCSM_CF */ /* Warn about any expected weird behavior */ if(var_op_typ[idx] == prc_typ){ if(var_typ_fnk && ((nco_prg_id != ncecat) && (nco_prg_id != ncpdq) && (nco_prg_id != ncrcat))){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Variable %s is of type %s, for which requested processing (i.e., averaging, differencing) is ill-defined\n",nco_prg_nm_get(),var[idx]->nm,nco_typ_sng(var[idx]->type)); } /* end if */ } /* end if prc */ } /* end loop over var */ /* Assign list pointers based on operation type for each variable */ *nbr_var_prc=*nbr_var_fix=0; for(idx=0;idxis_fix_var=var_out[idx]->is_fix_var=True; var_fix[*nbr_var_fix]=var[idx]; var_fix_out[*nbr_var_fix]=var_out[idx]; ++*nbr_var_fix; }else{ var[idx]->is_fix_var=var_out[idx]->is_fix_var=False; var_prc[*nbr_var_prc]=var[idx]; var_prc_out[*nbr_var_prc]=var_out[idx]; ++*nbr_var_prc; } /* end else */ } /* end loop over var */ /* Sanity check */ if(*nbr_var_prc+*nbr_var_fix != nbr_var){ (void)fprintf(stdout,"%s: ERROR nbr_var_prc+nbr_var_fix != nbr_var\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ /* fxm: Remove ncap exception when finished with ncap list processing */ /* fxm: ncpdq processes all variables when packing requested */ if(*nbr_var_prc == 0 && nco_prg_id != ncap && nco_prg_id != ncpdq && nco_prg_id != ncge){ (void)fprintf(stdout,"%s: ERROR no variables fit criteria for processing\n",nco_prg_nm_get()); switch(nco_prg_id){ case ncap: (void)fprintf(stdout,"%s: HINT Extraction list must contain at least one derived field\n",nco_prg_nm_get()); case ncatted: /* Do nothing */ break; case ncbo: (void)fprintf(stdout,"%s: HINT Extraction list must contain a non-coordinate variable that is not NC_CHAR or NC_STRING in order to perform a binary operation (e.g., subtraction)\n",nco_prg_nm_get()); break; case ncfe: (void)fprintf(stdout,"%s: HINT Extraction list must contain a non-coordinate variable that is not NC_CHAR or NC_STRING\n",nco_prg_nm_get()); break; case ncecat: (void)fprintf(stdout,"%s: HINT Extraction list must contain a non-coordinate variable\n",nco_prg_nm_get()); break; case ncflint: (void)fprintf(stdout,"%s: HINT Extraction list must contain a variable that is not NC_CHAR or NC_STRING\n",nco_prg_nm_get()); break; case ncks: /* Do nothing */ break; case ncpdq: (void)fprintf(stdout,"%s: HINT Extraction list must contain a variable that shares at least one dimension with the re-order list\n",nco_prg_nm_get()); break; case ncra: (void)fprintf(stdout,"%s: HINT Extraction list must contain a record variable that is not NC_CHAR or NC_STRING\n",nco_prg_nm_get()); break; case ncrcat: (void)fprintf(stdout,"%s: HINT Extraction list must contain a record variable which to concatenate\n",nco_prg_nm_get()); break; case ncwa: (void)fprintf(stdout,"%s: HINT Extraction list must contain a variable that contains an averaging dimension\n",nco_prg_nm_get()); break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ nco_exit(EXIT_FAILURE); } /* end if */ /* Free unused space and save pointers in output variables */ *var_fix_ptr=(var_sct **)nco_realloc(var_fix,*nbr_var_fix*sizeof(var_sct *)); *var_fix_out_ptr=(var_sct **)nco_realloc(var_fix_out,*nbr_var_fix*sizeof(var_sct *)); *var_prc_ptr=(var_sct **)nco_realloc(var_prc,*nbr_var_prc*sizeof(var_sct *)); *var_prc_out_ptr=(var_sct **)nco_realloc(var_prc_out,*nbr_var_prc*sizeof(var_sct *)); } /* end nco_var_lst_dvd */ void nco_var_lst_dvd_trv /* [fnc] Divide input lists into output lists (ncbo only) */ (var_sct * const var, /* I [sct] Variable list (input file) */ var_sct * const var_out, /* I [sct] Variable list (output file) */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ prc_typ_enm *prc) /* O [enm] Processing type */ { /* Purpose: Divide two input lists into output lists based on program type */ char *var_nm=NULL_CEWI; int nco_prg_id; /* [enm] Program key */ int idx_dmn; int idx_xcl; prc_typ_enm var_op_typ; nco_bool is_sz_rnk_prv_rth_opr; /* [flg] Size- and rank-preserving operator */ nco_bool var_typ_fnk=False; /* [flg] Variable type is too funky for arithmetic */ nc_type var_typ=NC_NAT; /* NC_NAT present in netcdf.h version netCDF 3.5+ */ nco_prg_id=nco_prg_id_get(); is_sz_rnk_prv_rth_opr=nco_is_sz_rnk_prv_rth_opr(nco_prg_id,nco_pck_plc); /* Initialize operation type to processed. Change to fixed where warranted later. */ var_op_typ=prc_typ; var_nm=var->nm; var_typ=var->type; /* Until 20131005, NCO default was to consider NC_BYTE and NC_UBYTE as funky, too */ if((var_typ == NC_CHAR) || (var_typ == NC_STRING)) var_typ_fnk=True; else var_typ_fnk=False; /* Many operators should not process coordinate variables, or auxiliary coordinate variables (lat, lon, time, latixy, longxy, ...) and bounds (lat_bnds, lon_bnds, ...) 20130112: As of today set is_crd_var true in nco_var_fll() when either of these conditions is true so no longer need to specify these conditions separately. Keep this old code here as a reminder that is_crd_var also incorporates these conditions is_spc_in_crd_att=nco_is_spc_in_crd_att(var[idx]->nc_id,var[idx]->id); is_spc_in_bnd_att=nco_is_spc_in_bnd_att(var[idx]->nc_id,var[idx]->id); */ /* Override operation type based depending on variable properties and program */ switch(nco_prg_id){ case ncap: var_op_typ=fix_typ; break; case ncatted: /* Do nothing */ break; case ncbo: if(var->is_crd_var || var_typ_fnk) var_op_typ=fix_typ; break; case ncfe: if(var->is_crd_var || var_typ_fnk) var_op_typ=fix_typ; break; case ncecat: /* Allow ncecat to concatenate funky variables */ if(var->is_crd_var) var_op_typ=fix_typ; break; case ncflint: /* Allow ncflint to interpolate record coordinates, not fixed coordinates ... */ if((var->is_crd_var || var_typ_fnk) && !var->is_rec_var) var_op_typ=fix_typ; /* ...unless the --fix_rec_crd switch was used to fix record coordinates as well ... */ if((var->is_crd_var && var->is_rec_var && FIX_REC_CRD)) var_op_typ=fix_typ; break; case ncks: /* Do nothing */ break; case ncra: if(!var->is_rec_var) var_op_typ=fix_typ; break; case ncrcat: if(!var->is_rec_var) var_op_typ=fix_typ; break; case ncpdq: case ncwa: if(nco_pck_plc != nco_pck_plc_nil){ /* Packing operation requested Variables are processed for packing/unpacking operator unless... */ if( /* ...packing coordinate variables has few benefits... */ (var->is_crd_var && !(nco_pck_plc == nco_pck_plc_upk) ) || /* unless if it's NOT a record variable and the policy is unpack 20120711. nco: ncpdq unpack coordinate variables */ /* ...unpacking requested for unpacked variable... */ (nco_pck_plc == nco_pck_plc_upk && !var->pck_ram) || /* ...or packing unpacked requested and variable is already packed... */ (nco_pck_plc == nco_pck_plc_all_xst_att && var->pck_ram) || /* ...or re-packing packed requested and variable is unpacked... */ (nco_pck_plc == nco_pck_plc_xst_new_att && !var->pck_ram) || /* ...or... */ ( /* ...any type of packing requested... */ (nco_pck_plc == nco_pck_plc_all_new_att || nco_pck_plc == nco_pck_plc_all_xst_att || nco_pck_plc == nco_pck_plc_xst_new_att) && /* ...yet map does not allow (re-)packing... */ !nco_pck_plc_typ_get(nco_pck_map,var->typ_upk,(nc_type *)NULL) ) ) var_op_typ=fix_typ; }else{ /* endif packing operation requested */ /* Process every variable containing an altered (averaged, re-ordered, reversed) dimension */ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ for(idx_xcl=0;idx_xcldim[idx_dmn]->id == dmn_xcl[idx_xcl]->id){ break; } } /* end loop over idx_xcl */ if(idx_xcl != nbr_dmn_xcl){ var_op_typ=prc_typ; break; } /* end if */ } /* end loop over idx_dmn */ /* Fix variables with no altered (averaged, re-ordered, reversed) dimensions */ if(idx_dmn == var->nbr_dim) var_op_typ=fix_typ; } /* endif averaging or re-ordering */ break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ /* Previous case-statement does not account for variables with no data */ if(nco_is_rth_opr(nco_prg_id)) if(var->sz == 0L) var_op_typ=fix_typ; if(CNV_CCM_CCSM_CF){ if(!strcmp(var_nm,"ntrm") || !strcmp(var_nm,"ntrn") || !strcmp(var_nm,"ntrk") || !strcmp(var_nm,"ndbase") || !strcmp(var_nm,"nsbase") || !strcmp(var_nm,"nbdate") || !strcmp(var_nm,"nbsec") || !strcmp(var_nm,"mdt") || !strcmp(var_nm,"mhisf")) var_op_typ=fix_typ; /* NB: all !strcmp()'s except "msk_" which uses strstr() */ if(is_sz_rnk_prv_rth_opr && (!strcmp(var_nm,"hyam") || !strcmp(var_nm,"hybm") || !strcmp(var_nm,"hyai") || !strcmp(var_nm,"hybi") || !strcmp(var_nm,"gw") || !strcmp(var_nm,"lon_bnds") || !strcmp(var_nm,"lat_bnds") || !strcmp(var_nm,"area") || !strcmp(var_nm,"ORO") || !strcmp(var_nm,"date") || !strcmp(var_nm,"datesec") || (strstr(var_nm,"msk_") == var_nm))) var_op_typ=fix_typ; /* Known "multi-dimensional coordinates" in CCSM-like model output: lat, lon, lev are normally 1-D coordinates Known exceptions: lat and lon are "2-D coordinates" in NARCCAP output NARCCAP specifies lat and lon in "coordinates" attribute of 2-D fields latixy and longxy are "2-D coordinates" in CLM output CLM does not specify latixy and longxy in "coordinates" attribute of any fields NARCCAP output gives all "coordinate-like" fields an "axis" attribute This includes the record coordinate (i.e., "time") which both ncra and ncwa _should_ process CLM does not give an "axis" attribute to any fields One method of chasing down all "coordinate-like" fields is to look for the field name in the "coordinates" attribute of any variable. However, this will miss (false-negative) the case when no variables use an N-D coordinate-like variable as a coordinate. And this may hit (false-positive) the record coordinate (often "time") which should be averaged by ncra, though perhaps not by nces. "coordinate-like" variables that should be "fixed", and not differenced, interpolated, or ensemble-averaged, include those satisfying these conditions: 0. Traditional coordinate (1-D variable same name as its dimension) 1. Present in a "coordinates" attribute (except "time" for ncra) 2. Present in a "bounds" attribute (except "time_bnds" for ncra) 3. Contain an "axis" attribute (except "time") fxm not done yet 4. Found in empirical list of variables NB: In the above algorithm discussion, "time" is my shorthand for "the record variable, if any" */ /* Conditions #1 and #2 are already implemented above in the case() statement */ /* Check condition #4 above: */ if(is_sz_rnk_prv_rth_opr && (!strcmp(var_nm,"lat") || !strcmp(var_nm,"lon") || !strcmp(var_nm,"lev") || !strcmp(var_nm,"longxy") || !strcmp(var_nm,"latixy") )) var_op_typ=fix_typ; } /* end if CNV_CCM_CCSM_CF */ /* Warn about any expected weird behavior */ if(var_op_typ == prc_typ){ if(var_typ_fnk && ((nco_prg_id != ncecat) && (nco_prg_id != ncpdq) && (nco_prg_id != ncrcat))){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Variable %s is of type %s, for which requested processing (i.e., averaging, differencing) is ill-defined\n",nco_prg_nm_get(),var->nm,nco_typ_sng(var->type)); } /* end if */ } /* end if prc */ if(var_op_typ == fix_typ){ var->is_fix_var=True; var_out->is_fix_var=True; }else{ var_out->is_fix_var=False; var->is_fix_var=False; } /* Export */ *prc=var_op_typ; } /* end nco_var_lst_dvd_trv */ ./nco-4.4.2/src/nco/nco_netcdf.c0000644000674300045400000027574212301166555015616 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_netcdf.c,v 1.234 2014/02/19 17:44:13 zender Exp $ */ /* Purpose: NCO wrappers for netCDF C library */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Utility routines not defined by netCDF library, but useful in working with it */ void nco_err_exit /* [fnc] Print netCDF error message, routine name, then exit */ (const int rcd, /* I [enm] netCDF error code */ const char * const msg) /* I [sng] Supplemental error message */ { /* Purpose: Print netCDF error message, routine name, then exit(EXIT_FAILURE) or abort() Routine is called by all wrappers when fatal error is encountered Goal is to have all NCO error exits to go through nco_err_exit() This provides uniform handling of exit() status and abort() option Successful NCO exits should call nco_exit() not nco_err_exit() msg variable allows wrapper to pass more descriptive information than is contained in the netCDF-defined error message. Use msg to print, e.g., name of variable or routine which caused error */ const char fnc_nm[]="nco_err_exit()"; #ifdef NCO_ABORT_ON_ERROR const char exit_fnc_nm[]="abort()"; #else /* !NCO_ABORT_ON_ERROR */ const char exit_fnc_nm[]="exit(EXIT_FAILURE)"; #endif /* !NCO_ABORT_ON_ERROR */ switch(rcd){ case NC_EBADTYPE: (void)fprintf(stdout,"ERROR NC_BADTYPE Not a netCDF data type\nHINT: NC_EBADTYPE errors can occur when NCO tries to write netCDF4 features to a netCDF3 file. Features that cannot be defined in a netCDF3 file, and that thus will trigger this error, include groups and netCDF4 atomic types (e.g., NC_STRING, NC_UBYTE). The workaround is to remove all netCDF4 features before attempting the conversion, or to just give up and write a netCDF4 output file instead of a netCDF3 output file.\n"); break; case NC_ECANTWRITE: (void)fprintf(stdout,"ERROR NC_ECANTWRITE Can't write file\nHINT: NC_ECANTWRITE errors can occur when NCO tries to write to an HDF5 file that is not netCDF4-compliant. One workaround is translate the file to a netCDF4-compliant file first, e.g., with \'ncks in.h5 out.nc\'.\n"); break; case NC_EINVAL: (void)fprintf(stdout,"ERROR NC_EINVAL Invalid argument\nHINT: NC_EINVAL errors can occur for many reasons. Three common ones are described here. 1. When NCO operators attempt to open netCDF4 files using the diskless option, usually invoked with --diskless_all, --ram_all, or --open_ram. Is your input file netCDF4 format? (http://nco.sf.net/nco.html#fmt_inq shows how to tell.) If so then omitting the diskless option may solve this problem. 2. When HDF4-enabled NCO attempts to directly write to an HDF4 file. The way that the operators ncrename and ncatted are formulated causes them to trigger this problem. We are working to solve this (fxm TODO nco1104). Please let us know if it affects you. For now the workaround is to convert the HDF4 file to netCDF4 first, then use ncrename or ncatted. 3. When invalid chunking directives are given, e.g., to unchunk a record variable or to chunk a variable with an invalid size (such as zero or larger than a fixed dimension)\n"); break; case NC_ELATEFILL: /* netcdf.h replaced NC_EFILLVALUE by NC_ELATEFILL after about netCDF ~4.2.1 */ (void)fprintf(stdout,"ERROR NC_ELATEFILL (formerly NC_EFILLVALUE) Attempt to define fill value when data already exists\nHINT: NC_ELATEFILL errors can occur when ncap2 attempts to define a variable with a _FillValue attribute in a netCDF4 file. We believe this is an NCO bug (fxm TODO nco1089) and are working to fix it. Does your output file need to be netCDF4 or netCDF4_classic format? If so, then wait for us to fix the bug. If not, change the output format to netCDF3 (e.g., with -3 option) as a temporary workaround. This file can then successfully be converted to netCDF4 (e.g., with ncks -4 in.nc out.nc).\n"); break; #ifdef ENABLE_NETCDF4 case NC_ENOTBUILT: (void)fprintf(stdout,"ERROR NC_ENOTBUILT Attempt to use feature that was not turned on when netCDF was built\nHINT: NC_ENOTBUILT errors occur only, in our experience, when NCO attempts to access an HDF4 (including HDF-EOS2) file. It is only possible to access HDF4 files from NCO if NCO is first re-linked to a version of netCDF configured with the --enable-hdf4 option, which itself must be linked to a version of HDF4 configured with the --disable-netcdf option. These are non-standard build options! Full instructions are here: http://www.unidata.ucar.edu/software/netcdf/docs/build_hdf4.html\nFollow those instructions to rebuild HDF4 and netCDF, then rebuild NCO on top of that netCDF, and then your NCO command will likely work.\n"); #endif /* !ENABLE_NETCDF4 */ case NC_ENOTNC: (void)fprintf(stdout,"ERROR NC_ENOTNC Not a netCDF file\nHINT: NC_ENOTNC errors can occur for many reasons. If your use case matches one of the four listed below, take the corrective action indicated:\n1. An NCO operator linked to the netCDF3 library attempts to read netCDF4 files. "); #ifdef ENABLE_NETCDF4 (void)fprintf(stdout," However, this executable seems to have been built with the capability to manipulate netCDF4 files, so it is unlikely that this command failed only because the input datasets are netCDF4 format. Something else is going wrong. \n"); #else /* !ENABLE_NETCDF4 */ (void)fprintf(stdout,"Are your input files netCDF4 format? (http://nco.sf.net/nco.html#fmt_inq shows how to tell.) If so then installing or re-building a netCDF4-compatible version of NCO should solve this problem. First upgrade netCDF to version 4.x, then install NCO using those netCDF 4.x libraries.\n2. NC_ENOTNC can occur when users attempt to utilize diskless (i.e., RAM) files. In this case remove the diskless switches (e.g., --ram or --diskless) and then re-issue the command. \n"); #endif /* !ENABLE_NETCDF4 */ (void)fprintf(stdout,"2. NCO attempts to utilize diskless (i.e., RAM) files. In this case remove the diskless switches (e.g., --ram or --diskless) and then re-issue the command.\n3. NCO attempts to read other non-supported filetypes, e.g., HDF4, HDF-EOS2. In this case it may be possible to access the input files using NCO if NCO is first re-linked to a version of netCDF configured with the --enable-hdf4 option. This is a non-standard netCDF build option described here: http://www.unidata.ucar.edu/software/netcdf/docs/build_hdf4.html\n4. Access to a DAP URL fails, and the backup method of downloading the URL using wget obtains a data aggregation file (e.g., a .ncml file) instead of an actual netCDF file. In this case the problem is with the DAP server or URL.\n"); break; case NC_ERANGE: (void)fprintf(stdout,"ERROR NC_ERANGE Result not representable in output file\nHINT: NC_ERANGE errors typically occur after an arithmetic operation results in a value not representible by the output variable type when NCO attempts to write those values to an output file. Possible workaround: Promote the variable to higher precision before attempting arithmetic. For example,\nncap2 -O -s \'foo=double(foo);\' in.nc in.nc\nFor more details, see http://nco.sf.net/nco.html#typ_cnv\n"); break; case NC_EUNLIMIT: (void)fprintf(stdout,"ERROR NC_UNLIMIT NC_UNLIMITED size already in use\nHINT: NC_EUNLIMIT errors can occur when attempting to convert netCDF4 classic files that contain multiple record dimensions into a netCDF3 file that allows only one record dimension. In this case, try first fixing the excess record dimension(s) (with, e.g., ncks --fix_rec_dmn) and then convert to netCDF3. For more details, see http://nco.sf.net/nco.html#fix_rec_dmn\n"); break; case NC_EVARSIZE: (void)fprintf(stdout,"ERROR NC_EVARSIZE One or more variable sizes violate format constraints\nHINT: NC_EVARSIZE errors can occur when attempting to aggregate netCDF3 classic files together into outputs that exceed the capacity of the netCDF3 classic file format, e.g., a variable with size in excess of 2^31 bytes. In this case, try altering the output file type to netCDF3 classic with 64-bit offsets (with --64) or to netCDF4 (with -4). For more details, see http://nco.sf.net/nco.html#fl_fmt\n"); break; } /* end switch */ /* Print NCO-generated error message, if any */ if(msg) (void)fprintf(stderr,"%s: ERROR Short NCO-generated message (usually name of function that triggered error): %s\n",fnc_nm,msg); /* On occasion, routine is called with non-netCDF errors, e.g., by nco_dfl_case_nc_type_err() non-netCDF errors call nco_err_exit() with rcd == 0 Only attempt to print netCDF error messages when rcd != 0 */ (void)fprintf(stderr,"%s: ERROR Error code is %d. ",fnc_nm,rcd); if(rcd == NC_NOERR){ (void)fprintf(stderr,"This indicates an error occurred outside of the netCDF layer, i.e., in NCO code or in a system call.\n"); }else{ (void)fprintf(stderr,"Translation into English with nc_strerror(%d) is \"%s\"\n",rcd,nc_strerror(rcd)); } /* !NC_NOERR */ (void)fprintf(stdout,"%s: ERROR NCO will now exit with system call %s\n",fnc_nm,exit_fnc_nm); #ifdef NCO_ABORT_ON_ERROR /* abort() produces core dump and traceback information Most debuggers (e.g., gdb) use this information to print the calling tree that produced the abort() This makes debugging much easier. Hence we recommend developers compile NCO with -DNCO_ABORT_ON_ERROR */ abort(); #else /* !NCO_ABORT_ON_ERROR */ /* exit() produces no core dump or useful debugger information It is slightly more friendly to the end-user since it does not leave core files laying around Hence we recommend installing NCO without -DNCO_ABORT_ON_ERROR for end users */ exit(EXIT_FAILURE); #endif /* !NCO_ABORT_ON_ERROR */ } /* end nco_err_exit() */ size_t /* O [B] Native type size */ nco_typ_lng /* [fnc] Convert netCDF type enum to native type size */ (const nc_type nco_typ) /* I [enm] netCDF type */ { /* Purpose: Return native size of specified netCDF type Routine is used to determine memory required to store variables in RAM This is only routine in nco_netcdf which needs NCO opaque type definitions nco_byte, nco_char, and nco_int defined in nco_typ.h */ switch(nco_typ){ case NC_FLOAT: return sizeof(float); case NC_DOUBLE: return sizeof(double); case NC_INT: return sizeof(nco_int); case NC_SHORT: return sizeof(short int); case NC_CHAR: return sizeof(nco_char); case NC_BYTE: return sizeof(nco_byte); case NC_UBYTE: return sizeof(nco_ubyte); case NC_USHORT: return sizeof(nco_ushort); case NC_UINT: return sizeof(nco_uint); case NC_INT64: return sizeof(nco_int64); case NC_UINT64: return sizeof(nco_uint64); case NC_STRING: return sizeof(nco_string); default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return 0; } /* end nco_typ_lng() */ const char * /* O [sng] String describing type */ nco_typ_sng /* [fnc] Convert netCDF type enum to string */ (const nc_type type) /* I [enm] netCDF type */ { if(type >= NC_FIRSTUSERTYPEID) return "User-defined"; switch(type){ case NC_FLOAT: return "NC_FLOAT"; case NC_DOUBLE: return "NC_DOUBLE"; case NC_INT: return "NC_INT"; case NC_SHORT: return "NC_SHORT"; case NC_CHAR: return "NC_CHAR"; case NC_BYTE: return "NC_BYTE"; case NC_UBYTE: return "NC_UBYTE"; case NC_USHORT: return "NC_USHORT"; case NC_UINT: return "NC_UINT"; case NC_INT64: return "NC_INT64"; case NC_UINT64: return "NC_UINT64"; case NC_STRING: return "NC_STRING"; case NC_VLEN: return "NC_VLEN"; case NC_OPAQUE: return "NC_OPAQUE"; case NC_ENUM: return "NC_ENUM"; case NC_COMPOUND: return "NC_COMPOUND"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_typ_sng() */ const char * /* O [sng] Native CDL type */ cdl_typ_nm /* [fnc] Return string describing native CDL type */ (const nc_type type) /* I [enm] netCDF type */ { /* Purpose: Divine CDL type string from netCDF external type enum */ switch(type){ case NC_FLOAT: return "float"; case NC_DOUBLE: return "double"; case NC_INT: return "int"; case NC_SHORT: return "short"; case NC_CHAR: return "char"; case NC_BYTE: return "byte"; case NC_UBYTE: return "ubyte"; case NC_USHORT: return "ushort"; case NC_UINT: return "uint"; case NC_INT64: return "int64"; case NC_UINT64: return "uint64"; case NC_STRING: return "string"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end cdl_typ_nm() */ const char * /* O [sng] Native XML type */ xml_typ_nm /* [fnc] Return string describing native XML type */ (const nc_type type) /* I [enm] netCDF type */ { /* Purpose: Divine XML type string from netCDF external type enum */ switch(type){ case NC_FLOAT: return "float"; case NC_DOUBLE: return "double"; case NC_INT: return "int"; case NC_SHORT: return "short"; case NC_CHAR: return "char"; case NC_BYTE: return "byte"; case NC_UBYTE: return "byte"; case NC_USHORT: return "short"; case NC_UINT: return "int"; case NC_INT64: return "long"; case NC_UINT64: return "long"; case NC_STRING: return "String"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end xml_typ_nm() */ const char * /* O [sng] Native CDL type suffix */ cdl_typ_sfx /* [fnc] Return suffix string for CDL type */ (const nc_type type) /* I [enm] netCDF type */ { /* Purpose: Return suffix string for CDL */ switch(type){ case NC_FLOAT: return ".f"; case NC_DOUBLE: return "."; case NC_INT: return ""; case NC_SHORT: return "s"; case NC_CHAR: return ""; case NC_BYTE: return "b"; case NC_UBYTE: return "ub"; case NC_USHORT: return "us"; case NC_UINT: return "u"; case NC_INT64: return "ll"; case NC_UINT64: return "ull"; case NC_STRING: return ""; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end cdl_typ_sfx() */ const char * /* O [sng] Native C type */ c_typ_nm /* [fnc] Return string describing native C type */ (const nc_type type) /* O [enm] netCDF type */ { /* Purpose: Divine internal (native) C type string from netCDF external type enum fxm: This breaks on Crays where both NC_FLOAT and NC_DOUBLE are native type float fxm: Modify this to handle different opaque types correctly This may mean defining tokens containing opaque type names in nco_typ.h */ switch(type){ case NC_FLOAT: return "float"; case NC_DOUBLE: return "double"; case NC_INT: return "NCO_INT_SNG"; case NC_SHORT: return "signed short int"; case NC_CHAR: return "NCO_CHAR_SNG"; case NC_BYTE: return "NCO_BYTE_SNG"; case NC_UBYTE: return "NCO_UBYTE_SNG"; case NC_USHORT: return "NCO_USHORT_SNG"; case NC_UINT: return "NCO_UINT_SNG"; case NC_INT64: return "NCO_INT64_SNG"; case NC_UINT64: return "NCO_UINT64_SNG"; case NC_STRING: return "NCO_STRING_SNG"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end c_typ_nm() */ const char * /* O [sng] Native Fortran77 type */ f77_typ_nm /* [fnc] Return string describing native Fortran77 type */ (const nc_type type) /* O [enm] netCDF type */ { /* Purpose: Divine internal (native) Fortran type string from netCDF external type enum */ switch(type){ case NC_FLOAT: return "real*4"; case NC_DOUBLE: return "real*8"; case NC_INT: return "integer*4"; case NC_SHORT: return "integer*2"; case NC_CHAR: return "character"; case NC_BYTE: return "character"; case NC_UBYTE: return "character"; case NC_USHORT: return "integer*2"; case NC_UINT: return "integer*4"; case NC_INT64: return "integer*8"; case NC_UINT64: return "integer*8"; case NC_STRING: return "character fxm"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end f77_typ_nm() */ const char * /* O [sng] Native Fortran90 type */ f90_typ_nm /* [fnc] Return string describing native Fortran90 type */ (const nc_type type) /* O [enm] netCDF type */ { /* Purpose: Divine internal (native) Fortran type string from netCDF external type enum */ switch(type){ case NC_FLOAT: return "real(selected_real_kind(p=6))"; case NC_DOUBLE: return "real(selected_real_kind(p=12))"; case NC_INT: return "integer(selected_int_kind(6))"; case NC_SHORT: return "integer(selected_int_kind(2))"; case NC_CHAR: return "character(1)"; case NC_BYTE: return "character(1)"; case NC_UBYTE: return "character(1)"; /* NB: Not sure about generality of integer kinds */ case NC_USHORT: return "integer(selected_int_kind(2))"; case NC_UINT: return "integer(selected_int_kind(6))"; case NC_INT64: return "integer(selected_int_kind(8))"; case NC_UINT64: return "integer(selected_int_kind(8))"; case NC_STRING: return "character(1) fxm"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end f90_typ_nm() */ const char * /* O [sng] String describing file format */ nco_fmt_sng /* [fnc] Convert netCDF file format enum to string */ (const int fl_fmt) /* I [enm] netCDF file format */ { /* Purpose: Convert netCDF file format enum to string */ switch(fl_fmt){ case NC_FORMAT_CLASSIC: return "NC_FORMAT_CLASSIC"; case NC_FORMAT_64BIT: return "NC_FORMAT_64BIT"; case NC_FORMAT_NETCDF4: return "NC_FORMAT_NETCDF4"; case NC_FORMAT_NETCDF4_CLASSIC: return "NC_FORMAT_NETCDF4_CLASSIC"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_fmt_sng() */ const char * /* O [sng] String describing file format for hidden attributes */ nco_fmt_hdn_sng /* [fnc] Convert netCDF file format enum to string for hidden attributes */ (const int fl_fmt) /* I [enm] netCDF file format */ { /* Purpose: Convert netCDF file format enum to string for hidden attributes 20131229: String values obtained from ncgen man page */ switch(fl_fmt){ case NC_FORMAT_CLASSIC: return "classic"; case NC_FORMAT_64BIT: return "64-bit offset"; case NC_FORMAT_NETCDF4: return "netCDF-4"; case NC_FORMAT_NETCDF4_CLASSIC: return "netCDF-4 classic model"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_fmt_hdn_sng() */ const char * /* O [sng] String describing extended file format */ nco_fmt_xtn_sng /* [fnc] Convert netCDF extended file format enum to string */ (const int fl_fmt_xtn) /* I [enm] netCDF extended file format */ { /* Purpose: Convert netCDF extended file format enum to string */ switch(fl_fmt_xtn){ case NC_FORMAT_NC3: return "NC_FORMAT_NC3"; case NC_FORMAT_NC_HDF5: return "NC_FORMAT_HDF5"; case NC_FORMAT_NC_HDF4: return "NC_FORMAT_HDF4"; case NC_FORMAT_PNETCDF: return "NC_FORMAT_PNETCDF"; case NC_FORMAT_DAP2: return "NC_FORMAT_DAP2"; case NC_FORMAT_DAP4: return "NC_FORMAT_DAP4"; case NC_FORMAT_UNDEFINED: return "NC_FORMAT_UNDEFINED"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_fmt_xtn_sng() */ const char * /* O [sng] String describing endianness for hidden attributes */ nco_ndn_sng /* [fnc] Convert netCDF endianness enum to string for hidden attributes */ (const int flg_ndn) /* I [enm] netCDF endianness */ { /* Purpose: Convert netCDF endianness enum to string for hidden attributes */ switch(flg_ndn){ case NC_ENDIAN_NATIVE: return "classic"; case NC_ENDIAN_LITTLE: return "little"; case NC_ENDIAN_BIG: return "big"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_ndn_sng() */ void nco_dfl_case_nc_type_err(void) /* [fnc] Print error and exit for illegal switch(nc_type) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(nctype) statement receives an illegal default case NCO emits warnings when compiled by GCC with -DNETCDF2_ONLY since, apparently, there are a whole bunch of things besides numeric types in the old nctype enum and gcc warns about enums that are not exhaustively considered in switch() statements. All these default statements can be removed with netCDF3 interface so perhaps these should be surrounded with #ifdef NETCDF2_ONLY constructs, but they actually do make sense for netCDF3 as well so I have implemented a uniform error function, nco_dfl_case_nc_type_err(), to be called by all routines which emit errors only when compiled with NETCDF2_ONLY. This makes the behavior easy to modify or remove in the future. Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_nc_type_err()"; (void)fprintf(stdout,"%s: ERROR switch(nctype) statement fell through to default case, which is illegal, because each type should have a well-defined action. This error may be triggered by using an NCO built with only netCDF3 functionality to examine a netCDF4 dataset that contains a new atomic type (e.g., NC_INT64).\nHINT: Configure/build NCO with --enable-netCDF4. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_nc_type_err() */ void nco_sng_cnv_err /* [fnc] Print error and exit for failed strtol()-type calls */ (const char *cnv_sng, /* I [sng] String to convert */ const char *sng_cnv_fnc, /* I [sng] Name of function used to convert string */ const char *err_ptr) /* I [chr] First illegal character in string */ { /* Purpose: Convenience routine for printing error and exiting when strtol()/strtoul()/strtoll()/strtoull() receives illegal characters. Placing this in its own routine saves many lines of error handling. */ const char fnc_nm[]="nco_sng_cnv_err()"; if(!strcmp(sng_cnv_fnc,"strtod")){ /* Handle conversion errors for strtod()... */ (void)fprintf(stdout,"%s: ERROR an NCO function or main program attempted to convert the (probably user-defined) string \"%s\" to a floating point type using the standard C-library function \"%s()\". This function stopped converting the input string when it encountered the illegal (i.e., non-numeric) character \'%c\'. This probably indicates a syntax error by the user. Please check the argument syntax and re-try the command. ",fnc_nm,cnv_sng,sng_cnv_fnc,err_ptr[0]); }else{ /* !strtod() */ /* Handle conversion errors for strtol(), strtoul()... */ (void)fprintf(stdout,"%s: ERROR an NCO function or main program attempted to convert the user-defined string \"%s\" to an integer-type using the standard C-library function \"%s()\". This function stopped converting the input string when it encountered the illegal (i.e., non-numeric or non-integer) character \'%c\'. This probably indicates a syntax error by the user. Please check the argument syntax and re-try the command. ",fnc_nm,cnv_sng,sng_cnv_fnc,err_ptr[0]); } /* !strtod() */ if(err_ptr[0] == ',') (void)fprintf(stdout,"HINT: Conversion functions like \"%s()\" accept only one number at a time, so comma-separated lists of numbers are invalid. ",sng_cnv_fnc); (void)fprintf(stdout,"Exiting...\n"); nco_err_exit(0,fnc_nm); } /* end nco_sng_cnv_err() */ void nco_dfl_case_prg_id_err(void) /* [fnc] Print error and exit for illegal switch(nco_prg_id_id) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(nco_prg_id) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_prg_id_err()"; (void)fprintf(stdout,"%s: ERROR switch(nco_prg_id) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(nco_prg_id) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_prg_id_err() */ /* Begin file-level routines */ int nco_create(const char * const fl_nm,const int cmode,int * const nc_id) { /* Purpose: Wrapper for nc_create() */ const char fnc_nm[]="nco_create()"; int rcd; rcd=nc_create(fl_nm,cmode,nc_id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"ERROR: %s unable to create file \"%s\"\n",fnc_nm,fl_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco_create */ int nco__create(const char * const fl_nm,const int cmode,const size_t sz_ntl,size_t * const bfr_sz_hnt,int * const nc_id) { /* Purpose: Wrapper for nc__create() */ const char fnc_nm[]="nco__create()"; int rcd; rcd=nc__create(fl_nm,cmode,sz_ntl,bfr_sz_hnt,nc_id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"ERROR: %s unable to create file \"%s\"\n",fnc_nm,fl_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco__create */ int nco_open(const char * const fl_nm,const int mode,int * const nc_id) { /* Purpose: Wrapper for nc_open() */ const char fnc_nm[]="nco_open()"; int rcd; rcd=nc_open(fl_nm,mode,nc_id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"ERROR: %s unable to open file \"%s\"\n",fnc_nm,fl_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco_open */ int nco__open(const char * const fl_nm,const int mode,size_t * const bfr_sz_hnt,int * const nc_id) { /* Purpose: Wrapper for nc__open() */ const char fnc_nm[]="nco__open()"; int rcd; rcd=nc__open(fl_nm,mode,bfr_sz_hnt,nc_id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"ERROR: %s unable to open file \"%s\"\n",fnc_nm,fl_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco__open */ int nco_open_flg(const char * const fl_nm,const int mode,int * const nc_id) { /* Purpose: Error-tolerant wrapper for nc_open(). Tolerates all errors. Currently used only by nco_fl_mk_lcl() to test file accessibility via DAP */ int rcd; rcd=nc_open(fl_nm,mode,nc_id); return rcd; } /* end nco_open */ #if 0 #ifdef HAVE_NETCDF4_H /* netCDF4 routines defined by Unidata netCDF4 Library libnetcdf.a 20051129: nc_*_par() routines require that netCDF4 be configured for parallel filesystems */ int nco_open_par(const char * const fl_nm,const int mode,MPI_Comm mpi_cmm,MPI_Info mpi_nfo,int * const nc_id) { /* Purpose: Wrapper for nc_open_par() */ const char fnc_nm[]="nco_open_par()"; int rcd; rcd=nc_open_par(fl_nm,mode,mpi_cmm,mpi_nfo,nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end nco_open_par */ #endif /* !HAVE_NETCDF4_H */ #endif /* !0 */ #ifdef ENABLE_PNETCDF /* pnetCDF routines defined by ANL Parallel netCDF Library libpnetcdf.a */ int ncompi_open(MPI_Comm mpi_cmm,const char * const fl_nm,const int mode,MPI_Info mpi_nfo,int * const nc_id) { /* Purpose: Wrapper for ncmpi_open() */ const char fnc_nm[]="ncompi_open()"; int rcd; rcd=ncmpi_open(mpi_cmm,fl_nm,mode,mpi_nfo,nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end ncompi_open */ #endif /* !ENABLE_PNETCDF */ int nco_redef(const int nc_id) { /* Purpose: Wrapper for nc_redef() */ int rcd; rcd=nc_redef(nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_redef()"); return rcd; } /* end nco_redef */ int nco_set_fill(const int nc_id,const int fill_mode,int * const old_mode) { /* Purpose: Wrapper for nc_set_fill() */ int rcd; rcd=nc_set_fill(nc_id,fill_mode,old_mode); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_set_fill()"); return rcd; } /* end nco_set_fill */ int nco_enddef(const int nc_id) { /* Purpose: Wrapper for nc_enddef() */ int rcd; rcd=nc_enddef(nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_enddef()"); return rcd; } /* end nco_enddef */ int /* O [enm] netCDF error code */ nco__enddef /* [fnc] Wrapper for nc__enddef */ (const int nc_id, /* [ID] netCDF ID */ const size_t hdr_pad) /* [B] Pad at end of header section */ { /* Purpose: Wrapper for nc__enddef() */ int rcd; /* hdr_pad is netCDF library h_minfree variable */ const size_t v_align=4UL; /* [B] Alignment of beginning of data section for fixed variables */ const size_t v_minfree=0UL; /* [B] Pad at end of data section for fixed size variables */ const size_t r_align=4UL; /* [B] Alignment of beginning of data section for record variables */ /* nc_enddef(ncid) is equivalent to nc__enddef(ncid,0,4,0,4) */ rcd=nc__enddef(nc_id,hdr_pad,v_align,v_minfree,r_align); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco__enddef()"); return rcd; } /* end nco__enddef */ int nco_sync(const int nc_id) { /* Purpose: Wrapper for nc_sync() */ int rcd; rcd=nc_sync(nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_sync()"); return rcd; } /* end nco_sync */ int nco_abort(const int nc_id) { /* Purpose: Wrapper for nc_abort() */ int rcd; rcd=nc_abort(nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_abort()"); return rcd; } /* end nco_abort */ int nco_close(const int nc_id) { /* Purpose: Wrapper for nc_close() */ const char fnc_nm[]="nco_close()"; int rcd=NC_NOERR; rcd=nc_close(nc_id); if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end nco_close */ int nco_inq(const int nc_id,int * const dmn_nbr_fl,int * const var_nbr_fl,int * const att_glb_nbr,int * const rec_dmn_id) { /* Purpose: Wrapper for nc_inq() */ int rcd; rcd=nc_inq(nc_id,dmn_nbr_fl,var_nbr_fl,att_glb_nbr,rec_dmn_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq()"); return rcd; } /* end nco_inq() */ #ifdef NEED_NC_INQ_FORMAT int nc_inq_format(int nc_id, int * const fl_fmt) { /* Purpose: Stub for nc_inq_format(), which appeared in netCDF 3.6.1 or 3.6.2 20070901 Current OPeNDAP does not have nc_inq_format() and thus requires this stub */ *fl_fmt=NC_FORMAT_CLASSIC; /* [enm] Output file format */ return NC_NOERR+0*nc_id; /* CEWI */ } /* end nc_inq_format() */ #endif /* !NEED_NC_INQ_FORMAT */ int nco_inq_format(const int nc_id,int * const fl_fmt) { /* Purpose: Wrapper for nc_inq_format() */ int rcd; /* NB: Function nc_inq_format(int ncid, int *formatp) appeared in netCDF 3.6.1 Forward compatibility prototype required for systems with netCDF < 3.6.1 */ rcd=nc_inq_format(nc_id,fl_fmt); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_format()"); return rcd; } /* end nco_inq_format() */ #ifndef NC_HAVE_INQ_FORMAT_EXTENDED int nc_inq_format_extended(const int nc_id,int * const fl_fmt,int * const mode) { /* Purpose: 20131222: Stub for nc_inq_format_extended(), which appeared in netCDF 4.3.1-rc7 Forward compatibility prototype required for systems with netCDF < 4.3.1 */ int rcd=NC_NOERR; *fl_fmt=NC_FORMAT_UNDEFINED; /* [enm] Output file format */ *mode=0; /* [enm] Output file format */ return NC_NOERR+0*nc_id+0*rcd; /* CEWI */ } /* end nc_inq_format_extended() */ #endif /* !NC_HAVE_INQ_FORMAT_EXTENDED */ int nco_inq_format_extended(const int nc_id,int * const fl_fmt,int * const mode) { /* Purpose: Wrapper for nc_inq_format_extended() */ int rcd=NC_NOERR; /* NB: 20131222: Function nc_inq_format_extended(int ncid,int *formatp,int *mode) appeared in netCDF 4.3.1-rc7 Forward compatibility prototype required for systems with netCDF < 4.3.1 */ rcd=nc_inq_format_extended(nc_id,fl_fmt,mode); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_format_extended()"); return rcd; } /* end nco_inq_format_extended() */ #ifdef HAVE_NETCDF4_H int nco_inq_ncid(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Wrapper for nc_inq_ncid() */ int rcd; rcd=nc_inq_ncid(nc_id,grp_nm,grp_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_ncid()"); return rcd; } /* end nco_inq_ncid() */ int nco_inq_ncid_flg(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Error-tolerant Wrapper for nc_inq_ncid(). Tolerates NC_ENOGRP */ int rcd; rcd=nc_inq_ncid(nc_id,grp_nm,grp_id); if(rcd == NC_ENOGRP) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_ncid()"); return rcd; } /* end nco_inq_ncid_flg() */ #endif /* !HAVE_NETCDF4_H */ int nco_inq_ndims(const int nc_id,int * const dmn_nbr_fl) { /* Purpose: Wrapper for nc_inq_ndims() */ int rcd; rcd=nc_inq_ndims(nc_id,dmn_nbr_fl); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_ndims()"); return rcd; } /* end nco_inq_ndims() */ int nco_inq_nvars(const int nc_id,int * const var_nbr_fl) { /* Purpose: Wrapper for nc_inq_nvars() */ int rcd; rcd=nc_inq_nvars(nc_id,var_nbr_fl); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_nvars()"); return rcd; } /* end nco_inq_nvars() */ int nco_inq_natts(const int nc_id,int * const att_glb_nbr) { /* Purpose: Wrapper for nc_inq_natts() */ int rcd; rcd=nc_inq_natts(nc_id,att_glb_nbr); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_natts()"); return rcd; } /* end nco_inq_natts() */ int nco_inq_unlimdim(const int nc_id,int * const rec_dmn_id) { /* Purpose: Wrapper for nc_inq_unlimdim() */ int rcd; rcd=nc_inq_unlimdim(nc_id,rec_dmn_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_unlimdim()"); return rcd; } /* end nco_inq_unlimdim() */ int nco_inq_unlimdim_flg(const int nc_id,int * const rec_dmn_id) { /* Purpose: Error-tolerant wrapper for nc_inq_unlimdim(). Tolerates NC_EBADDIM. */ int rcd; rcd=nc_inq_unlimdim(nc_id,rec_dmn_id); if(rcd == NC_EBADDIM) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_unlimdim_flg()"); return rcd; } /* end nco_inq_unlimdim_flg() */ int nco_get_chunk_cache (size_t * const sz_byt, /* [B] Raw data chunk cache size */ size_t * const cnk_nbr_hsh, /* [nbr] Chunk slots in raw data chunk cache hash table */ float * const pmp_fvr_frc) /* [frc] Preemption favor fraction */ { /* Purpose: Wrapper for nc_get_chunk_cache() */ int rcd; rcd=nc_get_chunk_cache(sz_byt,cnk_nbr_hsh,pmp_fvr_frc); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_chunk_cache()"); return rcd; } /* end nco_get_chunk_cache() */ int nco_set_chunk_cache (const size_t sz_byt, /* [B] Raw data chunk cache size */ const size_t cnk_nbr_hsh, /* [nbr] Chunk slots in raw data chunk cache hash table */ const float pmp_fvr_frc) /* [frc] Preemption favor fraction */ { /* Purpose: Wrapper for nc_set_chunk_cache() */ int rcd; rcd=nc_set_chunk_cache(sz_byt,cnk_nbr_hsh,pmp_fvr_frc); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_set_chunk_cache()"); return rcd; } /* end nco_set_chunk_cache() */ /* End File routines */ /* Begin Group routines (_grp) */ #ifdef HAVE_NETCDF4_H int nco_def_grp(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Wrapper for nc_def_grp() */ int rcd; rcd=nc_def_grp(nc_id,grp_nm,grp_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_grp()"); return rcd; } /* end nco_def_grp() */ int nco_def_grp_flg(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Error-tolerant wrapper for nc_def_grp(). Tolerates NC_ENAMEINUSE (-42) "String match to name in use" */ int rcd; rcd=nc_def_grp(nc_id,grp_nm,grp_id); if(rcd == NC_ENAMEINUSE) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_grp_flg()"); return rcd; } /* end nco_def_grp_flg() */ #ifndef NC_HAVE_RENAME_GRP int nc_rename_grp(int grp_id,const char * const grp_nm) { /* Purpose: Pseudo-library function to rename groups. This particular stub routine is only called by netCDF4-enabled code when built against a netCDF library that it too old to have the nc_rename_grp() function. Test by running something like this: ncrename -O -g g1,obama ~/nco/data/in_grp.nc ~/foo.nc */ const char fnc_nm[]="nc_rename_grp()"; char grp_nm_old[NC_MAX_NAME+1L]; int rcd; rcd=NC_NOERR; rcd+=nco_inq_grpname(grp_id,grp_nm_old); (void)fprintf(stdout,"INFO: %s reports attempt to rename group \"%s\" to \"%s\" was foiled because libnetcdf.a does not contain nc_rename_grp(). To obtain this functionality, please rebuild NCO against netCDF library version 4.3.1-pre1 (released ~201309) or later.\nContinuing as though nothing untoward happened...\n",fnc_nm,grp_nm_old,grp_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nc_rename_grp()"); return rcd; } /* end nc_rename_grp() */ #endif /* NC_HAVE_RENAME_GRP */ int nco_rename_grp(int grp_id,const char * const grp_nm) { /* Purpose: Wrapper for nc_rename_grp() */ int rcd; rcd=nc_rename_grp(grp_id,grp_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_rename_grp()"); return rcd; } /* end nco_rename_grp() */ int nco_inq_dimids(const int nc_id,int * const dmn_nbr,int * const dmn_ids,int flg_prn) { /* Purpose: Wrapper for nc_inq_dimids() */ int rcd; rcd=nc_inq_dimids(nc_id,dmn_nbr,dmn_ids,flg_prn); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dimids()"); return rcd; } /* end nco_inq_dimids() */ int nco_inq_grpname(const int nc_id,char * const grp_nm) { /* Purpose: Wrapper for nc_inq_grpname() */ int rcd; rcd=nc_inq_grpname(nc_id,grp_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grpname()"); return rcd; } /* end nco_inq_grpname() */ int nco_inq_grpname_full(const int nc_id,size_t * grp_nm_lng,char * const grp_nm_full) { /* Purpose: Wrapper for nc_inq_grpname_full() */ int rcd; rcd=nc_inq_grpname_full(nc_id,grp_nm_lng,grp_nm_full); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grpname_full()"); return rcd; } /* end nco_inq_grpname_full() */ int nco_inq_grpname_len(const int nc_id,size_t * const grp_nm_lng) { /* Purpose: Wrapper for nc_inq_grpname_len() */ int rcd; rcd=nc_inq_grpname_len(nc_id,grp_nm_lng); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grpname_len()"); return rcd; } /* end nco_inq_grpname_len() */ int nco_inq_grps(const int nc_id,int * const grp_nbr,int * const grp_ids) { /* Purpose: Wrapper for nc_inq_grps() */ int rcd; rcd=nc_inq_grps(nc_id,grp_nbr,grp_ids); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grps()"); return rcd; } /* end nco_inq_grps() */ int nco_inq_grp_ncid(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Wrapper for nc_inq_grp_ncid() */ int rcd; rcd=nc_inq_grp_ncid(nc_id,grp_nm,grp_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_ncid()"); return rcd; } /* end nco_inq_grp_ncid() */ int nco_inq_grp_ncid_flg(const int nc_id,const char * const grp_nm,int * const grp_id) { /* Purpose: Error-tolerant wrapper for nc_inq_grp_ncid(). Tolerates NC_ENOGRP */ int rcd; rcd=nc_inq_grp_ncid(nc_id,grp_nm,grp_id); if(rcd == NC_ENOGRP) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_ncid()"); return rcd; } /* end nco_inq_grp_ncid() */ int nco_inq_grp_full_ncid(const int nc_id,const char * const grp_nm_fll,int * const grp_id) { /* Purpose: Wrapper for nc_inq_grp_full_ncid() */ int fl_fmt; int rcd; rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_grp_full_ncid(nc_id,grp_nm_fll,grp_id); }else{ /* netCDF3 */ *grp_id=nc_id; } /* endif */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_full_ncid()"); return rcd; } /* end nco_inq_grp_full_ncid() */ int nco_inq_grp_full_ncid_flg(const int nc_id,const char * const grp_nm_fll,int * const grp_id) { /* Purpose: Error-tolerant Wrapper for nc_inq_grp_full_ncid(). Tolerates NC_ENOGRP */ int fl_fmt; int rcd; rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_grp_full_ncid(nc_id,grp_nm_fll,grp_id); }else{ /* netCDF3 */ *grp_id=nc_id; } /* endif */ if(rcd == NC_ENOGRP) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_full_ncid()"); return rcd; } /* end nco_inq_grp_full_ncid_flg() */ int nco_inq_grp_parent(const int nc_id,int * const prn_id) { /* Purpose: Wrapper for nc_inq_grp_parent() */ int rcd; rcd=nc_inq_grp_parent(nc_id,prn_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_parent()"); return rcd; } /* end nco_inq_grp_parent() */ int nco_inq_grp_parent_flg(const int nc_id,int * const prn_id) { /* Purpose: Error-tolerant Wrapper for nc_inq_grp_parent_flg(). Tolerates NC_ENOGRP */ int rcd; rcd=nc_inq_grp_parent(nc_id,prn_id); if(rcd == NC_ENOGRP) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_grp_parent_flg()"); return rcd; } /* end nco_inq_grp_parent_flg() */ int nco_inq_varids(const int nc_id,int * const var_nbr,int * const var_ids) { /* Purpose: Wrapper for nc_inq_varids() */ int rcd; rcd=nc_inq_varids(nc_id,var_nbr,var_ids); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varids()"); return rcd; } /* end nco_inq_varids() */ int nco_inq_unlimdims(const int nc_id,int *nbr_dmn_ult,int *dmn_ids_ult) { /* Purpose: Wrapper for nc_inq_unlimdims() */ int rcd; rcd=nc_inq_unlimdims(nc_id,nbr_dmn_ult,dmn_ids_ult); if(rcd != NC_NOERR) nco_err_exit(rcd,"nc_inq_unlimdims()"); return rcd; } /* end nco_inq_unlimdims() */ #endif /* !HAVE_NETCDF4_H */ /* End Group routines */ /* Begin Dimension routines (_dim) */ int nco_def_dim(const int nc_id,const char * const dmn_nm,const long dmn_sz,int * const dmn_id) { /* Purpose: Wrapper for nc_def_dim() */ int rcd; rcd=nc_def_dim(nc_id,dmn_nm,(size_t)dmn_sz,dmn_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_dim()"); return rcd; } /* end nco_def_dim */ int nco_inq_dimid(const int nc_id,const char * const dmn_nm,int * const dmn_id) { /* Purpose: Wrapper for nc_inq_dimid() */ const char fnc_nm[]="nco_inq_dimid()"; int rcd; rcd=nc_inq_dimid(nc_id,dmn_nm,dmn_id); if(rcd == NC_EBADDIM){ (void)fprintf(stdout,"ERROR: %s reports requested dimension \"%s\" is not in input file\n",fnc_nm,dmn_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end nco_inq_dimid */ int nco_inq_dimid_flg(const int nc_id,const char * const dmn_nm,int * const dmn_id) { /* Purpose: Error-tolerant wrapper for nc_inq_dimid(). Tolerates NC_EBADDIM. */ int rcd; rcd=nc_inq_dimid(nc_id,dmn_nm,dmn_id); if(rcd == NC_EBADDIM) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dimid_flg()"); return rcd; } /* end nco_inq_dimid */ int nco_inq_dim(const int nc_id,const int dmn_id,char *dmn_nm,long *dmn_sz) { /* Purpose: Wrapper for nc_inq_dim() */ int rcd; rcd=nc_inq_dim(nc_id,dmn_id,dmn_nm,(size_t *)dmn_sz); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dim()"); return rcd; }/* end nco_inq_dim */ int nco_inq_dim_flg(const int nc_id,const int dmn_id,char *dmn_nm,long *dmn_sz) { /* Purpose: Error-tolerant wrapper for nc_inq_dim_flg(). Tolerates NC_EBADDIM. */ int rcd; rcd=nc_inq_dim(nc_id,dmn_id,dmn_nm,(size_t *)dmn_sz); if(rcd == NC_EBADDIM) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dim_flg()"); return rcd; }/* end nco_inq_dim */ int nco_inq_dimname(const int nc_id,const int dmn_id,char *dmn_nm) { /* Purpose: Wrapper for nc_inq_dimname() */ int rcd; rcd=nc_inq_dimname(nc_id,dmn_id,dmn_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dimname()"); return rcd; } /* end nco_inq_dimname */ int nco_inq_dimlen(const int nc_id,const int dmn_id,long *dmn_sz) { /* Purpose: Wrapper for nc_inq_dimlen() */ int rcd; rcd=nc_inq_dimlen(nc_id,dmn_id,(size_t *)dmn_sz); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dimlen()"); return rcd; } /* end nco_inq_dimlen */ int nco_rename_dim(const int nc_id,const int dmn_id,const char * const dmn_nm) { /* Purpose: Wrapper for nc_rename_dim() */ int rcd; rcd=nc_rename_dim(nc_id,dmn_id,dmn_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_rename_dim()"); return rcd; } /* end nco_inq_rename_dim */ /* End Dimension routines */ /* Begin Variable routines (_var) */ int nco_copy_var(const int nc_in_id,const int var_id,const int nc_out_id) { /* Purpose: Wrapper for nc_copy_var() */ int rcd; rcd=nc_copy_var(nc_in_id,var_id,nc_out_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_copy_var()"); return rcd; } /* end nco_copy_var */ int nco_def_var(const int nc_id,const char * const var_nm,const nc_type var_typ,const int dmn_nbr,const int * const dmn_id,int * const var_id) { /* Purpose: Wrapper for nc_def_var() */ int rcd; rcd=nc_def_var(nc_id,var_nm,var_typ,dmn_nbr,dmn_id,var_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_var()"); return rcd; } /* end nco_def_var */ int nco_def_var_chunking (const int nc_id, /* [ID] netCDF ID */ const int var_id, /* [ID] Variable ID */ const int srg_typ, /* [enm] Storage type */ const size_t * const cnk_sz) /* [nbr] Chunk sizes */ { /* Purpose: Wrapper for nc_def_var_chunking() */ int rcd; /* NB: 20090713: netCDF4 API for nc_def_var_chunking() changed ~200906 Before that a weak netCDF4 prototype did not make cnk_sz const After I notified Unidata of this, they changed prototype to const size_t * const cnk_sz This API change may cause confusion/differences when compiling NCO with netCDF4 versions pre- and post-200906, e.g., netcdf-4.1-beta1-snapshot2009050200 has old behavior while netcdf-4.1-beta1-snapshot2009071200 has new behavior. Finding one-size-fits-all method is difficult! */ /* rcd=nc_def_var_chunking(nc_id,var_id,srg_typ,cnk_sz);*/ rcd=nc_def_var_chunking(nc_id,var_id,srg_typ,(size_t *)cnk_sz); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_var_chunking()"); return rcd; } /* end nco_def_var_chunking() */ int nco_def_var_deflate (const int nc_id, /* [ID] netCDF ID */ const int var_id, /* [ID] Variable ID */ const int shuffle, /* [flg] Turn on shuffle filter */ const int deflate, /* [flg] Turn on deflate filter */ const int dfl_lvl) /* [enm] Deflate level [0..9] */ { /* Purpose: Wrapper for nc_def_var_deflate() */ int rcd; int deflate_new; /* 20131204: Turn-off deflate filter when dfl_lvl == 0 */ if(dfl_lvl == 0) deflate_new=0; else deflate_new=deflate; rcd=nc_def_var_deflate(nc_id,var_id,shuffle,deflate_new,dfl_lvl); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_var_deflate()"); return rcd; } /* end nco_def_var_deflate() */ int nco_inq_var(const int nc_id,const int var_id,char * const var_nm,nc_type *var_typ,int * const dmn_nbr,int * const dmn_id,int * const nbr_att) { /* Purpose: Wrapper for nco_inq_var() */ int rcd; rcd=nc_inq_var(nc_id,var_id,var_nm,var_typ,dmn_nbr,dmn_id,nbr_att); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var()"); return rcd; } /* end nco_inq_var */ int nco_inq_var_chunking (const int nc_id, /* [ID] netCDF ID */ const int var_id, /* [ID] Variable ID */ int * const srg_typ, /* [enm] Storage type */ size_t * const cnk_sz) /* [nbr] Chunk sizes */ { /* Purpose: Wrapper for nc_inq_var_chunking() */ /* NB: netCDF chunking inquire function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_var_chunking(nc_id,var_id,srg_typ,cnk_sz); }else{ /* !netCDF4 */ /* Defensive programming */ *srg_typ=NC_CONTIGUOUS; } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var_chunking()"); return rcd; } /* end nco_inq_var_chunking() */ int nco_inq_var_deflate (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ int * const shuffle, /* O [flg] Turn on shuffle filter */ int * const deflate, /* O [flg] Turn on deflate filter */ int * const dfl_lvl) /* O [enm] Deflate level [0..9] */ { /* Purpose: Wrapper for nc_inq_var_deflate() */ /* NB: netCDF deflate inquire function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_var_deflate(nc_id,var_id,shuffle,deflate,dfl_lvl); }else{ /* !netCDF4 */ if(shuffle) *shuffle=0; if(deflate) *deflate=0; if(dfl_lvl) *dfl_lvl=0; } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var_deflate()"); return rcd; } /* end nco_inq_var_deflate() */ int nco_inq_var_endian (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ int * const ndn_typ) /* O [enm] Endianness */ { /* Purpose: Wrapper for nc_inq_var_endian() */ /* NB: netCDF endian inquire function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_var_endian(nc_id,var_id,ndn_typ); }else{ /* !netCDF4 */ if(ndn_typ) *ndn_typ=NC_ENDIAN_NATIVE; } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var_endian()"); return rcd; } /* end nco_inq_var_endian() */ int nco_inq_var_fill (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ int * const fll_nil, /* O [enm] NO_FILL */ void * const fll_val) /* O [enm] Fill value */ { /* Purpose: Wrapper for nc_inq_var_fill() */ /* NB: netCDF fill inquire function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_var_fill(nc_id,var_id,fll_nil,fll_val); }else{ /* !netCDF4 */ if(fll_nil) *fll_nil=0; /* fxm: implement netCDF3-compatible function which returns real fill values based on variable type This could be based on nco_mss_val_get() */ if(fll_val) assert(0); rcd=NC_NOERR; } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var_fill()"); return rcd; } /* end nco_inq_var_fill() */ int nco_def_var_fletcher32 (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ const int chk_typ) /* I [enm] Checksum type */ { /* Purpose: Wrapper for nc_def_var_fletcher32() */ /* NB: netCDF fletcher32 set function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd=NC_NOERR; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_def_var_fletcher32(nc_id,var_id,chk_typ); } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_def_var_fletcher32()"); return rcd; } /* end nco_def_var_fletcher32() */ int nco_inq_var_fletcher32 (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ int * const chk_typ) /* O [enm] Checksum type */ { /* Purpose: Wrapper for nc_inq_var_fletcher32() */ /* NB: netCDF fletcher32 inquire function only works on netCDF4 files NCO wrapper works on netCDF3 and netCDF4 files */ int rcd=NC_NOERR; int fl_fmt; /* [enm] Input file format */ rcd=nco_inq_format(nc_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ rcd=nc_inq_var_fletcher32(nc_id,var_id,chk_typ); }else{ /* !netCDF4 */ if(chk_typ) *chk_typ=NC_NOCHECKSUM; } /* !netCDF4 */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_var_fletcher32()"); return rcd; } /* end nco_inq_var_fletcher32() */ int /* O [flg] Return success code */ nco_inq_var_packing /* [fnc] Check whether variable is packed on disk */ (const int nc_id, /* I [ID] netCDF ID */ const int var_id, /* I [ID] Variable ID */ int * const packing) /* O [flg] Variable is packed on disk */ { /* Purpose: Check whether variable is packed on disk Designed to behave like netCDF-library call for packing (which does not exist) Based on nco_pck_dsk_inq() Difference is that: nco_pck_dsk_inq() fills in members of variable structure nco_inq_var_packing() does not need a variable structure, or anything from nco.h Hence, nco_inq_var_packing is suitable for light-overhead calls, such as by ncks for printing */ const char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ const char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ int rcd; /* [rcd] Return success code */ int has_scl_fct; /* [flg] Valid scale_factor attribute exists */ int has_add_fst; /* [flg] Valid add_offset attribute exists */ long add_fst_lng; /* [idx] Number of elements in add_offset attribute */ long scl_fct_lng; /* [idx] Number of elements in scale_factor attribute */ nc_type add_fst_typ; /* [idx] Type of add_offset attribute */ nc_type scl_fct_typ; /* [idx] Type of scale_factor attribute */ /* Initialize and default to most-likely outcome, that variable is not packed */ has_scl_fct=0; /* [flg] Valid scale_factor attribute exists */ has_add_fst=0; /* [flg] Valid add_offset attribute exists */ *packing=0; /* [flg] Variable is packed on disk */ /* Vet scale_factor */ rcd=nco_inq_att_flg(nc_id,var_id,scl_fct_sng,&scl_fct_typ,&scl_fct_lng); if(rcd != NC_ENOTATT){ if(scl_fct_typ == NC_BYTE || scl_fct_typ == NC_CHAR) return NC_NOERR; if(scl_fct_lng != 1) return NC_NOERR; has_scl_fct=1; /* [flg] Valid scale_factor attribute exists */ } /* endif */ /* Vet add_offset */ rcd=nco_inq_att_flg(nc_id,var_id,add_fst_sng,&add_fst_typ,&add_fst_lng); if(rcd != NC_ENOTATT){ if(add_fst_typ == NC_BYTE || add_fst_typ == NC_CHAR) return NC_NOERR; if(add_fst_lng != 1) return NC_NOERR; has_add_fst=1; /* [flg] Valid add_offset attribute exists */ } /* endif */ if(has_scl_fct && has_add_fst) if(scl_fct_typ != add_fst_typ) return NC_NOERR; /* Variable is considered packed iff either or both valid scale_factor or add_offset exist */ if(has_scl_fct || has_add_fst) *packing=1; /* [flg] Variable is packed on disk */ return NC_NOERR; } /* end nco_inq_var_packing() */ int nco_inq_varid(const int nc_id,const char * const var_nm,int * const var_id) { /* Purpose: Wrapper for nc_inq_varid() */ const char fnc_nm[]="nco_inq_varid()"; int rcd; rcd=nc_inq_varid(nc_id,var_nm,var_id); if(rcd == NC_ENOTVAR) (void)fprintf(stdout,"ERROR: %s reports requested variable \"%s\" is not in input file\n",fnc_nm,var_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end nco_inq_varid */ int nco_inq_varid_flg(const int nc_id,const char * const var_nm,int * const var_id) { /* Purpose: Error-tolerant wrapper for nc_inq_varid(). Tolerates NC_ENOTVAR. */ int rcd; rcd=nc_inq_varid(nc_id,var_nm,var_id); if(rcd == NC_ENOTVAR) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varid_flg()"); return rcd; } /* end nco_inq_varid */ int nco_inq_varname(const int nc_id,const int var_id,char * const var_nm) { /* Purpose: Wrapper for nc_inq_varname() */ int rcd; rcd=nc_inq_varname(nc_id,var_id,var_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varname()"); return rcd; } /* end nco_inq_varname */ int nco_inq_vartype(const int nc_id,const int var_id,nc_type * const var_typ) { /* Purpose: Wrapper for nc_inq_vartype() */ int rcd; rcd=nc_inq_vartype(nc_id,var_id,var_typ); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_vartype()"); return rcd; } /* end nco_inq_vartype */ int nco_inq_varndims(const int nc_id,const int var_id,int * const dmn_nbr) { /* Purpose: Wrapper for nc_inq_varndims() */ int rcd; rcd=nc_inq_varndims(nc_id,var_id,dmn_nbr); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varndims()"); return rcd; } /* end nco_inq_varndims */ int nco_inq_vardimid(const int nc_id,const int var_id,int * const dmn_id) { /* Purpose: Wrapper for nc_inq_vardimid() */ int rcd; rcd=nc_inq_vardimid(nc_id,var_id,dmn_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_vardimid()"); return rcd; } /* end nco_inq_vardimid */ int nco_inq_varnatts(const int nc_id,const int var_id,int * const nbr_att) { /* Purpose: Wrapper for nc_inq_varnatts() */ int rcd; rcd=nc_inq_varnatts(nc_id,var_id,nbr_att); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varnatts()"); return rcd; } /* end nco_inq_varnatts */ int nco_rename_var(const int nc_id,const int var_id,const char * const var_nm) { /* Purpose: Wrapper for nc_rename_var() */ int rcd; rcd=nc_rename_var(nc_id,var_id,var_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_rename_var()"); return rcd; } /* end nco_rename_var */ /* End _var */ /* Start _get _put _var */ int nco_get_var1(const int nc_id,const int var_id,const long * const srt,void * const vp,const nc_type var_typ) { /* Purpose: Wrapper for nc_get_var1_*() */ int rcd=NC_NOERR; switch(var_typ){ case NC_FLOAT: rcd=nc_get_var1_float(nc_id,var_id,(const size_t *)srt,(float *)vp); break; case NC_DOUBLE: rcd=nc_get_var1_double(nc_id,var_id,(const size_t *)srt,(double *)vp); break; case NC_INT: rcd=NCO_GET_VAR1_INT(nc_id,var_id,(const size_t *)srt,(nco_int *)vp); break; case NC_SHORT: rcd=nc_get_var1_short(nc_id,var_id,(const size_t *)srt,(nco_short *)vp); break; case NC_CHAR: rcd=NCO_GET_VAR1_CHAR(nc_id,var_id,(const size_t *)srt,(nco_char *)vp); break; case NC_BYTE: rcd=NCO_GET_VAR1_BYTE(nc_id,var_id,(const size_t *)srt,(nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_GET_VAR1_UBYTE(nc_id,var_id,(const size_t *)srt,(nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_GET_VAR1_USHORT(nc_id,var_id,(const size_t *)srt,(nco_ushort *)vp); break; case NC_UINT: rcd=NCO_GET_VAR1_UINT(nc_id,var_id,(const size_t *)srt,(nco_uint *)vp); break; case NC_INT64: rcd=NCO_GET_VAR1_INT64(nc_id,var_id,(const size_t *)srt,(nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_GET_VAR1_UINT64(nc_id,var_id,(const size_t *)srt,(nco_uint64 *)vp); break; case NC_STRING: rcd=NCO_GET_VAR1_STRING(nc_id,var_id,(const size_t *)srt,(nco_string *)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_var1()"); return rcd; } /* end nco_get_var1 */ int nco_put_var1(const int nc_id,const int var_id,const long * const srt,const void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_put_var1_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_put_var1_float(nc_id,var_id,(const size_t *)srt,(const float *)vp); break; case NC_DOUBLE: rcd=nc_put_var1_double(nc_id,var_id,(const size_t *)srt,(const double *)vp); break; case NC_INT: rcd=NCO_PUT_VAR1_INT(nc_id,var_id,(const size_t *)srt,(const nco_int *)vp); break; case NC_SHORT: rcd=nc_put_var1_short(nc_id,var_id,(const size_t *)srt,(const short *)vp); break; case NC_CHAR: rcd=NCO_PUT_VAR1_CHAR(nc_id,var_id,(const size_t *)srt,(const nco_char *)vp); break; case NC_BYTE: rcd=NCO_PUT_VAR1_BYTE(nc_id,var_id,(const size_t *)srt,(const nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_PUT_VAR1_UBYTE(nc_id,var_id,(const size_t *)srt,(const nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_PUT_VAR1_USHORT(nc_id,var_id,(const size_t *)srt,(const nco_ushort *)vp); break; case NC_UINT: rcd=NCO_PUT_VAR1_UINT(nc_id,var_id,(const size_t *)srt,(const nco_uint *)vp); break; case NC_INT64: rcd=NCO_PUT_VAR1_INT64(nc_id,var_id,(const size_t *)srt,(const nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_PUT_VAR1_UINT64(nc_id,var_id,(const size_t *)srt,(const nco_uint64 *)vp); break; /* Next line produces GCC warning: attention : passing argument 4 of ‘nc_put_var1_string’ from incompatible pointer type I think this warning occurs because this routine receives input vp as "const void * const vp", a singly indirect pointer, and then casts vp to a doubly indirect pointer on output, i.e., to something like "(const char **)vp" or "(const nco_string * const)vp". Is casting a singly-indirect pointer to a doubly-indirect ever allowed? */ /* Of the following three options we must pick one None is completely satisfactory with gcc Choose solution that allows trouble-free g++ compilation */ /* Next line produces gcc and g++ warning: attention : le transtypage annule des qualificateurs du type pointeur ciblé */ case NC_STRING: rcd=NCO_PUT_VAR1_STRING(nc_id,var_id,(const size_t *)srt,(const char **)vp); break; /* Next line produces g++ warning: erreur: invalid conversion from ‘char* const* const’ to ‘const char** */ /* case NC_STRING: rcd=NCO_PUT_VAR1_STRING(nc_id,var_id,(const size_t *)srt,(const nco_string * const)vp); break;*/ /* Next line produces g++ warning: erreur: invalid conversion from ‘char* const*’ to ‘const char** */ /* case NC_STRING: rcd=NCO_PUT_VAR1_STRING(nc_id,var_id,(const size_t *)srt,(const nco_string *)vp); break;*/ #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_put_var1()"); return rcd; } /* end nco_put_var1 */ int nco_get_vara(const int nc_id,const int var_id,const long * const srt,const long * const cnt,void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_get_vara_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_get_vara_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(float *)vp); break; case NC_DOUBLE: rcd=nc_get_vara_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(double *)vp); break; case NC_INT: rcd=NCO_GET_VARA_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_int *)vp); break; case NC_SHORT: rcd=nc_get_vara_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_short *)vp); break; case NC_CHAR: rcd=NCO_GET_VARA_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_char *)vp); break; case NC_BYTE: rcd=NCO_GET_VARA_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_GET_VARA_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_GET_VARA_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_ushort *)vp); break; case NC_UINT: rcd=NCO_GET_VARA_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_uint *)vp); break; case NC_INT64: rcd=NCO_GET_VARA_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_GET_VARA_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_uint64 *)vp); break; case NC_STRING: rcd=NCO_GET_VARA_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(nco_string *)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_vara()"); return rcd; } /* end nco_get_vara */ int nco_put_vara(const int nc_id,const int var_id,const long * const srt,const long * const cnt,const void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_put_vara_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_put_vara_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const float *)vp); break; case NC_DOUBLE: rcd=nc_put_vara_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const double *)vp); break; case NC_INT: rcd=NCO_PUT_VARA_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_int *)vp); break; case NC_SHORT: rcd=nc_put_vara_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const short *)vp); break; case NC_CHAR: rcd=NCO_PUT_VARA_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_char *)vp); break; case NC_BYTE: rcd=NCO_PUT_VARA_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_PUT_VARA_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_PUT_VARA_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_ushort *)vp); break; case NC_UINT: rcd=NCO_PUT_VARA_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_uint *)vp); break; case NC_INT64: rcd=NCO_PUT_VARA_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_PUT_VARA_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const nco_uint64 *)vp); break; /* NC_STRING prototype next causes same compiler warnings described in nco_put_var1() above */ case NC_STRING: rcd=NCO_PUT_VARA_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const char **)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_put_vara()"); return rcd; } /* end nco_put_vara */ int nco_get_vars(const int nc_id,const int var_id,const long * const srt,const long * const cnt,const long * const srd,void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_get_vars_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_get_vars_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(float *)vp); break; case NC_DOUBLE: rcd=nc_get_vars_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(double *)vp); break; case NC_INT: rcd=NCO_GET_VARS_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_int *)vp); break; case NC_SHORT: rcd=nc_get_vars_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_short *)vp); break; case NC_CHAR: rcd=NCO_GET_VARS_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_char *)vp); break; case NC_BYTE: rcd=NCO_GET_VARS_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_GET_VARS_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_GET_VARS_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_ushort *)vp); break; case NC_UINT: rcd=NCO_GET_VARS_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_uint *)vp); break; case NC_INT64: rcd=NCO_GET_VARS_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_GET_VARS_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_uint64 *)vp); break; case NC_STRING: rcd=NCO_GET_VARS_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(nco_string *)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_vars()"); return rcd; } /* end nco_get_vars */ int nco_put_vars(const int nc_id,const int var_id,const long * const srt,const long * const cnt,const long * const srd,const void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_put_vars_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_put_vars_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const float *)vp); break; case NC_DOUBLE: rcd=nc_put_vars_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const double *)vp); break; case NC_INT: rcd=NCO_PUT_VARS_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const nco_int *)vp); break; case NC_SHORT: rcd=nc_put_vars_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const short *)vp); break; case NC_CHAR: rcd=NCO_PUT_VARS_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const nco_char *)vp); break; case NC_BYTE: rcd=NCO_PUT_VARS_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_PUT_VARS_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_PUT_VARS_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const nco_ushort *)vp); break; case NC_UINT: rcd=NCO_PUT_VARS_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const nco_uint *)vp); break; case NC_INT64: rcd=NCO_PUT_VARS_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd, (const nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_PUT_VARS_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const nco_uint64 *)vp); break; /* NC_STRING prototype next causes same compiler warnings described in nco_put_var1() above */ case NC_STRING: rcd=NCO_PUT_VARS_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const char **)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_put_vars()"); return rcd; } /* end nco_put_vars */ int nco_get_varm(const int nc_id,const int var_id,const long * const srt,const long * const cnt,const long * const srd,const long * const map,void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_get_varm_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_get_varm_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(float *)vp); break; case NC_DOUBLE: rcd=nc_get_varm_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(double *)vp); break; case NC_INT: rcd=NCO_GET_VARM_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_int *)vp); break; case NC_SHORT: rcd=nc_get_varm_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_short *)vp); break; case NC_CHAR: rcd=NCO_GET_VARM_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_char *)vp); break; case NC_BYTE: rcd=NCO_GET_VARM_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_GET_VARM_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_GET_VARM_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_ushort *)vp); break; case NC_UINT: rcd=NCO_GET_VARM_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_uint *)vp); break; case NC_INT64: rcd=NCO_GET_VARM_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_GET_VARM_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_uint64 *)vp); break; case NC_STRING: rcd=NCO_GET_VARM_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(nco_string *)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_varm()"); return rcd; } /* end nco_get_varm */ int nco_put_varm(const int nc_id,const int var_id,const long * const srt,const long * const cnt,const long * const srd,const long * const map,const void * const vp,const nc_type type) { /* Purpose: Wrapper for nc_put_varm_*() */ int rcd=NC_NOERR; switch(type){ case NC_FLOAT: rcd=nc_put_varm_float(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const float *)vp); break; case NC_DOUBLE: rcd=nc_put_varm_double(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const double *)vp); break; case NC_INT: rcd=NCO_PUT_VARM_INT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_int *)vp); break; case NC_SHORT: rcd=nc_put_varm_short(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const short *)vp); break; case NC_CHAR: rcd=NCO_PUT_VARM_CHAR(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_char *)vp); break; case NC_BYTE: rcd=NCO_PUT_VARM_BYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 case NC_UBYTE: rcd=NCO_PUT_VARM_UBYTE(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_PUT_VARM_USHORT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_ushort *)vp); break; case NC_UINT: rcd=NCO_PUT_VARM_UINT(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_uint *)vp); break; case NC_INT64: rcd=NCO_PUT_VARM_INT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_PUT_VARM_UINT64(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const nco_uint64 *)vp); break; /* NC_STRING prototype next causes same compiler warnings described in nco_put_var1() above */ case NC_STRING: rcd=NCO_PUT_VARM_STRING(nc_id,var_id,(const size_t *)srt,(const size_t *)cnt,(const ptrdiff_t *)srd,(const ptrdiff_t *)map,(const char **)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_put_varm()"); return rcd; } /* end nco_put_varm */ /* End Variable routines */ /* Begin Attribute routines (_att) */ int nco_inq_att(const int nc_id,const int var_id,const char * const att_nm,nc_type * const att_typ,long * const att_sz) { /* Purpose: Wrapper for nc_inq_att() */ const char fnc_nm[]="nco_inq_att()"; int rcd; rcd=nc_inq_att(nc_id,var_id,att_nm,att_typ,(size_t *)att_sz); if(rcd != NC_NOERR){ (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco_inq_att */ int nco_inq_att_flg(const int nc_id,const int var_id,const char * const att_nm,nc_type * const att_typ,long * const att_sz) { /* Purpose: Error-tolerant wrapper for nc_inq_att(). Tolerates ENOTATT. */ const char fnc_nm[]="nco_inq_att_flg()"; int rcd; rcd=nc_inq_att(nc_id,var_id,att_nm,att_typ,(size_t *)att_sz); if(rcd == NC_ENOTATT) return rcd; if(rcd != NC_NOERR){ (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco_inq_att_flg */ int nco_inq_attid(const int nc_id,const int var_id,const char * const att_nm,int * const att_id) { /* Purpose: Wrapper for nc_inq_attid() */ int rcd; rcd=nc_inq_attid(nc_id,var_id,att_nm,att_id); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_attid()"); return rcd; } /* end nco_inq_attid */ int nco_inq_attid_flg(const int nc_id,const int var_id,const char * const att_nm,int * const att_id) { /* Purpose: Error-tolerant wrapper for nc_inq_attid(): Tolerates NC_ENOTATT. */ const char fnc_nm[]="nco_inq_attid_flg()"; int rcd; rcd=nc_inq_attid(nc_id,var_id,att_nm,att_id); if(rcd == NC_ENOTATT) return rcd; if(rcd != NC_NOERR){ (void)fprintf(stderr,"ERROR: %s unable to inquire attribute var_id: %d, att_nm: %s\n",fnc_nm,var_id,att_nm); nco_err_exit(rcd,fnc_nm); } /* endif */ return rcd; } /* end nco_inq_attid_flg */ int nco_inq_atttype(const int nc_id,const int var_id,const char * const att_nm,nc_type * const att_typ) { /* Purpose: Wrapper for nc_inq_atttype() */ int rcd; rcd=nc_inq_atttype(nc_id,var_id,att_nm,att_typ); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_atttype()"); return rcd; } /* end nco_inq_atttype */ int nco_inq_attlen(const int nc_id,const int var_id,const char * const att_nm,long * const att_sz) { /* Purpose: Wrapper for nc_inq_attlen() */ int rcd; rcd=nc_inq_attlen(nc_id,var_id,att_nm,(size_t *)att_sz); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_attlen()"); return rcd; } /* end nco_inq_attlen */ int nco_inq_attlen_flg(const int nc_id,const int var_id,const char * const att_nm,long * const att_sz) { /* Purpose: Error-tolerant wrapper for nc_inq_attlen(). Tolerates NC_ENOTATT. */ const char fnc_nm[]="nco_inq_attlen_flg()"; int rcd; rcd=nc_inq_attlen(nc_id,var_id,att_nm,(size_t *)att_sz); if(rcd == NC_ENOTATT) return rcd; if(rcd != NC_NOERR) nco_err_exit(rcd,fnc_nm); return rcd; } /* end nco_inq_attlen */ int nco_inq_attname(const int nc_id,const int var_id,const int att_id,char * const att_nm) { /* Purpose: Wrapper for nc_inq_attname() */ int rcd; rcd=nc_inq_attname(nc_id,var_id,att_id,att_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_attname()"); return rcd; } /* end nco_inq_attname */ int nco_copy_att(const int nc_id_in,const int var_id_in,const char * const att_nm,const int nc_id_out,const int var_id_out) { /* Purpose: Wrapper for nc_copy_att() */ int rcd; rcd=nc_copy_att(nc_id_in,var_id_in,att_nm,nc_id_out,var_id_out); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_copy_att()"); return rcd; } /* end nco_copy_att */ int nco_rename_att(const int nc_id,const int var_id,const char * const att_nm,const char * const att_new_nm) { /* Purpose: Wrapper for nc_rename_att() */ int rcd; rcd=nc_rename_att(nc_id,var_id,att_nm,att_new_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_rename_att()"); return rcd; } /* end nco_rename_att */ int nco_del_att(const int nc_id,const int var_id,const char * const att_nm) { /* Purpose: Wrapper for nc_del_att() */ int rcd; rcd=nc_del_att(nc_id,var_id,att_nm); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_del_att()"); return rcd; } /* end nco_del_att */ int nco_put_att(const int nc_id,const int var_id,const char * const att_nm,const nc_type att_typ,const long att_len,const void * const vp) { /* Purpose: Wrapper for nc_put_att_*() */ int rcd=NC_NOERR; switch(att_typ){ case NC_FLOAT: rcd=nc_put_att_float(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const float *)vp); break; case NC_DOUBLE: rcd=nc_put_att_double(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const double *)vp); break; case NC_INT: rcd=NCO_PUT_ATT_INT(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_int *)vp); break; case NC_SHORT: rcd=nc_put_att_short(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const short *)vp); break; case NC_CHAR: rcd=NCO_PUT_ATT_CHAR(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_char *)vp); break; case NC_BYTE: rcd=NCO_PUT_ATT_BYTE(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 /* 20051119: netCDF4 library did not support these until alpha10, still does not support nco_put/get_att_ubyte() */ case NC_UBYTE: rcd=NCO_PUT_ATT_UBYTE(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_PUT_ATT_USHORT(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_ushort *)vp); break; case NC_UINT: rcd=NCO_PUT_ATT_UINT(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_uint *)vp); break; case NC_INT64: rcd=NCO_PUT_ATT_INT64(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_PUT_ATT_UINT64(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const nco_uint64 *)vp); break; /* NC_STRING prototype next causes same compiler warnings described in nco_put_var1() above */ case NC_STRING: rcd=NCO_PUT_ATT_STRING(nc_id,var_id,att_nm,att_typ,(size_t)att_len,(const char **)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_put_att()"); return rcd; } /* end nco_put_att */ int nco_get_att(const int nc_id,const int var_id,const char * const att_nm,void * const vp,const nc_type att_typ) { /* Purpose: Wrapper for nc_get_att_*() */ int rcd=NC_NOERR; switch(att_typ){ case NC_FLOAT: rcd=nc_get_att_float(nc_id,var_id,att_nm,(float *)vp); break; case NC_DOUBLE: rcd=nc_get_att_double(nc_id,var_id,att_nm,(double *)vp); break; case NC_INT: rcd=NCO_GET_ATT_INT(nc_id,var_id,att_nm,(nco_int *)vp); break; case NC_SHORT: rcd=nc_get_att_short(nc_id,var_id,att_nm,(nco_short *)vp); break; case NC_CHAR: rcd=NCO_GET_ATT_CHAR(nc_id,var_id,att_nm,(nco_char *)vp); break; case NC_BYTE: rcd=NCO_GET_ATT_BYTE(nc_id,var_id,att_nm,(nco_byte *)vp); break; #ifdef ENABLE_NETCDF4 /* 20051119: netcdf4 library did not support these until alpha10, still does not support nco_put/get_att_ubyte() */ case NC_UBYTE: rcd=NCO_GET_ATT_UBYTE(nc_id,var_id,att_nm,(nco_ubyte *)vp); break; case NC_USHORT: rcd=NCO_GET_ATT_USHORT(nc_id,var_id,att_nm,(nco_ushort *)vp); break; case NC_UINT: rcd=NCO_GET_ATT_UINT(nc_id,var_id,att_nm,(nco_uint *)vp); break; case NC_INT64: rcd=NCO_GET_ATT_INT64(nc_id,var_id,att_nm,(nco_int64 *)vp); break; case NC_UINT64: rcd=NCO_GET_ATT_UINT64(nc_id,var_id,att_nm,(nco_uint64 *)vp); break; case NC_STRING: rcd=NCO_GET_ATT_STRING(nc_id,var_id,att_nm,(nco_string *)vp); break; #endif /* !ENABLE_NETCDF4 */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_att()"); return rcd; } /* end nco_get_att */ /* End Attribute routines */ /* Begin netCDF4 stubs */ #ifndef HAVE_NETCDF4_H /* NB: netCDF chunking/deflate define/inquire functions work only on netCDF4 files NCO stubs perform no-ops on netCDF3 files */ # ifdef NC_HAVE_NEW_CHUNKING_API /* Newer, post-200906 netCDF4 API has chk_sz as const netcdf.h signals this API with NC_HAVE_NEW_CHUNKING_API as of ~200911 */ int nc_def_var_chunking(const int nc_id,const int var_id,const int srg_typ,const size_t * const cnk_sz){return 1;} # else /* !NC_HAVE_NEW_CHUNKING_API */ /* Older, pre-200906 netCDF4 API has chk_sz as non-const */ int nc_def_var_chunking(const int nc_id,const int var_id,const int srg_typ,size_t * const cnk_sz){return 1;} # endif /* !NC_HAVE_NEW_CHUNKING_API */ int nc_inq_var_chunking(const int nc_id,const int var_id,int * const srg_typ,size_t *const cnk_sz){*srg_typ=(size_t)NC_CONTIGUOUS;*cnk_sz=(size_t)NULL;return 1;} int nc_def_var_deflate(const int nc_id,const int var_id,const int shuffle,const int deflate,const int dfl_lvl){return 1;} int nc_inq_var_deflate(const int nc_id,const int var_id,int * const shuffle, int * const deflate,int * const dfl_lvl){if(shuffle) *shuffle=0;if(deflate) *deflate=0;if(dfl_lvl) *dfl_lvl=0;return 1;} int nc_inq_var_endian(const int nc_id,const int var_id,int * const ndn_typ){if(ndn_typ) *ndn_typ=0;return 1;} int nc_def_var_fletcher32(const int nc_id,const int var_id,const int chk_typ){return 1;} int nc_inq_var_fletcher32(const int nc_id,const int var_id,int * const chk_typ){if(chk_typ) *chk_typ=NC_NOCHECKSUM;return 1;} int nc_inq_var_fill(const int nc_id,const int var_id,int * const fll_nil,void * const fll_val){if(fll_nil) *fll_nil=0;if(fll_val) assert(0);return 1;} int nc_get_chunk_cache(size_t * const sz_byt,size_t * const cnk_nbr_hsh,float * const pmp_fvr_frc){if(sz_byt) *sz_byt=0L;if(cnk_nbr_hsh) *cnk_nbr_hsh=0L;if(pmp_fvr_frc) *pmp_fvr_frc=0.0f;return 1;} int nc_set_chunk_cache(const size_t sz_byt,const size_t cnk_nbr_hsh,const float pmp_fvr_frc){return 1;} #endif /* HAVE_NETCDF4_H */ #if !defined(HAVE_NETCDF4_H) /* Stubs thus present a fake library for manipulating netCDF3 files with the netCDF4 API These are only called when netCDF4 library is unavailable, thus I/O assumed to be netCDF3 */ int nco_def_grp(const int nc_id,const char * const grp_nm,int * const grp_id){assert(0);return NC_NOERR;} int nco_rename_grp(int grp_id,const char * const grp_nm){assert(0);return NC_NOERR;} int nco_inq_grpname_full(const int nc_id,size_t * grp_nm_lng,char * const grp_nm_fll){assert(0);return NC_NOERR;} int nco_inq_grpname_len(const int nc_id,size_t * const grp_nm_lng){assert(0);return NC_NOERR;} int nco_inq_grps(const int nc_id,int * const grp_nbr,int * const grp_ids){if(grp_nbr) *grp_nbr=0;return NC_NOERR;} int nco_inq_grp_full_ncid(const int nc_id,const char * const grp_nm_fll,int * const grp_id){*grp_id=nc_id;return NC_NOERR;} int nco_inq_grp_ncid(const int nc_id,const char * const grp_nm,int * const grp_id){assert(0);return NC_NOERR;} int nco_inq_grp_parent(const int nc_id,int * const prn_id){assert(0);return NC_ENOGRP;} int nco_inq_grp_parent_flg(const int nc_id,int * const prn_id){return NC_ENOGRP;} int nco_inq_ncid_flg(const int nc_id,const char * const grp_nm,int * const grp_id){assert(0);return NC_NOERR;} int nco_inq_grp_ncid_flg(const int nc_id,const char * const grp_nm,int * const grp_id){*grp_id=nc_id;return NC_NOERR;} int nco_inq_grpname(const int nc_id,char * const grp_nm){if(grp_nm) strcpy(grp_nm,"/");return NC_NOERR;} int nco_inq_grp_full_ncid_flg(const int nc_id,const char * const grp_nm_fll,int * const grp_id){*grp_id=nc_id;return NC_NOERR;} int nco_inq_dimids(const int nc_id,int * const dmn_nbr,int * const dmn_ids,int flg_prn){ int dmn_idx; int rcd; rcd=nc_inq(nc_id,dmn_nbr,(int *)NULL,(int *)NULL,(int *)NULL); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_dimids()"); /* netCDF3 file dimension IDs range 0..N-1 */ if(dmn_ids) for(dmn_idx=0;dmn_idx<*dmn_nbr;dmn_idx++) dmn_ids[dmn_idx]=dmn_idx; return NC_NOERR; } /* end nco_inq_dimids() */ int nco_inq_unlimdims(const int nc_id,int *nbr_dmn_ult,int *dmn_ids_ult){ int rcd; int unlimid; rcd=nc_inq_unlimdim(nc_id,&unlimid); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_unlimdims()"); if(unlimid != -1){ *nbr_dmn_ult=1; if(dmn_ids_ult) dmn_ids_ult[0]=unlimid; }else{ *nbr_dmn_ult=0; } /* unlimid */ return NC_NOERR; } /* end nco_inq_unlimdims() */ int nco_inq_varids(const int nc_id,int * const var_nbr,int * const var_ids){ int rcd; /* netCDF3 files have only the root group, with variable IDs 0..N-1 */ rcd=nc_inq(nc_id,(int *)NULL,var_nbr,(int *)NULL,(int *)NULL); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_inq_varids()"); if(var_ids) for(int var_idx=0;var_idx<*var_nbr;var_idx++) var_ids[var_idx]=var_idx; return NC_NOERR; } /* end nco_inq_varids() */ #endif /* HAVE_NETCDF4_H */ #ifndef _MSC_VER #ifndef ENABLE_NETCDF4 int NCO_GET_VAR1_UBYTE(const int nc_id,const int var_id,const size_t *srt,nco_ubyte *ubp){return 1;} int NCO_GET_VAR1_USHORT(const int nc_id,const int var_id,const size_t *srt,nco_ushort *usp){return 1;} int NCO_GET_VAR1_UINT(const int nc_id,const int var_id,const size_t *srt,nco_uint *uip){return 1;} int NCO_GET_VAR1_INT64(const int nc_id,const int var_id,const size_t *srt,nco_int64 *i64p){return 1;} int NCO_GET_VAR1_UINT64(const int nc_id,const int var_id,const size_t *srt,nco_uint64 *ui64p){return 1;} int NCO_GET_VAR1_STRING(const int nc_id,const int var_id,const size_t *srt,nco_string *sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_PUT_VAR1_UBYTE(const int nc_id,const int var_id,const size_t *srt,const nco_ubyte *ubp){return 1;} int NCO_PUT_VAR1_USHORT(const int nc_id,const int var_id,const size_t *srt,const nco_ushort *usp){return 1;} int NCO_PUT_VAR1_UINT(const int nc_id,const int var_id,const size_t *srt,const nco_uint *uip){return 1;} int NCO_PUT_VAR1_INT64(const int nc_id,const int var_id,const size_t *srt,const nco_int64 *i64p){return 1;} int NCO_PUT_VAR1_UINT64(const int nc_id,const int var_id,const size_t *srt,const nco_uint64 *ui64p){return 1;} int NCO_PUT_VAR1_STRING(const int nc_id,const int var_id,const size_t *srt,const char **sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_GET_VARA_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_ubyte *ubp){return 1;} int NCO_GET_VARA_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_ushort *usp){return 1;} int NCO_GET_VARA_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_uint *uip){return 1;} int NCO_GET_VARA_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_int64 *i64p){return 1;} int NCO_GET_VARA_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_uint64 *ui64p){return 1;} int NCO_GET_VARA_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,nco_string *sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_PUT_VARA_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const nco_ubyte *ubp){return 1;} int NCO_PUT_VARA_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const nco_ushort *usp){return 1;} int NCO_PUT_VARA_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const nco_uint *uip){return 1;} int NCO_PUT_VARA_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const nco_int64 *i64p){return 1;} int NCO_PUT_VARA_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const nco_uint64 *ui64p){return 1;} int NCO_PUT_VARA_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const char **sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_GET_VARS_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_ubyte *ubp){return 1;} int NCO_GET_VARS_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_ushort *usp){return 1;} int NCO_GET_VARS_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_uint *uip){return 1;} int NCO_GET_VARS_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_int64 *i64p){return 1;} int NCO_GET_VARS_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_uint64 *ui64p){return 1;} int NCO_GET_VARS_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,nco_string *sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_PUT_VARS_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const nco_ubyte *ubp){return 1;} int NCO_PUT_VARS_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd, const nco_ushort *usp){return 1;} int NCO_PUT_VARS_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd, const nco_uint *uip){return 1;} int NCO_PUT_VARS_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd, const nco_int64 *i64p){return 1;} int NCO_PUT_VARS_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const nco_uint64 *ui64p){return 1;} int NCO_PUT_VARS_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const char **sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_GET_VARM_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_ubyte *ubp){return 1;} int NCO_GET_VARM_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_ushort *usp){return 1;} int NCO_GET_VARM_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_uint *uip){return 1;} int NCO_GET_VARM_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_int64 *i64p){return 1;} int NCO_GET_VARM_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_uint64 *ui64p){return 1;} int NCO_GET_VARM_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,nco_string *sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 int NCO_PUT_VARM_UBYTE(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const nco_ubyte *ubp){return 1;} int NCO_PUT_VARM_USHORT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const nco_ushort *usp){return 1;} int NCO_PUT_VARM_UINT(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const nco_uint *uip){return 1;} int NCO_PUT_VARM_INT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const nco_int64 *i64p){return 1;} int NCO_PUT_VARM_UINT64(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const nco_uint64 *ui64p){return 1;} int NCO_PUT_VARM_STRING(const int nc_id,const int var_id,const size_t *srt,const size_t *cnt,const ptrdiff_t *srd,const ptrdiff_t *map,const char **sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 /* 20051119: netcdf4 library did not support these until alpha10, still does not support nco_put/get_att_ubyte() */ int NCO_PUT_ATT_UBYTE(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const nco_ubyte *ubp){return 1;} int NCO_PUT_ATT_USHORT(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const nco_ushort *usp){return 1;} int NCO_PUT_ATT_UINT(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const nco_uint *uip){return 1;} int NCO_PUT_ATT_INT64(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const nco_int64 *i64p){return 1;} int NCO_PUT_ATT_UINT64(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const nco_uint64 *ui64p){return 1;} int NCO_PUT_ATT_STRING(const int nc_id,const int var_id,const char *att_nm,const nc_type att_typ,size_t att_len,const char **sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #ifndef ENABLE_NETCDF4 /* 20051119: netcdf4 library did not support these until alpha10, still does not support nco_put/get_att_ubyte() */ int NCO_GET_ATT_UBYTE(const int nc_id,const int var_id,const char *att_nm,nco_ubyte *ubp){return 1;} int NCO_GET_ATT_USHORT(const int nc_id,const int var_id,const char *att_nm,nco_ushort *usp){return 1;} int NCO_GET_ATT_UINT(const int nc_id,const int var_id,const char *att_nm,nco_uint *uip){return 1;} int NCO_GET_ATT_INT64(const int nc_id,const int var_id,const char *att_nm,nco_int64 *i64p){return 1;} int NCO_GET_ATT_UINT64(const int nc_id,const int var_id,const char *att_nm,nco_uint64 *ui64p){return 1;} int NCO_GET_ATT_STRING(const int nc_id,const int var_id,const char *att_nm,nco_string *sngp){return 1;} #endif /* ENABLE_NETCDF4 */ #endif /* _MSC_VER */ /* end netCDF4 stubs */ ./nco-4.4.2/src/nco/nco_mpi.h0000644000674300045400000000656512260451232015131 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_mpi.h,v 1.22 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: MPI utilities */ /* NB: Currently this header is only accessed by main() MPI programs Hence it is not (yet) part of libnco.a Header assumes its inclusion is already conditional on ENABLE_MPI Header is currently mostly for file-scope constants needed by MPI routines No functions (yet) but some will eventually live here after MPI functionalization Adding functions will require creating a corresponding *.c file *.c files must reside in libnco.a or link separately to MPI executables The latter would slightly complicate the build procedure I am not yet sure I want _any_ MPI dependencies in libnco.a Cross-platform link weirdness (e.g., AIX) makes avoiding this desirable */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_mpi.h" *//* MPI utilities */ #ifndef NCO_MPI_H #define NCO_MPI_H /* Standard header files */ #include /* Signal handling */ /* 3rd party vendors */ /* Personal headers */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ const int msg_bfr_lng=3; /* [nbr] Number of elements in msg_bfr */ const int wrk_id_bfr_lng=1; /* [nbr] Number of elements in wrk_id_bfr */ /* Sleep interval between successive write token requests fxm: TODO nco609 tune or remove this */ const double tkn_wrt_rqs_ntv=0.04; /* [s] Token request interval */ /* Convention is to assign manager responsibilities to rank 0 process NB: Manager rank must be < number of processes */ const int rnk_mgr=0; /* [idx] Manager rank */ /* Pass idx_all_wrk_ass in place of variable ID when all variables assigned Values for idx_all_wrk_ass must be exclusive of valid variable IDs Hence use a negative integer to signify idx_all_wrk_ass */ const int idx_all_wrk_ass=-1; /* [enm] All variables already assigned */ /* NB: Message fields must begin in location zero */ /* fxm: Define message structures rather than int arrays */ const int msg_lmn_tkn_wrt_rsp=0; /* [idx] Location of response */ /* Requests for the write token have two possible responses */ enum tkn_wrt_rsp_val{ /* [enm] Valid responses to write token requests */ tkn_wrt_rqs_dny, /* Deny request for write token (must wait and re-request) */ tkn_wrt_rqs_xcp /* Accept request for write token, OK to write */ }; /* end tkn_wrt_rsp_val enum */ /* These (and MPI_ANY_TAG) are valid entries for the MPI message tag field Processes may request to filter messages based on any of these tags */ enum nco_msg_tag_typ{ /* [enm] MPI message tag */ msg_tag_wrk_done, /* Notification that work is complete */ msg_tag_wrk_rqs, /* Request for work */ msg_tag_wrk_rsp, /* Response to work request */ msg_tag_tkn_wrt_rqs, /* Request for write token */ msg_tag_tkn_wrt_rsp /* Response to write token request */ }; /* end nco_msg_tag_typ enum */ const int nco_spn_lck_us=100; /* [us] Spinlock sleep interval */ int nco_spn_lck_brk=0; /* [nbr] Break spin lock, resume execution */ void nco_cnt_run(int signo); /* Signal handler */ void nco_cnt_run(int signo){nco_spn_lck_brk=1+0*signo;} /* Signal handler, CEWI */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_MPI_H */ ./nco-4.4.2/src/nco/ncks.c0000644000674300045400000014314212300513545014430 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncks.c,v 1.710 2014/02/17 23:12:37 zender Exp $ */ /* ncks -- netCDF Kitchen Sink */ /* Purpose: Extract (subsets of) variables from a netCDF file Print them to screen, or copy them to a new file, or both */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* URL: http://nco.cvs.sf.net/nco/nco/src/nco/ncks.c Usage: ncks ~/nco/data/in.nc ncks -v one ~/nco/data/in.nc ncks ~/nco/data/in.nc ~/foo.nc ncks -O -4 ~/nco/data/in.nc ~/foo.nc ncks -v one ~/nco/data/in.nc ~/foo.nc ncks -p /ZENDER/tmp -l /data/zender/tmp h0001.nc ~/foo.nc ncks -s "%+16.10f\n" -H -C -v three_dmn_var ~/nco/data/in.nc ncks -H -v fl_nm,fl_nm_arr ~/nco/data/in.nc ncks -H -C -u -d wvl,'0.4 micron','0.7 micron' -v wvl ~/nco/data/in.nc ncks -H -d fl_dim,1 -d char_dim,6,12 -v fl_nm,fl_nm_arr ~/nco/data/in.nc ncks -H -m -v char_var_nul,char_var_space,char_var_multinul ~/nco/data/in.nc ncks -H -C -v three_dmn_rec_var -d time,,,2 ~/nco/data/in.nc ncks -H -C -v lon -d lon,3,1 ~/nco/data/in.nc ncks -M -p http://thredds-test.ucar.edu/thredds/dodsC/testdods in.nc ncks -O -v one -p http://thredds-test.ucar.edu/thredds/dodsC/testdods in.nc ~/foo.nc ncks -O -G foo ~/nco/data/in.nc ~/foo.nc ncks -O -G :-5 -v v7 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -G level3name:-5 -v v7 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -v time ~/in_grp.nc ~/foo.nc ncks -O --sysconf ~/in_grp.nc ~/foo.nc ncks -C --xml_spr_chr=', ' -v two_dmn_rec_var_sng ~/nco/data/in.nc ncks --cdl -v one_dmn_rec_var ~/nco/data/in.nc ncks --jsn -C -v one_dmn_rec_var ~/nco/data/in.nc ncks --jsn -C -m -v one_dmn_rec_var ~/nco/data/in_grp.nc ncks -O -m -M -v Snow_Cover_Monthly_CMG ${DATA}/hdf/MOD10CM.A2007001.005.2007108111758.hdf */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* assert() */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { nco_bool ALPHABETIZE_OUTPUT=True; /* Option a */ nco_bool EXCLUDE_INPUT_LIST=False; /* Option x */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_NOCLOBBER=False; /* Option no-clobber */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool GET_GRP_INFO=False; /* [flg] Iterate file, get group extended information */ nco_bool GET_FILE_INFO=False; /* [flg] Get file information (#groups, #dimensions, #attributes, #variables) */ nco_bool GET_PRG_INFO=False; /* [flg] Get compiled program information (e.g., libraries) */ nco_bool GET_LIST=False; /* [flg] Iterate file, print variables and exit */ nco_bool GRP_VAR_UNN=False; /* [flg] Select union of specified groups and variables */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool HAVE_LIMITS=False; /* [flg] Are there user limits? (-d) */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ nco_bool PRN_CDL=False; /* [flg] Print CDL */ nco_bool PRN_HDN=False; /* [flg] Print hidden attributes */ nco_bool PRN_SRM=False; /* [flg] Print ncStream */ nco_bool PRN_JSN=False; /* [flg] Print JSON */ nco_bool PRN_XML=False; /* [flg] Print XML (NcML) */ nco_bool PRN_XML_LOCATION=True; /* [flg] Print XML location tag */ nco_bool PRN_DMN_IDX_CRD_VAL=True; /* [flg] Print leading dimension/coordinate indices/values Option Q */ nco_bool PRN_DMN_UNITS=False; /* [flg] Print dimensional units Option u */ nco_bool PRN_DMN_VAR_NM=True; /* [flg] Print dimension/variable names */ nco_bool PRN_DMN_UNITS_TGL=False; /* [flg] Toggle print dimensional units Option u */ nco_bool PRN_GLB_METADATA=False; /* [flg] Print global metadata */ nco_bool PRN_GLB_METADATA_TGL=False; /* [flg] Toggle print global metadata Option M */ nco_bool PRN_MSS_VAL_BLANK=True; /* [flg] Print missing values as blanks */ nco_bool PRN_QUIET=False; /* [flg] Turn off all printing to screen */ nco_bool PRN_VAR_DATA=False; /* [flg] Print variable data */ nco_bool PRN_VAR_DATA_TGL=False; /* [flg] Toggle print variable data Option H */ nco_bool PRN_VAR_METADATA=False; /* [flg] Print variable metadata */ nco_bool PRN_VAR_METADATA_TGL=False; /* [flg] Toggle print variable metadata Option m */ nco_bool PRN_VRB=False; /* [flg] Print data and metadata by default */ nco_bool PRN_NEW_FMT=False; /* [flg] Print using new print format */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=True; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option a */ char **fl_lst_in; char **grp_lst_in=NULL; char **var_lst_in=NULL; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *dlm_sng=NULL; char *fl_bnr=NULL; /* [sng] Unformatted binary output file */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *rec_dmn_nm=NULL; /* [sng] Record dimension name */ char *rec_dmn_nm_fix=NULL; /* [sng] Record dimension name (Original input name without _fix prefix) */ char *smr_sng=NULL; /* [sng] File summary string */ char *smr_xtn_sng=NULL; /* [sng] File extended summary string */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char *spr_chr=NULL; /* [sng] Separator for XML character types */ char *spr_nmr=NULL; /* [sng] Separator for XML numeric types */ char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncks.c,v 1.710 2014/02/17 23:12:37 zender Exp $"; const char * const CVS_Revision="$Revision: 1.710 $"; const char * const opt_sht_lst="34567aABb:CcD:d:FG:g:HhL:l:MmOo:Pp:qQrRs:uv:X:xz-:"; cnk_sct cnk; /* [sct] Chunking structure */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ extern char *optarg; extern int optind; FILE *fp_bnr=NULL; /* [fl] Unformatted binary output file handle */ gpe_sct *gpe=NULL; /* [sng] Group Path Editing (GPE) structure */ int abb_arg_nbr=0; int att_glb_nbr; int att_grp_nbr; int att_var_nbr; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int dmn_nbr_fl; int dmn_rec_fl; int fl_in_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Input file format */ int fl_nbr=0; int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int grp_dpt_fl; /* [nbr] Maximum group depth (root = 0) */ int grp_lst_in_nbr=0; /* [nbr] Number of groups explicitly specified by user */ int grp_nbr_fl; int idx; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int opt; int rcd=NC_NOERR; /* [rcd] Return code */ int var_lst_in_nbr=0; int var_nbr_fl; int var_ntm_fl; int xtr_nbr=0; /* xtr_nbr will not otherwise be set for -c with no -v */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ trv_tbl_sct *trv_tbl=NULL; /* [lst] Traversal table */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cdl",no_argument,0,0}, /* [flg] Print CDL */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"md5_dgs",no_argument,0,0}, /* [flg] Perform MD5 digests */ {"md5_digest",no_argument,0,0}, /* [flg] Perform MD5 digests */ {"md5_wrt_att",no_argument,0,0}, /* [flg] Write MD5 digests as attributes */ {"md5_write_attribute",no_argument,0,0}, /* [flg] Write MD5 digests as attributes */ {"cmp",no_argument,0,0}, {"compiler",no_argument,0,0}, {"id",no_argument,0,0}, /* [flg] Print normally hidden information, like file, group, and variable IDs */ {"hdn",no_argument,0,0}, /* [flg] Print hidden attributes */ {"hidden",no_argument,0,0}, /* [flg] Print hidden attributes */ {"lbr",no_argument,0,0}, {"library",no_argument,0,0}, {"mpi_implementation",no_argument,0,0}, {"msa_usr_rdr",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"msa_user_order",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"no_blank",no_argument,0,0}, /* [flg] Print numeric missing values */ {"no-blank",no_argument,0,0}, /* [flg] Print numeric missing values */ {"noblank",no_argument,0,0}, /* [flg] Print numeric missing values */ {"no_clb",no_argument,0,0}, {"noclobber",no_argument,0,0}, {"no-clobber",no_argument,0,0}, {"no_clobber",no_argument,0,0}, {"no_dmn_var_nm",no_argument,0,0}, /* [flg] Print dimension/variable names */ {"no_nm_prn",no_argument,0,0}, /* [flg] Print dimension/variable names */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"secret",no_argument,0,0}, {"shh",no_argument,0,0}, {"srm",no_argument,0,0}, /* [flg] Print ncStream */ {"sysconf",no_argument,0,0}, /* [flg] Perform sysconf() test */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"intersection",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"nsx",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"union",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"unn",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, {"jsn",no_argument,0,0}, /* [flg] Print JSON */ {"json",no_argument,0,0}, /* [flg] Print JSON */ {"w10",no_argument,0,0}, /* [flg] Print JSON */ {"w10n",no_argument,0,0}, /* [flg] Print JSON */ {"xml",no_argument,0,0}, /* [flg] Print XML (NcML) */ {"ncml",no_argument,0,0}, /* [flg] Print XML (NcML) */ {"xml_no_location",no_argument,0,0}, /* [flg] Omit XML location tag */ {"ncml_no_location",no_argument,0,0}, /* [flg] Omit XML location tag */ /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"file_format",required_argument,0,0}, {"fix_rec_dmn",required_argument,0,0}, /* [sng] Fix record dimension */ {"no_rec_dmn",required_argument,0,0}, /* [sng] Fix record dimension */ {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, {"mk_rec_dmn",required_argument,0,0}, /* [sng] Name of record dimension in output */ {"mk_rec_dim",required_argument,0,0}, /* [sng] Name of record dimension in output */ {"tst_udunits",required_argument,0,0}, {"xml_spr_chr",required_argument,0,0}, /* [flg] Separator for XML character types */ {"xml_spr_nmr",required_argument,0,0}, /* [flg] Separator for XML numeric types */ /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"abc",no_argument,0,'a'}, {"alphabetize",no_argument,0,'a'}, {"append",no_argument,0,'A'}, {"apn",no_argument,0,'A'}, {"bnr",required_argument,0,'b'}, {"binary",required_argument,0,'b'}, {"binary-file",required_argument,0,'b'}, {"fl_bnr",required_argument,0,'b'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"data",required_argument,0,'H'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"gpe",required_argument,0,'G'}, /* [sng] Group Path Edit (GPE) */ {"grp",required_argument,0,'g'}, {"group",required_argument,0,'g'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"hieronymus",no_argument,0,'H'}, /* fxm: need better mnemonic for -H */ {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"lcl",required_argument,0,'l'}, {"local",required_argument,0,'l'}, {"metadata",no_argument,0,'m'}, {"mtd",no_argument,0,'m'}, {"Metadata",no_argument,0,'M'}, {"Mtd",no_argument,0,'M'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"print",required_argument,0,'P'}, {"prn",required_argument,0,'P'}, {"path",required_argument,0,'p'}, {"quiet",no_argument,0,'q'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"sng_fmt",required_argument,0,'s'}, {"string",required_argument,0,'s'}, {"units",no_argument,0,'u'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {"get_grp_info",no_argument,0,0}, {"get_prg_info",no_argument,0,0}, {"get_file_info",no_argument,0,0}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif bfr_sz */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk_dmn */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_scl */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk_map */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk_plc */ if(!strcmp(opt_crr,"cmp") || !strcmp(opt_crr,"compiler")){ (void)fprintf(stdout,"%s\n",nco_cmp_get()); nco_exit(EXIT_SUCCESS); } /* endif "cmp" */ if(!strcmp(opt_crr,"cdl")) PRN_CDL=True; /* [flg] Print CDL */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fix_rec_dmn") || !strcmp(opt_crr,"no_rec_dmn")){ const char fix_pfx[]="fix_"; /* [sng] Prefix string to fix dimension */ rec_dmn_nm=(char *)nco_malloc((strlen(fix_pfx)+strlen(optarg)+1L)*sizeof(char)); rec_dmn_nm=strcpy(rec_dmn_nm,fix_pfx); rec_dmn_nm=strcat(rec_dmn_nm,optarg); rec_dmn_nm_fix=strdup(optarg); } /* endif fix_rec_dmn */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"get_grp_info") || !strcmp(opt_crr,"grp_info_get")) GET_GRP_INFO=True; if(!strcmp(opt_crr,"get_file_info")) GET_FILE_INFO=True; if(!strcmp(opt_crr,"get_prg_info")) GET_PRG_INFO=True; if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdn") || !strcmp(opt_crr,"hidden")) PRN_HDN=True; /* [flg] Print hidden attributes */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"lbr") || !strcmp(opt_crr,"library")){ (void)nco_lbr_vrs_prn(); nco_exit(EXIT_SUCCESS); } /* endif "lbr" */ if(!strcmp(opt_crr,"mk_rec_dmn") || !strcmp(opt_crr,"mk_rec_dim")) rec_dmn_nm=strdup(optarg); if(!strcmp(opt_crr,"mpi_implementation")){ (void)fprintf(stdout,"%s\n",nco_mpi_get()); nco_exit(EXIT_SUCCESS); } /* endif "mpi" */ if(!strcmp(opt_crr,"md5_dgs") || !strcmp(opt_crr,"md5_digest")){ if(!md5) md5=nco_md5_ini(); md5->dgs=True; if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Will perform MD5 digests of input and output hyperslabs\n",nco_prg_nm_get()); } /* endif "md5_dgs" */ if(!strcmp(opt_crr,"md5_wrt_att") || !strcmp(opt_crr,"md5_write_attribute")){ if(!md5) md5=nco_md5_ini(); md5->wrt=md5->dgs=True; if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Will write MD5 digests as attributes\n",nco_prg_nm_get()); } /* endif "md5_wrt_att" */ if(!strcmp(opt_crr,"msa_usr_rdr") || !strcmp(opt_crr,"msa_user_order")) MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ if(!strcmp(opt_crr,"no_blank") || !strcmp(opt_crr,"no-blank") || !strcmp(opt_crr,"noblank")) PRN_MSS_VAL_BLANK=!PRN_MSS_VAL_BLANK; if(!strcmp(opt_crr,"no_clb") || !strcmp(opt_crr,"no-clobber") || !strcmp(opt_crr,"no_clobber") || !strcmp(opt_crr,"noclobber")) FORCE_NOCLOBBER=!FORCE_NOCLOBBER; if(!strcmp(opt_crr,"no_dmn_var_nm") || !strcmp(opt_crr,"no_nm_prn")) PRN_DMN_VAR_NM=False; if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"secret") || !strcmp(opt_crr,"scr") || !strcmp(opt_crr,"shh")){ (void)fprintf(stdout,"Hidden/unsupported NCO options:\nCompiler used\t\t--cmp, --compiler\nHidden functions\t--scr, --ssh, --secret\nLibrary used\t\t--lbr, --library\nMemory clean\t\t--mmr_cln, --cln, --clean\nMemory dirty\t\t--mmr_drt, --drt, --dirty\nMPI implementation\t--mpi_implementation\nNameless printing\t--no_nm_prn, --no_dmn_var_nm\nNo-clobber files\t--no_clb, --no-clobber\nPseudonym\t\t--pseudonym, -Y (ncra only)\nStreams\t\t\t--srm\nSysconf\t\t\t--sysconf\nTest UDUnits\t\t--tst_udunits,'units_in','units_out','cln_sng'? \nVersion\t\t\t--vrs, --version\n\n"); nco_exit(EXIT_SUCCESS); } /* endif "shh" */ if(!strcmp(opt_crr,"srm")) PRN_SRM=True; /* [flg] Print ncStream */ if(!strcmp(opt_crr,"sysconf")){ long maxrss; /* [B] Maximum resident set size */ maxrss=nco_mmr_usg_prn((int)0); maxrss+=0; /* CEWI */ nco_exit(EXIT_SUCCESS); } /* endif "sysconf" */ if(!strcmp(opt_crr,"tst_udunits")){ /* Use this feature with, e.g., ncks --tst_udunits='5 meters',centimeters ~/nco/data/in.nc ncks --tst_udunits='days since 1918-11-11','days since 1939-09-09',standard ~/nco/data/in.nc ncks --tst_udunits='days since 1918-11-11','days since 1939-09-09',360_day ~/nco/data/in.nc ncks --tst_udunits='days since 1918-11-11','days since 1939-09-09',365_day ~/nco/data/in.nc ncks --tst_udunits='days since 1918-11-11','days since 1939-09-09',366_day ~/nco/data/in.nc */ char *cp; char **args; double crr_val; #ifndef ENABLE_UDUNITS (void)fprintf(stdout,"%s: Build NCO with UDUnits support to use this option\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); #endif /* !ENABLE_UDUNITS */ cp=strdup(optarg); args=nco_lst_prs_1D(cp,",",&lmt_nbr); nco_cln_clc_org(args[0],args[1],(lmt_nbr > 2 ? nco_cln_get_cln_typ(args[2]) : cln_nil),&crr_val); (void)fprintf(stdout,"Units in=%s, units out=%s, difference (date) or conversion (non-date) = %f\n",args[0],args[1],crr_val); if(cp) cp=(char *)nco_free(cp); nco_exit(EXIT_SUCCESS); } /* endif "tst_udunits" */ if(!strcmp(opt_crr,"unn") || !strcmp(opt_crr,"union")) GRP_VAR_UNN=True; if(!strcmp(opt_crr,"nsx") || !strcmp(opt_crr,"intersection")) GRP_VAR_UNN=False; if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; if(!strcmp(opt_crr,"jsn") || !strcmp(opt_crr,"json") || !strcmp(opt_crr,"w10") || !strcmp(opt_crr,"w10n")) PRN_JSN=True; /* [flg] Print JSON */ if(!strcmp(opt_crr,"xml") || !strcmp(opt_crr,"ncml")) PRN_XML=True; /* [flg] Print XML (NcML) */ if(!strcmp(opt_crr,"xml_no_location") || !strcmp(opt_crr,"ncml_no_location")){PRN_XML_LOCATION=False;PRN_XML=True;} /* [flg] Print XML location tag */ if(!strcmp(opt_crr,"xml_spr_chr")){spr_chr=(char *)strdup(optarg);PRN_XML=True;} /* [flg] Separator for XML character types */ if(!strcmp(opt_crr,"xml_spr_nmr")){spr_nmr=(char *)strdup(optarg);PRN_XML=True;} /* [flg] Separator for XML numeric types */ } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '5': /* Print using new print format */ PRN_NEW_FMT=!PRN_NEW_FMT; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Toggle ALPHABETIZE_OUTPUT */ ALPHABETIZE_OUTPUT=!ALPHABETIZE_OUTPUT; break; case 'b': /* Set file for binary output */ fl_bnr=(char *)strdup(optarg); break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=!EXTRACT_ASSOCIATED_COORDINATES; break; case 'c': /* Add all coordinates to extraction list? */ EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; HAVE_LIMITS=True; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'G': /* Apply Group Path Editing (GPE) to output group */ gpe=nco_gpe_prs_arg(optarg); /* fl_out_fmt=NC_FORMAT_NETCDF4; */ break; case 'g': /* Copy group argument for later processing */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); grp_lst_in=nco_lst_prs_2D(optarg_lcl,",",&grp_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'H': /* Toggle printing data to screen */ PRN_VAR_DATA_TGL=True; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'm': /* Toggle printing variable metadata to screen */ PRN_VAR_METADATA_TGL=True; break; case 'M': /* Toggle printing global metadata to screen */ PRN_GLB_METADATA_TGL=True; break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'P': /* Print data to screen, maximal verbosity */ PRN_VRB=True; EXTRACT_ASSOCIATED_COORDINATES=!EXTRACT_ASSOCIATED_COORDINATES; break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'q': /* [flg] Turn off all printing to screen */ PRN_QUIET=True; /* [flg] Turn off all printing to screen */ break; case 'Q': /* Turn off printing of dimension indices and coordinate values */ PRN_DMN_IDX_CRD_VAL=!PRN_DMN_IDX_CRD_VAL; break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 's': /* User specified delimiter string for printed output */ dlm_sng=(char *)strdup(optarg); break; case 'u': /* Toggle printing dimensional units */ PRN_DMN_UNITS_TGL=True; break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ HAVE_LIMITS=True; break; case 'x': /* Exclude rather than extract groups and variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'z': /* Print absolute path of all input variables then exit */ GET_LIST=True; break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Initialize traversal table */ (void)trv_tbl_init(&trv_tbl); /* Get program info for regressions tests */ if(GET_PRG_INFO) nco_get_prg_info(); /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); /* Construct GTT (Group Traversal Table), check -v and -g input names and create extraction list*/ (void)nco_bld_trv_tbl(in_id,trv_pth,lmt_nbr,lmt_arg,aux_nbr,aux_arg,MSA_USR_RDR,FORTRAN_IDX_CNV,grp_lst_in,grp_lst_in_nbr,var_lst_in,xtr_nbr,EXTRACT_ALL_COORDINATES,GRP_VAR_UNN,EXCLUDE_INPUT_LIST,EXTRACT_ASSOCIATED_COORDINATES,&flg_dne,trv_tbl); /* Check if all input -d dimensions were found */ (void)nco_chk_dmn(lmt_nbr,flg_dne); /* Get number of variables, dimensions, and global attributes in file */ (void)trv_tbl_inq(&att_glb_nbr,&att_grp_nbr,&att_var_nbr,&dmn_nbr_fl,&dmn_rec_fl,&grp_dpt_fl,&grp_nbr_fl,&var_ntm_fl,&var_nbr_fl,trv_tbl); /* Make output and input files consanguinous */ (void)nco_inq_format(in_id,&fl_in_fmt); if(fl_out && fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt; /* Process -z option if requested */ if(GET_LIST){ if(ALPHABETIZE_OUTPUT) trv_tbl_srt(trv_tbl); trv_tbl_prn(trv_tbl); goto close_and_free; } /* end GET_LIST */ /* Process --get_grp_info option if requested */ if(GET_GRP_INFO){ nco_prn_trv_tbl(in_id,trv_tbl); goto close_and_free; } /* end GET_GRP_INFO */ /* Process --get_file_info option if requested */ if(GET_FILE_INFO){ (void)fprintf(stderr,"%s: INFO reports file information\n",nco_prg_nm_get()); (void)fprintf(stdout,"%d subgroups, %d fixed dimensions, %d record dimensions, %d group + global attributes, %d atomic-type variables, %d non-atomic variables\n",grp_nbr_fl,trv_tbl->nbr_dmn-dmn_rec_fl,dmn_rec_fl,att_glb_nbr+att_glb_nbr,var_nbr_fl,var_ntm_fl); goto close_and_free; } /* end GET_FILE_INFO */ if(ALPHABETIZE_OUTPUT) trv_tbl_srt(trv_tbl); /* We now have final list of variables to extract. Phew. */ if(fl_out){ /* Copy everything (all data and metadata) to output file by default */ if(PRN_VAR_DATA_TGL) PRN_VAR_DATA=False; else PRN_VAR_DATA=True; if(PRN_VAR_METADATA_TGL) PRN_VAR_METADATA=False; else PRN_VAR_METADATA=True; if(PRN_GLB_METADATA_TGL) PRN_GLB_METADATA=False; else PRN_GLB_METADATA=True; if(FORCE_APPEND){ /* When appending, do not copy global metadata by default */ if(var_lst_in) PRN_GLB_METADATA=False; else PRN_GLB_METADATA=True; if(PRN_GLB_METADATA_TGL) PRN_GLB_METADATA=!PRN_GLB_METADATA; } /* !FORCE_APPEND */ }else{ /* !fl_out */ /* Only input file is specified, so some printing should occur */ if(PRN_VRB || (!PRN_VAR_DATA_TGL && !PRN_VAR_METADATA_TGL && !PRN_GLB_METADATA_TGL)){ /* Verbose printing simply means assume user wants deluxe frills by default */ if(PRN_DMN_UNITS_TGL) PRN_DMN_UNITS=False; else PRN_DMN_UNITS=True; if(PRN_VAR_DATA_TGL) PRN_VAR_DATA=False; else PRN_VAR_DATA=True; if(PRN_VAR_METADATA_TGL) PRN_VAR_METADATA=False; else PRN_VAR_METADATA=True; /* Assume user wants global metadata unless variable extraction is invoked */ if(var_lst_in == NULL) PRN_GLB_METADATA=True; if(PRN_GLB_METADATA_TGL) PRN_GLB_METADATA=!PRN_GLB_METADATA; }else{ /* end if PRN_VRB */ /* Default is to print data and metadata to screen if output file is not specified */ if(PRN_DMN_UNITS_TGL) PRN_DMN_UNITS=True; else PRN_DMN_UNITS=False; if(PRN_VAR_DATA_TGL) PRN_VAR_DATA=True; else PRN_VAR_DATA=False; if(PRN_VAR_METADATA_TGL) PRN_VAR_METADATA=True; else PRN_VAR_METADATA=False; if(PRN_GLB_METADATA_TGL) PRN_GLB_METADATA=True; else PRN_GLB_METADATA=False; } /* !PRN_VRB */ /* PRN_QUIET turns off all printing to screen */ if(PRN_QUIET) PRN_VAR_DATA=PRN_VAR_METADATA=PRN_GLB_METADATA=False; } /* !fl_out */ if(fl_bnr && !fl_out){ /* Native binary files depend on writing netCDF file to enter generic I/O logic */ (void)fprintf(stdout,"%s: ERROR Native binary files cannot be written unless netCDF output filename also specified. HINT: Repeat command with dummy netCDF file specified for output file (e.g., -o foo.nc)\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* endif fl_bnr */ if(gpe){ if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Group Path Edit (GPE) feature enabled\n",nco_prg_nm_get()); if(fl_out && fl_out_fmt != NC_FORMAT_NETCDF4 && nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: WARNING Group Path Edit (GPE) requires netCDF4 output format in most cases (except flattening) but user explicitly requested output format = %s. This command will fail if the output file requires netCDF4 features like groups, non-atomic types, or multiple record dimensions. However, it _will_ autoconvert netCDF4 atomic types (e.g., NC_STRING, NC_UBYTE...) to netCDF3 atomic types (e.g., NC_CHAR, NC_SHORT...).\n",nco_prg_nm_get(),nco_fmt_sng(fl_out_fmt)); } /* !gpe */ if(fl_out){ /* Output file was specified so PRN_ tokens refer to (meta)data copying */ int out_id; /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt; /* Verify output file format supports requested actions */ (void)nco_fl_fmt_vet(fl_out_fmt,cnk_nbr,dfl_lvl); /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); /* Create structure with all chunking information */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) rcd+=nco_cnk_ini(fl_out,cnk_arg,cnk_nbr,cnk_map,cnk_plc,cnk_sz_byt,cnk_sz_scl,&cnk); if(nco_dbg_lvl >= nco_dbg_dev) (void)nco_prn_var(in_id,trv_tbl); if(nco_dbg_lvl >= nco_dbg_dev) (void)nco_prn_var(out_id,trv_tbl); /* Define extracted groups, variables, and attributes in output file */ (void)nco_xtr_dfn(in_id,out_id,&cnk,dfl_lvl,gpe,md5,PRN_GLB_METADATA,PRN_VAR_METADATA,nco_pck_plc_nil,rec_dmn_nm,trv_tbl); /* Catenate timestamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); if(HISTORY_APPEND) (void)nco_vrs_att_cat(out_id); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* [fnc] Open unformatted binary data file for writing */ if(fl_bnr) fp_bnr=nco_bnr_open(fl_bnr); /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; /* Write extracted data to output file */ if(PRN_VAR_DATA) (void)nco_xtr_wrt(in_id,out_id,gpe,fp_bnr,md5,HAVE_LIMITS,trv_tbl); /* [fnc] Close unformatted binary data file */ if(fp_bnr) (void)nco_bnr_close(fp_bnr,fl_bnr); if(nco_dbg_lvl_get() == 14){ (void)nco_wrt_trv_tbl(in_id,trv_tbl,True); (void)nco_wrt_trv_tbl(out_id,trv_tbl,True); } /* Close output file and move it from temporary to permanent location */ (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); }else{ /* !fl_out */ nco_bool ALPHA_BY_FULL_GROUP=False; /* [flg] Print alphabetically by full group */ nco_bool ALPHA_BY_STUB_GROUP=True; /* [flg] Print alphabetically by stub group */ // nco_bool ALPHA_BY_FULL_OBJECT=False; /* [flg] Print alphabetically by full object */ // nco_bool ALPHA_BY_STUB_OBJECT=False; /* [flg] Print alphabetically by stub object */ char *fl_nm_stub; char *fl_in_dpl=NULL; char *sfx_ptr; /* Update all GTT dimensions with hyperslabbed size */ (void)nco_dmn_trv_msa_tbl(in_id,rec_dmn_nm,trv_tbl); /* No output file was specified so PRN_ tokens refer to screen printing */ prn_fmt_sct prn_flg; prn_flg.cdl=PRN_CDL; prn_flg.jsn=PRN_JSN; prn_flg.srm=PRN_SRM; prn_flg.xml=PRN_XML; prn_flg.trd=!(PRN_CDL || PRN_XML || PRN_JSN); if((prn_flg.cdl || prn_flg.xml) && nco_dbg_lvl >= nco_dbg_std) prn_flg.nfo_xtr=True; else prn_flg.nfo_xtr=False; prn_flg.new_fmt=(PRN_CDL || PRN_JSN || PRN_SRM || PRN_XML || PRN_NEW_FMT); prn_flg.hdn=PRN_HDN; /* CDL must print filename stub */ if(prn_flg.cdl || prn_flg.xml){ fl_in_dpl=strdup(fl_in); fl_nm_stub=strrchr(fl_in_dpl,'/'); if(fl_nm_stub) fl_nm_stub++; else fl_nm_stub=fl_in_dpl; sfx_ptr=strrchr(fl_nm_stub,'.'); if(sfx_ptr) *sfx_ptr='\0'; prn_flg.fl_stb=fl_nm_stub; } /* endif CDL */ /* JSON and XML need filename (unless location will be omitted) */ if(prn_flg.xml || prn_flg.jsn) prn_flg.fl_in=fl_in; prn_flg.spr_nmr=spr_nmr; prn_flg.spr_chr=spr_chr; prn_flg.xml_lcn=PRN_XML_LOCATION; prn_flg.gpe=gpe; prn_flg.md5=md5; prn_flg.nbr_zro=0; prn_flg.ndn=0; /* Initialize for prn_flg->trd */ prn_flg.spc_per_lvl=2; prn_flg.sxn_fst=2; prn_flg.var_fst=2; prn_flg.tab=4; if(nco_dbg_lvl >= nco_dbg_scl) prn_flg.fll_pth=True; else prn_flg.fll_pth=False; if(prn_flg.xml) prn_flg.nwl_pst_val=False; else prn_flg.nwl_pst_val=True; prn_flg.dlm_sng=dlm_sng; prn_flg.ALPHA_BY_FULL_GROUP=ALPHA_BY_FULL_GROUP; // prn_flg.ALPHA_BY_FULL_OBJECT=ALPHA_BY_FULL_OBJECT; prn_flg.ALPHA_BY_STUB_GROUP=ALPHA_BY_STUB_GROUP; // prn_flg.ALPHA_BY_STUB_OBJECT=ALPHA_BY_STUB_OBJECT; prn_flg.FORTRAN_IDX_CNV=FORTRAN_IDX_CNV; prn_flg.PRN_DMN_IDX_CRD_VAL=PRN_DMN_IDX_CRD_VAL; prn_flg.PRN_DMN_UNITS=PRN_DMN_UNITS; prn_flg.PRN_DMN_VAR_NM=PRN_DMN_VAR_NM; prn_flg.PRN_GLB_METADATA=PRN_GLB_METADATA; prn_flg.PRN_MSS_VAL_BLANK=PRN_MSS_VAL_BLANK; prn_flg.PRN_VAR_DATA=PRN_VAR_DATA; prn_flg.PRN_VAR_METADATA=PRN_VAR_METADATA; /* Derived formats */ if(prn_flg.cdl){ prn_flg.PRN_DMN_UNITS=False; prn_flg.PRN_DMN_VAR_NM=True; prn_flg.PRN_MSS_VAL_BLANK=True; } /* endif */ if(prn_flg.jsn){ /* JSON either prints metadata or data, not both */ if(prn_flg.PRN_VAR_DATA){ prn_flg.PRN_VAR_METADATA=False; prn_flg.PRN_GLB_METADATA=False; } /* !PRN_VAR_DATA */ if(prn_flg.PRN_GLB_METADATA) prn_flg.PRN_VAR_METADATA=False; } /* endif JSON */ if(prn_flg.xml) prn_flg.PRN_MSS_VAL_BLANK=False; /* File summary */ if(PRN_GLB_METADATA){ prn_flg.smr_sng=smr_sng=(char *)nco_malloc((strlen(fl_in)+300L*sizeof(char))); /* [sng] File summary string */ smr_xtn_sng=(char *)nco_malloc(300L*sizeof(char)); /* [sng] File extended summary string */ if(nco_dbg_lvl > nco_dbg_std) (void)sprintf(smr_xtn_sng," (representation of extended/underlying filetype %s)",nco_fmt_xtn_sng(nco_fmt_xtn_get())); else smr_xtn_sng[0]='\0'; (void)sprintf(smr_sng,"Summary of %s: filetype = %s%s, %i groups (max. depth = %i), %i dimensions (%i fixed, %i record), %i variables (%i atomic-type, %i non-atomic), %i attributes (%i global, %i group, %i variable)",fl_in,nco_fmt_sng(fl_in_fmt),smr_xtn_sng,grp_nbr_fl,grp_dpt_fl,trv_tbl->nbr_dmn,trv_tbl->nbr_dmn-dmn_rec_fl,dmn_rec_fl,var_nbr_fl+var_ntm_fl,var_nbr_fl,var_ntm_fl,att_glb_nbr+att_grp_nbr+att_var_nbr,att_glb_nbr,att_grp_nbr,att_var_nbr); if(!prn_flg.cdl && !prn_flg.xml && !prn_flg.srm) (void)fprintf(stdout,"%s\n\n",smr_sng); } /* endif summary */ if(!prn_flg.new_fmt){ /* Traditional printing order/format */ if(PRN_GLB_METADATA){ int dmn_ids_rec[NC_MAX_DIMS]; /* [ID] Record dimension IDs array */ int nbr_rec_lcl; /* [nbr] Number of record dimensions visible in root */ /* Get unlimited dimension information from input file/group */ rcd=nco_inq_unlimdims(in_id,&nbr_rec_lcl,dmn_ids_rec); if(nbr_rec_lcl > 0){ char dmn_nm[NC_MAX_NAME]; long rec_dmn_sz; for(int rec_idx=0;rec_idxnbr;obj_idx++){ /* Shallow copy to avoid indirection */ trv_obj=trv_tbl->lst[obj_idx]; /* Print this group */ if(trv_obj.nco_typ == nco_obj_typ_grp){ /* Print dimensions defined in this group */ // (void)nco_prn_dmn_xtr(in_id,trv_tbl); /* Print group attributes */ //if(PRN_GLB_METADATA) (void)nco_prn_grp_att(in_id,trv_tbl); ; } /* endif group */ if(trv_obj.nco_typ == nco_obj_typ_var){ if(PRN_VAR_METADATA) (void)nco_prn_xtr_mtd(in_id,&prn_flg,trv_tbl); if(PRN_VAR_DATA) (void)nco_prn_xtr_val(in_id,&prn_flg,trv_tbl); } /* endif variable */ } /* end loop over obj_idx */ } /* end if */ } /* endif new format */ if(fl_in_dpl) fl_in_dpl=(char *)nco_free(fl_in_dpl); } /* !fl_out */ /* goto close_and_free */ close_and_free: /* Close input netCDF file */ nco_close(in_id); /* Remove local copy of file */ if(FL_RTR_RMT_LCN && RM_RMT_FL_PST_PRC) (void)nco_fl_rm(fl_in); /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* ncks-specific memory */ if(fl_bnr) fl_bnr=(char *)nco_free(fl_bnr); if(rec_dmn_nm) rec_dmn_nm=(char *)nco_free(rec_dmn_nm); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(spr_nmr) spr_nmr=(char *)nco_free(spr_nmr); if(spr_chr) spr_chr=(char *)nco_free(spr_chr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(grp_lst_in_nbr > 0) grp_lst_in=nco_sng_lst_free(grp_lst_in,grp_lst_in_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) cnk.cnk_dmn=(cnk_dmn_sct **)nco_cnk_lst_free(cnk.cnk_dmn,cnk_nbr); trv_tbl_free(trv_tbl); for(idx=0;idx /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_fl_utl.h" /* File manipulation */ #include "nco_grp_utl.h" /* Group utilities */ #include "nco_lst_utl.h" /* List utilities */ #include "nco_mmr.h" /* Memory management */ /* Chunking policies: Handle each chunking policies in nco_cnk_sz_set() */ enum nco_cnk_plc{ /* [enm] Chunking policy */ nco_cnk_plc_nil, /* 0 [enm] Do not think about chunking */ nco_cnk_plc_all, /* 1 [enm] Chunk all variables */ nco_cnk_plc_g2d, /* 2 [enm] Chunk variables >= two dimensions */ nco_cnk_plc_g3d, /* 3 [enm] Chunk variables >= three dimensions */ nco_cnk_plc_xpl, /* 4 [enm] Chunk variables with explicitly chunked dimensions */ nco_cnk_plc_xst, /* 5 [enm] Chunk variables that are chunked in input */ nco_cnk_plc_uck /* 6 [enm] Unchunk all chunked variables */ }; /* end nco_cnk_plc enum */ /* Chunking type maps: */ enum nco_cnk_map{ /* [enm] Chunking conversion map */ nco_cnk_map_nil, /* 0 [enm] Do not chunk anything, storage is unchanged */ nco_cnk_map_dmn, /* 1 [enm] Chunksize equals dimension size */ nco_cnk_map_rd1, /* 2 [enm] Chunksize equals dimension size except record dimension has size one */ nco_cnk_map_scl, /* 3 [enm] Chunksize equals scalar size specified */ nco_cnk_map_prd, /* 4 [enm] Chunksize product is scalar size specified */ nco_cnk_map_lfp, /* 5 [enm] Chunksizes of lefter dimensions flexes to matches scalar size specified */ nco_cnk_map_xst, /* 6 [enm] Chunksize equals chunk-sizes in input file */ nco_cnk_map_rew /* 7 [enm] Chunksize balances access to 1D and 2D slabs of 3D variable */ }; /* end nco_cnk_map enum */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void nco_dfl_case_cnk_map_err(void); /* [fnc] Print error and exit for illegal switch(cnk_map) case */ void nco_dfl_case_cnk_plc_err(void); /* [fnc] Print error and exit for illegal switch(nco_cnk_plc) case */ const char * /* O [sng] Chunking map string */ nco_cnk_map_sng_get /* [fnc] Convert chunking map enum to string */ (const int nco_cnk_map); /* I [enm] Chunking map */ const char * /* O [sng] Chunking policy string */ nco_cnk_plc_sng_get /* [fnc] Convert chunking policy enum to string */ (const int nco_cnk_plc); /* I [enm] Chunking policy */ int /* [rcd] [enm] Return code */ nco_cnk_ini /* [fnc] Create structure with all chunking information */ (const char * const fl_out, /* I [sng] Output filename */ CST_X_PTR_CST_PTR_CST_Y(char,cnk_arg), /* I [sng] List of user-specified chunksizes */ const int cnk_nbr, /* I [nbr] Number of chunksizes specified */ const int cnk_map, /* I [enm] Chunking map */ const int cnk_plc, /* I [enm] Chunking policy */ const size_t cnk_sz_byt, /* I [B] Chunk size in bytes */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ cnk_sct * const cnk); /* O [sct] Chunking structure */ cnk_dmn_sct ** /* O [sct] Structure list with user-specified per-dimension chunking information */ nco_cnk_prs /* [fnc] Create chunking structures with name and chunksize elements */ (const int cnk_nbr, /* I [nbr] Number of chunksizes specified */ CST_X_PTR_CST_PTR_CST_Y(char,cnk_arg)); /* I [sng] List of user-specified chunksizes */ cnk_dmn_sct ** /* O [sct] Pointer to free'd structure list */ nco_cnk_lst_free /* [fnc] Free memory associated with chunking structure list */ (cnk_dmn_sct **cnk_lst, /* I/O [sct] Chunking structure list to free */ const int cnk_nbr); /* I [nbr] Number of chunking structures in list */ cnk_dmn_sct * /* O [sct] Pointer to free'd chunking structure */ nco_cnk_dmn_free /* [fnc] Free all memory associated with chunking structure */ (cnk_dmn_sct *cnk_dmn); /* I/O [sct] Chunking structure to free */ void nco_cnk_sz_set /* [fnc] Set chunksize parameters */ (const int nc_id, /* I [id] netCDF file ID */ CST_X_PTR_CST_PTR_CST_Y(lmt_msa_sct,lmt_all_lst), /* I [sct] Hyperslab limits */ const int lmt_all_lst_nbr, /* I [nbr] Number of hyperslab limits */ int * const cnk_map_ptr, /* I/O [enm] Chunking map */ int * const cnk_plc_ptr, /* I/O [enm] Chunking policy */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ CST_X_PTR_CST_PTR_CST_Y(cnk_dmn_sct,cnk_dmn), /* I [sct] Chunking information */ const int cnk_nbr); /* I [nbr] Number of dimensions with user-specified chunking */ void nco_cnk_sz_set_trv /* [fnc] Set chunksize parameters (GTT version of nco_cnk_sz_set() ) */ (const int grp_id_in, /* I [id] netCDF group ID in input file */ const int grp_id_out, /* I [id] netCDF group ID in output file */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const char * const var_nm, /* I [sng] Name of variable */ const dmn_cmn_sct * const dmn_cmn); /* I [sct] Dimension structure in output file */ int /* O [enm] Chunking map */ nco_cnk_map_get /* [fnc] Convert user-specified chunking map to key */ (const char *nco_cnk_map_sng); /* [sng] User-specified chunking map */ int /* O [enm] Chunking policy */ nco_cnk_plc_get /* [fnc] Convert user-specified chunking policy to key */ (const char *nco_cnk_plc_sng); /* [sng] User-specified chunking policy */ nco_bool /* O [flg] Variable is chunked on disk */ nco_cnk_dsk_inq /* [fnc] Check whether variable is chunked on disk */ (const int nc_id, /* I [idx] netCDF file ID */ const int var_id); /* I [id] Variable ID */ #if 0 size_t * /* O [nbr] Chunksize array for variable */ nco_cnk_sz_get /* [fnc] Determine chunksize array */ (const int nc_id, /* I [id] netCDF file ID */ const char * const var_nm, /* I [sng] Variable name */ const int cnk_map, /* I [enm] Chunking map */ const int cnk_plc, /* I [enm] Chunking policy */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ CST_X_PTR_CST_PTR_CST_Y(cnk_dmn_sct,cnk_dmn), /* I [sct] Chunking information */ const int cnk_nbr); /* I [nbr] Number of dimensions with user-specified chunking */ nco_bool /* O [flg] NCO will attempt to chunk variable */ nco_is_chunkable /* [fnc] Will NCO attempt to chunk variable? */ (const nc_type nc_typ_in); /* I [enm] Type of input variable */ #endif /* endif 0 */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_CNK_H */ ./nco-4.4.2/src/nco/nco_lmt.c0000644000674300045400000030752212277324011015132 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_lmt.c,v 1.208 2014/02/14 05:22:17 zender Exp $ */ /* Purpose: Hyperslab limits */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_lmt.h" /* Hyperslab limits */ void nco_lmt_init /* [fnc] Initialize limit to NULL/invalid values */ (lmt_sct *lmt) /* I/O [sct] Limit structure to initialize */ { lmt->nm=NULL; /* [sng] Dimension name */ lmt->nm_fll=NULL; /* [sng] Full dimension name */ lmt->grp_nm_fll=NULL; /* [sng] Full group where dimension is defined */ lmt->ssc_sng=NULL; /* [sng] User-specified string for dimension subcycle */ lmt->max_sng=NULL; /* [sng] User-specified string for dimension maximum */ lmt->min_sng=NULL; /* [sng] User-specified string for dimension minimum */ lmt->mro_sng=NULL; /* [sng] User-specified string for multi-record output */ lmt->rbs_sng=NULL; /* [sng] Used by ncra, ncrcat to re-base record coordinate (holds unit attribute from first file) */ lmt->srd_sng=NULL; /* [sng] User-specified string for dimension stride */ lmt->max_val=-1; /* [nbr] Double precision representation of maximum value of coordinate requested or implied */ lmt->min_val=-1; /* [nbr] Double precision representation of minimum value of coordinate requested or implied */ lmt->origin=-1; /* [nbr] Used by ncra, ncrcat to re-base record coordinate */ lmt->id=-1; /* [ID] Dimension ID */ lmt->lmt_typ=-1; /* [enm] Limit type (0, Coordinate value limit, 1, Dimension index limit, 2, UDUnits string ) */ lmt->cnt=-1; /* [nbr] Valid elements in this dimension (including effects of stride and wrapping) */ lmt->ssc=-1; /* [nbr] Subcycle of hyperslab */ lmt->end=-1; /* [nbr] Index to end of hyperslab */ lmt->max_idx=-1; /* [nbr] Index of maximum requested value in dimension */ lmt->min_idx=-1; /* [nbr] Index of minimum requested value in dimension */ lmt->rec_dmn_sz=-1; /* [nbr] Number of records in this file (multi-file record dimension only) */ lmt->rec_in_cml=-1; /* [nbr] Cumulative number of records in all files opened so far (multi-file record dimension only) */ lmt->idx_end_max_abs=-1; /* [nbr] Maximum allowed index in record dimension (multi-file record dimension only) */ lmt->rec_skp_ntl_spf=-1; /* [nbr] Records skipped in initial superfluous files (multi-file record dimension only) */ lmt->rec_skp_vld_prv=-1; /* [nbr] Records skipped since previous good one (multi-file record dimension only) */ lmt->rec_rmn_prv_ssc=-1; /* [nbr] Records remaining-to-be-read to complete subcycle group from previous file (multi-file record dimension only) */ lmt->srd=-1; /* [nbr] Stride of hyperslab */ lmt->srt=-1; /* [nbr] Index to start of hyperslab */ lmt->flg_mro=-1; /* [flg] True for multi-record output (used by ncra only) */ lmt->flg_input_complete=-1;/* [flg] True for multi-file operators when no more files need be opened */ lmt->is_rec_dmn=-1; /* [flg] True if record dimension, else False */ lmt->is_usr_spc_lmt=-1; /* [flg] True if any part of limit is user-specified, else False */ lmt->is_usr_spc_max=-1; /* [flg] True if user-specified, else False */ lmt->is_usr_spc_min=-1; /* [flg] True if user-specified, else False */ lmt->lmt_cln=cln_nil; /* [flg] Used by ncra, ncrcat to store enum of calendar-type attribute */ } /* end nco_lmt_init() */ void nco_lmt_prt /* [fnc] Print a Limit structure */ (lmt_sct *lmt) /* I/O [sct] Limit structure to print */ { (void)fprintf(stdout,"Name: %s\n",lmt->nm); (void)fprintf(stdout,"User-specified string for dimension subcycle: %s\n",lmt->ssc_sng); (void)fprintf(stdout,"User-specified string for dimension maximum : %s\n",lmt->max_sng); (void)fprintf(stdout,"User-specified string for dimension minimum: %s\n",lmt->min_sng); (void)fprintf(stdout,"User-specified string for multi-record output: %s\n",lmt->mro_sng); (void)fprintf(stdout,"Unit attribute from first file: %s\n",lmt->rbs_sng); (void)fprintf(stdout,"User-specified string for dimension stride: %s\n",lmt->srd_sng); (void)fprintf(stdout,"Maximum value of coordinate: %f\n",lmt->max_val); (void)fprintf(stdout,"Minimum value of coordinate: %f\n",lmt->min_val); (void)fprintf(stdout,"Origin: %f\n",lmt->origin); (void)fprintf(stdout,"ID: %d\n",lmt->id); (void)fprintf(stdout,"Limit type: %d\n",lmt->lmt_typ); (void)fprintf(stdout,"Valid elements: %li\n",lmt->cnt); (void)fprintf(stdout,"Subcycle of hyperslab: %li\n",lmt->ssc); (void)fprintf(stdout,"Index to end of hyperslab: %li\n",lmt->end); (void)fprintf(stdout,"Index of maximum requested value: %li\n",lmt->max_idx); (void)fprintf(stdout,"Index of minimum requested value: %li\n",lmt->min_idx); (void)fprintf(stdout,"Number of records in this file: %li\n",lmt->rec_dmn_sz); (void)fprintf(stdout,"Cumulative number of records in all files: %li\n",lmt->rec_in_cml); (void)fprintf(stdout,"Maximum allowed index in record dimension: %li\n",lmt->idx_end_max_abs); (void)fprintf(stdout,"Records skipped in initial superfluous files: %li\n",lmt->rec_skp_ntl_spf); (void)fprintf(stdout,"Records skipped since previous good one: %li\n",lmt->rec_skp_vld_prv); (void)fprintf(stdout,"Records remaining-to-be-read: %li\n",lmt->rec_rmn_prv_ssc); (void)fprintf(stdout,"Stride of hyperslab: %li\n",lmt->srd); (void)fprintf(stdout,"Index to start of hyperslab: %li\n",lmt->srt); (void)fprintf(stdout,"Is multi-record output: %d\n",lmt->flg_mro); (void)fprintf(stdout,"No more files need be opened: %d\n",lmt->flg_input_complete); (void)fprintf(stdout,"Is record dimension: %d\n",lmt->is_rec_dmn); (void)fprintf(stdout,"Any part is user-specified: %d\n",lmt->is_usr_spc_lmt); (void)fprintf(stdout,"Is user-specified maximum: %d\n",lmt->is_usr_spc_max); (void)fprintf(stdout,"Is user-specified minimum: %d\n",lmt->is_usr_spc_min); (void)fprintf(stdout,"Calendar-type attribute: %d\n",lmt->lmt_cln); } /* end nco_lmt_prt() */ void nco_lmt_cpy /* [fnc] Deep-copy a Limit structure */ (const lmt_sct * const lmt1, /* I [sct] Limit structure to copy */ lmt_sct *lmt2) /* O [sct] New limit structure (must be alloced before) */ { assert(lmt1->nm); /* Initialize to NULL/invalid */ (void)nco_lmt_init(lmt2); lmt2->nm=(char *)strdup(lmt1->nm); if(lmt1->nm_fll) lmt2->nm_fll=(char *)strdup(lmt1->nm_fll); if(lmt1->grp_nm_fll) lmt2->grp_nm_fll=(char *)strdup(lmt1->grp_nm_fll); if(lmt1->max_sng) lmt2->max_sng=(char *)strdup(lmt1->max_sng); if(lmt1->min_sng) lmt2->min_sng=(char *)strdup(lmt1->min_sng); if(lmt1->ssc_sng) lmt2->ssc_sng=(char *)strdup(lmt1->ssc_sng); if(lmt1->mro_sng) lmt2->mro_sng=(char *)strdup(lmt1->mro_sng); if(lmt1->rbs_sng) lmt2->rbs_sng=(char *)strdup(lmt1->rbs_sng); if(lmt1->srd_sng) lmt2->srd_sng=(char *)strdup(lmt1->srd_sng); lmt2->max_val=lmt1->max_val; lmt2->min_val=lmt1->min_val; lmt2->origin=lmt1->origin; lmt2->id=lmt1->id; lmt2->lmt_typ=lmt1->lmt_typ; lmt2->cnt=lmt1->cnt; lmt2->ssc=lmt1->ssc; lmt2->end=lmt1->end; lmt2->max_idx=lmt1->max_idx; lmt2->min_idx=lmt1->min_idx; lmt2->rec_dmn_sz=lmt1->rec_dmn_sz; lmt2->rec_in_cml=lmt1->rec_in_cml; lmt2->idx_end_max_abs=lmt1->idx_end_max_abs; lmt2->rec_skp_ntl_spf=lmt1->rec_skp_ntl_spf; lmt2->rec_skp_vld_prv=lmt1->rec_skp_vld_prv; lmt2->rec_rmn_prv_ssc=lmt1->rec_rmn_prv_ssc; lmt2->srd=lmt1->srd; lmt2->srt=lmt1->srt; lmt2->flg_mro=lmt1->flg_mro; lmt2->flg_input_complete=lmt1->flg_input_complete; lmt2->is_rec_dmn=lmt1->is_rec_dmn; lmt2->is_usr_spc_lmt=lmt1->is_usr_spc_lmt; lmt2->is_usr_spc_max=lmt1->is_usr_spc_max; lmt2->is_usr_spc_min=lmt1->is_usr_spc_min; lmt2->lmt_cln=lmt1->lmt_cln; } /* end nco_lmt_cpy() */ lmt_sct * /* O [sct] Pointer to free'd structure */ nco_lmt_free /* [fnc] Free memory associated with limit structure */ (lmt_sct *lmt) /* I/O [sct] Limit structure to free */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with dynamically allocated limit structure */ lmt->nm=(char *)nco_free(lmt->nm); lmt->nm_fll=(char *)nco_free(lmt->nm_fll); lmt->grp_nm_fll=(char *)nco_free(lmt->grp_nm_fll); lmt->ssc_sng=(char *)nco_free(lmt->ssc_sng); lmt->max_sng=(char *)nco_free(lmt->max_sng); lmt->min_sng=(char *)nco_free(lmt->min_sng); lmt->mro_sng=(char *)nco_free(lmt->mro_sng); lmt->rbs_sng=(char *)nco_free(lmt->rbs_sng); lmt->srd_sng=(char *)nco_free(lmt->srd_sng); lmt=(lmt_sct *)nco_free(lmt); return lmt; } /* end nco_lmt_free() */ lmt_sct ** /* O [sct] Pointer to free'd structure list */ nco_lmt_lst_free /* [fnc] Free memory associated with limit structure list */ (lmt_sct **lmt_lst, /* I/O [sct] Limit structure list to free */ const int lmt_nbr) /* I [nbr] Number of limit structures in list */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with dynamically allocated limit structure list */ int idx; for(idx=0;idxdmn_nm=(char *)nco_free(lmt_all->dmn_nm); /* NB: lmt_dmn[idx] are free'd by nco_lmt_lst_free() in calling routine */ lmt_all->lmt_dmn=(lmt_sct **)nco_free(lmt_all->lmt_dmn); lmt_all=(lmt_msa_sct *)nco_free(lmt_all); return lmt_all; } /* end nco_lmt_all_free() */ lmt_msa_sct ** /* O [sct] Pointer to free'd structure list */ nco_lmt_all_lst_free /* [fnc] Free memory associated with lmt_all structure list */ (lmt_msa_sct **lmt_all_lst, /* I/O [sct] Limit structure list to free */ const int lmt_all_nbr) /* I [nbr] Number of limit strucgtures in list */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with dynamically allocated lmt_msa_sct structure list */ int idx; for(idx=0;idxis_usr_spc_lmt=False; /* True if any part of limit is user-specified, else False */ lmt_dim->is_usr_spc_max=False; /* True if user-specified, else False */ lmt_dim->is_usr_spc_min=False; /* True if user-specified, else False */ /* rec_skp_ntl_spf, rec_skp_vld_prv, rec_in_cml, and rec_rmn_prv_ssc only used for MFO record dimension */ lmt_dim->rec_skp_ntl_spf=0L; /* Number of records skipped in initial superfluous files */ lmt_dim->rec_skp_vld_prv=0L; /* Number of records skipped since previous good one */ lmt_dim->rec_in_cml=0L; /* Number of records, read or not, in previously processed files */ lmt_dim->rec_rmn_prv_ssc=0L; /* Records remaining-to-be-read to complete subcycle group from previous file */ for(idx=0;idxid == dmn_id){ lmt_dim->is_usr_spc_lmt=True; /* True if any part of limit is user-specified, else False */ if(lmt[idx]->max_sng == NULL){ lmt_dim->max_sng=NULL; }else{ lmt_dim->max_sng=(char *)strdup(lmt[idx]->max_sng); lmt_dim->is_usr_spc_max=True; /* True if user-specified, else False */ } /* end if */ if(lmt[idx]->min_sng == NULL){ lmt_dim->min_sng=NULL; }else{ lmt_dim->min_sng=(char *)strdup(lmt[idx]->min_sng); lmt_dim->is_usr_spc_min=True; /* True if user-specified, else False */ } /* end if */ if(lmt[idx]->srd_sng) lmt_dim->srd_sng=(char *)strdup(lmt[idx]->srd_sng); else lmt_dim->srd_sng=NULL; if(lmt[idx]->ssc_sng) lmt_dim->ssc_sng=(char *)strdup(lmt[idx]->ssc_sng); else lmt_dim->ssc_sng=NULL; if(lmt[idx]->mro_sng) lmt_dim->mro_sng=(char *)strdup(lmt[idx]->mro_sng); else lmt_dim->mro_sng=NULL; lmt_dim->nm=(char *)strdup(lmt[idx]->nm); break; } /* end if */ } /* end loop over idx */ /* If this limit was not user-specified, then ... */ if(idx == lmt_nbr){ /* Create default limits to look as though user-specified them */ char dmn_nm[NC_MAX_NAME]; long cnt; int max_sng_sz; /* Fill-in limits with default parsing information */ rcd=nco_inq_dim_flg(nc_id,dmn_id,dmn_nm,&cnt); if(rcd == NC_EBADDIM){ (void)fprintf(stdout,"%s: ERROR attempting to find non-existent dimension with ID = %d in nco_lmt_sct_mk()\n",nco_prg_nm_get(),dmn_id); return False; } /* end if */ lmt_dim->nm=(char *)strdup(dmn_nm); lmt_dim->srd_sng=NULL; lmt_dim->ssc_sng=NULL; lmt_dim->mro_sng=NULL; /* Generate min and max strings to look as if user had specified them Adjust accordingly if FORTRAN_IDX_CNV was requested for other dimensions These sizes will later be decremented in nco_lmt_evl() where all information is converted internally to C-based indexing representation. Ultimately this problem arises because I want nco_lmt_evl() to think the user always did specify this dimension's hyperslab. Otherwise, problems arise when FORTRAN_IDX_CNV is specified by the user along with explicit hypersalbs for some dimensions excluding the record dimension. Then, when nco_lmt_sct_mk() creates the record dimension structure, it must be created consistently with the FORTRAN_IDX_CNV flag for the other dimensions. In order to do that, fill in max_sng, min_sng, and srd_sng arguments with strings as if they had been read from keyboard. An alternate solution is to add flag to lmt_sct indicating whether this limit struct had been automatically generated and then act accordingly. */ /* Decrement cnt to C-index value if necessary */ if(!FORTRAN_IDX_CNV) cnt--; if(cnt < 0L){ if(cnt == -1L) (void)fprintf(stdout,"%s: ERROR nco_lmt_sct_mk() reports record variable exists and is size zero, i.e., has no records yet.\n",nco_prg_nm_get()); (void)fprintf(stdout,"%s: HINT: Perform record-oriented operations only after file has valid records.\n",nco_prg_nm_get()); (void)fprintf(stdout,"%s: cnt < 0 in nco_lmt_sct_mk()\n",nco_prg_nm_get()); return False; } /* end if */ /* cnt < 10 covers negative numbers and SIGFPE from log10(cnt==0) Adding 1 is required for cnt=10,100,1000... */ if(cnt < 10L) max_sng_sz=1; else max_sng_sz=1+(int)ceil(log10((double)cnt)); /* Add one for NUL terminator */ lmt_dim->max_sng=(char *)nco_malloc(sizeof(char)*(max_sng_sz+1)); (void)sprintf(lmt_dim->max_sng,"%ld",cnt); if(FORTRAN_IDX_CNV){ lmt_dim->min_sng=(char *)strdup("1"); }else{ lmt_dim->min_sng=(char *)strdup("0"); } /* end else */ } /* end if user did not explicity specify limits for this dimension */ return lmt_dim; } /* end nco_lmt_sct_mk() */ lmt_sct ** /* O [sct] Structure list with user-specified strings for min and max limits */ nco_lmt_prs /* [fnc] Create limit structures with name, min_sng, max_sng elements */ (const int lmt_nbr, /* I [nbr] number of dimensions with limits */ CST_X_PTR_CST_PTR_CST_Y(char,lmt_arg)) /* I [sng] List of user-specified dimension limits */ { /* Purpose: Set name, min_sng, max_sng elements of comma separated list of names and ranges. Routine merely evaluates syntax of input expressions and does validate dimensions or ranges against those present in input netCDF file. */ /* Valid syntax adheres to nm,[min_sng][,[max_sng][,[srd_sng][,[ssc_sng]]]] */ char **arg_lst; char *msg_sng=NULL_CEWI; /* [sng] Error message */ const char dlm_sng[]=","; lmt_sct **lmt=NULL_CEWI; int idx; int arg_nbr; nco_bool NCO_SYNTAX_ERROR=False; /* [flg] Syntax error in hyperslab specification */ if(lmt_nbr > 0) lmt=(lmt_sct **)nco_malloc(lmt_nbr*sizeof(lmt_sct *)); for(idx=0;idx 6){ /* Too much information */ msg_sng=strdup("Too many (more than 6) arguments"); NCO_SYNTAX_ERROR=True; }else if(arg_lst[0] == NULL){ /* Dimension name not specified */ msg_sng=strdup("Dimension name not specified"); NCO_SYNTAX_ERROR=True; }else if(arg_nbr == 2 && arg_lst[1] == NULL){ /* No min specified */ msg_sng=strdup("Must specify minimum value"); NCO_SYNTAX_ERROR=True; }else if(arg_nbr == 3 && arg_lst[1] == NULL && arg_lst[2] == NULL){ /* No min or max when stride not specified */ msg_sng=strdup("Must specify minimum and/or maximum value since stride is also empty"); NCO_SYNTAX_ERROR=True; }else if(arg_nbr == 4 && arg_lst[3] == NULL){ /* Stride should be specified */ msg_sng=strdup("Stride must be specified (and be a positive integer)"); NCO_SYNTAX_ERROR=True; }else if(arg_nbr == 5 && arg_lst[4] == NULL){ /* Subcycle should be specified */ msg_sng=strdup("Subcycle must be specified (and be a positive integer)"); NCO_SYNTAX_ERROR=True; }else if(arg_nbr == 6 && arg_lst[5] == NULL){ /* Group-mode should be specified */ msg_sng=strdup("Group-mode must be specified (as 'm' or 'M')"); NCO_SYNTAX_ERROR=True; } /* end else */ if(NCO_SYNTAX_ERROR){ (void)fprintf(stdout,"%s: ERROR parsing hyperslab specification for dimension %s\n%s\n%s: HINT Conform request to hyperslab documentation at http://nco.sf.net/nco.html#hyp\n",nco_prg_nm_get(),lmt_arg[idx],msg_sng,nco_prg_nm_get()); msg_sng=(char *)nco_free(msg_sng); nco_exit(EXIT_FAILURE); } /* !NCO_SYNTAX_ERROR */ /* Initialize structure */ /* lmt strings that are not explicitly set by user remain NULL, i.e., specifying default setting will appear as if nothing at all was set. Hopefully, in routines that follow, branch followed when dimension has all default settings specified (e.g.,"-d foo,,,,") yields same answer as branch for which no hyperslab along that dimension was set. */ lmt[idx]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Initialize to NULL/invalid */ (void)nco_lmt_init(lmt[idx]); lmt[idx]->nm=NULL; lmt[idx]->is_usr_spc_lmt=True; /* True if any part of limit is user-specified, else False */ lmt[idx]->min_sng=NULL; lmt[idx]->max_sng=NULL; lmt[idx]->srd_sng=NULL; lmt[idx]->ssc_sng=NULL; lmt[idx]->mro_sng=NULL; /* rec_skp_ntl_spf is used for record dimension in multi-file operators */ lmt[idx]->rec_skp_ntl_spf=0L; /* Number of records skipped in initial superfluous files */ /* Fill-in structure */ lmt[idx]->nm=arg_lst[0]; lmt[idx]->min_sng=arg_lst[1]; /* Setting min_sng and max_sng to same pointer would lead to dangerous double-free() condition */ if(arg_nbr <= 2) lmt[idx]->max_sng=(char *)strdup(arg_lst[1]); if(arg_nbr > 2) lmt[idx]->max_sng=arg_lst[2]; if(arg_nbr > 3) lmt[idx]->srd_sng=arg_lst[3]; if(arg_nbr > 4) lmt[idx]->ssc_sng=arg_lst[4]; if(arg_nbr > 5) lmt[idx]->mro_sng=arg_lst[5]; if(lmt[idx]->max_sng == NULL) lmt[idx]->is_usr_spc_max=False; else lmt[idx]->is_usr_spc_max=True; if(lmt[idx]->min_sng == NULL) lmt[idx]->is_usr_spc_min=False; else lmt[idx]->is_usr_spc_min=True; /* Initialize types used to re-base coordinate variables */ lmt[idx]->origin=0.0; lmt[idx]->rbs_sng=NULL_CEWI; lmt[idx]->lmt_cln=cln_nil; /* 20130903: Initialize cumulative number of records in all files opened so far (multi-file record dimension only) */ lmt[idx]->rec_in_cml=0L; /* Free current pointer array to strings, leaving untouched the strings themselves They will be free()'d with limit structures in nco_lmt_lst_free() */ arg_lst=(char **)nco_free(arg_lst); } /* End loop over lmt structure list */ return lmt; } /* end nco_lmt_prs() */ int /* O [enm] Limit type */ nco_lmt_typ /* [fnc] Determine limit type */ (char *sng) /* I [ptr] Pointer to limit string */ { /* Purpose: Determine type of user-specified limit */ /* Test for UDUnits unit string, then simple coordinate, then date/time string (i.e., YYYY-MM-DD), else default to dimensional index */ /* Space delimits user-specified units, e.g., "3 meters" */ if(strchr(sng,' ')) return lmt_udu_sng; /* Colon delimits user-specified units, e.g., '1918-11-11 11:00:0.0' */ if(strchr(sng,':')) return lmt_udu_sng; /* Decimal point (very common so check early), e.g., "3.0" */ if(strchr(sng,'.')) return lmt_crd_val; /* Non-decimal (non-UDUnits) coordinate value, e.g., "3e10" or "3d10" */ if(strchr(sng,'E') || strchr(sng,'e') || strchr(sng,'D') || strchr(sng,'d')) return lmt_crd_val; /* Other date-like strings */ if( /* String contains non-leading dash with yyyy-mm-dd */ (strchr(sng,'-') && ((char *)strchr(sng,'-') != (char *)sng)) || False){ int yyyy,mm,dd; /* Scan for yyyy-mm-dd */ if(sscanf(sng,"%d-%d-%d",&yyyy,&mm,&dd) == 3) return lmt_udu_sng; } /* endif date-like string */ /* Default: Limit is dimension index */ return lmt_dmn_idx; } /* end nco_lmt_typ() */ char * /* O [sng] Units string */ nco_lmt_get_udu_att /* Returns specified attribute otherwise NULL */ (const int nc_id, /* I [idx] netCDF file ID */ const int var_id, const char *att_nm) /* I [id] Variable ID whose attribute to read */ { /* Grab units attribute from disk */ nc_type att_typ; long att_sz; char *fl_udu_sng=NULL_CEWI; if(nco_inq_att_flg(nc_id,var_id,att_nm,&att_typ,&att_sz) == NC_NOERR){ /* Allocate memory for attribute */ if(att_typ == NC_CHAR){ fl_udu_sng=(char *)nco_malloc((att_sz+1UL)*sizeof(char)); /* Get 'units' attribute */ (void)nco_get_att(nc_id,var_id,att_nm,fl_udu_sng,att_typ); fl_udu_sng[att_sz]='\0'; } /* !NC_CHAR */ } /* endif */ return fl_udu_sng; } /* end nco_lmt_get_udu_att() */ void nco_prn_lmt /* [fnc] Print limit information */ (lmt_sct lmt, /* I [sct] Limit structure */ int min_lmt_typ, /* I [nbr] Limit type */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ nco_bool flg_no_data_ok, /* I [flg] True if file contains no data for hyperslab */ long rec_usd_cml, /* I [nbr] Number of valid records already processed (only used for record dimensions in multi-file operators) */ monotonic_direction_enm monotonic_direction, /* I [enm] Monotonic_direction */ nco_bool rec_dmn_and_mfo, /* I [flg] True if record dimension in multi-file operator */ long cnt_rmn_ttl, /* I [nbr] Total records to be read from this and all remaining files */ long cnt_rmn_crr, /* I [nbr] Records to extract from current file */ long rec_skp_vld_prv_dgn) /* I [nbr] Records skipped at end of previous valid file, if any (diagnostic only) */ { /* Purpose: Print limit information */ (void)fprintf(stderr,"Dimension hyperslabber nco_lmt_evl() diagnostics:\n"); (void)fprintf(stderr,"Dimension name = %s\n",lmt.nm); (void)fprintf(stderr,"Limit type is %s\n",(min_lmt_typ == lmt_crd_val) ? "coordinate value" : (FORTRAN_IDX_CNV) ? "one-based dimension index" : "zero-based dimension index"); (void)fprintf(stderr,"Limit %s user-specified\n",(lmt.is_usr_spc_lmt) ? "is" : "is not"); (void)fprintf(stderr,"Limit %s record dimension\n",(lmt.is_rec_dmn) ? "is" : "is not"); (void)fprintf(stderr,"Current file %s specified hyperslab, data %s be read\n",(flg_no_data_ok) ? "is superfluous to" : "is required by",(flg_no_data_ok) ? "will not" : "will"); if(rec_dmn_and_mfo) (void)fprintf(stderr,"Cumulative number of records in all input files opened including this one = %li\n",lmt.rec_in_cml); if(rec_dmn_and_mfo) (void)fprintf(stderr,"Records skipped in initial superfluous files = %li\n",lmt.rec_skp_ntl_spf); if(rec_dmn_and_mfo) (void)fprintf(stderr,"Valid records read (and used) from previous files = %li\n",rec_usd_cml); if(cnt_rmn_ttl != -1L) (void)fprintf(stderr,"Total records to be read from this and all following files = %li\n",cnt_rmn_ttl); if(cnt_rmn_crr != -1L) (void)fprintf(stderr,"Records to be read from this file = %li\n",cnt_rmn_crr); if(rec_skp_vld_prv_dgn != -1L) (void)fprintf(stderr,"rec_skp_vld_prv_dgn (previous file, if any) = %li \n",rec_skp_vld_prv_dgn); if(rec_skp_vld_prv_dgn != -1L) (void)fprintf(stderr,"rec_skp_vld_prv (this file) = %li \n",lmt.rec_skp_vld_prv); (void)fprintf(stderr,"min_sng = %s\n",lmt.min_sng == NULL ? "NULL" : lmt.min_sng); (void)fprintf(stderr,"max_sng = %s\n",lmt.max_sng == NULL ? "NULL" : lmt.max_sng); (void)fprintf(stderr,"srd_sng = %s\n",lmt.srd_sng == NULL ? "NULL" : lmt.srd_sng); (void)fprintf(stderr,"ssc_sng = %s\n",lmt.ssc_sng == NULL ? "NULL" : lmt.ssc_sng); (void)fprintf(stderr,"mro_sng = %s\n",lmt.ssc_sng == NULL ? "NULL" : lmt.mro_sng); (void)fprintf(stderr,"monotonic_direction = %s\n",(monotonic_direction == not_checked) ? "not checked" : (monotonic_direction == increasing) ? "increasing" : "decreasing"); (void)fprintf(stderr,"min_val = %g\n",lmt.min_val); (void)fprintf(stderr,"max_val = %g\n",lmt.max_val); (void)fprintf(stderr,"min_idx = %li\n",lmt.min_idx); (void)fprintf(stderr,"max_idx = %li\n",lmt.max_idx); (void)fprintf(stderr,"srt = %li\n",lmt.srt); (void)fprintf(stderr,"end = %li\n",lmt.end); (void)fprintf(stderr,"cnt = %li\n",lmt.cnt); (void)fprintf(stderr,"srd = %li\n",lmt.srd); (void)fprintf(stderr,"ssc = %li\n",lmt.ssc); (void)fprintf(stderr,"WRP = %s\n",lmt.srt > lmt.end ? "YES" : "NO"); (void)fprintf(stderr,"SRD = %s\n",lmt.srd != 1L ? "YES" : "NO"); (void)fprintf(stderr,"SSC = %s\n",lmt.ssc != 1L ? "YES" : "NO"); (void)fprintf(stderr,"MRO = %s\n\n",lmt.flg_mro ? "YES" : "NO"); } void nco_lmt_evl /* [fnc] Parse user-specified limits into hyperslab specifications */ (const int grp_id, /* I [idx] netCDF group ID */ lmt_sct *lmt_ptr, /* I/O [sct] Structure from nco_lmt_prs() or from nco_lmt_sct_mk() to hold dimension limit information */ long rec_usd_cml, /* I [nbr] Number of valid records already processed (only used for record dimensions in multi-file operators) */ nco_bool FORTRAN_IDX_CNV) /* I [flg] Hyperslab indices obey Fortran convention */ { /* NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ /* Purpose: Take parsed list of dimension names, minima, and maxima strings and find appropriate indices into dimensions for formulation of dimension start and count vectors, or fail trying. */ char *fl_udu_sng=NULL_CEWI; /* Store units attribute of coordinate dimension */ char *msg_sng=NULL_CEWI; /* [sng] Error message */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ nco_bool flg_no_data_err=False; /* True if domain brackets no data (and not an MFO/record coordinate) */ nco_bool flg_no_data_ok=False; /* True if file contains no data for hyperslab */ nco_bool rec_dmn_and_mfo=False; /* True if record dimension in multi-file operator */ nco_bool NCO_SYNTAX_ERROR=False; /* [flg] Syntax error in hyperslab specification */ dmn_sct dim; lmt_sct lmt; int min_lmt_typ=int_CEWI; int max_lmt_typ=int_CEWI; monotonic_direction_enm monotonic_direction=not_checked; /* CEWI */ int nco_prg_id; /* Program ID */ int rcd=NC_NOERR; /* [enm] Return code */ int rec_dmn_id; /* [idx] Variable ID of record dimension, if any */ int dmn_ids_ult[NC_MAX_DIMS]; /* [nbr] Unlimited dimensions IDs array */ int nbr_dmn_ult; /* [nbr] Number of unlimited dimensions */ int fl_fmt; /* [nbr] File format */ long dmn_sz; long cnt_rmn_crr=-1L; /* Records to extract from current file */ long cnt_rmn_ttl=-1L; /* Total records to be read from this and all remaining files */ long rec_skp_vld_prv_dgn=-1L; /* Records skipped at end of previous valid file, if any (diagnostic only) */ lmt=*lmt_ptr; nco_prg_id=nco_prg_id_get(); /* Program ID */ /* Initialize limit structure */ lmt.flg_mro=False; lmt.max_val=0.0; lmt.min_val=0.0; lmt.ssc=1L; lmt.srd=1L; lmt.flg_input_complete=False; /* Get dimension ID from name */ rcd=nco_inq_dimid_flg(grp_id,lmt.nm,&lmt.id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"%s: ERROR dimension %s is not in input file\n",nco_prg_nm_get(),lmt.nm); nco_exit(EXIT_FAILURE); } /* endif */ /* Logic on whether to allow skipping current file depends on whether limit is specified for record dimension in multi-file operators. This information is not used in single-file operators, though whether the limit is a record limit may be tested. Program defensively and define this flag in all cases. */ (void)nco_inq_format(grp_id,&fl_fmt); /* Obtain unlimited dimensions for group */ (void)nco_inq_unlimdims(grp_id,&nbr_dmn_ult,dmn_ids_ult); rec_dmn_id=-1; if(fl_fmt == NC_FORMAT_NETCDF4){ for(int idx_dmn=0;idx_dmn 0 in order to apply limits.\n",nco_prg_nm_get(),lmt.nm,dmn_sz); nco_exit(EXIT_FAILURE); } /* end if */ if(lmt.srd_sng){ if(strchr(lmt.srd_sng,'.') || strchr(lmt.srd_sng,'e') || strchr(lmt.srd_sng,'E') || strchr(lmt.srd_sng,'d') || strchr(lmt.srd_sng,'D')){ (void)fprintf(stdout,"%s: ERROR Requested stride for %s, %s, must be integer\n",nco_prg_nm_get(),lmt.nm,lmt.srd_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.srd=strtol(lmt.srd_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.srd_sng,"strtol",sng_cnv_rcd); if(lmt.srd < 1L){ (void)fprintf(stdout,"%s: ERROR Stride for %s is %li but must be > 0\n",nco_prg_nm_get(),lmt.nm,lmt.srd); nco_exit(EXIT_FAILURE); } /* end if */ } /* !lmt.srd_sng */ if(lmt.ssc_sng){ if(strchr(lmt.ssc_sng,'.') || strchr(lmt.ssc_sng,'e') || strchr(lmt.ssc_sng,'E') || strchr(lmt.ssc_sng,'d') || strchr(lmt.ssc_sng,'D')){ (void)fprintf(stdout,"%s: ERROR Requested subcycle for %s, %s, must be integer\n",nco_prg_nm_get(),lmt.nm,lmt.ssc_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.ssc=strtol(lmt.ssc_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.ssc_sng,"strtol",sng_cnv_rcd); if(lmt.ssc < 1L){ (void)fprintf(stdout,"%s: ERROR Subcycle for %s is %li but must be > 0\n",nco_prg_nm_get(),lmt.nm,lmt.ssc); nco_exit(EXIT_FAILURE); } /* end if */ if(nco_prg_id != ncra && nco_prg_id != ncrcat){ (void)fprintf(stdout,"%s: ERROR Subcycle only implemented for ncra and ncrcat\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end ncra */ } /* !lmt.ssc_sng */ if(lmt.mro_sng){ if(strcasecmp(lmt.mro_sng,"m")){ (void)fprintf(stdout,"%s: ERROR Requested MRO flag for %s, \"%s\", must be 'm' or 'M'\n",nco_prg_nm_get(),lmt.nm,lmt.mro_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.flg_mro=True; } /* !lmt.mro_sng */ /* In case flg_mro is set in ncra.c by --mro */ if(lmt.flg_mro){ if(nco_prg_id == ncrcat){ (void)fprintf(stdout,"%s: INFO Specifying Multi-Record Output (MRO) option ('m', 'M', or --mro) is redundant. MRO is always true for ncrcat.\n",nco_prg_nm_get()); }else if(nco_prg_id != ncra){ (void)fprintf(stdout,"%s: ERROR Multi-Record Output (MRO) ('m', 'M', or --mro) is only valid for ncra.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end else */ } /* !lmt.mro_sng */ /* If min_sng and max_sng are both NULL then set type to lmt_dmn_idx */ if(lmt.min_sng == NULL && lmt.max_sng == NULL){ /* Limiting indices will be set to default extrema a bit later */ min_lmt_typ=max_lmt_typ=lmt_dmn_idx; }else{ /* min_sng and max_sng are not both NULL */ /* Limit is coordinate value if string contains decimal point or is in exponential format Otherwise limit is interpreted as zero-based dimension offset */ if(lmt.min_sng) min_lmt_typ=nco_lmt_typ(lmt.min_sng); if(lmt.max_sng) max_lmt_typ=nco_lmt_typ(lmt.max_sng); /* Copy lmt_typ from defined limit to undefined */ if(!lmt.min_sng) min_lmt_typ=max_lmt_typ; if(!lmt.max_sng) max_lmt_typ=min_lmt_typ; } /* end else */ /* Both min_lmt_typ and max_lmt_typ are now defined Continue only if both limits are of the same type */ if(min_lmt_typ != max_lmt_typ){ (void)fprintf(stdout,"%s: ERROR -d %s,%s,%s\n",nco_prg_nm_get(),lmt.nm,lmt.min_sng,lmt.max_sng); (void)fprintf(stdout,"Limits on dimension \"%s\" must be of same numeric type:\n",lmt.nm); (void)fprintf(stdout,"\"%s\" was interpreted as a %s.\n",lmt.min_sng,(min_lmt_typ == lmt_crd_val) ? "coordinate value" : (FORTRAN_IDX_CNV) ? "one-based dimension index" : "zero-based dimension index"); (void)fprintf(stdout,"\"%s\" was interpreted as a %s.\n",lmt.max_sng,(max_lmt_typ == lmt_crd_val) ? "coordinate value" : (FORTRAN_IDX_CNV) ? "one-based dimension index" : "zero-based dimension index"); (void)fprintf(stdout,"(Limit arguments containing a decimal point (or in exponential format) are interpreted as coordinate values; arguments without a decimal point are interpreted as zero-based or one-based (depending on -F switch) dimensional indices.)\n"); nco_exit(EXIT_FAILURE); } /* end if */ lmt.lmt_typ=min_lmt_typ; /* Coordinate re-basing code */ lmt.origin=0.0; /* Get variable ID of coordinate */ rcd=nco_inq_varid_flg(grp_id,lmt.nm,&dim.cid); if(rcd == NC_NOERR){ char *cln_sng=NULL_CEWI; fl_udu_sng=nco_lmt_get_udu_att(grp_id,dim.cid,"units"); /* Units attribute of coordinate variable */ cln_sng=nco_lmt_get_udu_att(grp_id,dim.cid,"calendar"); /* Calendar attribute */ if(rec_dmn_and_mfo && fl_udu_sng && lmt.rbs_sng){ #ifdef ENABLE_UDUNITS /* Re-base and reset origin to 0.0 if re-basing fails */ if(nco_cln_clc_org(fl_udu_sng,lmt.rbs_sng,lmt.lmt_cln,&lmt.origin) != NCO_NOERR) lmt.origin=0.0; #endif /* !ENABLE_UDUNITS */ } /* endif */ /* ncra and ncrcat read "calendar" attribute in main() Avoid multiple reads of calendar attribute in multi-file operations */ if(!rec_dmn_and_mfo){ if(cln_sng) lmt.lmt_cln=nco_cln_get_cln_typ(cln_sng); else lmt.lmt_cln=cln_nil; } /* endif */ if(cln_sng) cln_sng=(char *)nco_free(cln_sng); } /* end if limit is coordinate */ if((lmt.lmt_typ == lmt_crd_val) || (lmt.lmt_typ == lmt_udu_sng)){ double *dmn_val_dp; double dmn_max; double dmn_min; long max_idx; long min_idx; long tmp_idx; long dmn_srt=0L; /* Get coordinate type */ (void)nco_inq_vartype(grp_id,dim.cid,&dim.type); /* Warn when coordinate type is weird */ if(dim.type == NC_BYTE || dim.type == NC_UBYTE || dim.type == NC_CHAR || dim.type == NC_STRING) (void)fprintf(stderr,"\n%s: WARNING Coordinate %s is type %s. Dimension truncation is unpredictable.\n",nco_prg_nm_get(),lmt.nm,nco_typ_sng(dim.type)); /* if(lmt.ssc != 1L) (void)fprintf(stderr,"\n%s: WARNING Hyperslabs for %s are based on coordinate values rather than dimension indices. The behavior of the subcycle hyperslab argument is ill-defined, unpredictable, and unsupported for coordinate-based hyperslabs. Only min, max, and stride are supported for coordinate-value based hyperslabbing. Subcycle may or may not work as you intend. Use at your own risk.\n",nco_prg_nm_get(),lmt.nm); */ /* Allocate enough space to hold coordinate */ dmn_val_dp=(double *)nco_malloc(dmn_sz*nco_typ_lng(NC_DOUBLE)); #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ { /* begin OpenMP critical */ /* Block is critical for identical in_id's Block is thread-safe for distinct in_id's */ /* 20110221: replace nco_get_vara() with nc_get_vara_double() */ /* Retrieve this coordinate */ nc_get_vara_double(grp_id,dim.cid,(const size_t *)&dmn_srt,(const size_t *)&dmn_sz,dmn_val_dp); } /* end OpenMP critical */ /* Officially change type */ dim.type=NC_DOUBLE; /* Assuming coordinate is monotonic, direction of monotonicity is determined by first two elements */ if(dmn_sz == 1L){ monotonic_direction=increasing; }else{ if(dmn_val_dp[0] > dmn_val_dp[1]) monotonic_direction=decreasing; else monotonic_direction=increasing; } /* end else */ if(monotonic_direction == increasing){ min_idx=0L; max_idx=dmn_sz-1L; }else{ min_idx=dmn_sz-1L; max_idx=0L; } /* end else */ /* Determine min and max values of entire coordinate */ dmn_min=dmn_val_dp[min_idx]; dmn_max=dmn_val_dp[max_idx]; /* Set defaults */ lmt.min_val=dmn_val_dp[min_idx]; lmt.max_val=dmn_val_dp[max_idx]; /* Convert UDUnits strings if necessary */ /* If we are here then either min_sng or max_sng or both are set */ if(lmt.lmt_typ == lmt_udu_sng){ if(!fl_udu_sng){ (void)fprintf(stdout,"%s: ERROR attempting to read units attribute from variable \"%s\" \n",nco_prg_nm_get(),dim.nm); nco_exit(EXIT_FAILURE); } /* end if */ if(lmt.min_sng) if(nco_cln_clc_org(lmt.min_sng,fl_udu_sng,lmt.lmt_cln,&lmt.min_val) != NCO_NOERR) nco_exit(EXIT_FAILURE); if(lmt.max_sng) if(nco_cln_clc_org(lmt.max_sng,fl_udu_sng,lmt.lmt_cln,&lmt.max_val) != NCO_NOERR) nco_exit(EXIT_FAILURE); }else{ /* end UDUnits conversion */ /* Convert user-specified limits into double precision numeric values, or supply defaults */ if(lmt.min_sng){ lmt.min_val=strtod(lmt.min_sng,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.min_sng,"strtod",sng_cnv_rcd); } /* !lmt.min_sng */ if(lmt.max_sng){ lmt.max_val=strtod(lmt.max_sng,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.max_sng,"strtod",sng_cnv_rcd); } /* !lmt.max_sng */ /* Re-base coordinates as necessary in multi-file operatators (MFOs) lmt.origin was calculated earlier in routine */ if(rec_dmn_and_mfo){ if(lmt.min_sng) lmt.min_val-=lmt.origin; if(lmt.max_sng) lmt.max_val-=lmt.origin; } /* endif MFO */ } /* end UDUnits conversion */ /* Warn when min_val > max_val (i.e., wrapped coordinate) */ if(nco_dbg_lvl_get() > nco_dbg_std && lmt.min_val > lmt.max_val) (void)fprintf(stderr,"%s: INFO Interpreting hyperslab specifications as wrapped coordinates [%s <= %g] and [%s >= %g]\n",nco_prg_nm_get(),lmt.nm,lmt.max_val,lmt.nm,lmt.min_val); /* Fail when... */ if( /* Following condition added 20000508, changes behavior of single point hyperslabs depending on whether hyperslab occurs in record dimension during multi-file operator operation. Altered behavior of single point hyperslabs so that single point hyperslabs in the record coordinate (i.e., -d time,1.0,1.0) may be treated differently than single point hyperslabs in other coordinates. Multifile operators will skip files if single point hyperslabs in record coordinate lay outside record coordinate range of file. For non-record coordinates (and for all operators besides ncra and ncrcat on record coordinates), single point hyperslabs will choose the closest value rather than skip the file (I believe). This should be verified. */ /* User specified single point, coordinate is not wrapped, and both extrema fall outside valid crd range */ (rec_dmn_and_mfo && (lmt.min_val == lmt.max_val) && ((lmt.min_val > dmn_max) || (lmt.max_val < dmn_min))) || /* User did not specify single point, coordinate is not wrapped, and either extrema falls outside valid crd range */ ((lmt.min_val < lmt.max_val) && ((lmt.min_val > dmn_max) || (lmt.max_val < dmn_min))) || /* User did not specify single point, coordinate is wrapped, and both extrema fall outside valid crd range */ ((lmt.min_val > lmt.max_val) && ((lmt.min_val > dmn_max) && (lmt.max_val < dmn_min))) || False){ /* Allow for possibility that current file is superfluous */ if(rec_dmn_and_mfo){ flg_no_data_ok=True; goto no_data_ok; }else{ (void)fprintf(stdout,"%s: ERROR User-specified coordinate value range %g <= %s <= %g does not fall within valid coordinate range %g <= %s <= %g\n",nco_prg_nm_get(),lmt.min_val,lmt.nm,lmt.max_val,dmn_min,lmt.nm,dmn_max); nco_exit(EXIT_FAILURE); } /* end else */ } /* end if */ /* Armed with target coordinate minima and maxima, we are ready to bracket user-specified range */ /* If min_sng or max_sng were omitted, use extrema */ if(lmt.min_sng == NULL) lmt.min_idx=min_idx; if(lmt.max_sng == NULL) lmt.max_idx=max_idx; /* Single slice requires finding the closest coordinate */ if(lmt.min_val == lmt.max_val){ double dst_new; double dst_old; lmt.min_idx=0L; dst_old=fabs(lmt.min_val-dmn_val_dp[0]); for(tmp_idx=1L;tmp_idx 100.0 or < -200.0). -1L flags are replaced with correct indices (0L or dmn_sz-1L) following search loop block. Overwriting -1L flags with 0L or dmn_sz-1L later is more heuristic than setting them = 0L here, since 0L is valid search result. */ if(monotonic_direction == increasing){ if(lmt.min_sng){ /* Find index of smallest coordinate greater than min_val */ tmp_idx=0L; while((dmn_val_dp[tmp_idx] < lmt.min_val) && (tmp_idx < dmn_sz)) tmp_idx++; if(tmp_idx != dmn_sz) lmt.min_idx=tmp_idx; else lmt.min_idx=-1L; } /* end if */ if(lmt.max_sng){ /* Find index of largest coordinate less than max_val */ tmp_idx=dmn_sz-1L; while((dmn_val_dp[tmp_idx] > lmt.max_val) && (tmp_idx > -1L)) tmp_idx--; if(tmp_idx != -1L) lmt.max_idx=tmp_idx; else lmt.max_idx=-1L; } /* end if */ /* 20110221: csz fix hyperslab bug TODO nco1007 triggered by ncks -O -v lat -d lat,20.,20.001 ~/nco/data/in.nc ~/foo.nc This returned all values but should have returned none Algorithm was broken because, although valid min and max indices existed, they contained the empty set. Now when this happens, set flg_no_data_err block */ if( /* Points are not wrapped ... */ (lmt.min_val < lmt.max_val) && /* ... and valid indices were found for both bracketing points... */ (lmt.min_idx != -1L && lmt.max_idx != -1L) && /* ...and indices contain empty set, i.e., min_idx > max_idx for increasing data... */ lmt.min_idx > lmt.max_idx) flg_no_data_err=True; /* end if monotonic_direction == increasing */ }else{ /* monotonic_direction == decreasing */ if(lmt.min_sng){ /* Find index of smallest coordinate greater than min_val */ tmp_idx=dmn_sz-1L; while((dmn_val_dp[tmp_idx] < lmt.min_val) && (tmp_idx > -1L)) tmp_idx--; if(tmp_idx != -1L) lmt.min_idx=tmp_idx; else lmt.min_idx=-1L; } /* end if */ if(lmt.max_sng){ /* Find index of largest coordinate less than max_val */ tmp_idx=0L; while((dmn_val_dp[tmp_idx] > lmt.max_val) && (tmp_idx < dmn_sz)) tmp_idx++; if(tmp_idx != dmn_sz) lmt.max_idx=tmp_idx; else lmt.max_idx=-1L; } /* end if */ if( /* Points are not wrapped ... */ (lmt.min_val > lmt.max_val) && /* ... and valid indices were found for both bracketing points... */ (lmt.min_idx != -1L && lmt.max_idx != -1L) && /* ...and indices contain empty set, i.e., min_idx < max_idx for decreasing data... */ lmt.min_idx < lmt.max_idx) flg_no_data_err=True; } /* end else monotonic_direction == decreasing */ /* Case where both min_idx and max_idx = -1 was flagged as error above Case of wrapped coordinate: Either, but not both, of min_idx or max_idx will be flagged with -1 See explanation above */ if(lmt.min_idx == -1L && (lmt.min_val > lmt.max_val)) lmt.min_idx=0L; if(lmt.max_idx == -1L && (lmt.min_val > lmt.max_val)) lmt.max_idx=dmn_sz-1L; } /* end if min_val != max_val */ /* User-specified ranges are now bracketed */ /* Convert indices of minima and maxima to srt and end indices */ if(monotonic_direction == increasing){ lmt.srt=lmt.min_idx; lmt.end=lmt.max_idx; }else{ lmt.srt=lmt.max_idx; lmt.end=lmt.min_idx; } /* end else */ /* Free space allocated for dimension */ dmn_val_dp=(double*)nco_free(dmn_val_dp); if(rec_dmn_and_mfo){ /* No wrapping with multi-file operators */ if((monotonic_direction == increasing && lmt.min_val > lmt.max_val) || (monotonic_direction == decreasing && lmt.min_val < lmt.max_val)){ flg_no_data_ok=True; goto no_data_ok; } /* endif */ if(rec_usd_cml == 0L){ /* Skipped records remains zero until valid records are processed */ lmt.rec_skp_vld_prv=0L; }else if(rec_usd_cml > 0L){ /* Otherwise, adjust starting index by records skipped in jumps across file boundaries */ lmt.srt+=lmt.srd-1L-lmt.rec_skp_vld_prv%lmt.srd; if(lmt.srt>lmt.end){ /* Do not allow record dimension wrapping in MFOs */ flg_no_data_ok=True; goto no_data_ok; } /* endif */ } /* endif */ /* If we are here then there are valid records in current file */ } /* end if rec_dmn_and_mfo */ }else{ /* end if limit arguments were coordinate values */ /* Convert limit strings to zero-based indicial offsets */ /* Specifying stride alone, but not min or max, is legal, e.g., -d time,,,2 Thus is_usr_spc_lmt may be True, even though one or both of min_sng, max_sng is NULL Furthermore, both min_sng and max_sng are artifically created by nco_lmt_sct_mk() for record dimensions when the user does not explicitly specify limits. In this case, min_sng_and max_sng are non-NULL though no limits were specified In fact, min_sng and max_sng are set to the minimum and maximum string values of the first file processed. However, we can tell if these strings were artificially generated because nco_lmt_sct_mk() sets the is_usr_spc_lmt flag to False in such cases. Subsequent files may have different numbers of records, but nco_lmt_sct_mk() is only called once. Thus we must update min_idx and max_idx here for each file This causes min_idx and max_idx to be out of sync with min_sng and max_sng, which are only set in nco_lmt_sct_mk() for the first file. In hindsight, artificially generating min_sng and max_sng may be bad idea */ /* Following logic is messy, but hard to simplify */ if(!lmt.min_sng || !lmt.is_usr_spc_lmt){ /* No user-specified value available--generate minimal dimension index */ if(FORTRAN_IDX_CNV) lmt.min_idx=1L; else lmt.min_idx=0L; }else{ /* Use user-specified limit when available */ lmt.min_idx=strtol(lmt.min_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.min_sng,"strtol",sng_cnv_rcd); } /* end if */ if(!lmt.max_sng || !lmt.is_usr_spc_lmt){ /* No user-specified value available---generate maximal dimension index */ if(FORTRAN_IDX_CNV) lmt.max_idx=dmn_sz; else lmt.max_idx=dmn_sz-1L; }else{ /* Use user-specified limit when available */ lmt.max_idx=strtol(lmt.max_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.max_sng,"strtol",sng_cnv_rcd); } /* end if */ /* Adjust indices if FORTRAN style input was specified */ if(FORTRAN_IDX_CNV){ /* 20120726: Die when Fortran index is zero */ if(lmt.min_idx == 0L || lmt.max_idx == 0L){ (void)fprintf(stdout,"%s: ERROR User-specified Fortran (1-based) index for dimension %s = 0.\n",nco_prg_nm_get(),lmt.nm); msg_sng=strdup("Fortran indices must be >= 1"); NCO_SYNTAX_ERROR=True; } /* endif illegal Fortran index */ /* 20120709: Adjust positive indices only */ if(lmt.min_idx > 0L) lmt.min_idx--; if(lmt.max_idx > 0L) lmt.max_idx--; } /* end if */ /* 20120709 Negative integer as min or max element of hyperslab specification indicates offset from end */ if(lmt.min_idx < 0L) lmt.min_idx+=dmn_sz-1L; if(lmt.max_idx < 0L) lmt.max_idx+=dmn_sz-1L; /* Exit if requested indices are always invalid for all operators... */ if(lmt.min_idx < 0L){ msg_sng=strdup("Minimum index is too negative"); NCO_SYNTAX_ERROR=True; }else if(lmt.max_idx < 0L){ msg_sng=strdup("Maximum index is too negative"); NCO_SYNTAX_ERROR=True; }else if(lmt.ssc > lmt.srd){ (void)fprintf(stdout,"%s: ERROR User-specified subcycle exceeds stride for %s: %li > %li\n",nco_prg_nm_get(),lmt.nm,lmt.ssc,lmt.srd); msg_sng=strdup("Subcycle exceeds stride"); NCO_SYNTAX_ERROR=True; }else if(!rec_dmn_and_mfo && lmt.min_idx >= dmn_sz){ msg_sng=strdup("Minimum index greater than size in non-MFO"); NCO_SYNTAX_ERROR=True; (void)fprintf(stdout,"%s: ERROR User-specified dimension index range %li <= %s <= %li does not fall within valid dimension index range 0 <= %s <= %li\n",nco_prg_nm_get(),lmt.min_idx,lmt.nm,lmt.max_idx,lmt.nm,dmn_sz-1L); } /* end if impossible indices */ if(NCO_SYNTAX_ERROR){ (void)fprintf(stdout,"%s: ERROR evaluating hyperslab specification for %s: %s\n%s: HINT Conform request to hyperslab documentation at http://nco.sf.net/nco.html#hyp\n",nco_prg_nm_get(),lmt.nm,msg_sng,nco_prg_nm_get()); msg_sng=(char *)nco_free(msg_sng); nco_exit(EXIT_FAILURE); } /* !NCO_SYNTAX_ERROR */ /* NB: Subcycle is officially supported only for ncra and ncrcat (record dimension only) */ if(lmt.ssc != 1L && !rec_dmn_and_mfo) (void)fprintf(stderr,"%s: WARNING Subcycle argument is only supported for the record dimension on ncra and ncrcat operations\n",nco_prg_nm_get()); /* Logic depends on whether this is record dimension in multi-file operator */ if(!rec_dmn_and_mfo || !lmt.is_usr_spc_lmt){ /* For non-record dimensions and for record dimensions where limit was automatically generated (to include whole file), starting and ending indices are simply minimum and maximum indices already in structure */ lmt.srt=lmt.min_idx; lmt.end=lmt.max_idx; }else{ /* Initialize rec_skp_vld_prv to 0L on first call to nco_lmt_evl() This is necessary due to intrinsic hysterisis of rec_skp_vld_prv rec_skp_vld_prv is used only by multi-file operators rec_skp_vld_prv counts records skipped at end of previous valid file rec_usd_cml and rec_skp_ntl_spf are both zero only for first file */ if(rec_usd_cml == 0L && lmt.rec_skp_ntl_spf == 0L) lmt.rec_skp_vld_prv=0L; /* For record dimensions with user-specified limit, allow possibility that limit pertains to record dimension in a multi-file operator. Then user-specified maximum index may exceed number of records in any one file Thus lmt.srt does not necessarily equal lmt.min_idx and lmt.end does not necessarily equal lmt.max_idx */ /* NB: Stride is officially supported for ncks (all dimensions) and for ncra and ncrcat (record dimension only) */ if(lmt.srd != 1L && nco_prg_id != ncks && !lmt.is_rec_dmn) (void)fprintf(stderr,"%s: WARNING Stride argument for non-record dimension is only supported by ncks, use at your own risk...\n",nco_prg_nm_get()); { /* Block hides scope of local internal variables */ long srt_min_lcl; /* [idx] Minimum start index (in absolute index space, i.e., relative to first file) for current file */ long end_max_lcl; /* [idx] Maximum end index (in absolute index space, i.e., relative to first file) for current file */ srt_min_lcl=(lmt.is_usr_spc_min ? lmt.min_idx : lmt.rec_in_cml+0L); end_max_lcl=(lmt.is_usr_spc_max ? lmt.max_idx : lmt.rec_in_cml+dmn_sz-1L); /* Maximum allowed index in record dimension */ lmt.idx_end_max_abs=end_max_lcl; /* Have we reached file containing srt_min_lcl yet? */ if(srt_min_lcl > lmt.rec_in_cml+dmn_sz-1L){ /* This and all previous files are superfluous because the starting record is in a subsequent file */ flg_no_data_ok=True; goto no_data_ok; } /* endif srt_min_lcl in future file */ /* Until records have been used, start index is srt_min_lcl adjusted for records contained in all previous files Thereafter start index loses memory of/dependence on absolute start index, and only cares for how many records, if any, were skipped since last valid record. This number, modulo stride, is new start index. */ if(rec_usd_cml == 0L) lmt.srt=srt_min_lcl-lmt.rec_in_cml; else lmt.srt=lmt.srd-1L-lmt.rec_skp_vld_prv%lmt.srd; if(lmt.srt > dmn_sz-1L){ /* Perhaps data were read in previous file(s) yet next record is in future file due to long stride */ flg_no_data_ok=True; goto no_data_ok; } /* endif */ lmt.end=(end_max_lcl < lmt.rec_in_cml+dmn_sz) ? end_max_lcl-lmt.rec_in_cml : dmn_sz-1L; /* If lmt.srt <= lmt.end then then there are (may be?) valid records in current file If lmt.srt > lmt.end then all desired data (for this dimension) were definitely read in previous file(s) This happens when user-specified lmt.max_idx is not desired (because min_idx+N*stride skips over it) Then we would first find out right here that all desired data have been read Test for end_max_lcl above does not catch this case because we are _in_ (not beyond) file with end_max_lcl */ /* Are we past file containing end_max_lcl yet? */ if(end_max_lcl < lmt.rec_in_cml){ /* This and all subsequent files are superfluous because all requested records have already been read Optimize MFOs by checking "input complete" flag to jump out of file loop Saves time because no other input files will be opened */ lmt.flg_input_complete=True; flg_no_data_ok=True; goto no_data_ok; } /* endif past end_max_lcl */ if((end_max_lcl < lmt.rec_in_cml) || /* Are we past file containing end_max_lcl yet? */ (lmt.srt > lmt.end)){ /* Does stride put first index beyond last possible index? */ /* This and all subsequent files are superfluous because all requested records have already been read Optimize MFOs by checking "input complete" flag to jump out of file loop Saves time because no other input files will be opened */ lmt.flg_input_complete=True; flg_no_data_ok=True; goto no_data_ok; } /* endif already past end_max_lcl or will stride over end_max_lcl */ } /* end block hides scope of local internal variables */ /* If we are here then there are valid records in current file */ } /* endif user-specified limits to record dimension */ } /* end else limit arguments are hyperslab indices */ /* NB: MFO record dimension never reaches this block if current file is superfluous In that case code has already branched down to flg_data_ok or flg_data_err */ if(rec_dmn_and_mfo){ /* NB: This is---and must be---performed as integer arithmetic */ cnt_rmn_crr=1L+(lmt.end-lmt.srt)/lmt.srd; /* This fixes "sloppy" specification of end index by user, i.e., ensures that end index coincides with a stride */ lmt.end=lmt.srt+(cnt_rmn_crr-1L)*lmt.srd; /* Save current rec_skp_vld_prv for diagnostics (printed below) for this file */ rec_skp_vld_prv_dgn=lmt.rec_skp_vld_prv; /* Next file must know how many records in this file come after (and thus will be skipped) last used record in this file */ lmt.rec_skp_vld_prv=dmn_sz-1L-lmt.end; } /* !rec_dmn_and_mfo */ /* Compute cnt from srt, end, and srd This is fine for multi-file record dimensions since those operators read-in one record at a time and thus never actually use lmt.cnt for record dimension. */ if(lmt.srd == 1L){ if(lmt.srt <= lmt.end) lmt.cnt=lmt.end-lmt.srt+1L; else lmt.cnt=dmn_sz-lmt.srt+lmt.end+1L; }else{ if(lmt.srt <= lmt.end) lmt.cnt=1L+(lmt.end-lmt.srt)/lmt.srd; else lmt.cnt=1L+((dmn_sz-lmt.srt)+lmt.end)/lmt.srd; } /* end else */ /* NB: Degenerate cases of WRP && SRD exist for which dmn_cnt_2 == 0 This occurs when srd is large enough, or max_idx small enough, such that no values are selected in the second read. e.g., "-d lon,60,0,10" if sz(lon)=128 has dmn_cnt_2 == 0 Since netCDF library reports an error reading and writing cnt=0 dimensions, kludge is necessary Syntax ensures that it is always the second read, not the first, which is obviated Therefore we convert these degenerate cases into non-wrapped coordinates to be processed by single read For these degenerate cases only, [srt,end] are not a permutation of [min_idx,max_idx] */ if( (lmt.srd != 1L) && /* SRD */ (lmt.srt > lmt.end) && /* WRP */ (lmt.cnt == (1L+(dmn_sz-lmt.srt-1L)/lmt.srd)) && /* dmn_cnt_1 == cnt -> dmn_cnt_2 == 0 */ True){ long greatest_srd_multiplier_1st_hyp_slb; /* Greatest integer m such that srt+m*srd < dmn_sz */ long last_good_idx_1st_hyp_slb; /* C-index of last valid member of 1st hyperslab (= srt+m*srd) */ /* long left_over_idx_1st_hyp_slb;*/ /* # of elements from first hyperslab that count towards current stride */ long first_good_idx_2nd_hyp_slb; /* C-index of first valid member of 2nd hyperslab, if any */ /* NB: Perform these operations with integer arithmetic or else! */ /* Wrapped dimensions with stride may not start at idx 0 on second read */ greatest_srd_multiplier_1st_hyp_slb=(dmn_sz-lmt.srt-1L)/lmt.srd; last_good_idx_1st_hyp_slb=lmt.srt+lmt.srd*greatest_srd_multiplier_1st_hyp_slb; /* left_over_idx_1st_hyp_slb=dmn_sz-last_good_idx_1st_hyp_slb-1L;*/ first_good_idx_2nd_hyp_slb=(last_good_idx_1st_hyp_slb+lmt.srd)%dmn_sz; /* Conditions causing dmn_cnt_2 == 0 */ if(first_good_idx_2nd_hyp_slb > lmt.end) lmt.end=last_good_idx_1st_hyp_slb; } /* end if */ /* Cases where domain brackets no data, in error, have counts set to zero here This kludge allows codepaths for both WRP and out-of-domain to flow without goto statements Out-of-domain errors will soon exit with error, while WRP conditions will proceed */ if(flg_no_data_err) lmt.cnt=0L; /* Exit when valid bracketed range contains no coordinates and that is not legal, i.e., this is not a superfluous file in an MFO */ if(lmt.cnt == 0){ if(lmt.lmt_typ == lmt_crd_val) (void)fprintf(stdout,"%s: ERROR Domain %g <= %s <= %g brackets no coordinate values.\n",nco_prg_nm_get(),lmt.min_val,lmt.nm,lmt.max_val); if(lmt.lmt_typ == lmt_dmn_idx) (void)fprintf(stdout,"%s: ERROR Empty domain for %s\n",nco_prg_nm_get(),lmt.nm); nco_exit(EXIT_FAILURE); } /* end if */ /* Coordinate-valued limits that bracket no values in current file jump here with goto Index-valued limits with no values in current file flow here naturally */ no_data_ok: /* end goto */ if(flg_no_data_ok){ /* File is superfluous (contributes no data) to specified hyperslab Set output parameters to well-defined state This state must not cause ncra or ncrcat to retrieve any data ncra and ncrcat use loops for the record dimension, so this is accomplished by setting loop control values (lmt_rec.srt > lmt_rec.end) that cause record loop always to be skipped (never entered) */ lmt.srt=-1L; lmt.end=lmt.srt-1L; lmt.cnt=-1L; /* Augment number of records skipped in initial superfluous files */ if(rec_usd_cml == 0L) lmt.rec_skp_ntl_spf+=dmn_sz; /* Augment records skipped since last good one */ lmt.rec_skp_vld_prv+=dmn_sz; /* Set variables to preserve utility of diagnostics at end of routine */ cnt_rmn_crr=rec_skp_vld_prv_dgn=0L; } /* endif */ /* Accumulate count of records in all opened files, including this one Increment here at end so this structure member includes records from current file only at end of this routine, where it can only be used diagnostically NB: Location of this augmentation is important! Moving it would have side-effects! */ lmt.rec_in_cml+=dmn_sz; /* Place contents of working structure in location of returned structure */ *lmt_ptr=lmt; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)nco_prn_lmt(lmt,min_lmt_typ,FORTRAN_IDX_CNV,flg_no_data_ok,rec_usd_cml,monotonic_direction,rec_dmn_and_mfo,cnt_rmn_ttl,cnt_rmn_crr,rec_skp_vld_prv_dgn); } /* end dbg */ if(lmt.srt > lmt.end && !flg_no_data_ok){ if(nco_prg_id != ncks) (void)fprintf(stderr,"WARNING: Possible instance of Schweitzer data hole requiring better diagnostics TODO #148\n"); if(nco_prg_id != ncks) (void)fprintf(stderr,"HINT: If operation fails, try multislabbing (http://nco.sf.net/nco.html#msa) wrapped dimension using ncks first, and then apply %s to the resulting file\n",nco_prg_nm_get()); } /* end dbg */ fl_udu_sng=(char *)nco_free(fl_udu_sng); } /* end nco_lmt_evl() */ void nco_lmt_evl_dmn_crd /* [fnc] Parse user-specified limits into hyperslab specifications */ (const int nc_id, /* I [ID] netCDF file ID */ long rec_usd_cml, /* I [nbr] Number of valid records already processed (only used for record dimensions in multi-file operators) */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ const char * const grp_nm_fll,/* I [sng] Full group name (dimension or coordinate) */ const char * const nm, /* I [sng] Name (dimension or coordinate) */ const size_t sz, /* I [nbr] Size (dimension or coordinate) */ const nco_bool is_rec, /* I [flg] Is a record (dimension or coordinate) */ const nco_bool is_crd, /* I [flg] Is a coordinate variable */ lmt_sct *lmt_ptr) /* I/O [sct] Structure from nco_lmt_prs() in input, filled on output */ { /* Purpose: Take parsed list of dimension names, minima, and maxima strings and find appropriate indices into dimensions for formulation of dimension start and count vectors, or fail trying. Based on original nco_lmt_evl(). Used for both dimensions and coordinate variables. Use case example: /lon(4) /g8/lon(2) ncks -d lon,0,3,1 -v lon -H ~/nco/data/in_grp.nc "-d lon,0,3,1" is valid for /lon(4) but not for /g8/lon(2) Reminder: Coordinate values should be specified using real notation with a decimal point required in the value, whereas dimension indices are specified using integer notation without a decimal point. ncks -d lat,-90.,90.,1 -H -v area ~/nco/data/in_grp.nc # limit type is defined as lmt_crd_val ncks -d lat,0,1,1 -H -v area ~/nco/data/in_grp.nc # limit type is defined as lmt_dmn_idx lmt_crd_val, 0, Coordinate value limit lmt_dmn_idx, 1, Dimension index limit lmt_udu_sng 2, UDUnits string Tests: ncks -D 11 -d lon,0.,90.,1 -v lon -H ~/nco/data/in_grp.nc ncks -D 11 -d lon,0,1,1 -v lon -H ~/nco/data/in_grp.nc */ char *fl_udu_sng=NULL_CEWI; /* [sng] Store units attribute of coordinate dimension */ char *msg_sng=NULL_CEWI; /* [sng] Error message */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ nco_bool flg_no_data_err=False; /* [flg] True if domain brackets no data (and not an MFO/record coordinate) */ nco_bool flg_no_data_ok=False; /* [flg] True if file contains no data for hyperslab */ nco_bool rec_dmn_and_mfo=False; /* [flg] True if record dimension in multi-file operator */ nco_bool NCO_SYNTAX_ERROR=False;/* [flg] Syntax error in hyperslab specification */ dmn_sct dim; /* [sct] Dimension Structure */ lmt_sct lmt; /* [sct] Structure from nco_lmt_prs() */ int min_lmt_typ=int_CEWI; int max_lmt_typ=int_CEWI; int nco_prg_id; /* [enm] Program ID */ monotonic_direction_enm monotonic_direction=not_checked; /* CEWI */ long dmn_sz; /* [nbr] Dimension size */ long cnt_rmn_crr=-1L; /* [nbr] Records to extract from current file */ long cnt_rmn_ttl=-1L; /* [nbr] Total records to be read from this and all remaining files */ long rec_skp_vld_prv_dgn=-1L; /* [nbr] Records skipped at end of previous valid file, if any (diagnostic only) */ int var_id=-1; /* [id] ID of variable */ int grp_id=-1; /* [id] ID of group */ nc_type var_typ=NC_NAT; /* [enm] Type of variable */ lmt=*lmt_ptr; nco_prg_id=nco_prg_id_get(); /* Initialize limit structure */ lmt.flg_mro=False; lmt.max_val=0.0; lmt.min_val=0.0; lmt.ssc=1L; lmt.srd=1L; lmt.flg_input_complete=False; /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,grp_nm_fll,&grp_id); /* Use parameter to inquire about coordinate. NB: There might be cases where a variable with the same name as dimension exists, but it is not a "real" 1-D coordinate. Coordinates must be 1D. Use case: ncks -O -v ts -d time,0,1 -d Latitude,40.0 -d Longitude,-105.0 http://hydro1.sci.gsfc.nasa.gov/opendap/hyrax/ncml/LPRM_AMSRE_D_SOILM3_timeSeries.ncml amsre.nc */ if(is_crd){ /* Obtain coordinate variable ID using group ID */ (void)nco_inq_varid(grp_id,nm,&var_id); /* Get coordinate type */ (void)nco_inq_vartype(grp_id,var_id,&var_typ); } /* !is_crd */ /* Use info from parameter to assign locally used size */ dmn_sz=sz; /* Use info from parameter to assign record/not record to limit */ lmt.is_rec_dmn=is_rec; /* Logic on whether to allow skipping current file depends on whether limit is specified for record dimension in multi-file operators. This information is not used in single-file operators, though whether the limit is a record limit may be tested. Program defensively and define this flag in all cases. */ if(lmt.is_rec_dmn && (nco_prg_id == ncra || nco_prg_id == ncrcat)) rec_dmn_and_mfo=True; else rec_dmn_and_mfo=False; if(rec_dmn_and_mfo){ lmt.rec_dmn_sz=dmn_sz; lmt.idx_end_max_abs=lmt.rec_in_cml+dmn_sz-1L; /* Maximum allowed index in record dimension */ } /* !rec_dmn_and_mfo */ /* Bomb if dmn_sz < 1 */ if(dmn_sz < 1L){ (void)fprintf(stdout,"%s: ERROR Size of dimension %s is %li in input file, but must be > 0 in order to apply limits.\n",nco_prg_nm_get(),lmt.nm,dmn_sz); nco_exit(EXIT_FAILURE); } /* end if */ if(lmt.srd_sng){ if(strchr(lmt.srd_sng,'.') || strchr(lmt.srd_sng,'e') || strchr(lmt.srd_sng,'E') || strchr(lmt.srd_sng,'d') || strchr(lmt.srd_sng,'D')){ (void)fprintf(stdout,"%s: ERROR Requested stride for %s, %s, must be integer\n",nco_prg_nm_get(),lmt.nm,lmt.srd_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.srd=strtol(lmt.srd_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.srd_sng,"strtol",sng_cnv_rcd); if(lmt.srd < 1L){ (void)fprintf(stdout,"%s: ERROR Stride for %s is %li but must be > 0\n",nco_prg_nm_get(),lmt.nm,lmt.srd); nco_exit(EXIT_FAILURE); } /* end if */ } /* !lmt.srd_sng */ if(lmt.ssc_sng){ if(strchr(lmt.ssc_sng,'.') || strchr(lmt.ssc_sng,'e') || strchr(lmt.ssc_sng,'E') || strchr(lmt.ssc_sng,'d') || strchr(lmt.ssc_sng,'D')){ (void)fprintf(stdout,"%s: ERROR Requested subcycle for %s, %s, must be integer\n",nco_prg_nm_get(),lmt.nm,lmt.ssc_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.ssc=strtol(lmt.ssc_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.ssc_sng,"strtol",sng_cnv_rcd); if(lmt.ssc < 1L){ (void)fprintf(stdout,"%s: ERROR Subcycle for %s is %li but must be > 0\n",nco_prg_nm_get(),lmt.nm,lmt.ssc); nco_exit(EXIT_FAILURE); } /* end if */ if(nco_prg_id != ncra && nco_prg_id != ncrcat){ (void)fprintf(stdout,"%s: ERROR Subcycle only implemented for ncra and ncrcat\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end ncra */ } /* !lmt.ssc_sng */ if(lmt.mro_sng){ if(strcasecmp(lmt.mro_sng,"m")){ (void)fprintf(stdout,"%s: ERROR Requested MRO flag for %s, \"%s\", must be 'm' or 'M'\n",nco_prg_nm_get(),lmt.nm,lmt.mro_sng); nco_exit(EXIT_FAILURE); } /* end if */ lmt.flg_mro=True; } /* !lmt.mro_sng */ /* In case flg_mro is set in ncra.c by --mro */ if(lmt.flg_mro){ if(nco_prg_id == ncrcat){ (void)fprintf(stdout,"%s: INFO Specifying Multi-Record Output (MRO) option ('m', 'M', or --mro) is redundant. MRO is always true for ncrcat.\n",nco_prg_nm_get()); }else if(nco_prg_id != ncra){ (void)fprintf(stdout,"%s: ERROR Multi-Record Output (MRO) ('m', 'M', or --mro) is only valid for ncra.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end else */ } /* !lmt.mro_sng */ /* If min_sng and max_sng are both NULL then set type to lmt_dmn_idx */ if(lmt.min_sng == NULL && lmt.max_sng == NULL){ /* Limiting indices will be set to default extrema a bit later */ min_lmt_typ=max_lmt_typ=lmt_dmn_idx; }else{ /* min_sng and max_sng are not both NULL */ /* Limit is coordinate value if string contains decimal point or is in exponential format Otherwise limit is interpreted as zero-based dimension offset */ if(lmt.min_sng) min_lmt_typ=nco_lmt_typ(lmt.min_sng); if(lmt.max_sng) max_lmt_typ=nco_lmt_typ(lmt.max_sng); /* Copy lmt_typ from defined limit to undefined */ if(lmt.min_sng == NULL) min_lmt_typ=max_lmt_typ; if(lmt.max_sng == NULL) max_lmt_typ=min_lmt_typ; } /* end else */ /* Both min_lmt_typ and max_lmt_typ are now defined Continue only if both limits are of the same type */ if(min_lmt_typ != max_lmt_typ){ (void)fprintf(stdout,"%s: ERROR -d %s,%s,%s\n",nco_prg_nm_get(),lmt.nm,lmt.min_sng,lmt.max_sng); (void)fprintf(stdout,"Limits on dimension \"%s\" must be of same numeric type:\n",lmt.nm); (void)fprintf(stdout,"\"%s\" was interpreted as a %s.\n",lmt.min_sng,(min_lmt_typ == lmt_crd_val) ? "coordinate value" : (FORTRAN_IDX_CNV) ? "one-based dimension index" : "zero-based dimension index"); (void)fprintf(stdout,"\"%s\" was interpreted as a %s.\n",lmt.max_sng,(max_lmt_typ == lmt_crd_val) ? "coordinate value" : (FORTRAN_IDX_CNV) ? "one-based dimension index" : "zero-based dimension index"); (void)fprintf(stdout,"(Limit arguments containing a decimal point (or in exponential format) are interpreted as coordinate values; arguments without a decimal point are interpreted as zero-based or one-based (depending on -F switch) dimensional indices.)\n"); nco_exit(EXIT_FAILURE); } /* end if */ lmt.lmt_typ=min_lmt_typ; /* Coordinate re-basing code */ lmt.origin=0.0; /* If there is a coordinate variable */ if(is_crd){ /* Get variable ID of coordinate. NOTE: using group ID */ (void)nco_inq_varid(grp_id,lmt.nm,&dim.cid); char *cln_sng=NULL_CEWI; fl_udu_sng=nco_lmt_get_udu_att(grp_id,var_id,"units"); /* Units attribute of coordinate variable */ cln_sng=nco_lmt_get_udu_att(grp_id,var_id,"calendar"); /* Calendar attribute */ if(rec_dmn_and_mfo && fl_udu_sng && lmt.rbs_sng){ #ifdef ENABLE_UDUNITS /* Re-base and reset origin to 0.0 if re-basing fails */ if(nco_cln_clc_org(fl_udu_sng,lmt.rbs_sng,lmt.lmt_cln,&lmt.origin) != NCO_NOERR) lmt.origin=0.0; #endif /* !ENABLE_UDUNITS */ } /* endif */ /* ncra and ncrcat read the "calendar" attribute in main() Avoid multiple reads of calendar attribute in multi-file operations */ if(!rec_dmn_and_mfo){ if(cln_sng) lmt.lmt_cln=nco_cln_get_cln_typ(cln_sng); else lmt.lmt_cln=cln_nil; } /* endif */ if(cln_sng) cln_sng=(char *)nco_free(cln_sng); } /* End Needed only to read variable, if dimension is a coordinate variable */ if((lmt.lmt_typ == lmt_crd_val) || (lmt.lmt_typ == lmt_udu_sng)){ double *dmn_val_dp=NULL; double dmn_max; double dmn_min; long max_idx; long min_idx; long tmp_idx; long dmn_srt=0L; /* Warn when coordinate type is weird */ if(var_typ == NC_BYTE || var_typ == NC_UBYTE || var_typ == NC_CHAR || var_typ == NC_STRING) (void)fprintf(stderr,"\n%s: WARNING Coordinate %s is type %s. Dimension truncation is unpredictable.\n",nco_prg_nm_get(),lmt.nm,nco_typ_sng(var_typ)); /* Allocate enough space to hold coordinate */ dmn_val_dp=(double *)nco_malloc(dmn_sz*nco_typ_lng(NC_DOUBLE)); #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ { /* begin OpenMP critical */ /* Block is critical for identical in_id's Block is thread-safe for distinct in_id's */ /* 20110221: replace nco_get_vara() with nc_get_vara_double() */ /* Retrieve this coordinate */ int rcd; rcd=nc_get_vara_double(grp_id,var_id,(const size_t *)&dmn_srt,(const size_t *)&dmn_sz,dmn_val_dp); /* Exit if read error */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nc_get_vara_double()"); } /* end OpenMP critical */ /* Officially change type */ var_typ=NC_DOUBLE; /* Assuming coordinate is monotonic, direction of monotonicity is determined by first two elements */ if(dmn_sz == 1L){ monotonic_direction=increasing; }else{ if(dmn_val_dp[0] > dmn_val_dp[1]) monotonic_direction=decreasing; else monotonic_direction=increasing; } /* end else */ if(monotonic_direction == increasing){ min_idx=0L; max_idx=dmn_sz-1L; }else{ min_idx=dmn_sz-1L; max_idx=0L; } /* end else */ /* Determine min and max values of entire coordinate */ dmn_min=dmn_val_dp[min_idx]; dmn_max=dmn_val_dp[max_idx]; /* Set defaults */ lmt.min_val=dmn_val_dp[min_idx]; lmt.max_val=dmn_val_dp[max_idx]; /* Convert UDUnits strings if necessary */ /* If we are here then either min_sng or max_sng or both are set */ if(lmt.lmt_typ == lmt_udu_sng){ if(!fl_udu_sng){ (void)fprintf(stdout,"%s: ERROR attempting to read units attribute from variable \"%s\" \n",nco_prg_nm_get(),lmt.nm); nco_exit(EXIT_FAILURE); } /* end if */ if(lmt.min_sng) if(nco_cln_clc_org(lmt.min_sng,fl_udu_sng,lmt.lmt_cln,&lmt.min_val) != NCO_NOERR) nco_exit(EXIT_FAILURE); if(lmt.max_sng) if(nco_cln_clc_org(lmt.max_sng,fl_udu_sng,lmt.lmt_cln,&lmt.max_val) != NCO_NOERR) nco_exit(EXIT_FAILURE); }else{ /* end UDUnits conversion */ /* Convert user-specified limits into double precision numeric values, or supply defaults */ if(lmt.min_sng){ lmt.min_val=strtod(lmt.min_sng,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.min_sng,"strtod",sng_cnv_rcd); } /* !lmt.min_sng */ if(lmt.max_sng){ lmt.max_val=strtod(lmt.max_sng,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.max_sng,"strtod",sng_cnv_rcd); } /* !lmt.max_sng */ /* Re-base coordinates as necessary in multi-file operatators (MFOs) lmt.origin was calculated earlier in routine */ if(rec_dmn_and_mfo){ if(lmt.min_sng) lmt.min_val-=lmt.origin; if(lmt.max_sng) lmt.max_val-=lmt.origin; } /* endif MFO */ } /* end UDUnits conversion */ /* Warn when min_val > max_val (i.e., wrapped coordinate) */ if(nco_dbg_lvl_get() > nco_dbg_std && lmt.min_val > lmt.max_val) (void)fprintf(stderr,"%s: INFO Interpreting hyperslab specifications as wrapped coordinates [%s <= %g] and [%s >= %g]\n",nco_prg_nm_get(),lmt.nm,lmt.max_val,lmt.nm,lmt.min_val); /* Fail when... */ if( /* Following condition added 20000508, changes behavior of single point hyperslabs depending on whether hyperslab occurs in record dimension during multi-file operator operation. Altered behavior of single point hyperslabs so that single point hyperslabs in the record coordinate (i.e., -d time,1.0,1.0) may be treated differently than single point hyperslabs in other coordinates. Multifile operators will skip files if single point hyperslabs in record coordinate lay outside record coordinate range of file. For non-record coordinates (and for all operators besides ncra and ncrcat on record coordinates), single point hyperslabs will choose the closest value rather than skip the file (I believe). This should be verified. */ /* User specified single point, coordinate is not wrapped, and both extrema fall outside valid crd range */ (rec_dmn_and_mfo && (lmt.min_val == lmt.max_val) && ((lmt.min_val > dmn_max) || (lmt.max_val < dmn_min))) || /* User did not specify single point, coordinate is not wrapped, and either extrema falls outside valid crd range */ ((lmt.min_val < lmt.max_val) && ((lmt.min_val > dmn_max) || (lmt.max_val < dmn_min))) || /* User did not specify single point, coordinate is wrapped, and both extrema fall outside valid crd range */ ((lmt.min_val > lmt.max_val) && ((lmt.min_val > dmn_max) && (lmt.max_val < dmn_min))) || False){ /* Allow for possibility that current file is superfluous */ if(rec_dmn_and_mfo){ flg_no_data_ok=True; goto no_data_ok; }else{ (void)fprintf(stdout,"%s: ERROR User-specified coordinate value range %g <= %s <= %g does not fall within valid coordinate range %g <= %s <= %g\n",nco_prg_nm_get(),lmt.min_val,lmt.nm,lmt.max_val,dmn_min,lmt.nm,dmn_max); nco_exit(EXIT_FAILURE); } /* end else */ } /* end if */ /* Armed with target coordinate minima and maxima, we are ready to bracket user-specified range */ /* If min_sng or max_sng were omitted, use extrema */ if(lmt.min_sng == NULL) lmt.min_idx=min_idx; if(lmt.max_sng == NULL) lmt.max_idx=max_idx; /* Single slice requires finding the closest coordinate */ if(lmt.min_val == lmt.max_val){ double dst_new; double dst_old; lmt.min_idx=0L; dst_old=fabs(lmt.min_val-dmn_val_dp[0]); for(tmp_idx=1L;tmp_idx 100.0 or < -200.0). -1L flags are replaced with correct indices (0L or dmn_sz-1L) following search loop block. Overwriting -1L flags with 0L or dmn_sz-1L later is more heuristic than setting them = 0L here, since 0L is valid search result. */ if(monotonic_direction == increasing){ if(lmt.min_sng){ /* Find index of smallest coordinate greater than min_val */ tmp_idx=0L; while((dmn_val_dp[tmp_idx] < lmt.min_val) && (tmp_idx < dmn_sz)) tmp_idx++; if(tmp_idx != dmn_sz) lmt.min_idx=tmp_idx; else lmt.min_idx=-1L; } /* end if */ if(lmt.max_sng){ /* Find index of largest coordinate less than max_val */ tmp_idx=dmn_sz-1L; while((dmn_val_dp[tmp_idx] > lmt.max_val) && (tmp_idx > -1L)) tmp_idx--; if(tmp_idx != -1L) lmt.max_idx=tmp_idx; else lmt.max_idx=-1L; } /* end if */ /* 20110221: csz fix hyperslab bug TODO nco1007 triggered by ncks -O -v lat -d lat,20.,20.001 ~/nco/data/in.nc ~/foo.nc This returned all values but should have returned none Algorithm was broken because, although valid min and max indices existed, they contained the empty set. Now when this happens, set flg_no_data_err block */ if( /* Points are not wrapped ... */ (lmt.min_val < lmt.max_val) && /* ... and valid indices were found for both bracketing points... */ (lmt.min_idx != -1L && lmt.max_idx != -1L) && /* ...and indices contain empty set, i.e., min_idx > max_idx for increasing data... */ lmt.min_idx > lmt.max_idx) flg_no_data_err=True; /* end if monotonic_direction == increasing */ }else{ /* monotonic_direction == decreasing */ if(lmt.min_sng){ /* Find index of smallest coordinate greater than min_val */ tmp_idx=dmn_sz-1L; while((dmn_val_dp[tmp_idx] < lmt.min_val) && (tmp_idx > -1L)) tmp_idx--; if(tmp_idx != -1L) lmt.min_idx=tmp_idx; else lmt.min_idx=-1L; } /* end if */ if(lmt.max_sng){ /* Find index of largest coordinate less than max_val */ tmp_idx=0L; while((dmn_val_dp[tmp_idx] > lmt.max_val) && (tmp_idx < dmn_sz)) tmp_idx++; if(tmp_idx != dmn_sz) lmt.max_idx=tmp_idx; else lmt.max_idx=-1L; } /* end if */ if( /* Points are not wrapped ... */ (lmt.min_val > lmt.max_val) && /* ... and valid indices were found for both bracketing points... */ (lmt.min_idx != -1L && lmt.max_idx != -1L) && /* ...and indices contain empty set, i.e., min_idx < max_idx for decreasing data... */ lmt.min_idx < lmt.max_idx) flg_no_data_err=True; } /* end else monotonic_direction == decreasing */ /* Case where both min_idx and max_idx = -1 was flagged as error above Case of wrapped coordinate: Either, but not both, of min_idx or max_idx will be flagged with -1 See explanation above */ if(lmt.min_idx == -1L && (lmt.min_val > lmt.max_val)) lmt.min_idx=0L; if(lmt.max_idx == -1L && (lmt.min_val > lmt.max_val)) lmt.max_idx=dmn_sz-1L; } /* end if min_val != max_val */ /* User-specified ranges are now bracketed */ /* Convert indices of minima and maxima to srt and end indices */ if(monotonic_direction == increasing){ lmt.srt=lmt.min_idx; lmt.end=lmt.max_idx; }else{ lmt.srt=lmt.max_idx; lmt.end=lmt.min_idx; } /* end else */ /* Free space allocated for dimension */ dmn_val_dp=(double*)nco_free(dmn_val_dp); if(rec_dmn_and_mfo){ /* No wrapping with multi-file operators */ if((monotonic_direction == increasing && lmt.min_val > lmt.max_val) || (monotonic_direction == decreasing && lmt.min_val < lmt.max_val)){ flg_no_data_ok=True; goto no_data_ok; } /* endif */ if(rec_usd_cml == 0L){ /* Skipped records remains zero until valid records are processed */ lmt.rec_skp_vld_prv=0L; }else if(rec_usd_cml > 0L){ /* Otherwise, adjust starting index by records skipped in jumps across file boundaries */ lmt.srt+=lmt.srd-1L-lmt.rec_skp_vld_prv%lmt.srd; if(lmt.srt>lmt.end){ /* Do not allow record dimension wrapping in MFOs */ flg_no_data_ok=True; goto no_data_ok; } /* endif */ } /* endif */ /* If we are here then there are valid records in current file */ } /* end if rec_dmn_and_mfo */ }else{ /* end if limit arguments were coordinate values */ /* Convert limit strings to zero-based indicial offsets */ /* Specifying stride alone, but not min or max, is legal, e.g., -d time,,,2 Thus is_usr_spc_lmt may be True, even though one or both of min_sng, max_sng is NULL Furthermore, both min_sng and max_sng are artifically created by nco_lmt_sct_mk() for record dimensions when the user does not explicitly specify limits. In this case, min_sng_and max_sng are non-NULL though no limits were specified In fact, min_sng and max_sng are set to the minimum and maximum string values of the first file processed. However, we can tell if these strings were artificially generated because nco_lmt_sct_mk() sets the is_usr_spc_lmt flag to False in such cases. Subsequent files may have different numbers of records, but nco_lmt_sct_mk() is only called once. Thus we must update min_idx and max_idx here for each file This causes min_idx and max_idx to be out of sync with min_sng and max_sng, which are only set in nco_lmt_sct_mk() for the first file. In hindsight, artificially generating min_sng and max_sng may be bad idea */ /* Following logic is messy, but hard to simplify */ if(lmt.min_sng == NULL || !lmt.is_usr_spc_lmt){ /* No user-specified value available--generate minimal dimension index */ if(FORTRAN_IDX_CNV) lmt.min_idx=1L; else lmt.min_idx=0L; }else{ /* Use user-specified limit when available */ lmt.min_idx=strtol(lmt.min_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.min_sng,"strtol",sng_cnv_rcd); } /* end if */ if(lmt.max_sng == NULL || !lmt.is_usr_spc_lmt){ /* No user-specified value available---generate maximal dimension index */ if(FORTRAN_IDX_CNV) lmt.max_idx=dmn_sz; else lmt.max_idx=dmn_sz-1L; }else{ /* Use user-specified limit when available */ lmt.max_idx=strtol(lmt.max_sng,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(lmt.max_sng,"strtol",sng_cnv_rcd); } /* end if */ /* Adjust indices if FORTRAN style input was specified */ if(FORTRAN_IDX_CNV){ /* 20120726: Die when Fortran index is zero */ if(lmt.min_idx == 0L || lmt.max_idx == 0L){ (void)fprintf(stdout,"%s: ERROR User-specified Fortran (1-based) index for dimension %s = 0.\n",nco_prg_nm_get(),lmt.nm); msg_sng=strdup("Fortran indices must be >= 1"); NCO_SYNTAX_ERROR=True; } /* endif illegal Fortran index */ /* 20120709: Adjust positive indices only */ if(lmt.min_idx > 0L) lmt.min_idx--; if(lmt.max_idx > 0L) lmt.max_idx--; } /* end if */ /* 20120709 Negative integer as min or max element of hyperslab specification indicates offset from end */ if(lmt.min_idx < 0L) lmt.min_idx+=dmn_sz-1L; if(lmt.max_idx < 0L) lmt.max_idx+=dmn_sz-1L; /* Exit if requested indices are always invalid for all operators... */ if(lmt.min_idx < 0L){ msg_sng=strdup("Minimum index is too negative"); NCO_SYNTAX_ERROR=True; }else if(lmt.max_idx < 0L){ msg_sng=strdup("Maximum index is too negative"); NCO_SYNTAX_ERROR=True; }else if(lmt.ssc > lmt.srd){ (void)fprintf(stdout,"%s: ERROR User-specified subcycle exceeds stride for %s: %li > %li\n",nco_prg_nm_get(),lmt.nm,lmt.ssc,lmt.srd); msg_sng=strdup("Subcycle exceeds stride"); NCO_SYNTAX_ERROR=True; }else if(!rec_dmn_and_mfo && lmt.min_idx >= dmn_sz){ msg_sng=strdup("Minimum index greater than size in non-MFO"); NCO_SYNTAX_ERROR=True; (void)fprintf(stdout,"%s: ERROR User-specified dimension index range %li <= %s <= %li does not fall within valid dimension index range 0 <= %s <= %li\n",nco_prg_nm_get(),lmt.min_idx,lmt.nm,lmt.max_idx,lmt.nm,dmn_sz-1L); }else if(lmt.max_idx >= dmn_sz && nco_prg_id == ncks){ /* 20130203 pvn Check for -d max > dimension size; check fortran case; check multi file operators */ msg_sng=strdup("ERROR: Maximum index exceeds dimension size"); NCO_SYNTAX_ERROR=True; } /* end if impossible indices */ if(NCO_SYNTAX_ERROR){ (void)fprintf(stdout,"%s: ERROR evaluating hyperslab specification for %s: %s\n%s: HINT Conform request to hyperslab documentation at http://nco.sf.net/nco.html#hyp\n",nco_prg_nm_get(),lmt.nm,msg_sng,nco_prg_nm_get()); msg_sng=(char *)nco_free(msg_sng); nco_exit(EXIT_FAILURE); } /* !NCO_SYNTAX_ERROR */ /* NB: Subcycle is officially supported only for ncra and ncrcat (record dimension only) */ if(lmt.ssc != 1L && !rec_dmn_and_mfo) (void)fprintf(stderr,"%s: WARNING Subcycle argument is only supported for the record dimension on ncra and ncrcat operations\n",nco_prg_nm_get()); /* Logic depends on whether this is record dimension in multi-file operator */ if(!rec_dmn_and_mfo || !lmt.is_usr_spc_lmt){ /* For non-record dimensions and for record dimensions where limit was automatically generated (to include whole file), starting and ending indices are simply minimum and maximum indices already in structure */ lmt.srt=lmt.min_idx; lmt.end=lmt.max_idx; }else{ /* Initialize rec_skp_vld_prv to 0L on first call to nco_lmt_evl() This is necessary due to intrinsic hysterisis of rec_skp_vld_prv rec_skp_vld_prv is used only by multi-file operators rec_skp_vld_prv counts records skipped at end of previous valid file rec_usd_cml and rec_skp_ntl_spf are both zero only for first file */ if(rec_usd_cml == 0L && lmt.rec_skp_ntl_spf == 0L) lmt.rec_skp_vld_prv=0L; /* For record dimensions with user-specified limit, allow possibility that limit pertains to record dimension in a multi-file operator. Then user-specified maximum index may exceed number of records in any one file Thus lmt.srt does not necessarily equal lmt.min_idx and lmt.end does not necessarily equal lmt.max_idx */ /* NB: Stride is officially supported for ncks (all dimensions) and for ncra and ncrcat (record dimension only) */ if(lmt.srd != 1L && nco_prg_id != ncks && !lmt.is_rec_dmn) (void)fprintf(stderr,"%s: WARNING Stride argument for non-record dimension is only supported by ncks, use at your own risk...\n",nco_prg_nm_get()); { /* Block hides scope of local internal variables */ long srt_min_lcl; /* [idx] Minimum start index (in absolute index space, i.e., relative to first file) for current file */ long end_max_lcl; /* [idx] Maximum end index (in absolute index space, i.e., relative to first file) for current file */ srt_min_lcl=(lmt.is_usr_spc_min ? lmt.min_idx : lmt.rec_in_cml+0L); end_max_lcl=(lmt.is_usr_spc_max ? lmt.max_idx : lmt.rec_in_cml+dmn_sz-1L); /* Maximum allowed index in record dimension */ lmt.idx_end_max_abs=end_max_lcl; /* Are we past file containing end_max_lcl yet? */ if(end_max_lcl < lmt.rec_in_cml){ /* This and all subsequent files are superfluous because all requested records have already been read Optimize MFOs by checking "input complete" flag to jump out of file loop Saves time because no other input files will be opened */ lmt.flg_input_complete=True; flg_no_data_ok=True; goto no_data_ok; } /* endif past end_max_lcl */ /* Have we reached file containing srt_min_lcl yet? */ if(srt_min_lcl > lmt.rec_in_cml+dmn_sz-1L){ /* This and all previous files are superfluous because the starting record is in a subsequent file */ flg_no_data_ok=True; goto no_data_ok; } /* endif srt_min_lcl in future file */ /* Until records have been used, start index is srt_min_lcl adjusted for records contained in all previous files Thereafter start index loses memory of/dependence on absolute start index, and only cares for how many records, if any, were skipped since last valid record. This number, modulo stride, is new start index. */ if(rec_usd_cml == 0L) lmt.srt=srt_min_lcl-lmt.rec_in_cml; else lmt.srt=lmt.srd-1L-lmt.rec_skp_vld_prv%lmt.srd; if(lmt.srt > dmn_sz-1L){ /* Perhaps data were read in previous file(s) yet next record is in future file due to long stride */ flg_no_data_ok=True; goto no_data_ok; } /* endif */ lmt.end=(end_max_lcl < lmt.rec_in_cml+dmn_sz) ? end_max_lcl-lmt.rec_in_cml : dmn_sz-1L; } /* end block hides scope of local internal variables */ /* If we are here then there are valid records in current file */ } /* endif user-specified limits to record dimension */ } /* end else limit arguments are hyperslab indices */ /* NB: MFO record dimension never reaches this block if current file is superfluous In that case code has already branched down to flg_data_ok or flg_data_err */ if(rec_dmn_and_mfo){ /* NB: This is---and must be---performed as integer arithmetic */ cnt_rmn_crr=1L+(lmt.end-lmt.srt)/lmt.srd; /* This fixes "sloppy" specification of end index by user, i.e., ensures that end index coincides with a stride */ lmt.end=lmt.srt+(cnt_rmn_crr-1L)*lmt.srd; /* Save current rec_skp_vld_prv for diagnostics (printed below) for this file */ rec_skp_vld_prv_dgn=lmt.rec_skp_vld_prv; /* Next file must know how many records in this file come after (and thus will be skipped) last used record in this file */ lmt.rec_skp_vld_prv=dmn_sz-1L-lmt.end; } /* !rec_dmn_and_mfo */ /* Compute cnt from srt, end, and srd This is fine for multi-file record dimensions since those operators read-in one record at a time and thus never actually use lmt.cnt for record dimension. */ if(lmt.srd == 1L){ if(lmt.srt <= lmt.end) lmt.cnt=lmt.end-lmt.srt+1L; else lmt.cnt=dmn_sz-lmt.srt+lmt.end+1L; }else{ if(lmt.srt <= lmt.end) lmt.cnt=1L+(lmt.end-lmt.srt)/lmt.srd; else lmt.cnt=1L+((dmn_sz-lmt.srt)+lmt.end)/lmt.srd; } /* end else */ /* NB: Degenerate cases of WRP && SRD exist for which dmn_cnt_2 == 0 This occurs when srd is large enough, or max_idx small enough, such that no values are selected in the second read. e.g., "-d lon,60,0,10" if sz(lon)=128 has dmn_cnt_2 == 0 Since netCDF library reports an error reading and writing cnt=0 dimensions, kludge is necessary Syntax ensures that it is always the second read, not the first, which is obviated Therefore we convert these degenerate cases into non-wrapped coordinates to be processed by single read For these degenerate cases only, [srt,end] are not a permutation of [min_idx,max_idx] */ if( (lmt.srd != 1L) && /* SRD */ (lmt.srt > lmt.end) && /* WRP */ (lmt.cnt == (1L+(dmn_sz-lmt.srt-1L)/lmt.srd)) && /* dmn_cnt_1 == cnt -> dmn_cnt_2 == 0 */ True){ long greatest_srd_multiplier_1st_hyp_slb; /* Greatest integer m such that srt+m*srd < dmn_sz */ long last_good_idx_1st_hyp_slb; /* C-index of last valid member of 1st hyperslab (= srt+m*srd) */ /* long left_over_idx_1st_hyp_slb;*/ /* # of elements from first hyperslab that count towards current stride */ long first_good_idx_2nd_hyp_slb; /* C-index of first valid member of 2nd hyperslab, if any */ /* NB: Perform these operations with integer arithmetic or else! */ /* Wrapped dimensions with stride may not start at idx 0 on second read */ greatest_srd_multiplier_1st_hyp_slb=(dmn_sz-lmt.srt-1L)/lmt.srd; last_good_idx_1st_hyp_slb=lmt.srt+lmt.srd*greatest_srd_multiplier_1st_hyp_slb; /* left_over_idx_1st_hyp_slb=dmn_sz-last_good_idx_1st_hyp_slb-1L;*/ first_good_idx_2nd_hyp_slb=(last_good_idx_1st_hyp_slb+lmt.srd)%dmn_sz; /* Conditions causing dmn_cnt_2 == 0 */ if(first_good_idx_2nd_hyp_slb > lmt.end) lmt.end=last_good_idx_1st_hyp_slb; } /* end if */ /* Cases where domain brackets no data, in error, have counts set to zero here This kludge allows codepaths for both WRP and out-of-domain to flow without goto statements Out-of-domain errors will soon exit with error, while WRP conditions will proceed */ if(flg_no_data_err) lmt.cnt=0L; /* Exit when valid bracketed range contains no coordinates and that is not legal, i.e., this is not a superfluous file in an MFO */ if(lmt.cnt == 0){ if(lmt.lmt_typ == lmt_crd_val) (void)fprintf(stdout,"%s: ERROR Domain %g <= %s <= %g brackets no coordinate values.\n",nco_prg_nm_get(),lmt.min_val,lmt.nm,lmt.max_val); if(lmt.lmt_typ == lmt_dmn_idx) (void)fprintf(stdout,"%s: ERROR Empty domain for %s\n",nco_prg_nm_get(),lmt.nm); nco_exit(EXIT_FAILURE); } /* end if */ /* Coordinate-valued limits that bracket no values in current file jump here with goto Index-valued limits with no values in current file flow here naturally */ no_data_ok: /* end goto */ if(flg_no_data_ok){ /* File is superfluous (contributes no data) to specified hyperslab Set output parameters to well-defined state This state must not cause ncra or ncrcat to retrieve any data ncra and ncrcat use loops for the record dimension, so this is accomplished by setting loop control values (lmt_rec.srt > lmt_rec.end) that cause record loop always to be skipped (never entered) */ lmt.srt=-1L; lmt.end=lmt.srt-1L; lmt.cnt=-1L; /* Augment number of records skipped in initial superfluous files */ if(rec_usd_cml == 0L) lmt.rec_skp_ntl_spf+=dmn_sz; /* Augment records skipped since last good one */ lmt.rec_skp_vld_prv+=dmn_sz; /* Set variables to preserve utility of diagnostics at end of routine */ cnt_rmn_crr=rec_skp_vld_prv_dgn=0L; } /* endif */ /* Accumulate count of records in all opened files, including this one Increment here at end so this structure member includes records from current file only at end of this routine, where it can only be used diagnostically NB: Location of this augmentation is important! Moving it would have side-effects! */ lmt.rec_in_cml+=dmn_sz; /* Place contents of working structure in location of returned structure */ *lmt_ptr=lmt; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)nco_prn_lmt(lmt,min_lmt_typ,FORTRAN_IDX_CNV,flg_no_data_ok,rec_usd_cml,monotonic_direction,rec_dmn_and_mfo,cnt_rmn_ttl,cnt_rmn_crr,rec_skp_vld_prv_dgn); } /* end dbg */ if(lmt.srt > lmt.end && !flg_no_data_ok){ if(nco_prg_id != ncks) (void)fprintf(stderr,"WARNING: Possible instance of Schweitzer data hole requiring better diagnostics TODO #148\n"); if(nco_prg_id != ncks) (void)fprintf(stderr,"HINT: If operation fails, try multislabbing (http://nco.sf.net/nco.html#msa) wrapped dimension using ncks first, and then apply %s to the resulting file\n",nco_prg_nm_get()); } /* end dbg */ fl_udu_sng=(char *)nco_free(fl_udu_sng); } /* nco_lmt_evl_dmn_crd() */ ./nco-4.4.2/src/nco/mpncbo.c0000644000674300045400000014446012262450454014762 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/mpncbo.c,v 1.142 2014/01/06 06:46:04 zender Exp $ */ /* mpncbo -- netCDF binary operator */ /* Purpose: Compute sum, difference, product, or ratio of specified hyperslabs of specfied variables from two input netCDF files and output them to a single file. */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: mpncbo -O -p ~/nco/data in.nc in.nc ~/foo.nc mpncbo -O -v mss_val in.nc in.nc ~/foo.nc mpncbo -p /data/zender/tmp h0001.nc ~/foo.nc mpncbo -p /data/zender/tmp -l /data/zender/tmp/rmt h0001.nc h0002.nc ~/foo.nc mpncbo -p /ZENDER/tmp -l /data/zender/tmp/rmt h0001.nc h0002.nc ~/foo.nc mpncbo -p /ZENDER/tmp -l /usr/tmp/zender h0001.nc h0002.nc ~/foo.nc Test type conversion: ncks -O -C -v float_var in.nc foo1.nc ncrename -v float_var,double_var foo1.nc ncks -O -C -v double_var in.nc foo2.nc mpncbo -O -C -v double_var foo1.nc foo2.nc foo3.nc mpncbo -O -C -v double_var foo2.nc foo1.nc foo4.nc ncks -H -m foo1.nc ncks -H -m foo2.nc ncks -H -m foo3.nc ncks -H -m foo4.nc Test nco_var_cnf_dmn: ncks -O -v scalar_var in.nc ~/foo.nc ; ncrename -v scalar_var,four_dmn_rec_var foo.nc ; mpncbo -O -v four_dmn_rec_var in.nc ~/foo.nc foo2.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #include /* POSIX stuff */ #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #ifdef ENABLE_MPI # include /* MPI definitions */ # include "nco_mpi.h" /* MPI utilities */ #endif /* !ENABLE_MPI */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FILE_1_RETRIEVED_FROM_REMOTE_LOCATION; nco_bool FILE_2_RETRIEVED_FROM_REMOTE_LOCATION; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order*/ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ nco_bool flg_ddra=False; /* [flg] DDRA diagnostics */ char **fl_lst_abb=NULL; /* Option a */ char **fl_lst_in; char **var_lst_in=NULL_CEWI; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in_1=NULL; /* fl_in_1 is nco_realloc'd when not NULL */ char *fl_in_2=NULL; /* fl_in_2 is nco_realloc'd when not NULL */ char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL; /* MPI CEWI */ char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *nco_op_typ_sng=NULL; /* [sng] Operation type */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ const char * const CVS_Id="$Id: mpncbo.c,v 1.142 2014/01/06 06:46:04 zender Exp $"; const char * const CVS_Revision="$Revision: 1.142 $"; const char * const opt_sht_lst="3467ACcD:d:FhL:l:Oo:p:rRSt:v:X:xy:-:"; cnk_dmn_sct **cnk_dmn=NULL_CEWI; #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.MRV_flg=False,.flg_ddra=False,.lmn_nbr=0LL,.lmn_nbr_avg=0LL,.lmn_nbr_wgt=0LL,.nco_op_typ=nco_op_nil,.rnk_avg=0,.rnk_var=0,.rnk_wgt=0,.tmr_flg=nco_tmr_srt,.var_idx=0,.wgt_brd_flg=False,.wrd_sz=0}; #endif /* !__cplusplus */ dmn_sct **dim_1; dmn_sct **dim_2; dmn_sct **dmn_out; extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ int *in_id_1_arr; int *in_id_2_arr; int abb_arg_nbr=0; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_idx; int fl_nbr=0; int fl_in_fmt_1; /* [enm] Input file format */ int fl_in_fmt_2; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx; int jdx; int dmn_idx; int dmn_jdx; int in_id_1; int in_id_2; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl_1; int nbr_dmn_fl_2; int nbr_dmn_xtr_1; int nbr_dmn_xtr_2; int nbr_var_fix_1; /* nbr_var_fix_1 gets incremented */ int nbr_var_fix_2; /* nbr_var_fix_2 gets incremented */ int nbr_var_fl_1; int nbr_var_fl_2; int nbr_var_prc_1; /* nbr_var_prc_1 gets incremented */ int nbr_var_prc_2; /* nbr_var_prc_2 gets incremented */ int xtr_nbr_1=0; /* xtr_nbr_1 won't otherwise be set for -c with no -v */ int xtr_nbr_2=0; /* xtr_nbr_2 won't otherwise be set for -c with no -v */ int nco_op_typ=nco_op_nil; /* [enm] Operation type */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; lmt_sct **aux=NULL_CEWI; /* Auxiliary coordinate limits */ lmt_sct **lmt=NULL_CEWI; lmt_all_sct **lmt_all_lst=NULL_CEWI; /* List of *lmt_all structures */ nm_id_sct *dmn_lst_1; nm_id_sct *dmn_lst_2; nm_id_sct *xtr_lst_1=NULL; /* xtr_lst_1 may be alloc()'d from NULL with -c option */ nm_id_sct *xtr_lst_2=NULL; /* xtr_lst_2 may be alloc()'d from NULL with -c option */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var_1; var_sct **var_2; var_sct **var_fix_1; var_sct **var_fix_2; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc_1; var_sct **var_prc_2; var_sct **var_prc_out; #ifdef ENABLE_MPI /* #if defined(ENABLE_MPI) && !defined(ENABLE_NETCDF4) */ /* Declare all MPI-specific variables here */ MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */ nco_bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */ int fl_nm_lng; /* [nbr] Output file name length CEWI */ int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */ int msg_tag_typ; /* [enm] MPI message tag type */ int prc_rnk; /* [idx] Process rank */ int prc_nbr=0; /* [nbr] Number of MPI processes */ int tkn_wrt_rsp; /* [enm] Response to request for write token */ int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */ int rnk_wrk; /* [idx] Worker rank */ int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */ #endif /* !ENABLE_MPI */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"ddra",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"mdl_cmp",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"msa_usr_rdr",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"msa_user_order",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"suspend", no_argument,0,'S'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"operation",required_argument,0,'y'}, {"op_typ",required_argument,0,'y'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ #ifdef ENABLE_MPI /* MPI Initialization */ MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr); MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk); #endif /* !ENABLE_MPI */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"ddra") || !strcmp(opt_crr,"mdl_cmp")) ddra_info.flg_ddra=flg_ddra=True; /* [flg] DDRA diagnostics */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"msa_usr_rdr") || !strcmp(opt_crr,"msa_user_order")) MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* The debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; #ifdef ENABLE_MPI case 'S': /* Suspend with signal handler to facilitate debugging */ if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stdout,"%s: ERROR Could not install suspend handler.\n",nco_prg_nm); while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */ break; #endif /* !ENABLE_MPI */ case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr_1=xtr_nbr_2=var_lst_in_nbr; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'y': /* User-specified operation type overrides invocation default */ nco_op_typ_sng=(char *)strdup(optarg); nco_op_typ=nco_op_typ_get(nco_op_typ_sng); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Make uniform list of user-specified chunksizes */ if(cnk_nbr > 0) cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Make uniform list of user-specified dimension limits */ lmt=nco_lmt_prs(lmt_nbr,lmt_arg); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_1_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); in_id_2_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filenames */ fl_idx=0; /* Input file _1 */ fl_in_1=nco_fl_nm_prs(fl_in_1,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in_1); /* Make sure file is on local system and is readable or die trying */ fl_in_1=nco_fl_mk_lcl(fl_in_1,fl_pth_lcl,&FILE_1_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl && FILE_1_RETRIEVED_FROM_REMOTE_LOCATION) (void)fprintf(stderr,", local file is %s",fl_in_1); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in_2); /* Make sure file is on local system and is readable or die trying */ fl_in_2=nco_fl_mk_lcl(fl_in_2,fl_pth_lcl,&FILE_2_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl && FILE_2_RETRIEVED_FROM_REMOTE_LOCATION) (void)fprintf(stderr,", local file is %s",fl_in_2); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx 0){ int aux_idx_nbr; aux=nco_aux_evl(in_id_1,aux_nbr,aux_arg,&aux_idx_nbr); if(aux_idx_nbr > 0){ lmt=(lmt_sct **)nco_realloc(lmt,(lmt_nbr+aux_idx_nbr)*sizeof(lmt_sct *)); int lmt_nbr_new=lmt_nbr+aux_idx_nbr; int aux_idx=0; for(int lmt_idx=lmt_nbr;lmt_idx2 ordering, may occasionally find xtr_nbr_2 > xtr_nbr_1 This occurs, e.g., when fl_in_1 contains reduced variables and full coordinates are only in fl_in_2 and so will not appear xtr_lst_1 */ /* Sort extraction list by variable ID for fastest I/O */ if(xtr_nbr_1 > 1) xtr_lst_1=nco_lst_srt_nm_id(xtr_lst_1,xtr_nbr_1,False); if(xtr_nbr_2 > 1) xtr_lst_2=nco_lst_srt_nm_id(xtr_lst_2,xtr_nbr_2,False); /* We now have final list of variables to extract. Phew. */ /* Find coordinate/dimension values associated with user-specified limits NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ for(idx=0;idx 0) (void)nco_dmn_lmt_all_mrg(dmn_out,nbr_dmn_xtr_1,lmt_all_lst,nbr_dmn_fl_1); if(nco_dbg_lvl >= nco_dbg_sbr){ for(idx=0;idxnm,dmn_out[jdx]->nm)){ /* NB: Copy new dim data but do NOT free original as dimension element is aliased in var_2 array */ (void)nco_dmn_cpy(dim_2[idx],dmn_out[jdx]); break; } /* endif */ /* Dimension not found so die gracefully */ if(jdx==nbr_dmn_xtr_1){ (void)fprintf(fp_stdout,"%s: ERROR dimension \"%s\" in second file %s is not present in first file %s\n",nco_prg_nm,dim_2[idx]->nm,fl_in_2,fl_in_1); nco_exit(EXIT_FAILURE); } /* endif dimension not found */ } /* end loop over dimensions */ /* Refresh var_2 with the new dim_2 data */ (void)nco_var_dmn_refresh(var_2,xtr_nbr_2); /* Divide variable lists into lists of fixed variables and variables to be processed Create lists from file_1 last so those values remain in *_out arrays */ (void)nco_var_lst_dvd(var_2,var_out,xtr_nbr_2,CNV_CCM_CCSM_CF,True,nco_pck_plc_nil,nco_pck_map_nil,(dmn_sct **)NULL,0,&var_fix_2,&var_fix_out,&nbr_var_fix_2,&var_prc_2,&var_prc_out,&nbr_var_prc_2); /* Avoid double-free() condition */ var_fix_out=(var_sct **)nco_free(var_fix_out); var_prc_out=(var_sct **)nco_free(var_prc_out); (void)nco_var_lst_dvd(var_1,var_out,xtr_nbr_1,CNV_CCM_CCSM_CF,True,nco_pck_plc_nil,nco_pck_map_nil,(dmn_sct **)NULL,0,&var_fix_1,&var_fix_out,&nbr_var_fix_1,&var_prc_1,&var_prc_out,&nbr_var_prc_1); /* Die gracefully on unsupported features... */ if(nbr_var_fix_1 < nbr_var_fix_2){ (void)fprintf(fp_stdout,"%s: ERROR First file has fewer fixed variables than second file (%d < %d). This feature is TODO nco581.\n",nco_prg_nm,nbr_var_fix_1,nbr_var_fix_2); nco_exit(EXIT_FAILURE); } /* endif */ /* Merge two variable lists into same order */ rcd=nco_var_lst_mrg(&var_prc_1,&var_prc_2,&nbr_var_prc_1,&nbr_var_prc_2); /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt_1; /* Verify output file format supports requested actions */ (void)nco_fl_fmt_vet(fl_out_fmt,cnk_nbr,dfl_lvl); /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); /* 20101019 fxm got to here merging ncbo 4.0.5 into mpncbo */ /* Assign zero to start and unity to stride vectors in output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr_1); #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ #endif /* !ENABLE_MPI */ /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt_1; /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); /* Copy global attributes */ (void)nco_att_cpy(in_id_1,out_id,NC_GLOBAL,NC_GLOBAL,(nco_bool)True); /* Catenate time-stamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); #ifdef ENABLE_MPI /* Initialize MPI task information */ if(prc_nbr > 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr); #endif /* !ENABLE_MPI */ /* Define dimensions in output file */ (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_xtr_1); /* fxm: TODO 550 put max_dim_sz/list(var_1,var_2) into var_def(var_out) */ /* Define variables in output file, copy their attributes */ (void)nco_var_dfn(in_id_1,fl_out,out_id,var_out,xtr_nbr_1,(dmn_sct **)NULL,(int)0,nco_pck_plc_nil,nco_pck_map_nil,dfl_lvl); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl_1,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ #ifdef ENABLE_MPI } /* prc_rnk != rnk_mgr */ /* Manager obtains output filename and broadcasts to workers */ if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); MPI_Bcast(&fl_nm_lng,1,MPI_INT,rnk_mgr,MPI_COMM_WORLD); if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char)); MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,rnk_mgr,MPI_COMM_WORLD); if(prc_rnk == rnk_mgr){ /* MPI manager code */ TKN_WRT_FREE=False; #endif /* !ENABLE_MPI */ /* Copy variable data for non-processed variables */ (void)nco_msa_var_val_cpy(in_id_1,out_id,var_fix_1,nbr_var_fix_1,lmt_all_lst,nbr_dmn_fl_1); #ifdef ENABLE_MPI /* Close output file so workers can open it */ nco_close(out_id); TKN_WRT_FREE=True; } /* prc_rnk != rnk_mgr */ #endif /* !ENABLE_MPI */ /* ncbo() code has been similar to nces() (and ncra()) wherever possible Major differences occur where performance would otherwise suffer From now on, however, binary-file and binary-operation nature of ncbo() is too different from nces() paradigm to justify following nces() style. Instead, we adopt symmetric nomenclature (e.g., file_1, file_2), and perform differences variable-by-variable so peak memory usage goes as Order(2*maximum variable size) rather than Order(3*maximum record size) or Order(3*file size) */ /* Perform various error-checks on input file */ if(False) (void)nco_fl_cmp_err_chk(); /* Default operation depends on invocation name */ if(nco_op_typ_sng == NULL) nco_op_typ=nco_op_typ_get(nco_op_typ_sng); /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ /* Compensate for incrementing on each worker's first message */ var_wrt_nbr=-prc_nbr+1; idx=0; /* While variables remain to be processed or written... */ while(var_wrt_nbr < nbr_var_prc_1){ /* Receive message from any worker */ MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); /* Obtain MPI message tag type */ msg_tag_typ=mpi_stt.MPI_TAG; /* Get sender's prc_rnk */ rnk_wrk=wrk_id_bfr[0]; /* Allocate next variable, if any, to worker */ if(msg_tag_typ == msg_tag_wrk_rqs){ var_wrt_nbr++; /* [nbr] Number of variables written */ /* Worker closed output file before sending msg_tag_wrk_rqs */ TKN_WRT_FREE=True; if(idx < nbr_var_prc_1){ /* Tell requesting worker to allocate space for next variable */ msg_bfr[0]=idx; /* [idx] Variable to be processed */ msg_bfr[1]=out_id; /* Output file ID */ msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ /* Point to next variable on list */ idx++; }else{ msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ msg_bfr[1]=out_id; /* Output file ID */ } /* endif idx */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); /* msg_tag_typ != msg_tag_wrk_rqs */ }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ /* Allocate token if free, else ask worker to try later */ if(TKN_WRT_FREE){ TKN_WRT_FREE=False; msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ }else{ msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ } /* !TKN_WRT_FREE */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ } /* end while var_wrt_nbr < nbr_var_prc_1 */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ wrk_id_bfr[0]=prc_rnk; while(1){ /* While work remains... */ /* Send msg_tag_wrk_rqs */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); /* Receive msg_tag_wrk_rsp */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,0,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); idx=msg_bfr[0]; out_id=msg_bfr[1]; if(idx == idx_all_wrk_ass) break; else{ var_prc_out[idx]->id=msg_bfr[2]; /* Process this variable same as UP code */ #else /* !ENABLE_MPI */ #ifdef _OPENMP /* OpenMP notes: shared(): msk and wgt are not altered within loop private(): wgt_avg does not need initialization */ #pragma omp parallel for default(none) firstprivate(ddra_info) private(idx,in_id_1,in_id_2,dmn_idx,dmn_jdx) shared(nco_dbg_lvl,dim_1,fl_in_1,fl_in_2,fl_out,flg_ddra,in_id_1_arr,in_id_2_arr,nbr_dmn_xtr_1,nbr_var_prc_1,nbr_var_prc_2,nco_op_typ,out_id,nco_prg_nm,rcd,var_prc_1,var_prc_2,var_prc_out,lmt_all_lst,nbr_dmn_fl_1) #endif /* !_OPENMP */ /* UP and SMP codes main loop over variables */ for(idx=0;idx= nco_dbg_var) (void)fprintf(fp_stderr,"%s, ",var_prc_1[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); in_id_1=in_id_1_arr[omp_get_thread_num()]; in_id_2=in_id_2_arr[omp_get_thread_num()]; (void)nco_var_mtd_refresh(in_id_1,var_prc_1[idx]); has_mss_val=var_prc_1[idx]->has_mss_val; (void)nco_msa_var_get(in_id_1,var_prc_1[idx],lmt_all_lst,nbr_dmn_fl_1); /* Find and set variable dmn_nbr, ID, mss_val, type in second file */ (void)nco_var_mtd_refresh(in_id_2,var_prc_2[idx]); /* Read hyperslab from second file */ (void)nco_msa_var_get(in_id_2,var_prc_2[idx],lmt_all_lst,nbr_dmn_fl_1); /* Check that all dims in var_prc_2 are in var_prc_1 */ for(dmn_idx=0;dmn_idxnbr_dim;dmn_idx++){ for(dmn_jdx=0;dmn_jdxnbr_dim;dmn_jdx++) if(!strcmp(var_prc_2[idx]->dim[dmn_idx]->nm,var_prc_1[idx]->dim[dmn_jdx]->nm)) break; if(dmn_jdx==var_prc_1[idx]->nbr_dim){ (void)fprintf(fp_stdout,"%s: ERROR Variables do not conform:\nFile %s variable %s has dimension %s not present in file %s variable %s\n",nco_prg_nm,fl_in_2,var_prc_2[idx]->nm, var_prc_2[idx]->dim[dmn_idx]->nm,fl_in_1,var_prc_1[idx]->nm); nco_exit(EXIT_FAILURE); } /* endif error */ } /* end loop over idx */ /* Die gracefully on unsupported features... */ if(var_prc_1[idx]->nbr_dim < var_prc_2[idx]->nbr_dim){ (void)fprintf(fp_stdout,"%s: ERROR Variable %s has lesser rank in first file than in second file (%d < %d). This feature is NCO TODO 552.\n",nco_prg_nm,var_prc_1[idx]->nm,var_prc_1[idx]->nbr_dim,var_prc_2[idx]->nbr_dim); nco_exit(EXIT_FAILURE); } /* endif */ if(var_prc_1[idx]->nbr_dim > var_prc_2[idx]->nbr_dim) (void)ncap_var_cnf_dmn(&var_prc_out[idx],&var_prc_2[idx]); /* var2 now conforms in size to var1, and is in memory */ /* fxm: TODO 268 allow var1 or var2 to typecast */ /* Make sure var2 conforms to type of var1 */ if(var_prc_1[idx]->type != var_prc_2[idx]->type){ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO Input variables do not conform in type:\nFile 1 = %s variable %s has type %s\nFile 2 = %s variable %s has type %s\nFile 3 = %s variable %s will have type %s\n",nco_prg_nm,fl_in_1,var_prc_1[idx]->nm,nco_typ_sng(var_prc_1[idx]->type),fl_in_2,var_prc_2[idx]->nm,nco_typ_sng(var_prc_2[idx]->type),fl_out,var_prc_1[idx]->nm,nco_typ_sng(var_prc_1[idx]->type)); } /* endif different type */ var_prc_2[idx]=nco_var_cnf_typ(var_prc_1[idx]->type,var_prc_2[idx]); /* Change missing_value of var_prc_2, if any, to missing_value of var_prc_1, if any */ has_mss_val=nco_mss_val_cnf(var_prc_1[idx],var_prc_2[idx]); /* mss_val in fl_1, if any, overrides mss_val in fl_2 */ if(has_mss_val) mss_val=var_prc_1[idx]->mss_val; /* Perform specified binary operation */ switch(nco_op_typ){ case nco_op_add: /* [enm] Add file_1 to file_2 */ (void)nco_var_add(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break; case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */ (void)nco_var_mlt(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break; case nco_op_dvd: /* [enm] Divide file_1 by file_2 */ (void)nco_var_dvd(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break; case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */ (void)nco_var_sbt(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break; default: /* Other defined nco_op_typ values are valid for ncra(), ncrcat(), ncwa(), not ncbo() */ (void)fprintf(fp_stdout,"%s: ERROR Illegal nco_op_typ in binary operation\n",nco_prg_nm); nco_exit(EXIT_FAILURE); break; } /* end case */ var_prc_2[idx]->val.vp=nco_free(var_prc_2[idx]->val.vp); #ifdef ENABLE_MPI /* Obtain token and prepare to write */ while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); tkn_wrt_rsp=msg_bfr[0]; /* Wait then re-send request */ if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; } /* end while loop waiting for write token */ /* Worker has token---prepare to write */ if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ if(RAM_OPEN) md_open=NC_WRITE|NC_SHARE|NC_DISKLESS; else md_open=NC_WRITE|NC_SHARE; rcd=nco_fl_open(fl_out_tmp,md_open,&bfr_sz_hnt,&out_id); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl_1,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); #else /* !ENABLE_MPI */ #ifdef _OPENMP #pragma omp critical #endif /* !_OPENMP */ #endif /* !ENABLE_MPI */ /* Common code for UP, SMP, and MPI */ { /* begin OpenMP critical */ /* Copy result to output file and free workspace buffer */ if(var_prc_1[idx]->nbr_dim == 0){ (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_1[idx]->val.vp,var_prc_1[idx]->type); }else{ /* end if variable is scalar */ (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_1[idx]->val.vp,var_prc_1[idx]->type); } /* end else */ } /* end OpenMP critical */ var_prc_1[idx]->val.vp=nco_free(var_prc_1[idx]->val.vp); if(flg_ddra){ /* DDRA diagnostics Usage: ncbo -O -C --mdl -p ~/nco/data in.nc in.nc ~/foo.nc ncbo -O -C --mdl -p ${DATA}/nco_bm stl_5km.nc stl_5km.nc ~/foo.nc ncbo -O -C --mdl -p ${DATA}/nco_bm gcm_T85.nc gcm_T85.nc ~/foo.nc */ /* Assign remaining input for DDRA diagnostics */ ddra_info.lmn_nbr=var_prc_1[idx]->sz; /* [nbr] Variable size */ ddra_info.nco_op_typ=nco_op_typ; /* [enm] Operation type */ ddra_info.rnk_var=var_prc_1[idx]->nbr_dim; /* I [nbr] Variable rank (in input file) */ ddra_info.var_idx=idx; /* [enm] Index */ ddra_info.wrd_sz=nco_typ_lng(var_prc_1[idx]->type); /* [B] Bytes per element */ /* DDRA diagnostics */ rcd+=nco_ddra /* [fnc] Count operations */ (var_prc_1[idx]->nm, /* I [sng] Variable name */ (char *)NULL, /* I [sng] Weight name */ &ddra_info); /* I [sct] DDRA information */ } /* !flg_ddra */ #ifdef ENABLE_MPI /* Close output file and increment written counter */ nco_close(out_id); var_wrt_nbr++; } /* endif tkn_wrt_rqs_xcp */ } /* end else !idx_all_wrk_ass */ } /* end while loop requesting work/token */ } /* endif Worker */ #else /* !ENABLE_MPI */ } /* end (OpenMP parallel for) loop over idx */ #endif /* !ENABLE_MPI */ if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Close input netCDF files */ for(thr_idx=0;thr_idxlmt_dmn_nbr;jdx++) lmt_all_lst[idx]->lmt_dmn[jdx]=nco_lmt_free(lmt_all_lst[idx]->lmt_dmn[jdx]); if(nbr_dmn_fl_1 > 0) lmt_all_lst=nco_lmt_all_lst_free(lmt_all_lst,nbr_dmn_fl_1); lmt=(lmt_sct**)nco_free(lmt); if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_1_arr) in_id_1_arr=(int *)nco_free(in_id_1_arr); if(in_id_2_arr) in_id_2_arr=(int *)nco_free(in_id_2_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) aux=(lmt_sct **)nco_free(aux); /* Free chunking information */ for(idx=0;idx 0) cnk_dmn=nco_cnk_lst_free(cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr_1 > 0) dim_1=nco_dmn_lst_free(dim_1,nbr_dmn_xtr_1); if(nbr_dmn_xtr_2 > 0) dim_2=nco_dmn_lst_free(dim_2,nbr_dmn_xtr_2); if(nbr_dmn_xtr_1 > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr_1); /* Free variable lists Using nco_var_lst_free() to free main var_1 and var_2 lists would fail if ncap_var_prc_dmn() had to broadcast any variables because pointer var_1 and var_2 still contain dangling pointer to old variable. Hence, use nco_var_lst_free() to free prc and fix lists and use nco_free() to free main var_1 and var_2 lists. Dangling pointers in var_1 and var_2 are unsafe: fxm TODO 578 */ if(nbr_var_prc_1 > 0) var_prc_1=nco_var_lst_free(var_prc_1,nbr_var_prc_1); if(nbr_var_fix_1 > 0) var_fix_1=nco_var_lst_free(var_fix_1,nbr_var_fix_1); if(nbr_var_prc_2 > 0) var_prc_2=nco_var_lst_free(var_prc_2,nbr_var_prc_2); if(nbr_var_fix_2 > 0) var_fix_2=nco_var_lst_free(var_fix_2,nbr_var_fix_2); var_1=(var_sct **)nco_free(var_1); var_2=(var_sct **)nco_free(var_2); if(xtr_nbr_1 > 0) var_out=nco_var_lst_free(var_out,xtr_nbr_1); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix_out=(var_sct **)nco_free(var_fix_out); } /* !flg_cln */ #ifdef ENABLE_MPI MPI_Finalize(); #endif /* !ENABLE_MPI */ /* End timer */ ddra_info.tmr_flg=nco_tmr_end; /* [enm] Timer flag */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); if(rcd != NC_NOERR) nco_err_exit(rcd,"main"); nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/mpncpdq.c0000644000674300045400000017034212262450454015144 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/mpncpdq.c,v 1.114 2014/01/06 06:46:04 zender Exp $ */ /* mpncpdq -- netCDF pack, re-dimension, query */ /* Purpose: Pack, re-dimension, query single netCDF file and output to a single file */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncpdq -O -D 3 -a lat,lev,lon -v three_dmn_var ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -a lon,lev,lat -v three_dmn_var ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -a lon,time -x -v three_double_dmn ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -P all_new ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P all_xst ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P xst_new ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P upk ~/nco/data/in.nc ~/foo.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* machine time */ #include /* POSIX stuff */ #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #ifdef ENABLE_MPI #include /* MPI definitions */ #include "nco_mpi.h" /* MPI utilities */ #endif /* !ENABLE_MPI */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { aed_sct *aed_lst_add_fst=NULL_CEWI; aed_sct *aed_lst_scl_fct=NULL_CEWI; nco_bool **dmn_rvr_in=NULL; /* [flg] Reverse dimension */ nco_bool *dmn_rvr_rdr=NULL; /* [flg] Reverse dimension */ nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool REDEFINED_RECORD_DIMENSION=False; /* [flg] Re-defined record dimension */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **dmn_rdr_lst_in=NULL_CEWI; /* Option a */ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in=NULL_CEWI; char **var_lst_in=NULL_CEWI; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *nco_pck_plc_sng=NULL_CEWI; /* [sng] Packing policy Option P */ char *nco_pck_map_sng=NULL_CEWI; /* [sng] Packing map Option M */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *rec_dmn_nm_in=NULL; /* [sng] Record dimension name, original */ char *rec_dmn_nm_out=NULL; /* [sng] Record dimension name, re-ordered */ char *rec_dmn_nm_out_crr=NULL; /* [sng] Name of record dimension, if any, required by re-order */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ const char * const CVS_Id="$Id: mpncpdq.c,v 1.114 2014/01/06 06:46:04 zender Exp $"; const char * const CVS_Revision="$Revision: 1.114 $"; const char * const opt_sht_lst="3467Aa:CcD:d:FhL:l:M:Oo:P:p:RrSt:v:Ux-:"; cnk_dmn_sct **cnk_dmn=NULL_CEWI; dmn_sct **dim=NULL_CEWI; dmn_sct **dmn_out; dmn_sct **dmn_rdr=NULL; /* [sct] Dimension structures to be re-ordered */ extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ int **dmn_idx_out_in=NULL; /* [idx] Dimension correspondence, output->input CEWI */ int *in_id_arr; int abb_arg_nbr=0; int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int dmn_out_idx; /* [idx] Index over output dimension list */ int dmn_out_idx_rec_in=NCO_REC_DMN_UNDEFINED; /* [idx] Record dimension index in output dimension list, original */ int dmn_rdr_nbr=0; /* [nbr] Number of dimension to re-order */ int dmn_rdr_nbr_in=0; /* [nbr] Original number of dimension to re-order */ int dmn_rdr_nbr_utl=0; /* [nbr] Number of dimension to re-order, utilized */ int fl_idx=int_CEWI; int fl_nbr=0; int fl_in_fmt; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx=int_CEWI; int idx_rdr=int_CEWI; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_out; int nbr_dmn_xtr; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int nco_pck_map=nco_pck_map_flt_sht; /* [enm] Packing map */ int nco_pck_plc=nco_pck_plc_nil; /* [enm] Packing policy */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int rec_dmn_id_in=NCO_REC_DMN_UNDEFINED; /* [id] Record dimension ID in input file */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; lmt_sct **aux=NULL_CEWI; /* Auxiliary coordinate limits */ lmt_sct **lmt=NULL_CEWI; lmt_all_sct **lmt_all_lst=NULL_CEWI; /* List of *lmt_all structures */ nm_id_sct *dmn_lst; nm_id_sct *dmn_rdr_lst; nm_id_sct *xtr_lst=NULL; /* xtr_lst may be alloc()'d from NULL with -c option */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc; var_sct **var_prc_out; #ifdef ENABLE_MPI /* Declare all MPI-specific variables here */ MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */ nco_bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */ int fl_nm_lng; /* [nbr] Output file name length */ int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */ int jdx=0; /* [idx] For MPI indexing local variables */ /* csz: fxm why 60? make dynamic? */ int lcl_idx_lst[60]; /* [arr] Array containing indices of variables processed at each Worker */ int lcl_nbr_var=0; /* [nbr] Count of variables processes at each Worker */ int msg_tag_typ; /* [enm] MPI message tag type */ int prc_rnk; /* [idx] Process rank */ int prc_nbr=0; /* [nbr] Number of MPI processes */ int tkn_wrt_rsp; /* [enm] Response to request for write token */ int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */ int rnk_wrk; /* [idx] Worker rank */ int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */ #endif /* !ENABLE_MPI */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"arrange",required_argument,0,'a'}, {"permute",required_argument,0,'a'}, {"reorder",required_argument,0,'a'}, {"rdr",required_argument,0,'a'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"pck_map",required_argument,0,'M'}, {"map",required_argument,0,'M'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"pack_policy",required_argument,0,'P'}, {"pck_plc",required_argument,0,'P'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"suspend", no_argument,0,'S'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"unpack",no_argument,0,'U'}, {"upk",no_argument,0,'U'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ #ifdef ENABLE_MPI /* MPI Initialization */ MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr); MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk); #endif /* !ENABLE_MPI */ /* Start clock and save command line */ cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Re-order dimensions */ dmn_rdr_lst_in=nco_lst_prs_2D(optarg,",",&dmn_rdr_nbr_in); dmn_rdr_nbr=dmn_rdr_nbr_in; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'M': /* Packing map */ nco_pck_map_sng=(char *)strdup(optarg); nco_pck_map=nco_pck_map_get(nco_pck_map_sng); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'P': /* Packing policy */ nco_pck_plc_sng=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; #ifdef ENABLE_MPI case 'S': /* Suspend with signal handler to facilitate debugging */ if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stdout,"%s: ERROR Could not install suspend handler.\n",nco_prg_nm); while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */ break; #endif /* !ENABLE_MPI */ case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'U': /* Unpacking switch */ nco_pck_plc_sng=(char *)strdup("upk"); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Make uniform list of user-specified chunksizes */ if(cnk_nbr > 0) cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Make uniform list of user-specified dimension limits */ lmt=nco_lmt_prs(lmt_nbr,lmt_arg); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); /* Parse auxiliary coordinates */ if(aux_nbr > 0){ int aux_idx_nbr; aux=nco_aux_evl(in_id,aux_nbr,aux_arg,&aux_idx_nbr); if(aux_idx_nbr > 0){ lmt=(lmt_sct **)nco_realloc(lmt,(lmt_nbr+aux_idx_nbr)*sizeof(lmt_sct *)); int lmt_nbr_new=lmt_nbr+aux_idx_nbr; int aux_idx=0; for(int lmt_idx=lmt_nbr;lmt_idx 1) xtr_lst=nco_lst_srt_nm_id(xtr_lst,xtr_nbr,False); /* Find coordinate/dimension values associated with user-specified limits NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ for(idx=0;idx 0) (void)nco_dmn_lmt_all_mrg(dmn_out,nbr_dmn_xtr,lmt_all_lst,nbr_dmn_fl); /* No re-order dimensions specified implies packing request */ if(dmn_rdr_nbr == 0){ if(nco_pck_plc == nco_pck_plc_nil) nco_pck_plc=nco_pck_plc_get(nco_pck_plc_sng); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: DEBUG Packing map is %s and packing policy is %s\n",nco_prg_nm_get(),nco_pck_map_sng_get(nco_pck_map),nco_pck_plc_sng_get(nco_pck_plc)); } /* endif */ /* From this point forward, assume ncpdq operator packs or re-orders, not both */ if(dmn_rdr_nbr > 0 && nco_pck_plc != nco_pck_plc_nil){ (void)fprintf(fp_stdout,"%s: ERROR %s does not support simultaneous dimension re-ordering (-a switch) and packing (-P switch).\nHINT: Invoke %s twice, once to re-order (with -a), and once to pack (with -P).\n",nco_prg_nm,nco_prg_nm,nco_prg_nm); nco_exit(EXIT_FAILURE); } /* end if */ if(dmn_rdr_nbr > 0){ /* NB: Same logic as in ncwa, perhaps combine into single function, nco_dmn_avg_rdr_prp()? */ /* Make list of user-specified dimension re-orders */ /* Create reversed dimension list */ dmn_rvr_rdr=(nco_bool *)nco_malloc(dmn_rdr_nbr*sizeof(nco_bool)); for(idx_rdr=0;idx_rdrnm)) break; } /* end loop over idx_rdr */ if(idx != nbr_dmn_xtr) dmn_rdr[dmn_rdr_nbr_utl++]=dim[idx]; else if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: WARNING re-ordering dimension \"%s\" is not contained in any variable in extraction list\n",nco_prg_nm,dmn_rdr_lst[idx_rdr].nm); } /* end loop over idx_rdr */ dmn_rdr_nbr=dmn_rdr_nbr_utl; /* Collapse extra dimension structure space to prevent accidentally using it */ dmn_rdr=(dmn_sct **)nco_realloc(dmn_rdr,dmn_rdr_nbr*sizeof(dmn_sct *)); /* Dimension list in name-ID format is no longer needed */ dmn_rdr_lst=nco_nm_id_lst_free(dmn_rdr_lst,dmn_rdr_nbr); /* Make sure no re-ordering dimension is specified more than once */ for(idx=0;idxid == dmn_rdr[idx_rdr]->id){ (void)fprintf(fp_stdout,"%s: ERROR %s specified more than once in reducing list\n",nco_prg_nm,dmn_rdr[idx]->nm); nco_exit(EXIT_FAILURE); } /* end if */ } /* end if */ } /* end loop over idx_rdr */ } /* end loop over idx */ if(dmn_rdr_nbr > nbr_dmn_xtr){ (void)fprintf(fp_stdout,"%s: ERROR More re-ordering dimensions than extracted dimensions\n",nco_prg_nm); nco_exit(EXIT_FAILURE); } /* end if */ } /* dmn_rdr_nbr <= 0 */ /* Is this a CCM/CCSM/CF-format history tape? */ CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id); /* Fill-in variable structure list for all extracted variables */ var=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); for(idx=0;idx= nco_dbg_var){ for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var[idx]->nm,var[idx]->id); for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var_fix[idx]->nm,var_fix[idx]->id); for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var_prc[idx]->nm,var_prc[idx]->id); } /* end if */ #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ #endif /* !ENABLE_MPI */ /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt; /* Verify output file format supports requested actions */ (void)nco_fl_fmt_vet(fl_out_fmt,cnk_nbr,dfl_lvl); /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); if(nco_dbg_lvl >= nco_dbg_sbr) (void)fprintf(stderr,"Input, output file IDs = %d, %d\n",in_id,out_id); /* Copy global attributes */ (void)nco_att_cpy(in_id,out_id,NC_GLOBAL,NC_GLOBAL,(nco_bool)True); /* Catenate time-stamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); #ifdef ENABLE_MPI /* Initialize MPI task information */ if(prc_nbr > 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr); } /* !prc_rnk == rnk_mgr */ #endif /* !ENABLE_MPI */ /* If re-ordering, then in files with record dimension... */ if(dmn_rdr_nbr > 0 && rec_dmn_id_in != NCO_REC_DMN_UNDEFINED){ /* ...which, if any, output dimension structure currently holds record dimension? */ for(dmn_out_idx=0;dmn_out_idxis_rec_dmn) break; if(dmn_out_idx != nbr_dmn_out){ dmn_out_idx_rec_in=dmn_out_idx; /* Initialize output record dimension to input record dimension */ rec_dmn_nm_in=rec_dmn_nm_out=dmn_out[dmn_out_idx_rec_in]->nm; }else{ dmn_out_idx_rec_in=NCO_REC_DMN_UNDEFINED; } /* end else */ } /* end if file contains record dimension */ /* If re-ordering, determine and set new dimensionality in metadata of each re-ordered variable */ if(dmn_rdr_nbr > 0){ dmn_idx_out_in=(int **)nco_malloc(nbr_var_prc*sizeof(int *)); dmn_rvr_in=(nco_bool **)nco_malloc(nbr_var_prc*sizeof(nco_bool *)); for(idx=0;idxnbr_dim*sizeof(int)); dmn_rvr_in[idx]=(nco_bool *)nco_malloc(var_prc[idx]->nbr_dim*sizeof(nco_bool)); /* nco_var_dmn_rdr_mtd() does re-order heavy lifting */ rec_dmn_nm_out_crr=nco_var_dmn_rdr_mtd(var_prc[idx],var_prc_out[idx],dmn_rdr,dmn_rdr_nbr,dmn_idx_out_in[idx],dmn_rvr_rdr,dmn_rvr_in[idx]); /* If record dimension required by current variable re-order... ...and variable is multi-dimensional (one dimensional arrays cannot request record dimension changes)... */ if(rec_dmn_nm_out_crr && var_prc_out[idx]->nbr_dim > 1){ /* ...differs from input and current output record dimension(s)... */ if(strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_in) && strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_out)){ /* ...and current output record dimension already differs from input record dimension... */ if(REDEFINED_RECORD_DIMENSION){ /* ...then requested re-order requires multiple record dimensions... */ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(fp_stdout,"%s: WARNING Re-order requests multiple record dimensions\n. Only first request will be honored (netCDF allows only one record dimension). Record dimensions involved [original,first change request (honored),latest change request (made by variable %s)]=[%s,%s,%s]\n",nco_prg_nm,var_prc[idx]->nm,rec_dmn_nm_in,rec_dmn_nm_out,rec_dmn_nm_out_crr); break; }else{ /* !REDEFINED_RECORD_DIMENSION */ /* ...otherwise, update output record dimension name... */ rec_dmn_nm_out=rec_dmn_nm_out_crr; /* ...and set new and un-set old record dimensions... */ var_prc_out[idx]->dim[0]->is_rec_dmn=True; dmn_out[dmn_out_idx_rec_in]->is_rec_dmn=False; /* ...and set flag that record dimension has been re-defined... */ REDEFINED_RECORD_DIMENSION=True; } /* !REDEFINED_RECORD_DIMENSION */ } /* endif new and old record dimensions differ */ } /* endif current variable is record variable */ } /* end loop over var_prc */ } /* endif dmn_rdr_nbr > 0 */ /* NB: Much of following logic is required by netCDF constraint that only one record variable is allowed per file. netCDF4 will relax this constraint. Hence making following logic prettier or funcionalizing is not high priority. Logic may need to be simplified/re-written once netCDF4 is released. */ if(REDEFINED_RECORD_DIMENSION){ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change record dimension from %s to %s. netCDF allows only one record dimension. Hence %s will make %s record (least rapidly varying) dimension in all variables that contain it.\n",nco_prg_nm,rec_dmn_nm_in,rec_dmn_nm_out,nco_prg_nm,rec_dmn_nm_out); /* Changing record dimension may invalidate is_rec_var flag Updating is_rec_var flag to correct value, even if value is ignored, helps keep user appraised of unexpected dimension re-orders. is_rec_var may change both for "fixed" and "processed" variables When is_rec_var changes for processed variables, may also need to change ancillary information and to check for duplicate dimensions. Ancillary information (dmn_idx_out_in) is available only for var_prc! Hence must update is_rec_var flag for var_fix and var_prc separately */ /* Update is_rec_var flag for var_fix */ for(idx=0;idxnbr_dim;dmn_out_idx++) if(!strcmp(var_fix[idx]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)) break; /* ...Will variable be record variable in output file?... */ if(dmn_out_idx == var_fix[idx]->nbr_dim){ /* ...No. Variable will be non-record---does this change its status?... */ if(nco_dbg_lvl >= nco_dbg_var) if(var_fix[idx]->is_rec_var == True) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n",nco_prg_nm,var_fix[idx]->nm); /* Assign record flag dictated by re-order */ var_fix[idx]->is_rec_var=False; }else{ /* ...otherwise variable will be record variable... */ /* ...Yes. Variable will be record... */ /* ...Will becoming record variable change its status?... */ if(var_fix[idx]->is_rec_var == False){ if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n",nco_prg_nm,var_fix[idx]->nm); /* Change record flag to status dictated by re-order */ var_fix[idx]->is_rec_var=True; } /* endif status changing from non-record to record */ } /* endif variable will be record variable */ } /* end loop over var_fix */ /* Update is_rec_var flag for var_prc */ for(idx=0;idxnbr_dim;dmn_out_idx++) if(!strcmp(var_prc_out[idx]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)) break; /* ...Will variable be record variable in output file?... */ if(dmn_out_idx == var_prc_out[idx]->nbr_dim){ /* ...No. Variable will be non-record---does this change its status?... */ if(nco_dbg_lvl >= nco_dbg_var) if(var_prc_out[idx]->is_rec_var == True) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n",nco_prg_nm,var_prc_out[idx]->nm); /* Assign record flag dictated by re-order */ var_prc_out[idx]->is_rec_var=False; }else{ /* ...otherwise variable will be record variable... */ /* ...Yes. Variable will be record... */ /* ...must ensure new record dimension is not duplicate dimension... */ if(var_prc_out[idx]->has_dpl_dmn){ int dmn_dpl_idx; for(dmn_dpl_idx=1;dmn_dpl_idxnbr_dim;dmn_dpl_idx++){ /* NB: loop starts from 1 */ if(var_prc_out[idx]->dmn_id[0] == var_prc_out[idx]->dmn_id[dmn_dpl_idx]){ (void)fprintf(stdout,"%s: ERROR Requested re-order turns duplicate non-record dimension %s in variable %s into output record dimension. netCDF does not support duplicate record dimensions in a single variable.\n%s: HINT: Exclude variable %s from extraction list with \"-x -v %s\".\n",nco_prg_nm_get(),rec_dmn_nm_out,var_prc_out[idx]->nm,nco_prg_nm_get(),var_prc_out[idx]->nm,var_prc_out[idx]->nm); nco_exit(EXIT_FAILURE); } /* endif err */ } /* end loop over dmn_out */ } /* endif has_dpl_dmn */ /* ...Will becoming record variable change its status?... */ if(var_prc_out[idx]->is_rec_var == False){ if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n",nco_prg_nm,var_prc_out[idx]->nm); /* Change record flag to status dictated by re-order */ var_prc_out[idx]->is_rec_var=True; /* ...Swap dimension information for multi-dimensional variables... */ if(var_prc_out[idx]->nbr_dim > 1){ /* Swap dimension information when turning multi-dimensional non-record variable into record variable. Single dimensional non-record variables that turn into record variables already have correct dimension information */ dmn_sct *dmn_swp; /* [sct] Dimension structure for swapping */ int dmn_idx_rec_in; /* [idx] Record dimension index in input variable */ int dmn_idx_rec_out; /* [idx] Record dimension index in output variable */ int dmn_idx_swp; /* [idx] Dimension index for swapping */ /* If necessary, swap new record dimension to first position */ /* Label indices with standard names */ dmn_idx_rec_in=dmn_out_idx; dmn_idx_rec_out=0; /* Swap indices in map */ dmn_idx_swp=dmn_idx_out_in[idx][dmn_idx_rec_out]; dmn_idx_out_in[idx][dmn_idx_rec_out]=dmn_idx_rec_in; dmn_idx_out_in[idx][dmn_idx_rec_in]=dmn_idx_swp; /* Swap dimensions in list */ dmn_swp=var_prc_out[idx]->dim[dmn_idx_rec_out]; var_prc_out[idx]->dim[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_in]; var_prc_out[idx]->dim[dmn_idx_rec_in]=dmn_swp; /* NB: Change dmn_id,cnt,srt,end,srd together to minimize chances of forgetting one */ /* Correct output variable structure copy of output record dimension information */ var_prc_out[idx]->dmn_id[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->id; var_prc_out[idx]->cnt[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->cnt; var_prc_out[idx]->srt[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->srt; var_prc_out[idx]->end[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->end; var_prc_out[idx]->srd[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->srd; /* Correct output variable structure copy of input record dimension information */ var_prc_out[idx]->dmn_id[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->id; var_prc_out[idx]->cnt[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->cnt; var_prc_out[idx]->srt[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->srt; var_prc_out[idx]->end[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->end; var_prc_out[idx]->srd[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->srd; } /* endif multi-dimensional */ } /* endif status changing from non-record to record */ } /* endif variable will be record variable */ } /* end loop over var_prc */ } /* !REDEFINED_RECORD_DIMENSION */ #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* Defining dimension in output file done by Manager alone */ #endif /* !ENABLE_MPI */ /* Once new record dimension, if any, is known, define dimensions in output file */ (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_out); #ifdef ENABLE_MPI } /* prc_rnk != rnk_mgr */ #endif /* !ENABLE_MPI */ /* Alter metadata for variables that will be packed */ if(nco_pck_plc != nco_pck_plc_nil){ if(nco_pck_plc != nco_pck_plc_upk){ /* Allocate attribute list container for maximum number of entries */ aed_lst_add_fst=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); aed_lst_scl_fct=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); } /* endif packing */ for(idx=0;idx= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ #ifdef ENABLE_MPI } /* prc_rnk != rnk_mgr */ /* Manager obtains output filename and broadcasts to workers */ if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); MPI_Bcast(&fl_nm_lng,1,MPI_INT,0,MPI_COMM_WORLD); if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char)); MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,0,MPI_COMM_WORLD); #endif /* !ENABLE_MPI */ /* Assign zero to start and unity to stride vectors in output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr); #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ TKN_WRT_FREE=False; #endif /* !ENABLE_MPI */ /* Copy variable data for non-processed variables */ (void)nco_msa_var_val_cpy(in_id,out_id,var_fix,nbr_var_fix,lmt_all_lst,nbr_dmn_fl); #ifdef ENABLE_MPI /* Close output file so workers can open it */ nco_close(out_id); TKN_WRT_FREE=True; } /* prc_rnk != rnk_mgr */ #endif /* !ENABLE_MPI */ /* Close first input netCDF file */ nco_close(in_id); /* Loop over input files (not currently used, fl_nbr == 1) */ for(fl_idx=0;fl_idx= nco_dbg_fl) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in); /* Make sure file is on local system and is readable or die trying */ if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"local file %s:\n",fl_in); /* Open file once per thread to improve caching */ for(thr_idx=0;thr_idx nbr_var_prc-1){ msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ msg_bfr[1]=out_id; /* Output file ID */ }else{ /* Tell requesting worker to allocate space for next variable */ msg_bfr[0]=idx; /* [idx] Variable to be processed */ msg_bfr[1]=out_id; /* Output file ID */ msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ /* Point to next variable on list */ idx++; } /* endif idx */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); /* msg_tag_typ != msg_tag_wrk_rqs */ }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ /* Allocate token if free, else ask worker to try later */ if(TKN_WRT_FREE){ TKN_WRT_FREE=False; msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ }else{ msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ } /* !TKN_WRT_FREE */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ } /* end while var_wrt_nbr < nbr_var_prc */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ wrk_id_bfr[0]=prc_rnk; while(1){ /* While work remains... */ /* Send msg_tag_wrk_rqs */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); /* Receive msg_tag_wrk_rsp */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,0,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); idx=msg_bfr[0]; out_id=msg_bfr[1]; if(idx == idx_all_wrk_ass) break; else{ lcl_idx_lst[lcl_nbr_var]=idx; /* storing the indices for subsequent processing by the worker */ lcl_nbr_var++; var_prc_out[idx]->id=msg_bfr[2]; /* Process this variable same as UP code */ #if 0 /* NB: Immediately preceding MPI else scope confounds Emacs indentation Fake end scope restores correct indentation, simplifies code-checking */ } /* fake end else */ #endif /* !0 */ #else /* !ENABLE_MPI */ #ifdef _OPENMP #pragma omp parallel for default(none) private(idx,in_id) shared(aed_lst_add_fst,aed_lst_scl_fct,nco_dbg_lvl,dmn_idx_out_in,dmn_rdr_nbr,dmn_rvr_in,in_id_arr,nbr_var_prc,nco_pck_map,nco_pck_plc,out_id,nco_prg_nm,rcd,var_prc,var_prc_out) #endif /* !_OPENMP */ /* UP and SMP codes main loop over variables */ for(idx=0;idxnc_id=in_id; if(nco_dbg_lvl >= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Retrieve variable from disk into memory */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_msa_var_get(in_id,var_prc[idx],lmt_all_lst,nbr_dmn_fl); if(dmn_rdr_nbr > 0){ if((var_prc_out[idx]->val.vp=(void *)nco_malloc_flg(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type))) == NULL){ (void)fprintf(fp_stdout,"%s: ERROR Unable to malloc() %ld*%lu bytes for value buffer for variable %s in main()\n",nco_prg_nm_get(),var_prc_out[idx]->sz,(unsigned long)nco_typ_lng(var_prc_out[idx]->type),var_prc_out[idx]->nm); nco_exit(EXIT_FAILURE); } /* endif err */ /* Change dimensionionality of values */ rcd=nco_var_dmn_rdr_val(var_prc[idx],var_prc_out[idx],dmn_idx_out_in[idx],dmn_rvr_in[idx]); /* Re-ordering required two value buffers, time to free input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); /* Free current dimension correspondence */ dmn_idx_out_in[idx]=nco_free(dmn_idx_out_in[idx]); dmn_rvr_in[idx]=nco_free(dmn_rvr_in[idx]); } /* endif dmn_rdr_nbr > 0 */ if(nco_pck_plc != nco_pck_plc_nil){ /* Copy input variable buffer to processed variable buffer */ /* fxm: this is dangerous and leads to double free()'ing variable buffer */ var_prc_out[idx]->val=var_prc[idx]->val; /* (Un-)Pack variable according to packing specification */ nco_pck_val(var_prc[idx],var_prc_out[idx],nco_pck_map,nco_pck_plc,aed_lst_add_fst+idx,aed_lst_scl_fct+idx); } /* endif dmn_rdr_nbr > 0 */ #ifdef ENABLE_MPI /* Obtain token and prepare to write */ while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); tkn_wrt_rsp=msg_bfr[0]; /* Wait then re-send request */ if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; } /* end while loop waiting for write token */ /* Worker has token---prepare to write */ if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ if(RAM_OPEN) md_open=NC_WRITE|NC_SHARE|NC_DISKLESS; else md_open=NC_WRITE|NC_SHARE; rcd=nco_fl_open(fl_out_tmp,md_open,&bfr_sz_hnt,&out_id); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); #else /* !ENABLE_MPI */ #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ #endif /* !ENABLE_MPI */ { /* begin OpenMP critical */ /* Common code for UP, SMP, and MPI */ /* Copy variable to output file then free value buffer */ if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); }else{ /* end if variable is scalar */ (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end if variable is array */ } /* end OpenMP critical */ /* Free current output buffer */ var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); #ifdef ENABLE_MPI /* Close output file and increment written counter */ nco_close(out_id); var_wrt_nbr++; } /* endif tkn_wrt_rqs_xcp */ } /* end else !idx_all_wrk_ass */ } /* end while loop requesting work/token */ } /* endif Worker */ #else /* !ENABLE_MPI */ } /* end (OpenMP parallel for) loop over idx */ #endif /* !ENABLE_MPI */ if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(fp_stderr,"\n"); #ifdef ENABLE_MPI MPI_Barrier(MPI_COMM_WORLD); if(prc_rnk == rnk_mgr) { /* Manager only */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* ! prc_rnk == rnk_mgr */ else{ /* Workers */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); #endif /* !ENABLE_MPI */ /* Write/overwrite packing attributes for newly packed and re-packed variables Logic here should nearly mimic logic in nco_var_dfn() */ if(nco_pck_plc != nco_pck_plc_nil && nco_pck_plc != nco_pck_plc_upk){ nco_bool nco_pck_plc_alw; /* [flg] Packing policy allows packing nc_typ_in */ /* ...put file in define mode to allow metadata writing... */ if(RAM_OPEN) md_open=NC_WRITE|NC_DISKLESS; else md_open=NC_WRITE; rcd=nco_fl_open(fl_out_tmp,md_open,&bfr_sz_hnt,&out_id); (void)nco_redef(out_id); /* ...loop through all variables that may have been packed... */ #ifdef ENABLE_MPI for(jdx=0;jdxtyp_upk,(nc_type *)NULL))){ /* Verify input variable was newly packed by this operator Writing pre-existing (non-re-packed) attributes here would fail because nco_pck_dsk_inq() never fills in var->scl_fct.vp and var->add_fst.vp Logic is same as in nco_var_dfn() (except var_prc[] instead of var[]) If operator newly packed this particular variable... */ if( /* ...either because operator newly packs all variables... */ (nco_pck_plc == nco_pck_plc_all_new_att) || /* ...or because operator newly packs un-packed variables like this one... */ (nco_pck_plc == nco_pck_plc_all_xst_att && !var_prc[idx]->pck_ram) || /* ...or because operator re-packs packed variables like this one... */ (nco_pck_plc == nco_pck_plc_xst_new_att && var_prc[idx]->pck_ram) ){ /* Replace dummy packing attributes with final values, or delete them */ if(nco_dbg_lvl >= nco_dbg_io) (void)fprintf(stderr,"%s: main() replacing dummy packing attribute values for variable %s\n",nco_prg_nm,var_prc[idx]->nm); (void)nco_aed_prc(out_id,aed_lst_add_fst[idx].id,aed_lst_add_fst[idx]); (void)nco_aed_prc(out_id,aed_lst_scl_fct[idx].id,aed_lst_scl_fct[idx]); } /* endif variable is newly packed by this operator */ } /* endif nco_pck_plc_alw */ } /* end loop over var_prc */ (void)nco_enddef(out_id); #ifdef ENABLE_MPI nco_close(out_id); #endif /* !ENABLE_MPI */ } /* nco_pck_plc == nco_pck_plc_nil || nco_pck_plc == nco_pck_plc_upk */ #ifdef ENABLE_MPI if(prc_rnk == prc_nbr-1) /* Send Token to Manager */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); else MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* !Workers */ if(prc_rnk == rnk_mgr){ /* Only Manager */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_nbr-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); } /* prc_rnk != rnk_mgr */ #endif /* !ENABLE_MPI */ /* Close input netCDF file */ for(thr_idx=0;thr_idx 0){ /* Free dimension correspondence list */ for(idx=0;idx 0) dmn_rdr_lst_in=nco_sng_lst_free(dmn_rdr_lst_in,dmn_rdr_nbr_in); /* Free dimension list pointers */ dmn_rdr=(dmn_sct **)nco_free(dmn_rdr); /* Dimension structures in dmn_rdr are owned by dmn and dmn_out, free'd later */ } /* endif dmn_rdr_nbr > 0 */ if(nco_pck_plc != nco_pck_plc_nil){ if(nco_pck_plc_sng) nco_pck_plc_sng=(char *)nco_free(nco_pck_plc_sng); if(nco_pck_map_sng) nco_pck_map_sng=(char *)nco_free(nco_pck_map_sng); if(nco_pck_plc != nco_pck_plc_upk){ /* No need for loop over var_prc variables to free attribute values Variable structures and attribute edit lists share same attribute values Free them only once, and do it in nco_var_free() */ aed_lst_add_fst=(aed_sct *)nco_free(aed_lst_add_fst); aed_lst_scl_fct=(aed_sct *)nco_free(aed_lst_scl_fct); } /* nco_pck_plc == nco_pck_plc_upk */ } /* nco_pck_plc == nco_pck_plc_nil */ /* NB: lmt now referenced within lmt_all_lst[idx] */ for(idx=0;idxlmt_dmn_nbr;jdx++) lmt_all_lst[idx]->lmt_dmn[jdx]=nco_lmt_free(lmt_all_lst[idx]->lmt_dmn[jdx]); if(nbr_dmn_fl > 0) lmt_all_lst=nco_lmt_all_lst_free(lmt_all_lst,nbr_dmn_fl); lmt=(lmt_sct**)nco_free(lmt); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_arr) in_id_arr=(int *)nco_free(in_id_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) aux=(lmt_sct **)nco_free(aux); /* Free chunking information */ for(idx=0;idx 0) cnk_dmn=nco_cnk_lst_free(cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); if(xtr_nbr > 0) var_out=nco_var_lst_free(var_out,xtr_nbr); var_prc=(var_sct **)nco_free(var_prc); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix=(var_sct **)nco_free(var_fix); var_fix_out=(var_sct **)nco_free(var_fix_out); } /* !flg_cln */ #ifdef ENABLE_MPI MPI_Finalize(); #endif /* !ENABLE_MPI */ nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/ncap_lex.l0000644000674300045400000013215212274266124015303 0ustar zendercgdcsm%{ /* $Header: /cvsroot/nco/nco/src/nco/ncap_lex.l,v 1.80 2014/02/04 22:40:20 zender Exp $ -*-C-*- */ /* Everything from here to closing brace is placed at top of lexer */ /* Purpose: Token generator for ncap parser */ /* Copyright (C) 1995--2013 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Example lexers: /data/zender/ora/lexyacc/ch3-05.l GCC lexer is hard-coded in C for speed, but is easy to read: ../src/gcc-3.x.x/c-lex.c Unidata ${DATA}/tmp/netcdf-3.5.1-beta10/src/ncgen/ncgen.l */ /* Usage: scp ~/nco/src/nco/ncap_lex.l goldhill.cgd.ucar.edu:nco/src/nco scp ~/nco/src/nco/ncap_lex.l krein.math.uci.edu:nco/src/nco flex --stdout ~/nco/src/nco/ncap_lex.l > ~/nco/src/nco/ncap_lex.c flex --header-file=${HOME}/nco/src/nco/ncap_lex.h --stdout ~/nco/src/nco/ncap_lex.l > ~/nco/src/nco/ncap_lex.c NB: flex with -Cf or -CF not -I if this scanner will not be interactive */ /* Standard header files */ #include /* assert() debugging macro */ #include /* Integer representation, INT_MIN, INT_MAX... */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strdup */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Headers specific to this program */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "ncap.h" /* netCDF arithmetic processor-specific definitions (symbol table, ...) */ #include "ncap_yacc.h" /* Symbol definitions from parser */ /* We want yylex() errors to skip current line rather than stop execution We do this by provoking error in parser by returning unrecognized token This causes parser to read up to next ';' To avoid having two error messages we prefix error message to yyerror with '#' This causes yyerror to print current error and skip next error fxm: Hackish, but I see no other way */ /* NCO prototypes yylex() in three separate places---Ensure that all prototypes agree! The alternative, prototyping yylex() once in ncap.h, requires YY*STYPE (ncap_yacc.h) too That is unappealing since we want ncap.h segregable from parser and scanner dependencies (Asterisks inserted into token names in comments so that cpp does not expand token) 1. Top of ncap_lex.l via YY*DECL token Define YY*DECL token so yylex() accepts re-entrant arguments (Flex p. 12, Bison p. 60) Use YY*DECL on line following its definition to make prototype visible in ncap_lex.c This quiets a compiler warning 2. Top of ncap_yacc.y via YY*DECL token Required to quiet compiler warning (see additional comments in ncap_yacc.y) 3. In ncap_lex.l ncap_ntl_scn() declaration Required for ncap_ntl_scn() call to yylex() (additional comments in ncap_ntl_scn()) */ #define YY_DECL int yylex(YYSTYPE *lval_ptr,prs_sct *prs_arg) YY_DECL; #if (defined(__GNUC__) || defined(__INTEL_COMPILER)) && !defined(__PATHCC__) && !defined(PGI_CC) && (defined(ENABLE_DEBUG_CUSTOM) || defined(ENABLE_OPTIMIZE_CUSTOM)) /* CEWI fxm 20040110 Prototype functions that cause warnings with pedantic GCC compiling Portability of this entire section is questionable, so enclose in ifdef GCC We already assume lexer is flex since AT&T lex does not understand rules Thus prototyping following flex-specific functions adds no additional assumptions See also 20040112 thread in comp.compilers */ /* Implicit declaration warnings: -D_POSIX_SOURCE also avoids fileno warning */ int fileno(FILE *); /* fixes: warning: implicit declaration of function `fileno', -D_POSIX_SOURCE also avoids this warning */ /* int yy_flex_realloc(void *,size_t); *//* fixes: warning: implicit declaration of function `yy_flex_realloc'. Is this obsolete? Other versions of flex on Linux seem to want void * yy_flex_realloc(void *,size_t), which actually makes more sense given that it is a realloc() function */ /* 20050318: Fedora Core 2 flex 2.5.4 gcc 3.4.2 This prototype causes error: conflicting types for 'yy_flex_realloc' */ /* Missing prototypes warnings: Triggered by -Wmissing-prototypes */ FILE *yyget_in(void); /* fixes: warning: no previous prototype for `yyget_in' */ FILE *yyget_out(void); /* fixes: warning: no previous prototype for `yyget_out' */ char *yyget_text(void); /* fixes: warning: no previous prototype for `yyget_text' */ int yyget_debug(void); /* fixes: warning: no previous prototype for `yyget_debug' */ int yyget_leng(void); /* fixes: warning: no previous prototype for `yyget_leng' */ int yyget_lineno(void); /* fixes: warning: no previous prototype for `yyget_lineno' */ int yylex_destroy(void); /* fixes: warning: no previous prototype for `yylex_destroy' */ void yyset_debug(int bdebug); /* fixes: warning: no previous prototype for `yyset_debug' */ void yyset_in(FILE *in_str); /* fixes: warning: no previous prototype for `yyset_in' */ void yyset_lineno(int line_number); /* fixes: warning: no previous prototype for `yyset_lineno' */ void yyset_out(FILE *out_str); /* fixes: warning: no previous prototype for `yyset_out' */ #endif /* !__GNUC__ */ /* Global variables */ extern size_t ncap_ncl_dpt_crr; /* [nbr] Depth of current #include file (declared in ncap.c) */ extern size_t *ncap_ln_nbr_crr; /* [cnt] Line number (declared in ncap.c) */ extern char **ncap_fl_spt_glb; /* [fl] Script file (declared in ncap.c) */ /* File scope variables */ /* fxm: turn arbitrary size into pre-processor token */ char ncap_err_sng[200]; /* [sng] Buffer for error string */ /* Is lexer on left or right hand side of equals sign? LHS should contain only a variable or attribute In this case return variable/attribute name to parser If on RHS then return attribute value or variable structure Initialize to false, change to true if token is '=', false is token is ';' */ static nco_bool RHS=False; /* [flg] Is lexer on RHS of '=' sign? */ /* Headers necessary for INCLUDE state */ #define NCO_MAX_NCL_DPT 10 YY_BUFFER_STATE ncl_stk[NCO_MAX_NCL_DPT]; /* Include stack */ %} /* %x defines exclusive start states Once state is active, other rules do not match until initial state is restored NB: State names may not contain hyphens CCOMMENT: Handle C comments LMB92 p. 172, p. 43 INCLUDE: Read in #include file (from example in flex manpage) DMN_LST: Dimension list LHS_SUBSCRIPT: Left Hand Side subscripts (currently LHS casting) RHS_SUBSCRIPT: Right Hand Side subscripts (currently not used) */ %x CCOMMENT DMN_LST INCLUDE LHS_SUBSCRIPT RHS_SUBSCRIPT /* Definitions: LMB92 p. 153 Definitions are named regular expressions, e.g., DGT [0-9] Definitions enclosed in braces in rules section, e.g. {DGT}, are interpreted literally DGT [0-9] Digit LPH [A-Za-z_] Alphabetic character LPHDGT [A-Za-z0-9_] Alphanumeric character XPN [eE][+-]?[0-9]+ Real number Exponent */ DOT '.' DGT [0-9] LPH [A-Za-z_] LPHDGT [A-Za-z0-9_] XPN [eE][+-]?[0-9]+ /* Following sections after %% are lexer rules Each rule is regular expression followed by C-code for action If token matches regular expression then C-code is executed */ %% \#include { /* INCLUDE is exclusive start state for obtaining #include filename */ BEGIN INCLUDE; } /* end include */ [ \t]* /* Eat whitespace */ [^ \t\n]+ { /* Get include file name */ if(ncap_ncl_dpt_crr >= NCO_MAX_NCL_DPT){ (void)fprintf(stderr,"%s: ERROR File %s nesting depth of %lu is too deep",nco_prg_nm_get(),yytext,(unsigned long)ncap_ncl_dpt_crr); nco_exit(EXIT_FAILURE); } /* endif */ if(nco_dbg_lvl_get() > 1) (void)fprintf(stderr,"%s: INFO Will descend from file %s at nesting depth %lu to #include'd file %s at depth %lu\n",nco_prg_nm_get(),ncap_fl_spt_glb[ncap_ncl_dpt_crr],(unsigned long)ncap_ncl_dpt_crr,yytext,(unsigned long)ncap_ncl_dpt_crr+1UL); /* Put current input buffer on stack */ ncl_stk[ncap_ncl_dpt_crr]=YY_CURRENT_BUFFER; /* Increment nesting level */ ncap_ncl_dpt_crr++; /* Allocate another entry in line counter array */ ncap_ln_nbr_crr=(size_t *)nco_realloc(ncap_ln_nbr_crr,ncap_ncl_dpt_crr+1UL); /* Initialize line number counter for new file */ ncap_ln_nbr_crr[ncap_ncl_dpt_crr]=1UL; /* Store file name for diagnostics */ ncap_fl_spt_glb=(char **)nco_realloc(ncap_fl_spt_glb,ncap_ncl_dpt_crr+1UL); ncap_fl_spt_glb[ncap_ncl_dpt_crr]=(char *)strdup(yytext); if((yyin=fopen(ncap_fl_spt_glb[ncap_ncl_dpt_crr],"r")) == NULL){ (void)fprintf(stderr,"%s: ERROR Unable to open script file %s\n",nco_prg_nm_get(),ncap_fl_spt_glb[ncap_ncl_dpt_crr]); nco_exit(EXIT_FAILURE); } /* endif error */ /* Create new scanner input buffer for include file and switch to it Current start conditions remains active in new input buffer */ nco_yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* end enter #include file */ <> { /* NB: AT&T lex does not appear to have rules */ nco_bool NCO_SCRIPT_WITH_EOF_IS_TOPLEVEL=True; /* Emerge from #include file if nested, else exit lexer */ if(ncap_ncl_dpt_crr > 0UL){ /* If we are exiting a #include'd script, delete its buffers */ NCO_SCRIPT_WITH_EOF_IS_TOPLEVEL=False; /* [flg] */ if(nco_dbg_lvl_get() > 1) (void)fprintf(stderr,"%s: DEBUG Found EOF, emerging from file %s at nesting depth %lu to file %s at depth %lu\n",nco_prg_nm_get(),ncap_fl_spt_glb[ncap_ncl_dpt_crr],(unsigned long)ncap_ncl_dpt_crr,ncap_fl_spt_glb[ncap_ncl_dpt_crr-1],(unsigned long)ncap_ncl_dpt_crr-1UL); ncap_fl_spt_glb[ncap_ncl_dpt_crr]=(char *)nco_free(ncap_fl_spt_glb[ncap_ncl_dpt_crr]); /* Decrement depth of nesting */ ncap_ncl_dpt_crr--; /* De-allocate entry from line counter array */ ncap_ln_nbr_crr=(size_t *)nco_realloc(ncap_ln_nbr_crr,ncap_ncl_dpt_crr+1UL); /* De-allocate entry from script name array */ ncap_fl_spt_glb=(char **)nco_realloc(ncap_fl_spt_glb,ncap_ncl_dpt_crr+1UL); } /* endif #include'd script */ if(NCO_SCRIPT_WITH_EOF_IS_TOPLEVEL){ /* Emerged from zeroth level, exit lexer */ yyterminate(); }else{ /* Reclaim storage used by buffer just exited */ yy_delete_buffer(YY_CURRENT_BUFFER); /* Switch back to parent buffer */ nco_yy_switch_to_buffer(ncl_stk[ncap_ncl_dpt_crr]); } /* endelse */ } /* end */ "/*" { /* CCOMMENT is exclusive start state for C comments LMB92 p. 172 When CCOMMENT state is active, only CCOMMENT rules will match (hence an "exclusive start state" rather than "regular start state") Thus must (re)-define line number incrementing */ BEGIN CCOMMENT; } \n { /* Throw away comment text but increment line counter */ ncap_ln_nbr_crr[ncap_ncl_dpt_crr]++; } . { /* Throw away everything except end comment text */ } "*/" { /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* end CCOMMENT start state rules */ "(/" { /* Dimension list */ if(nco_dbg_lvl_get() > 0) (void)fprintf(stderr,"Entering DMN_LST with %s\n",yytext); BEGIN DMN_LST; return IGNORE; } /* End dimension list */ [ \t\n]* /* Eat whitespace */ "/)" { if(nco_dbg_lvl_get() > 0) (void)fprintf(stderr,"Exiting DMN_LST with %s\n",yytext); /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* End dimension list */ [^\]\n]*[\]\n]/"/)" { /*{LPH}{LPHDGT}*[ \t\n]*[,]?[ \t\n]* {*/ /* Recognize dimension lists */ if(nco_dbg_lvl_get() > 0) (void)fprintf(stderr,"Lexing dimension list %s\n",yytext); /* Valid subscripts must contain alphanumeric string */ if(yyleng < 3) goto end_dmn_lst; end_dmn_lst: /* Errors encountered during LHS processing jump to here */ /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* end dimension list */ \n { /* NB: Remaining rules are default state, also known as INITIAL state, or 0 state */ /* Ignore new lines */ ncap_ln_nbr_crr[ncap_ncl_dpt_crr]++; } [ \t]+ { /* Eat spaces and tabs */ } \/\/[^\n]* { /* Enable C++ comments */ } \"[^"\n]*["\n] { /* Process quoted strings */ char *bfr; bfr=(char*)nco_malloc(yyleng*sizeof(char)); strcpy(bfr,&yytext[1]); bfr[yyleng-2]='\0'; /* Replace C-language escape codes with actual byte values */ (void)sng_ascii_trn(bfr); lval_ptr->sng=strdup(bfr); bfr=(char*)nco_free(bfr); if(nco_dbg_lvl_get() > 3){ (void)fprintf(stderr,"Lexing string: %s\n",yytext); (void)fprintf(stderr,"Made string: %s\n",lval_ptr->sng); } /* endif */ return SNG; } /* end quoted strings */ {DGT}*\.{DGT}*({XPN})?[LlDd]?|{DGT}*({XPN})[LlDd]? { /* double or long double */ /* NB: Tempted to prepend lexer expressions for floats and doubles with [+-]? so that unary plus/minus is handled in lexer rather than parser. However, this has unintended side effects so let parser handle it for now */ char *sng_cnv_rcd=char_CEWI; /* [sng] strtol()/strtoul() return code */ if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a double %s\n",yytext); lval_ptr->scv.val.d=strtod(yytext,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(yytext,"strtod",sng_cnv_rcd); lval_ptr->scv.type=NC_DOUBLE; return SCV; } /* end double or long double */ {DGT}*\.{DGT}*({XPN})?[Ff]|{DGT}*({XPN})[Ff] { /* float */ float float_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a float %s\n",yytext); if(sscanf((char *)yytext,"%e",&float_tkn) != 1){ sprintf(ncap_err_sng,"#Bad float: %s",yytext); nco_yyerror(prs_arg,ncap_err_sng); return EPROVOKE; } /* endif */ lval_ptr->scv.val.f=float_tkn; lval_ptr->scv.type=NC_FLOAT; return SCV; } /* end float */ {DGT}+("LL"|"ll") { /* int64 */ nco_int64 int64_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing an int64 %s\n",yytext); if(sscanf((char *)yytext,"%lli",&int64_tkn) != 1){ sprintf(ncap_err_sng,"Bad int64 constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.i=int64_tkn; lval_ptr->scv.type=NC_INT64; return SCV; } /* end int64 */ {DGT}+("ULL"|"ull") { /* uint64 */ nco_uint64 uint64_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a uint64 %s\n",yytext); if(sscanf((char *)yytext,"%llu",&uint64_tkn) != 1){ sprintf(ncap_err_sng,"Bad uint64 constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.i=uint64_tkn; lval_ptr->scv.type=NC_UINT64; return SCV; } /* end uint64 */ {DGT}+[lL]? { /* int */ nco_int int_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing an int %s\n",yytext); /* NB: Format depends on opaque type of nco_int Until 200911, nco_int was C-type long, and now nco_int is C-type int if(sscanf((char *)yytext,"%li",&int_tkn) != 1){ */ if(sscanf((char *)yytext,"%i",&int_tkn) != 1){ sprintf(ncap_err_sng,"Bad int constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.i=int_tkn; lval_ptr->scv.type=NC_INT; return SCV; } /* end int */ {DGT}+([uU]|"ul"|"UL") { /* uint */ nco_uint uint_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a uint %s\n",yytext); if(sscanf((char *)yytext,"%u",&uint_tkn) != 1){ sprintf(ncap_err_sng,"Bad uint constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.ui=uint_tkn; lval_ptr->scv.type=NC_UINT; return SCV; } /* end uint */ {DGT}+[sS] { /* short */ nco_short short_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a short %s\n",yytext); if(sscanf((char *)yytext,"%hi",&short_tkn) != 1){ sprintf(ncap_err_sng,"Bad short constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.s=short_tkn; lval_ptr->scv.type=NC_SHORT; return SCV; } /* end short */ {DGT}+("us"|"US") { /* ushort */ nco_ushort short_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a ushort %s\n",yytext); if(sscanf((char *)yytext,"%hu",&short_tkn) != 1){ sprintf(ncap_err_sng,"Bad short constant: %s",(char *)yytext); nco_yyerror(prs_arg,ncap_err_sng); } /* endif err */ lval_ptr->scv.val.s=short_tkn; lval_ptr->scv.type=NC_USHORT; return SCV; } /* end short */ {DGT}+[Bb] { /* byte */ nco_byte byte_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a byte %s\n",yytext); if(sscanf((char *)yytext,"%hhi",&byte_tkn) != 1){ sprintf(ncap_err_sng,"#Bad byte: %s",yytext); nco_yyerror(prs_arg,ncap_err_sng); return EPROVOKE; } /* endif err */ lval_ptr->scv.val.b=byte_tkn; lval_ptr->scv.type=NC_BYTE; return SCV; } /* end byte */ {DGT}+("UB"|"ub") { /* ubyte */ nco_ubyte ubyte_tkn; if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing a ubyte %s\n",yytext); if(sscanf((char *)yytext,"%hhu",&ubyte_tkn) != 1){ sprintf(ncap_err_sng,"#Bad byte: %s",yytext); nco_yyerror(prs_arg,ncap_err_sng); return EPROVOKE; } /* endif err */ lval_ptr->scv.val.ub=ubyte_tkn; lval_ptr->scv.type=NC_UBYTE; return SCV; } /* end ubyte */ foo1_zyx {return ABS;} /* Strategy for lexing control statements: 1. Look for language control statements (if, while, do, for) 2. Look for NCO-defined intrinsic functions (abs, pack, unpack) 3. Look for mathematical intrinsic functions (sin, cos) 4. Look for NCO-defined named constants (M_PI, M_E) */ "if" {return IF;} "print" {return PRINT;} foo2_zyx {return ABS;} /* TOKEN whitespace (: Token followed any amount of whitespace followed by opening parenthesis signifies function name, not variable name. This disambiguates variable and functional namespaces. Dimension reducing functions (min,max,avg,ttl) need thought Each function should allow specification of optional dimension list, e.g., foo=avg(var,(/lat,lon/)); should return mean T over lat,lon dimensions Certain functions, however, have binary versions, e.g., foo=min(var_1,var_2); should return point-wise minimum values Dimension lists require syntax like (/.../) to disambiguate meanings like foo=min(lat,lat) End result: foo=min(lat) Returns minimum value of lat foo=min(lat,(/lat/)) Returns minimum value of lat foo=min(lat,lat) Returns copy of lat (i.e., pointwise minimum of lat and lat) foo=min(var,(/dmn_1,dmn_2/)) Returns minimum of variable over dmn_1, dmn_2 dimensions */ abs/[ ]*\( {return ABS;} atostr/[ ]*\( {return ATOSTR;} avg/[ ]*\( {prs_arg->nco_op_typ=nco_op_avg;return RDC;} min/[ ]*\( {prs_arg->nco_op_typ=nco_op_min;return RDC;} max/[ ]*\( {prs_arg->nco_op_typ=nco_op_max;return RDC;} ttl/[ ]*\( {prs_arg->nco_op_typ=nco_op_ttl;return RDC;} pck/[ ]*\( {return PACK;} pack/[ ]*\( {return PACK;} pow/[ ]*\( {return POWER;} upk/[ ]*\( {return UNPACK;} unpack/[ ]*\( {return UNPACK;} float/[ ]*\( { lval_ptr->cnv_type = NC_FLOAT;return CNV_TYPE;} double/[ ]*\( { lval_ptr->cnv_type = NC_DOUBLE;return CNV_TYPE;} long/[ ]*\( { lval_ptr->cnv_type = NC_INT;return CNV_TYPE;} int/[ ]*\( { lval_ptr->cnv_type = NC_INT;return CNV_TYPE;} short/[ ]*\( { lval_ptr->cnv_type = NC_SHORT;return CNV_TYPE;} ushort/[ ]*\( { lval_ptr->cnv_type = NC_USHORT;return CNV_TYPE;} uint/[ ]*\( { lval_ptr->cnv_type = NC_UINT;return CNV_TYPE;} int64/[ ]*\( { lval_ptr->cnv_type = NC_INT64;return CNV_TYPE;} uint64/[ ]*\( { lval_ptr->cnv_type = NC_UINT64;return CNV_TYPE;} ubyte/[ ]*\( { lval_ptr->cnv_type = NC_UBYTE;return CNV_TYPE;} byte/[ ]*\( { lval_ptr->cnv_type = NC_BYTE;return CNV_TYPE;} char/[ ]*\( { lval_ptr->cnv_type = NC_CHAR;return CNV_TYPE;} M_PI {return NAMED_CONSTANT;} {LPH}{LPHDGT}*/[ ]*\( { /* Compare input with mathematical function names in table and return pointer to structure containing name, double function, float function */ int idx; for(idx=0;idxsym_tbl_nbr;idx++) if(!strcmp(yytext,(prs_arg->sym_tbl[idx]->nm))){ lval_ptr->sym=prs_arg->sym_tbl[idx]; return FUNCTION; } /* endif */ (void)sprintf(ncap_err_sng,"Warning: Unable to locate function %s. Perhaps %s is a variable?",yytext,yytext); (void)nco_yyerror(prs_arg,ncap_err_sng); return EPROVOKE; } /* end functions */ {LPH}{LPHDGT}*@{LPH}{LPHDGT}* { /* Recognize variable attributes, e.g., var_nm@att_nm */ aed_sct *ptr_aed; char *amp_ptr; char att_nm[NC_MAX_NAME]; char var_nm[NC_MAX_NAME]; int rcd=NC_NOERR; int rcd_out; int var_id; long att_sz; nc_type type; ptr_unn val; size_t sng_lng; nco_bool blkp; var_sct var_lkp; /* for us when calling lookup vars on first pass only */ if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing attribute %s\n",yytext); amp_ptr=strchr(yytext,'@'); sng_lng=amp_ptr-yytext; strncpy(var_nm,yytext,sng_lng); var_nm[sng_lng]='\0'; strcpy(att_nm,++amp_ptr); var_lkp.nm=var_nm; /* Assume global attribute when variable name is "global" */ if(!strcmp(var_nm,"global")) var_id=NC_GLOBAL; else rcd=nco_inq_varid_flg(prs_arg->in_id,var_nm,&var_id); /* We are on RHS so return value of attribute (if available) to parser During initial scan, just return attributes on RHS if(prs_arg->ntl_scn){ if(!RHS){ lval_ptr->aed.att_nm=(char *)strdup(att_nm); lval_ptr->aed.var_nm=(char *)strdup(var_nm); return OUT_ATT; }else{ return IGNORE; } } */ if(RHS){ /* First check if attribute has already been saved in symbol table If so then obtain and return value, else check input file If attribute is present obtain and return value from disk else return NC_BYTE of value 0 If attribute is NC_CHAR then return SNG type Other types (NC_FLOAT, NC_DOUBLE, NC_BYTE, NC_SHORT) return SCV */ ptr_aed=ncap_aed_lookup(var_nm,att_nm,prs_arg,False); if(ptr_aed){ if(ptr_aed->type == NC_CHAR){ (void)cast_void_nctype(ptr_aed->type,&ptr_aed->val); lval_ptr->sng=(char *)nco_malloc((ptr_aed->sz+1)*nco_typ_lng(NC_CHAR)); strncpy(lval_ptr->sng,(char *)(ptr_aed->val.cp),(size_t)(ptr_aed->sz)); lval_ptr->sng[ptr_aed->sz]='\0'; return SNG; }else{ lval_ptr->scv=ptr_unn_2_scv(ptr_aed->type,ptr_aed->val); return SCV; } /* end else */ } /* end if */ if(rcd == NC_NOERR){ rcd=nco_inq_att_flg(prs_arg->in_id,var_id,att_nm,&type,&att_sz); if (rcd == NC_ENOTATT){ (void)sprintf(ncap_err_sng,"Warning: Unable to locate RHS attribute %s of variable %s with var ID = %d in file %s. Returning 0-byte.",att_nm,var_nm,var_id,prs_arg->fl_in); (void)nco_yyerror(prs_arg,ncap_err_sng); lval_ptr->scv.val.b=0; lval_ptr->scv.type=NC_BYTE; return SCV; } /* end if */ if(rcd == NC_NOERR){ val.vp=(void *)nco_malloc(att_sz*nco_typ_lng(type)); rcd=nco_get_att(prs_arg->in_id,var_id,att_nm,val.vp,type); if(type == NC_CHAR){ (void)cast_void_nctype(type,&val); lval_ptr->sng=(char *)nco_malloc((att_sz+1)*sizeof(char)); strncpy(lval_ptr->sng,(char *)val.cp,(size_t)att_sz); lval_ptr->sng[att_sz]='\0';; val.vp=(void*)nco_free(val.vp); return SNG; }else{ lval_ptr->scv=ptr_unn_2_scv(type,val); val.vp=(void*)nco_free(val.vp); return SCV; } /* end else */ } /* end if */ }else{ /* ...else rcd reported an error */ /* Attribute is not in table or on disk so return 0-byte */ (void)sprintf(ncap_err_sng,"Warning: Unable to locate RHS attribute %s of variable %s with var ID = %d in file %s. Returning 0-byte.",att_nm,var_nm,var_id,prs_arg->fl_in); (void)nco_yyerror(prs_arg,ncap_err_sng); lval_ptr->scv.val.b=0; lval_ptr->scv.type=NC_BYTE; return SCV; } /* end if */ }/* end if RHS */ /* We are on LHS so simply save information for later processing by parser Atrribute is valid if its associated variable is in input or output file */ if(!RHS){ if(prs_arg->ntl_scn) blkp= ( ncap_var_lookup(&var_lkp,prs_arg,False) !=NULL) ; else blkp=False; rcd_out=nco_inq_varid_flg(prs_arg->out_id,var_nm,&var_id); if(rcd == NC_NOERR || rcd_out == NC_NOERR || blkp ){ lval_ptr->aed.att_nm=(char *)strdup(att_nm); lval_ptr->aed.var_nm=(char *)strdup(var_nm); return OUT_ATT; }else{ (void)sprintf(ncap_err_sng,"#Warning: unable to locate variable %s. So cannot create attribute %s",var_nm,yytext); (void)nco_yyerror(prs_arg,ncap_err_sng); return EPROVOKE; } /* end else */ } /* end if */ } /* End scalar values. Phew! */ {LPH}{LPHDGT}*/\[ { /* Recognize variables with subscripts */ if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing variable with subscripts %s\n",yytext); if(RHS){ lval_ptr->var_nm_RHS=(char *)strdup(yytext); BEGIN RHS_SUBSCRIPT; return VAR; }else{ lval_ptr->var_nm_LHS=(char *)strdup(yytext); BEGIN LHS_SUBSCRIPT; return OUT_VAR; } /* end else */ } /* end variables with subscripts */ {LPH}{LPHDGT}* { /* Recognize plain variables */ if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"Lexing variable %s\n",yytext); if(RHS){ /* fxm mmr: memory leak since var_nm_RHS is never free()'d */ lval_ptr->var_nm_RHS=(char *)strdup(yytext); return VAR; }else{ lval_ptr->var_nm_LHS=(char *)strdup(yytext); return OUT_VAR; } /* end else */ } /* end variables without subscripts */ \[[^\]\n]*[\]\n] { /* fxm: allow whitespace in dimension list */ /* Recognize subscripted (hyperslabbed) variables Hyperslabbed variables for now indicated with square brackets Using square brackets so development does not break functions Left context is described in LMB92 p. 152 Subscript syntax is taken from Fortran9X specification: x[dmn1,dmn2,...,dmnN] x[a:b,c:,:d,e] */ const char * const sbs_dlm=","; /* [sng] Subscript delimiter */ static const char * const tpl_nm="Internally generated template"; char **sbs_lst; /* [sng] Array of dimension subscripts */ char *sbs_sng; /* [sng] Subscript */ int dmn_nbr; /* [nbr] Number of dimensions */ int idx; /* [idx] Counter */ int jdx; /* [idx] Counter */ double val=1.0; /* [frc] Value of template */ var_sct *var; /* [sct] Variable */ dmn_sct **dmn; /* [dmn] Dimension structure list */ dmn_sct *dmn_item; dmn_sct **dmn_new; /* Valid subscripts must contain alphanumeric string */ if(nco_dbg_lvl_get() > 2) (void)fprintf(stderr,"Interpreting %s as LHS_SUBSCRIPT\n",yytext); if(yyleng < 3) goto end_LHS_sbs; /* if(prs_arg->ntl_scn) goto end_LHS_sbs; */ /* Copy token into user memory and turn into list of dimension names */ sbs_sng=(char *)nco_malloc(yyleng*sizeof(char)); strcpy(sbs_sng,&yytext[1]); sbs_sng[yyleng-2]='\0'; sbs_lst=nco_lst_prs_2D(sbs_sng,sbs_dlm,&dmn_nbr); dmn=(dmn_sct **)nco_malloc(dmn_nbr*sizeof(dmn_sct *)); (void)nco_redef(prs_arg->out_id); for(idx=0;idxdmn_out */ for(jdx=0;jdx<*(prs_arg->nbr_dmn_out);jdx++){ dmn_item=(*(prs_arg->dmn_out))[jdx]; if(!strcmp(sbs_lst[idx],dmn_item->nm)){ dmn[idx]=dmn_item; break; } /* endif */ } /* end loop over jdx */ if(jdx != *(prs_arg->nbr_dmn_out)) continue; /* then try seach for dimension in prs_arg->dmn_in */ for (jdx=0;jdxnbr_dmn_in;jdx++){ dmn_item = prs_arg->dmn_in[jdx]; /* If found add dimension to dmn_out and dmn */ if(!strcmp(sbs_lst[idx],dmn_item->nm)){ /* BEWARE -- nco_dmn_out_grow() increments *(prs_arg->nbr_dmn_out) */ dmn_new = nco_dmn_out_grow(prs_arg); *dmn_new=nco_dmn_dpl(dmn_item); (void)nco_dmn_xrf(*dmn_new,dmn_item); /* write found dimension to output */ (void)nco_dmn_dfn(prs_arg->fl_out,prs_arg->out_id,dmn_new,1); dmn[idx]=*dmn_new; break; } /* endif */ } /* end loop over jdx */ if(jdx != prs_arg->nbr_dmn_in) continue; /* Exit action if dimension not found */ (void)sprintf(ncap_err_sng,"Warning: Unrecognized dimension \"%s\" in LHS subscripts",sbs_lst[idx]); (void)nco_yyerror(prs_arg,ncap_err_sng); (void)nco_enddef(prs_arg->out_id); goto end_LHS_sbs; } /* endif */ (void)nco_enddef(prs_arg->out_id); /* Check that un-limited dimension is first dimension */ for(idx=1;idxis_rec_dmn){ (void)sprintf(ncap_err_sng,"Warning:\"%s\" is the record dimension. It can only be the first dimension in a list",dmn[idx]->nm); (void)nco_yyerror(prs_arg,ncap_err_sng); goto end_LHS_sbs; } /* endif */ /* Create template variable to cast all RHS expressions */ var=(var_sct *)nco_malloc(sizeof(var_sct)); /* Set defaults */ (void)var_dfl_set(var); /* [fnc] Set defaults for each member of variable structure */ /* Overwrite with LHS information */ /* fxm mmr: memory leak with var->nm */ var->nm=(char *)strdup(tpl_nm); var->type=NC_DOUBLE; var->nbr_dim=dmn_nbr; var->dim=dmn; /* Allocate space for dimension structures */ if(var->nbr_dim > 0) var->dmn_id=(int *)nco_malloc(var->nbr_dim*sizeof(int)); else var->dmn_id=(int *)NULL; if(var->nbr_dim > 0) var->cnt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->cnt=(long *)NULL; if(var->nbr_dim > 0) var->srt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srt=(long *)NULL; if(var->nbr_dim > 0) var->end=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->end=(long *)NULL; if(var->nbr_dim > 0) var->srd=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srd=(long *)NULL; /* Defensive programming */ var->sz=1L; /* Attach LHS dimensions to variable */ for(idx=0;idxdim[idx]=dmn[idx]; var->dmn_id[idx]=dmn[idx]->id; var->cnt[idx]=dmn[idx]->cnt; var->srt[idx]=dmn[idx]->srt; var->end[idx]=dmn[idx]->end; var->srd[idx]=dmn[idx]->srd; var->sz*=var->cnt[idx]; } /* end loop over dim */ /* don't initalize val in intial scan */ if(prs_arg->ntl_scn) { var->val.vp=(void*)NULL; goto end_var; } /* Allocate space for variable values fxm: more efficient and safer to use nco_calloc() and not fill with values? */ if((var->val.vp=(void *)nco_malloc_flg(var->sz*nco_typ_lng(var->type))) == NULL){ (void)fprintf(stderr,"%s: ERROR Unable to malloc() %ld*%lu bytes for var_LHS() in lexer\n",nco_prg_nm_get(),var->sz,(unsigned long)nco_typ_lng(var->type)); nco_exit(EXIT_FAILURE); } /* end if */ /* Copy arbitrary value into variable Placing a uniform value in variable should be unnecessary since variable is intended for use solely as dimensional template for nco_var_cnf_dmn() Nevertheless, copy 1.0 into value for safety */ { /* Change scope to define convenience variables which reduce de-referencing */ long var_sz; /* [nbr] Number of elements in variable */ size_t var_typ_sz; /* [B] Size of single element of variable */ char *var_val_cp; /* [ptr] Pointer to values */ var_sz=var->sz; /* [nbr] Number of elements in variable */ var_typ_sz=nco_typ_lng(var->type); var_val_cp=(char *)var->val.vp; for(idx=0;idxvar_LHS=var; if(nco_dbg_lvl_get() > 2) (void)fprintf(stderr,"%s: Lexer creating LHS cast template: Template var->nm %s, var->nbr_dim %d, var->sz %li\n",nco_prg_nm_get(),prs_arg->var_LHS->nm,prs_arg->var_LHS->nbr_dim,prs_arg->var_LHS->sz); if(0){ /* Remove some compiler warning messages CEWI */ /* Following two statements remove "defined but not used" messages in ncap_lex.c (lex.yy.c) */ (void)yyunput((int)0,(char *)NULL); /* (void)yy_flex_realloc((void *)NULL,(size_t)NULL);*/ /* Remove warnings which only occur on SGI IRIX cc */ yy_full_match=yy_full_match+0; yy_full_lp=yy_full_lp+0; yy_full_state=yy_full_state+0; } /* endif False */ /* Free dimension list memory */ (void)nco_free(sbs_sng); /* char list */ if(dmn_nbr > 0) sbs_lst=nco_sng_lst_free(sbs_lst,dmn_nbr); end_LHS_sbs: /* Errors encountered during LHS processing jump to here */ /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* end LHS subscripted variables */ \[[^\]\n]*[\]\n] { /* RHS_SUBSCRIPT */ (void)sprintf(ncap_err_sng,"Warning RHS subscripts are not yet implemented"); (void)nco_yyerror(prs_arg,ncap_err_sng); /* Return to default state, known as INITIAL state or 0 state LMB92 p. 43 */ BEGIN INITIAL; } /* end RHS_SUBSCRIPT */ "&&" { /* And */ return AND; } /* end && */ "||" { /* Or */ return OR; } /* end || */ "==" { /* Comparison equals */ lval_ptr->nco_rlt_opr=nco_op_eq; return COMPARISON; } /* end == */ "!=" { /* Comparison not equals */ lval_ptr->nco_rlt_opr=nco_op_ne; return COMPARISON; } /* end != */ "<=" { /* Comparison less than or equal to */ lval_ptr->nco_rlt_opr=nco_op_le; return COMPARISON; } /* end <= */ ">=" { /* Comparison greater than or equal to */ lval_ptr->nco_rlt_opr=nco_op_ge; return COMPARISON; } /* end >= */ "<" { /* Comparison less than */ lval_ptr->nco_rlt_opr=nco_op_lt; return COMPARISON; } /* end < */ ">" { /* Comparison greater than */ lval_ptr->nco_rlt_opr=nco_op_gt; return COMPARISON; } /* end > */ = { /* Equals assignment */ RHS=True; return yytext[0]; } /* end equals */ ; { /* semi-colon indicates end-of-statement */ RHS=False; return yytext[0]; } /* end semi-colon */ . { /* Everything not parsed by above falls through to here */ if(nco_dbg_lvl_get() > 5) (void)fprintf(stderr,"%s: Following token reached last lexer rule: %s\n",nco_prg_nm_get(),yytext); return yytext[0]; } /* end trickle down */ %% /* Begin user functions section */ int /* fxm: 20060217 Change to int from bool to work with g++ */ yywrap(void) { /* Purpose: Routine to replace library-defined yywrap() yywrap() is called when YY_INPUT returns EOF, e.g., at end of script Returning false (zero) means there is more to scan, and input has been redirected to new source, e.g., yyin points to new file. Returning true (non-zero) means scanning is complete, so scanner terminates and returns 0 to calling function Default is to return true (one) when called---this terminates scanner */ if(nco_dbg_lvl_get() >= 3) (void)fprintf(stderr,"%s: DEBUG yywrap() called with ncap_ncl_dpt_crr = %lu\n",nco_prg_nm_get(),(unsigned long)ncap_ncl_dpt_crr); /* comp.compilers thread 20020523 yywrap() should always return 1, even when scanning a #include'd file return (ncap_ncl_dpt_crr <= 1) ? 1 : 0; */ return 1; } /* end yywrap() */ void ncap_ntl_scn /* [fnc] Scan command script, construct I/O lists */ (prs_sct * const prs_arg, /* I/O [sct] Global information required in parser routines */ const char * const spt_arg_cat, /* I [sng] User-specified script */ nm_id_sct** const xtr_lst_a, /* O [sct] RHS variables present in input file */ int * const nbr_lst_a, /* O [nbr] Number of distinct RHS variables in input file */ nm_id_sct** const xtr_lst_b, /* O [sct] LHS variables present in input file */ int * const nbr_lst_b, /* O [nbr] Number of distinct LHS variables in input file */ nm_id_sct** const xtr_lst_c, /* O [sct] Parent variables of LHS attributes in input file */ int * const nbr_lst_c, /* O [nbr] Number of attribute parent variables in input file */ nm_id_sct** const xtr_lst_d, /* O [sct] LHS dimensions in input file */ int * const nbr_lst_d) /* O [nbr] Number of LHS dimensions in input file */ { /* Purpose: Scan command script, construct I/O lists Call routine to learn metadata contents of output file prior to arithmetic processing lst_a: RHS variables present in input file lst_b: LHS variables present in input file lst_c: Parent variables of LHS attributes in input file lst_d: Dimensions required by LHS subscripts (casting) */ /* 20020510: ncap_ntl_scn() was in ncap_utl.c but chokes g++ (not gcc) g++ complains that since YYSTYPE is defined in ncap_yacc.h, it is an error to call external function (yylex()) that uses this type Although the error is somewhat bogus, there is some merit to it Placing routine in ncap.l gives routine access to yylex() prototype and YYSTYPE Since ncap_ntl_scn() does call yylex(), it may reside in ncap.l To move routine to other file, #define NCAP_NTL_SCN_NOT_IN_NCAP_L */ #undef NCAP_NTL_SCN_NOT_IN_NCAP_L #ifdef NCAP_NTL_SCN_NOT_IN_NCAP_L /* Get YYSTYPE prior to calling scanner */ #include "ncap_yacc.h" /* ncap_yacc.h (ncap.tab.h) is produced from ncap_yacc.y by parser generator */ extern FILE *yyin; /* [fl] File handle for script file */ extern int yylex(YYSTYPE *lval_ptr,prs_sct *prs_arg); /* [fnc] Scanner entrypoint */ /* Following declaration gets rid of implicit declaration compiler warning It is a condensation of the lexer declaration from lex.yy.c: YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); */ extern int yy_scan_string(const char *); #endif /* NCAP_NTL_SCN_NOT_IN_NCAP_L */ nco_bool mch_flg; /* [flg] Variable is defined in list already */ char *var_nm; int lst_a_nbr=0; /* [nbr] Number of elements in list A */ int lst_b_nbr=0; /* [nbr] Number of elements in list B */ int lst_c_nbr=0; /* [nbr] Number of elements in list C */ int lst_d_nbr=0; /* [nbr] Number of elements in list D */ int lst_t_nbr=0; /* [nbr] Number of elements in list T */ int tkn_crr=-1; /* [tkn] Current token, must initialize to non-zero value */ int var_id; int var_idx; nm_id_sct *lst_a=NULL_CEWI; nm_id_sct *lst_b=NULL_CEWI; nm_id_sct *lst_c=NULL_CEWI; nm_id_sct *lst_d=NULL_CEWI; nm_id_sct *lst_t=NULL_CEWI; YYSTYPE lval; /* [tkn] Token */ if(spt_arg_cat){ yy_scan_string(spt_arg_cat); }else{ /* Open script file for reading */ if((yyin=fopen(ncap_fl_spt_glb[ncap_ncl_dpt_crr],"r")) == NULL){ (void)fprintf(stderr,"%s: ERROR Unable to open script file %s\n",nco_prg_nm_get(),ncap_fl_spt_glb[ncap_ncl_dpt_crr]); nco_exit(EXIT_FAILURE); } /* endif error */ } /* endif input from script */ /* While there are more tokens... */ while(tkn_crr != 0){ /* ...obtain next token from lexer... */ tkn_crr=yylex(&lval,prs_arg); /* ...determine which variables and attributes exist in input file... */ switch (tkn_crr){ case IGNORE: break; /* Do nothing */ case SCV: break; /* Do nothing */ case EPROVOKE: break; /* Do nothing */ case VAR: /* Search for RHS variables in input file */ var_nm=lval.var_nm_RHS; if(NC_NOERR == nco_inq_varid_flg(prs_arg->in_id,var_nm,&var_id)){ mch_flg=False; /* [flg] Variable is defined in list already */ /* Search RHS variables already known to be in input file... */ for(var_idx=0;var_idxin_id,var_nm,&var_id)){ mch_flg=False; for(var_idx=0;var_idxin_id,var_nm,&var_id)){ mch_flg=False; for(var_idx=0;var_idxlst,lval.sbs_lst->nbr); if(lst_t_nbr > 0) (void)nco_nm_id_lst_free(lst_t,lst_t_nbr); break; default: /* Tokens that fall through are perfectly safe and normal Tokens values 1--256 are ASCII characters, values > 256 defined in yy.tab.h */ if(nco_dbg_lvl_get() >= 5)(void)fprintf(stderr,"%s: DEBUG Token type %d not handled in ncap_ntl_scn()\n",nco_prg_nm_get(),tkn_crr); break; } /* end switch */ } /* end while */ if(lst_a_nbr > 0){*xtr_lst_a=lst_a;*nbr_lst_a=lst_a_nbr;} if(lst_b_nbr > 0){*xtr_lst_b=lst_b;*nbr_lst_b=lst_b_nbr;} if(lst_c_nbr > 0){*xtr_lst_c=lst_c;*nbr_lst_c=lst_c_nbr;} if(lst_d_nbr > 0){*xtr_lst_d=lst_d;*nbr_lst_d=lst_d_nbr;} } /* end ncap_ntl_scn() */ int /* O [enm] Return code */ ncap_ncwa_scn /* [fnc] Scan command script, construct I/O lists */ (prs_sct * const prs_arg, /* I/O [sct] Global information required in parser routines */ const char * const msk_sng, /* I [sng] User-specified script */ char **msk_nm, /* O [sng] Masking variable name */ double *msk_val, /* O [frc] Masking value */ int *op_typ_rlt) /* O [enm] Relational operator type */ { /* Get YYSTYPE prior to calling scanner */ /* #include "ncap_yacc.h" extern int yylex(YYSTYPE *lval_ptr,prs_sct *prs_arg); extern int yy_scan_string(const char *); */ nco_bool scv_def=False; int op_typ=-1; int rcd=1; char *fnl_sng; char *msk_nm_LHS=NULL; scv_sct scv_out; int tkn_crr=-1; /* [tkn] Current token, must initialize to non-zero value */ YYSTYPE lval; /* [tkn] Token */ fnl_sng=(char *)nco_malloc((strlen(msk_sng)+3UL)*sizeof(char)); (void)strcpy(fnl_sng,msk_sng); (void)strcat(fnl_sng,";\n"); yy_scan_string(fnl_sng); /* While there are more tokens... */ while(tkn_crr != 0){ /* ...obtain next token from lexer... */ tkn_crr=yylex(&lval,prs_arg); /* ...determine which variables and attributes exist in input file... */ switch(tkn_crr){ case OUT_VAR: msk_nm_LHS=strdup(lval.var_nm_LHS); break; case COMPARISON: op_typ=lval.nco_rlt_opr; break; case SCV: scv_out=lval.scv; scv_def=True; break; default: /* Tokens that fall through are perfectly safe and normal Tokens values 1--256 are ASCII characters, values > 256 defined in yy.tab.h */ if(nco_dbg_lvl_get() >= 5) (void)fprintf(stderr,"%s: DEBUG Token type %d not handled in ncap_ntl_scn()\n",nco_prg_nm_get(),tkn_crr); /* Assume single '=' means '==' if op_typ is not defined */ if(tkn_crr == '=' && op_typ == -1) op_typ=nco_op_eq; break; } /* end switch */ } /* end while */ /* Check all three items have been scanned in */ if(msk_nm_LHS == (char *)NULL){ (void)fprintf(stderr,"%s: Mask string (%s) does not contain valid variable name\n",nco_prg_nm_get(),msk_sng); rcd=0; }else{ *msk_nm=msk_nm_LHS; } /* endif */ if(op_typ == -1){ (void)fprintf(stderr,"%s: Mask string (%s) does not contain valid comparison operator\n",nco_prg_nm_get(),msk_sng); rcd=0; }else{ *op_typ_rlt=op_typ; } /* endif */ if(scv_def == False){ (void)fprintf(stderr,"%s: Mask string (%s) does not contain valid number\n",nco_prg_nm_get(),msk_sng); rcd=0; }else{ (void)nco_scv_cnf_typ((nc_type)NC_DOUBLE,&scv_out); *msk_val=scv_out.val.d; } /* endif */ return rcd; } /* end ncap_ncwa_scn() */ /* End user functions section */ ./nco-4.4.2/src/nco/nco_rec_var.h0000644000674300045400000000273412260451232015757 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_rec_var.h,v 1.21 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Record variable utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_rec_var.h" *//* Record variable utilities */ #ifndef NCO_REC_VAR_H #define NCO_REC_VAR_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void rec_var_dbg /* [fnc] Aid in debugging problems with record dimension */ (const int nc_id, /* I [id] netCDF file ID */ const char * const dbg_sng); /* I [sng] Debugging message to print */ void rec_crd_chk /* Check for monotonicity of coordinate values */ (const var_sct * const var, /* I [sct] Coordinate to check for monotonicity */ const char * const fl_in, /* I [sng] Input filename */ const char * const fl_out, /* I [sng] Output filename */ const long idx_rec, /* I [idx] Index of record coordinate in input file */ const long idx_rec_out); /* I [idx] Index of record coordinate in output file */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_REC_VAR_H */ ./nco-4.4.2/src/nco/nco_grp_utl.h0000644000674300045400000014031112301221754016004 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_grp_utl.h,v 1.461 2014/02/19 21:36:44 pvicente Exp $ */ /* Purpose: Group utilities */ /* Copyright (C) 2011--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_var_utl.h" *//* Group utilities */ #ifndef NCO_GRP_UTL_H #define NCO_GRP_UTL_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* assert() */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, exit */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_att_utl.h" /* Attribute utilities */ #include "nco_aux.h" /* Auxiliary coordinates */ #include "nco_cnf_dmn.h" /* Conform dimensions */ #include "nco_cnk.h" /* Chunking */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_grp_trv.h" /* Group traversal */ #include "nco_mmr.h" /* Memory management */ #include "nco_msa.h" /* Multi-slabbing algorithm */ #include "nco_prn.h" /* Print variables, attributes, metadata */ #include "nco_var_lst.h" /* Variable list utilities */ #include "nco_cnv_csm.h" /* CCM/CCSM/CF conventions */ /* Dynamic array implementation of group stack */ typedef struct { int grp_nbr; /* [nbr] Number of items in stack = number of elements in grp_id array */ int *grp_id; /* [ID] Group ID */ } grp_stk_sct; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ nm_id_sct * /* O [sct] Extraction list */ nco_trv_tbl_nm_id /* [fnc] Create extraction list of nm_id_sct from traversal table */ (const int nc_id_in, /* I [ID] netCDF input file ID */ const int nc_id_out, /* I [ID] netCDF output file ID */ const gpe_sct * const gpe, /* I [sct] GPE structure */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ void nco_flg_set_grp_var_ass /* [fnc] Set flags for groups and variables associated with matched object */ (const char * const grp_nm_fll, /* I [sng] Full name of group */ const nco_obj_typ obj_typ, /* I [enm] Object type (group or variable) */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ int /* O [rcd] Return code */ nco_def_grp_full /* [fnc] Ensure all components of group path are defined */ (const int nc_id, /* I [ID] netCDF output-file ID */ const char * const grp_nm_fll, /* I [sng] Full group name */ int * const grp_out_id); /* O [ID] Deepest group ID */ int /* [rcd] Return code */ nco_inq_grps_full /* [fnc] Discover and return IDs of apex and all sub-groups */ (const int grp_id, /* I [ID] Apex group */ int * const grp_nbr, /* O [nbr] Number of groups */ int * const grp_ids); /* O [ID] Group IDs of children */ void nco_grp_itr_free /* [fnc] Free group iterator */ (grp_stk_sct * const grp_stk); /* O [sct] Group stack pointer */ int /* [rcd] Return code */ nco_grp_stk_get /* [fnc] Initialize and obtain group iterator */ (const int grp_id, /* I [ID] Apex group */ grp_stk_sct ** const grp_stk); /* O [sct] Group stack pointer */ int /* [rcd] Return code */ nco_grp_stk_nxt /* [fnc] Find and return next group ID */ (grp_stk_sct * const grp_stk, /* O [sct] Group stack pointer */ int * const grp_id); /* O [ID] Group ID */ grp_stk_sct * /* O [sct] Group stack pointer */ nco_grp_stk_ntl /* [fnc] Initialize group stack */ (void); void nco_grp_stk_psh /* [fnc] Push group ID onto stack */ (grp_stk_sct * const grp_stk, /* I/O [sct] Group stack pointer */ const int grp_id); /* I [ID] Group ID to push */ int /* O [ID] Group ID that was popped */ nco_grp_stk_pop /* [fnc] Remove and return group ID from stack */ (grp_stk_sct * const grp_stk); /* I/O [sct] Group stack pointer */ void nco_grp_stk_free /* [fnc] Free group stack */ (grp_stk_sct * const grp_stk); /* O [sct] Group stack pointer */ int /* [rcd] Return code */ nco_grp_dfn /* [fnc] Define groups in output file */ (const int out_id, /* I [ID] netCDF output-file ID */ nm_id_sct *grp_xtr_lst, /* [grp] Number of groups to be defined */ const int grp_nbr); /* I [nbr] Number of groups to be defined */ int /* [rcd] Return code */ nco_def_grp_rcr /* [fnc] Define groups */ (const int in_id, /* I [ID] netCDF input-file ID */ const int out_id, /* I [ID] netCDF output-file ID */ const char * const prn_nm, /* I [sng] Parent group name */ const int rcr_lvl); /* I [nbr] Recursion level */ int nco_get_sls_chr_cnt /* [fnc] Get number of slash characterrs in a string path */ (char * const nm_fll); /* I [sct] Full name */ int nco_get_sng_pth_sct /* [fnc] Get string path structure */ (char * const nm_fll, /* I [sng] Full name */ sng_pth_sct ***str_pth_lst); /* I/O [sct] List of path components */ void nco_prn_grp_nm_fll /* [fnc] Debug function to print group full name from ID */ (const int grp_id); /* I [ID] Group ID */ nco_bool /* O [flg] All user-specified names are in file */ nco_xtr_mk /* [fnc] Check -v and -g input names and create extraction list */ (char **grp_lst_in, /* I [sng] User-specified list of groups */ const int grp_xtr_nbr, /* I [nbr] Number of groups in list */ char **var_lst_in, /* I [sng] User-specified list of variables */ const int var_xtr_nbr, /* I [nbr] Number of variables in list */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ const nco_bool flg_unn, /* I [flg] Select union of specified groups and variables */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_xcl /* [fnc] Convert extraction list to exclusion list */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_crd_add /* [fnc] Add all coordinates to extraction list */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_cf_add /* [fnc] Add to extraction list variable associated with CF convention */ (const int nc_id, /* I [ID] netCDF file ID */ const char * const cf_nm, /* I [sng] CF convention ("coordinates" or "bounds") */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_cf_prv_add /* [fnc] Add specified CF-compliant coordinates of specified variable to extraction list */ (const int nc_id, /* I [ID] netCDF file ID */ const trv_sct * const var_trv, /* I [sct] Variable (object) */ const char * const cf_nm, /* I [sng] CF convention ( "coordinates" or "bounds") */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_prn_att_trv /* [fnc] Print all attributes of single variable */ (const int in_id, /* I [id] netCDF input file ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_xtr_crd_ass_add /* [fnc] Add to extraction list all coordinates associated with extracted variables */ (const int nc_id, /* I netCDF file ID */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_get_prg_info(void); /* [fnc] Get program info */ void nco_prn_xtr_mtd /* [fnc] Print variable metadata (called with PRN_VAR_METADATA) */ (const int nc_id, /* I netCDF file ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_xtr_lst_prn /* [fnc] Print name-ID structure list */ (nm_id_sct * const nm_id_lst, /* I [sct] Name-ID structure list */ const int nm_id_nbr); /* I [nbr] Number of name-ID structures in list */ void nco_prn_dmn /* [fnc] Print dimensions for a group */ (const int nc_id, /* I [ID] File ID */ const char * const grp_nm_fll); /* I [sng] Full name of group */ void nco_prn_xtr_val /* [fnc] Print variable data (called with PRN_VAR_DATA) */ (const int nc_id, /* I netCDF file ID */ prn_fmt_sct * const prn_flg, /* I/O [sct] Print formatting flags */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ int /* O [nbr] Number of matches to current rx */ nco_trv_rx_search /* [fnc] Search for pattern matches in traversal table */ (const char * const rx_sng, /* I [sng] Regular expression pattern */ const nco_obj_typ obj_typ, /* I [enm] Object type (group or variable) */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_dmn_mrk /* [fnc] Mark extracted dimensions */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_xtr_grp_mrk /* [fnc] Mark extracted groups */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_xtr_dfn /* [fnc] Define extracted groups, variables, and attributes in output file */ (const int nc_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sng] GPE structure */ const md5_sct * const md5, /* I [sct] MD5 configuration */ const nco_bool CPY_GRP_METADATA, /* I [flg] Copy group metadata (attributes) */ const nco_bool CPY_VAR_METADATA, /* I [flg] Copy variable metadata (attributes) */ const int nco_pck_plc, /* I [enm] Packing policy */ const char * const rec_dmn_nm, /* I [sng] Record dimension name */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_xtr_wrt /* [fnc] Write extracted data to output file */ (const int nc_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const gpe_sct * const gpe, /* I [sct] GPE structure */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ const nco_bool HAVE_LIMITS, /* I [flg] Dimension limits exist */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ nco_bool /* O [flg] True if in scope */ nco_crd_var_dmn_scp /* [fnc] Is coordinate variable in dimension scope */ (const trv_sct * const var_trv, /* I [sct] GTT Object Variable */ const dmn_trv_sct * const dmn_trv, /* I [sct] GTT unique dimension */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ int /* [rcd] Return code */ nco_grp_itr /* [fnc] Populate traversal table by examining, recursively, subgroups of parent */ (const int grp_id, /* I [ID] Group ID */ char * const grp_nm_fll_prn, /* I [sng] Absolute group name of parent (path) */ char * const grp_nm_fll, /* I [sng] Absolute group name (path) */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_bld_crd_rec_var_trv /* [fnc] Build dimension information for all variables */ (const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_bld_crd_var_trv /* [fnc] Build GTT "crd_sct" coordinate variable structure */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_prn_trv_tbl /* [fnc] Print GTT (Group Traversal Table) for debugging with --get_grp_info */ (const int nc_id, /* I [ID] File ID */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_bld_dmn_ids_trv /* [fnc] Build dimension info for all variables */ (const int nc_id, /* I [ID] netCDF file ID */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_has_crd_dmn_scp /* [fnc] Is there a variable with same name in dimension's scope? */ (const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_bld_var_dmn /* [fnc] Assign variables dimensions to either coordinates or dimension structs */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ crd_sct * /* O [sct] Coordinate object */ nco_scp_var_crd /* [fnc] Is coordinate in scope of variable? */ (trv_sct *var_trv, /* I [sct] Variable object */ dmn_trv_sct *dmn_trv); /* I [sct] Dimension object */ int /* O [nbr] Comparison result */ nco_cmp_crd_dpt /* [fnc] Compare two crd_sct's by group depth */ (const void *p1, /* I [sct] crd_sct* to compare */ const void *p2); /* I [sct] crd_sct* to compare */ void nco_wrt_trv_tbl /* [fnc] Obtain file information from GTT (Group Traversal Table) for debugging */ (const int nc_id, /* I [ID] File ID */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ nco_bool use_flg_xtr); /* I [flg] Use flg_xtr in selection */ void nco_gpe_chk /* [fnc] Check valid GPE new name */ (const char * const grp_out_fll, /* I [sng] Group name */ const char * const var_nm, /* I [sng] Variable name */ gpe_nm_sct ** gpe_nm, /* I/O [sct] GPE name duplicate check array */ int * nbr_gpe_nm); /* I/O [nbr] Number of GPE entries */ void nco_get_rec_dmn_nm /* [fnc] Return array of record names */ (const trv_sct * const var_trv, /* I [sct] Variable object */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ nm_tbl_sct ** rec_dmn_nm); /* I/O [sct] Array of record names */ void nco_prs_aux_crd /* [fnc] Parse auxiliary coordinates */ (const int nc_id, /* I [ID] netCDF file ID */ const int aux_nbr, /* I [nbr] Number of auxiliary coordinates */ char *aux_arg[], /* I [sng] Auxiliary coordinates */ const nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ const nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ const nco_bool EXTRACT_ASSOCIATED_COORDINATES, /* I [flg] Extract all coordinates associated with extracted variables? */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ var_sct ** /* O [sct] Variable list */ nco_fll_var_trv /* [fnc] Fill-in variable structure list for all extracted variables */ (const int nc_id, /* I [id] netCDF file ID */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ var_sct ** /* O [sct] Variable list */ nco_var_trv /* [fnc] Fill-in variable structure list for all variables named "var_nm" */ (const int nc_id, /* I [id] netCDF file ID */ const char * const var_nm, /* I [sng] Variable name (relative) */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ void nco_cpy_fix_var_trv /* [fnc] Copy fixed variables from input to output file */ (const int nc_id, /* I [ID] netCDF input file ID */ const int out_id, /* I [ID] netCDF output file ID */ const gpe_sct * const gpe, /* I [sng] GPE structure */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_prc_cmn /* [fnc] Process objects (ncbo only) */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_id_2, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_sct * trv_1, /* I [sct] Table object */ trv_sct * trv_2, /* I [sct] Table object */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ nco_bool flg_grp_1, /* I [flg] Use table 1 as template for group creation on True, otherwise use table 2 */ const nco_bool flg_dfn); /* I [flg] Action type (True for define variables, False when write variables ) */ void nco_cpy_fix /* [fnc] Copy fixed object (ncbo only) */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ trv_sct *trv_1, /* I/O [sct] Table object */ trv_tbl_sct * const trv_tbl_1, /* I [sct] GTT (Group Traversal Table) */ const nco_bool flg_dfn); /* I [flg] Action type (True for define variables, False when write variables ) */ nco_bool /* O [flg] Copy packing attributes */ nco_pck_cpy_att /* [fnc] Inquire about copying packing attributes */ (const int nco_prg_id, /* I [enm] Program ID */ const int nco_pck_plc, /* I [enm] Packing policy */ const var_sct * const var_prc); /* I [sct] Variable */ nco_bool /* O [flg] True for match found */ nco_rel_mch /* [fnc] Relative match of object in table 1 to table 2 */ (const int nc_id_1, /* I [id] netCDF input-file ID from file 1 */ const int nc_id_2, /* I [id] netCDF input-file ID from file 2 */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_sct * var_trv, /* I [sct] Table variable object (can be from table 1 or 2) */ nco_bool flg_tbl_1, /* I [flg] Table variable object is from table1 for True, otherwise is from table 2 */ nco_bool flg_grp_1, /* I [flg] Use table 1 as template for group creation on True, otherwise use table 2 */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ const nco_bool flg_dfn); /* I [flg] Action type (True for define variables, False when write variables ) */ void nco_prc_cmn_nm /* [fnc] Process common objects from a common mames list */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_id_2, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ const nco_cmn_t * const cmn_lst, /* I [sct] List of common names */ const int nbr_cmn_nm, /* I [nbr] Number of common names entries */ const nco_bool flg_dfn); /* I [flg] Action type (True for define variables, False when write variables ) */ void nco_var_prc_fix_trv /* [fnc] Store processed and fixed variables info into GTT */ (const int nbr_var_prc, /* I [nbr] Number of processed variables */ var_sct **var_prc, /* I [sct] Array of processed variables */ const int nbr_var_fix, /* I [nbr] Number of fixed variables */ var_sct **var_fix, /* I [sct] Array of fixed variables */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_var_typ_trv /* [fnc] Transfer variable type into GTT */ (const int xtr_nbr, /* I [nbr] Number of extracted variables */ var_sct **var, /* I [sct] Array of extracted variables */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ var_sct * /* O [sct] Variable structure */ nco_var_fll_trv /* [fnc] Allocate variable structure and fill with metadata */ (const int nc_id, /* I [id] netCDF file ID */ const int var_id, /* I [id] Variable ID */ const trv_sct * const var_trv, /* I [sct] Object to write (variable) */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ int /* O [id] Output file variable ID */ nco_cpy_var_dfn_trv /* [fnc] Define specified variable in output file */ (const int nc_in_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const char * const grp_out_fll, /* I [sng] Output group name */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ const char * const rec_dmn_nm_cst, /* I [sng] User-specified record dimension, if any, to create or fix in output file */ trv_sct *var_trv, /* I/O [sct] Object to write (variable) */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_dmn_rdr_trv /* [fnc] Transfer dimension structures to be re-ordered (ncpdq) into GTT */ (int **dmn_idx_out_in, /* I [idx] Dimension correspondence, output->input, output of nco_var_dmn_rdr_mtd() */ const int nbr_var_prc, /* I [nbr] Size of above array (number of processed variables) */ var_sct **var_prc_out, /* I [sct] Processed variables */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_var_dmn_rdr_mtd_trv /* [fnc] Determine and set new dimensionality in metadata of each re-ordered variable */ (trv_tbl_sct * const trv_tbl, /* I/O [sct] GTT (Group Traversal Table) */ const int nbr_var_prc, /* I [nbr] Number of processed variables */ var_sct **var_prc, /* I/O [sct] Processed variables */ var_sct **var_prc_out, /* I/O [sct] Processed variables */ const int nbr_var_fix, /* I [nbr] Number of processed variables */ var_sct **var_fix, /* I/O [sct] Fixed variables */ dmn_sct **dmn_rdr, /* I [sct] Dimension structures to be re-ordered */ const int dmn_rdr_nbr, /* I [nbr] Number of dimension to re-order */ const nco_bool *dmn_rvr_rdr); /* I [flg] Reverse dimension */ void nco_var_dmn_rdr_val_trv /* [fnc] Change dimension ordering of variable values */ (const var_sct * const var_in, /* I [ptr] Variable with metadata and data in original order */ var_sct * const var_out, /* I/O [ptr] Variable whose data will be re-ordered */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ nco_bool /* O [flg] Re-define dimension ordering */ nco_rdf_dmn_trv /* [fnc] Re-define dimension ordering */ (trv_sct var_trv, /* I [sct] varible with record dimension name, re-ordered */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ int * idx_var_mrk_out); /* O [nbr] Index in GTT where name was found */ nco_bool /* [flg] Name was found */ nco_var_prc_idx_trv /* [fnc] Find index of processed variable that matches full name */ (const char * const var_nm_fll, /* I [nbr] Full name of variable */ var_sct **var_prc_out, /* I [sct] Processed variables */ const int nbr_var_prc, /* I [nbr] Number of processed variables */ int * var_prc_idx_out); /* O [nbr] Number of dimension to re-order */ void nco_aed_prc_trv /* [fnc] Process single attribute edit for single variable (GTT) */ (const int nc_id, /* I [id] Input netCDF file ID */ const aed_sct *aed, /* I [sct] Structure containing information necessary to edit */ const int nbr_aed, /* I [nbr] Number of attribute structures */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_dmn_trv_msa_tbl /* [fnc] Update all GTT dimensions with hyperslabbed size */ (const int nc_id, /* I [ID] netCDF input file ID */ const char * const rec_dmn_nm, /* I [sng] Record dimension name */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void /* [fnc] Update all GTT dimensions with hyperslabbed size */ nco_dmn_msa_tbl /* [fnc] Define specified variable in output file */ (const int grp_in_id, /* I [id] netCDF input group ID */ const char * const rec_dmn_nm_cst, /* I [sng] User-specified record dimension, if any, to create or fix in output file */ trv_sct *var_trv, /* I/O [sct] Object to write (variable) trv_map_dmn_set() is O */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_dmn_dgn_tbl /* [fnc] Transfer degenerated dimensions information into GTT */ (dmn_sct **dmn_dgn, /* [sct] Degenerate (size 1) dimensions used by ncwa */ const int nbr_dmn_dgn, /* I [nbr] Total number of dimensions in list */ trv_tbl_sct *trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_dmn_lst_ass_var_trv /* [fnc] Create list of all dimensions associated with input variable list (ncpdq only) */ (const int nc_id, /* I [id] netCDF file ID */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ int *nbr_dmn_xtr, /* O [nbr] Number of dimensions associated with variables to be extracted */ dmn_sct ***dim); /* O [sct] Array of dimensions associated with variables to be extracted */ void nco_dmn_avg_mk /* [fnc] Build dimensions to average(ncwa)/re-order(ncpdq) array from input dimension names */ (const int nc_id, /* I [id] netCDF file ID */ char **obj_lst_in, /* I [sng] User-specified list of dimension names (-a names without the - ) */ const int nbr_dmn_in, /* I [nbr] Total number of dimensions in input list (size of above array) */ const nco_bool flg_rdd, /* I [flg] Retain degenerate dimensions */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ dmn_sct ***dmn_avg, /* O [sct] Array of dimensions to average */ int *nbr_dmn_avg); /* O [nbr] Number of dimensions to average (size of above array) */ void nco_dmn_out_mk /* [fnc] Build dimensions array to keep on output */ (dmn_sct **dmn_xtr, /* I [sct] Array of dimensions associated with variables to be extracted */ const int nbr_dmn_xtr, /* I [nbr] Number of dimensions associated with variables to be extracted (size of above array) */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ dmn_sct ***dmn_out, /* O [sct] Array of dimensions on ouput */ int *nbr_dmn_out); /* O [nbr] Number of dimensions on output (size of above array) */ void nco_dmn_id_mk /* [fnc] Mark flag average, optionally flag degenerate for all dimensions that have the input ID */ (const int dmn_id, /* I [nbr] Number of dimensions associated with variables to be extracted (size of above array) */ const nco_bool flg_rdd, /* I [flg] Mark flag retain degenerate dimension */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_bld_rec_dmn /* [fnc] Build record dimensions array */ (const int nc_id, /* I [ID] netCDF input file ID */ const nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ lmt_sct ***lmt_rec, /* I/O [lst] (ncra) Record dimensions */ int *nbr_rec, /* I/O [nbr] (ncra) Number of record dimensions (size of above array) */ trv_tbl_sct * trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_prn_tbl_lmt /* [fnc] Print table limits */ (trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_bld_trv_tbl /* [fnc] Construct GTT, Group Traversal Table (groups,variables,dimensions, limits) */ (const int nc_id, /* I [ID] netCDF file ID */ char * const grp_pth, /* I [sng] Absolute group path where to start build (root typically) */ int lmt_nbr, /* I [nbr] number of dimensions with limits */ CST_X_PTR_CST_PTR_CST_Y(char,lmt_arg), /* I [sng] List of user-specified dimension limits */ const int aux_nbr, /* I [nbr] Number of auxiliary coordinates */ char *aux_arg[], /* I [sng] Auxiliary coordinates */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ char **grp_lst_in, /* I [sng] User-specified list of groups */ const int grp_lst_in_nbr, /* I [nbr] Number of groups in list */ char **var_lst_in, /* I [sng] User-specified list of variables */ const int var_xtr_nbr, /* I [nbr] Number of variables in list */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ const nco_bool flg_unn, /* I [flg] Select union of specified groups and variables */ const nco_bool EXCLUDE_INPUT_LIST, /* I [flg] Exclude rather than extract groups and variables specified with -v */ const nco_bool EXTRACT_ASSOCIATED_COORDINATES, /* I [flg] Extract all coordinates associated with extracted variables? */ nco_dmn_dne_t **flg_dne, /* I/O [lst] Flag to check if input dimension -d "does not exist" */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_bld_lmt /* [fnc] Assign user specified dimension limits to traversal table */ (const int nc_id, /* I [ID] netCDF file ID */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ int lmt_nbr, /* I [nbr] Number of user-specified dimension limits */ lmt_sct **lmt, /* I [sct] Structure comming from nco_lmt_prs() */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_msa_var_get_lmn_trv /* [fnc] Read a used defined limit */ (const int nc_id, /* I [ID] netCDF file ID */ var_sct *var_prc, /* I/O [sct] Variable */ const char * const rec_nm_fll, /* I [sng] Full name of record being done in loop (trv_tbl->lmt_rec[idx_rec]->nm_fll ) */ const long idx_rec_crr_in, /* [idx] Index of current record in current input file */ const trv_tbl_sct * const trv_tbl);/* I [sct] GTT (Group Traversal Table) */ nco_bool /* O [flg] Skip variable */ nco_skp_var /* [fnc] Skip variable while doing record */ (const var_sct * const var_prc, /* I [sct] Processed variable */ const char * const rec_nm_fll, /* I [sng] Full name of record being done in loop (trv_tbl->lmt_rec[idx_rec]->nm_fll ) */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ var_sct * /* O [sct] Variable (weight) */ nco_var_get_wgt_trv /* [fnc] Retrieve weighting or mask variable */ (const int nc_id, /* I [id] netCDF file ID */ const char * const wgt_nm, /* I [sng] Weight variable name (relative) */ const var_sct * const var, /* I [sct] Variable that needs the weight/mask variable */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ dmn_trv_sct * /* O [sct] Table dimension object */ nco_dmn_usr_sng /* [fnc] Parse input string and return table dimension object */ (const char * const usr_sng, /* I [sng] Object name */ const trv_tbl_sct * const trv_tbl, /* I [lst] Traversal table */ nco_bool *is_opt); /* O [flg] Dimension presence is optional (name has '.') */ trv_sct * /* O [sct] Table object */ nco_obj_usr_sng /* [fnc] Parse input string and return table object */ (const char * const usr_sng, /* I [sng] Object name */ const trv_tbl_sct * const trv_tbl, /* I [lst] Traversal table */ nco_bool *is_opt); /* O [flg] Dimension presence is optional (input string has '.') */ void nco_aed_prc_grp /* [fnc] Process attributes in groups */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ void nco_aed_prc_glb /* [fnc] Process attributes in root group */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ void nco_aed_prc_var /* [fnc] Process attributes in variables */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ void nco_aed_prc_var_xtr /* [fnc] Process attributes in variables that match table extraction flag */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ void nco_aed_prc_var_nm /* [fnc] Process attributes in variables that match input name */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl); /* I [lst] Traversal table */ void nco_grp_var_lst /* [fnc] Export list of variable names for group */ (const int nc_id, /* I [id] netCDF file ID */ const char * const grp_nm_fll, /* I [sng] Absolute group name */ char ***nm_lst, /* I/O [sng] List of names */ int *nm_lst_nbr); /* I/O [nbr] Number of items in list */ void nco_bld_nsm /* [fnc] Build ensembles */ (const int nc_id, /* I [id] netCDF file ID */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_nm_skp /* [fnc] Extract list of variable names to skip for template definition */ (const int nc_id, /* I [ID] netCDF file ID */ const char * const grp_nm_fll, /* I [sng] Group full name where all names reside */ const nco_cmn_t *cmn_lst, /* I [sct] List of names (relative) */ const int nbr_cmn_nm, /* I [nbr] Number of names (size of above array) */ nco_cmn_t **skp_lst, /* I/O [sct] List of skip names (full) */ int * nbr_skp_nm, /* I/O [nbr] Number of skip names (size of above array) */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ char * /* O [sng] Name of variable */ nco_var_has_cf /* [fnc] Variable has CF-compliant information ("coordinates" or "bounds") */ (const int nc_id, /* I [ID] netCDF file ID */ const trv_sct * const var_trv, /* I [sct] Variable (object) */ const char * const cf_nm, /* I [sng] CF convention ( "coordinates" or "bounds") */ nco_bool *flg_cf_fnd); /* I/O [flg] CF variable was found */ void nco_chk_dmn /* [fnc] Check valid dimension names */ (const int lmt_nbr, /* I [nbr] number of dimensions with limits */ nco_dmn_dne_t * flg_dne); /* I [lst] Flag to check if input dimension -d "does not exist" */ void nco_chk_dmn_in /* [fnc] Check input dimensions */ (int lmt_nbr, /* I [nbr] Number of user-specified dimension limits */ lmt_sct **lmt, /* I [sct] Structure comming from nco_lmt_prs() */ nco_dmn_dne_t **dne_lst, /* I/O [lst] Flag to check if input dimension -d "does not exist" */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ nco_bool /* O [flg] True if variable 1 is in scope of variable 2 */ nco_var_scp /* [fnc] Is variable 1 is in scope of variable 2 */ (const trv_sct * const var_trv_1, /* I [sct] Variable 1 */ const trv_sct * const var_trv_2, /* I [sct] Variable 2 */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ void nco_dmn_swap /* [fnc] Swap dimensions */ (const char * const dmn_nm_1, /* I [sng] Name of dimension 1 */ const char * const dmn_nm_2, /* I [sng] Name of dimension 2 */ dmn_cmn_sct *dmn_cmn, /* I/O [sct] Dimension structure array */ const int nbr_dmn); /* I [nbr] Number of dimensions (size of above array) */ void nco_dfn_dmn /* [fnc] Define dimension size and ID in array */ (const char * const dmn_nm, /* I [sng] Name of dimension */ const long dmn_sz, /* I [nbr] Size of dimension */ const int dmn_id, /* I [id] ID of dimension */ dmn_cmn_sct *dmn_cmn, /* I/O [sct] Dimension structure array */ const int nbr_dmn); /* I [nbr] Number of dimensions (size of above array) */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_aux_crd_dpt /* [fnc] Compare two aux_crd_sct's by group depth */ (const void *val_1, /* I [sct] aux_crd_sct * to compare */ const void *val_2); /* I [sct] aux_crd_sct * to compare */ void nco_bld_crd_aux /* [fnc] Build auxiliary coordinates information into table */ (const int nc_id, /* I [ID] netCDF file ID */ trv_tbl_sct *trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_lmt_aux_tbl /* [fnc] Apply limits to variable in table */ (const int nc_id, /* I [ID] netCDF file ID */ lmt_sct **lmt, /* I [sct] Limits */ const int nbr_lmt, /* I [nbr] Number of limits */ const char * const var_nm_fll, /* I [sng] Variable full name */ const int dmn_id, /* I [id] ID of dimension to apply the limits */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ int * nco_dmn_malloc /* [fnc] Inquire about number of dimensions in group and return dynamic array of dimension IDs */ (const int nc_id, /* I [ID] netCDF file ID */ const char * const grp_nm_fll, /* I [sng] Group full name */ int *nbr_dmn); /* I/O [nbr] Number of dimensions in group */ void nco_lmt_std_att_lat_lon /* [fnc] Apply limits to variable in table that contains 'standard_name' attribute "latitude" */ (const int nc_id, /* I [ID] netCDF file ID */ lmt_sct **lmt, /* I [sct] Limits */ const int nbr_nbr, /* I [nbr] Number of limits */ const int dmn_id, /* I [id] ID of dimension to apply the limits */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_lmt_aux /* [fnc] Apply auxiliary -X limits (Auxiliary function called by different functions ) */ (const int nc_id, /* I [ID] netCDF file ID */ lmt_sct **lmt, /* I [sct] Limits */ const int nbr_nbr, /* I [nbr] Number of limits */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ const int idx_tbl, /* I [nbr] Table index */ const int idx_dmn, /* I [nbr] Dimension index */ trv_tbl_sct * const trv_tbl); /* I/O [sct] GTT (Group Traversal Table) */ void nco_prn_var /* [fnc] Print variable (debug only) */ (const int nc_id, /* I [ID] netCDF file ID (Input or output file) */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_dmn_lmt /* [fnc] Convert a lmt_sct array to dmn_sct (name only) */ (lmt_sct **lmt, /* I [lst] lmt_sct array */ const int nbr_lmt, /* I [nbr] Size of lmt_sct array */ dmn_sct ***dmn); /* O [sct] dmn_sct array */ void nco_nsm_dfn_wrt /* [fnc] Define OR write ensemble fixed variables */ (const int nc_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ const nco_bool flg_def, /* [fnc] Define OR write */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_nsm_ncr /* [fnc] Increase ensembles (more than 1 file cases) */ (const int nc_id, /* I [id] netCDF file ID */ trv_tbl_sct * const trv_tbl); /* I/O [sct] Traversal table */ void nco_prn_nsm /* [fnc] Print ensembles */ (const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_GRP_UTL_H */ ./nco-4.4.2/src/nco/libnco.h0000644000674300045400000000511512260451231014740 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/libnco.h,v 1.59 2013/12/31 05:14:01 zender Exp $ */ /* Purpose: netCDF Operator (NCO) library */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Most libnco.h headers depend on netcdf.h and nco_netcdf.h headers */ /* Usage: #include "libnco.h" *//* netCDF Operator (NCO) library */ #ifndef LIBNCO_H /* Contents have not yet been inserted in current source file */ #define LIBNCO_H /* Core headers */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ #include "nco.h" /* netCDF Operator (NCO) definitions */ /* Library headers */ #include "nco_att_utl.h" /* Attribute utilities */ #include "nco_aux.h" /* Auxiliary coordinates */ #include "nco_bnr.h" /* Binary write utilities */ #include "nco_cln_utl.h" /* Calendar utilities */ #include "nco_cnf_dmn.h" /* Conform dimensions */ #include "nco_cnf_typ.h" /* Conform variable types */ #include "nco_cnk.h" /* Chunking */ #include "nco_cnv_arm.h" /* ARM conventions */ #include "nco_cnv_csm.h" /* CCM/CCSM/CF conventions */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_dbg.h" /* Debugging */ #include "nco_dmn_utl.h" /* Dimension utilities */ #include "nco_fl_utl.h" /* File manipulation */ #include "nco_grp_trv.h" /* Group traversal */ #include "nco_grp_utl.h" /* Group utilities */ #include "nco_lmt.h" /* Hyperslab limits */ #include "nco_lst_utl.h" /* List utilities */ #include "nco_md5.h" /* MD5 digests */ #include "nco_mmr.h" /* Memory management */ #include "nco_msa.h" /* Multi-slabbing algorithm */ #include "nco_mss_val.h" /* Missing value utilities */ #include "nco_omp.h" /* OpenMP utilities */ #include "nco_pck.h" /* Packing and unpacking variables */ #include "nco_prn.h" /* Print variables, attributes, metadata */ #include "nco_rec_var.h" /* Record variable utilities */ #include "nco_rth_flt.h" /* Float-precision arithmetic, MSVC macros */ #include "nco_rth_utl.h" /* Arithmetic controls and utilities */ #include "nco_scl_utl.h" /* Scalar utilities */ #include "nco_scm.h" /* Software configuration management */ #include "nco_sng_utl.h" /* String utilities */ #include "nco_srm.h" /* Streams */ #include "nco_var_avg.h" /* Average variables */ #include "nco_uthash.h" /* Hash table functionality */ #include "nco_var_lst.h" /* Variable list utilities */ #include "nco_var_rth.h" /* Variable arithmetic */ #include "nco_var_scv.h" /* Arithmetic between variables and scalar values */ #include "nco_var_utl.h" /* Variable utilities */ #endif /* LIBNCO_H */ ./nco-4.4.2/src/nco/ncbo.c0000644000674300045400000010123512277324010014410 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncbo.c,v 1.287 2014/02/14 05:22:16 zender Exp $ */ /* ncbo -- netCDF binary operator */ /* Purpose: Compute sum, difference, product, or ratio of specified hyperslabs of specfied variables from two input netCDF files and output them to a single file. */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncbo -O -p ~/nco/data in.nc in.nc ~/foo.nc ncbo -O -v mss_val -p ~/nco/data in.nc in.nc ~/foo.nc ncbo -p /data/zender/tmp h0001.nc ~/foo.nc ncbo -p /data/zender/tmp -l /data/zender/tmp/rmt h0001.nc h0002.nc ~/foo.nc ncbo -p /ZENDER/tmp -l /data/zender/tmp/rmt h0001.nc h0002.nc ~/foo.nc ncbo -p /ZENDER/tmp -l /usr/tmp/zender h0001.nc h0002.nc ~/foo.nc Test type conversion: ncks -O -C -v float_var in.nc foo1.nc ncrename -v float_var,double_var foo1.nc ncks -O -C -v double_var in.nc foo2.nc ncbo -O -C -v double_var foo1.nc foo2.nc foo3.nc ncbo -O -C -v double_var foo2.nc foo1.nc foo4.nc ncks -H -m foo1.nc ncks -H -m foo2.nc ncks -H -m foo3.nc ncks -H -m foo4.nc Test nco_var_cnf_dmn(): ncks -O -v scalar_var in.nc ~/foo.nc ; ncrename -v scalar_var,four_dmn_rec_var foo.nc ; ncbo -O -v four_dmn_rec_var in.nc ~/foo.nc foo2.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #ifdef ENABLE_MPI # include /* MPI definitions */ # include "nco_mpi.h" /* MPI utilities */ #endif /* !ENABLE_MPI */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FILE_1_RETRIEVED_FROM_REMOTE_LOCATION=False; nco_bool FILE_2_RETRIEVED_FROM_REMOTE_LOCATION=False; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool GRP_VAR_UNN=False; /* [flg] Select union of specified groups and variables */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order*/ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=True; /* [flg] Clean memory prior to exit */ nco_bool flg_ddra=False; /* [flg] DDRA diagnostics */ char **fl_lst_abb=NULL; /* Option a */ char **fl_lst_in; char **var_lst_in=NULL_CEWI; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in_1=NULL; /* fl_in_1 is nco_realloc'd when not NULL */ char *fl_in_2=NULL; /* fl_in_2 is nco_realloc'd when not NULL */ char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *nco_op_typ_sng=NULL; /* [sng] Operation type */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char **grp_lst_in=NULL; /* [sng] User-specified list of groups */ char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncbo.c,v 1.287 2014/02/14 05:22:16 zender Exp $"; const char * const CVS_Revision="$Revision: 1.287 $"; const char * const opt_sht_lst="3467ACcD:d:FG:g:hL:l:Oo:p:rRt:v:X:xzy:-:"; cnk_sct cnk; /* [sct] Chunking structure */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.MRV_flg=False,.flg_ddra=False,.lmn_nbr=0LL,.lmn_nbr_avg=0LL,.lmn_nbr_wgt=0LL,.nco_op_typ=nco_op_nil,.rnk_avg=0,.rnk_var=0,.rnk_wgt=0,.tmr_flg=nco_tmr_srt,.var_idx=0,.wgt_brd_flg=False,.wrd_sz=0}; #endif /* !__cplusplus */ extern char *optarg; extern int optind; gpe_sct *gpe=NULL; /* [sng] Group Path Editing (GPE) structure */ int *in_id_1_arr; int *in_id_2_arr; int abb_arg_nbr=0; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_idx; int fl_nbr=0; int fl_in_fmt_1; /* [enm] Input file format */ int fl_in_fmt_2; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx; int in_id_1; int in_id_2; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_glb_att_1; /* [nbr] Number of global attributes in file */ int nbr_glb_att_2; /* [nbr] Number of global attributes in file */ int nbr_grp_att_1; /* [nbr] Number of group attributes in file */ int nbr_grp_att_2; /* [nbr] Number of group attributes in file */ int nbr_att_var_1; /* [nbr] Number of variable attributes in file */ int nbr_att_var_2; /* [nbr] Number of variable attributes in file */ int nbr_dmn_fl_1; /* [nbr] Number of dimensions in file */ int nbr_dmn_fl_2; /* [nbr] Number of dimensions in file */ int nbr_rec_fl_1; /* [nbr] Number of record dimensions in file */ int nbr_rec_fl_2; /* [nbr] Number of record dimensions in file */ int grp_dpt_fl_1; /* [nbr] Maximum group depth (root = 0) */ int grp_dpt_fl_2; /* [nbr] Maximum group depth (root = 0) */ int grp_lst_in_nbr=0; /* [nbr] Number of groups explicitly specified by user */ int nbr_grp_fl_1; /* [nbr] Number of groups in file */ int nbr_grp_fl_2; /* [nbr] Number of groups in file */ int var_ntm_fl_1; /* [nbr] Number of non-atomic variables in file */ int var_ntm_fl_2; /* [nbr] Number of non-atomic variables in file */ int nbr_var_fl_1; /* [nbr] Number of atomic-type variables in file */ int nbr_var_fl_2; /* [nbr] Number of atomic-type variables in file */ int nbr_gpe_nm; /* [nbr] Number of GPE entries */ int nbr_cmn_nm; /* [nbr] Number of common entries */ int nco_op_typ=nco_op_nil; /* [enm] Operation type */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ trv_tbl_sct *trv_tbl_1=NULL; /* [lst] Traversal table input file 1 */ trv_tbl_sct *trv_tbl_2=NULL; /* [lst] Traversal table input file 2 */ gpe_nm_sct *gpe_nm=NULL; /* [sct] GPE name duplicate check array */ nco_cmn_t *cmn_lst=NULL; /* [sct] A list of common names */ nco_dmn_dne_t *flg_dne1=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ nco_dmn_dne_t *flg_dne2=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"ddra",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"mdl_cmp",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"hdf_upk",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"hdf_unpack",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"msa_usr_rdr",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"msa_user_order",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"intersection",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"nsx",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"union",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"unn",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"gpe",required_argument,0,'G'}, /* [sng] Group Path Edit (GPE) */ {"grp",required_argument,0,'g'}, {"group",required_argument,0,'g'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"operation",required_argument,0,'y'}, {"op_typ",required_argument,0,'y'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ nbr_gpe_nm=0; /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk_dmn */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"ddra") || !strcmp(opt_crr,"mdl_cmp")) ddra_info.flg_ddra=flg_ddra=True; /* [flg] DDRA diagnostics */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdf_upk") || !strcmp(opt_crr,"hdf_unpack")) nco_upk_cnv=nco_upk_HDF; /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"msa_usr_rdr") || !strcmp(opt_crr,"msa_user_order")) MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"unn") || !strcmp(opt_crr,"union")) GRP_VAR_UNN=True; if(!strcmp(opt_crr,"nsx") || !strcmp(opt_crr,"intersection")) GRP_VAR_UNN=False; if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* The debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'G': /* Apply Group Path Editing (GPE) to output group */ gpe=nco_gpe_prs_arg(optarg); fl_out_fmt=NC_FORMAT_NETCDF4; break; case 'g': /* Copy group argument for later processing */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); grp_lst_in=nco_lst_prs_2D(optarg_lcl,",",&grp_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'y': /* User-specified operation type overrides invocation default */ nco_op_typ_sng=(char *)strdup(optarg); nco_op_typ=nco_op_typ_get(nco_op_typ_sng); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Initialize traversal tables */ (void)trv_tbl_init(&trv_tbl_1); (void)trv_tbl_init(&trv_tbl_2); /* Default operation depends on invocation name */ if(nco_op_typ_sng == NULL) nco_op_typ=nco_op_typ_get(nco_op_typ_sng); /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_1_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); in_id_2_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filenames */ fl_idx=0; /* Input file _1 */ fl_in_1=nco_fl_nm_prs(fl_in_1,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in_1); /* Make sure file is on local system and is readable or die trying */ fl_in_1=nco_fl_mk_lcl(fl_in_1,fl_pth_lcl,&FILE_1_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl && FILE_1_RETRIEVED_FROM_REMOTE_LOCATION) (void)fprintf(stderr,", local file is %s",fl_in_1); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in_2); /* Make sure file is on local system and is readable or die trying */ fl_in_2=nco_fl_mk_lcl(fl_in_2,fl_pth_lcl,&FILE_2_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl && FILE_2_RETRIEVED_FROM_REMOTE_LOCATION) (void)fprintf(stderr,", local file is %s",fl_in_2); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Group Path Edit (GPE) feature enabled\n",nco_prg_nm_get()); if(fl_out_fmt != NC_FORMAT_NETCDF4) (void)fprintf(stderr,"%s: WARNING Group Path Edit (GPE) requires netCDF4 output format in most cases (except flattening) but user explicitly requested output format = %s. This command will fail if the output file requires netCDF4 features like groups or netCDF4 atomic types (e.g., NC_STRING, NC_UBYTE...).\n",nco_prg_nm_get(),nco_fmt_sng(fl_out_fmt)); } /* !gpe */ /* Match 2 tables (find common objects) and export common objects */ (void)trv_tbl_mch(trv_tbl_1,trv_tbl_2,&cmn_lst,&nbr_cmn_nm); /* Is this a CCM/CCSM/CF-format history tape? */ CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id_1); /* Process common objects (DEFINE mode, True as flg_dfn parameter) */ (void)nco_prc_cmn_nm(in_id_1,in_id_2,out_id,&cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_tbl_1,trv_tbl_2,cmn_lst,nbr_cmn_nm,(nco_bool)True); /* Copy global attributes from file 1 */ (void)nco_att_cpy(in_id_1,out_id,NC_GLOBAL,NC_GLOBAL,(nco_bool)True); /* Catenate timestamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); if(HISTORY_APPEND) (void)nco_vrs_att_cat(out_id); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Process common objects (WRITE mode, False as flg_dfn parameter) */ (void)nco_prc_cmn_nm(in_id_1,in_id_2,out_id,&cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_tbl_1,trv_tbl_2,cmn_lst,nbr_cmn_nm,(nco_bool)False); /* Close input netCDF files */ for(thr_idx=0;thr_idx 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) cnk.cnk_dmn=(cnk_dmn_sct **)nco_cnk_lst_free(cnk.cnk_dmn,cnk_nbr); trv_tbl_free(trv_tbl_1); trv_tbl_free(trv_tbl_2); if(gpe) gpe=(gpe_sct *)nco_gpe_free(gpe); /* Memory management for GPE names */ for(idx=0;idx 0) cmn_lst=(nco_cmn_t *)nco_free(cmn_lst); for(idx=0;idx /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, qsort */ #include /* need LONG_MAX */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_bnr.h" /* Binary write utilities */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_grp_utl.h" /* Group utilities */ #include "nco_lmt.h" /* Hyperslab limits */ #include "nco_mmr.h" /* Memory management */ #include "nco_prn.h" /* Print variables, attributes, metadata */ #include "nco_sng_utl.h" /* String utilities */ #include "nco_var_utl.h" /* Variable utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ nco_bool /* if false then we are at the end of the slab */ nco_msa_clc_idx (nco_bool NORMALIZE, /* Return indices of slab within the slab */ lmt_msa_sct *lmt_a, /* I list of lmts for each dimension */ long *indices, /* I/O so routine can keep track of where its at */ lmt_sct* lmt_out, /* O output hyperslab */ int *slb); /* slab which the above limit refers to */ void nco_msa_prn_idx /* [fnc] Print multiple hyperslab indices */ (lmt_msa_sct * lmt_lst); void nco_msa_clc_cnt /* [fnc] Calculate size of multiple hyperslab */ (lmt_msa_sct *lmt_lst); void nco_msa_wrp_splt /* [fnc] Split wrapped dimensions */ (lmt_msa_sct *lmt_lst); nco_bool /* O return true if limits overlap */ nco_msa_ovl /* [fnc] see if limits overlap */ (lmt_msa_sct *lmt_lst); int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_lmt_srt /* [fnc] Sort comparison operator */ (const void *vp1, const void* vp2); void nco_msa_qsort_srt /* [fnc] sort limits by srt values */ (lmt_msa_sct *lmt_lst); void nco_msa_lmt_all_ntl /* [fnc] Initilaize lmt_msa_sct's */ (int in_id, nco_bool MSA_USR_RDR, lmt_msa_sct **lmt_all_lst, int nbr_dmn_fl, lmt_sct** lmt, int lmt_nbr); void * /* O pointer to malloced slab */ nco_msa_rcr_clc /* Multi slab algorithm (recursive routine) */ (int i, /* current depth, we start at 0 */ int imax, /* maximium depth (i.e the number of dims in variable (does not change)*/ lmt_sct **lmt, /* limits of the current hyperslab these change as we recurse */ lmt_msa_sct **lmt_lst, /* list of limits in each dimension (this remains STATIC as we recurse */ var_sct *var1); /* Infor for routine to read var (should not change */ long /* O [idx] Minimum value */ nco_msa_min_idx /* [fnc] Find minimum values in current and return minimum value */ (const long * const current, /* I [idx] Current indices */ nco_bool * const mnm, /* O [flg] Minimum */ const int size); /* I [nbr] Size of current and min */ void nco_msa_ram_2_dsk /* [fnc] Convert hyperlsab indices into indices relative to disk */ (long *dmn_sbs_ram, /* Input indices */ lmt_msa_sct** lmt_msa, /* input hyperlab limits */ int nbr_dmn, /* number of dimensions */ long *dmn_sbs_dsk, /* Output - indices relative to disk */ nco_bool flg_free); /* Free static space on last call */ void nco_msa_var_get /* [fnc] Get var data from disk taking accound of multihyperslabs */ (const int in_id, /* I [id] netCDF input file ID */ var_sct *var_in, lmt_msa_sct * const * lmt_lst, /* I multi-hyperslab limits */ int nbr_dmn_fl); /* I [nbr] Number of multi-hyperslab limits */ void nco_msa_var_val_cpy /* [fnc] Copy variables data from input to output file */ (const int in_id, /* I [enm] netCDF file ID */ const int out_id, /* I [enm] netCDF output file ID */ var_sct ** const var, /* I/O [sct] Variables to copy to output file */ const int nbr_var, /* I [nbr] Number of variables */ lmt_msa_sct * const * lmt_lst, /* I multi-hyperslab limits */ int nbr_dmn_fl); /* I [nbr] Number of multi-hyperslab limits */ void nco_msa_wrp_splt_trv /* [fnc] Split wrapped dimensions (traversal table version) */ (dmn_trv_sct *dmn_trv); /* [sct] Dimension structure from traversal table */ void nco_msa_clc_cnt_trv /* [fnc] Calculate size of multiple hyperslab (traversal table version) */ (dmn_trv_sct *dmn_trv); /* [sct] Dimension structure from traversal table */ nco_bool /* O [flg] return true if limits overlap (traversal table version) */ nco_msa_ovl_trv /* [fnc] See if limits overlap */ (dmn_trv_sct *dmn_trv); /* [sct] Dimension structure from traversal table */ void nco_msa_qsort_srt_trv /* [fnc] Sort limits by srt values (traversal table version) */ (dmn_trv_sct *dmn_trv); /* [sct] Dimension structure from traversal table */ void nco_msa_wrp_splt_cpy /* [fnc] Split wrapped dimensions (make deep copy of new wrapped limits) */ (lmt_msa_sct *lmt_lst); /* [sct] MSA */ void nco_cpy_var_val_mlt_lmt_trv /* [fnc] Copy variable data from input to output file */ (const int in_id, /* I [id] netCDF input file ID */ const int out_id, /* I [id] netCDF output file ID */ FILE * const fp_bnr, /* I [flg] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ const trv_sct * const var_trv); /* I [sct] Object to write (variable) */ void nco_cpy_msa_lmt /* [fnc] Copy MSA struct from table to local function (print or write) */ (const trv_sct * const var_trv, /* I [sct] Object to write (variable) */ lmt_msa_sct ***lmt_msa); /* O [sct] MSA array for dimensions */ void nco_msa_var_get_trv /* [fnc] Get variable data from disk taking account of multihyperslabs */ (const int nc_id, /* I [ID] netCDF file ID */ var_sct *var_in, /* I/O [sct] Variable */ const trv_tbl_sct * const trv_tbl);/* I [sct] GTT (Group Traversal Table) */ void nco_lmt_msa_free /* [fnc] Free MSA */ (const int nbr_dmn, /* I [nbr] Number of dimensions */ lmt_msa_sct **lmt_msa); /* I [sct] MSA */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_MSA_H */ ./nco-4.4.2/src/nco/nco_var_scv.h0000644000674300045400000001173012260451232015775 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_var_scv.h,v 1.28 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Arithmetic between variables and scalar values */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_var_scv.h" *//* Arithmetic between variables and scalar values */ #ifndef NCO_VAR_SCV_H #define NCO_VAR_SCV_H /* Standard header files */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_cnf_typ.h" /* Conform variable types */ #include "nco_rth_flt.h" /* Float-precision arithmetic, MSVC macros */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void var_scv_add /* [fnc] Add scalar to variable */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz,/* I [nbr] Size (in elements) of array operand */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [val] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ void var_scv_mlt /* [fnc] Multiply variable by scalar */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operand */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [val] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ void var_scv_mod /* [fnc] Modulo variable by scalar */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [val] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ void scv_var_mod /* [fnc] Modulo scalar by variable */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [val] Value of missing value */ scv_sct *scv, /* I [val] Pointer to scalar value (first operand) */ ptr_unn op2); /* I/O [val] Values of second operand */ void var_scv_dvd /* [fnc] Divide variable by scalar */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [flg] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ void scv_var_dvd /* [fnc] Divide scalar by variable */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [flg] Value of missing value */ scv_sct *scv, /* I [val] Pointer to scalar value (first operand) */ ptr_unn op2); /* I/O [val] Values of second operand */ void var_scv_pwr /* [fnc] Empower variable by scalar */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [flg] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ void scv_var_pwr /* [fnc] Empower scalar by variable */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operands */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [flg] Value of missing value */ scv_sct *scv, /* I [val] Pointer to scalar value (first operand) */ ptr_unn op2); /* I/O [val] Values of second operand */ void var_scv_sub /* [fnc] Subtract scalar from variable */ (const nc_type type, /* I [enm] netCDF type of operands */ const long sz, /* I [nbr] Size (in elements) of array operand */ const int has_mss_val, /* I [flg] Flag for missing values */ ptr_unn mss_val, /* I [val] Value of missing value */ ptr_unn op1, /* I/O [val] Values of first operand */ scv_sct *scv); /* I [val] Pointer to scalar value (second operand) */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_VAR_SCV_H */ ./nco-4.4.2/src/nco/Makefile.am0000644000674300045400000001054312246756364015401 0ustar zendercgdcsm# $Header: /cvsroot/nco/nco/src/nco/Makefile.am,v 1.54 2013/12/02 01:05:56 zender Exp $ -*-makefile-*- if BUILD_YACC_SOURCE NCAP=ncap else NCAP= endif if BUILD_YACC_SOURCE NCWA=ncwa else NCWA= endif if NCO_NEED_GETOPT_LONG NCO_GETOPT_C=nco_getopt.c NCO_GETOPT_H=nco_getopt.h else NCO_GETOPT_C= NCO_GETOPT_H= endif if ENABLE_MPI bin_PROGRAMS = ${NCAP} ncatted ncbo ncecat ncflint ncks ncpdq ncra ncrename mpncbo mpncecat mpncflint mpncpdq mpncra mpncwa ${NCWA} else bin_PROGRAMS = ${NCAP} ncatted ncbo ncecat ncflint ncks ncpdq ncra ncrename ${NCWA} endif AM_YFLAGS = -d --name-prefix=nco_yy ncap_SOURCES = ncap_utl.c ncap.c ncap_yacc.y ncap_lex.l ncap_LDADD = libnco.la ncatted_SOURCES = ncatted.c ncatted_LDADD = libnco.la ncbo_SOURCES = ncbo.c ncbo_LDADD = libnco.la ncecat_SOURCES = ncecat.c ncecat_LDADD = libnco.la ncflint_SOURCES = ncflint.c ncflint_LDADD = libnco.la ncks_SOURCES = ncks.c ncks_LDADD = libnco.la ncpdq_SOURCES = ncpdq.c ncpdq_LDADD = libnco.la ncra_SOURCES = ncra.c ncra_LDADD = libnco.la ncrename_SOURCES = ncrename.c ncrename_LDADD = libnco.la mpncbo_SOURCES = mpncbo.c mpncbo_LDADD = libnco.la mpncecat_SOURCES = mpncecat.c mpncecat_LDADD = libnco.la mpncflint_SOURCES = mpncflint.c mpncflint_LDADD = libnco.la mpncpdq_SOURCES = mpncpdq.c mpncpdq_LDADD = libnco.la mpncra_SOURCES = mpncra.c mpncra_LDADD = libnco.la # ncwa also requires ncap_yacc.y which should already have been built for ncap ncwa_SOURCES = ncwa.c ncap_utl.c ncap_lex.l ncap_yacc.c ncwa_LDADD = libnco.la mpncwa_SOURCES = mpncwa.c ncap_utl.c ncap_lex.l ncap_yacc.c mpncwa_LDADD = libnco.la HEADER_SRC = \ libnco.h \ ${NCO_GETOPT_H} \ ncap.h \ ncap_yacc.h \ nco.h \ nco_att_utl.h \ nco_aux.h \ nco_bnr.h \ nco_cln_utl.h \ nco_cnf_dmn.h \ nco_cnf_typ.h \ nco_cnk.h \ nco_cnv_arm.h \ nco_cnv_csm.h \ nco_ctl.h \ nco_dbg.h \ nco_dmn_utl.h \ nco_fl_utl.h \ nco_grp_utl.h \ nco_grp_trv.h \ nco_lmt.h \ nco_lst_utl.h \ nco_md5.h \ nco_mmr.h \ nco_mpi.h \ nco_msa.h \ nco_mss_val.h \ nco_netcdf.h \ nco_omp.h \ nco_pck.h \ nco_prn.h \ nco_rec_var.h \ nco_rth_flt.h \ nco_rth_utl.h \ nco_scl_utl.h \ nco_scm.h \ nco_sng_utl.h \ nco_srm.h \ nco_typ.h \ nco_uthash.h \ nco_var_avg.h \ nco_var_lst.h \ nco_var_rth.h \ nco_var_scv.h \ nco_var_utl.h lib_LTLIBRARIES = libnco.la # This creates version-stamped shared-library, e.g., libnco-2.9.4.so libnco_la_LDFLAGS = -release @VERSION@ # Fedora Core nco.spec in nco-3.1.2 wants to install headers # Fedora Core nco.spec in nco-3.9.7 still wants to install headers # Maybe smart/required for -devel packages? # To my knowledge, though, only NCO programs use libnco # For this reason Debian packages should not (yet) install NCO headers # Remove following line until learn how to prevent Debian from installing headers #include_HEADERS = $(HEADER_SRC) libnco_la_SOURCES = \ ${HEADER_SRC} \ ${NCO_GETOPT_C} \ nco_att_utl.c \ nco_aux.c \ nco_bnr.c \ nco_cln_utl.c \ nco_cnf_dmn.c \ nco_cnf_typ.c \ nco_cnk.c \ nco_cnv_arm.c \ nco_cnv_csm.c \ nco_ctl.c \ nco_dbg.c \ nco_dmn_utl.c \ nco_fl_utl.c \ nco_grp_utl.c \ nco_grp_trv.c \ nco_lmt.c \ nco_lst_utl.c \ nco_md5.c \ nco_mmr.c \ nco_msa.c \ nco_mss_val.c \ nco_netcdf.c \ nco_omp.c \ nco_pck.c \ nco_prn.c \ nco_rec_var.c \ nco_rth_flt.c \ nco_rth_utl.c \ nco_scl_utl.c \ nco_scm.c \ nco_sng_utl.c \ nco_srm.c \ nco_var_avg.c \ nco_var_lst.c \ nco_var_rth.c \ nco_var_scv.c \ nco_var_utl.c TESTS = ${DAP_TESTS} EXTRA_DIST = ${NCO_GETOPT_C} DISTCLEANFILES = ncap_lex.c ncap_yacc.c ncap_yacc.h install-exec-hook: cd $(DESTDIR)$(bindir) && ln -s -f ncbo ncdiff || (rm -f ncdiff && ln -s -f ncbo ncdiff) cd $(DESTDIR)$(bindir) && ln -s -f ncra ncea || (rm -f ncea && ln -s -f ncra ncea) cd $(DESTDIR)$(bindir) && ln -s -f ncra nces || (rm -f nces && ln -s -f ncra nces) cd $(DESTDIR)$(bindir) && ln -s -f ncra ncrcat || (rm -f ncrcat && ln -s -f ncra ncrcat) if ENABLE_MPI cd $(DESTDIR)$(bindir) && ln -s -f mpncbo mpncdiff || (rm -f mpncdiff && ln -s -f mpncbo mpncdiff) cd $(DESTDIR)$(bindir) && ln -s -f mpncra mpncea || (rm -f mpncea && ln -s -f mpncra mpncea) cd $(DESTDIR)$(bindir) && ln -s -f mpncra mpnces || (rm -f mpnces && ln -s -f mpncra mpnces) cd $(DESTDIR)$(bindir) && ln -s -f mpncra mpncrcat || (rm -f mpncrcat && ln -s -f mpncra mpncrcat) endif uninstall-hook: cd $(DESTDIR)$(bindir) && rm -f ncdiff ncea nces ncrcat mpncdiff mpncea mpnces mpncrcat CLEANFILES=ncdiff ncea nces ncrcat mpncdiff mpncea mpnces mpncrcat ./nco-4.4.2/src/nco/nco_rec_var.c0000644000674300045400000001271012260451232015745 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_rec_var.c,v 1.29 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Record variable utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_rec_var.h" /* Record variable utilities */ void rec_var_dbg /* [fnc] Aid in debugging problems with record dimension */ (const int nc_id, /* I [id] netCDF file ID */ const char * const dbg_sng) /* I [sng] Debugging message to print */ { /* Purpose: Aid in debugging problems with record dimension */ /* Usage: if(nco_dbg_lvl == 73) rec_var_dbg(out_id,"After ncvarput()"); */ int nbr_dmn_fl; int nbr_var_fl; int rec_dmn_id=NCO_REC_DMN_UNDEFINED; long dmn_sz; (void)fprintf(stderr,"%s: DBG %s\n",nco_prg_nm_get(),dbg_sng); (void)nco_inq(nc_id,&nbr_dmn_fl,&nbr_var_fl,(int *)NULL,&rec_dmn_id); if(rec_dmn_id == NCO_REC_DMN_UNDEFINED){ (void)fprintf(stderr,"%s: DBG %d dimensions, %d variables, no record dimension\n",nco_prg_nm_get(),nbr_dmn_fl,nbr_var_fl); }else{ (void)nco_inq_dimlen(nc_id,rec_dmn_id,&dmn_sz); (void)fprintf(stderr,"%s: DBG %d dimensions, %d variables, record dimension size is %li\n",nco_prg_nm_get(),nbr_dmn_fl,nbr_var_fl,dmn_sz); } /* end else */ (void)fflush(stderr); } /* end rec_var_dbg() */ void rec_crd_chk /* Check for monotonicity of coordinate values */ (const var_sct * const var, /* I [sct] Coordinate to check for monotonicity */ const char * const fl_in, /* I [sng] Input filename */ const char * const fl_out, /* I [sng] Output filename */ const long idx_rec, /* I [idx] Index of record coordinate in input file */ const long idx_rec_out) /* I [idx] Index of record coordinate in output file */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Check for monotonicity of coordinate values */ static char *rec_crd_nm=NULL; static double rec_crd_val_crr; static double rec_crd_val_lst; static monotonic_direction_enm monotonic_direction; /* 20130424: First record coordinate variable received will be tested for monotonicity Subsequent record coordinate variables will be ignored Fixes problem caused by associated record coordinates like time_bnds Will be necessary to generalize this for netCDF4 files with multiple record coordinates */ if(idx_rec_out == 0L && !rec_crd_nm) rec_crd_nm=(char *)strdup(var->nm); if(rec_crd_nm) if(strcmp(rec_crd_nm,var->nm)) return; /* Use implicit type conversion */ switch(var->type){ case NC_FLOAT: rec_crd_val_crr=var->val.fp[0]; break; case NC_DOUBLE: rec_crd_val_crr=var->val.dp[0]; break; case NC_INT: rec_crd_val_crr=var->val.ip[0]; break; case NC_SHORT: rec_crd_val_crr=var->val.sp[0]; break; case NC_USHORT: rec_crd_val_crr=var->val.usp[0]; break; case NC_UINT: rec_crd_val_crr=var->val.uip[0]; break; case NC_INT64: rec_crd_val_crr=var->val.i64p[0]; break; case NC_UINT64: rec_crd_val_crr=var->val.ui64p[0]; break; case NC_BYTE: rec_crd_val_crr=var->val.bp[0]; break; case NC_UBYTE: rec_crd_val_crr=var->val.ubp[0]; break; case NC_CHAR: rec_crd_val_crr=var->val.cp[0]; break; case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(idx_rec_out > 1L){ if(((rec_crd_val_crr > rec_crd_val_lst) && monotonic_direction == decreasing) || ((rec_crd_val_crr < rec_crd_val_lst) && monotonic_direction == increasing)){ if(idx_rec-1 == -1){ /* Inter-file non-monotonicity */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO/WARNING Inter-file non-monotonicity. Record coordinate \"%s\" does not monotonically %s between last specified record of previous input file (whose name is not cached locally and thus currently unavailable for printing) and first specified record (i.e., record index = %ld) of current input file (%s). This message is often informational only and may usually be safely ignored. It is quite common when joining files with \"wrapped\" record coordinates, e.g., joining a January file to a December file when the time coordinate is enumerated as day of year. It is also common when joining files which employ a \"time=base_time+time_offset\" convention. Sometimes, however, this message is a warning which signals that the user has joined files together in a different order than intended and that corrective action should be taken to re-order the input files. Output file %s will contain these non-monotonic record coordinate values (%f, %f) at record indices %ld, %ld.\n",nco_prg_nm_get(),var->nm,(monotonic_direction == decreasing ? "decrease" : "increase"),idx_rec,fl_in,fl_out,rec_crd_val_lst,rec_crd_val_crr,idx_rec_out-1L,idx_rec_out); }else{ /* Intra-file non-monotonicity */ (void)fprintf(stderr,"%s: WARNING Intra-file non-monotonicity. Record coordinate \"%s\" does not monotonically %s between (input file %s record indices: %ld, %ld) (output file %s record indices %ld, %ld) record coordinate values %f, %f\n",nco_prg_nm_get(),var->nm,(monotonic_direction == decreasing ? "decrease" : "increase"),fl_in,idx_rec-1L,idx_rec,fl_out,idx_rec_out-1,idx_rec_out,rec_crd_val_lst,rec_crd_val_crr); } /* end if Intra-file non-monotonicity */ } /* end if not monotonic */ }else if(idx_rec_out == 1L){ if(rec_crd_val_crr > rec_crd_val_lst) monotonic_direction=increasing; else monotonic_direction=decreasing; } /* end if */ rec_crd_val_lst=rec_crd_val_crr; } /* end rec_crd_chk() */ ./nco-4.4.2/src/nco/nco.h0000644000674300045400000014473312300577754014301 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco.h,v 1.489 2014/02/18 06:38:36 pvicente Exp $ */ /* Purpose: netCDF Operator (NCO) definitions */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco.h" *//* netCDF Operator (NCO) definitions */ #ifndef NCO_H /* Contents have not yet been inserted in current source file */ #define NCO_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* Personal headers */ #include "nco_typ.h" /* Type definitions, opaque types */ #include "nco_uthash.h" /* Hash table functionality */ /* C pre-processor macros for instantiating variable values with string tokens Macros for token pasting described at http://www.parashift.com/c++-faq-lite Layer of indirection is required, use public macro to call private macro */ #define TKN2SNG_PRV(x) #x #define TKN2SNG(x) TKN2SNG_PRV(x) /* Encapsulate C++ const usage in C99-safe macro C++ compilers will use type-safe version C89 and C99 compilers use less type-safe version that is standards-compliant */ #ifdef __cplusplus # define CST_X_PTR_CST_PTR_CST_Y(x,y) const x * const * const y # define X_CST_PTR_CST_PTR_Y(x,y) x const * const * y #else /* !__cplusplus */ # define CST_X_PTR_CST_PTR_CST_Y(x,y) x * const * const y # define X_CST_PTR_CST_PTR_Y(x,y) x * const * y #endif /* !__cplusplus */ #ifdef __cplusplus /* Use C-bindings so C++-compiled and C-compiled libraries are compatible */ extern "C" { #endif /* !__cplusplus */ /* Replace restrict by __restrict in g++ compiler Substitute whitespace for restrict in all other C++ compilers */ #ifdef __cplusplus # ifdef __GNUG__ # define restrict __restrict # else /* !__GNUG__ */ # define restrict # endif /* !__GNUG__ */ #endif /* !__cplusplus */ /* Boolean values */ /* From Wikipedia: "On a recent C compiler (supporting the C99 standard), there is a _Bool type, which is used to define bool by the stdbool.h header: #include bool b = false; ... b = true; During its standardization process, the C++ programming language introduced the bool, true and false keywords, adding a native datatype to support boolean data. Preprocessor macros may be used to turn bool into _Bool, false into 0 and true into 1, allowing compatibility with the aforementioned C99 use of the stdbool.h header." */ #define nco_bool int #ifndef __cplusplus # ifndef bool # define bool int # endif /* bool */ #endif /* __cplusplus */ #ifndef True # define True 1 #endif /* True */ #ifndef False # define False 0 #endif /* False */ /* Variables marked CEWI "Compiler Error Warning Initialization" are initialized to prevent spurious "warning: `float foo' might be used uninitialized in this function" warnings when, e.g., GCC -Wuninitialized is turned on. Note that these warning messages are compiler- and OS-dependent GCC warning on Alpha, e.g., cannot be removed by this trick */ #define NULL_CEWI NULL #define char_CEWI '\0' #define double_CEWI 0.0 #define float_CEWI 0.0 #define int_CEWI 0 #define long_CEWI 0L #define long_long_CEWI ((long long int)0LL) #define nco_bool_CEWI 0 #define nco_byte_CEWI ((signed char)0) #define nco_char_CEWI '\0' #define nco_int_CEWI (0L) #define nco_short_CEWI ((short int)0) #define nco_ubyte_CEWI ((unsigned char)0) #define nco_ushort_CEWI ((unsigned short int)0) #define nco_uint_CEWI (0U) #define nco_int64_CEWI ((long long int)0LL) #define nco_uint64_CEWI ((unsigned long long int)0ULL) #define nco_string_CEWI NULL #define short_CEWI 0 #define size_t_CEWI 0UL /* Numeric constants to simplify arithmetic */ #define NCO_BYT_PER_KB 1024UL #define NCO_BYT_PER_MB 1048576UL #define NCO_BYT_PER_GB 1073741824UL #define NCO_BYT_PER_TB 1099511627776UL /* netcdf.h NC_GLOBAL is, strictly, the variable ID for global attributes NCO_REC_DMN_UNDEFINED is dimension ID of record dimension iff record dimension is undefined Normally using -1 for this ID is fine, but token makes meaning clearer NB: nc_inq() family returns -1 for missing record dimensions */ #define NCO_REC_DMN_UNDEFINED -1 /* Valid netCDF4 deflation levels (dfl_lvl) range from 0..9 inclusive Variables with dfl_lvl == 0 return true for compression yet are not deflated Calling deflation routine with dfl_lvl == 0 wastes time _unless_ user wishes to uncompress variable is currently deflated with dfl_lvl != 0. Undefined dfl_lvl indicates user has not yet specified and intended dfl_lvl This undefined value must be less than zero (and not equal to zero) so that if(dfl_lvl >= 0) deflate(); only calls deflate() when user requests it. Setting dfl_lvl == 0 decompresses variable */ #define NCO_DFL_LVL_UNDEFINED -1 /* netcdf.h defines four NC_FORMAT tokens: NC_FORMAT_CLASSIC, ... The values are (currently) enumerated from one to four Operators need to check if fl_out_fmt has been user-specified Safest way is to compare current value of fl_out_fmt to initial value Initial value should be a number that will never be a true netCDF format */ #define NCO_FORMAT_UNDEFINED 0 /* Argument to strtol() and strtoul() indicating base-10 conversions */ #define NCO_SNG_CNV_BASE10 10 /* netCDF provides no guidance on maximum nesting of groups */ #define NCO_MAX_GRP_DEPTH 10 /* Flag that iterator found no more groups in container */ #define NCO_LST_GRP 0 /* Debugging level that quiets all non-requested informational messages This value is compared against user-selected nco_dbg_lvl Running operators with --quiet automatically sets nco_dbg_lvl=NCO_DBG_QUIET */ #define NCO_DBG_QUIET 0 /* Find traversal table objects via hash table rather than brute-force strcmp() search */ #define NCO_HSH_TRV_OBJ 1 /* NCO_MSS_VAL_SNG names attribute whose value is "skipped" by arithmetic, aka the missing value attribute Attribute name should be either "missing_value" or "_FillValue" */ #ifndef NCO_MSS_VAL_SNG /* 20070831: TKN2SNG() technique inserts quotes into string though same test code in c.c does not produce extra quotes. TODO nco905. */ /*# define NCO_MSS_VAL_SNG missing_value */ /*# define NCO_MSS_VAL_SNG _FillValue*/ /*char nco_mss_val_sng[]=TKN2SNG(NCO_MSS_VAL_SNG);*/ /* [sng] Missing value attribute name */ /* Arcane workaround using NCO_USE_FILL_VALUE necessary because TKN2SNG() macro above is broken. TODO nco905 */ # define NCO_USE_FILL_VALUE # ifdef NCO_USE_FILL_VALUE /* NCO_NETCDF4_AND_FILLVALUE tells whether netCDF4 restrictions on _FillValue operations (must be defined before variable written, cannot be changed after variable written) can affect output file */ # ifdef ENABLE_NETCDF4 # define NCO_NETCDF4_AND_FILLVALUE # endif /* !ENABLE_NETCDF4 */ # endif /* !NCO_USE_FILL_VALUE */ #endif /* NCO_MSS_VAL_SNG */ /* Prototype global functions before defining them in next block */ char *nco_mss_val_sng_get(void); /* [sng] Missing value attribute name */ char *nco_not_mss_val_sng_get(void); /* [sng] Not missing value attribute name */ char *nco_prg_nm_get(void); int nco_prg_id_get(void); unsigned short nco_dbg_lvl_get(void); unsigned short nco_fmt_xtn_get(void); unsigned short nco_mrd_cnv_get(void); unsigned short nco_rth_cnv_get(void); unsigned short nco_upk_cnv_get(void); void nco_fmt_xtn_set(unsigned short nco_fmt_xtn_arg); #ifdef MAIN_PROGRAM_FILE /* Current file contains main() */ /* Tokens and variables with scope limited to main.c, and global variables allocated here */ int nco_prg_id; /* [enm] Program ID */ int nco_prg_id_get(void){return nco_prg_id;} /* [enm] Program ID */ char *nco_prg_nm; /* [sng] Program name */ char *nco_prg_nm_get(void){return nco_prg_nm;} /* [sng] Program name */ unsigned short nco_dbg_lvl=0; /* [enm] Debugging level */ unsigned short nco_dbg_lvl_get(void){return nco_dbg_lvl;} /* [enm] Debugging level */ unsigned short nco_fmt_xtn=0; /* [enm] Extended file format */ unsigned short nco_fmt_xtn_get(void){return nco_fmt_xtn;} /* [enm] Extended file format */ void nco_fmt_xtn_set(unsigned short nco_fmt_xtn_arg){nco_fmt_xtn=nco_fmt_xtn_arg;} /* [enm] Extended file format */ unsigned short nco_mrd_cnv=0; /* [enm] Multiple Record Dimension convention */ unsigned short nco_mrd_cnv_get(void){return nco_mrd_cnv;} /* [enm] Multiple Record Dimension convention */ unsigned short nco_rth_cnv=1; /* [enm] Arithmetic convention */ unsigned short nco_rth_cnv_get(void){return nco_rth_cnv;} /* [enm] Arithmetic convention */ unsigned short nco_upk_cnv=0; /* [enm] Unpacking convention */ unsigned short nco_upk_cnv_get(void){return nco_upk_cnv;} /* [enm] Unpacking convention */ # ifdef NCO_USE_FILL_VALUE /* This arcane get()/set() usage necessary because TKN2SNG() macro above is broken. TODO nco905 */ char nco_mss_val_sng[]="_FillValue"; /* [sng] Missing value attribute name */ char nco_not_mss_val_sng[]="missing_value"; /* [sng] Not missing value attribute name */ # else /* !NCO_USE_FILL_VALUE */ char nco_mss_val_sng[]="missing_value"; /* [sng] Missing value attribute name */ char nco_not_mss_val_sng[]="_FillValue"; /* [sng] Not missing value attribute name */ # endif /* !NCO_USE_FILL_VALUE */ char *nco_mss_val_sng_get(void){return nco_mss_val_sng;} /* [sng] Missing value attribute name */ char *nco_not_mss_val_sng_get(void){return nco_not_mss_val_sng;} /* [sng] Not missing value attribute name */ #else /* MAIN_PROGRAM_FILE is NOT defined, i.e., current file does not contain main() */ /* External references to global variables are declared as extern here Variables with local file scope in all files except main.c are allocated here */ #endif /* MAIN_PROGRAM_FILE is NOT defined, i.e., the current file does not contain main() */ /* Compatibility tokens for when NCO compiled with older netcdf.h It is hard to track where/when many tokens defined Easiest to individually check for pre-definition of each */ /* Three compatibility tokens new to netCDF4 netcdf.h: */ #ifndef NC_NETCDF4 # define NC_NETCDF4 (0x1000) /* Use netCDF-4/HDF5 format */ #endif #ifndef NC_ENDIAN_NATIVE # define NC_ENDIAN_NATIVE 0 #endif #ifndef NC_ENDIAN_LITTLE # define NC_ENDIAN_LITTLE 1 #endif #ifndef NC_ENDIAN_BIG # define NC_ENDIAN_BIG 2 #endif #ifndef NC_CHUNKED # define NC_CHUNKED (0) #endif #ifndef NC_CONTIGUOUS # define NC_CONTIGUOUS (1) #endif #ifndef NC_NOCHECKSUM # define NC_NOCHECKSUM 0 #endif #ifndef NC_FLETCHER32 # define NC_FLETCHER32 1 #endif /* Six compatibility tokens not all available until netCDF 3.6.1 netcdf.h NC_64BIT_OFFSET is used (so far) only in nco_fl_utl.c */ #ifndef NC_CLASSIC_MODEL # define NC_CLASSIC_MODEL 0x0100 /**< Enforce classic model. Mode flag for nc_create(). */ #endif #ifndef NC_64BIT_OFFSET # define NC_64BIT_OFFSET 0x0200 /* Use large (64-bit) file offsets */ #endif #ifndef NC_DISKLESS # define NC_DISKLESS 0x0008 /* Use diskless file. Mode flag for nc_open() or nc_create(). */ #endif #ifndef NC_FORMAT_CLASSIC # define NC_FORMAT_CLASSIC (1) #endif #ifndef NC_FORMAT_64BIT # define NC_FORMAT_64BIT (2) #endif #ifndef NC_FORMAT_NETCDF4 # define NC_FORMAT_NETCDF4 (3) #endif #ifndef NC_FORMAT_NETCDF4_CLASSIC # define NC_FORMAT_NETCDF4_CLASSIC (4) /* create netcdf-4 files, with NC_CLASSIC_MODEL. */ #endif /* Seven compatibility tokens introduced 20131222 in netCDF 4.3.1-rc7 netcdf.h */ #ifndef NC_FORMAT_UNDEFINED # define NC_FORMAT_UNDEFINED (0) #else # define NC_HAVE_INQ_FORMAT_EXTENDED #endif #ifndef NC_FORMAT_NC3 # define NC_FORMAT_NC3 (1) #endif #ifndef NC_FORMAT_NC_HDF5 # define NC_FORMAT_NC_HDF5 (2) /*cdf 4 subset of HDF5 */ #endif #ifndef NC_FORMAT_NC_HDF4 # define NC_FORMAT_NC_HDF4 (3) /* netcdf 4 subset of HDF4 */ #endif #ifndef NC_FORMAT_PNETCDF # define NC_FORMAT_PNETCDF (4) #endif #ifndef NC_FORMAT_DAP2 # define NC_FORMAT_DAP2 (5) #endif #ifndef NC_FORMAT_DAP4 # define NC_FORMAT_DAP4 (6) #endif /* Backwards-compatibility error codes for netCDF4 Currently used only in nco_grp_utl.c and nco_netcdf.c */ #ifndef NC_EBADGRPID # define NC_EBADGRPID (-116) /**< Bad group ID. */ #endif #ifndef NC_ENOGRP # define NC_ENOGRP (-125) /**< No group found. */ #endif /* Two backwards-compatibility error codes implemented in 201106 to diagnose problems with DAP Currently used only in nco_fl_utl.c */ #ifndef NC_ECANTREAD # define NC_ECANTREAD (-102) /**< Can't read. */ #endif #ifndef NC_EDAPSVC # define NC_EDAPSVC (-70) /**< DAP server error */ #endif /* NCO began using MIN/MAX tokens in nco_pck.c on 20101130 Not sure when these tokens were introduced to netcdf.h */ #ifndef NC_MAX_BYTE # define NC_MAX_BYTE 127 #endif #ifndef NC_MIN_BYTE # define NC_MIN_BYTE (-NC_MAX_BYTE-1) #endif #ifndef NC_MAX_CHAR # define NC_MAX_CHAR 255 #endif #ifndef NC_MAX_SHORT # define NC_MAX_SHORT 32767 #endif #ifndef NC_MIN_SHORT # define NC_MIN_SHORT (-NC_MAX_SHORT - 1) #endif #ifndef NC_MAX_INT # define NC_MAX_INT 2147483647 #endif #ifndef NC_MIN_INT # define NC_MIN_INT (-NC_MAX_INT - 1) #endif #ifndef NC_MAX_FLOAT # define NC_MAX_FLOAT 3.402823466e+38f #endif #ifndef NC_MIN_FLOAT # define NC_MIN_FLOAT (-NC_MAX_FLOAT) #endif #ifndef NC_MAX_DOUBLE # define NC_MAX_DOUBLE 1.7976931348623157e+308 #endif #ifndef NC_MIN_DOUBLE # define NC_MIN_DOUBLE (-NC_MAX_DOUBLE) #endif #ifndef NC_MAX_UBYTE # define NC_MAX_UBYTE NC_MAX_CHAR #endif #ifndef NC_MAX_USHORT # define NC_MAX_USHORT 65535U #endif #ifndef NC_MAX_UINT # define NC_MAX_UINT 4294967295U #endif #ifndef NC_MAX_INT64 # define NC_MAX_INT64 (9223372036854775807LL) #endif #ifndef NC_MIN_INT64 # define NC_MIN_INT64 (-9223372036854775807LL-1) #endif #ifndef NC_MAX_UINT64 # define NC_MAX_UINT64 (18446744073709551615ULL) #endif /* Endif older netcdf.h */ /* Define compatibility tokens when user does not have znetCDF */ #ifndef ENABLE_ZNETCDF # ifndef NC_COMPRESS # define NC_COMPRESS 0x200 /* bn file is compressed */ # endif #endif /* !ENABLE_ZNETCDF */ /* NB: Use NCO_NOERR and NCO_ERR as return codes to other functions, not to shell (e.g., Bash, Csh) Shell exit codes (where 0 indicates success) are traditionally opposite C exit codes (where 0 indicates failure) */ /* Internal NCO return code indicating success */ #define NCO_NOERR 1 /* Internal NCO return code indicating failure */ #define NCO_ERR 0 /* UDUnits return code indicating success */ #define UDUNITS_NOERR 0 /* NB: Use EXIT_SUCCESS and EXIT_FAILURE as return codes to shell (e.g., Bash, Csh), not to other functions Shell exit codes (where 0 indicates success) are traditionally opposite C-function (not C-program) exit codes (where 0 indicates failure) 20130711: FC19 x86_64 Linux defines EXIT_FAILURE == 134 */ #ifndef EXIT_SUCCESS /* Most likely this is a SUN4 machine */ # define EXIT_SUCCESS 0 #endif /* SUN4 */ #ifndef EXIT_FAILURE /* Most likely this is a SUN4 machine */ # define EXIT_FAILURE 1 #endif /* SUN4 */ #define TRV_MAP_SIZE NC_MAX_DIMS enum nco_prg_id{ /* [enm] Key value for all netCDF operators */ ncap, ncatted, ncbo, ncfe, ncecat, ncflint, ncks, ncpdq, ncra, ncrcat, ncrename, ncwa, ncge, /* 20131018: New operator */ ncmv /* 20131018: Potential new operator */ }; /* end nco_prg_id enum */ enum nco_dbg_typ_enm{ /* [enm] Debugging levels */ /* List in increasing levels of verbosity */ nco_dbg_quiet, /* 0 [enm] Quiet all non-error messages */ nco_dbg_std, /* 1 [enm] Standard mode. Minimal, but some, messages */ nco_dbg_fl, /* 2 [enm] Filenames */ nco_dbg_scl, /* 3 [enm] Scalars, other per-file information */ nco_dbg_grp, /* 4 [enm] Groups, highest level per-file loop information */ nco_dbg_var, /* 5 [enm] Variables, highest level per-group loop information */ nco_dbg_crr, /* 6 [enm] Current task */ nco_dbg_sbr, /* 7 [enm] Subroutine names on entry and exit */ nco_dbg_io, /* 8 [enm] Subroutine I/O */ nco_dbg_vec, /* 9 [enm] Entire vectors */ nco_dbg_vrb, /* 10 [enm] Verbose, print everything possible */ nco_dbg_old, /* 11 [enm] Old debugging blocks not used anymore */ nco_dbg_dev, /* 12 [enm] NCO developer information; only useful for debugging */ nco_dbg_nbr /* 13 [enm] Number of debugging types (equals last enumerated value) */ }; /* end nco_dbg_typ_enm */ enum nco_op_typ{ /* [enm] Operation type */ /* Types used in ncbo(): */ nco_op_add, /* [enm] Add file_1 to file_2 */ nco_op_dvd, /* [enm] Divide file_1 by file_2 */ nco_op_mlt, /* [enm] Multiply file_1 by file_2 */ nco_op_sbt, /* [enm] Subtract file_2 from file_1 */ /* Types used in ncra(), ncrcat(), ncwa(): */ nco_op_avg, /* [enm] Average */ nco_op_min, /* [enm] Minimum value */ nco_op_max, /* [enm] Maximum value */ nco_op_ttl, /* [enm] Linear sum */ nco_op_sqravg, /* [enm] Square of mean */ nco_op_avgsqr, /* [enm] Mean of sum of squares */ nco_op_sqrt, /* [enm] Square root of mean */ nco_op_rms, /* [enm] Root-mean-square (normalized by N) */ nco_op_rmssdn, /* [enm] Root-mean square normalized by N-1 */ nco_op_nil /* [enm] Nil or undefined operation type */ }; /* end nco_op_typ enum */ enum nco_rlt_opr{ /* [enm] Arithmetic relations (comparisons) for masking */ nco_op_eq, /* Equality */ nco_op_ne, /* Inequality */ nco_op_lt, /* Less than */ nco_op_gt, /* Greater than */ nco_op_le, /* Less than or equal to */ nco_op_ge /* Greater than or equal to */ }; /* end nco_rlt_opr enum */ typedef enum nco_obj_typ_enm{ /* [enm] netCDF4 object type: group, variable */ nco_obj_typ_err=-1, /* -1 Invalid type for initialization */ nco_obj_typ_grp, /* 0, Group */ nco_obj_typ_var, /* 1, Variable of atomic type */ nco_obj_typ_nonatomic_var /* 2, Variable of non-atomic type (vlen, opaque, enum, compound, user-defined) */ } nco_obj_typ; enum nco_fmt_xtn{ /* [enm] Extended or underlying filetype */ /* 20131222: Tokens defined as of netCDF 4.3.1-rc7 */ nco_fmt_xtn_nil=NC_FORMAT_UNDEFINED, /* 0 Undefined (more precisely, not yet defined) */ nco_fmt_xtn_nc3=NC_FORMAT_NC3, /* 1 netCDF3 */ nco_fmt_xtn_hdf5=NC_FORMAT_NC_HDF5, /* 2 HDF5 */ nco_fmt_xtn_hdf4=NC_FORMAT_NC_HDF4, /* 3 HDF4 */ nco_fmt_xtn_pnetcdf=NC_FORMAT_PNETCDF, /* 4 PnetCDF */ nco_fmt_xtn_dap2=NC_FORMAT_DAP2, /* 5 DAP2 */ nco_fmt_xtn_dap4=NC_FORMAT_DAP4, /* 6 DAP4 */ }; /* end nco_fmt_xtn */ enum nco_mrd_cnv{ /* [enm] Multiple Record Dimension convention: for ncecat and ncpdq */ /* This currently could be implemented as a flag rather than an enum General case may need more than binary option so use enum */ nco_mrd_restrict, /* 0 Fix some dimensions so as to avoid producing additional record dimensions */ nco_mrd_allow /* 1 Allow multiple record dimensions when operator produces them naturally */ }; /* end nco_mrd_cnv */ enum nco_rth_cnv{ /* [enm] Arithmetic convention to assume */ nco_rth_flt_flt, /* 0 Keep single-precision floating point (default and NCO historical norm) */ nco_rth_flt_dbl /* 1 Promote single-precision floating point to double before arithmetic */ }; /* end nco_rth_cnv */ enum nco_upk_cnv{ /* [enm] Unpacking convention to assume */ /* netCDF convention : http://www.unidata.ucar.edu/software/netcdf/docs/netcdf/Attribute-Conventions.html HDF/NASA convention: http://modis-atmos.gsfc.nasa.gov/MOD08_D3/faq.html */ nco_upk_netCDF, /* 0 netCDF unpack convention: unpacked=(scale_factor*packed)+add_offset */ nco_upk_HDF /* 1 HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ }; /* end nco_upk_cnv */ typedef enum aed{ /* [enm] Attribute editor mode */ aed_append, aed_create, aed_delete, aed_modify, aed_overwrite } aed_enm; /* end aed enum */ typedef enum gpe{ /* [enm] Group Path Editing mode */ gpe_append, gpe_delete, gpe_flatten, gpe_backspace } gpe_enm; /* end gpe enum */ typedef enum { /* [enm] Memory allocation type */ nco_mmr_calloc, /* [enm] nco_calloc() */ nco_mmr_free, /* [enm] nco_free() */ nco_mmr_malloc, /* [enm] nco_malloc() */ nco_mmr_realloc /* [enm] nco_realloc() */ } nco_mmr_typ_enm; /* end nco_mmr_typ enum */ typedef enum { /* [enm] Arithmetic precision rank */ /* Ranked ordering of "arithmetic precision" from lowest to highest */ nco_rth_prc_rnk_string, /* [enm] */ /* Least precise */ nco_rth_prc_rnk_char, /* [enm] */ nco_rth_prc_rnk_ubyte, /* [enm] */ nco_rth_prc_rnk_byte, /* [enm] */ nco_rth_prc_rnk_ushort, /* [enm] */ nco_rth_prc_rnk_short, /* [enm] */ nco_rth_prc_rnk_uint, /* [enm] */ nco_rth_prc_rnk_int, /* [enm] */ nco_rth_prc_rnk_uint64, /* [enm] */ nco_rth_prc_rnk_int64, /* [enm] */ nco_rth_prc_rnk_float, /* [enm] */ nco_rth_prc_rnk_double /* [enm] */ /* Most precise */ } nco_rth_prc_rnk_enm; /* end nco_rth_prc_rnk enum */ typedef enum { /* [enm] Timer flag */ nco_tmr_srt, /* [enm] Initialize timer (first timer call) */ nco_tmr_mtd, /* [enm] Metadata timer (second timer call) */ nco_tmr_rgl, /* [enm] Regular timer call (main loop timer call) */ nco_tmr_end /* [enm] Close timer (last timer call) */ } nco_tmr_flg; /* [enm] Timer flag */ typedef enum { /* [enm] Node enumerator Nie02 nodeEnum */ typ_scv, /* [enm] Scalar value */ typ_sym, /* [enm] Symbol identifier */ typ_opr /* [enm] Operator */ } nod_typ_enm; /* end Node enumerator */ /* end enumeration section */ typedef enum { /* [enm] Calendar type */ cln_std=1, /* Standard mixed Julian/Gregorian */ cln_grg, /* Gregorian Calendar */ cln_jul, /* Julian Calendar */ cln_360, /* 30-day month Calendar */ cln_365, /* No Leap year Calendar */ cln_366, /* Leap year Calendar */ cln_nil /* No calendar found */ } nco_cln_typ; /* [enm] Calendar type */ /* Limit structure */ typedef struct { /* lmt_sct */ char *nm; /* [sng] Dimension name */ char *nm_fll; /* [sng] Full dimension name */ char *grp_nm_fll; /* [sng] Full group where dimension is defined. Added for group support from original netCDF3 */ char *max_sng; /* User-specified string for dimension maximum */ char *min_sng; /* User-specified string for dimension minimum */ char *mro_sng; /* User-specified string for multi-record output */ char *ssc_sng; /* User-specified string for dimension subcycle */ char *rbs_sng; /* Used by ncra, ncrcat to re-base record coordinate (holds unit attribute from first file) */ char *srd_sng; /* User-specified string for dimension stride */ double max_val; /* Double precision representation of maximum value of coordinate requested or implied */ double min_val; /* Double precision representation of minimum value of coordinate requested or implied */ double origin; /* Used by ncra, ncrcat to re-base record coordinate */ int id; /* Dimension ID */ int lmt_typ; /* crd_val or dmn_idx */ long cnt; /* # of valid elements in this dimension (including effects of stride and wrapping) */ long ssc; /* Subcycle of hyperslab */ long end; /* Index to end of hyperslab */ long max_idx; /* Index of maximum requested value in dimension */ long min_idx; /* Index of minimum requested value in dimension */ /* Following four flags are used only by multi-file operators ncra and ncrcat: */ long idx_end_max_abs; /* [idx] Maximum allowed index in record dimension (multi-file record dimension only) */ long rec_dmn_sz; /* [nbr] Number of records in this file (multi-file record dimension only) */ long rec_in_cml; /* [nbr] Cumulative number of records in all files opened so far (multi-file record dimension only) */ long rec_rmn_prv_ssc; /* [nbr] Records remaining-to-be-read to complete subcycle group from previous file (multi-file record dimension only) */ long rec_skp_ntl_spf; /* [nbr] Records skipped in initial superfluous files (multi-file record dimension only) */ long rec_skp_vld_prv; /* [nbr] Records skipped since previous good one (multi-file record dimension only) */ long srd; /* Stride of hyperslab */ long srt; /* Index to start of hyperslab */ nco_bool flg_mro; /* True for multi-record output (used by ncra only) */ nco_bool flg_input_complete; /* True for multi-file operators when no more files need be opened */ nco_bool is_rec_dmn; /* True if record dimension, else False */ nco_bool is_usr_spc_lmt; /* True if any part of limit is user-specified, else False */ nco_bool is_usr_spc_max; /* True if user-specified, else False */ nco_bool is_usr_spc_min; /* True if user-specified, else False */ nco_cln_typ lmt_cln; /* Used by ncra, ncrcat to store enum of calendar-type attribute */ } lmt_sct; /* Name ID structure */ typedef struct{ /* nm_id_sct */ char *nm; /* Variable (stub name) */ int id; /* [id] Variable ID */ int grp_id_in; /* [id] Group ID in input file */ int grp_id_out; /* [id] Group ID in output file */ } nm_id_sct; /* Rename structure */ typedef struct{ /* rnm_sct */ char *old_nm; char *new_nm; int id; } rnm_sct; /* DDRA information structure */ typedef struct{ /* ddra_info_sct */ int nco_op_typ; /* [enm] Operation type */ int rnk_avg; /* [nbr] Rank of averaging space */ int rnk_var; /* [nbr] Variable rank (in input file) */ int rnk_wgt; /* [nbr] Rank of weight */ int var_idx; /* [enm] Index */ int wrd_sz; /* [B] Bytes per element */ long long lmn_nbr; /* [nbr] Variable size */ long long lmn_nbr_avg; /* [nbr] Averaging block size */ long long lmn_nbr_wgt; /* [nbr] Weight size */ nco_bool flg_ddra; /* [flg] Run DDRA diagnostics */ nco_bool MRV_flg; /* [flg] Avergaging dimensions are MRV dimensions */ nco_bool wgt_brd_flg; /* [flg] Broadcast weight for this variable */ nco_tmr_flg tmr_flg; /* [enm] Timer flag */ } ddra_info_sct; /* Pointer union */ typedef union{ /* ptr_unn */ float * restrict fp; double * restrict dp; nco_int * restrict ip; short * restrict sp; nco_char * restrict cp; nco_byte * restrict bp; nco_ubyte * restrict ubp; nco_ushort * restrict usp; nco_uint * restrict uip; nco_int64 * restrict i64p; nco_uint64 * restrict ui64p; nco_string * restrict sngp; void * restrict vp; } ptr_unn; /* Value union */ typedef union{ /* val_unn */ float f; double d; nco_int i; short s; nco_char c; nco_byte b; nco_ubyte ub; nco_ushort us; nco_uint ui; nco_int64 i64; nco_uint64 ui64; nco_string sng; } val_unn; /* Scalar value structure */ typedef struct{ /* scv_sct */ val_unn val; /* [sct] Value */ nc_type type; /* [enm] netCDF type */ nod_typ_enm nod_typ; /* [enm] Node type */ } scv_sct; /* Group Path Editing (GPE) structure */ typedef struct{ /* gpe_sct */ char *arg; /* [sng] Full GPE specification (for debugging) */ char *edt; /* [sng] Editing component of full GPE specification */ char *nm; /* [sng] Group name component of full GPE specification */ char *nm_cnn; /* [sng] Canonicalized (i.e., slash-terminated) group name */ gpe_enm md; /* [enm] Editing mode to perform */ short lvl_nbr; /* [nbr] Number of levels to shift */ size_t lng; /* [nbr] Length of user-specified group path */ size_t lng_cnn; /* [nbr] Length of canonicalized user-specified group path */ size_t lng_edt; /* [nbr] Length of editing component of full GPE specification */ } gpe_sct; /* Attribute editing structure */ typedef struct{ /* aed_sct */ char *att_nm; /* Name of attribute */ char *var_nm; /* Name of variable, or NULL for global attribute */ int id; /* Variable ID or NC_GLOBAL (= -1) for global attribute */ long sz; /* Number of elements in attribute */ nc_type type; /* Type of attribute */ ptr_unn val; /* Pointer to attribute value */ aed_enm mode; /* Action to perform with attribute */ } aed_sct; /* MD5 flags structure */ typedef struct{ /* md5_sct */ char *att_nm; /* [sng] MD5 attribute name */ nco_bool dgs; /* [flg] Perform MD5 digests */ nco_bool wrt; /* [flg] Write MD5 digests as attributes */ } md5_sct; /* Print flags structure */ typedef struct{ /* prn_fmt_sct */ char *fl_in; /* [sng] Input filename */ char *fl_stb; /* [sng] Input filename stub */ char *smr_sng; /* [sng] Summary string */ char *spr_chr; /* [sng] Separator string for character types */ char *spr_nmr; /* [sng] Separator string for numeric types */ gpe_sct *gpe; /* I [sng] GPE structure */ md5_sct *md5; /* [flg] MD5 configuration */ nco_bool cdl; /* [flg] Print CDL */ nco_bool srm; /* [flg] Print ncStream */ nco_bool trd; /* [flg] Print traditional NCO format */ nco_bool jsn; /* [flg] Print JSON */ nco_bool xml; /* [flg] Print XML (NcML) */ nco_bool hdn; /* [flg] Print hidden attributes */ nco_bool xml_lcn; /* [flg] Print XML location tag */ nco_bool nfo_xtr; /* [flg] Print extra information in CDL/XML mode */ nco_bool new_fmt; /* [flg] Print in new format */ nco_bool nwl_pst_val; /* [flg] Print newline after variable values */ int nbr_zro; /* [nbr] Trailing zeros allowed after decimal point */ int ndn; /* [nbr] Indentation */ int fll_pth; /* [nbr] Print full paths */ int tab; /* [nbr] Number of spaces in tab */ int spc_per_lvl; /* [nbr] Indentation spaces per group level */ int sxn_fst; /* [nbr] Offset of section from group name */ int var_fst; /* [nbr] Offset of variable from section name */ char *dlm_sng; /* User specified delimiter string for printed output */ nco_bool ALPHA_BY_FULL_GROUP; /* [flg] Print alphabetically by full group */ nco_bool ALPHA_BY_FULL_OBJECT; /* [flg] Print alphabetically by full object */ nco_bool ALPHA_BY_STUB_GROUP; /* [flg] Print alphabetically by stub group */ nco_bool ALPHA_BY_STUB_OBJECT; /* [flg] Print alphabetically by stub object */ nco_bool FORTRAN_IDX_CNV; /* Option F */ nco_bool PRN_DMN_IDX_CRD_VAL; /* [flg] Print leading dimension/coordinate indices/values Option Q */ nco_bool PRN_DMN_UNITS; /* [flg] Print dimensional units Option u */ nco_bool PRN_DMN_VAR_NM; /* [flg] Print dimension/variable names */ nco_bool PRN_GLB_METADATA; /* [flg] Print global metadata */ nco_bool PRN_MSS_VAL_BLANK; /* [flg] Print missing values as blanks */ nco_bool PRN_VAR_DATA; /* [flg] Print variable data */ nco_bool PRN_VAR_METADATA; /* [flg] Print variable metadata */ } prn_fmt_sct; /* Attribute structure */ typedef struct{ /* att_sct */ char *nm; nc_type type; long sz; char fmt[5]; ptr_unn val; } att_sct; /* Per-dimension chunking specification (free with nco_cnk_dmn_free()) */ typedef struct{ /* cnk_dmn_sct */ char *nm; /* [sng] Dimension name */ char *nm_fll; /* [sng] Full dimension name */ size_t sz; /* [nbr] Chunk size */ nco_bool is_usr_spc_cnk; /* [flg] Chunk size was user-specified */ } cnk_dmn_sct; /* Chunking structure */ typedef struct{ /* cnk_sct */ nco_bool flg_usr_rqs; /* [flg] User requested chunking */ int cnk_nbr; /* [nbr] Number of user-specified chunk sizes */ cnk_dmn_sct **cnk_dmn; /* [sct] User-specified per-dimension chunking information */ int cnk_map; /* [enm] Chunking map */ int cnk_plc; /* [enm] Chunking policy */ size_t cnk_sz_scl; /* [nbr] Chunk size scalar */ size_t cnk_sz_byt; /* [B] Chunk size in Bytes */ } cnk_sct; /* GTT structure to break full path name into components */ typedef struct{ char *nm; /* [sng] Path component */ int psn; /* [nbr] Position of path component */ } sng_pth_sct; /* MSA Limits structure: GTT has a member for every unique dimension and for every coordinate variable */ typedef struct { char *dmn_nm; /* [sng] Dimension name */ long dmn_sz_org; /* [nbr] Original size of dimension */ long dmn_cnt; /* [nbr] Hyperslabbed size of dimension */ nco_bool BASIC_DMN; /* [flg] Limit is same as dimension in input file */ nco_bool WRP; /* [flg] Limit is wrapped (true if wrapping, lmt_dmn_nbr==2) */ nco_bool MSA_USR_RDR; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ int lmt_dmn_nbr; /* [nbr] Number of lmt arguments */ lmt_sct **lmt_dmn; /* [sct] List of limit structures associated with each dimension */ int lmt_crr; /* [nbr] Index of current limit structure being initialized (helper to initialze lmt_sct*) */ } lmt_msa_sct; /* GTT coordinate variable structure; it contains netCDF model fields and an MSA field */ typedef struct{ char *crd_nm_fll; /* [sng] Full coordinate name */ char *dmn_nm_fll; /* [sng] Full name of dimension for *this* coordinate */ char *crd_grp_nm_fll; /* [sng] Full group name where coordinate is located */ char *dmn_grp_nm_fll; /* [sng] Full group name where dimension of *this* coordinate is located */ char *nm; /* [sng] Name of dimension and coordinate */ nco_bool is_rec_dmn; /* [flg] Is a record dimension? */ size_t sz; /* [nbr] Size of coordinate */ nc_type var_typ; /* [enm] NetCDF type */ lmt_msa_sct lmt_msa; /* [sct] MSA Limits structure for every coordinate */ int dmn_id; /* [ID] Unique ID for dimension (duplicate of dmn_trv_sct.dim_id, since all coordinates share that ID) */ int grp_dpt; /* [nbr] Depth of group (root = 0); needed to get in scope of variable match */ } crd_sct; /* GTT dimension structure (stored in *groups*); it contains netCDF model fields and an MSA field */ typedef struct{ char *grp_nm_fll; /* [sng] Full group name where dimension was defined */ char *nm_fll; /* [sng] Dimension fully qualified name (path) */ char *nm; /* [sng] Dimension name */ nco_bool is_rec_dmn; /* [flg] Is a record dimension? */ size_t sz; /* [nbr] Size of dimension */ int crd_nbr; /* [nbr] Number of coordinate structures */ crd_sct **crd; /* [sct] List of coordinate structures */ lmt_msa_sct lmt_msa; /* [sct] MSA Limits structure (implicit that is for non-coordinate case) */ int dmn_id; /* [ID] Dimension ID; same as "var_dmn_sct.id" from nc_inq_dimid() */ nco_bool has_crd_scp; /* [flg] Does variable with same name exist in dimension's scope? */ nco_bool flg_xtr; /* [flg] Extract dimension */ } dmn_trv_sct; /* Build a list of 'standard_name' 'latitude' and 'longitude' coordinates (Auxiliary Coordinates) */ typedef struct{ char *nm_fll; /* [sng] Coordinate full name ('latitude' or 'longitude') */ int dmn_id; /* [id] Dimension ID of dimension of 'latitude' and 'longitude' coordinate variables, e.g., lat_gds(gds_crd) */ char units[NC_MAX_NAME+1]; /* [sng] Units of 'latitude' and 'longitude' */ nc_type crd_typ; /* [enm] netCDF type of both "latitude" and "longitude" */ int grp_dpt; /* [nbr] Depth of group (root = 0) */ } aux_crd_sct; /* GTT Variable dimensions: Dimension have name and size, and can have an associated variable (coordinate variable) */ typedef struct{ char *dmn_nm_fll; /* [sng] Full dimension name */ char *dmn_nm; /* [sng] Dimension name */ char *grp_nm_fll; /* [sng] Full group where dimension is defined */ nco_bool is_rec_dmn; /* [flg] Is a record dimension? */ nco_bool is_crd_var; /* [flg] Dimension has an associated coordinate variable */ crd_sct *crd; /* [sct] Pointer to coordinate variable if any */ dmn_trv_sct *ncd; /* [sct] Pointer to non-coordinate dimension if any */ int dmn_id; /* [ID] Dimension ID; same as dmn_trv_sct.id from nc_inq_vardimid() */ aux_crd_sct *lat_crd; /* [lst] Array of 'latitude' coordinates */ aux_crd_sct *lon_crd; /* [lst] Array of 'longitude' coordinates */ int nbr_lat_crd; /* [nbr] Number of items in 'latitude' coordinates array */ int nbr_lon_crd; /* [nbr] Number of items in 'longitude' coordinates array */ /* Following are members only used by transformation operators (non-ncks) */ nco_bool flg_dmn_avg; /* [flg] Diferentiate between dimensions to average or keep for this variable (ncwa) */ nco_bool flg_rdd; /* [flg] Retain dimension as degenerate (size 1) (ncwa) */ } var_dmn_sct; /* Processing type enumerator */ typedef enum { err_typ=-1, /* -1 [enm] Invalid type for initialization */ fix_typ, /* 0 [enm] Fixed variable (operator alters neither data nor metadata) */ prc_typ /* 1 [enm] Process variable (operator may alter data and metadata) */ } prc_typ_enm; /* GTT Object structure Information for each object/node in traversal tree Contains basic information about this object/node needed by traversal algorithm Node/object is either group or variable like in HDF5 Initialize trv_sct structure to defaults in trv_tbl_init() Populate trv_sct structure with correct values in nco_grp_itr() Deep-copy each pointer member of trv_sct structure in nco_grp_itr() free() each pointer member of trv_sct structure in trv_tbl_free() */ typedef struct{ nco_obj_typ nco_typ; /* [enm] netCDF4 object type: group or variable */ char *nm_fll; /* [sng] Fully qualified name (path) */ var_dmn_sct *var_dmn; /* [sct] (For variables only) Dimensions for variable object */ nco_bool is_crd_var; /* [flg] (For variables only) Is a coordinate variable? (unique dimension exists in scope) */ nco_bool is_rec_var; /* [flg] (For variables only) Is a record variable? (is_crd_var must be True) */ nc_type var_typ; /* [enm] (For variables only) NetCDF type */ size_t nm_fll_lng; /* [sng] Length of full name */ char *grp_nm_fll; /* [sng] Full group name (for groups, same as nm_fll) */ char *grp_nm; /* [sng] Group name (for groups, same as nm) */ char *nm; /* [sng] Relative name (i.e., variable name or last component of path name for groups) */ size_t nm_lng; /* [sng] Length of short name */ int grp_dpt; /* [nbr] Depth of group (root = 0) */ int nbr_att; /* [nbr] Number of attributes */ int nbr_dmn; /* [nbr] Number of dimensions */ int nbr_rec; /* [nbr] Number of record dimensions */ int nbr_grp; /* [nbr] (For groups only) Number of sub-groups */ int nbr_var; /* [nbr] (For groups only) Number of variables */ nco_bool flg_cf; /* [flg] Object matches CF-metadata extraction criteria */ nco_bool flg_crd; /* [flg] Object matches coordinate extraction criteria */ nco_bool flg_dfl; /* [flg] Object meets default subsetting criteria */ nco_bool flg_gcv; /* [flg] Group contains matched variable */ nco_bool flg_mch; /* [flg] Object matches user-specified strings */ nco_bool flg_mtd; /* [flg] Group contains only metadata */ nco_bool flg_ncs; /* [flg] Group is ancestor of specified group or variable */ nco_bool flg_nsx; /* [flg] Object matches intersection criteria */ nco_bool flg_rcr; /* [flg] Extract group recursively */ nco_bool flg_unn; /* [flg] Object matches union criteria */ nco_bool flg_vfp; /* [flg] Variable matches full path specification */ nco_bool flg_vsg; /* [flg] Variable selected because group matches */ nco_bool flg_xcl; /* [flg] Object matches exclusion criteria */ nco_bool flg_xtr; /* [flg] Extract object */ nco_bool flg_aux; /* [flg] Variable contains auxiliary coordinates */ nco_bool flg_std_att_lat; /* [flg] Variable contains 'standard_name' attribute "latitude" */ nco_bool flg_std_att_lon; /* [flg] Variable contains 'standard_name' attribute "longitude" */ /* Following are members only used by transformation operators (non-ncks) */ prc_typ_enm enm_prc_typ; /* [enm] Processing type enumerator */ nc_type var_typ_out; /* [enm] NetCDF type in output file (ncflint) (ncpdq) */ int *dmn_idx_out_in; /* [nbr] Dimension correspondence, output->input (ncpdq); output of nco_var_dmn_rdr_mtd() */ nco_bool *dmn_rvr_in; /* [flg] Reverse dimensions (ncpdq) */ nco_bool flg_rdr; /* [flg] Variable has dimensions to re-order (ncpdq) */ char *rec_dmn_nm_out; /* [sng] Record dimension name, re-ordered (ncpdq) (used as flag also for re-defined record dimension)*/ char *grp_nm_fll_prn; /* [sng] (ncge) Parent group full name */ /* Good hash, dude */ UT_hash_handle hh; /* [sct] Handle for hash table */ char *hsh_key; /* [sng] Hash key (must be unique!) */ nco_bool flg_nsm_prn; /* [flg] (ncge) Group is ensemble parent group */ nco_bool flg_nsm_mbr; /* [flg] (ncge) Variable or group is ensemble member */ nco_bool flg_nsm_tpl; /* [flg] (ncge) Variable is template */ char *nsm_nm; /* [sng] (ncge) Ensemble parent group name i.e., full path to ensemble parent */ } trv_sct; /* Fill actual value of dmn_sct structure in nco_dmn_fll() free() each pointer member of dmn_sct structure in nco_dmn_free() deep-copy each pointer member of dmn_sct structure in nco_dmn_dpl() */ /* Dimension structure */ typedef struct dmn_sct_tag{ /* dmn_sct */ char *nm; /* [sng] Dimension name */ char fmt[5]; /* [sng] Hint for printf()-style formatting */ int cid; /* [id] Variable ID of associated coordinate, if any */ int id; /* [id] Dimension ID */ int nc_id; /* [id] File ID */ long cnt; /* [nbr] Number of valid elements in this dimension (including effects of stride and wrapping) */ long end; /* [idx] Index to end of hyperslab */ long srd; /* [nbr] Stride of hyperslab */ long srt; /* [idx] Index to start of hyperslab */ long sz; /* [nbr] Full size of dimension in file (NOT the hyperslabbed size) */ nc_type type; /* [enm] Type of coordinate, if applicable */ ptr_unn val; /* [sct] Buffer to hold hyperslab fxm: is this ever used? */ short is_crd_dmn; /* [flg] Is this a coordinate dimension? */ short is_rec_dmn; /* [flg] Is this the record dimension? */ size_t cnk_sz; /* [nbr] Chunk size */ struct dmn_sct_tag *xrf; /* [sct] Cross-reference to associated dimension structure (usually the structure for dimension on output) */ } dmn_sct; /* end dmn_sct_tag */ /* Ensemble group structure (ncge). It contains a name for the group (e.g., /cesm/cesm_01) and a list of variables for the group */ typedef struct{ char *mbr_nm_fll; /* [sng] Goup full name */ char **var_nm_fll; /* [sng] List of full variable names for this group (e.g., /cesm/cesm_01/tas) */ int var_nbr; /* [nbr] Number of variable for this group (size of above array) */ } nsm_grp_sct; /* Ensemble (ncge) */ typedef struct{ char *grp_nm_fll_prn; /* [sng] Parent group full name (key for ensemble) (e.g., /cesm) */ nsm_grp_sct *mbr; /* [sng] List of ensemble group member structs (size is mbr_nbr) */ char **var_mbr_fll; /* [sng] List of variable ensemble members (e.g., /cesm/cesm_01/tas) */ char **grp_mbr_fll; /* [sng] List of group ensemble members (e.g., /cesm/cesm_01) */ int mbr_nbr; /* [nbr] Number of members (groups) of ensemble (i.e., number in this ensemble in this file) */ int mbr_var_nbr; /* [nbr] Number of variable members of ensemble */ int mbr_srt; /* [nbr] Member offsets (multi files, keep track of new added members) */ int mbr_end; /* [nbr] Member offsets (multi files, keep track of new added members) */ } nsm_sct; /* Name structure */ typedef struct{ /* nm_sct */ char *nm; /* [sng] Name */ } nm_sct; /* Name list structure */ typedef struct{ /* nm_tbl_sct */ nm_sct *lst; /* [sct] List of nm_sct (char * currently) */ int nbr; /* [nbr] Number of items in "lst" array */ } nm_tbl_sct; /* GTT (Group Traversal Table) structure contains two lists 1) lst: All objects (variables and groups) in file tree (HDF5 model) 2) lst_dmn: All unique dimensions (in groups) in file tree (netCDF addition to HDF5) */ typedef struct{ /* Members used by all operators */ trv_sct *lst; /* [sct] Array of trv_sct */ unsigned int nbr; /* [nbr] Number of trv_sct elements */ dmn_trv_sct *lst_dmn; /* [sct] Array of dmn_trv_sct */ unsigned int nbr_dmn; /* [nbr] Number of dmn_trv_sct elements */ trv_sct *hsh; /* [hsh] Hash table of all trv_sct objects */ dmn_sct *dmn_dgn; /* [sct] (ncwa) Degenerate dimensions */ int nbr_dmn_dgn; /* [sct] (ncwa) Number of degenerate dimensions (size of above array) */ int nsm_nbr; /* [nbr] (ncge) Number of ensembles (i.e., number in first file) */ nsm_sct *nsm; /* [lst] (ncge) List of ensembles (size is nsm_nbr) */ char *nsm_sfx; /* [sng] (ncge) Ensemble suffix (e.g., /cesm + _avg). Store here instead of passing as function parameters (ncge only) */ nm_tbl_sct *nsm_skp; /* [lst] (ncge) Skip list (fixed variables to define at ensemble parent group) */ } trv_tbl_sct; /* GPE duplicate name check structure */ typedef struct{ /* gpe_nm_sct */ char *var_nm_fll; /* [sng] Fully qualified variable name */ } gpe_nm_sct; /* Common variable names; common defined as same absolute path in 2 files */ typedef struct{ char *nm; /* [sng] A name */ nco_bool flg_in_fl[2]; /* [flg] Is this name in each file?; files are [0] and [1] */ } nco_cmn_t; /* cell_methods structure */ typedef struct{ char *dmn_nm; /* [sng] Dimension name */ int op_type; /* [enm] Operation type */ } cell_methods_sct; /* Limit "lmt_sct" monotonic direction */ typedef enum { decreasing, /* 0 */ increasing, /* 1 */ not_checked /* 2 */ } monotonic_direction_enm; /* Structure to check for valid input dimension */ typedef struct { nco_bool flg_dne; /* [flg] Flag to check if input dimension -d "does not exist" */ char *dim_nm; /* [sng] Dimension name */ } nco_dmn_dne_t; /* Initialize default value of each member of var_sct structure in var_dfl_set() Fill actual value of var_sct structure in nco_var_fll() free() each pointer member of var_sct structure in nco_var_free() deep-copy each pointer member of var_sct structure in nco_var_dpl() */ /* Variable structure */ typedef struct var_sct_tag{ /* var_sct */ char *nm; /* [sng] Variable name */ char *nm_fll; /* [sng] Absolute variable name (needed for GTT search for object by full name) */ char fmt[5]; /* [sng] Hint for printf()-style formatting */ dmn_sct **dim; /* [sct] Pointers to full dimension structures */ int *dmn_id; /* [id] Contiguous vector of dimension IDs */ int cid; /* [id] Dimension ID of associated coordinate, if any */ int dfl_lvl; /* [enm] Deflate level [0..9] */ int has_add_fst; /* [flg] Valid add_offset attribute exists */ int has_dpl_dmn; /* [flg] Variable has duplicate copies of same dimension */ int has_mss_val; /* [flg] Is there a missing_value attribute? */ int has_scl_fct; /* [flg] Valid scale_factor attribute exists */ int id; /* [id] Variable ID */ int nbr_att; /* [nbr] Number of attributes */ int nbr_dim; /* [nbr] Number of dimensions of variable in input file */ int nc_id; /* [id] File ID */ int pck_dsk; /* [flg] Variable is packed on disk (valid scale_factor, add_offset, or both attributes exist) */ int pck_ram; /* [flg] Variable is packed in memory (valid scale_factor, add_offset, or both attributes exist) */ int shuffle; /* [flg] Turn on shuffle filter */ int undefined; /* [flg] Variable is still undefined (in first parser pass) */ long *cnt; /* [nbr] Contiguous vector of lengths of hyperslab */ long *end; /* [idx] Contiguous vector of indices to end of hyperslab */ long *srd; /* [nbr] Contiguous vector of stride of hyperslab */ long *srt; /* [idx] Contiguous vector of indices to start of hyperslab */ long *tally; /* [nbr] Number of valid operations performed so far */ long sz; /* [nbr] Number of elements (NOT bytes) in hyperslab (NOT full size of variable in input file!) */ long sz_rec; /* [nbr] Number of elements in one record of hyperslab */ nc_type typ_dsk; /* [enm] Type of variable on disk (never changes) */ nc_type typ_pck; /* [enm] Type of variable when packed (on disk). typ_pck = typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ nc_type typ_upk; /* [enm] Type of variable when unpacked (expanded) (in memory) */ nc_type type; /* [enm] Type of variable in RAM */ ptr_unn add_fst; /* [frc] Value of add_offset attribute of type typ_upk */ ptr_unn mss_val; /* [frc] Value of missing_value attribute, if any (mss_val stored in this structure must be same type as variable) */ ptr_unn scl_fct; /* [frc] Value of scale_factor attribute of type typ_upk */ ptr_unn val; /* [bfr] Buffer to hold hyperslab */ short is_crd_var; /* [flg] Is this a coordinate variable? */ short is_fix_var; /* [flg] Is this a fixed (non-processed) variable? */ short is_rec_var; /* [flg] Is this a record variable? */ size_t *cnk_sz; /* [id] Contiguous vector of chunk sizes */ struct var_sct_tag *xrf; /* [sct] Cross-reference to associated variable structure (usually structure for variable on output) fxm: deprecate! TODO nco226 */ } var_sct; /* end var_sct_tag */ /* Dimension utility structure to share common fields; used in nco_cnk_sz_set_trv() */ typedef struct{ char nm[NC_MAX_NAME+1L];/* [sng] Name of dimension/coordinate */ char *nm_fll; /* [sng] Full dimension name */ nco_bool is_rec_dmn; /* [flg] Is a record dimension/coordinate? */ size_t sz; /* [nbr] Size of dimension/coordinate */ nco_bool BASIC_DMN; /* [flg] Limit is same as dimension in input file */ size_t dmn_cnt; /* [nbr] Hyperslabbed size of dimension */ int id; /* [id] Dimension ID */ } dmn_cmn_sct; #ifdef __cplusplus } /* end extern "C" */ #endif /* !__cplusplus */ #endif /* NCO_H */ ./nco-4.4.2/src/nco/ncwa.c0000644000674300045400000016361612300513547014434 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncwa.c,v 1.409 2014/02/17 23:12:39 zender Exp $ */ /* ncwa -- netCDF weighted averager */ /* Purpose: Compute averages of specified hyperslabs of specfied variables in a single input netCDF file and output them to a single file. */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* fxm: 19981202 deactivated -n and -W switches and code left in place to rethink normalization switches */ /* Usage: ncwa -O -a lon ~/nco/data/in.nc ~/foo.nc ncwa -O -R -p /ZENDER/tmp -l ~/nco/data in.nc ~/foo.nc ncwa -O -C -a lat,lon,time -w gw -v PS -p /fs/cgd/csm/input/atm SEP1.T42.0596.nc ~/foo.nc;ncks -H foo.nc scp ~/nco/src/nco/ncwa.c esmf.ess.uci.edu:nco/src/nco */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #ifndef _MSC_VER # include "ncap.h" /* netCDF arithmetic processor-specific definitions (symbol table, ...) */ #endif /* _MSC_VER */ #include "libnco.h" /* netCDF Operator (NCO) library */ #ifndef _MSC_VER /* Global variables (keep consistent with global variables declared in ncap.c) */ size_t ncap_ncl_dpt_crr=0UL; /* [nbr] Depth of current #include file (incremented in ncap.l) */ size_t *ncap_ln_nbr_crr; /* [cnt] Line number (incremented in ncap.l) */ char **ncap_fl_spt_glb; /* [fl] Script file */ #endif /* _MSC_VER */ int main(int argc,char **argv) { nco_bool CNV_CCM_CCSM_CF; nco_bool DO_CONFORM_MSK=False; /* Did nco_var_cnf_dmn() find truly conforming mask? */ nco_bool DO_CONFORM_WGT=False; /* Did nco_var_cnf_dmn() find truly conforming weight? */ nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool GRP_VAR_UNN=False; /* [flg] Select union of specified groups and variables */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ nco_bool MULTIPLY_BY_TALLY=False; /* Not currently implemented */ nco_bool MUST_CONFORM=False; /* [flg] Must nco_var_cnf_dmn() find truly conforming variables? */ nco_bool NORMALIZE_BY_TALLY=True; /* Not currently implemented */ nco_bool NORMALIZE_BY_WEIGHT=True; /* Not currently implemented */ nco_bool NRM_BY_DNM=True; /* Option N Normalize by denominator */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WGT_MSK_CRD_VAR=True; /* [flg] Weight and/or mask coordinate variables */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cll_mth=True; /* [flg] Add/modify cell_methods attributes */ nco_bool flg_cln=True; /* [flg] Clean memory prior to exit */ nco_bool flg_ddra=False; /* [flg] DDRA diagnostics */ nco_bool flg_rdd=False; /* [flg] Retain degenerate dimensions */ char *aux_arg[NC_MAX_DIMS]; char **dmn_avg_lst_in=NULL_CEWI; /* Option a */ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in=NULL_CEWI; char **var_lst_in=NULL_CEWI; char **grp_lst_in=NULL_CEWI; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *msk_nm=NULL; char *msk_cnd_sng=NULL; /* Mask string to be "parsed" and values given to msk_nm, msk_val, op_typ_rlt */ char *nco_op_typ_sng; /* Operation type */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char *wgt_nm=NULL; char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncwa.c,v 1.409 2014/02/17 23:12:39 zender Exp $"; const char * const CVS_Revision="$Revision: 1.409 $"; const char * const opt_sht_lst="3467Aa:B:bCcD:d:Fg:G:hIL:l:M:m:nNOo:p:rRT:t:v:Ww:xy:-:"; cnk_sct cnk; /* [sct] Chunking structure */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.MRV_flg=False,.flg_ddra=False,.lmn_nbr=0LL,.lmn_nbr_avg=0LL,.lmn_nbr_wgt=0LL,.nco_op_typ=nco_op_nil,.rnk_avg=0,.rnk_var=0,.rnk_wgt=0,.tmr_flg=nco_tmr_srt,.var_idx=0,.wgt_brd_flg=False,.wrd_sz=0}; #endif /* !__cplusplus */ dmn_sct **dim=NULL_CEWI; dmn_sct **dmn_out=NULL_CEWI; dmn_sct **dmn_avg=NULL_CEWI; double msk_val=1.0; /* Option M */ extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ int *in_id_arr; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int abb_arg_nbr=0; int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int dmn_avg_nbr=0; int fl_idx=int_CEWI; int fl_nbr=0; int fl_in_fmt; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int grp_lst_in_nbr=0; /* [nbr] Number of groups explicitly specified by user */ int idx=int_CEWI; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_out=0; int nbr_dmn_xtr; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int nco_op_typ=nco_op_avg; /* Operation type */ int op_typ_rlt=0; /* Option o */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; md5_sct *md5=NULL; /* [sct] MD5 configuration */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc; var_sct **var_prc_out; var_sct *wgt_avg=NULL; trv_tbl_sct *trv_tbl=NULL; /* [lst] Traversal table */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ gpe_sct *gpe=NULL; /* [sng] Group Path Editing (GPE) structure */ #ifndef _MSC_VER prs_sct prs_arg; /* I/O [sct] Global information required in ncwa parser */ #endif static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cll_mth",no_argument,0,0}, /* [flg] Add/modify cell_methods attributes */ {"cell_methods",no_argument,0,0}, /* [flg] Add/modify cell_methods attributes */ {"no_cll_mth",no_argument,0,0}, /* [flg] Do not add/modify cell_methods attributes */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"ddra",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"mdl_cmp",no_argument,0,0}, /* [flg] DDRA diagnostics */ {"dbl",no_argument,0,0}, /* [flg] Arithmetic convention: promote float to double */ {"flt",no_argument,0,0}, /* [flg] Arithmetic convention: keep single-precision */ {"rth_dbl",no_argument,0,0}, /* [flg] Arithmetic convention: promote float to double */ {"rth_flt",no_argument,0,0}, /* [flg] Arithmetic convention: keep single-precision */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"hdf_upk",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"hdf_unpack",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"append",no_argument,0,'A'}, {"average",required_argument,0,'a'}, {"avg",required_argument,0,'a'}, {"mask_condition",required_argument,0,'B'}, {"msk_cnd_sng",required_argument,0,'B'}, {"retain-degenerate-dimensions",no_argument,0,'b'}, /* [flg] Retain degenerate dimensions */ {"rdd",no_argument,0,'b'}, /* [flg] Retain degenerate dimensions */ {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"wgt_msk_crd_var",no_argument,0,'I'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"mask-variable",required_argument,0,'m'}, {"mask_variable",required_argument,0,'m'}, {"mask",required_argument,0,'m'}, {"msk_var",required_argument,0,'m'}, {"msk_nm",required_argument,0,'m'}, {"mask-value",required_argument,0,'M'}, {"mask_value",required_argument,0,'M'}, {"msk_val",required_argument,0,'M'}, {"nintap",required_argument,0,'n'}, {"nmr",no_argument,0,'N'}, {"numerator",no_argument,0,'N'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"mask_comparator",required_argument,0,'T'}, {"msk_cmp_typ",required_argument,0,'T'}, {"op_rlt",required_argument,0,'T'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"normalize-by-tally",no_argument,0,'W',}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"weight",no_argument,0,'w'}, {"wgt",no_argument,0,'w'}, {"wgt_var",no_argument,0,'w'}, {"operation",required_argument,0,'y'}, {"op_typ",required_argument,0,'y'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); NORMALIZE_BY_TALLY=NORMALIZE_BY_TALLY+0; /* CEWI: Avert compiler warning that variable is set but never used */ NORMALIZE_BY_WEIGHT=NORMALIZE_BY_WEIGHT+0; /* CEWI: Avert compiler warning that variable is set but never used */ /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif bfr_sz */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk_dmn */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cll_mth") || !strcmp(opt_crr,"cell_methods")) flg_cll_mth=True; /* [flg] Add/modify cell_methods attributes */ if(!strcmp(opt_crr,"no_cll_mth") || !strcmp(opt_crr,"no_cell_methods")) flg_cll_mth=False; /* [flg] Add/modify cell_methods attributes */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"ddra") || !strcmp(opt_crr,"mdl_cmp")) ddra_info.flg_ddra=flg_ddra=True; /* [flg] DDRA diagnostics */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"dbl") || !strcmp(opt_crr,"rth_dbl")) nco_rth_cnv=nco_rth_flt_dbl; /* [flg] Arithmetic convention: promote float to double */ if(!strcmp(opt_crr,"flt") || !strcmp(opt_crr,"rth_flt")) nco_rth_cnv=nco_rth_flt_flt; /* [flg] Arithmetic convention: keep single-precision */ if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdf_upk") || !strcmp(opt_crr,"hdf_unpack")) nco_upk_cnv=nco_upk_HDF; /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Dimensions over which to average hyperslab */ if(dmn_avg_lst_in){ (void)fprintf(fp_stdout,"%s: ERROR Option -a appears more than once\n",nco_prg_nm); (void)fprintf(fp_stdout,"%s: HINT Use -a dim1,dim2,... not -a dim1 -a dim2 ...\n",nco_prg_nm); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* endif */ dmn_avg_lst_in=nco_lst_prs_2D(optarg,",",&dmn_avg_nbr); break; case 'B': /* Mask string to be parsed */ msk_cnd_sng=(char *)strdup(optarg); #ifdef _MSC_VER (void)fprintf(fp_stdout,"%s: ERROR -B and --mask_condition options unsupported on Windows, which lacks a free, standard parser and lexer. HINT: Break condition into component -m -T -M switches, e.g., use -m ORO -T lt -M 1.0 instead of -B \"ORO < 1\"\n",nco_prg_nm); nco_exit(EXIT_FAILURE); #endif /* !_MSC_VER */ break; case 'b': /* [flg] Retain degenerate dimensions */ flg_rdd=True; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'G': /* Apply Group Path Editing (GPE) to output group */ /* NB: GNU getopt() optional argument syntax is ugly (requires "=" sign) so avoid it http://stackoverflow.com/questions/1052746/getopt-does-not-parse-optional-arguments-to-parameters */ gpe=nco_gpe_prs_arg(optarg); fl_out_fmt=NC_FORMAT_NETCDF4; break; case 'g': /* Copy group argument for later processing */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); grp_lst_in=nco_lst_prs_2D(optarg_lcl,",",&grp_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'I': /* [flg] Weight and/or mask coordinate variables */ WGT_MSK_CRD_VAR=!WGT_MSK_CRD_VAR; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'm': /* Name of variable to use as mask in reducing. Default is none */ msk_nm=(char *)strdup(optarg); break; case 'M': /* Good data defined by relation to mask value. Default is 1. */ msk_val=strtod(optarg,&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtod",sng_cnv_rcd); break; case 'N': NRM_BY_DNM=False; NORMALIZE_BY_TALLY=False; NORMALIZE_BY_WEIGHT=False; break; case 'n': NORMALIZE_BY_WEIGHT=False; (void)fprintf(fp_stdout,"%s: ERROR This option has been disabled while I rethink its implementation\n",nco_prg_nm); nco_exit(EXIT_FAILURE); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 'T': /* Relational operator type. Default is 0, eq, equality */ op_typ_rlt=nco_op_prs_rlt(optarg); break; case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'W': NORMALIZE_BY_TALLY=False; (void)fprintf(fp_stdout,"%s: ERROR This option has been disabled while I rethink its implementation\n",nco_prg_nm); nco_exit(EXIT_FAILURE); break; case 'w': /* Variable to use as weight in reducing. Default is none */ wgt_nm=(char *)strdup(optarg); break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'y': /* Operation type */ nco_op_typ_sng=(char *)strdup(optarg); nco_op_typ=nco_op_typ_get(nco_op_typ_sng); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Initialize traversal table */ trv_tbl_init(&trv_tbl); /* Parse mask string */ #ifndef _MSC_VER if(msk_cnd_sng){ int cst_zero=0; /* Set arguments for scan */ prs_arg.fl_in=NULL; /* [sng] Input data file */ prs_arg.in_id=0; /* [id] Input data file ID */ prs_arg.fl_out=NULL; /* [sng] Output data file */ prs_arg.out_id=0; /* [id] Output data file ID */ prs_arg.att_lst=NULL; /* [sct] Attributes in script */ prs_arg.nbr_att=&cst_zero; /* [nbr] Number of attributes in script */ prs_arg.dmn_in=NULL; /* [dmn_in] List of all dimensions in input */ prs_arg.nbr_dmn_in=0; /* [nbr] Number of dimensions in input */ prs_arg.dmn_out=NULL; /* [sct] Pointer to output dimension list */ prs_arg.nbr_dmn_out=&cst_zero; /* [nbr] Number of dimensions in output list */ prs_arg.sym_tbl=NULL; /* [fnc] Symbol table for functions */ prs_arg.sym_tbl_nbr=0; /* [nbr] Number of functions in table */ prs_arg.ntl_scn=False; /* [flg] Initial scan of script */ prs_arg.var_LHS=NULL; /* [var] LHS cast variable */ prs_arg.nco_op_typ=nco_op_nil; /* [enm] Operation type */ /* Initialize line counter */ ncap_ln_nbr_crr=(size_t *)nco_realloc(ncap_ln_nbr_crr,ncap_ncl_dpt_crr+1UL); ncap_ln_nbr_crr[ncap_ncl_dpt_crr]=1UL; /* [cnt] Line number incremented in ncap.l */ if(ncap_ncwa_scn(&prs_arg,msk_cnd_sng,&msk_nm,&msk_val,&op_typ_rlt) == 0) nco_exit(EXIT_FAILURE); } /* endif msk_cnd_sng */ #endif /* _MSC_VER */ /* Ensure we do not attempt to normalize by non-existent weight */ if(wgt_nm == NULL) NORMALIZE_BY_WEIGHT=False; /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); (void)nco_inq_format(in_id,&fl_in_fmt); /* Construct GTT, Group Traversal Table (groups,variables,dimensions, limits) */ (void)nco_bld_trv_tbl(in_id,trv_pth,lmt_nbr,lmt_arg,aux_nbr,aux_arg,MSA_USR_RDR,FORTRAN_IDX_CNV,grp_lst_in,grp_lst_in_nbr,var_lst_in,xtr_nbr,EXTRACT_ALL_COORDINATES,GRP_VAR_UNN,EXCLUDE_INPUT_LIST,EXTRACT_ASSOCIATED_COORDINATES,&flg_dne,trv_tbl); /* Get number of variables, dimensions, and global attributes in file, file format */ (void)trv_tbl_inq((int *)NULL,(int *)NULL,(int *)NULL,&nbr_dmn_fl,(int *)NULL,(int *)NULL,(int *)NULL,(int *)NULL,&nbr_var_fl,trv_tbl); /* Allocate array of dimensions associated with variables to be extracted with maximum possible size */ dim=(dmn_sct **)nco_malloc(nbr_dmn_fl*sizeof(dmn_sct *)); /* Find dimensions associated with variables to be extracted */ (void)nco_dmn_lst_ass_var_trv(in_id,trv_tbl,&nbr_dmn_xtr,&dim); /* Not specifying any dimensions is interpreted as specifying all dimensions */ if(dmn_avg_nbr == 0){ dmn_avg_nbr=nbr_dmn_xtr; dmn_avg_lst_in=(char **)nco_malloc(dmn_avg_nbr*sizeof(char *)); for(idx=0;idxnm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO No dimensions specified with -a, therefore reducing (averaging, taking minimum, etc.) over all dimensions\n",nco_prg_nm); } /* end if dmn_avg_nbr == 0 */ /* Allocate array of dimensions to average with maximum possible size */ dmn_avg=(dmn_sct **)nco_malloc(nbr_dmn_fl*sizeof(dmn_sct *)); /* Allocate array of dimensions to keep on output with maximum possible size */ dmn_out=(dmn_sct **)nco_malloc(nbr_dmn_fl*sizeof(dmn_sct *)); /* Create list of dimensions to average */ (void)nco_dmn_avg_mk(in_id,dmn_avg_lst_in,dmn_avg_nbr,flg_rdd,trv_tbl,&dmn_avg,&dmn_avg_nbr); /* Create list of dimensions to keep on output */ (void)nco_dmn_out_mk(dim,nbr_dmn_xtr,trv_tbl,&dmn_out,&nbr_dmn_out); dmn_avg=(dmn_sct **)nco_realloc(dmn_avg,dmn_avg_nbr*sizeof(dmn_sct *)); dmn_out=(dmn_sct **)nco_realloc(dmn_out,nbr_dmn_out*sizeof(dmn_sct *)); /* Transfer degenerated dimensions information into GTT */ (void)nco_dmn_dgn_tbl(dmn_out,nbr_dmn_out,trv_tbl); /* Fill-in variable structure list for all extracted variables. NOTE: Using GTT version */ var=nco_fll_var_trv(in_id,&xtr_nbr,trv_tbl); /* Duplicate to output array */ var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); for(idx=0;idx= nco_dbg_var){ for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var[idx]->nm,var[idx]->id); for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var_fix[idx]->nm,var_fix[idx]->id); for(idx=0;idxnm = %s, ->id=[%d]\n",idx,var_prc[idx]->nm,var_prc[idx]->id); } /* end if */ /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt; /* Verify output file format supports requested actions */ (void)nco_fl_fmt_vet(fl_out_fmt,cnk_nbr,dfl_lvl); /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); /* Create structure with all chunking information */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) rcd+=nco_cnk_ini(fl_out,cnk_arg,cnk_nbr,cnk_map,cnk_plc,cnk_sz_byt,cnk_sz_scl,&cnk); /* Define dimensions, extracted groups, variables, and attributes in output file. */ (void)nco_xtr_dfn(in_id,out_id,&cnk,dfl_lvl,gpe,md5,True,True,nco_pck_plc_nil,(char *)NULL,trv_tbl); /* Catenate time-stamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); /* Add new missing values to output file while in define mode */ if(msk_nm){ for(idx=0;idxnm_fll,trv_tbl); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; /* Define for var_prc_out because mss_val for var_prc will be overwritten in nco_var_mtd_refresh() */ if(!var_prc_out[idx]->has_mss_val){ var_prc_out[idx]->has_mss_val=True; var_prc_out[idx]->mss_val=nco_mss_val_mk(var_prc[idx]->type); (void)nco_put_att(grp_out_id,var_prc_out[idx]->id,nco_mss_val_sng_get(),var_prc_out[idx]->type,1,var_prc_out[idx]->mss_val.vp); } /* end if */ } /* end for */ } /* end if */ /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Add cell_methods attributes (before exiting define mode) */ if(flg_cll_mth) rcd+=nco_cnv_cf_cll_mth_add(out_id,var_prc_out,nbr_var_prc,dmn_avg,dmn_avg_nbr,nco_op_typ,gpe,trv_tbl); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Assign zero to start and unity to stride vectors in output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr); /* Copy variable data for non-processed variables */ (void)nco_cpy_fix_var_trv(in_id,out_id,gpe,trv_tbl); /* Close first input netCDF file */ nco_close(in_id); /* Loop over input files (not currently used, fl_nbr == 1) */ for(fl_idx=0;fl_idx= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in); /* Make sure file is on local system and is readable or die trying */ if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(nco_dbg_lvl >= nco_dbg_fl && FL_RTR_RMT_LCN) (void)fprintf(stderr,", local file is %s",fl_in); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ for(thr_idx=0;thr_idxnm_fll,trv_tbl); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(in_id,var_trv->grp_nm_fll,&grp_id); if(nco_dbg_lvl >= nco_dbg_var && nco_dbg_lvl < nco_dbg_nbr) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var && nco_dbg_lvl < nco_dbg_nbr) (void)fflush(fp_stderr); /* Allocate and, if necessary, initialize accumulation space for all processed variables */ var_prc_out[idx]->sz=var_prc[idx]->sz; /* fxm: verify that var_prc->tally is not needed */ if((var_prc_out[idx]->tally=(long *)nco_malloc_flg(var_prc_out[idx]->sz*sizeof(long))) == NULL){ (void)fprintf(fp_stdout,"%s: ERROR Unable to malloc() %ld*%ld bytes for tally buffer for variable %s in main()\n",nco_prg_nm_get(),var_prc_out[idx]->sz,(long)sizeof(long),var_prc_out[idx]->nm); nco_exit(EXIT_FAILURE); } /* end if err */ (void)nco_zero_long(var_prc_out[idx]->sz,var_prc_out[idx]->tally); if((var_prc_out[idx]->val.vp=(void *)nco_malloc_flg(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type))) == NULL){ (void)fprintf(fp_stdout,"%s: ERROR Unable to malloc() %ld*%lu bytes for value buffer for variable %s in main()\n",nco_prg_nm_get(),var_prc_out[idx]->sz,(unsigned long)nco_typ_lng(var_prc_out[idx]->type),var_prc_out[idx]->nm); nco_exit(EXIT_FAILURE); } /* end if err */ (void)nco_var_zero(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->val); (void)nco_var_mtd_refresh(grp_id,var_prc[idx]); /* Retrieve variable from disk into memory */ (void)nco_msa_var_get_trv(in_id,var_prc[idx],trv_tbl); /* Convert char, short, long, int types to doubles before arithmetic */ var_prc[idx]=nco_typ_cnv_rth(var_prc[idx],nco_op_typ); var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); /* Check mask found for this variable, using msk */ if(msk && (!var_prc[idx]->is_crd_var || WGT_MSK_CRD_VAR)){ msk_out=nco_var_cnf_dmn(var_prc[idx],msk,msk_out,MUST_CONFORM,&DO_CONFORM_MSK); /* If msk and var did not conform then do not mask var! */ if(DO_CONFORM_MSK){ msk_out=nco_var_cnf_typ(var_prc[idx]->type,msk_out); /* mss_val for var_prc has been overwritten in nco_var_mtd_refresh() */ if(!var_prc[idx]->has_mss_val){ var_prc[idx]->has_mss_val=True; var_prc[idx]->mss_val=nco_mss_val_mk(var_prc[idx]->type); } /* end if */ /* Mask by changing variable to missing value where condition is false */ (void)nco_var_msk(var_prc[idx]->type,var_prc[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,msk_val,op_typ_rlt,msk_out->val,var_prc[idx]->val); } /* end if */ } /* end if */ /* Perform non-linear transformations before weighting */ if(!var_prc[idx]->is_crd_var){ switch(nco_op_typ){ case nco_op_avgsqr: /* Square variable before weighting */ case nco_op_rms: /* Square variable before weighting */ case nco_op_rmssdn: /* Square variable before weighting */ (void)nco_var_mlt(var_prc[idx]->type,var_prc[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->val,var_prc[idx]->val); break; default: /* All other operations are linear, do nothing to them yet */ break; } /* end case */ } /* var_prc[idx]->is_crd_var */ /* Check weight found for this variable, using wgt */ if(wgt && (!var_prc[idx]->is_crd_var || WGT_MSK_CRD_VAR)){ /* fxm: nco_var_cnf_dmn() has bug where it does not allocate tally array for weights that do already conform to var_prc. TODO #114. */ wgt_out=nco_var_cnf_dmn(var_prc[idx],wgt,wgt_out,MUST_CONFORM,&DO_CONFORM_WGT); if(DO_CONFORM_WGT){ wgt_out=nco_var_cnf_typ(var_prc[idx]->type,wgt_out); /* Weight after any initial non-linear operation so, e.g., variable is squared but not weights */ /* Weight variable by taking product of weight and variable */ (void)nco_var_mlt(var_prc[idx]->type,var_prc[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,wgt_out->val,var_prc[idx]->val); } /* end if weights conformed */ } /* end if weight was specified and then tested for conformance */ /* Copy (masked) (weighted) values from var_prc to var_prc_out */ (void)memcpy((void *)(var_prc_out[idx]->val.vp),(void *)(var_prc[idx]->val.vp),var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type)); /* 20050516: fxm: destruction of var_prc_out in nco_var_avg() leaves dangling pointers in var_out? */ /* Reduce variable over specified dimensions (tally array is set here) NB: var_prc_out[idx] is new, so corresponding var_out[idx] is dangling nco_var_avg() will perform nco_op_typ on all variables except coordinate variables nco_var_avg() always performs averaging on coordinate variables */ var_prc_out[idx]=nco_var_avg(var_prc_out[idx],dmn_avg,dmn_avg_nbr,nco_op_typ,flg_rdd,&ddra_info); /* var_prc_out[idx]->val now holds numerator of averaging expression documented in NCO User's Guide Denominator is also tricky due to sundry normalization options These logical switches are VERY tricky---be careful modifying them */ if(NRM_BY_DNM && DO_CONFORM_WGT && (!var_prc[idx]->is_crd_var || WGT_MSK_CRD_VAR)){ /* Duplicate wgt_out as wgt_avg so that wgt_out is not contaminated by any averaging operation and may be re-used on next variable. Free wgt_avg after each use but continue to re-use wgt_out */ wgt_avg=nco_var_dpl(wgt_out); if(var_prc[idx]->has_mss_val){ double mss_val_dbl=double_CEWI; /* Set denominator to missing value at all locations where variable is missing value If this is accomplished by setting weight to missing value wherever variable is missing value then weight must not be re-used by next variable (which might conform but have missing values in different locations) This is one good reason to copy wgt_out into disposable wgt_avg for each new variable */ /* First, make sure wgt_avg has same missing value as variable */ (void)nco_mss_val_cp(var_prc[idx],wgt_avg); /* Copy missing value into double precision variable */ switch(wgt_avg->type){ case NC_FLOAT: mss_val_dbl=wgt_avg->mss_val.fp[0]; break; case NC_DOUBLE: mss_val_dbl=wgt_avg->mss_val.dp[0]; break; case NC_INT: mss_val_dbl=wgt_avg->mss_val.ip[0]; break; case NC_SHORT: mss_val_dbl=wgt_avg->mss_val.sp[0]; break; case NC_USHORT: mss_val_dbl=wgt_avg->mss_val.usp[0]; break; case NC_UINT: mss_val_dbl=wgt_avg->mss_val.uip[0]; break; case NC_INT64: mss_val_dbl=wgt_avg->mss_val.i64p[0]; break; case NC_UINT64: mss_val_dbl=wgt_avg->mss_val.ui64p[0]; break; case NC_BYTE: mss_val_dbl=wgt_avg->mss_val.bp[0]; break; case NC_UBYTE: mss_val_dbl=wgt_avg->mss_val.ubp[0]; break; case NC_CHAR: mss_val_dbl=wgt_avg->mss_val.cp[0]; break; case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Second, mask wgt_avg where variable is missing value */ (void)nco_var_msk(wgt_avg->type,wgt_avg->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,mss_val_dbl,nco_op_ne,var_prc[idx]->val,wgt_avg->val); } /* endif weight must be checked for missing values */ /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); if(msk && DO_CONFORM_MSK){ /* Must mask weight in same fashion as variable was masked If msk and var did not conform then do not mask wgt Ensure wgt_avg has a missing value */ if(!wgt_avg->has_mss_val){ wgt_avg->has_mss_val=True; wgt_avg->mss_val=nco_mss_val_mk(wgt_avg->type); } /* end if */ /* Mask by changing weight to missing value where condition is false */ (void)nco_var_msk(wgt_avg->type,wgt_avg->sz,wgt_avg->has_mss_val,wgt_avg->mss_val,msk_val,op_typ_rlt,msk_out->val,wgt_avg->val); } /* endif weight must be masked */ /* fxm: temporary kludge to make sure weight has tally space wgt_avg may lack valid tally array in ncwa because wgt_avg is created, sometimes, before the tally array for var_prc_out[idx] is created. When this occurs the nco_var_dpl() call in nco_var_cnf_dmn() does not copy tally array into wgt_avg. See related note about this above. TODO #114.*/ if(wgt_avg->sz > 0) if((wgt_avg->tally=(long *)nco_realloc(wgt_avg->tally,wgt_avg->sz*sizeof(long))) == NULL){ (void)fprintf(fp_stdout,"%s: ERROR Unable to realloc() %ld*%ld bytes for tally buffer for weight %s in main()\n",nco_prg_nm_get(),wgt_avg->sz,(long)sizeof(long),wgt_avg->nm); nco_exit(EXIT_FAILURE); } /* end if */ /* Average weight over specified dimensions (tally array is set here) */ wgt_avg=nco_var_avg(wgt_avg,dmn_avg,dmn_avg_nbr,nco_op_avg,flg_rdd,&ddra_info); if(MULTIPLY_BY_TALLY){ /* NB: Currently this is not implemented */ /* Multiply numerator (weighted sum of variable) by tally We deviously accomplish this by dividing denominator by tally */ (void)nco_var_nrm(wgt_avg->type,wgt_avg->sz,wgt_avg->has_mss_val,wgt_avg->mss_val,wgt_avg->tally,wgt_avg->val); } /* endif */ /* Divide numerator by denominator */ /* Diagnose common PEBCAK before it causes core dump */ if(var_prc_out[idx]->sz == 1L && var_prc_out[idx]->type == NC_INT && var_prc_out[idx]->val.ip[0] == 0){ (void)fprintf(fp_stdout,"%s: ERROR Weight in denominator weight = 0.0, will cause SIGFPE\n%s: HINT Sum of masked, averaged weights must be non-zero\n%s: HINT A possible workaround is to remove variable \"%s\" from output file using \"%s -x -v %s ...\"\n%s: Expecting core dump...now!\n",nco_prg_nm,nco_prg_nm,nco_prg_nm,var_prc_out[idx]->nm,nco_prg_nm,var_prc_out[idx]->nm,nco_prg_nm); } /* end if */ /* Rather complex conditional statement is shorter than switch() */ if( /* Normalize by weighted tally if .... */ (nco_op_typ != nco_op_min) && /* ...operation is not min() and... */ (nco_op_typ != nco_op_max) && /* ...operation is not max() and... */ (nco_op_typ != nco_op_ttl || /* ...operation is not ttl() or... */ var_prc[idx]->is_crd_var) /* ...variable is a coordinate */ ){ /* Divide numerator by masked, averaged, weights */ (void)nco_var_dvd(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,wgt_avg->val,var_prc_out[idx]->val); } /* endif */ /* Free wgt_avg, but keep wgt_out, after each use */ if(wgt_avg) wgt_avg=nco_var_free(wgt_avg); /* End of branch for normalization when weights were specified */ }else if(NRM_BY_DNM){ /* Branch for normalization when no weights were specified Normalization is just due to tally */ if(var_prc[idx]->is_crd_var){ /* Always return averages (never extrema or other statistics) of coordinates Prevent coordinate variables from encountering nco_var_nrm_sdn() */ (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->tally,var_prc_out[idx]->val); }else{ /* !var_prc[idx]->is_crd_var */ switch(nco_op_typ){ case nco_op_avg: /* Normalize sum by tally to create mean */ case nco_op_sqravg: /* Normalize sum by tally to create mean */ case nco_op_avgsqr: /* Normalize sum of squares by tally to create mean square */ case nco_op_rms: /* Normalize sum of squares by tally to create mean square */ case nco_op_sqrt: /* Normalize sum by tally to create mean */ (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->tally,var_prc_out[idx]->val); break; case nco_op_rmssdn: /* Normalize sum of squares by tally-1 to create mean square for sdn */ (void)nco_var_nrm_sdn(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->tally,var_prc_out[idx]->val); break; case nco_op_min: /* Minimum is already in buffer, do nothing */ case nco_op_max: /* Maximum is already in buffer, do nothing */ case nco_op_ttl: /* Total is already in buffer, do nothing */ break; default: (void)fprintf(fp_stdout,"%s: ERROR Illegal nco_op_typ in non-weighted normalization\n",nco_prg_nm); nco_exit(EXIT_FAILURE); break; } /* end switch */ } /* !var_prc[idx]->is_crd_var */ }else if(!NRM_BY_DNM){ /* User turned off normalization so we are done */ ; }else{ (void)fprintf(fp_stdout,"%s: ERROR Unforeseen logical branch in main()\n",nco_prg_nm); nco_exit(EXIT_FAILURE); } /* end if */ /* Some non-linear operations require additional processing */ if(!var_prc[idx]->is_crd_var){ switch(nco_op_typ){ case nco_op_sqravg: /* Square mean to create square of the mean (for sdn) */ (void)nco_var_mlt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->val,var_prc_out[idx]->val); break; case nco_op_sqrt: /* Take root of mean to create root mean */ case nco_op_rms: /* Take root of mean of sum of squares to create root mean square */ case nco_op_rmssdn: /* Take root of sdn mean of sum of squares to create root mean square for sdn */ (void)nco_var_sqrt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->tally,var_prc_out[idx]->val,var_prc_out[idx]->val); break; default: break; } /* end switch */ } /* var_prc[idx]->is_crd_var */ /* Free tally buffer */ var_prc_out[idx]->tally=(long *)nco_free(var_prc_out[idx]->tally); /* Revert any arithmetic promotion but leave unpacked (for now) */ var_prc_out[idx]=nco_var_cnf_typ(var_prc_out[idx]->typ_upk,var_prc_out[idx]); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ { /* begin OpenMP critical */ /* Copy average to output file then free averaging buffer */ if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); }else{ /* end if variable is scalar */ (void)nco_put_vara(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end if variable is array */ } /* end OpenMP critical */ if(flg_ddra){ /* DDRA diagnostics Usage: ncwa -O -C --mdl -a lat,lon,time -w lat ~/nco/data/in.nc ~/foo.nc ncwa -O -C --mdl -a lat,lon -w lat ${DATA}/nco_bm/stl_5km.nc ~/foo.nc ncwa -O -C --mdl -a lat,lon,time -w lat ${DATA}/nco_bm/gcm_T85.nc ~/foo.nc */ /* Assign remaining input for DDRA diagnostics */ ddra_info.lmn_nbr=var_prc[idx]->sz; /* [nbr] Variable size */ if(wgt) ddra_info.lmn_nbr_wgt=wgt->sz; /* [nbr] Weight size */ ddra_info.nco_op_typ=nco_op_typ; /* [enm] Operation type */ ddra_info.rnk_var=var_prc[idx]->nbr_dim; /* I [nbr] Variable rank (in input file) */ if(wgt) ddra_info.rnk_wgt=wgt->nbr_dim; /* [nbr] Rank of weight */ ddra_info.var_idx=idx; /* [enm] Index */ ddra_info.wrd_sz=nco_typ_lng(var_prc[idx]->type); /* [B] Bytes per element */ /* DDRA diagnostics */ rcd+=nco_ddra /* [fnc] Count operations */ (var_prc[idx]->nm, /* I [sng] Variable name */ wgt_nm, /* I [sng] Weight name */ &ddra_info); /* I [sct] DDRA information */ } /* !flg_ddra */ /* Free current output buffer */ var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); /* Free possible weight/mask found */ if(wgt) wgt=nco_var_free(wgt); if(wgt_out) wgt_out=nco_var_free(wgt_out); if(msk) msk=nco_var_free(msk); if(msk_out) msk_out=nco_var_free(msk_out); } /* end (OpenMP parallel for) loop over idx */ if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(stderr,"\n"); /* Close input netCDF file */ for(thr_idx=0;thr_idx 0) dmn_avg=(dmn_sct **)nco_free(dmn_avg); if(msk_nm) msk_nm=(char *)nco_free(msk_nm); if(msk_cnd_sng) msk_cnd_sng=(char *)nco_free(msk_cnd_sng); if(wgt_avg) wgt_avg=nco_var_free(wgt_avg); if(wgt_nm) wgt_nm=(char *)nco_free(wgt_nm); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_arr) in_id_arr=(int *)nco_free(in_id_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free chunking information */ for(idx=0;idx 0) cnk.cnk_dmn=(cnk_dmn_sct **)nco_cnk_lst_free(cnk.cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_out > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_out); /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); /* ncwa uses nco_var_lst_free() on var_prc_out because var_out has dangling pointers */ if(nbr_var_fix > 0) var_fix_out=nco_var_lst_free(var_fix_out,nbr_var_fix); if(nbr_var_prc > 0) var_prc_out=nco_var_lst_free(var_prc_out,nbr_var_prc); var_prc=(var_sct **)nco_free(var_prc); var_fix=(var_sct **)nco_free(var_fix); var_out=(var_sct **)nco_free(var_out); for(idx=0;idx /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* assert() debugging macro */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #include /* POSIX stuff */ #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* Internationalization i18n, Linux Journal 200211 p. 57--59 */ #ifdef I18N #include /* Internationalization i18n */ #include /* Locale setlocale() */ #define _(sng) gettext (sng) #define gettext_noop(sng) (sng) #define N_(sng) gettext_noop(sng) #endif /* I18N */ #ifndef _LIBINTL_H # define gettext(foo) foo #endif /* _LIBINTL_H */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #ifdef ENABLE_MPI #include /* MPI definitions */ #include "nco_mpi.h" /* MPI utilities */ #endif /* !ENABLE_MPI */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ #ifdef ENABLE_MPI void checkpointMpi(int prc_rnk, int stage){ int msg[]={0,0}; int rcd; /* [rcd] Return code */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ if(prc_rnk == rnk_mgr){ msg[0]=stage; msg[1]=stage; } /* endif */ (void)fprintf(fp_stderr,"%d checkpointing at stage %d\n",prc_rnk,stage); /* make everyone continue from this point. */ rcd=MPI_Bcast(msg,2,MPI_INT,rnk_mgr,MPI_COMM_WORLD); if(prc_rnk != rnk_mgr) { /* basic sanity check */ assert(msg[0] == stage); assert(msg[1] == stage); } /* end if */ } /* end checkpointMpi() */ #endif /* !ENABLE_MPI */ int main(int argc,char **argv) { nco_bool CNV_ARM; nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_APPEND=True; /* Option H */ nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool LAST_RECORD=False; nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in; char **var_lst_in=NULL_CEWI; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *nco_op_typ_sng=NULL_CEWI; /* [sng] Operation type Option y */ char *nco_pck_plc_sng=NULL_CEWI; /* [sng] Packing policy Option P */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ const char * const CVS_Id="$Id: mpncra.c,v 1.150 2014/01/06 06:46:05 zender Exp $"; const char * const CVS_Revision="$Revision: 1.150 $"; const char * const opt_sht_lst="3467ACcD:d:FHhL:l:n:Oo:p:P:rRSt:v:xY:y:-:"; dmn_sct **dim; dmn_sct **dmn_out; extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ int *in_id_arr; int abb_arg_nbr=0; int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_idx; int fl_nbr=0; int fl_in_fmt; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx=int_CEWI; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_xtr; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int nco_op_typ=nco_op_avg; /* [enm] Default operation is averaging */ int nco_pck_plc=nco_pck_plc_nil; /* [enm] Default packing is none */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int rec_dmn_id=NCO_REC_DMN_UNDEFINED; int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; lmt_sct **lmt=NULL_CEWI; lmt_sct *lmt_rec=NULL_CEWI; lmt_all_sct **lmt_all_lst; /* List of *lmt_all structures */ lmt_all_sct *lmt_all_rec=NULL_CEWI; /* Pointer to record limit structure in above list */ long idx_rec; /* [idx] Index of current record in current input file */ long rec_usd_cml=0L; /* [idx] Index of current record in output file (0 is first, ...) */ nco_int base_time_srt=nco_int_CEWI; nco_int base_time_crr=nco_int_CEWI; nm_id_sct *dmn_lst; nm_id_sct *xtr_lst=NULL; /* xtr_lst may be alloc()'d from NULL with -c option */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out=NULL_CEWI; var_sct **var_prc; var_sct **var_prc_out; #ifdef ENABLE_MPI /* Declare all MPI-specific variables here */ MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */ nco_bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */ int fl_nm_lng; /* [nbr] Output file name length */ int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */ int jdx=0; /* [idx] MPI index for local variables */ int lcl_idx_lst[60]; /* [arr] Array containing indices of variables processed at each Worker */ int lcl_nbr_var=0; /* [nbr] Count of variables processes at each Worker */ int msg_tag_typ; /* [enm] MPI message tag type */ int prc_rnk; /* [idx] Process rank */ int prc_nbr=0; /* [nbr] Number of MPI processes */ int tkn_wrt_rnk=0; /* [idx] Rank of process holding write token */ int tkn_wrt_rsp; /* [enm] Response to request for write token */ int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */ int rnk_wrk; /* [idx] Worker rank */ int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */ #endif /* !ENABLE_MPI */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"fl_lst_in",no_argument,0,'H'}, {"file_list",no_argument,0,'H'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"nintap",required_argument,0,'n'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"pack",required_argument,0,'P'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"suspend", no_argument,0,'S'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"pseudonym",required_argument,0,'Y'}, {"program",required_argument,0,'Y'}, {"prg_nm",required_argument,0,'Y'}, {"math",required_argument,0,'y'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ #ifdef _LIBINTL_H setlocale(LC_ALL,""); /* LC_ALL sets all localization tokens to same value */ bindtextdomain("nco","/home/zender/share/locale"); /* ${LOCALEDIR} is e.g., /usr/share/locale */ /* MO files should be in ${LOCALEDIR}/es/LC_MESSAGES */ textdomain("nco"); /* PACKAGE is name of program */ #endif /* not _LIBINTL_H */ #ifdef ENABLE_MPI /* MPI Initialization */ MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr); MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk); #endif /* !ENABLE_MPI */ /* Start clock and save command line */ cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'H': /* Toggle writing input file list attribute */ FL_LST_IN_APPEND=!FL_LST_IN_APPEND; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'n': /* NINTAP-style abbreviation of files to average */ fl_lst_abb=nco_lst_prs_2D(optarg,",",&abb_arg_nbr); if(abb_arg_nbr < 1 || abb_arg_nbr > 5){ (void)fprintf(stdout,gettext("%s: ERROR Incorrect abbreviation for file list\n"),nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end if */ break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'P': /* Packing policy */ nco_pck_plc_sng=(char *)strdup(optarg); nco_pck_plc=nco_pck_plc_get(nco_pck_plc_sng); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; #ifdef ENABLE_MPI case 'S': /* Suspend with signal handler to facilitate debugging */ if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stderr,"%s: ERROR Could not install suspend handler.\n",nco_prg_nm_get()); while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */ break; #endif /* !ENABLE_MPI */ case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'Y': /* Pseudonym */ /* Call nco_prg_prs to reset pseudonym */ optarg_lcl=(char *)strdup(optarg); if(nco_prg_nm) nco_prg_nm=(char *)nco_free(nco_prg_nm); nco_prg_nm=nco_prg_prs(optarg_lcl,&nco_prg_id); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'y': /* Operation type */ nco_op_typ_sng=(char *)strdup(optarg); if(nco_prg_id == ncra || nco_prg_id == ncfe || nco_prg_id == ncge) nco_op_typ=nco_op_typ_get(nco_op_typ_sng); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Make uniform list of user-specified chunksizes */ if(cnk_nbr > 0) cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Make uniform list of user-specified dimension limits */ if(lmt_nbr > 0) lmt=nco_lmt_prs(lmt_nbr,lmt_arg); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); /* Get number of variables, dimensions, and record dimension ID of input file */ (void)nco_inq(in_id,&nbr_dmn_fl,&nbr_var_fl,(int *)NULL,&rec_dmn_id); (void)nco_inq_format(in_id,&fl_in_fmt); /* Form initial extraction list which may include extended regular expressions */ xtr_lst=nco_var_lst_mk(in_id,nbr_var_fl,var_lst_in,EXCLUDE_INPUT_LIST,EXTRACT_ALL_COORDINATES,&xtr_nbr); /* Change included variables to excluded variables */ if(EXCLUDE_INPUT_LIST) xtr_lst=nco_var_lst_xcl(in_id,nbr_var_fl,xtr_lst,&xtr_nbr); /* Is this a CCM/CCSM/CF-format history tape? */ CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id); /* Add all coordinate variables to extraction list */ if(EXTRACT_ALL_COORDINATES) xtr_lst=nco_var_lst_crd_add(in_id,nbr_dmn_fl,nbr_var_fl,xtr_lst,&xtr_nbr,CNV_CCM_CCSM_CF); /* Extract coordinates associated with extracted variables */ if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst=nco_var_lst_crd_ass_add(in_id,xtr_lst,&xtr_nbr,CNV_CCM_CCSM_CF); /* Sort extraction list by variable ID for fastest I/O */ if(xtr_nbr > 1) xtr_lst=nco_lst_srt_nm_id(xtr_lst,xtr_nbr,False); /* We now have final list of variables to extract. Phew. */ /* Find coordinate/dimension values associated with user-specified limits NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ for(idx=0;idx 0) (void)nco_dmn_lmt_all_mrg(dmn_out,nbr_dmn_xtr,lmt_all_lst,nbr_dmn_fl); /* Duplicate input dimension structures for output dimension structures */ dmn_out=(dmn_sct **)nco_malloc(nbr_dmn_xtr*sizeof(dmn_sct *)); for(idx=0;idxlmt_cln=cln_nil; lmt_rec->origin=0.0; lmt_rec->rbs_sng=NULL; /* Obtain metadata for record coordinate */ rcd=nco_inq_varid_flg(in_id,lmt_rec->nm,&var_id); if(rcd == NC_NOERR){ char *cln_att_sng=NULL; lmt_rec->rbs_sng=nco_lmt_get_udu_att(in_id,var_id,"units"); cln_att_sng=nco_lmt_get_udu_att(in_id,var_id,"calendar"); lmt_rec->lmt_cln=nco_cln_get_cln_typ(cln_att_sng); if(cln_att_sng) cln_att_sng=(char*)nco_free(cln_att_sng); }else{ /* endif record coordinate exists */ /* Record dimension, but not record coordinate, exists, which is fine. Reset return code. */ rcd=NC_NOERR; } /* endif record coordinate exists */ } /* endif ncra, ncrcat */ } /* endif record dimension exists */ if(rec_dmn_id != NCO_REC_DMN_UNDEFINED){ for(idx=0;idxnm,lmt_all_lst[idx]->dmn_nm)){ lmt_all_rec=lmt_all_lst[idx]; /* Can only have one record limit */ if(lmt_all_rec->lmt_dmn_nbr > 1L){ (void)fprintf(stdout,"%s: Although this program allows multiple hyperslab limits for a single dimension, it allows only one unwrapped limit for the record dimension \"%s\". You have specified %i.\n",nco_prg_nm_get(),lmt_all_rec->dmn_nm,lmt_all_rec->lmt_dmn_nbr); nco_exit(EXIT_FAILURE); } /* end if */ if(nco_prg_id==ncra || nco_prg_id==ncrcat){ /* Change record dim in lmt_all_lst so that cnt=1 */ lmt_all_lst[idx]->dmn_cnt=1L; lmt_all_lst[idx]->lmt_dmn[0]->srt=0L; lmt_all_lst[idx]->lmt_dmn[0]->end=0L; lmt_all_lst[idx]->lmt_dmn[0]->cnt=1L; lmt_all_lst[idx]->lmt_dmn[0]->srd=1L; } /* endif ncra || ncrcat */ break; } /* endif current limit applies to record dimension */ } /* end loop over all dimensions */ } /* end if file has record dimension */ /* Is this an ARM-format data file? */ CNV_ARM=nco_cnv_arm_inq(in_id); /* NB: nco_cnv_arm_base_time_get() with same nc_id contains OpenMP critical region */ if(CNV_ARM) base_time_srt=nco_cnv_arm_base_time_get(in_id); /* Fill-in variable structure list for all extracted variables */ var=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); for(idx=0;idx 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr); #endif /* !ENABLE_MPI */ if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); /* Define dimensions in output file */ (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_xtr); /* Define variables in output file, copy their attributes */ (void)nco_var_dfn(in_id,fl_out,out_id,var_out,xtr_nbr,(dmn_sct **)NULL,(int)0,nco_pck_plc_nil,nco_pck_map_nil,dfl_lvl); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ (void)nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ #ifdef ENABLE_MPI } /* prc_rnk != rnk_mgr */ /* Manager obtains output filename and broadcasts to workers */ if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); MPI_Bcast(&fl_nm_lng,1,MPI_INT,0,MPI_COMM_WORLD); if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char)); MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,0,MPI_COMM_WORLD); #endif /* !ENABLE_MPI */ /* Pre-processor token spaghetti here is necessary so that 1. UP/SMP/MPI codes all zero srt vectors before calling nco_var_val_cpy() 2. No codes zero srt vectors more than once */ /* Assign zero to start and unity to stride vectors in output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr); #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ TKN_WRT_FREE=False; #endif /* !ENABLE_MPI */ /* Copy variable data for non-processed variables */ /* (void)nco_var_val_cpy(in_id,out_id,var_fix,nbr_var_fix); */ (void)nco_msa_var_val_cpy(in_id,out_id,var_fix,nbr_var_fix,lmt_all_lst,nbr_dmn_fl); #ifdef ENABLE_MPI /* Close output file so workers can open it */ nco_close(out_id); TKN_WRT_FREE=True; } /* prc_rnk != rnk_mgr */ #else /* !ENABLE_MPI */ /* Close first input netCDF file (SMP only since MPI code immediate re-opens) */ (void)nco_close(in_id); #endif /* !ENABLE_MPI */ /* Allocate and, if necesssary, initialize accumulation space for processed variables */ for(idx=0;idxsz=var_prc[idx]->sz=var_prc[idx]->sz_rec; } /* endif */ if(nco_prg_id == ncra || nco_prg_id == ncfe){ var_prc_out[idx]->tally=var_prc[idx]->tally=(long *)nco_malloc(var_prc_out[idx]->sz*sizeof(long int)); (void)nco_zero_long(var_prc_out[idx]->sz,var_prc_out[idx]->tally); var_prc_out[idx]->val.vp=(void *)nco_malloc(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type)); (void)nco_var_zero(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->val); } /* end if */ } /* end loop over idx */ #ifdef ENABLE_MPI /* NB: Only manager code manipulates value of TKN_WRT_FREE Pass 1: Workers construct local persistant variable lists Open first file mpncra and mpncrcat process first record only mpnces ingests complete file Workers create local list of their variables Pass 2: Complete record/file loops with local variable lists Workers skip first timestep (mpncra/mpncrcat) Workers process only variables in their local list from Pass 1 This variable persistance is necessary for mpncra and mpnces since their workers must maintain running tallies for each variable. Variable persistance is not necessary for mpncrcat However, we do it anyway to keep mpncrcat and mpncra similar mpncrcat writes records as it reads them and finishes after pass 2 Pass 3: mpnces and mpncra require a final loop to normalize and write Write-token for this loop is passed sequentially through the ranks */ /* Begin Pass 1: Workers construct local persistant variable lists */ fl_idx=0; /* Variables may have different ID, missing_value, type, in each file */ for(idx=0;idx= nco_dbg_std && lmt_rec->srt > lmt_rec->end) (void)fprintf(stdout,gettext("%s: WARNING %s (input file %d) is superfluous\n"),nco_prg_nm_get(),fl_in,fl_idx); idx_rec=lmt_rec->srt; if(fl_idx == fl_nbr-1 && idx_rec >= 1L+lmt_rec->end-lmt_rec->srd) LAST_RECORD=True; /* Process all variables in first record */ if(nco_dbg_lvl > nco_dbg_scl) (void)fprintf(stderr,gettext("Record %ld of %s is output record %ld\n"),idx_rec,fl_in,rec_usd_cml); if(prc_rnk == rnk_mgr){ /* MPI manager code */ /* Compensate for incrementing on each worker's first message */ var_wrt_nbr=-prc_nbr+1; idx=0; /* While variables remain to be processed or written... */ while(var_wrt_nbr < nbr_var_prc){ /* Receive any message from any worker */ MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); /* Obtain MPI message tag type */ msg_tag_typ=mpi_stt.MPI_TAG; /* Get sender's prc_rnk */ rnk_wrk=wrk_id_bfr[0]; /* Allocate next variable, if any, to worker */ if(msg_tag_typ == msg_tag_wrk_rqs){ var_wrt_nbr++; /* [nbr] Number of variables written */ /* Worker closed output file before sending msg_tag_wrk_rqs */ if(nco_prg_id == ncrcat) TKN_WRT_FREE=True; /* File written to at this point only for ncrcat */ if(idx > nbr_var_prc-1){ msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ msg_bfr[1]=out_id; /* Output file ID */ }else{ /* Tell requesting worker to allocate space for next variable */ msg_bfr[0]=idx; /* [idx] Variable to be processed */ /* csz: fxm Workers do not need to know Master's out_id */ msg_bfr[1]=out_id; /* Output file ID */ msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ /* Point to next variable on list */ idx++; } /* endif idx */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs && nco_prg_id == ncrcat){ /* msg_tag_typ != msg_tag_wrk_rqs */ /* Allocate token if free, else ask worker to try later */ if(TKN_WRT_FREE){ TKN_WRT_FREE=False; msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ }else{ msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ } /* !TKN_WRT_FREE */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ } /* end while var_wrt_nbr < nbr_var_prc */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ /* csz: fxm delete redundant statement with two lines further down */ wrk_id_bfr[0]=prc_rnk; var_wrt_nbr=0; while(1){ /* While work remains... */ /* Send msg_tag_wrk_rqs */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); /* Receive msg_tag_wrk_rsp */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); idx=msg_bfr[0]; /* csz: fxm dangerous---workers must get and use their own out_id's, not master's out_id */ out_id=msg_bfr[1]; if(idx == idx_all_wrk_ass){ break; }else{ /* idx != idx_all_wrk_ass */ /* Assign this variable to this worker for rest of program */ lcl_idx_lst[lcl_nbr_var]=idx; /* csz: got to here reading logic */ lcl_nbr_var++; var_prc_out[idx]->id=msg_bfr[2]; if(nco_dbg_lvl >= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Update hyperslab start indices to current record for each variable */ var_prc[idx]->srt[0]=idx_rec; var_prc[idx]->end[0]=idx_rec; var_prc[idx]->cnt[0]=1L; /* Retrieve variable from disk into memory */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_var_get(in_id,var_prc[idx]); if(nco_prg_id == ncra){ /* Convert char, short, long, int types to doubles before arithmetic */ /* Output variable type is "sticky" so only convert on first record */ if(rec_usd_cml == 0) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); /* Convert var_prc to type of var_prc_out in case type of variable on disk has changed */ var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ nco_opr_drv(rec_usd_cml,nco_op_typ,var_prc[idx],var_prc_out[idx]); } /* !ncra */ /* Append current record to output file */ if(nco_prg_id == ncrcat){ var_prc_out[idx]->srt[0]=var_prc_out[idx]->end[0]=rec_usd_cml; var_prc_out[idx]->cnt[0]=1L; /* Replace this time_offset value with time_offset from initial file base_time */ if(CNV_ARM && !strcmp(var_prc[idx]->nm,"time_offset")) var_prc[idx]->val.dp[0]+=(base_time_crr-base_time_srt); /* Obtain token and prepare to write */ while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); tkn_wrt_rsp=msg_bfr[0]; /* Wait then re-send request */ if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; } /* end while loop waiting for write token */ /* Worker has token---prepare to write */ if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ if(RAM_OPEN) md_open=NC_WRITE|NC_SHARE|NC_DISKLESS; else md_open=NC_WRITE|NC_SHARE; rcd=nco_fl_open(fl_out_tmp,md_open,&bfr_sz_hnt,&out_id); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); if(var_prc_out[idx]->sz_rec > 1L) (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc[idx]->val.vp,var_prc_out[idx]->type); else (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc[idx]->val.vp,var_prc_out[idx]->type); /* Close output file and increment written counter */ nco_close(out_id); var_wrt_nbr++; } /* endif tkn_wrt_rqs_xcp */ } /* end if ncrcat */ /* Make sure record coordinate, if any, is monotonic */ if(nco_prg_id == ncrcat && var_prc[idx]->is_crd_var) (void)rec_crd_chk(var_prc[idx],fl_in,fl_out,idx_rec,rec_usd_cml); /* Convert missing_value, if any, back to unpacked type */ if(var_prc[idx]->has_mss_val && var_prc[idx]->type != var_prc[idx]->typ_upk && !LAST_RECORD) var_prc[idx]=nco_cnv_mss_val_typ(var_prc[idx],var_prc[idx]->typ_upk); /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(stderr,"\n"); } /* !idx_all_wrk_ass */ } /* while(1) loop requesting work/token in Worker */ rec_usd_cml++; /* [idx] Index of current record in output file (0 is first, ...) */ } /* endif Worker */ printf("DEBUG: End of first pass of ncra/ncrcat at node %d\n",prc_rnk); /* End of ncra, ncrcat section */ }else{ /* ncfe */ if(prc_rnk == rnk_mgr){ /* MPI manager code */ /* Compensate for incrementing on each worker's first message */ var_wrt_nbr=-prc_nbr+1; idx=0; /* While variables remain to be processed or written... */ while(var_wrt_nbr < nbr_var_prc){ /* Receive message from any worker */ MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); /* Obtain MPI message tag type */ msg_tag_typ=mpi_stt.MPI_TAG; /* Get sender's prc_rnk */ rnk_wrk=wrk_id_bfr[0]; /* Allocate next variable, if any, to worker */ if(msg_tag_typ == msg_tag_wrk_rqs){ var_wrt_nbr++; /* [nbr] Number of variables written */ /* Worker closed output file before sending msg_tag_wrk_rqs */ /* TKN_WRT_FREE=True; ncfe does not do file write here */ if(idx > nbr_var_prc-1){ msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ msg_bfr[1]=out_id; /* Output file ID */ }else{ /* Tell requesting worker to allocate space for next variable */ msg_bfr[0]=idx; /* [idx] Variable to be processed */ msg_bfr[1]=out_id; /* Output file ID */ msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ /* Point to next variable on list */ idx++; } /* endif idx */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_wrk_rqs */ } /* end while var_wrt_nbr < nbr_var_prc */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ while(1){ /* While work remains... */ /* Send msg_tag_wrk_rqs */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); /* Receive msg_tag_wrk_rsp */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); idx=msg_bfr[0]; out_id=msg_bfr[1]; if(idx == idx_all_wrk_ass) break; else{ lcl_idx_lst[lcl_nbr_var]=idx; /* storing the indices for subsequent processing by the worker */ lcl_nbr_var++; var_prc_out[idx]->id=msg_bfr[2]; if(nco_dbg_lvl >= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Retrieve variable from disk into memory */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_var_get(in_id,var_prc[idx]); /* Convert char, short, long, int types to doubles before arithmetic */ /* var_prc[idx]=nco_typ_cnv_rth(var_prc[idx],nco_op_typ); */ /* Output variable type is "sticky" so only convert on first record */ if(fl_idx == 0) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); /* Convert var_prc to type of var_prc_out in case type of variable on disk has changed */ var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ /* Note: fl_idx not rec_usd_cml! */ nco_opr_drv(fl_idx,nco_op_typ,var_prc[idx],var_prc_out[idx]); /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* !idx_all_wrk_ass */ } /* while(1) loop requesting work/token in Worker */ } /* endif Worker */ } /* end else ncfe */ if(nco_dbg_lvl > nco_dbg_scl) (void)fprintf(stderr,"\n"); /* Close input netCDF file */ nco_close(in_id); #ifdef ENABLE_MPI /* This barrier ensures that all nodes have reached this point together. Otherwise, the manager code should be altered so it can deal with nodes in different stages of execution at any time. Daniel: I think we should be convinced of this parallelization structure before bothering with implementing the code restructuring in the manager that would let us remove the barrier. The barrier should only negligibly impact performance. */ checkpointMpi(prc_rnk, 1); #endif /* ENABLE_MPI */ /* End Pass 1: Workers construct local persistant variable lists */ printf("DEBUG: prc_rnk %d is done with 1st pass\n",prc_rnk); /* Begin Pass 2: Complete record/file loops with local variable lists */ #endif /* !ENABLE_MPI */ /* Loop over input files */ for(fl_idx=0;fl_idx= nco_dbg_fl) (void)fprintf(stderr,gettext("\nInput file %d is %s; "),fl_idx,fl_in); /* Make sure file is on local system and is readable or die trying */ if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,gettext("local file %s:\n"),fl_in); /* Open file once per thread to improve caching */ for(thr_idx=0;thr_idx= nco_dbg_std && lmt_rec->srt > lmt_rec->end) (void)fprintf(stdout,gettext("%s: WARNING %s (input file %d) is superfluous\n"),nco_prg_nm_get(),fl_in,fl_idx); for(idx_rec=lmt_rec->srt;idx_rec<=lmt_rec->end;idx_rec+=lmt_rec->srd){ if(fl_idx == fl_nbr-1 && idx_rec >= 1L+lmt_rec->end-lmt_rec->srd) LAST_RECORD=True; #ifdef ENABLE_MPI if(fl_idx == 0 && idx_rec == lmt_rec->srt){ /* MPI operators processed first record in first-stage loop */ continue; }else{ /* a loop of idx = stored indices */ if(prc_rnk == rnk_mgr){ /* For ncrcat, Manager gives write access for each record in each file */ if(nco_prg_id == ncrcat){ /* Give Write access to write current record */ /* var_wrt_nbr=-prc_nbr+1; */ var_wrt_nbr=0; while(var_wrt_nbr < nbr_var_prc){ /* Give write access to Workers who have some variables; wrong condn? */ /* Receive message from any worker */ MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); /* Obtain MPI message tag type */ msg_tag_typ=mpi_stt.MPI_TAG; /* Get sender's prc_rnk */ rnk_wrk=wrk_id_bfr[0]; if(msg_tag_typ == msg_tag_wrk_done) TKN_WRT_FREE=True; if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ if(rnk_wrk == tkn_wrt_rnk){ /* Prev write completed */ TKN_WRT_FREE=True; } /* rnk_wrk != tkn_wrt_rnk */ /* Allocate token if free, else ask worker to try later */ if(TKN_WRT_FREE){ TKN_WRT_FREE=False; msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ tkn_wrt_rnk=rnk_wrk; /* To track who has the token */ var_wrt_nbr++; }else{ msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ } /* !TKN_WRT_FREE */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ } /* End-while token request loop */ } /* !ncrcat */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ wrk_id_bfr[0]=prc_rnk; var_wrt_nbr=0; /* if(fl_idx == 0 && idx_rec == lmt_rec->srt) continue; else a loop of idx = stored indices */ for(jdx=0;jdx nco_dbg_scl) (void)fprintf(stderr,gettext("Record %ld of %s is output record %ld\n"),idx_rec,fl_in,rec_usd_cml); #if 0 /* NB: Immediately preceding MPI for scope confounds Emacs indentation Fake end scope restores correct indentation, simplifies code-checking */ } /* fake end for */ #endif /* !0 */ #ifndef ENABLE_MPI #ifdef _OPENMP #pragma omp parallel for default(none) private(idx,in_id) shared(CNV_ARM,base_time_crr,base_time_srt,nco_dbg_lvl,fl_in,fl_out,idx_rec,rec_usd_cml,in_id_arr,LAST_RECORD,nbr_var_prc,nco_op_typ,out_id,prg,rcd,var_prc,var_prc_out) #endif /* !_OPENMP */ /* UP and SMP codes main loop over variables */ for(idx=0;idx= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Update hyperslab start indices to current record for each variable */ var_prc[idx]->srt[0]=idx_rec; var_prc[idx]->end[0]=idx_rec; var_prc[idx]->cnt[0]=1L; /* Retrieve variable from disk into memory */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_var_get(in_id,var_prc[idx]); if(nco_prg_id == ncra){ /* Convert char, short, long, int types to doubles before arithmetic */ var_prc[idx]=nco_typ_cnv_rth(var_prc[idx],nco_op_typ); /* Output variable type is "sticky" so only convert on first record */ if(rec_usd_cml == 0) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); /* Convert var_prc to type of var_prc_out in case type of variable on disk has changed */ var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ nco_opr_drv(rec_usd_cml,nco_op_typ,var_prc[idx],var_prc_out[idx]); } /* end if ncra */ /* Append current record to output file */ if(nco_prg_id == ncrcat){ var_prc_out[idx]->srt[0]=var_prc_out[idx]->end[0]=rec_usd_cml; var_prc_out[idx]->cnt[0]=1L; /* Replace this time_offset value with time_offset from initial file base_time */ if(CNV_ARM && !strcmp(var_prc[idx]->nm,"time_offset")) var_prc[idx]->val.dp[0]+=(base_time_crr-base_time_srt); #ifdef ENABLE_MPI /* Obtain token and prepare to write */ while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); tkn_wrt_rsp=msg_bfr[0]; /* Wait then re-send request */ if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; } /* end while loop waiting for write token */ /* Worker has token---prepare to write */ if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ rcd=nco_fl_open(fl_out_tmp,NC_WRITE|NC_SHARE,&bfr_sz_hnt,&out_id); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); #else /* !ENABLE_MPI */ #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ #endif /* !ENABLE_MPI */ if(var_prc_out[idx]->sz_rec > 1) (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc[idx]->val.vp,var_prc_out[idx]->type); else (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc[idx]->val.vp,var_prc_out[idx]->type); #ifdef ENABLE_MPI /* Close output file and increment written counter */ nco_close(out_id); var_wrt_nbr++; } /* endif tkn_wrt_rqs_xcp */ #endif /* !ENABLE_MPI */ } /* end if ncrcat */ /* Make sure record coordinate, if any, is monotonic */ if(nco_prg_id == ncrcat && var_prc[idx]->is_crd_var) (void)rec_crd_chk(var_prc[idx],fl_in,fl_out,idx_rec,rec_usd_cml); /* Convert missing_value, if any, back to disk type */ if(var_prc[idx]->has_mss_val && var_prc[idx]->type != var_prc[idx]->typ_upk && !LAST_RECORD) var_prc[idx]=nco_cnv_mss_val_typ(var_prc[idx],var_prc[idx]->typ_upk); /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* end (OpenMP Parallel for) loop over variables */ #ifdef ENABLE_MPI if(nco_prg_id == ncrcat){ /* Return token after writing record's last variable */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_done,MPI_COMM_WORLD); } /* !ncrcat */ #endif /* !ENABLE_MPI */ rec_usd_cml++; /* [idx] Index of current record in output file (0 is first, ...) */ if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(stderr,"\n"); #ifdef ENABLE_MPI } /* !Worker */ } /* end else ! fl_idx=0,idx_rec=srt */ #endif /* !ENABLE_MPI */ } /* end loop over idx_rec */ #ifdef ENABLE_MPI if(prc_rnk != rnk_mgr){ /* Only Worker */ #endif /* !ENABLE_MPI */ /* Warn if fewer than number of requested records were read and final file has been processed */ if(lmt_rec->lmt_typ == lmt_dmn_idx && lmt_rec->is_usr_spc_min && lmt_rec->is_usr_spc_max){ long rec_nbr_rqs; /* Number of records user requested */ rec_nbr_rqs=1L+(lmt_rec->max_idx-lmt_rec->min_idx)/lmt_rec->srd; if(nco_dbg_lvl >= nco_dbg_std && fl_idx == fl_nbr-1 && rec_nbr_rqs != rec_usd_cml) (void)fprintf(stdout,gettext("%s: WARNING User requested %li records but only %li were found\n"),nco_prg_nm_get(),rec_nbr_rqs,rec_usd_cml); } /* end if */ /* Error if no records were read and final file has been processed */ if(rec_usd_cml <= 0 && fl_idx == fl_nbr-1){ (void)fprintf(stdout,gettext("%s: ERROR No records lay within specified hyperslab\n"),nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ #ifdef ENABLE_MPI } /* !Worker */ printf("DEBUG: prc_rnk %d at the end of ncra/rcat\n",prc_rnk); #endif /* !ENABLE_MPI */ /* End of ncra, ncrcat section */ }else{ /* ncfe */ #ifdef ENABLE_MPI if(prc_rnk != rnk_mgr){ /* Only Worker does the ncfe processing */ if(fl_idx == 0){ continue; }else{ /* a loop of idx = stored indices */ for(jdx=0;jdx= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Retrieve variable from disk into memory */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_var_get(in_id,var_prc[idx]); /* Convert char, short, long, int types to doubles before arithmetic */ /* var_prc[idx]=nco_typ_cnv_rth(var_prc[idx],nco_op_typ); */ /* Output variable type is "sticky" so only convert on first record */ if(fl_idx == 0) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); /* Convert var_prc to type of var_prc_out in case type of variable on disk has changed */ var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ /* Note: fl_idx not rec_usd_cml! */ nco_opr_drv(fl_idx,nco_op_typ,var_prc[idx],var_prc_out[idx]); /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* end (OpenMP parallel for) loop over idx */ #ifdef ENABLE_MPI } /* end else !fl_idx=0 */ } /* !Worker */ #endif /* !ENABLE_MPI */ } /* end else ncfe */ if(nco_dbg_lvl > nco_dbg_scl) (void)fprintf(stderr,"\n"); /* Close input netCDF file */ for(thr_idx=0;thr_idxis_crd_var){ /* Return linear averages of coordinates unless computing extrema Prevent coordinate variables from encountering nco_var_nrm_sdn() */ if((nco_op_typ != nco_op_min) && (nco_op_typ != nco_op_max)) (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); }else{ /* !var_prc[idx]->is_crd_var */ switch(nco_op_typ){ case nco_op_avg: /* Normalize sum by tally to create mean */ case nco_op_sqrt: /* Normalize sum by tally to create mean */ case nco_op_sqravg: /* Normalize sum by tally to create mean */ case nco_op_rms: /* Normalize sum of squares by tally to create mean square */ case nco_op_avgsqr: /* Normalize sum of squares by tally to create mean square */ (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); break; case nco_op_rmssdn: /* Normalize sum of squares by tally-1 to create mean square for sdn */ (void)nco_var_nrm_sdn(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); break; case nco_op_min: /* Minimum is already in buffer, do nothing */ case nco_op_max: /* Maximum is already in buffer, do nothing */ case nco_op_ttl: /* Total is already in buffer, stuff missing values into elements with zero tally */ (void)nco_var_tll_zro_mss_val(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); default: break; } /* end switch */ /* Some operations require additional processing */ switch(nco_op_typ){ case nco_op_rms: /* Take root of mean of sum of squares to create root mean square */ case nco_op_rmssdn: /* Take root of sdn mean of sum of squares to create root mean square for sdn */ case nco_op_sqrt: /* Take root of mean to create root mean */ (void)nco_var_sqrt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val,var_prc_out[idx]->val); break; case nco_op_sqravg: /* Square mean to create square of the mean (for sdn) */ (void)nco_var_mlt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->val,var_prc_out[idx]->val); break; default: break; } /* end switch */ } /* !var_prc[idx]->is_crd_var */ var_prc_out[idx]->tally=var_prc[idx]->tally=(long *)nco_free(var_prc[idx]->tally); } /* end (OpenMP parallel for) loop over variables */ #ifdef ENABLE_MPI printf("DEBUG: End of Normzn at prc_rnk %d\n",prc_rnk); } /* prc_rnk == rnk_mgr */ for(idx = 0; idx < nbr_var_prc; idx++) { assert(var_prc_out[idx]->tally == var_prc[idx]->tally); if (var_prc_out[idx]->tally == 0) continue; printf("DEBUG: node %d reset idx %d tally for var_prc(out) (cleanup)\n",prc_rnk,idx); var_prc_out[idx]->tally=var_prc[idx]->tally=(long *)nco_free(var_prc[idx]->tally); } printf("DEBUG: Mgr shud prnt this too, prc_rnk %d\n",prc_rnk); #endif /* !ENABLE_MPI */ } /* !ncra/ncfe */ #ifdef ENABLE_MPI printf("DEBUG: After all processing; Before barrier, prc_rnk %d\n",prc_rnk); if(prc_rnk == rnk_mgr){ /* Only Manager */ rcd=nco_fl_open(fl_out_tmp,NC_WRITE|NC_SHARE,&bfr_sz_hnt,&out_id); printf("DEBUG: prc_rnk %d opened out file\n",prc_rnk); #endif /* !ENABLE_MPI */ /* Manually fix YYMMDD date which was mangled by averaging */ if(CNV_CCM_CCSM_CF && nco_prg_id == ncra) (void)nco_cnv_ccm_ccsm_cf_date(out_id,var_out,xtr_nbr); /* End Pass 2: Complete record/file loops with local variable lists */ /* Begin Pass 3: */ /* End Pass 3: */ /* Add time variable to output file NB: nco_cnv_arm_time_install() contains OpenMP critical region */ if(CNV_ARM && nco_prg_id == ncrcat) (void)nco_cnv_arm_time_install(out_id,base_time_srt,dfl_lvl); #ifdef ENABLE_MPI nco_close(out_id); printf("DEBUG: Mgr prc_rnk %d closed out file %d after fixing date, time \n", prc_rnk, out_id); MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); printf("DEBUG: Mgr sent token to worker 1 for final write\n"); }else{ /* Workers */ printf("DEBUG: prc_rnk %d waiting for msg from Mgr for final write\n",prc_rnk); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); printf("DEBUG: prc_rnk %d got token for final write to %d\n",prc_rnk, out_id); if(nco_prg_id == ncra || nco_prg_id == ncfe){ /* Copy averages to output file and free averaging buffers */ rcd=nco_fl_open(fl_out_tmp,NC_WRITE|NC_SHARE,&bfr_sz_hnt,&out_id); printf("DEBUG: prc_rnk %d opened output file for final write\n",prc_rnk); for(jdx=0;jdxval.ip[0]); */ var_prc_out[idx]=nco_var_cnf_typ(var_prc_out[idx]->typ_upk,var_prc_out[idx]); /* printf("DEBUG: After nco_var_cnf_typ prc_rnk %d var val %f\n",prc_rnk,var_prc_out[idx]->val.ip[0]); */ /* Packing/Unpacking */ if(nco_pck_plc == nco_pck_plc_all_new_att) var_prc_out[idx]=nco_put_var_pck(out_id,var_prc_out[idx],nco_pck_plc); printf("DEBUG: prc_rnk %d to final write var %s with idx %d val %g\n",prc_rnk,var_prc_out[idx]->nm,idx,var_prc_out[idx]->val.fp[0]); if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); }else{ /* end if variable is scalar */ /* Size of record dimension is one in output file */ if(nco_prg_id == ncra) var_prc_out[idx]->cnt[0]=1L; (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end if variable is an array */ var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); } /* end loop over jdx */ /* Close output file */ nco_close(out_id); printf("DEBUG: prc_rnk %d closed out file after writing\n",prc_rnk); /* Send Token to Manager */ } /* end if */ if(prc_rnk == prc_nbr-1) MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); else MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* !Workers */ if(prc_rnk == rnk_mgr){ /* Only Manager */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_nbr-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); (void)nco_fl_mv(fl_out_tmp,fl_out); } /* !Manager */ MPI_Finalize(); #else /* !ENABLE_MPI */ /* Copy averages to output file and free averaging buffers */ if(nco_prg_id == ncra || nco_prg_id == ncfe){ for(idx=0;idxtyp_upk,var_prc_out[idx]); /* Packing/Unpacking */ if(nco_pck_plc == nco_pck_plc_all_new_att) var_prc_out[idx]=nco_put_var_pck(out_id,var_prc_out[idx],nco_pck_plc); if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); }else{ /* end if variable is scalar */ /* Size of record dimension is 1 in output file */ if(nco_prg_id == ncra) var_prc_out[idx]->cnt[0]=1L; (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end if variable is an array */ var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); } /* end loop over idx */ } /* end if */ /* Close output file and move it from temporary to permanent location */ (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); #endif /* !ENABLE_MPI */ /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* ncra-specific memory cleanup */ if(nco_prg_id == ncra || nco_prg_id == ncrcat) lmt_rec=nco_lmt_free(lmt_rec); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_arr) in_id_arr=(int *)nco_free(in_id_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) lmt=nco_lmt_lst_free(lmt,lmt_nbr); /* Free chunking information */ for(idx=0;idx 0) cnk_dmn=nco_cnk_lst_free(cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); #if 1 /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); if(xtr_nbr > 0) var_out=nco_var_lst_free(var_out,xtr_nbr); var_prc=(var_sct **)nco_free(var_prc); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix=(var_sct **)nco_free(var_fix); var_fix_out=(var_sct **)nco_free(var_fix_out); #endif /* !1 */ #if 0 /* 20051027: Try ncwa free()'ing technique to avoid freeing dangling pointers */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); /* ncwa uses nco_var_lst_free() on var_prc_out because var_out has dangling pointers */ if(nbr_var_fix > 0) var_fix_out=nco_var_lst_free(var_fix_out,nbr_var_fix); if(nbr_var_prc > 0) var_prc_out=nco_var_lst_free(var_prc_out,nbr_var_prc); var_prc=(var_sct **)nco_free(var_prc); var_fix=(var_sct **)nco_free(var_fix); var_out=(var_sct **)nco_free(var_out); #endif /* !0 */ } /* !flg_cln */ nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/nco_var_utl.h0000644000674300045400000001727212277324011016017 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_var_utl.h,v 1.103 2014/02/14 05:22:17 zender Exp $ */ /* Purpose: Variable utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_var_utl.h" *//* Variable utilities */ #ifndef NCO_VAR_UTL_H #define NCO_VAR_UTL_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* assert() */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, exit */ #include /* strcmp() */ #include /* need LONG_MAX */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_att_utl.h" /* Attribute utilities */ #include "nco_bnr.h" /* Binary write utilities */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_dmn_utl.h" /* Dimension utilities */ #include "nco_grp_utl.h" /* Variable utilities */ #include "nco_md5.h" /* MD5 digests */ #include "nco_mmr.h" /* Memory management */ #include "nco_mss_val.h" /* Missing value utilities */ #include "nco_pck.h" /* Packing and unpacking variables */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void nco_cpy_var_val /* [fnc] Copy variable data from input to output file, no limits */ (const int in_id, /* I [id] netCDF input file ID */ const int out_id, /* I [id] netCDF output file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ const char *var_nm); /* I [sng] Variable name */ void nco_cpy_var_val_lmt /* [fnc] Copy variable data from input to output file, simple hyperslabs */ (const int in_id, /* I [id] netCDF input file ID */ const int out_id, /* I [id] netCDF output file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ char *var_nm, /* I [sng] Variable name */ const lmt_sct * const lmt, /* I [sct] Hyperslab limits */ const int lmt_nbr); /* I [nbr] Number of hyperslab limits */ nco_bool /* O [flg] Faster copy on Multi-record Multi-variable netCDF3 files */ nco_use_mm3_workaround /* [fnc] Use faster copy on Multi-record Multi-variable netCDF3 files? */ (const int in_id, /* I [id] Input file ID */ const int fl_out_fmt); /* I [enm] Output file format */ void nco_cpy_rec_var_val /* [fnc] Copy all record variables, record-by-record, from input to output file, no limits */ (const int in_id, /* I [id] netCDF input file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ CST_X_PTR_CST_PTR_CST_Y(nm_id_sct,var_lst), /* I [sct] Record variables to be extracted */ const int var_nbr); /* I [nbr] Number of record variables */ void nco_var_copy /* [fnc] Copy hyperslab variables of type var_typ from op1 to op2 */ (const nc_type var_typ, /* I [enm] netCDF type */ const long sz, /* I [nbr] Number of elements to copy */ const ptr_unn op1, /* I [sct] Values to copy */ ptr_unn op2); /* O [sct] Destination to copy values to */ int /* O [enm] Return code */ var_dfl_set /* [fnc] Set defaults for each member of variable structure */ (var_sct * const var); /* I [sct] Variable strucutre to initialize to defaults */ void nco_var_dfn /* [fnc] Define variables and write their attributes to output file */ (const int in_id, /* I [enm] netCDF input-file ID */ const char * const fl_out, /* I [sng] Name of output file */ const int out_id, /* I [enm] netCDF output-file ID */ var_sct * const * const var, /* I/O [sct] Variables to be defined in output file */ const int nbr_var, /* I [nbr] Number of variables to be defined */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_ncl), /* I [sct] Dimensions included in output file */ const int nbr_dmn_ncl, /* I [nbr] Number of dimensions in list */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ const int dfl_lvl); /* I [enm] Deflate level [0..9] */ var_sct * /* O [sct] Copy of input variable */ nco_var_dpl /* [fnc] Duplicate input variable */ (const var_sct * const var); /* I [sct] Variable to duplicate */ var_sct * /* O [sct] Pointer to free'd variable */ nco_var_free /* [fnc] Free all memory associated with variable structure */ (var_sct *var); /* I/O [sct] Variable to free */ void nco_var_get /* [fnc] Allocate, retrieve variable hyperslab from disk to memory */ (const int nc_id, /* I [id] netCDF file ID */ var_sct *var); /* I [sct] Variable to get */ var_sct ** /* O [sct] Pointer to free'd structure list */ nco_var_lst_free /* [fnc] Free memory associated with variable structure list */ (var_sct **var_lst, /* I/O [sct] Variable structure list to free */ const int var_nbr); /* I [nbr] Number of variable structures in list */ nco_bool /* [flg] Variable is listed in a "bounds" attribute */ nco_is_spc_in_bnd_att /* [fnc] Variable is listed in a "bounds" attribute */ (const int nc_id, /* I [id] netCDF file ID */ const int var_trg_id); /* I [id] Variable ID */ nco_bool /* [flg] Variable is listed in a "coordinates" attribute */ nco_is_spc_in_crd_att /* [fnc] Variable is listed in a "coordinates" attribute */ (const int nc_id, /* I [id] netCDF file ID */ const int var_trg_id); /* I [id] Variable ID */ void nco_var_mtd_refresh /* [fnc] Update variable metadata (dmn_nbr, ID, mss_val, type) */ (const int nc_id, /* I [id] netCDF input-file ID */ var_sct * const var); /* I/O [sct] Variable to update */ void nco_var_srd_srt_set /* [fnc] Assign zero to start and unity to stride vectors in variables */ (var_sct ** const var, /* I [sct] Variables whose subcycle, start, and stride arrays to set */ const int nbr_var); /* I [nbr] Number of structures in variable structure list */ void nco_var_dmn_refresh /* [fnc] Refresh var hyperslab info with var->dim[] info */ (var_sct ** const var, /* I [sct] Variables to refresh */ const int nbr_var); /* I [nbr] Number of structures in variable structure list */ void nco_var_val_cpy /* [fnc] Copy variables data from input to output file */ (const int in_id, /* I [enm] netCDF file ID */ const int out_id, /* I [enm] netCDF output file ID */ var_sct ** const var, /* I/O [sct] Variables to copy to output file */ const int nbr_var); /* I [nbr] Number of variables */ void nco_xrf_dmn /* [fnc] Switch pointers to dimension structures so var->dim points to var->dim->xrf */ (var_sct * const var); /* I [sct] Variable to manipulate */ void nco_xrf_var /* [fnc] Make xrf elements of variable structures point to eachother */ (var_sct * const var_1, /* I/O [sct] Variable */ var_sct * const var_2); /* I/O [sct] Related variable */ var_sct * /* O [sct] Variable structure */ nco_var_fll /* [fnc] Allocate variable structure and fill with metadata */ (const int nc_id, /* I [id] netCDF file ID */ const int var_id, /* I [id] variable ID */ const char * const var_nm, /* I [sng] Variable name */ dmn_sct * const * const dim, /* I [sct] Dimensions available to variable */ const int nbr_dim); /* I [nbr] Number of dimensions in list */ nc_type nco_get_typ /* [fnc] Obtain netCDF type to define variable from NCO program ID */ (const var_sct * const var); /* I [sct] Variable to be defined in output file */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_VAR_UTL_H */ ./nco-4.4.2/src/nco/nco_cnf_typ.c0000644000674300045400000022004112301221754015764 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnf_typ.c,v 1.76 2014/02/19 21:36:44 pvicente Exp $ */ /* Purpose: Conform variable types */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_cnf_typ.h" /* Conform variable types */ void cast_void_nctype /* [fnc] Cast generic pointer to netCDF type */ (const nc_type type, /* I [enm] netCDF type to cast void pointer to*/ ptr_unn * const ptr) /* I/O [ptr] Pointer to pointer union whose vp element will be cast to type type*/ { /* Purpose: Cast generic pointer in ptr_unn structure from type void to output netCDF type */ switch(type){ case NC_FLOAT: ptr->fp=(float *)ptr->vp; break; case NC_DOUBLE: ptr->dp=(double *)ptr->vp; break; case NC_INT: ptr->ip=(nco_int *)ptr->vp; break; case NC_SHORT: ptr->sp=(short *)ptr->vp; break; case NC_CHAR: ptr->cp=(nco_char *)ptr->vp; break; case NC_BYTE: ptr->bp=(nco_byte *)ptr->vp; break; case NC_UBYTE: ptr->ubp=(nco_ubyte *)ptr->vp; break; case NC_USHORT: ptr->usp=(nco_ushort *)ptr->vp; break; case NC_UINT: ptr->uip=(nco_uint *)ptr->vp; break; case NC_INT64: ptr->i64p=(nco_int64 *)ptr->vp; break; case NC_UINT64: ptr->ui64p=(nco_uint64 *)ptr->vp; break; case NC_STRING: ptr->sngp=(nco_string *)ptr->vp; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ } /* end cast_void_nctype() */ void cast_nctype_void /* [fnc] Cast generic pointer in ptr_unn structure from type type to type void */ (const nc_type type, /* I [enm] netCDF type of pointer */ ptr_unn * const ptr) /* I/O pointer to pointer union which to cast from type type to type void */ { /* Cast generic pointer in ptr_unn structure from type type to type void */ switch(type){ case NC_FLOAT: ptr->vp=(void *)ptr->fp; break; case NC_DOUBLE: ptr->vp=(void *)ptr->dp; break; case NC_INT: ptr->vp=(void *)ptr->ip; break; case NC_SHORT: ptr->vp=(void *)ptr->sp; break; case NC_CHAR: ptr->vp=(void *)ptr->cp; break; case NC_BYTE: ptr->vp=(void *)ptr->bp; break; case NC_UBYTE: ptr->vp=(void *)ptr->ubp; break; case NC_USHORT: ptr->vp=(void *)ptr->usp; break; case NC_UINT: ptr->vp=(void *)ptr->uip; break; case NC_INT64: ptr->vp=(void *)ptr->i64p; break; case NC_UINT64: ptr->vp=(void *)ptr->ui64p; break; case NC_STRING: ptr->vp=(void *)ptr->sngp; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ } /* end cast_nctype_void() */ var_sct * /* O [var] Variable after (possible) conversion */ nco_typ_cnv_rth /* [fnc] Convert char, short, long, int types to doubles before arithmetic */ (var_sct *var, /* I/O [var] Variable to be considered for conversion */ const int nco_op_typ) /* I [enm] Operation type */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Convert char, short, long, int types to doubles for arithmetic Conversions are performed unless arithmetic operation type is min or max Floats (and doubles, of course) are not converted for performance reasons Remember to convert back after weighting and arithmetic are complete! */ /* Variables which are unpacked into NC_FLOAT should remain NC_FLOAT here Unpacking happens 'transparently' when original data are read by nco_var_get() Output structures (i.e., var_prc_out) often correspond to original input type Thus var structure may have typ_upk=NC_FLOAT and type=NC_SHORT In that case, promote based on typ_upk rather than on type Otherwise most var's that had been unpacked would be converted to NC_DOUBLE here That would put them in conflict with corresponding var_out, which is usually based on typ_upk Check this first, then proceed with normal non-float->double conversion */ /* 20130906: Users have long been uncomfortable with not implicitly converting floats to doubles A new section of the manual that describes the advantages and disadvantages: http://nco.sf.net/nco.html#fxm Implementing --dbl switch on ncwa, ncra, nces (ncap2?) to force implicit conversion */ if(nco_rth_cnv_get() == nco_rth_flt_flt){ /* Traditional NCO convention: promote, where necessary, anything but floats and doubles */ if(var->typ_upk == NC_FLOAT){ var=nco_var_cnf_typ((nc_type)NC_FLOAT,var); }else{ /* Conversion only for appropriate operation types */ if(var->type != NC_FLOAT && var->type != NC_DOUBLE && nco_op_typ != nco_op_min && nco_op_typ != nco_op_max) var=nco_var_cnf_typ((nc_type)NC_DOUBLE,var); } /* end if */ }else{ /* !nco_rth_flt_flt */ /* User-specified new convention: promote, where necessary, anything but doubles */ /* Conversion only for appropriate operation types */ if(var->type != NC_DOUBLE && nco_op_typ != nco_op_min && nco_op_typ != nco_op_max) var=nco_var_cnf_typ((nc_type)NC_DOUBLE,var); } /* !nco_rth_flt_flt */ return var; } /* nco_typ_cnv_rth() */ var_sct * /* O [sct] Variable reverted to on-disk type */ nco_cnv_var_typ_dsk /* [fnc] Revert variable to on-disk type */ (var_sct *var) /* I [sct] Variable to be reverted */ { /* Purpose: Revert variable to on-disk type */ if(var->type != var->typ_dsk) var=nco_var_cnf_typ(var->typ_dsk,var); return var; } /* nco_cnv_var_typ_dsk() */ var_sct * /* O [sct] Variable with mss_val converted to typ_upk */ nco_cnv_mss_val_typ /* [fnc] Convert missing_value, if any, to mss_val_out_typ */ (var_sct *var, /* I [sct] Variable with missing_value to convert */ const nc_type mss_val_out_typ) /* I [enm] Type of mss_val on output */ { /* Purpose: Convert variable missing_value field, if any, to mss_val_out_typ Routine is currently called only by ncra and by nco_var_get(), for following reason: Most applications should call nco_var_cnf_typ() without calling nco_cnv_mss_val_typ() since nco_var_cnf_typ() converts misssing_value type along with variable type. The important exception to this is ncra ncra refreshes variable metadata (including missing_value, if any) once per file (naturally), but refreshes variable values once per record. Current type of missing_value is not stored separately in variable structure (maybe this is a mistake), so type of missing value may remain as promoted type for arithmetic. When next record is read and nco_typ_cnf_rth() promotion of new input to arithmetic type (double, if necessary) will fail when it tries to convert the missing_value, if any, which _was already promoted_. Performing type conversion on memory already converted is a no-no! And it results in unpredictable and incorrect answers Thus it is very important to synchronize type of variable and missing_value In the case described above, ncra simply calls this routine to convert missing_value to typ_upk at the end of each record. Routine is dangerous because it _allows_ mss_val and variable to be different types Make sure you have a (very) good reason to do this! Better permanent solution is to add missing_value type to variable structure */ nc_type var_in_typ; /* [enm] Type of variable and mss_val on input */ ptr_unn mss_val_in; ptr_unn mss_val_out; var_in_typ=var->type; /* [enm] Type of variable and mss_val on input */ /* Skip if no missing_value or if missing_value is already typ_upk */ if(!var->has_mss_val || var_in_typ == mss_val_out_typ) return var; /* Simple error-checking and diagnostics */ if(nco_dbg_lvl_get() >= nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: %s NCO_MSS_VAL_SNG attribute of variable %s from type %s to type %s\n",nco_prg_nm_get(),mss_val_out_typ > var_in_typ ? "Promoting" : "Demoting",var->nm,nco_typ_sng(var_in_typ),nco_typ_sng(mss_val_out_typ)); } /* end if */ /* Sequence of following commands is important (copy before overwriting!) */ mss_val_in=var->mss_val; mss_val_out.vp=(void *)nco_malloc(nco_typ_lng(mss_val_out_typ)); (void)nco_val_cnf_typ(var_in_typ,mss_val_in,mss_val_out_typ,mss_val_out); var->mss_val=mss_val_out; /* Free original Of course this only changes var_in->mss_val Calling routine must update var_out->mss_val if var_out->val points to var_in->val This dangling pointer was a problem in ncpdq */ mss_val_in.vp=nco_free(mss_val_in.vp); return var; /* O [sct] Variable with mss_val converted to typ_upk */ } /* nco_cnv_mss_val_typ() */ var_sct * /* O [sct] Pointer to variable structure of type var_out_typ */ nco_var_cnf_typ /* [fnc] Return copy of input variable typecast to desired type */ (const nc_type var_out_typ, /* I [enm] Type to convert variable structure to */ var_sct * const var_in) /* I/O [enm] Pointer to variable structure (may be destroyed) */ { /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Return copy of input variable typecast to desired type Routine converts missing_value, if any, to output type Routine saves time by returning original variable structure with val and type members changed as necessary Routine assumes variable and missing_value, if any, are same type in memory This is currently always true except briefly in ncra (and possibly ncpdq) This condition is unsafe and is described more fully in nco_cnv_mss_val_typ() */ long idx; long sz; long sz_msk=long_CEWI; /* Holds value when called with var_in->val.vp==NULL */ nc_type var_in_typ; ptr_unn val_in; ptr_unn val_out; var_sct *var_out; /* Do types of variable AND its missing value already match? This routine assumes missing_value, if any, to be same type as variable */ if(var_in->type == var_out_typ) return var_in; if(var_in->val.vp==NULL){ /* Variable has no data when var_in.val.vp==NULL In this case function should only convert missing values Accomplish this by temporarily masking off val_in by setting var_in->sz=0 Restore correct size at function end fxm: 20050521 Which operators take advantage of this behavior? */ sz_msk=var_in->sz; var_in->sz=0L; } /* endif NULL */ /* Setting output pointer equal to input pointer is confusing Theoretical advantage is that it speeds up routine Nevertheless, be careful... */ var_out=var_in; var_in_typ=var_in->type; /* Simple error-checking and diagnostics */ if(nco_dbg_lvl_get() >= nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: %s variable %s from type %s to type %s\n",nco_prg_nm_get(),var_out_typ > var_in_typ ? "Promoting" : "Demoting",var_in->nm,nco_typ_sng(var_in_typ),nco_typ_sng(var_out_typ)); } /* end if */ /* Move current variable values to swap location */ val_in=var_in->val; /* Allocate space for type-conforming values */ var_out->type=var_out_typ; var_out->val.vp=(void *)nco_malloc(var_out->sz*nco_typ_lng(var_out->type)); /* Define convenience variables to avoid repetitive indirect addressing */ sz=var_out->sz; val_out=var_out->val; /* Copy and typecast missing_value attribute, if any */ /* Calling routine must avoid re-promoting missing values already promoted during arithmetic */ if(var_out->has_mss_val){ ptr_unn var_in_mss_val; /* Sequence of following commands is important (copy before overwriting!) */ var_in_mss_val=var_out->mss_val; var_out->mss_val.vp=(void *)nco_malloc(nco_typ_lng(var_out->type)); (void)nco_val_cnf_typ(var_in_typ,var_in_mss_val,var_out_typ,var_out->mss_val); /* Free original */ var_in_mss_val.vp=nco_free(var_in_mss_val.vp); } /* end if */ /* Typecast pointer to values before access There is only one var structure so use shortcut, de-referenced types */ (void)cast_void_nctype(var_in_typ,&val_in); (void)cast_void_nctype(var_out_typ,&val_out); /* Copy and typecast entire array of values, using C implicit coercion */ switch(var_out_typ){ case NC_FLOAT: switch(var_in_typ){ case NC_FLOAT: for(idx=0L;idx NB: Rounding with lrint(), lrintf(), llrint(), and llrintf() imposes dependency on */ case NC_FLOAT: for(idx=0L;idxsz=sz_msk; /* Free input variable data */ val_in.vp=nco_free(val_in.vp); return var_out; } /* end nco_var_cnf_typ() */ var_sct * /* O [sct] Pointer to variable structure of type var_out_typ */ nco_var_cnf_typ_tst /* [fnc] Return copy of input variable typecast to desired type */ (const nc_type var_out_typ, /* I [enm] Type to convert variable structure to */ var_sct * const var_in) /* I/O [enm] Pointer to variable structure (may be destroyed) */ { /* 20120302: Same as nco_var_cnf_typ() but keeps missing values in range on down-promotions Similar changes were made to nco_val_cnf_typ_tst() which is based on nco_val_cnf_typ() Intended to address TODO nco1035 */ /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Return copy of input variable typecast to desired type Routine converts missing_value, if any, to output type Routine saves time by returning original variable structure with val and type members changed as necessary Routine assumes variable and missing_value, if any, are same type in memory This is currently always true except briefly in ncra (and possibly ncpdq) This condition is unsafe and is described more fully in nco_cnv_mss_val_typ() */ long idx; long sz; long sz_msk=long_CEWI; /* Holds value when called with var_in->val.vp==NULL */ nc_type var_in_typ; ptr_unn val_in; ptr_unn val_out; var_sct *var_out; /* Do types of variable AND its missing value already match? This routine assumes missing_value, if any, to be same type as variable */ if(var_in->type == var_out_typ) return var_in; if(var_in->val.vp==NULL){ /* Variable has no data when var_in.val.vp==NULL In this case function should only convert missing values Accomplish this by temporarily masking off val_in by setting var_in->sz=0 Restore correct size at function end fxm: 20050521 Which operators take advantage of this behavior? */ sz_msk=var_in->sz; var_in->sz=0L; } /* endif NULL */ /* Setting output pointer equal to input pointer is confusing Theoretical advantage is that it speeds up routine Nevertheless, be careful... */ var_out=var_in; var_in_typ=var_in->type; /* Simple error-checking and diagnostics */ if(nco_dbg_lvl_get() >= nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: %s variable %s from type %s to type %s\n",nco_prg_nm_get(),var_out_typ > var_in_typ ? "Promoting" : "Demoting",var_in->nm,nco_typ_sng(var_in_typ),nco_typ_sng(var_out_typ)); } /* end if */ /* Move current variable values to swap location */ val_in=var_in->val; /* Allocate space for type-conforming values */ var_out->type=var_out_typ; var_out->val.vp=(void *)nco_malloc(var_out->sz*nco_typ_lng(var_out->type)); /* Define convenience variables to avoid repetitive indirect addressing */ sz=var_out->sz; val_out=var_out->val; /* Copy and typecast missing_value attribute, if any */ /* Calling routine must avoid re-promoting missing values already promoted during arithmetic */ if(var_out->has_mss_val){ ptr_unn var_in_mss_val; /* Sequence of following commands is important (copy before overwriting!) */ var_in_mss_val=var_out->mss_val; var_out->mss_val.vp=(void *)nco_malloc(nco_typ_lng(var_out->type)); (void)nco_val_cnf_typ(var_in_typ,var_in_mss_val,var_out_typ,var_out->mss_val); /* Free original */ var_in_mss_val.vp=nco_free(var_in_mss_val.vp); } /* end if */ /* Typecast pointer to values before access There is only one var structure so use shortcut, de-referenced types */ (void)cast_void_nctype(var_in_typ,&val_in); (void)cast_void_nctype(var_out_typ,&val_out); /* Copy and typecast entire array of values, using C implicit coercion */ switch(var_out_typ){ case NC_FLOAT: switch(var_in_typ){ case NC_FLOAT: for(idx=0L;idx NB: Rounding with lrint(), lrintf(), llrint(), and llrintf() imposes dependency on */ case NC_FLOAT: for(idx=0L;idxsz=sz_msk; /* Free input variable data */ val_in.vp=nco_free(val_in.vp); return var_out; } /* end nco_var_cnf_typ_tst() */ void nco_val_cnf_typ /* [fnc] Copy val_in and typecast from typ_in to typ_out */ (const nc_type typ_in, /* I [enm] Type of input value */ ptr_unn val_in, /* I [ptr] Pointer to input value */ const nc_type typ_out, /* I [enm] Type of output value */ ptr_unn val_out) /* I [ptr] Pointer to output value */ { /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Fill val_out with copy of val_in that has been typecast from typ_in to typ_out Last-referenced state of both value pointers is assumed to be .vp, and val_out union is returned in that state */ /* val_in and val_out should not be same pointer union since val_out must hold enough space (one element of type typ_out) to hold output and output type may be larger than input type */ /* Typecast pointer to values before access */ (void)cast_void_nctype(typ_in,&val_in); (void)cast_void_nctype(typ_out,&val_out); /* Copy and typecast single value using implicit coercion rules of C */ switch(typ_out){ case NC_FLOAT: switch(typ_in){ case NC_FLOAT: *val_out.fp=*val_in.fp; break; case NC_DOUBLE: *val_out.fp=*val_in.dp; break; case NC_INT: *val_out.fp=*val_in.ip; break; case NC_SHORT: *val_out.fp=*val_in.sp; break; case NC_CHAR: *val_out.fp=strtod((const char *)val_in.cp,(char **)NULL); break; case NC_BYTE: *val_out.fp=*val_in.bp; break; case NC_UBYTE: *val_out.fp=*val_in.ubp; break; case NC_USHORT: *val_out.fp=*val_in.usp; break; case NC_UINT: *val_out.fp=*val_in.uip; break; case NC_INT64: *val_out.fp=*val_in.i64p; break; case NC_UINT64: *val_out.fp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_DOUBLE: switch(typ_in){ case NC_FLOAT: *val_out.dp=*val_in.fp; break; case NC_DOUBLE: *val_out.dp=*val_in.dp; break; case NC_INT: *val_out.dp=*val_in.ip; break; case NC_SHORT: *val_out.dp=*val_in.sp; break; case NC_CHAR: *val_out.dp=strtod((const char *)val_in.cp,(char **)NULL); break; case NC_BYTE: *val_out.dp=*val_in.bp; break; case NC_UBYTE: *val_out.dp=*val_in.ubp; break; case NC_USHORT: *val_out.dp=*val_in.usp; break; case NC_UINT: *val_out.dp=*val_in.uip; break; case NC_INT64: *val_out.dp=*val_in.i64p; break; case NC_UINT64: *val_out.dp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_INT: switch(typ_in){ case NC_FLOAT: *val_out.ip=(nco_int)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.ip=(nco_int)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.ip=*val_in.ip; break; case NC_SHORT: *val_out.ip=*val_in.sp; break; case NC_CHAR: *val_out.ip=(nco_int)strtod((const char *)val_in.cp,(char **)NULL); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_BYTE: *val_out.ip=*val_in.bp; break; case NC_UBYTE: *val_out.ip=*val_in.ubp; break; case NC_USHORT: *val_out.ip=*val_in.usp; break; case NC_UINT: *val_out.ip=*val_in.uip; break; case NC_INT64: *val_out.ip=*val_in.i64p; break; case NC_UINT64: *val_out.ip=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_SHORT: switch(typ_in){ case NC_FLOAT: *val_out.sp=(short int)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.sp=(short int)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.sp=*val_in.ip; break; case NC_SHORT: *val_out.sp=*val_in.sp; break; case NC_CHAR: *val_out.sp=(short int)strtod((const char *)val_in.cp,(char **)NULL); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_BYTE: *val_out.sp=*val_in.bp; break; case NC_UBYTE: *val_out.sp=*val_in.ubp; break; case NC_USHORT: *val_out.sp=*val_in.usp; break; case NC_UINT: *val_out.sp=*val_in.uip; break; case NC_INT64: *val_out.sp=*val_in.i64p; break; case NC_UINT64: *val_out.sp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_CHAR: switch(typ_in){ case NC_FLOAT: *val_out.cp=(nco_char)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.cp=(nco_char)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.cp=*val_in.ip; break; case NC_SHORT: *val_out.cp=*val_in.sp; break; case NC_CHAR: *val_out.cp=*val_in.cp; break; case NC_BYTE: *val_out.cp=*val_in.bp; break; case NC_UBYTE: *val_out.cp=*val_in.ubp; break; case NC_USHORT: *val_out.cp=*val_in.usp; break; case NC_UINT: *val_out.cp=*val_in.uip; break; case NC_INT64: *val_out.cp=*val_in.i64p; break; case NC_UINT64: *val_out.cp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_BYTE: switch(typ_in){ case NC_FLOAT: *val_out.bp=(nco_byte)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.bp=(nco_byte)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.bp=*val_in.ip; break; case NC_SHORT: *val_out.bp=*val_in.sp; break; case NC_CHAR: *val_out.bp=*val_in.cp; break; case NC_BYTE: *val_out.bp=*val_in.bp; break; case NC_UBYTE: *val_out.bp=*val_in.ubp; break; case NC_USHORT: *val_out.bp=*val_in.usp; break; case NC_UINT: *val_out.bp=*val_in.uip; break; case NC_INT64: *val_out.bp=*val_in.i64p; break; case NC_UINT64: *val_out.bp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_UBYTE: switch(typ_in){ case NC_FLOAT: *val_out.ubp=(nco_ubyte)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.ubp=(nco_ubyte)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.ubp=*val_in.ip; break; case NC_SHORT: *val_out.ubp=*val_in.sp; break; case NC_CHAR: *val_out.ubp=*val_in.cp; break; case NC_BYTE: *val_out.ubp=*val_in.bp; break; case NC_UBYTE: *val_out.ubp=*val_in.ubp; break; case NC_USHORT: *val_out.ubp=*val_in.usp; break; case NC_UINT: *val_out.ubp=*val_in.uip; break; case NC_INT64: *val_out.ubp=*val_in.i64p; break; case NC_UINT64: *val_out.ubp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_USHORT: switch(typ_in){ case NC_FLOAT: *val_out.usp=(nco_ushort)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.usp=(nco_ushort)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.usp=*val_in.ip; break; case NC_SHORT: *val_out.usp=*val_in.sp; break; case NC_CHAR: *val_out.usp=*val_in.cp; break; case NC_BYTE: *val_out.usp=*val_in.bp; break; case NC_UBYTE: *val_out.usp=*val_in.ubp; break; case NC_USHORT: *val_out.usp=*val_in.usp; break; case NC_UINT: *val_out.usp=*val_in.uip; break; case NC_INT64: *val_out.usp=*val_in.i64p; break; case NC_UINT64: *val_out.usp=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_UINT: switch(typ_in){ case NC_FLOAT: *val_out.uip=(nco_uint)lrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.uip=(nco_uint)lrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.uip=*val_in.ip; break; case NC_SHORT: *val_out.uip=*val_in.sp; break; case NC_CHAR: *val_out.uip=*val_in.cp; break; case NC_BYTE: *val_out.uip=*val_in.bp; break; case NC_UBYTE: *val_out.uip=*val_in.ubp; break; case NC_USHORT: *val_out.uip=*val_in.usp; break; case NC_UINT: *val_out.uip=*val_in.uip; break; case NC_INT64: *val_out.uip=*val_in.i64p; break; case NC_UINT64: *val_out.uip=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_INT64: switch(typ_in){ case NC_FLOAT: *val_out.i64p=(nco_int64)llrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.i64p=(nco_int64)llrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.i64p=*val_in.ip; break; case NC_SHORT: *val_out.i64p=*val_in.sp; break; case NC_CHAR: *val_out.i64p=*val_in.cp; break; case NC_BYTE: *val_out.i64p=*val_in.bp; break; case NC_UBYTE: *val_out.i64p=*val_in.ubp; break; case NC_USHORT: *val_out.i64p=*val_in.usp; break; case NC_UINT: *val_out.i64p=*val_in.uip; break; case NC_INT64: *val_out.i64p=*val_in.i64p; break; case NC_UINT64: *val_out.i64p=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_UINT64: switch(typ_in){ case NC_FLOAT: *val_out.ui64p=(nco_uint64)llrintf(*val_in.fp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: *val_out.ui64p=(nco_uint64)llrint(*val_in.dp); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: *val_out.ui64p=*val_in.ip; break; case NC_SHORT: *val_out.ui64p=*val_in.sp; break; case NC_CHAR: *val_out.ui64p=*val_in.cp; break; case NC_BYTE: *val_out.ui64p=*val_in.bp; break; case NC_UBYTE: *val_out.ui64p=*val_in.ubp; break; case NC_USHORT: *val_out.ui64p=*val_in.usp; break; case NC_UINT: *val_out.ui64p=*val_in.uip; break; case NC_INT64: *val_out.ui64p=*val_in.i64p; break; case NC_UINT64: *val_out.ui64p=*val_in.ui64p; break; case NC_STRING: break; default: nco_dfl_case_nc_type_err(); break; } break; case NC_STRING: switch(typ_in){ case NC_FLOAT: break; case NC_DOUBLE: break; case NC_INT: break; case NC_SHORT: break; case NC_CHAR: break; case NC_BYTE: break; case NC_UBYTE: break; case NC_USHORT: break; case NC_UINT: break; case NC_INT64: break; case NC_UINT64: break; case NC_STRING: *val_out.sngp=*val_in.sngp; break; default: nco_dfl_case_nc_type_err(); break; } break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* NB: There is no need to un-typecast input pointers because they were passed by value and are thus purely local to this routine. The only thing changed by this routine is the contents of the location pointed to by the pointer to the output value. */ } /* end nco_val_cnf_typ */ int /* O [enm] Dummy return */ nco_scv_cnf_typ /* [fnc] Convert scalar attribute to typ_new using C implicit coercion */ (const nc_type typ_new, /* I [enm] Type to convert scv_old to */ scv_sct * const scv_old) /* I/O [sct] Scalar value to convert */ { /* Purpose: Convert scalar attribute to typ_new using C implicit coercion */ nc_type typ_old=scv_old->type; scv_sct scv_new; switch (typ_new){ case NC_FLOAT: switch(typ_old){ case NC_FLOAT: scv_new.val.f=(scv_old->val).f; break; case NC_DOUBLE: scv_new.val.f=(scv_old->val).d; break; case NC_INT: scv_new.val.f=(scv_old->val).i; break; case NC_SHORT: scv_new.val.f=(scv_old->val).s; break; case NC_BYTE: scv_new.val.f=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.f=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.f=(scv_old->val).us; break; case NC_UINT: scv_new.val.f=(scv_old->val).ui; break; case NC_INT64: scv_new.val.f=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.f=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_DOUBLE: switch(typ_old){ case NC_FLOAT: scv_new.val.d=(scv_old->val).f; break; case NC_DOUBLE: scv_new.val.d =(scv_old->val).d; break; case NC_INT: scv_new.val.d=(scv_old->val).i; break; case NC_SHORT: scv_new.val.d=(scv_old->val).s; break; case NC_BYTE: scv_new.val.d=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.d=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.d=(scv_old->val).us; break; case NC_UINT: scv_new.val.d=(scv_old->val).ui; break; case NC_INT64: scv_new.val.d=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.d=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_INT: switch(typ_old){ case NC_FLOAT: scv_new.val.i=(nco_int)lrintf((scv_old->val).f); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: scv_new.val.i=(nco_int)lrint((scv_old->val).d); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: scv_new.val.i =scv_old->val.i; break; case NC_SHORT: scv_new.val.i=(scv_old->val).s; break; case NC_BYTE: scv_new.val.i=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.i=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.i=(scv_old->val).us; break; case NC_UINT: scv_new.val.i=(scv_old->val).ui; break; case NC_INT64: scv_new.val.i=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.i=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_SHORT: switch(typ_old){ case NC_FLOAT: scv_new.val.s=(short int)lrintf((scv_old->val).f); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_DOUBLE: scv_new.val.s=(short int)lrint((scv_old->val).d); break; /* Coerce to avoid C++ compiler assignment warning */ case NC_INT: scv_new.val.s=(scv_old->val).i; break; case NC_SHORT: scv_new.val.s=(scv_old->val).s; break; case NC_BYTE: scv_new.val.s=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.s=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.s=(scv_old->val).us; break; case NC_UINT: scv_new.val.s=(scv_old->val).ui; break; case NC_INT64: scv_new.val.s=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.s=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_CHAR: /* Do nothing */ break; case NC_BYTE: switch(typ_old){ case NC_FLOAT: scv_new.val.b=(nco_byte)lrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.b=(nco_byte)lrint((scv_old->val).d); break; case NC_INT: scv_new.val.b=(scv_old->val).i; break; case NC_SHORT: scv_new.val.b=(scv_old->val).s; break; case NC_BYTE: scv_new.val.b=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.b=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.b=(scv_old->val).us; break; case NC_UINT: scv_new.val.b=(scv_old->val).ui; break; case NC_INT64: scv_new.val.b=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.b=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_UBYTE: switch(typ_old){ case NC_FLOAT: scv_new.val.ub=(nco_ubyte)lrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.ub=(nco_ubyte)lrint((scv_old->val).d); break; case NC_INT: scv_new.val.ub=(scv_old->val).i; break; case NC_SHORT: scv_new.val.ub=(scv_old->val).s; break; case NC_BYTE: scv_new.val.ub=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.ub=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.ub=(scv_old->val).us; break; case NC_UINT: scv_new.val.ub=(scv_old->val).ui; break; case NC_INT64: scv_new.val.ub=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.ub=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_USHORT: switch(typ_old){ case NC_FLOAT: scv_new.val.us=(nco_ushort)lrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.us=(nco_ushort)lrint((scv_old->val).d); break; case NC_INT: scv_new.val.us=(scv_old->val).i; break; case NC_SHORT: scv_new.val.us=(scv_old->val).s; break; case NC_BYTE: scv_new.val.us=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.us=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.us=(scv_old->val).us; break; case NC_UINT: scv_new.val.us=(scv_old->val).ui; break; case NC_INT64: scv_new.val.us=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.us=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_UINT: switch(typ_old){ case NC_FLOAT: scv_new.val.ui=(nco_uint)lrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.ui=(nco_uint)lrint((scv_old->val).d); break; case NC_INT: scv_new.val.ui=(scv_old->val).i; break; case NC_SHORT: scv_new.val.ui=(scv_old->val).s; break; case NC_BYTE: scv_new.val.ui=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.ui=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.ui=(scv_old->val).us; break; case NC_UINT: scv_new.val.ui=(scv_old->val).ui; break; case NC_INT64: scv_new.val.ui=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.ui=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_INT64: switch(typ_old){ case NC_FLOAT: scv_new.val.i64=(nco_int64)llrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.i64=(nco_int64)llrint((scv_old->val).d); break; case NC_INT: scv_new.val.i64=(scv_old->val).i; break; case NC_SHORT: scv_new.val.i64=(scv_old->val).s; break; case NC_BYTE: scv_new.val.i64=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.i64=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.i64=(scv_old->val).us; break; case NC_UINT: scv_new.val.i64=(scv_old->val).ui; break; case NC_INT64: scv_new.val.i64=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.i64=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_UINT64: switch(typ_old){ case NC_FLOAT: scv_new.val.ui64=(nco_uint64)llrintf((scv_old->val).f); break; case NC_DOUBLE: scv_new.val.ui64=(nco_uint64)llrint((scv_old->val).d); break; case NC_INT: scv_new.val.ui64=(scv_old->val).i; break; case NC_SHORT: scv_new.val.ui64=(scv_old->val).s; break; case NC_BYTE: scv_new.val.ui64=(scv_old->val).b; break; case NC_UBYTE: scv_new.val.ui64=(scv_old->val).ub; break; case NC_USHORT: scv_new.val.ui64=(scv_old->val).us; break; case NC_UINT: scv_new.val.ui64=(scv_old->val).ui; break; case NC_INT64: scv_new.val.ui64=(scv_old->val).i64; break; case NC_UINT64: scv_new.val.ui64=(scv_old->val).ui64; break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; case NC_STRING: switch(typ_old){ case NC_FLOAT: break; case NC_DOUBLE: break; case NC_INT: break; case NC_SHORT: break; case NC_BYTE: break; case NC_UBYTE: break; case NC_USHORT: break; case NC_UINT: break; case NC_INT64: break; case NC_UINT64: break; case NC_STRING: break; case NC_CHAR: break; case NC_NAT: break; } break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ scv_new.type=typ_new; *scv_old=scv_new; return True; } /* end nco_scv_cnf_typ */ nco_bool /* O [flg] Input is signed type */ nco_typ_sgn /* [fnc] Identify signed types */ (const nc_type typ_in) /* I [enm] Type to check for signedness */ { nco_bool flg_sgn=True; /* CEWI */ switch(typ_in){ case NC_FLOAT: case NC_DOUBLE: case NC_INT64: case NC_INT: case NC_SHORT: case NC_BYTE: case NC_CHAR: case NC_NAT: case NC_STRING: flg_sgn=True; break; case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_UINT64: flg_sgn=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return flg_sgn; } /* end nco_typ_sgn */ nco_bool /* O [flg] Input is netCDF3 atomic type */ nco_typ_nc3 /* [fnc] Identify netCDF3 atomic types */ (nc_type typ_in) /* I [enm] Type to check netCDF3 compliance */ { nco_bool flg_nc3=True; /* CEWI */ switch(typ_in){ case NC_FLOAT: case NC_DOUBLE: case NC_INT: case NC_SHORT: case NC_BYTE: case NC_CHAR: flg_nc3=True; break; case NC_STRING: case NC_INT64: case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_UINT64: flg_nc3=False; break; case NC_NAT: default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return flg_nc3; } /* end nco_typ_nc3 */ nc_type /* O [enm] netCDF3 type */ nco_typ_nc4_nc3 /* [fnc] Convert netCDF4 to netCDF3 atomic type */ (const nc_type typ_nc4) /* I [enm] netCDF4 type */ { /* Purpose: Perform intelligent type conversion from netCDF4->3 type */ /* Already netCDF3 type */ if(nco_typ_nc3(typ_nc4)) return typ_nc4; switch(typ_nc4){ case NC_UBYTE: return NC_SHORT; break; case NC_USHORT: case NC_UINT: case NC_INT64: case NC_UINT64: return NC_INT; break; case NC_STRING: return NC_CHAR; break; case NC_NAT: default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return typ_nc4; } /* end nco_typ_nc4_nc3 */ nc_type /* O [enm] Return Highest type */ ncap_typ_hgh /* [fnc] Return Highest type */ (nc_type typ_1, /* I [enm] type */ nc_type typ_2) /* I [enm] type */ { /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Perform intelligent type conversion with the netCDF3/4 types The logic is as follows 1) If one type is double highest type double .. end 2) if one type float then highest type float .. end 3) if both are signed type then highest type returned 4) if both are unsigned type then highest type returned 5) First var signed second var unsigned if the signed type can represent all values af the unsigned type Then the signed type returned If the types are the same then unsigned type returned If the signed type is less than the unsigned type then the unsigned type is returned Examples: NC_CHAR,NC_UBYTE -> result NC_CHAR NC_INT, NC_USHORT -> result NC_INT NC_SHORT, NC_UINT -> result NC_UINT NC_INT64, NC_UINT -> result NC_INT64 NC_INT64,NC_UINT64 -> result NC_UINT64 */ nco_bool v1s; nco_bool v2s; /* Already identical */ if(typ_1 == typ_2) return typ_1; /* Deal with NC_DOUBLE */ if(typ_1 == NC_DOUBLE || typ_2 == NC_DOUBLE) return NC_DOUBLE; /* Deal with NC_FLOAT */ if(typ_1 == NC_FLOAT || typ_2 == NC_FLOAT) return NC_FLOAT; v1s=nco_typ_sgn(typ_1); v2s=nco_typ_sgn(typ_2); /* Both signed or both unsigned */ if(v1s == v2s) return (typ_1 > typ_2 ? typ_1 : typ_2); /* From here on one is signed the other unsigned */ /* Swap vars about so var_1 is signed, var_2 unsigned */ if(v1s == False && v2s == True){ nc_type typ_tmp; typ_tmp=typ_1;typ_1=typ_2;typ_2=typ_tmp; } switch(typ_1){ case NC_NAT: return typ_2; break; case NC_BYTE: return typ_2; break; case NC_CHAR: return typ_2; break; case NC_SHORT: return (typ_2 < NC_USHORT ? typ_1 : typ_2); break; case NC_INT: return (typ_2 < NC_UINT ? typ_1 : typ_2); break; case NC_INT64: return (typ_2 < NC_UINT64 ? typ_1 : typ_2); break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return typ_1; } /* end ncap_typ_hgh */ nc_type /* O [enm] Higher precision of input variables */ ncap_var_retype /* [fnc] Promote variable to higher common precision */ (var_sct *var_1, /* I/O [sct] Variable */ var_sct *var_2) /* I/O [sct] Variable */ { /* Threads: Routine is thread safe and makes no unsafe routines */ /* Purpose: Perform intelligent type conversion with netCDF3/4 types */ nc_type typ_hgh; typ_hgh=ncap_typ_hgh(var_1->type,var_2->type); if(var_1->type != typ_hgh) var_1=nco_var_cnf_typ(typ_hgh,var_1); if(var_2->type != typ_hgh) var_2=nco_var_cnf_typ(typ_hgh,var_2); return typ_hgh; } /* end ncap_var_retype */ nc_type /* O [enm] Highest precision of arguments */ ncap_scv_scv_cnf_typ_hgh_prc /* [fnc] Promote arguments to higher precision if necessary */ (scv_sct * const scv_1, /* I/O [sct] Scalar value */ scv_sct * const scv_2) /* I/O [sct] Scalar value */ { /* fxm: TODO nco616: netCDF4 breaks assumption that range/precision increases with nc_type enum */ /* Purpose: Promote scalar values to higher of two precisions, if necessary */ if(scv_1->type == scv_2->type){ return scv_1->type; }else if(scv_1->type > scv_2->type){ (void)nco_scv_cnf_typ(scv_1->type,scv_2); return scv_1->type; }else{ (void)nco_scv_cnf_typ(scv_2->type,scv_1); return scv_2->type; } /* endif */ } /* end ncap_scv_scv_cnf_typ_hgh_prc */ nc_type /* O [enm] Highest precision of arguments */ ncap_var_scv_cnf_typ_hgh_prc /* [fnc] Promote arguments to higher precision if necessary */ (var_sct ** const var, /* I/O [sct] Variable */ scv_sct * const scv) /* I/O [sct] Scalar value */ { /* fxm: TODO nco616: netCDF4 breaks assumption that range/precision increases with nc_type enum */ /* Purpose: If types of variable and scalar value differ, convert argument with lower precision to higher precision type. Otherwise do nothing. fxm: Assumes nc_type increases monotonically with precision */ /* Do nothing if types match */ if((*var)->type == scv->type){ return (*var)->type; }else if((*var)->type > scv->type){ (void)nco_scv_cnf_typ((*var)->type,scv); return (*var)->type; }else{ *var=nco_var_cnf_typ(scv->type,*var); return scv->type; } /* endif */ } /* end ncap_var_scv_cnf_typ_hgh_prc() */ ./nco-4.4.2/src/nco/nco_ctl.c0000644000674300045400000017173612300514201015113 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_ctl.c,v 1.463 2014/02/17 23:17:21 zender Exp $ */ /* Purpose: Program flow control functions */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_ctl.h" /* Program flow control functions */ const char * /* O [sng] Compiler and version */ nco_cmp_get(void) /* [fnc] Return compiler and version */ { /* Purpose: Return string containing compiler and version */ const char fnc_nm[]="nco_cmp_get()"; #if defined(_AIX) && !defined(__GNUC__) && !defined(__xlC__) #define NCO_XLC_LIKELY static const char cmp_nm[]="xlc"; /* [sng] Compiler name */ static const char cmp_sng[]="Token _AIX defined in nco_cmp_get(), probably compiled with AIX xlc_r or xlc"; /* [sng] Compiler string */ #endif /* !_AIX */ #if defined(__xlC__) #define NCO_XLC_LIKELY static const char cmp_nm[]="xlC"; /* [sng] Compiler name */ static const char cmp_sng[]="Token __xlC__ defined in nco_cmp_get(), probably compiled with AIX xlC_r or xlC"; /* [sng] Compiler string */ #endif /* !__xlC__ */ #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__PATHCC__) && !defined(PGI_CC) /* Testing for GCC macros early is dangerous because some compilers, including Intel's, define GCC macros for compatibility */ static const char cmp_nm[]="gcc"; /* [sng] Compiler name */ static const char cmp_sng[]="Token __GNUC__ defined in nco_cmp_get(), probably compiled with GNU gcc"; /* [sng] Compiler string */ static const char cmp_vrs[]=TKN2SNG(__VERSION__); // [sng] Compiler version static const char cmp_vrs_mjr[]=TKN2SNG(__GNUC__); // [sng] Compiler major version static const char cmp_vrs_mnr[]=TKN2SNG(__GNUC_MINOR__); // [sng] Compiler minor version static const char cmp_vrs_pch[]=TKN2SNG(__GNUC_PATCHLEVEL__); // [sng] Compiler patch version if(nco_dbg_lvl_get() >= nco_dbg_fl){ (void)fprintf(stderr,"%s: INFO GCC major version is %s\n",nco_prg_nm_get(),cmp_vrs_mjr); (void)fprintf(stderr,"%s: INFO GCC minor version is %s\n",nco_prg_nm_get(),cmp_vrs_mnr); (void)fprintf(stderr,"%s: INFO GCC patch version is %s\n",nco_prg_nm_get(),cmp_vrs_pch); } /* endif dbg */ if(nco_dbg_lvl_get() >= nco_dbg_std){ (void)fprintf(stderr,"%s: INFO GCC version is %s\n",nco_prg_nm_get(),cmp_vrs); } /* endif dbg */ #endif /* !__GNUC__ */ #ifdef __INTEL_COMPILER /* Some compilers, including icc, also define __GNUC__ by default */ static const char cmp_nm[]="icc"; static const char cmp_sng[]="Token __INTEL_COMPILER defined in nco_cmp_get(), probably compiled with Intel icc"; /* [sng] Compiler string */ #endif /* !__INTEL_COMPILER */ #ifdef __PATHCC__ /* Some compilers, including pathcc, also define __GNUC__ by default */ static const char cmp_nm[]="pathcc"; static const char cmp_sng[]="Token __PATHCC__ defined in nco_cmp_get(), probably compiled with PathScale (Qlogic) pathcc"; /* [sng] Compiler string */ #endif /* !__PATHCC__ */ #ifdef PGI_CC static const char cmp_nm[]="pgcc"; static const char cmp_sng[]="Token PGI_CC defined in nco_cmp_get(), probably compiled with PGI pgcc"; /* [sng] Compiler string */ #endif /* !PGI_CC */ /* In case none of the above tokens matched */ #if !defined(NCO_XLC_LIKELY) && !defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__PATHCC__) && !defined(PGI_CC) /* Unknown compiler */ static const char cmp_nm[]="unknown"; /* [sng] Compiler name */ static const char cmp_sng[]="Unknown compiler tokens in nco_cmp_get(), compiler is unknown"; /* [sng] Compiler string */ #endif /* !unknown */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s reports compiler name is \"%s\"\n%s\n",nco_prg_nm_get(),fnc_nm,cmp_nm,cmp_sng); return cmp_nm; } /* end nco_cmp_get() */ const char * /* O [sng] MPI implementation */ nco_mpi_get(void) /* [fnc] Return MPI implementation */ { /* Purpose: Return string containing MPI implementation information */ const char fnc_nm[]="nco_mpi_get()"; #ifdef _H_MPI static const char mpi_nm[]="PPE"; /* [sng] MPI name */ static const char mpi_sng[]="Token _H_MPI defined in nco_mpi_get(), MPI environment is probably AIX PPE MPI"; /* [sng] MPI string */ #endif /* !_H_MPI */ #ifdef LAM_MPI static const char mpi_nm[]="LAM"; /* [sng] MPI name */ static const char mpi_sng[]="Token LAM_MPI defined in nco_mpi_get(), MPI environment is probably LAM-MPI"; /* [sng] MPI string */ #endif /* !LAM_MPI */ #if MPICH_NAME == '1' static const char mpi_nm[]="MPICH"; /* [sng] MPI name */ static const char mpi_sng[]="Token MPICH_NAME defined to 1 in nco_mpi_get(), MPI environment is probably MPICH version 1"; /* [sng] MPI string */ #endif /* !MPICH_NAME */ #ifdef MPICH2 static const char mpi_nm[]="MPICH2"; /* [sng] MPI name */ static const char mpi_sng[]="Token MPICH2 defined in nco_mpi_get(), MPI environment is probably MPICH2, i.e., MPICH version 2"; /* [sng] MPI string */ #endif /* !MPICH2 */ /* In case no token matched */ #if !defined(_H_MPI) && !defined(LAM_MPI) && (MPICH_NAME != '1') && !defined(MPICH2) #ifndef MPI_VERSION /* MPI is not installed */ static const char mpi_nm[]="none"; /* [sng] MPI name */ static const char mpi_sng[]="No MPI tokens found in nco_mpi_get(), MPI environment is not active"; /* [sng] MPI string */ #else /* MPI_VERSION */ /* Unknown MPI implementation */ static const char mpi_nm[]="unknown"; /* [sng] MPI name */ static const char mpi_sng[]="Unknown MPI tokens found in nco_mpi_get(), MPI environment is present and of unknown pedigree"; /* [sng] MPI string */ #endif /* MPI_VERSION */ #endif /* !unknown */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s reports MPI implementation name is \"%s\"\n%s\n",nco_prg_nm_get(),fnc_nm,mpi_nm,mpi_sng); return mpi_nm; } /* end nco_mpi_get() */ int /* O [rcd] Return code */ nco_ddra /* [fnc] Count operations */ (const char * const var_nm, /* I [sng] Variable name */ const char * const wgt_nm, /* I [sng] Weight name */ const ddra_info_sct * const ddra_info) /* I [sct] DDRA information */ { /* Purpose: Estimate operation counts required */ /* 20070509 CEWI RUVICFFU: ntg_nbr_rdc_dfl, ntg_nbr_nrm_dfl, flp_nbr_rdc_dfl, flp_nbr_nrm_dfl, rnk_avg */ const char fnc_nm[]="nco_ddra()"; /* Following speed parameter estimates are for clay.ess.uci.edu clay is the dual opteron used in ppr_ZeM07 */ const float ntg_nbr_brd_fdg_fct=1.8; /* [frc] Empirical correction to broadcasting */ const float spd_flp_ncwa=153e6; /* [# s-1] Floating point operation speed */ const float spd_ntg_ncwa=200e6; /* [# s-1] Integer operation speed */ const float spd_flp_ncbo=353.2e6; /* [# s-1] Floating point operation speed */ const float spd_ntg_ncbo=1386.54e6; /* [# s-1] Integer operation speed */ const float spd_rd=63.375e6; /* [B s-1] Disk read bandwidth */ const float spd_wrt=57.865e6; /* [B s-1] Disk write bandwidth */ /* 20060602: hjm estimates faster speeds for ncbo: spd_flp_ncbo = 353.2e6: Based on unoptimized operations in tacg function spd_ntg_ncbo = 1386.54e6: Based on counting unoptimized operations in tacg function hjm estimates slower speeds for ncwa: spd_flp_ncwa = 153e6: Based on direct PAPI measures spd_ntg_ncwa = 200e6: Based on direct measure, using large data set, calculating backwards */ float spd_flp=float_CEWI; /* [# s-1] Floating point operation speed */ float spd_ntg=float_CEWI; /* [# s-1] Integer operation speed */ int rcd=NC_NOERR; /* [rcd] Return code */ /* Timer information */ static clock_t tm_obs_old; /* [us] Microseconds initially */ static float tm_obs_ttl=0.0; /* [s] Total seconds elapsed */ clock_t tm_obs_crr; /* [us] Microseconds currently */ float tm_obs_dff; /* [s] Seconds elapsed */ /* Cumulative file costs */ static long long lmn_nbr_ttl=0LL; /* I/O [nbr] Cumulative variable size */ static long long ntg_nbr_ttl=0LL; /* I/O [nbr] Cumulative integer operations */ static long long flp_nbr_ttl=0LL; /* I/O [nbr] Cumulative floating point operations */ /* Cumulative times */ static float tm_ntg_ttl=0.0f; /* I/O [s] Cumulative integer time */ static float tm_flp_ttl=0.0f; /* I/O [s] Cumulative floating point time */ static float tm_rd_ttl=0.0f; /* I/O [s] Cumulative read time */ static float tm_wrt_ttl=0.0f; /* I/O [s] Cumulative write time */ static float tm_io_ttl=0.0f; /* [s] I/O time */ static float tm_ttl=0.0f; /* I/O [s] Cumulative time */ /* Current variable costs */ float tm_ntg; /* [s] Integer time */ float tm_flp; /* [s] Floating point time */ float tm_rd; /* [s] Read time */ float tm_wrt; /* [s] Write time */ float tm_io=float_CEWI; /* [s] I/O time */ float tm_crr=float_CEWI; /* [s] Time for this variable */ long long ntg_nbr=long_long_CEWI; /* [nbr] Integer operations */ long long flp_nbr=long_long_CEWI; /* [nbr] Floating point operations */ long long rd_nbr_byt=long_long_CEWI; /* [B] Bytes read */ long long wrt_nbr_byt=long_long_CEWI; /* [B] Bytes written */ /* Summary statistics */ float tm_frc_flp_ttl=float_CEWI; /* [frc] Floating point time fraction */ float tm_frc_io_ttl=float_CEWI; /* [frc] I/O time fraction */ float tm_frc_ntg_ttl=float_CEWI; /* [frc] Integer time fraction */ float tm_frc_rd_ttl=float_CEWI; /* [frc] Read time fraction */ float tm_frc_wrt_ttl=float_CEWI; /* [frc] Write time fraction */ /* Default algorithm costs if invoked */ long long ntg_nbr_byt_swp_dfl; /* [nbr] Integer operations for byte-swap */ long long ntg_nbr_brd_dfl; /* [nbr] Integer operations for broadcasting */ long long ntg_nbr_clc_dfl; /* [nbr] Integer operations for collection */ /* long long ntg_nbr_rdc_dfl; */ /* [nbr] Integer operations for reduction */ /* long long ntg_nbr_nrm_dfl; */ /* [nbr] Integer operations for normalization */ long long flp_nbr_bnr_dfl; /* [nbr] Floating point operations for binary arithmetic */ /* long long flp_nbr_rdc_dfl; */ /* [nbr] Floating point operations for reduction */ /* long long flp_nbr_nrm_dfl; */ /* [nbr] Floating point operations for normalization */ /* Initialize all algorithm counts for this variable to zero then increment */ long long ntg_nbr_byt_swp=0LL; /* [nbr] Integer operations for byte-swap */ long long ntg_nbr_brd=0LL; /* [nbr] Integer operations for broadcasting */ long long ntg_nbr_clc=0LL; /* [nbr] Integer operations for collection */ long long ntg_nbr_rdc=0LL; /* [nbr] Integer operations for reduction */ long long ntg_nbr_nrm=0LL; /* [nbr] Integer operations for normalization */ long long flp_nbr_bnr=0LL; /* [nbr] Floating point operations for binary arithmetic */ long long flp_nbr_rdc=0LL; /* [nbr] Floating point operations for reduction */ long long flp_nbr_nrm=0LL; /* [nbr] Floating point operations for normalization */ /* Copies of DDRA information */ int nco_op_typ; /* [enm] Operation type */ /* int rnk_avg; */ /* [nbr] Rank of averaging space */ int rnk_var; /* [nbr] Variable rank (in input file) */ int rnk_wgt; /* [nbr] Rank of weight */ int var_idx=int_CEWI; /* [enm] Index */ int wrd_sz; /* [B] Bytes per element */ long long lmn_nbr=int_CEWI; /* [nbr] Variable size */ long long lmn_nbr_avg; /* [nbr] Averaging block size */ long long lmn_nbr_wgt; /* [nbr] Weight size */ nco_bool MRV_flg; /* [flg] Avergaging dimensions are MRV dimensions */ nco_bool wgt_brd_flg; /* [flg] Broadcast weight for this variable */ /* Locals */ long long lmn_nbr_out=long_long_CEWI; /* [nbr] Output elements */ /* Where possible, work in terms of "default" counts per algorithm Algorithms (e.g., reduction, byte-swapping) are generally subroutines Record hand-counted counts in only one place This makes it easier and less error-prone to propagate optimizations Also, easier to think in terms of procedures than raw counts Algorithms for subtraction: "byte_swap+byte_swap+binary_arithmetic+byte_swap" Algorithms for non-weighted, non-MRV averaging: "byte_swap(input)+collection+reduction+normalization+byte_swap(output)" Algorithms for non-weighted, MRV averaging: "byte_swap(input)+reduction+normalization+byte_swap(output)" Algorithms for weighted, non-MRV averaging: "byte_swap(input)+byte_swap(weight)+broadcast(weight)+ collection(numerator)+collection(denominator)+ binary_arithmetic(weight*value)+ reduction(numerator)+reduction(denominator)+ normalization(numerator)+normalization(denominator)+byte_swap(output)" Units: [nbr] = Operation counts for lmn_nbr elements [nbr nbr-1] = Operation counts per element */ switch(ddra_info->tmr_flg){ case nco_tmr_srt: /* [enm] Initialize timer (first timer call) */ tm_obs_crr=clock(); tm_obs_old=tm_obs_crr; return rcd; /* [rcd] Return code */ break; case nco_tmr_mtd: /* [enm] Metadata timer (second timer call) */ case nco_tmr_end: /* [enm] Close timer (last timer call) */ goto update_timers; break; case nco_tmr_rgl: /* [enm] Regular timer call (main loop timer call) */ break; default: nco_dfl_case_tmr_typ_err(); break; } /* end switch */ /* Decode input */ MRV_flg=ddra_info->MRV_flg; /* [flg] Avergaging dimensions are MRV dimensions */ lmn_nbr=ddra_info->lmn_nbr; /* [nbr] Variable size */ lmn_nbr_avg=ddra_info->lmn_nbr_avg; /* [nbr] Averaging block size */ lmn_nbr_wgt=ddra_info->lmn_nbr_wgt; /* [nbr] Weight size */ nco_op_typ=ddra_info->nco_op_typ; /* [enm] Operation type */ /* rnk_avg=ddra_info->rnk_avg; */ /* [nbr] Rank of averaging space */ rnk_var=ddra_info->rnk_var; /* [nbr] Variable rank (in input file) */ rnk_wgt=ddra_info->rnk_wgt; /* [nbr] Rank of weight */ var_idx=ddra_info->var_idx; /* [enm] Index */ wgt_brd_flg=ddra_info->wgt_brd_flg; /* [flg] Broadcast weight for this variable */ wrd_sz=ddra_info->wrd_sz; /* [B] Bytes per element */ /* Derived variables */ switch(nco_op_typ){ /* Types used in ncbo(), ncflint() */ case nco_op_add: /* [enm] Add file_1 to file_2 */ case nco_op_dvd: /* [enm] Divide file_1 by file_2 */ case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */ case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */ spd_flp=spd_flp_ncbo; /* [# s-1] Floating point operation speed */ spd_ntg=spd_ntg_ncbo; /* [# s-1] Integer operation speed */ lmn_nbr_out=lmn_nbr; /* [nbr] Output elements */ break; /* Types used in ncra(), ncrcat(), ncwa(): */ case nco_op_avg: /* [enm] Average */ case nco_op_min: /* [enm] Minimum value */ case nco_op_max: /* [enm] Maximum value */ case nco_op_ttl: /* [enm] Linear sum */ case nco_op_sqravg: /* [enm] Square of mean */ case nco_op_avgsqr: /* [enm] Mean of sum of squares */ case nco_op_sqrt: /* [enm] Square root of mean */ case nco_op_rms: /* [enm] Root-mean-square (normalized by N) */ case nco_op_rmssdn: /* [enm] Root-mean square normalized by N-1 */ spd_flp=spd_flp_ncwa; /* [# s-1] Floating point operation speed */ spd_ntg=spd_ntg_ncwa; /* [# s-1] Integer operation speed */ lmn_nbr_out=lmn_nbr/lmn_nbr_avg; /* [nbr] Output elements */ break; case nco_op_nil: /* [enm] Nil or undefined operation type */ break; default: (void)fprintf(stdout,"%s: ERROR Illegal nco_op_typ in %s\n",nco_prg_nm_get(),fnc_nm); nco_exit(EXIT_FAILURE); break; } /* end switch */ flp_nbr_bnr_dfl=lmn_nbr; /* [nbr] Floating point operations for binary arithmetic */ /* flp_nbr_nrm_dfl=lmn_nbr_out; */ /* [nbr] Floating point operations for normalization */ /* flp_nbr_rdc_dfl=lmn_nbr; */ /* [nbr] Floating point operations for reduction */ /* Integer operations for broadcasting weight */ ntg_nbr_brd_dfl=(long long int)(ntg_nbr_brd_fdg_fct*lmn_nbr*(6*rnk_var+8*rnk_wgt+2)); /* [nbr] N(6R+8R_w+2) */ /* Byte-swap integer operations per element */ ntg_nbr_byt_swp_dfl=wrd_sz+2; /* [nbr nbr-1] W+2 */ /* Integer operations for collection */ ntg_nbr_clc_dfl=lmn_nbr*(14*rnk_var+4); /* [nbr] N(14R+4) */ /* Integer operations for normalization */ /* ntg_nbr_nrm_dfl=4*lmn_nbr_out; */ /* [nbr] 4N/N_A = 4N_O */ /* Integer operations for reduction */ /* ntg_nbr_rdc_dfl=lmn_nbr*6+lmn_nbr_out; */ /* [nbr] N(6+N/N_A) */ switch(nco_op_typ){ /* Types used in ncbo(), ncflint() */ case nco_op_add: /* [enm] Add file_1 to file_2 */ case nco_op_dvd: /* [enm] Divide file_1 by file_2 */ case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */ case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */ /* Subtraction computation assumes variables are same size fxm: Account for broadcasting */ /* One floating point (add/subtract/multiply/divide) per element */ flp_nbr_bnr=flp_nbr_bnr_dfl; /* Byte-swap elements from two input files and one output file */ ntg_nbr_byt_swp=3*lmn_nbr*ntg_nbr_byt_swp_dfl; /* 3N(W+2) */ rd_nbr_byt=2*lmn_nbr*wrd_sz; /* [B] Bytes read */ wrt_nbr_byt=lmn_nbr_out*wrd_sz; /* [B] Bytes written */ break; /* Types used in ncra(), ncrcat(), ncwa(): */ case nco_op_avg: /* [enm] Average */ case nco_op_min: /* [enm] Minimum value */ case nco_op_max: /* [enm] Maximum value */ case nco_op_ttl: /* [enm] Linear sum */ case nco_op_sqravg: /* [enm] Square of mean */ case nco_op_avgsqr: /* [enm] Mean of sum of squares */ case nco_op_sqrt: /* [enm] Square root of mean */ case nco_op_rms: /* [enm] Root-mean-square (normalized by N) */ case nco_op_rmssdn: /* [enm] Root-mean square normalized by N-1 */ rd_nbr_byt=lmn_nbr*wrd_sz; /* [B] Bytes read */ wrt_nbr_byt=lmn_nbr_out*wrd_sz; /* [B] Bytes written */ /* One floating point add per input element to sum numerator */ flp_nbr_rdc=lmn_nbr; /* One floating point divide per output element to normalize numerator by denominatro (tally) */ flp_nbr_nrm=lmn_nbr_out; /* Byte-swap elements from one input file and one (rank-reduced) output file */ ntg_nbr_byt_swp=(lmn_nbr+lmn_nbr_out)*ntg_nbr_byt_swp_dfl; if(!MRV_flg){ /* Collection required for numerator */ ntg_nbr_clc+=ntg_nbr_clc_dfl; } /* !MRV_flg */ if(wgt_nm){ if(var_idx == 0){ /* Set cost = 0 after first variable since only read weight once */ rd_nbr_byt+=lmn_nbr_wgt*wrd_sz; /* [B] Bytes read */ /* Byte-swap cost for first weight input is usually negligible */ ntg_nbr_byt_swp+=lmn_nbr_wgt*ntg_nbr_byt_swp_dfl; } /* var_idx != 0 */ /* One floating point multiply per input element for weight*value in numerator, and one floating point add per input element to sum weight in denominator */ flp_nbr_rdc+=2*lmn_nbr; /* One floating point divide per output element to normalize denominator by tally */ flp_nbr_nrm+=lmn_nbr_out; if(wgt_brd_flg){ /* fxm: Charge for broadcasting weight at least once */ /* Broadcasting cost for weight */ ntg_nbr_brd=ntg_nbr_brd_dfl; } /* !wgt_brd_flg */ if(!MRV_flg){ /* Collection required for denominator */ ntg_nbr_clc+=ntg_nbr_clc_dfl; } /* !MRV_flg */ } /* !wgt_nm */ break; case nco_op_nil: /* [enm] Nil or undefined operation type */ break; default: (void)fprintf(stdout,"%s: ERROR Illegal nco_op_typ in %s\n",nco_prg_nm_get(),fnc_nm); nco_exit(EXIT_FAILURE); break; } /* end switch */ flp_nbr= /* [nbr] Floating point operations */ flp_nbr_bnr+ /* [nbr] Floating point operations for binary arithmetic */ flp_nbr_rdc+ /* [nbr] Floating point operations for reduction */ flp_nbr_nrm; /* [nbr] Floating point operations for normalization */ ntg_nbr= /* [nbr] Integer operations */ ntg_nbr_byt_swp+ /* [nbr] Integer operations for byte-swap */ ntg_nbr_brd+ /* [nbr] Integer operations for broadcasting */ ntg_nbr_clc+ /* [nbr] Integer operations for collection */ ntg_nbr_rdc+ /* [nbr] Integer operations for reduction */ ntg_nbr_nrm; /* [nbr] Integer operations for normalization */ tm_ntg=ntg_nbr/spd_ntg; /* [s] Integer time */ tm_flp=flp_nbr/spd_flp; /* [s] Floating point time */ tm_rd=rd_nbr_byt/spd_rd; /* [s] Read time */ tm_wrt=wrt_nbr_byt/spd_wrt; /* [s] Write time */ tm_io=tm_rd+tm_wrt; /* [s] I/O time */ tm_crr=tm_ntg+tm_flp+tm_rd+tm_wrt; /* [s] Time for this variable */ /* Increment running totals */ lmn_nbr_ttl+=lmn_nbr; /* [nbr] Cumulative variable size */ flp_nbr_ttl+=flp_nbr; /* [nbr] Cumulative floating point operations */ ntg_nbr_ttl+=ntg_nbr; /* [nbr] Cumulative integer operations */ tm_ntg_ttl+=tm_ntg; /* [s] Cumulative integer time */ tm_flp_ttl+=tm_flp; /* [s] Cumulative floating point time */ tm_rd_ttl+=tm_rd; /* [s] Cumulative read time */ tm_wrt_ttl+=tm_wrt; /* [s] Cumulative write time */ tm_io_ttl+=tm_io; /* [s] Cumulative I/O time */ tm_ttl+=tm_crr; /* [s] Cumulative time */ tm_frc_flp_ttl=tm_flp_ttl/tm_ttl; /* [frc] Floating point time fraction */ tm_frc_io_ttl=tm_io_ttl/tm_ttl; /* [frc] I/O time fraction */ tm_frc_ntg_ttl=tm_ntg_ttl/tm_ttl; /* [frc] Integer time fraction */ tm_frc_rd_ttl=tm_rd_ttl/tm_ttl; /* [frc] Read time fraction */ tm_frc_wrt_ttl=tm_wrt_ttl/tm_ttl; /* [frc] Write time fraction */ if(var_idx == 0){ /* Table headings */ (void)fprintf(stderr,"%3s %8s %8s %8s %8s %5s %5s %8s %8s %8s %4s %4s %4s %4s %4s %7s %7s\n", "idx"," var_nm "," lmn "," flp "," ntg ","tm_io"," tm "," lmn_ttl"," flp_ttl"," ntg_ttl"," flp"," ntg"," rd"," wrt"," io"," tm_ttl"," tm_obs"); (void)fprintf(stderr,"%3s %8s %8s %8s %8s %5s %5s %8s %8s %8s %4s %4s %4s %4s %4s %7s %7s\n", " "," "," # "," # "," # "," s "," s "," # "," # "," # "," % "," % "," % "," % "," % "," s "," s "); } /* var_idx != 0 */ /* Update timers */ update_timers: /* NB: POSIX requires CLOCKS_PER_SEC equals 1000000 so resolution = 1 microsecond */ tm_obs_crr=clock(); tm_obs_dff=(float)(tm_obs_crr-tm_obs_old)/CLOCKS_PER_SEC; tm_obs_old=tm_obs_crr; tm_obs_ttl+=tm_obs_dff; switch(ddra_info->tmr_flg){ case nco_tmr_mtd: /* [enm] Metadata timer (second timer call) */ if(ddra_info->flg_ddra || nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stderr,"%s: TIMER Metadata setup and file layout before main loop took %7.2f s\n",nco_prg_nm_get(),tm_obs_ttl); break; case nco_tmr_rgl: /* [enm] Regular timer call (main loop timer call) */ (void)fprintf(stderr, "%3d %8s %8.2e %8.2e %8.2e %5.2f %5.2f %8.2e %8.2e %8.2e %4.1f %4.1f %4.1f %4.1f %4.1f %7.2f %7.2f\n", var_idx,var_nm,(float)lmn_nbr,(float)flp_nbr,(float)ntg_nbr,tm_io,tm_crr,(float)lmn_nbr_ttl,(float)flp_nbr_ttl,(float)ntg_nbr_ttl,100.0*tm_frc_flp_ttl,100.0*tm_frc_ntg_ttl,100.0*tm_frc_rd_ttl,100.0*tm_frc_wrt_ttl,100.0*tm_frc_io_ttl,tm_ttl,tm_obs_ttl); break; case nco_tmr_end: /* [enm] Close timer (last timer call) */ if(ddra_info->flg_ddra || nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stderr,"%s: TIMER Wallclock-elapsed time for command is %7.2f s\n",nco_prg_nm_get(),tm_obs_ttl); break; default: nco_dfl_case_tmr_typ_err(); break; } /* end switch */ return rcd; /* [rcd] Return code */ } /* nco_ddra() */ void nco_dfl_case_tmr_typ_err(void) /* [fnc] Print error and exit for illegal switch(tmr_typ) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(tmr_typ) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_tmr_typ_err()"; (void)fprintf(stdout,"%s: ERROR switch(tmr_typ) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(tmr_typ) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_tmr_typ_err() */ void nco_exit /* [fnc] Wrapper for exit() */ (int rcd) /* I [enm] Return code */ { /* Purpose: Wrapper for exit() */ const char fnc_nm[]="nco_exit()"; #ifdef NCO_ABORT_ON_ERROR const char exit_nm[]="abort()"; #else /* !NCO_ABORT_ON_ERROR */ const char exit_nm[]="exit(EXIT_FAILURE)"; #endif /* !NCO_ABORT_ON_ERROR */ if(rcd == EXIT_SUCCESS){ exit(rcd); }else{ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stdout,"%s: ERROR exiting through %s which will now call %s\n",nco_prg_nm_get(),fnc_nm,exit_nm); #ifdef NCO_ABORT_ON_ERROR abort(); #else /* !NCO_ABORT_ON_ERROR */ exit(rcd); #endif /* !NCO_ABORT_ON_ERROR */ } /* endif rcd */ } /* nco_exit() */ void nco_exit_gracefully(void) /* [fnc] Clean up timers, file descriptors, memory, then exit */ { /* Purpose: Clean up timers, file descriptors, memory, then exit */ (void)fclose(stderr); (void)fclose(stdin); (void)fclose(stdout); /* This should be penultimate command in program After program name is free'd, calls to nco_prg_nm_get() will fail */ (void)nco_free(nco_prg_nm_get()); nco_exit(EXIT_SUCCESS); } /* end nco_exit_gracefully() */ nco_bool /* [flg] Program is multi-file operator */ nco_is_mfo /* [fnc] Query whether program is multi-file operator */ (const int nco_prg_id) /* [enm] Program ID */ { /* Purpose: Is this a multi-file operator (MFO)? MFOs take arbitrarily large numbers of input files ncbo and ncflint are not MFOs because they take a fixed number (two) of input files MFOs attempt to read input filenames from stdin when input filenames are not positional arguments */ switch(nco_prg_id){ case ncfe: case ncecat: case ncra: case ncrcat: case ncge: return True; break; case ncap: case ncatted: case ncbo: case ncflint: case ncks: case ncpdq: case ncrename: case ncwa: return False; break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ return False; } /* end nco_is_mfo() */ nco_bool /* [flg] Program does arithmetic */ nco_is_rth_opr /* [fnc] Query whether program does arithmetic */ (const int nco_prg_id) /* [enm] Program ID */ { /* Purpose: Is operator arithmetic? For purposes of this function, an arithmetic operator is one which changes values Concatenators (ncrcat, ncecat) are not arithmetic because they just glue data Permutor (ncpdq) is not arithmetic because it just re-arranges values Packer (ncpdq) is not arithmetic because it re-represents values Attributors (ncrename, ncatted) are not arithmetic because they change metadata, not data nco_is_rth_opr() flag help control packing behavior Clearly, arithmetic operators must operate on unpacked values Hence, one use of nco_is_rth_opr() is to tell arithmetic operators to automatically unpack variables when reading them Non-arithmetic operators do not need to unpack variables */ switch(nco_prg_id){ case ncap: case ncbo: case ncfe: case ncflint: case ncra: case ncwa: case ncge: return True; break; case ncatted: case ncecat: case ncks: case ncpdq: case ncrcat: case ncrename: return False; break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ return False; } /* end nco_is_rth_opr() */ nco_bool /* [flg] Program does arithmetic and preserves rank */ nco_is_sz_rnk_prv_rth_opr /* [fnc] Is program size and rank-preserving arithmetic operator? */ (const int nco_prg_id, /* I [enm] Program ID */ const int nco_pck_plc) /* I [enm] Packing policy */ { /* Purpose: Is program size and rank-preserving arithmetic operator? For purposes of this function, arithmetic operators change values Concatenators (ncrcat, ncecat) are not arithmetic because they just glue data Permutor (ncpdq) _is not_ arithmetic because it only re-arranges values Packer (ncpdq) _is_ arithmetic because it uses floating point arithmetic to re-represent values nco_pck_plc flag is required as input and used only to distinguish between ncpdq packing and permuting. Attributors (ncrename, ncatted) are not arithmetic because they change metadata, not data Averager ncwa is clearly not size or rank-preserving Averager ncra preserves numeric rank though not record-dimension size and so is so is not size and rank-preserving. One use of nco_is_sz_rnk_prv_rth_opr() is to tell which operators should not process multidimensional coordinate values. For example, we want ncwa to act on coordinates that are reduced However, we do not want ncfe, ncbo, or ncflint, for example, to load and process single or multi-dimensional coordinate variables. Nor do we want ncpdq to pack variables like gaussian weights, or area since that causes a significant loss of arithmetic precision when those are used as weights in re-inflated files. Such variables to these operators are best treated as "fixed" variables to be copied directly from the input to the output file. */ switch(nco_prg_id){ case ncap: case ncbo: case ncfe: case ncge: case ncflint: return True; break; case ncatted: case ncecat: case ncks: case ncrcat: case ncra: /* Process (not fix) time-varying fields like date, datesec */ case ncrename: case ncwa: return False; break; case ncpdq: if(nco_pck_plc != nco_pck_plc_nil) return True; else return False; break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ return False; } /* end nco_is_sz_rnk_prv_rth_opr() */ void nco_lbr_vrs_prn(void) /* [fnc] Print netCDF library version */ { /* Purpose: Print netCDF library version */ char *cmp_dat_sng; char *dlr_ptr; char *lbr_sng; char *lbr_vrs_sng; char *of_ptr; size_t cmp_dat_sng_lng; size_t lbr_vrs_sng_lng; /* Behavior of nc_inq_libvers() depends on library versions. Return values are: netCDF 3.4--3.6.x: "3.4 of May 16 1998 14:06:16 $" netCDF 4.0-alpha1--4.0-alpha10: NULL netCDF 4.0-alpha11--4.0-alpha16: "4.0-alpha11" netCDF 4.0-beta1--present: "4.0-beta1" */ lbr_sng=(char *)strdup(nc_inq_libvers()); /* (void)fprintf(stderr,"%s: nco_lbr_vrs_prn() returns %s\n",nco_prg_nm_get(),lbr_sng);*/ of_ptr=strstr(lbr_sng," of "); if(of_ptr == NULL){ (void)fprintf(stderr,"%s: WARNING nco_lbr_vrs_prn() reports of_ptr == NULL\n",nco_prg_nm_get()); lbr_vrs_sng_lng=(size_t)strlen(lbr_sng); }else{ lbr_vrs_sng_lng=(size_t)(of_ptr-lbr_sng); } /* endif */ lbr_vrs_sng=(char *)nco_malloc(lbr_vrs_sng_lng+1ul); strncpy(lbr_vrs_sng,lbr_sng,lbr_vrs_sng_lng); lbr_vrs_sng[lbr_vrs_sng_lng]='\0'; /* NUL-terminate */ dlr_ptr=strstr(lbr_sng," $"); if(of_ptr && dlr_ptr){ cmp_dat_sng_lng=(size_t)(dlr_ptr-of_ptr-4ul); /* 4 is the length of " of " */ cmp_dat_sng=(char *)nco_malloc(cmp_dat_sng_lng+1ul); strncpy(cmp_dat_sng,of_ptr+4ul,cmp_dat_sng_lng); /* 4 is the length of " of " */ cmp_dat_sng[cmp_dat_sng_lng]='\0'; /* NUL-terminate */ }else{ cmp_dat_sng=(char *)strdup("Unknown"); } /* endif */ (void)fprintf(stderr,"Linked to netCDF library version %s, compiled %s\n",lbr_vrs_sng,cmp_dat_sng); cmp_dat_sng=(char *)nco_free(cmp_dat_sng); lbr_vrs_sng=(char *)nco_free(lbr_vrs_sng); lbr_sng=(char *)nco_free(lbr_sng); } /* end nco_lbr_vrs_prn() */ void nco_cnf_prn(void) /* [fnc] Print NCO configuration and help text */ { /* Purpose: Print NCO configuration and help text */ (void)fprintf(stdout,"Homepage: http://nco.sf.net\n"); (void)fprintf(stdout,"User's Guide: http://nco.sf.net/nco.html\n"); /* fxm: TKN2YESNO breaks when TKN is undefined Full macro language like M4 might be useful here, though probably too much trouble */ #define TKN2YESNO(x) ((x+0) ? ("No"):("Yes")) /* NB: Keep configuration option tokens consistent among configure.ac, bld/Makefile, and nco_ctl.c Alphabetize list by first word in English text description of token */ (void)fprintf(stdout,"Configuration Option:\tActive?\tMeaning or Reference:\nCheck _FillValue\t%s\thttp://nco.sf.net/nco.html#mss_val\nCheck missing_value\t%s\thttp://nco.sf.net/nco.html#mss_val\nCompressed netCDF3\t%s\thttp://nco.sf.net/nco.html#znetcdf (pre-alpha)\nDAP clients (libdap)\t%s\thttp://nco.sf.net/nco.html#dap\nDAP clients (libnetcdf)\t%s\thttp://nco.sf.net/nco.html#dap\nDebugging: Custom\t%s\tPedantic, bounds checking (slowest execution)\nDebugging: Symbols\t%s\tProduce symbols for debuggers (e.g., dbx, gdb)\nGNU Scientific Library\t%s\thttp://nco.sf.net/nco.html#gsl\nHDF4 support\t\t%s\thttp://nco.sf.net/nco.html#hdf4\nInternationalization\t%s\thttp://nco.sf.net/nco.html#i18n (pre-alpha)\nMPI parallelization\t%s\thttp://nco.sf.net/nco.html#mpi (beta)\nnetCDF3 64-bit files\t%s\thttp://nco.sf.net/nco.html#lfs\nnetCDF4/HDF5 available\t%s\thttp://nco.sf.net/nco.html#nco4\nnetCDF4/HDF5 enabled\t%s\thttp://nco.sf.net/nco.html#nco4\nOpenMP SMP threading\t%s\thttp://nco.sf.net/nco.html#omp\nOptimization: run-time\t%s\tFastest execution possible (slowest compilation)\nParallel netCDF3\t%s\thttp://nco.sf.net/nco.html#pnetcdf (pre-alpha)\nRegular Expressions\t%s\thttp://nco.sf.net/nco.html#rx\nShared libraries built\t%s\tSmall, dynamically linked executables\nStatic libraries built\t%s\tLarge executables with private namespaces\nUDUnits conversions\t%s\thttp://nco.sf.net/nco.html#udunits\nUDUnits2 conversions\t%s\thttp://nco.sf.net/nco.html#udunits\n%s", (!strcmp("_FillValue",nco_mss_val_sng_get())) ? "Yes" : "No", (!strcmp("missing_value",nco_mss_val_sng_get())) ? "Yes" : "No", #if defined(ENABLE_ZNETCDF) && (ENABLE_ZNETCDF) "Yes", #else /* !ENABLE_ZNETCDF */ "No", #endif /* !ENABLE_ZNETCDF */ #if defined(ENABLE_DAP_OPENDAP) && (ENABLE_DAP_OPENDAP) "Yes", #else /* !ENABLE_DAP_OPENDAP */ "No", #endif /* !ENABLE_DAP_OPENDAP */ #if defined(ENABLE_DAP_NETCDF) && (ENABLE_DAP_NETCDF) "Yes", #else /* !ENABLE_DAP_NETCDF */ "No", #endif /* !ENABLE_DAP_NETCDF */ #if defined(ENABLE_DEBUG_CUSTOM) && (ENABLE_DEBUG_CUSTOM) "Yes", #else /* !ENABLE_DEBUG_CUSTOM */ "No", #endif /* !ENABLE_DEBUG_CUSTOM */ #if defined(ENABLE_DEBUG_SYMBOLS) && (ENABLE_DEBUG_SYMBOLS) "Yes", #else /* !ENABLE_DEBUG_SYMBOLS */ "No", #endif /* !ENABLE_DEBUG_SYMBOLS */ #if defined(ENABLE_GSL) && (ENABLE_GSL) "Yes", #else /* !ENABLE_GSL */ "No", #endif /* !ENABLE_GSL */ /* 20131018: This switch is not active yet. Requires netCDF library support */ #if defined(ENABLE_HDF4) && (ENABLE_HDF4) "Yes", #else /* !ENABLE_HDF4 */ "Unknown", #endif /* !ENABLE_HDF4 */ #if defined(I18N) && (I18N) "Yes", #else /* !I18N */ "No", #endif /* !I18N */ #if defined(ENABLE_MPI) && (ENABLE_MPI) "Yes", #else /* !ENABLE_MPI */ "No", #endif /* !ENABLE_MPI */ #if defined(NC_64BIT_OFFSET) && (NC_64BIT_OFFSET) "Yes", #else /* !NC_64BIT_OFFSET */ "No", #endif /* !NC_64BIT_OFFSET */ #if defined(HAVE_NETCDF4_H) && (HAVE_NETCDF4_H) "Yes", #else /* !HAVE_NETCDF4_H */ "No", #endif /* !HAVE_NETCDF4_H */ #if defined(ENABLE_NETCDF4) && (ENABLE_NETCDF4) "Yes", #else /* !ENABLE_NETCDF4 */ "No", #endif /* !ENABLE_NETCDF4 */ #if defined(_OPENMP) && (_OPENMP) "Yes", #else /* !_OPENMP */ "No", #endif /* !_OPENMP */ #if defined(ENABLE_OPTIMIZE_CUSTOM) && (ENABLE_OPTIMIZE_CUSTOM) "Yes", #else /* !ENABLE_OPTIMIZE_CUSTOM */ "No", #endif /* !ENABLE_OPTIMIZE_CUSTOM */ #if defined(ENABLE_PNETCDF) && (ENABLE_PNETCDF) "Yes", #else /* !ENABLE_PNETCDF */ "No", #endif /* !ENABLE_PNETCDF */ #if defined(NCO_HAVE_REGEX_FUNCTIONALITY) && (NCO_HAVE_REGEX_FUNCTIONALITY) "Yes", #else /* !NCO_HAVE_REGEX_FUNCTIONALITY */ "No", #endif /* !NCO_HAVE_REGEX_FUNCTIONALITY */ #if defined(ENABLE_SHARED) && (ENABLE_SHARED) "Yes", #else /* !ENABLE_SHARED */ "No", #endif /* !ENABLE_SHARED */ #if defined(ENABLE_STATIC) && (ENABLE_STATIC) "Yes", #else /* !ENABLE_STATIC */ "No", #endif /* !ENABLE_STATIC */ #if defined(ENABLE_UDUNITS) && (ENABLE_UDUNITS) "Yes", #else /* !ENABLE_UDUNITS */ "No", #endif /* !ENABLE_UDUNITS */ #if defined(HAVE_UDUNITS2_H) && (HAVE_UDUNITS2_H) "Yes", #else /* !HAVE_UDUNITS2_H */ "No", #endif /* !HAVE_UDUNITS2_H */ ""); /* End of print statement marker */ (void)fprintf(stderr,"\n%s",nco_nmn_get()); } /* end nco_cnf_prn() */ const char * /* O [sng] Mnemonic that describes current NCO version */ nco_nmn_get(void) /* [fnc] Return mnemonic that describes current NCO version */ { /* Purpose: Return mnemonic describing current NCO version Always Include terminal \n so mnemonic does not dangle */ return "Dreams about Laura at Co-op, Shari in restaurant, John at conference\n"; } /* end nco_nmn_get() */ char * /* O [sng] nm_in stripped of any path (i.e., program name stub) */ nco_prg_prs /* [fnc] Strip program name to stub and set program ID */ (const char * const nm_in, /* I [sng] Name of program, i.e., argv[0] (may include path prefix) */ int * const prg_lcl) /* O [enm] Enumerated number corresponding to nm_in */ { /* Purpose: Set program name and enum */ char *nm_out; char *nm_out_tmp; char *nm_out_orig; /* Get program name (use strrchr() first in case nm_in contains a path) */ nm_out_orig=nm_out_tmp=(char *)strdup(nm_in); #ifdef _MSC_VER int len; if(strrchr(nm_out_tmp,'\\')) nm_out_tmp=strrchr(nm_out_tmp,'\\')+1; char *s=strstr(nm_out_tmp,".exe"); if(s!=NULL && !strcmp(s,".exe")){ len=strlen(nm_out_tmp); /* cut any '.exe' from name */ nm_out_tmp[len-4]='\0'; } /* endif */ #else /* !_MSC_VER */ if(strrchr(nm_out_tmp,'/')) nm_out_tmp=strrchr(nm_out_tmp,'/')+1; #endif /* !_MSC_VER */ /* Skip possible libtool prefix */ if(!strncmp(nm_out_tmp,"lt-",3)){nm_out_tmp+=3;} /* Classify calling program */ /* ncap and acceptable synonyms (symbolic links): */ if(!strcmp(nm_out_tmp,"ncap")){*prg_lcl=ncap;} else if(!strcmp(nm_out_tmp,"ncap2")){*prg_lcl=ncap;} /* ncatted and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncatted")){*prg_lcl=ncatted;} /* ncbo and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"mpncbo")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"mpncdiff")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncadd")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncbo")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncdiff")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncdivide")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncmult")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncmultiply")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncsub")){*prg_lcl=ncbo;} else if(!strcmp(nm_out_tmp,"ncsubtract")){*prg_lcl=ncbo;} /* ncecat and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncecat")){*prg_lcl=ncecat;} else if(!strcmp(nm_out_tmp,"mpncecat")){*prg_lcl=ncecat;} /* ncfe and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncea")){*prg_lcl=ncfe;} else if(!strcmp(nm_out_tmp,"mpncea")){*prg_lcl=ncfe;} else if(!strcmp(nm_out_tmp,"nces")){*prg_lcl=ncfe;} else if(!strcmp(nm_out_tmp,"mpnces")){*prg_lcl=ncfe;} else if(!strcmp(nm_out_tmp,"ncfe")){*prg_lcl=ncfe;} else if(!strcmp(nm_out_tmp,"mpncfe")){*prg_lcl=ncfe;} /* ncge and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncge")){*prg_lcl=ncge;} else if(!strcmp(nm_out_tmp,"mpncge")){*prg_lcl=ncge;} /* ncflint and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncflint")){*prg_lcl=ncflint;} else if(!strcmp(nm_out_tmp,"mpncflint")){*prg_lcl=ncflint;} /* ncks and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncks")){*prg_lcl=ncks;} /* ncpdq and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncpdq")){*prg_lcl=ncpdq;} else if(!strcmp(nm_out_tmp,"mpncpdq")){*prg_lcl=ncpdq;} else if(!strcmp(nm_out_tmp,"ncpack")){*prg_lcl=ncpdq;} else if(!strcmp(nm_out_tmp,"ncunpack")){*prg_lcl=ncpdq;} /* ncra and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncrs")){*prg_lcl=ncra;} else if(!strcmp(nm_out_tmp,"mpncrs")){*prg_lcl=ncra;} else if(!strcmp(nm_out_tmp,"ncra")){*prg_lcl=ncra;} else if(!strcmp(nm_out_tmp,"mpncra")){*prg_lcl=ncra;} /* ncrcat and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncrcat")){*prg_lcl=ncrcat;} else if(!strcmp(nm_out_tmp,"mpncrcat")){*prg_lcl=ncrcat;} /* ncrename and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncrename")){*prg_lcl=ncrename;} /* ncwa and acceptable synonyms (symbolic links): */ else if(!strcmp(nm_out_tmp,"ncws")){*prg_lcl=ncwa;} else if(!strcmp(nm_out_tmp,"mpncws")){*prg_lcl=ncwa;} else if(!strcmp(nm_out_tmp,"ncwa")){*prg_lcl=ncwa;} else if(!strcmp(nm_out_tmp,"mpncwa")){*prg_lcl=ncwa;} else{ (void)fprintf(stdout,"%s: ERROR executable name %s not registered in nco_prg_prs()\n",nm_out_tmp,nm_out_tmp); nco_exit(EXIT_FAILURE); } /* end else */ /* Duplicate stub for returning */ nm_out=(char *)strdup(nm_out_tmp); /* Free copy of argv[0] */ nm_out_orig=(char *)nco_free(nm_out_orig); return nm_out; } /* end nco_prg_prs() */ void nco_usg_prn(void) { /* Purpose: Print correct command-line usage (currently to stdout) */ char *opt_sng=NULL_CEWI; int prg_lcl; prg_lcl=nco_prg_id_get(); switch(prg_lcl){ case ncap: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-F] [-f] [--fl_fmt fmt] [-h] [--hdf] [--hdr_pad nbr] [-L lvl] [-l path] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-s algebra] [-S fl.nco] [-t thr_nbr] [-v] in.nc [out.nc]\n"); break; case ncatted: opt_sng=(char *)strdup("[-a ...] [--bfr sz] [-D nco_dbg_lvl] [-h] [--hdr_pad nbr] [-l path] [-O] [-o out.nc] [-p path] [-R] [-r] in.nc [[out.nc]]\n"); break; case ncbo: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-h] [--hdf] [--hdr_pad nbr] [-L lvl] [-l path] [--msa] [-n ...] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-t thr_nbr] [--unn] [-v ...] [-X box] [-x] [-y op_typ] in_1.nc in_2.nc [out.nc]\n"); break; case ncflint: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fix_rec_crd] [--fl_fmt fmt] [-h] [--hdf] [--hdr_pad nbr] [-i var,val] [-L lvl] [-l path] [--msa] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-t thr_nbr] [-v ...] [-X box] [-x] [-w wgt_1[,wgt_2]] in_1.nc in_2.nc [out.nc]\n"); break; case ncks: opt_sng=(char *)strdup("[-3] [-4] [-5] [-6] [-7] [-A] [-a] [-b fl_bnr] [--bfr sz] [-C] [-c] [--cdl] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fix_rec_dmn dim] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-H] [-h] [--hdn] [--hdr_pad nbr] [-L lvl] [-l path] [-M] [-m] [--md5_dgs] [--md5_wrt] [--mk_rec_dmn dim] [--msa] [--no_blank] [--no_tmp_fl] [-O] [-o out.nc] [-P] [-p path] [-Q] [-q] [-R] [-r] [--ram_all] [-s format] [-u] [--unn] [-v ...] [-X box] [-x] [--xml] [--xml_no_loc] [--xml_spr_chr sng] [--xml_spr_nmr sng] in.nc [[out.nc]]\n"); break; case ncpdq: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [-a ...] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-h] [--hdf] [--hdr_pad nbr] [-L lvl] [-l path] [-M pck_map] [--mrd] [--msa] [--no_tmp_fl] [-O] [-o out.nc] [-P pck_plc] [-p path] [-R] [-r] [--ram_all] [-t thr_nbr] [--unn] [-U] [-v ...] [-X box] [-x] in.nc [out.nc]\n"); break; case ncra: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [--dbl|flt] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-H] [-h] [--hdf] [--hdr_pad nbr] [-L lvl] [-l path] [--mro] [--msa] [-n ...] [--no_cll_mth] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [--rec_apn] [-t thr_nbr] [--unn] [-v ...] [-X box] [-x] [-y op_typ] in.nc [...] [out.nc]\n"); break; case ncfe: case ncge: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [--dbl|flt] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-H] [-h] [--hdf] [--hdr_pad nbr] [-L lvl] [-l path] [--msa] [-n ...] [--no_tmp_fl] [--nsm_fl] [--nsm_grp] [--nsm_sfx] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-t thr_nbr] [--unn] [-v ...] [-X box] [-x] [-y op_typ] in.nc [...] [out.nc]\n"); break; case ncrcat: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-H] [-h] [--hdr_pad nbr] [-L lvl] [-l path] [--md5_digest] [--msa] [-n ...] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [--rec_apn] [-t thr_nbr] [--unn] [-v ...] [-X box] [-x] in.nc [...] [out.nc]\n"); break; case ncecat: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [--gag] [-H] [-h] [--hdr_pad nbr] [-L lvl] [-l path] [-M] [--md5_digest] [--mrd] [--msa] [-n ...] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-t thr_nbr] [-u ulm_nm] [--unn] [-v ...] [-X box] [-x] in.nc [...] [out.nc]\n"); break; case ncrename: opt_sng=(char *)strdup("[-a ...] [--bfr sz] [-D nco_dbg_lvl] [-d ...] [-g ...] [-h] [--hdr_pad nbr] [-l path] [-O] [-o out.nc] [-p path] [-R] [-r] [-v ...] in.nc [[out.nc]]\n"); break; case ncwa: opt_sng=(char *)strdup("[-3] [-4] [-6] [-7] [-A] [-a ...] [-B mask_cond] [-b] [--bfr sz] [-C] [-c] [--cnk_byt sz] [--cnk_dmn nm,sz] [--cnk_map map] [--cnk_plc plc] [--cnk_scl sz] [-D nco_dbg_lvl] [-d ...] [--dbl|flt] [-F] [--fl_fmt fmt] [-G grp:lvl] [-g ...] [-h] [--hdf] [--hdr_pad nbr] [-I] [-L lvl] [-l path] [-m mask] [-M mask_val] [-N] [--no_cll_mth] [--no_tmp_fl] [-O] [-o out.nc] [-p path] [-R] [-r] [--ram_all] [-T mask_comp] [-t thr_nbr] [--unn] [-v ...] [-w wgt] [-x] [-y op_typ] in.nc [out.nc]\n"); break; default: nco_dfl_case_prg_id_err(); break; } /* end switch */ /* We now have command-specific command line option string */ (void)fprintf(stdout,"%s Command line options cheatsheet (full details at http://nco.sf.net/nco.html#%s):\n",nco_prg_nm_get(),nco_prg_nm_get()); (void)fprintf(stdout,"%s %s\n",nco_prg_nm_get(),opt_sng); if(strstr(opt_sng,"[-3]")) (void)fprintf(stdout,"-3, --3, --fl_fmt=classic\tOutput file in netCDF3 CLASSIC (32-bit offset) storage format\n"); #ifdef ENABLE_NETCDF4 if(strstr(opt_sng,"[-4]")) (void)fprintf(stdout,"-4, --4, --netcdf4\t\tOutput file in netCDF4 (HDF5) storage format\n"); #endif /* !ENABLE_NETCDF4 */ if(strstr(opt_sng,"[-5]")) (void)fprintf(stdout,"-5, --5, \t\tPrint alphabetically by group then variable\n"); if(strstr(opt_sng,"[-6]")) (void)fprintf(stdout,"-6, --64, --fl_fmt=64bit\tOutput file in netCDF3 64-bit offset storage format\n"); if(strstr(opt_sng,"[-7]")) (void)fprintf(stdout,"-7, --7, --fl_fmt=netcdf4_classic\tOutput file in netCDF4 CLASSIC format (3+4=7)\n"); if(strstr(opt_sng,"[-A]")) (void)fprintf(stdout,"-A, --apn, --append\tAppend to existing output file, if any\n"); if(strstr(opt_sng,"[-a")){ if(prg_lcl == ncatted) (void)fprintf(stdout,"-a, --attribute att_nm,var_nm,mode,att_typ,att_val Attribute specification:\n\t\t\tmode = a,c,d,m,o and att_typ = f,d,l,s,c,b\n"); #ifdef ENABLE_NETCDF4 if(prg_lcl == ncatted) (void)fprintf(stdout,"\t\t\tnetCDF4 att_typ's = ub,us,u,ll,ull\n"); #endif /* !ENABLE_NETCDF4 */ if(prg_lcl == ncks) (void)fprintf(stdout,"-a, --abc, --alphabetize\tDisable alphabetization of extracted variables\n"); if(prg_lcl == ncpdq) (void)fprintf(stdout,"-a, --arrange, --permute, --reorder, --rdr [-]rdr_dim1[,[-]rdr_dim2[...]] Re-order dimensions\n"); if(prg_lcl == ncrename) (void)fprintf(stdout,"-a, --attribute old_att,new_att Attribute's old and new names\n"); if(prg_lcl == ncwa) (void)fprintf(stdout,"-a, --avg, --average avg_dim1[,avg_dim2[...]] Averaging dimensions\n"); } /* end if */ if(strstr(opt_sng,"[-B")){ #ifndef _MSC_VER if(prg_lcl == ncwa) (void)fprintf(stdout,"-B, --msk_cnd, --mask_condition mask_cond\tMask condition (e.g., \"ORO < 1\")\n"); #endif /* _MSC_VER */ } /* end if -B */ if(strstr(opt_sng,"[-b ")) (void)fprintf(stdout,"-b, --fl_bnr, --binary-file fl_bnr\tUnformatted binary file to write\n"); if(strstr(opt_sng,"[-b]")) (void)fprintf(stdout,"-b, --rdd, --retain-degenerate-dimensions\tRetain degenerate dimensions\n"); if(strstr(opt_sng,"--bfr")) (void)fprintf(stdout," --bfr_sz, --buffer_size sz\tBuffer size to open files with\n"); if(strstr(opt_sng,"[-C]")) (void)fprintf(stdout,"-C, --nocoords\t\tAssociated coordinate variables should not be processed\n"); if(strstr(opt_sng,"[-c]")) (void)fprintf(stdout,"-c, --crd, --coords\tCoordinate variables will all be processed\n"); if(strstr(opt_sng,"--cdl")) (void)fprintf(stdout," --cdl\t\tPrint CDL (netCDF lingua franca used by ncdump/ncgen)\n"); if(strstr(opt_sng,"--cnk_dmn")) (void)fprintf(stdout," --cnk_dmn, --chunk_dimension nm,sz\tChunksize of dimension nm is sz\n"); if(strstr(opt_sng,"--cnk_map")) (void)fprintf(stdout," --cnk_map, --chunk_map map\t\tChunking map [dmn,lfp,prd,rd1,rew,scl,xpl,xst]\n"); if(strstr(opt_sng,"--cnk_plc")) (void)fprintf(stdout," --cnk_plc, --chunk_policy plc\tChunking policy [all,g2d,g3d,xpl,xst,uck]\n"); if(strstr(opt_sng,"--cnk_scl")) (void)fprintf(stdout," --cnk_scl, --chunk_scalar sz\tChunksize scalar (for all dimensions)\n"); if(strstr(opt_sng,"[-D")) (void)fprintf(stdout,"-D, --dbg_lvl, --debug-level lvl\tDebug-level is lvl\n"); if(strstr(opt_sng,"[-d")){ if(prg_lcl == ncrename) (void)fprintf(stdout,"-d, --dmn, --dimension old_dim,new_dim Dimension's old and new names\n"); else if(prg_lcl == ncra || prg_lcl == ncrcat) (void)fprintf(stdout,"-d, --dmn, --dimension dim,[min][,[max][[[,stride[,subcycle]]]]] Dimension's limits, stride, subcycle in hyperslab\n"); else (void)fprintf(stdout,"-d, --dmn, --dimension dim,[min][,[max]][,[stride]] Dimension's limits and stride in hyperslab\n"); } /* end if -d */ if(strstr(opt_sng,"--dbl|flt")) (void)fprintf(stdout," --dbl, --flt, --rth_dbl|flt\tdbl: Always promote single- to double-precision b4 arithmetic (default). flt: OK with single-precision arithmetic.\n"); if(strstr(opt_sng,"[-F]")) (void)fprintf(stdout,"-F, --ftn, --fortran\tFortran indexing conventions (1-based) for I/O\n"); if(strstr(opt_sng,"[-f]")) (void)fprintf(stdout,"-f, --fnc_tbl, --prn_fnc_tbl\tPrint function table\n"); if(strstr(opt_sng,"--fix_rec_crd")) (void)fprintf(stdout," --fix_rec_crd\tDo not interpolate/multiply record coordinate variables\n"); if(strstr(opt_sng,"--fix_rec_dmn dim")) (void)fprintf(stdout," --fix_rec_dmn dim\tChange dimension dim (or all) to fixed dimension in output file\n"); #ifdef ENABLE_NETCDF4 if(strstr(opt_sng,"--fl_fmt")) (void)fprintf(stdout," --fl_fmt, --file_format fmt\tFile format [classic,64bit,netcdf4,netcdf4_classic]\n"); #else /* !ENABLE_NETCDF4 */ if(strstr(opt_sng,"--fl_fmt")) (void)fprintf(stdout," --fl_fmt, --file_format fmt\tFile format [classic,64bit]\n"); #endif /* !ENABLE_NETCDF4 */ #ifdef ENABLE_NETCDF4 if(strstr(opt_sng,"--gag")) (void)fprintf(stdout," --gag, --aggregate_group\tGroup Aggregation (not Record Aggregation)\n"); if(strstr(opt_sng,"[-G")) (void)fprintf(stdout,"-G, --gpe [grp_nm][:[lvl]]\tGroup Path Editing path, levels to replace\n"); if(strstr(opt_sng,"[-g")){ if(prg_lcl == ncrename) (void)fprintf(stdout,"-g, --grp --group\told_grp,new_grp Group's old and new names\n"); if(prg_lcl != ncrename) (void)fprintf(stdout,"-g, --grp grp1[,grp2[...]] Group(s) to process (regular expressions supported)\n"); } /* end if */ #endif /* !ENABLE_NETCDF4 */ if(strstr(opt_sng,"[-H]")){ if(prg_lcl == ncks) (void)fprintf(stdout,"-H, --data, --hieronymus\tToggle printing data\n"); if(nco_is_mfo(prg_lcl)) (void)fprintf(stdout,"-H, --fl_lst_in, --file_list\tDo not create \"input_file_list\" global attribute\n"); } /* end if -H */ if(strstr(opt_sng,"[-h]")) (void)fprintf(stdout,"-h, --hst, --history\tDo not append to \"history\" global attribute\n"); if(strstr(opt_sng,"--hdn")) (void)fprintf(stdout," --hdn, --hidden\tPrint hidden (aka special) attributes\n"); if(strstr(opt_sng,"--hdf")) (void)fprintf(stdout," --hdf_upk, --hdf_upk\tHDF unpack convention: unpacked=scale_factor*(packed-add_offset)\n"); if(strstr(opt_sng,"--hdr_pad")) (void)fprintf(stdout," --hdr_pad, --header_pad\tPad output header with nbr bytes\n"); if(strstr(opt_sng,"[-i var,val]")) (void)fprintf(stdout,"-i, --ntp, --interpolate var,val\tInterpolant and value\n"); if(strstr(opt_sng,"[-I]")) (void)fprintf(stdout,"-I, --wgt_msk_crd_var\tDo not weight or mask coordinate variables\n"); #ifdef ENABLE_NETCDF4 if(strstr(opt_sng,"[-L")) (void)fprintf(stdout,"-L, --dfl_lvl, --deflate lvl\tLempel-Ziv deflation (lvl=0..9) for netCDF4 output\n"); #endif /* !ENABLE_NETCDF4 */ if(strstr(opt_sng,"[-l")) (void)fprintf(stdout,"-l, --lcl, --local path\tLocal storage path for remotely-retrieved files\n"); if(strstr(opt_sng,"[-M")){ if(prg_lcl == ncecat) (void)fprintf(stdout,"-M, --glb_mtd_spp\tDo not copy global metadata\n"); if(prg_lcl == ncks) (void)fprintf(stdout,"-M, --Mtd, --Metadata\tToggle printing global metadata\n"); if(prg_lcl == ncpdq) (void)fprintf(stdout,"-M, --pck_map, --pack_map, --map pck_map\tPack map [flt_sht,flt_byt,hgh_sht,hgh_byt,nxt_lsr]\n"); if(prg_lcl == ncwa) (void)fprintf(stdout,"-M, --msk_val, --mask-value, --mask_value mask_val\tMasking value (default is 1.0)\n"); } /* end if */ if(strstr(opt_sng,"[-m")){ if(prg_lcl == ncwa) (void)fprintf(stdout,"-m, --msk_nm, --msk_var, --mask-variable, --mask_variable mask_var\tMasking variable name\n"); if(prg_lcl == ncks) (void)fprintf(stdout,"-m, --mtd, --metadata\tToggle printing variable metadata\n"); } /* end if */ if(strstr(opt_sng,"--md5_digest")) (void)fprintf(stdout," --md5_dgs, --md5_digest\tPerform MD5 digests\n"); if(strstr(opt_sng,"--md5_wrt_att")) (void)fprintf(stdout," --md5_wrt, --md5_write\tWrite MD5 digests as attributes\n"); if(strstr(opt_sng,"--mk_rec_dmn")) (void)fprintf(stdout," --mk_rec_dmn dim\tDefine dim as record dimension in output file\n"); if(strstr(opt_sng,"--mro")) (void)fprintf(stdout," --mro\t\tMulti-Record Output\n"); if(strstr(opt_sng,"[-N]")) (void)fprintf(stdout,"-N, --nmr, --numerator\tNo normalization\n"); if(strstr(opt_sng,"[-n ...]")){ /* if(prg_lcl == ncwa) (void)fprintf(stdout,"-n\t\tNormalize by tally but not weight\n");*/ if(prg_lcl != ncwa) (void)fprintf(stdout,"-n, --nintap nbr_files,[nbr_numeric_chars[,increment]] NINTAP-style abbreviation of file list\n"); } /* end if -n */ if(strstr(opt_sng,"--no_blank")) (void)fprintf(stdout," --no_blank\t\tPrint numeric missing values instead of blanks (underscores)\n"); if(strstr(opt_sng,"--no_cll_mth")) (void)fprintf(stdout," --no_cll_mth\tDo not add/modify cell_methods attributes\n"); if(strstr(opt_sng,"--no_tmp_fl")) (void)fprintf(stdout," --no_tmp_fl\t\tDo not write output to temporary file\n"); if(strstr(opt_sng,"--nsm_fl")) (void)fprintf(stdout," --nsm_fl, --ensemble_file\tEnsembles comprise equally weighted files\n"); if(strstr(opt_sng,"--nsm_grp")) (void)fprintf(stdout," --nsm_grp, --ensemble_group\tEnsembles comprise equally weighted groups\n"); if(strstr(opt_sng,"--nsm_sfx")) (void)fprintf(stdout," --nsm_sfx, --ensemble_suffix\tPlace ensemble output in group parent/parent+nsm_sfx\n"); if(strstr(opt_sng,"[-o")) (void)fprintf(stdout,"-o, --output, --fl_out fl_out\tOutput file name (or use last positional argument)\n"); if(strstr(opt_sng,"[-O]")) (void)fprintf(stdout,"-O, --ovr, --overwrite\tOverwrite existing output file, if any\n"); if(strstr(opt_sng,"[-P")){ if(prg_lcl == ncks) (void)fprintf(stdout,"-P, --prn, --print\tPrint data, metadata, and units. Abbreviation for -C -H -M -m -u.\n"); if(prg_lcl == ncpdq) (void)fprintf(stdout,"-P, --pck_plc, --pack_policy pck_plc\tPacking policy [all_new,all_xst,xst_new,upk]\n"); } /* end if -P */ if(strstr(opt_sng,"[-p")) (void)fprintf(stdout,"-p, --pth, --path path\tPath prefix for all input filenames\n"); if(strstr(opt_sng,"[-Q]")) (void)fprintf(stdout,"-Q, \t\t\tToggle printing of dimension indices and coordinate values\n"); if(strstr(opt_sng,"[-q]")) (void)fprintf(stdout,"-q, --quiet\t\tTurn off all printing to screen\n"); if(strstr(opt_sng,"[-R]")) (void)fprintf(stdout,"-R, --rtn, --retain\tRetain remotely-retrieved files after use\n"); if(strstr(opt_sng,"[-r]")) (void)fprintf(stdout,"-r, --revision, --vrs, --version\tCompile-time configuration and/or program version\n"); if(strstr(opt_sng,"--ram_all")) (void)fprintf(stdout," --ram_all, --diskless_all\tOpen netCDF3 files and create output files in RAM\n"); if(strstr(opt_sng,"--rec_apn")) (void)fprintf(stdout," --rec_apn, --record_append\tAppend records directly to output file\n"); if(strstr(opt_sng,"[-s")){ if(prg_lcl != ncap) (void)fprintf(stdout,"-s, --sng_fmt, --string format\tString format for text output\n"); if(prg_lcl == ncap) (void)fprintf(stdout,"-s, --spt, --script algebra\tAlgebraic command defining single output variable\n"); } /* end if */ if(strstr(opt_sng,"[-S")) (void)fprintf(stdout,"-S, --fl_spt, --script-file fl.nco\tScript file containing multiple algebraic commands\n"); if(strstr(opt_sng,"[-T")) (void)fprintf(stdout,"-T, --mask_comparator, --msk_cmp_typ, --op_rlt comparator\tComparator for mask condition: eq,ne,ge,le,gt,lt\n"); if(strstr(opt_sng,"[-t")) (void)fprintf(stdout,"-t, --thr_nbr, --threads, --omp_num_threads thr_nbr\tThread number for OpenMP\n"); if(strstr(opt_sng,"[-U]")) (void)fprintf(stdout,"-U, --upk, --unpack\tUnpack input file\n"); if(strstr(opt_sng,"[-u")){ if(prg_lcl == ncks) (void)fprintf(stdout,"-u, --units\t\tToggle printing units of variables, if any\n"); if(prg_lcl == ncecat) (void)fprintf(stdout,"-u, --ulm_nm --rcd_nm\tNew unlimited (record) dimension name\n"); } /* end if */ if(strstr(opt_sng,"--unn")) (void)fprintf(stdout," --unn, --union\tSelect union of specified groups and variables\n"); if(strstr(opt_sng,"[-v")){ if(prg_lcl == ncrename) (void)fprintf(stdout,"-v, --variable old_var,new_var Variable's old and new names\n"); if(prg_lcl == ncap) (void)fprintf(stdout,"-v, --variable \t\tOutput file includes ONLY user-defined variables\n"); if(prg_lcl != ncrename && prg_lcl != ncap) (void)fprintf(stdout,"-v, --variable var1[,var2[...]] Variable(s) to process (regular expressions supported)\n"); } /* end if */ /* if(strstr(opt_sng,"[-W]")) (void)fprintf(stdout,"-W\t\tNormalize by weight but not tally\n");*/ if(strstr(opt_sng,"[-w")){ if(prg_lcl == ncwa) (void)fprintf(stdout,"-w, --wgt_var, --weight wgt\tWeighting variable name\n"); if(prg_lcl == ncflint) (void)fprintf(stdout,"-w, --wgt_var, --weight wgt_1[,wgt_2] Weight(s) of file(s)\n"); } /* end if */ if(strstr(opt_sng,"[-X")) (void)fprintf(stdout,"-X, --auxiliary lon_min,lon_max,lat_min,lat_max\tAuxiliary coordinate bounding box\n"); if(strstr(opt_sng,"[-x]")) (void)fprintf(stdout,"-x, --xcl, --exclude\tExtract all variables EXCEPT those specified with -v\n"); if(strstr(opt_sng,"--xml")) (void)fprintf(stdout," --xml\t\tPrint XML (NcML, netCDF Markup Language)\n"); if(strstr(opt_sng,"--xml_no_loc")) (void)fprintf(stdout," --xml_no_location\tOmit NcML location element\n"); if(strstr(opt_sng,"--xml_spr_chr")) (void)fprintf(stdout," --xml_spr_chr sng\tSeparator for NcML character types\n"); if(strstr(opt_sng,"--xml_spr_nmr")) (void)fprintf(stdout," --xml_spr_nmr sng\tSeparator for NcML numeric types\n"); if(strstr(opt_sng,"[-y op_typ]")){ if(prg_lcl == ncbo)(void)fprintf(stdout,"-y, --op_typ, --operation op_typ\tBinary arithmetic operation: add,sbt,mlt,dvd (+,-,*,/)\n"); if(prg_lcl == ncra || prg_lcl == ncfe || prg_lcl == ncge || prg_lcl == ncwa)(void)fprintf(stdout,"-y, --op_typ, --operation op_typ\tArithmetic operation: avg,min,max,ttl,sqravg,avgsqr,sqrt,rms,rmssdn\n"); } /* All operators have input files, no need to strstr(in.nc) */ if(prg_lcl == ncbo || prg_lcl == ncflint){ (void)fprintf(stdout,"in_1.nc in_2.nc\t\tInput file names\n"); }else{ if(nco_is_mfo(prg_lcl)) (void)fprintf(stdout,"in.nc [...]\t\tInput file names\n"); else (void)fprintf(stdout,"in.nc\t\t\tInput file name\n"); } /* endif in.nc */ if(strstr(opt_sng,"[out.nc]")) (void)fprintf(stdout,"out.nc\t\t\tOutput file name (or use -o switch)\n"); /* if(strstr(opt_sng,"-")) (void)fprintf(stdout,"-\n");*/ /* Free the space holding option string */ opt_sng=(char *)nco_free(opt_sng); /* Public service announcements */ (void)fprintf(stdout,"\nEight ways to find more help on %s and/or NCO:\n",nco_prg_nm_get()); (void)fprintf(stdout,"1. Examples: http://nco.sf.net/nco.html#xmp_%s\n",nco_prg_nm_get()); (void)fprintf(stdout,"2. Ref. manual: http://nco.sf.net/nco.html#%s\n",nco_prg_nm_get()); (void)fprintf(stdout,"3. User's Guide: http://nco.sf.net#RTFM\n"); (void)fprintf(stdout,"4. Manual pages: \'man %s\', \'man nco\', ...\n",nco_prg_nm_get()); (void)fprintf(stdout,"5. Homepage: http://nco.sf.net\n"); (void)fprintf(stdout,"6. FAQ: http://nco.sf.net#FAQ\n"); (void)fprintf(stdout,"7. Help Forum: http://sf.net/projects/nco/forums/forum/9830\n"); (void)fprintf(stdout,"8. Publications: http://nco.sf.net#pub\n"); (void)fprintf(stdout,"Post questions, suggestions, patches at http://sf.net/projects/nco\n"); } /* end nco_usg_prn() */ ./nco-4.4.2/src/nco/nco_getopt.c0000644000674300045400000002234511424417574015647 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_getopt.c,v 1.4 2010/07/30 00:40:28 zender Exp $ */ /* "my_getopt" package is "drop-in" replacement for GNU getopt() by Benjamin Sittler downloaded from http://www.geocities.com/ResearchTriangle/Node/9405/#my_getopt It is distributed under the BSD-like license below Modifications: 20030101: Downloaded source 20030108: Renamed my_getopt.h, my_getopt.c to nco_getopt.c, nco_getopt.h */ /* Original, unmodified license header: */ /* * my_getopt.c - my re-implementation of getopt. * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "nco_getopt.h" /* csz renamed this with nco_ prefix */ int my_optind=1, my_opterr=1, my_optopt=0; char *my_optarg=0; /* this is the plain old UNIX getopt, with GNU-style extensions. */ /* if you're porting some piece of UNIX software, this is all you need. */ /* this supports GNU-style permution and optional arguments */ int my_getopt(int argc, char * argv[], const char *opts) { static int charind=0; const char *s; char mode, colon_mode; int off = 0, opt = -1; if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; else { if((colon_mode = *opts) == ':') off ++; if(((mode = opts[off]) == '+') || (mode == '-')) { off++; if((colon_mode != ':') && ((colon_mode = opts[off]) == ':')) off ++; } } my_optarg = 0; if(charind) { my_optopt = argv[my_optind][charind]; for(s=opts+off; *s; s++) if(my_optopt == *s) { charind++; if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) { if(argv[my_optind][charind]) { my_optarg = &(argv[my_optind++][charind]); charind = 0; } else if(*(++s) != ':') { charind = 0; if(++my_optind >= argc) { if(my_opterr) fprintf(stderr, "%s: option requires an argument -- %c\n", argv[0], my_optopt); opt = (colon_mode == ':') ? ':' : '?'; goto my_getopt_ok; } my_optarg = argv[my_optind++]; } } opt = my_optopt; goto my_getopt_ok; } if(my_opterr) fprintf(stderr, "%s: illegal option -- %c\n", argv[0], my_optopt); opt = '?'; if(argv[my_optind][++charind] == '\0') { my_optind++; charind = 0; } my_getopt_ok: if(charind && ! argv[my_optind][charind]) { my_optind++; charind = 0; } } else if((my_optind >= argc) || ((argv[my_optind][0] == '-') && (argv[my_optind][1] == '-') && (argv[my_optind][2] == '\0'))) { my_optind++; opt = -1; } else if((argv[my_optind][0] != '-') || (argv[my_optind][1] == '\0')) { char *tmp; int i, j, k; if(mode == '+') opt = -1; else if(mode == '-') { my_optarg = argv[my_optind++]; charind = 0; opt = 1; } else { for(i=j=my_optind; i j) { tmp=argv[--i]; for(k=i; k+1 argc) my_optind = argc; return opt; } /* this is the extended getopt_long{,_only}, with some GNU-like * extensions. Implements _getopt_internal in case any programs * expecting GNU libc getopt call it. */ int _my_getopt_internal(int argc, char * argv[], const char *shortopts, const struct option *longopts, int *longind, int long_only) { char mode, colon_mode = *shortopts; int shortoff = 0, opt = -1; if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; else { if((colon_mode = *shortopts) == ':') shortoff ++; if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) { shortoff++; if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':')) shortoff ++; } } my_optarg = 0; if((my_optind >= argc) || ((argv[my_optind][0] == '-') && (argv[my_optind][1] == '-') && (argv[my_optind][2] == '\0'))) { my_optind++; opt = -1; } else if((argv[my_optind][0] != '-') || (argv[my_optind][1] == '\0')) { char *tmp; int i, j, k; opt = -1; if(mode == '+') return -1; else if(mode == '-') { my_optarg = argv[my_optind++]; return 1; } for(i=j=my_optind; i j) { tmp=argv[--i]; for(k=i; k+1= argc) { opt = (colon_mode == ':') ? ':' : '?'; if(my_opterr) fprintf(stderr, "%s: option `--%s' requires an argument\n", argv[0], longopts[found].name); } else my_optarg = argv[my_optind]; } if(!opt) { if (longind) *longind = found; if(!longopts[found].flag) opt = longopts[found].val; else *(longopts[found].flag) = longopts[found].val; } my_optind++; } else if(!hits) { if(offset == 1) opt = my_getopt(argc, argv, shortopts); else { opt = '?'; if(my_opterr) fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], argv[my_optind++]); } } else { opt = '?'; if(my_opterr) fprintf(stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[my_optind++]); } } if (my_optind > argc) my_optind = argc; return opt; } int my_getopt_long(int argc, char * argv[], const char *shortopts, const struct option *longopts, int *longind) { return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0); } int my_getopt_long_only(int argc, char * argv[], const char *shortopts, const struct option *longopts, int *longind) { return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1); } ./nco-4.4.2/src/nco/nco_rth_utl.c0000644000674300045400000004716512300513546016023 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_rth_utl.c,v 1.69 2014/02/17 23:12:38 zender Exp $ */ /* Purpose: Arithmetic controls and utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_rth_utl.h" /* Arithmetic controls and utilities */ nco_rth_prc_rnk_enm /* [enm] Ranked precision of arithmetic type */ nco_rth_prc_rnk /* [fnc] Rank precision of arithmetic type */ (const nc_type nco_typ) /* I [enm] netCDF type of operand */ { /* Purpose: Ranked precision of arithmetic type */ switch(nco_typ){ case NC_FLOAT: return nco_rth_prc_rnk_float; case NC_DOUBLE: return nco_rth_prc_rnk_double; case NC_INT: return nco_rth_prc_rnk_int; case NC_SHORT: return nco_rth_prc_rnk_short; case NC_CHAR: return nco_rth_prc_rnk_char; case NC_BYTE: return nco_rth_prc_rnk_byte; case NC_UBYTE: return nco_rth_prc_rnk_ubyte; case NC_USHORT: return nco_rth_prc_rnk_ushort; case NC_UINT: return nco_rth_prc_rnk_uint; case NC_INT64: return nco_rth_prc_rnk_int64; case NC_UINT64: return nco_rth_prc_rnk_uint64; case NC_STRING: return nco_rth_prc_rnk_string; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (nco_rth_prc_rnk_enm)0; } /* end nco_rth_prc_rnk() */ void nco_opr_nrm /* [fnc] Normalization of arithmetic operations for ncra/nces */ (const int nco_op_typ, /* I [enm] Operation type */ const int nbr_var_prc, /* I [nbr] Number of processed variables */ X_CST_PTR_CST_PTR_Y(var_sct,var_prc), /* I [sct] Variables in input file */ X_CST_PTR_CST_PTR_Y(var_sct,var_prc_out), /* I/O [sct] Variables in output file */ const char * const rec_nm_fll, /* I [sng] Full name of record dimension */ const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { /* Purpose: Normalize appropriate ncra/nces operation (avg, min, max, ttl, ...) on operands Values of var_prc are not altered but are not const because missing values are cast Values of var_prc_out are altered (i.e., normalized) */ int idx=int_CEWI; int nbr_var_prc_cpy; int nco_op_typ_cpy; nco_op_typ_cpy=nco_op_typ; nbr_var_prc_cpy=nbr_var_prc; #ifdef _OPENMP #pragma omp parallel for default(none) private(idx) shared(nbr_var_prc_cpy,nco_op_typ_cpy,var_prc,var_prc_out) #endif /* !_OPENMP */ for(idx=0;idxis_crd_var){ /* Return linear averages of coordinates unless computing extrema Prevent coordinate variables from encountering nco_var_nrm_sdn() */ (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); }else{ /* !var_prc[idx]->is_crd_var */ switch(nco_op_typ_cpy){ case nco_op_avg: /* Normalize sum by tally to create mean */ case nco_op_sqrt: /* Normalize sum by tally to create mean */ case nco_op_sqravg: /* Normalize sum by tally to create mean */ case nco_op_rms: /* Normalize sum of squares by tally to create mean square */ case nco_op_avgsqr: /* Normalize sum of squares by tally to create mean square */ (void)nco_var_nrm(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); break; case nco_op_rmssdn: /* Normalize sum of squares by tally-1 to create mean square for sdn */ (void)nco_var_nrm_sdn(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); break; case nco_op_min: /* Minimum is already in buffer, do nothing */ case nco_op_max: /* Maximum is already in buffer, do nothing */ break; case nco_op_ttl: /* Total is already in buffer, stuff missing values into elements with zero tally */ (void)nco_var_tll_zro_mss_val(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val); break; default: break; } /* end switch */ /* Some operations require additional processing */ switch(nco_op_typ_cpy) { case nco_op_rms: /* Take root of mean of sum of squares to create root mean square */ case nco_op_rmssdn: /* Take root of sdn mean of sum of squares to create root mean square for sdn */ case nco_op_sqrt: /* Take root of mean to create root mean */ (void)nco_var_sqrt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc[idx]->tally,var_prc_out[idx]->val,var_prc_out[idx]->val); break; case nco_op_sqravg: /* Square mean to create square of the mean (for sdn) */ (void)nco_var_mlt(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,var_prc_out[idx]->val,var_prc_out[idx]->val); break; default: break; } /* end switch */ } /* !var_prc[idx]->is_crd_var */ } /* end (OpenMP parallel for) loop over variables */ } /* end nco_opr_nrm() */ void nco_opr_drv /* [fnc] Intermediate control of arithmetic operations for ncra/nces */ (const long idx_rec, /* I [idx] Index of record (ncra), file (ncfe), or group (ncge) in current operation */ const int nco_op_typ, /* I [enm] Operation type */ const var_sct * const var_prc, /* I [sct] Variable in input file */ var_sct * const var_prc_out) /* I/O [sct] Variable in output file */ { /* Purpose: Perform appropriate ncra/nces operation (avg, min, max, ttl, ...) on operands nco_opr_drv() is called within the record loop of ncra, and within file loop of nces These operations perform some, but not all, of necessary operations for each procedure Most arithmetic operations require additional procedures such as normalization be performed after all files/records have been processed Some operations require special care at initialization This determination is based on the idx_rec variable When idx_rec == 0, these operations may perform special initializations The exact numeric value of idx_rec does not matter What matters is whether it is zero or non-zero */ /* NCO's paradigm is that coordinate variables represent grid axes Reducing such grids to a single-value must be done The most representative value of the grid is the average The total, min, max, rms, etc. of the grid usually makes no sense Users are most interested in the mean grid coordinate 20130112: The same logic applies to CF-style coordinates, e.g., to variables matching the CF "bounds" and "coordinates" conventions */ if(var_prc->is_crd_var){ (void)nco_var_add_tll_ncra(var_prc->type,var_prc->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->tally,var_prc->val,var_prc_out->val); return; } /* !var_prc->is_crd_var */ /* var_prc_out->type and var_prc->type should be equal and thus interchangeable var_prc_out->sz and var_prc->sz should be equal and thus interchangeable */ switch (nco_op_typ){ case nco_op_min: /* Minimum */ /* On first loop, simply copy variables from var_prc to var_prc_out */ if(idx_rec == 0) (void)nco_var_copy(var_prc->type,var_prc->sz,var_prc->val,var_prc_out->val); else (void)nco_var_min_bnr(var_prc_out->type,var_prc_out->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->val,var_prc_out->val); break; case nco_op_max: /* Maximium */ /* On first loop, simply copy variables from var_prc to var_prc_out */ if(idx_rec == 0) (void)nco_var_copy(var_prc->type,var_prc->sz,var_prc->val,var_prc_out->val); else (void)nco_var_max_bnr(var_prc_out->type,var_prc_out->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->val,var_prc_out->val); break; case nco_op_ttl: /* Total */ /* NB: Copying input to output on first loop for nco_op_ttl, in similar manner to nco_op_[max/min], can work However, copying with nco_var_copy() would not change the tally variable, leaving it equal to zero Then an extra step would be necessary to set tally equal to one where missing values were not present Otherwise, e.g., ensemble averages of one file would never have non-zero tallies Hence, use special nco_var_copy_tll() function to copy and change tally only in first loop iteration This way, tally is self-consistent with var_prc_out at all times Moreover, running total must never be set to missing_value, because subsequent additions (with nco_var_add_tll_ncra()) only check new addend (not running sum) against missing value. Hence (as of 20120521) nco_var_copy_tll() specifically resets sum to zero rather than to missing value Parent function (e.g., ncra.c) must post-process ttl buffers nco_op_ttl with nco_var_tll_zro_mss_val() */ if(idx_rec == 0) (void)nco_var_copy_tll(var_prc->type,var_prc->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->tally,var_prc->val,var_prc_out->val); else (void)nco_var_add_tll_ncra(var_prc->type,var_prc->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->tally,var_prc->val,var_prc_out->val); break; case nco_op_avg: /* Average */ case nco_op_sqrt: /* Squareroot will produce the squareroot of the mean */ case nco_op_sqravg: /* Square of the mean */ /* These operations all require subsequent normalization, where degenerate tallies are accounted for Thus, they all call nco_var_add_tll_ncra() every iteration, without special treatment on first iteration */ (void)nco_var_add_tll_ncra(var_prc->type,var_prc->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->tally,var_prc->val,var_prc_out->val); break; case nco_op_rms: /* Root mean square */ case nco_op_rmssdn: /* Root mean square normalized by N-1 */ case nco_op_avgsqr: /* Mean square */ /* Square values in var_prc first */ nco_var_mlt(var_prc->type,var_prc->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->val,var_prc->val); /* Sum the squares */ (void)nco_var_add_tll_ncra(var_prc_out->type,var_prc_out->sz,var_prc->has_mss_val,var_prc->mss_val,var_prc->tally,var_prc->val,var_prc_out->val); break; } /* end switch */ } /* end nco_opr_drv() */ const char * /* O [enm] Arithmetic operation */ nco_op_typ_cf_sng /* [fnc] Convert arithmetic operation type enum to string */ (const int nco_op_typ) /* I [enm] Arithmetic operation type */ { /* Purpose: Convert arithmetic operation type enum to string for use in CF Cell Methods http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.7-draft1/cf-conventions.html#appendix-cell-methods */ switch(nco_op_typ){ case nco_op_avg: return "mean"; break; /* [enm] Average */ case nco_op_min: return "minimum"; break; /* [enm] Minimum value */ case nco_op_max: return "maximum"; break; /* [enm] Maximum value */ case nco_op_ttl: return "sum"; break; /* [enm] Linear sum */ case nco_op_sqravg: return "TBD"; break; /* [enm] Square of mean */ case nco_op_avgsqr: return "variance"; break; /* [enm] Mean of sum of squares */ case nco_op_sqrt: return "TBD"; break; /* [enm] Square root of mean */ case nco_op_rms: return "TBD"; break; /* [enm] Root-mean-square (normalized by N) */ case nco_op_rmssdn: return "TBD"; break; /* [enm] Root-mean square normalized by N-1 */ case nco_op_add: case nco_op_sbt: case nco_op_mlt: case nco_op_dvd: case nco_op_nil: default: return "BROKEN"; break; /* [enm] Nil or undefined operation type */ } /* end switch */ } /* end nco_op_typ_cf_sng() */ int /* O [enm] Arithmetic operation */ nco_op_typ_get /* [fnc] Convert user-specified operation into operation key */ (const char * const nco_op_sng) /* I [sng] User-specified operation */ { /* Purpose: Process '-y' command line argument Convert user-specified string to enumerated operation type */ const char fnc_nm[]="nco_op_typ_get()"; /* [sng] Function name */ char *nco_prg_nm; /* [sng] Program name */ int nco_prg_id; /* [enm] Program ID */ nco_prg_nm=nco_prg_nm_get(); /* [sng] Program name */ nco_prg_id=nco_prg_id_get(); /* [enm] Program ID */ if(nco_op_sng == NULL){ /* If nco_op_typ_get() is called when user-specified option string is NULL, then operation type may be implied by program name itself */ if(!strcmp(nco_prg_nm,"ncadd")) return nco_op_add; if(!strcmp(nco_prg_nm,"mpncbo")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"mpncdiff")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"ncbo")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"ncdiff")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"ncsub")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"ncsubtract")) return nco_op_sbt; if(!strcmp(nco_prg_nm,"ncmult")) return nco_op_mlt; if(!strcmp(nco_prg_nm,"ncmultiply")) return nco_op_mlt; if(!strcmp(nco_prg_nm,"ncdivide")) return nco_op_dvd; (void)fprintf(stderr,"%s: ERROR %s reports empty user-specified operation string in conjunction with unknown or ambiguous executable name %s\n",nco_prg_nm,fnc_nm,nco_prg_nm); nco_exit(EXIT_FAILURE); } /* endif */ if(!strcmp(nco_op_sng,"avg") || !strcmp(nco_op_sng,"average") || !strcmp(nco_op_sng,"mean")) return nco_op_avg; if(!strcmp(nco_op_sng,"avgsqr")) return nco_op_avgsqr; if(!strcmp(nco_op_sng,"max") || !strcmp(nco_op_sng,"maximum")) return nco_op_max; if(!strcmp(nco_op_sng,"min") || !strcmp(nco_op_sng,"minimum")) return nco_op_min; if(!strcmp(nco_op_sng,"rms") || !strcmp(nco_op_sng,"root-mean-square")) return nco_op_rms; if(!strcmp(nco_op_sng,"rmssdn")) return nco_op_rmssdn; if(!strcmp(nco_op_sng,"sqravg")) return nco_op_sqravg; if(!strcmp(nco_op_sng,"sqrt") || !strcmp(nco_op_sng,"square-root")) return nco_op_sqrt; if(!strcmp(nco_op_sng,"total") || !strcmp(nco_op_sng,"ttl") || !strcmp(nco_op_sng,"sum")) return nco_op_ttl; if(!strcmp(nco_op_sng,"add") || !strcmp(nco_op_sng,"+") || !strcmp(nco_op_sng,"addition")) return nco_op_add; if(!strcmp(nco_op_sng,"sbt") || !strcmp(nco_op_sng,"-") || !strcmp(nco_op_sng,"dff") || !strcmp(nco_op_sng,"diff") || !strcmp(nco_op_sng,"sub") || !strcmp(nco_op_sng,"subtract") || !strcmp(nco_op_sng,"subtraction")) return nco_op_sbt; if(!strcmp(nco_op_sng,"dvd") || !strcmp(nco_op_sng,"/") || !strcmp(nco_op_sng,"divide") || !strcmp(nco_op_sng,"division")) return nco_op_dvd; if(!strcmp(nco_op_sng,"mlt") || !strcmp(nco_op_sng,"*") || !strcmp(nco_op_sng,"mult") || !strcmp(nco_op_sng,"multiply") || !strcmp(nco_op_sng,"multiplication")) return nco_op_mlt; (void)fprintf(stderr,"%s: ERROR %s reports unknown user-specified operation type \"%s\"\n",nco_prg_nm,fnc_nm,nco_op_sng); (void)fprintf(stderr,"%s: HINT Valid operation type (op_typ) choices:\n",nco_prg_nm); if(nco_prg_id == ncbo) (void)fprintf(stderr,"addition: add,+,addition\nsubtraction: sbt,-,dff,diff,sub,subtract,subtraction\nmultiplication: mlt,*,mult,multiply,multiplication\ndivision: dvd,/,divide,division\n"); else (void)fprintf(stderr,"min or minimum, max or maximum, ttl or total or sum, avg or average or mean, sqrt or square-root, sqravg, avgsqr, rms or root-mean-square, rmssdn\n"); nco_exit(EXIT_FAILURE); return False; /* Statement should not be reached */ } /* end nco_op_typ_get() */ int /* O [enm] Relational operation */ nco_op_prs_rlt /* [fnc] Convert Fortran abbreviation for relational operator into NCO operation key */ (const char * const op_sng) /* I [sng] Fortran representation of relational operator */ { /* Purpose: Convert Fortran abbreviation for relational operator into NCO operation key */ /* Classify the relation */ if(!strcmp(op_sng,"eq")){ return nco_op_eq; }else if(!strcmp(op_sng,"ne")){ return nco_op_ne; }else if(!strcmp(op_sng,"lt")){ return nco_op_lt; }else if(!strcmp(op_sng,"gt")){ return nco_op_gt; }else if(!strcmp(op_sng,"le")){ return nco_op_le; }else if(!strcmp(op_sng,"ge")){ return nco_op_ge; }else{ (void)fprintf(stdout,"%s: ERROR %s not registered in nco_op_prs_rlt()\n",nco_prg_nm_get(),op_sng); nco_exit(EXIT_FAILURE); } /* end else */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return False; /* Statement should not be reached */ } /* end nco_op_prs_rlt() */ void vec_set /* [fnc] Fill every value of first operand with value of second operand */ (const nc_type type, /* I [enm] netCDF type of operand */ const long sz, /* I [nbr] size (in elements) of operand */ ptr_unn op1, /* I [sct] Values of first operand */ const double op2) /* I [frc] Value to fill vector with */ { /* Purpose: Fill every value of first operand with value of second operand */ long idx; /* Typecast pointer to values before access */ (void)cast_void_nctype(type,&op1); switch(type){ case NC_FLOAT: for(idx=0;idx= 0.0) ? floor(x+0.5) : ceil(x-0.5);}; long long int llrintf(float x){return (x >= 0.0f) ? floorf(x+0.5f) : ceilf(x-0.5f);}; long int lrint(double x){return (x >= 0.0) ? floor(x+0.5) : ceil(x-0.5);}; long int lrintf(float x){return (x >= 0.0f) ? floorf(x+0.5f) : ceilf(x-0.5f);}; long long int llround(double x){return floor(x+0.5);} long long int llroundf(float x){return floorf(x+0.5f);} long int lround(double x){return floor(x+0.5);} long int lroundf(float x){return floorf(x+0.5f);} #endif /* !_MSC_VER */ /* In ANSI C, provides standard math intrinsics in double precision On most architectures, single precision ("float") versions are also supplied C++ compilers need float versions of these functions to be efficient anyway Names of these optional float functions end in "f", as specified by ANSI Create any needed float functions simply by coercing I/O of double versions MacOS X does not provide float versions of _any_ standard function! */ /* fxm: TODO #37 inline these definitions? */ #ifdef NEED_FMODF float fmodf(float x,float y){return (float)(fmod((double)x,(double)y));} #endif /* !NEED_FMODF */ #ifdef NEED_POWF float powf(float x,float y){return (float)(pow((double)x,(double)y));} #endif /* !NEED_POWF */ #ifdef NEED_ACOSF float acosf(float x){return (float)(acos((double)x));} #endif /* !NEED_ACOSF */ #ifdef NEED_ACOSHF float acoshf(float x){return (float)(acosh((double)x));} #endif /* !NEED_ACOSHF */ #ifdef NEED_ASINF float asinf(float x){return (float)(asin((double)x));} #endif /* !NEED_ASINF */ #ifdef NEED_ASINHF float asinhf(float x){return (float)(asinh((double)x));} #endif /* !NEED_ASINHF */ #ifdef NEED_ATANF float atanf(float x){return (float)(atan((double)x));} #endif /* !NEED_ATANF */ #ifdef NEED_ATAN2F float atan2f(float x,float y){return (float)(atan2((double)x,(double)y));} #endif /* !NEED_ATAN2F */ #ifdef NEED_ATANHF float atanhf(float x){return (float)(atanh((double)x));} #endif /* !NEED_ATANHF */ #ifdef NEED_CEILF float ceilf(float x){return (float)(ceil((double)x));} #endif /* !NEED_CEILF */ #ifdef NEED_COSF float cosf(float x){return (float)(cos((double)x));} #endif /* !NEED_COSF */ #ifdef NEED_COSHF float coshf(float x){return (float)(cosh((double)x));} #endif /* !NEED_COSHF */ #ifdef NEED_ERFCF float erfcf(float x){return (float)(erfc((double)x));} #endif /* !NEED_ERFCF */ #ifdef NEED_ERFF float erff(float x){return (float)(erf((double)x));} #endif /* !NEED_ERFF */ #ifdef NEED_EXPF float expf(float x){return (float)(exp((double)x));} #endif /* !NEED_EXPF */ #ifdef NEED_FABSF float fabsf(float x){return (float)(fabs((double)x));} #endif /* !NEED_FABSF */ #ifdef NEED_FLOORF float floorf(float x){return (float)(floor((double)x));} #endif /* !NEED_FLOORF */ #ifdef NEED_GAMMAF float gammaf(float x){return (float)(gamma((double)x));} #endif /* !NEED_GAMMAF */ #ifdef NEED_LOG10F float log10f(float x){return (float)(log10((double)x));} #endif /* !NEED_LOG10F */ #ifdef NEED_LOGF float logf(float x){ /* fxm TODO ncap57: Eventually remove this debugging statement and the include stdio that it requires */ /* (void)fprintf(stderr,"%s: DEBUG Using NCO-supplied function logf() from nco_rth_flt.c\n",nco_prg_nm_get()); */ return (float)(log((double)x));} #endif /* !NEED_LOGF */ #ifdef NEED_SINF float sinf(float x){return (float)(sin((double)x));} #endif /* !NEED_SINF */ #ifdef NEED_SINHF float sinhf(float x){return (float)(sinh((double)x));} #endif /* !NEED_SINHF */ #ifdef NEED_SQRTF float sqrtf(float x){return (float)(sqrt((double)x));} #endif /* !NEED_SQRTF */ #ifdef NEED_TANF float tanf(float x){return (float)(tan((double)x));} #endif /* !NEED_TANF */ #ifdef NEED_TANHF float tanhf(float x){return (float)(tanh((double)x));} #endif /* !NEED_TANHF */ /* fxm TODO nco652 */ double /* O [frc] Random fraction in [0,1] */ rnd_nbr /* [fnc] Generate random fraction in [0,1] */ (double x) /* I [frc] Immaterial */ { /* Purpose: Wrapper for system random number generator Output does not depend on input value of x 201207: Without srand() and srandom() seeds, same number would be generated each time */ long rnd_nbr_lng; double rnd_nbr_dbl_frc; x=x+0.0; /* CEWI */ #ifdef _MSC_VER /* Seed random-number generator with current time */ srand((unsigned)time(NULL)); rnd_nbr_lng=rand(); #else /* !_MSC_VER */ /* Seed random-number generator with current time */ srandom((unsigned)time(NULL)); rnd_nbr_lng=random(); #endif /* !_MSC_VER */ rnd_nbr_dbl_frc=rnd_nbr_lng*1.0/RAND_MAX; return rnd_nbr_dbl_frc; } /* end rnd_nbr() */ #define NEED_RND_NBRF #ifdef NEED_RND_NBRF float rnd_nbrf(float x){return (float)(rnd_nbr((double)x));} #endif /* !NEED_RND_NBRF */ /* fxm TODO nco1092 */ /* C math library math.h guaranteed to include floor() and ceil() So floor() and ceil() are safe to use in definition of other would-be intrinsics Helpful summary of POSIX, ISO, and MSVC math intrinsics at http://www.johndcook.com/math_h.html */ #ifdef NEED_RINT /* Lack of double-precision version implies lack of single-precision version */ # define NEED_RINTF double /* O [frc] Rounded value of x */ rint /* [fnc] Round x to nearest even integer, raise exceptions */ (double x) /* I [frc] Value to round */ { /* Purpose: Rounding function for lame systems that lack the intrinsic rint() rint() should round x to nearest integer, using current rounding direction (unlike round(), which always rounds away from zero). Halfway cases are rounded to nearest even integer (!). Yes, that appears to be an accurate summary of this highly technical IEEE floating point rounding algorithm. Only difference from nearbyint() is that rint() should raise inexact flag, nearbyint() should not NB: POSIX version of rint() sets IEEE inexact exceptions (unlike nearbyint()) This hacked version does not */ /* Source: */ return (x >= 0.0) ? floor(x+0.5) : ceil(x-0.5); } /* end rint() */ #endif /* !NEED_RINT */ #ifdef NEED_NEARBYINT /* Lack of double-precision version implies lack of single-precision version */ # define NEED_NEARBYINTF double /* O [frc] Rounded value of x */ nearbyint /* [fnc] Round x to nearest even integer, do not raise exceptions */ (double x) /* I [frc] Value to round */ { /* Purpose: Rounding function for lame systems that lack the intrinsic nearbyint() nearbyint() should round x to nearest integer, using current rounding direction (unlike round(), which always rounds away from zero). Halfway cases are rounded to nearest even integer (!). Yes, that appears to be an accurate summary of this highly technical IEEE floating point rounding algorithm. Only difference from rint() is that rint() should raise inexact flag, nearbyint() should not NB: POSIX version of nearbyint() does not set IEEE inexact exceptions (unlike rint()) */ /* Source: */ return (x >= 0.0) ? floor(x+0.5) : ceil(x-0.5); } /* end nearbyint() */ #endif /* !NEED_NEARBYINT */ #ifdef NEED_ROUND /* Lack of double-precision version implies lack of single-precision version */ # define NEED_ROUNDF double /* O [frc] Rounded value of x */ round /* [fnc] Round x to nearest integer, half-way cases round away from zero */ (double x) /* I [frc] Value to round */ { /* Purpose: Rounding function for lame systems that lack the intrinsic round() round() should round x to nearest integer, halfway cases away from zero regardless of current rounding direction (unlike rint() and nearbyint()) Source: http://www.codeproject.com/Articles/58289/C-Round-Function NB: POSIX version should set IEEE inexact exceptions This hacked version does not */ /* NB: function returns int and then implicit coercion turns receptor into floating point */ return (x >= 0) ? (int)(x+0.5) : (int)(x-0.5); } /* end round() */ #endif /* !NEED_ROUND */ #ifdef NEED_TRUNC /* Lack of double-precision version implies lack of single-precision version */ # define NEED_TRUNCF double /* O [frc] Truncated value of x */ trunc /* [fnc] Truncate x to nearest integer not larger in absolute value */ (double x) /* I [frc] Value to truncate */ { /* Purpose: Truncating function for lame systems that lack the intrinsic trunc() trunc() should round x to nearest integer not larger in absolute value Truncation is the same thing as implicit conversion to int */ /* NB: function returns int and then implicit coercion turns receptor into floating point */ return (int)x; } /* end trunc() */ #endif /* !NEED_TRUNC */ #ifdef NEED_RINTF float rintf(float x){return (float)(rint((double)x));} #endif /* !NEED_RINTF */ #ifdef NEED_ROUNDF float roundf(float x){return (float)(round((double)x));} #endif /* !NEED_ROUNDF */ #ifdef NEED_NEARBYINTF float nearbyintf(float x){return (float)(nearbyint((double)x));} #endif /* !NEED_NEARBYINTF */ #ifdef NEED_TRUNCF float truncf(float x){return (float)(trunc((double)x));} #endif /* !NEED_TRUNCF */ ./nco-4.4.2/src/nco/nco_bnr.h0000644000674300045400000000334412260451231015114 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_bnr.h,v 1.21 2013/12/31 05:14:01 zender Exp $ */ /* Purpose: Binary write utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_bnr.h" *//* Binary write utilities */ #ifndef NCO_BNR_H #define NCO_BNR_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ FILE * /* O [fl] Unformatted binary output file handle */ nco_bnr_open /* [fnc] Open unformatted binary data file for writing */ (const char * const fl_bnr); /* [sng] Unformatted binary output file */ int /* [rcd] Return code */ nco_bnr_close /* [fnc] Close unformatted binary data file for writing */ (FILE *fp_bnr, /* I [fl] Unformatted binary output file handle */ const char * const fl_bnr); /* [sng] Unformatted binary output file */ size_t /* O [nbr] Number of elements successfully written */ nco_bnr_wrt /* [fnc] Write unformatted binary data */ (FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const char * const var_nm, /* I [sng] Variable name */ const long var_sz, /* I [nbr] Variable size */ const nc_type var_typ, /* I [enm] Variable type */ const void * const void_ptr); /* I [ptr] Data to write */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_BNR_H */ ./nco-4.4.2/src/nco/nco_aux.c0000644000674300045400000006452112277324010015131 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_aux.c,v 1.80 2014/02/14 05:22:16 zender Exp $ */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Purpose: Support hyperslabbing cell-based grids over coordinate ranges This works on datasets that contain CF-convention auxiliary coordinate variables. Such datasets contain variables with standard_name's "latitude" and "longitude". Cells that contain a value within the user-requested range are considered a match. Could be useful to look at the CF bounds variable instead but harder. Author: Karen Schuchardt Example usage: ncks -X 0.,45.,0.,90. -X 180.,225.,-90.,0. ~/nco/data/in.nc ~/foo.nc */ #include "nco_aux.h" /* Auxiliary coordinates */ nco_bool nco_find_lat_lon (int nc_id, char var_nm_lat[], char var_nm_lon[], char **units, int *lat_id, int *lon_id, nc_type *crd_typ) { /* Purpose: Find auxiliary coordinate variables that map to latitude/longitude Find variables with standard_name = "latitude" and "longitude" Return true if both latitude and longitude standard names are found Also return needed information about these auxiliary coordinates Assumes that units and types for latitude and longitude are identical Caller responsible for memory management for variable names Memory for unit strings must be freed by caller */ const char fnc_nm[]="nco_find_lat_lon()"; char var_nm[NC_MAX_NAME]; char value[NC_MAX_NAME]; int idx; int nvars=0; int rcd=NC_NOERR; int crd_nbr=0; int var_dimid[NC_MAX_VAR_DIMS]; /* [enm] Dimension ID */ int var_att_nbr; /* [nbr] Number of attributes */ int var_dmn_nbr; /* [nbr] Number of dimensions */ long lenp; nc_type var_typ; /* [enm] variable type */ /* Make sure CF tag exists. Currently require CF-1.0 value */ if(NCO_GET_ATT_CHAR(nc_id,NC_GLOBAL,"Conventions",value) || !strstr(value,"CF-1.")){ if(nco_dbg_lvl_get() >= nco_dbg_dev) (void)fprintf(stderr,"%s: WARNING %s reports file \"Convention\" attribute is missing or is present but not of the form \"CF-1.X\". Auxiliary coordinate support (i.e., the -X option) cannot be expected to behave well file does not support CF-1.X metadata conventions. Continuing anyway...\n",nco_prg_nm_get(),fnc_nm); } /* !CF */ /* Get number of variables */ rcd=nco_inq_nvars(nc_id,&nvars); /* For each variable, see if standard name is latitude or longitude */ for(idx=0;idx 1) (void)fprintf(stderr,"%s: WARNING %s reports latitude variable %s has %d dimensions. NCO only supports hyperslabbing of auxiliary coordinate variables with a single dimension. Continuing with unpredictable results...\n",nco_prg_nm_get(),fnc_nm,var_nm,var_dmn_nbr); /* Assign type; assumed same for both lat and lon */ *crd_typ=var_typ; crd_nbr++; } /* endif latitude */ if(!strcmp(value,"longitude")){ strcpy(var_nm_lon,var_nm); *lon_id=idx; crd_nbr++; } /* endif longitude */ if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG %s variable <%s>\n",nco_prg_nm_get(),fnc_nm, var_nm); } } /* endif standard_name */ } /* end loop over vars */ if(crd_nbr != 2){ if(nco_dbg_lvl_get() >= nco_dbg_dev) (void)fprintf(stdout,"nco_find_lat_lon() unable to identify lat/lon auxiliary coordinate variables.\n"); return False; }else return True; } /* end nco_find_lat_lon() */ int /* [enm] Return status */ nco_get_dmn_info (int nc_id, int var_id, char dmn_nm[], int *dimid, long *dmn_sz) { /* Purpose: Get dimension information associated with specified variable In our case, this is lat or lon---they are presumed to be identical */ int rcd=NC_NOERR; nc_type var_typ; /* variable type */ int var_dimid[NC_MAX_VAR_DIMS]; /* dimension ids */ int var_att_nbr; /* number of attributes */ int var_dmn_nbr; /* number of dims */ /* Get dimension information */ rcd=nco_inq_var(nc_id,var_id,0,&var_typ,&var_dmn_nbr,var_dimid,&var_att_nbr); if(rcd == NC_NOERR){ *dimid=var_dimid[0]; rcd=nco_inq_dimlen(nc_id,var_dimid[0],dmn_sz); rcd=nco_inq_dimname(nc_id,var_dimid[0],dmn_nm); } /* endif */ if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_get_dmn_info() unable to get dimension information"); return rcd; } /* end nco_get_dmn_info() */ lmt_sct ** nco_aux_evl (int in_id, int aux_nbr, char *aux_arg[], int *lmt_nbr, char *nm_dmn) /* O [sng] Dimension name */ { /* Purpose: Create lmt structure of slabs of continguous cells that match rectangular region specified by -X arguments. Intended for use with non-monotonic grids Requires CF-1.0 conventions Uses latitude/longitude centers rather than cell_bounds to detect matches Code assumes units are degrees if they are not radians */ const char fnc_nm[]="nco_aux_evl()"; /* [sng] Function name */ char *units=NULL; /* fxm TODO nco925: "units" value needs dynamically allocated size in case value exceeds NC_MAX_NAME */ char cll_idx_sng[100]; /* Buffer for user-assigned limit names */ char dmn_nm[NC_MAX_NAME]; char var_nm_lat[NC_MAX_NAME]; char var_nm_lon[NC_MAX_NAME]; dmn_sct lat; dmn_sct lon; double lat_crr; /* [dgr] Current cell latitude */ double lon_crr; /* [dgr] Current cell longitude */ float lat_min; /* [dgr] Lower left latitude of bounding rectangle */ float lat_max; /* [dgr] Upper right longitude of bounding rectangle */ float lon_min; /* [dgr] Lower left longitude of bounding rectangle */ float lon_max; /* [dgr] Upper right latitude of bounding rectangle */ int aux_idx; /* [idx] Index over user -X options */ int cll_grp_nbr=0; /* [nbr] Number of groups of cells within this bounding box */ int cll_idx; /* [idx] Cell index */ int cll_idx_min=-1; /* [idx] Minimum index of cell in consecutive cell set */ int cll_nbr_cns=0; /* [nbr] Number of consecutive cells within current group */ int cll_nbr_ttl=0; /* [nbr] Total number of cells within this bounding box */ int dmn_id=int_CEWI; int lat_id; int lon_id; int rcd=NC_NOERR; lmt_sct **lmt=NULL; /* [sct] List of returned lmt structures */ long dmn_sz=0; nc_type crd_typ; void *vp_lat; /* [dgr] Latitude coordinate array, float or double */ void *vp_lon; /* [dgr] Longitude coordinate array, float or double */ nco_bool has_lat_lon; *lmt_nbr=0; /* Obtain lat/lon variable names */ has_lat_lon=nco_find_lat_lon(in_id,var_nm_lat,var_nm_lon,&units,&lat_id,&lon_id,&crd_typ); if(!has_lat_lon) return NULL; /* Obtain dimension information of lat/lon coordinates */ rcd+=nco_get_dmn_info(in_id,lat_id,dmn_nm,&dmn_id,&dmn_sz); if(rcd != NC_NOERR) nco_err_exit(rcd,"nco_aux_evl() unable get past nco_get_dmn_info()\n"); /* Load latitude/longitude variables needed to search for region matches */ lat.type=crd_typ; lat.sz=dmn_sz; lat.srt=0L; vp_lat=(void *)nco_malloc(dmn_sz*nco_typ_lng(lat.type)); lon.type=crd_typ; lon.sz=dmn_sz; lon.srt=0L; vp_lon=(void *)nco_malloc(dmn_sz*nco_typ_lng(lon.type)); rcd+=nco_get_vara(in_id,lat_id,&lat.srt,&lat.sz,vp_lat,lat.type); rcd+=nco_get_vara(in_id,lon_id,&lon.srt,&lon.sz,vp_lon,lon.type); lmt_sct lmt_tpl; (void)nco_lmt_init(&lmt_tpl); lmt_tpl.nm=(char *)strdup(dmn_nm); lmt_tpl.lmt_typ=lmt_dmn_idx; lmt_tpl.is_usr_spc_lmt=True; lmt_tpl.is_usr_spc_min=True; lmt_tpl.is_usr_spc_max=True; lmt_tpl.flg_mro=False; lmt_tpl.srd_sng=(char *)strdup("1"); lmt_tpl.ssc_sng=NULL; lmt_tpl.ssc_sng=NULL; lmt_tpl.mro_sng=NULL; lmt_tpl.mro_sng=NULL; lmt_tpl.is_rec_dmn=0; lmt_tpl.id=dmn_id; lmt_tpl.min_idx=0; lmt_tpl.max_idx=0; lmt_tpl.srt=0L; lmt_tpl.end=0L; lmt_tpl.cnt=0L; lmt_tpl.srd=1L; lmt_tpl.ssc=1L; /* malloc() lmt structure to return No way to know exact size in advance though maximum is about dim_sz/2 */ int MAX_LMT_NBR=dmn_sz/2; if(aux_nbr > 0) lmt=(lmt_sct **)nco_malloc(MAX_LMT_NBR*sizeof(lmt_sct *)); /* Loop over user-specified bounding boxes */ for(aux_idx=0;aux_idx= lon_min && lon_crr <= lon_max && lat_crr >= lat_min && lat_crr <= lat_max){ if(cll_idx_min == -1){ /* First cell within current bounding box */ cll_idx_min=cll_idx; cll_nbr_cns=1; }else if(cll_idx == cll_idx_min+cll_nbr_cns){ /* Later, contiguous cell within current bounding box */ cll_nbr_cns++; } /* end found matching cell */ }else if(cll_idx_min != -1){ /* Current cell is not within bounding box though immediately previous cell is */ sprintf(cll_idx_sng,"%d",cll_idx_min); lmt_tpl.min_sng=(char *)strdup(cll_idx_sng); lmt_tpl.min_idx=lmt_tpl.srt=cll_idx_min; sprintf(cll_idx_sng,"%d",cll_idx_min+cll_nbr_cns-1); lmt_tpl.max_sng=(char *)strdup(cll_idx_sng); lmt_tpl.max_idx=lmt_tpl.end=cll_idx_min+cll_nbr_cns-1; lmt_tpl.cnt=cll_nbr_cns; (*lmt_nbr)++; if(*lmt_nbr > MAX_LMT_NBR) nco_err_exit(0,"%s: Number of slabs exceeds allocated mamory"); lmt[(*lmt_nbr)-1]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); *lmt[(*lmt_nbr)-1]=lmt_tpl; cll_grp_nbr++; cll_nbr_ttl+=cll_nbr_cns; /* Indicate that next cell, if any, in this bounding box requires new limit structure */ cll_idx_min=-1; } /* end if one or more consecutive matching cells */ } /* end loop over cells */ if(nco_dbg_lvl_get() > nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: %s reports bounding-box %g <= %s <= %g and %g <= %s <= %g brackets %d distinct group(s) comprising %d total gridpoint(s)\n",nco_prg_nm_get(),fnc_nm,lon_min,var_nm_lon,lon_max,lat_min,var_nm_lat,lat_max,cll_grp_nbr,cll_nbr_ttl); } } /* end loop over user supplied -X options */ /* Free allocated memory */ if(units) units=(char *)nco_free(units); if(vp_lat) vp_lat=nco_free(vp_lat); if(vp_lon) vp_lon=nco_free(vp_lon); /* With some loss of generality, we assume cell-based coordinates are not record coordinates spanning multiple files. Thus finding no cells within any bounding box constitutes a domain error. */ if(*lmt_nbr == 0){ (void)fprintf(stdout,"%s: ERROR %s reports that none of the %d specified auxiliary-coordinate bounding-box(es) contain any latitude/longitude coordinate pairs. This condition was not flagged as an error until 20110221. Prior to that, when no coordinates were in any of the user-specified auxiliary-coordinate hyperslab(s), NCO mistakenly returned the entire coordinate range as being within the hyperslab(s).\n",nco_prg_nm_get(),fnc_nm,aux_nbr); nco_exit(EXIT_FAILURE); } /* end if */ lmt=(lmt_sct **)nco_realloc(lmt,(*lmt_nbr)*sizeof(lmt_sct *)); /* Export dimension name */ strcpy(nm_dmn,dmn_nm); return lmt; } /* end nco_aux_evl() */ void nco_aux_prs (const char *bnd_bx_sng, const char *units, float *lon_min, float *lon_max, float *lat_min, float *lat_max) { /* Purpose: Parse command-line arguments of form: lon_min,lon_max,lat_min,lat_max */ char *bnd_bx_sng_tmp; char *crd_tkn; bnd_bx_sng_tmp=strdup(bnd_bx_sng); sscanf(bnd_bx_sng,"%f,%f,%f,%f",lon_min,lon_max,lat_min,lat_max); crd_tkn=strtok(bnd_bx_sng_tmp,", "); if(crd_tkn) sscanf(crd_tkn,"%f",lon_min); else nco_err_exit(0,"nco_aux_prs(): Problem with LL longitude string"); crd_tkn=strtok(NULL,", "); if(crd_tkn) sscanf(crd_tkn,"%f",lon_max); else nco_err_exit(0,"nco_aux_prs(): Problem with UR longitude string"); crd_tkn=strtok(NULL,", "); if(crd_tkn) sscanf(crd_tkn,"%f",lat_min); else nco_err_exit(0,"nco_aux_prs(): Problem with LL latitude string"); crd_tkn=strtok(NULL,", "); if(crd_tkn) sscanf(crd_tkn,"%f",lat_max); else nco_err_exit(0,"nco_aux_prs(): Problem with UR latitude string"); if(bnd_bx_sng_tmp) bnd_bx_sng_tmp=(char *)nco_free(bnd_bx_sng_tmp); if(!strcmp(units,"radians")){ /* WIN32 math.h does not define M_PI */ #ifndef M_PI # define M_PI 3.14159265358979323846 #endif /* M_PI */ *lon_min*=M_PI/180.0; *lon_max*=M_PI/180.0; *lat_min*=M_PI/180.0; *lat_max*=M_PI/180.0; } /* endif radians */ } /* nco_aux_prs */ lmt_sct ** /* O [lst] Auxiliary coordinate limits */ nco_aux_evl_trv (const int nc_id, /* I [ID] netCDF file ID */ int aux_nbr, /* I [sng] Number of auxiliary coordinates */ char *aux_arg[], /* I [sng] Auxiliary coordinates */ trv_sct *lat_trv, /* I [sct] "latitude" variable */ trv_sct *lon_trv, /* I [sct] "longitude" variable */ const nc_type crd_typ, /* I [nbr] netCDF type of both "latitude" and "longitude" */ const char * const units, /* I [sng] Units of both "latitude" and "longitude" */ int *aux_lmt_nbr) /* I/O [nbr] Number of coordinate limits */ { /* Purpose: Create lmt structure of slabs of continguous cells that match rectangular region specified by -X arguments. Intended for use with non-monotonic grids Requires CF-1.0 conventions Uses latitude/longitude centers rather than cell_bounds to detect matches Code assumes units are degrees if they are not radians */ const char fnc_nm[]="nco_aux_evl_trv()"; char cll_idx_sng[100]; /* Buffer for user-assigned limit names */ char dmn_nm[NC_MAX_NAME]; char var_nm_lat[NC_MAX_NAME]; char var_nm_lon[NC_MAX_NAME]; dmn_sct lat; dmn_sct lon; double lat_crr; /* [dgr] Current cell latitude */ double lon_crr; /* [dgr] Current cell longitude */ float lat_min; /* [dgr] Lower left latitude of bounding rectangle */ float lat_max; /* [dgr] Upper right longitude of bounding rectangle */ float lon_min; /* [dgr] Lower left longitude of bounding rectangle */ float lon_max; /* [dgr] Upper right latitude of bounding rectangle */ int aux_idx; /* [idx] Index over user -X options */ int cll_grp_nbr=0; /* [nbr] Number of groups of cells within this bounding box */ int cll_idx; /* [idx] Cell index */ int cll_idx_min=-1; /* [idx] Minimum index of cell in consecutive cell set */ int cll_nbr_cns=0; /* [nbr] Number of consecutive cells within current group */ int cll_nbr_ttl=0; /* [nbr] Total number of cells within this bounding box */ int dmn_id=int_CEWI; int lat_id; int lon_id; int rcd=NC_NOERR; int grp_id_lat; /* [id] Group ID */ int grp_id_lon; /* [id] Group ID */ lmt_sct **lmt=NULL; /* [sct] List of returned lmt structures */ long dmn_sz=0; void *vp_lat; /* [dgr] Latitude coordinate array, float or double */ void *vp_lon; /* [dgr] Longitude coordinate array, float or double */ *aux_lmt_nbr=0; /* Obtain group ID of 'latitude' and 'longitude' from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,lat_trv->grp_nm_fll,&grp_id_lat); (void)nco_inq_grp_full_ncid(nc_id,lon_trv->grp_nm_fll,&grp_id_lon); /* Obtain variable ID of 'latitude' and 'longitude' */ (void)nco_inq_varid(grp_id_lat,lat_trv->nm,&lat_id); (void)nco_inq_varid(grp_id_lon,lon_trv->nm,&lon_id); /* Obtain dimension information of lat/lon coordinates */ (void)nco_get_dmn_info(grp_id_lat,lat_id,dmn_nm,&dmn_id,&dmn_sz); /* Load latitude/longitude variables needed to search for region matches */ lat.type=crd_typ; lat.sz=dmn_sz; lat.srt=0L; vp_lat=(void *)nco_malloc(dmn_sz*nco_typ_lng(lat.type)); lon.type=crd_typ; lon.sz=dmn_sz; lon.srt=0L; vp_lon=(void *)nco_malloc(dmn_sz*nco_typ_lng(lon.type)); rcd+=nco_get_vara(grp_id_lat,lat_id,&lat.srt,&lat.sz,vp_lat,lat.type); rcd+=nco_get_vara(grp_id_lon,lon_id,&lon.srt,&lon.sz,vp_lon,lon.type); lmt_sct lmt_tpl; (void)nco_lmt_init(&lmt_tpl); lmt_tpl.nm=(char *)strdup(dmn_nm); lmt_tpl.lmt_typ=lmt_dmn_idx; lmt_tpl.is_usr_spc_lmt=True; lmt_tpl.is_usr_spc_min=True; lmt_tpl.is_usr_spc_max=True; lmt_tpl.flg_mro=False; lmt_tpl.srd_sng=(char *)strdup("1"); lmt_tpl.ssc_sng=NULL; lmt_tpl.ssc_sng=NULL; lmt_tpl.mro_sng=NULL; lmt_tpl.mro_sng=NULL; lmt_tpl.is_rec_dmn=0; lmt_tpl.id=dmn_id; lmt_tpl.min_idx=0; lmt_tpl.max_idx=0; lmt_tpl.srt=0L; lmt_tpl.end=0L; lmt_tpl.cnt=0L; lmt_tpl.srd=1L; lmt_tpl.ssc=1L; /* malloc() lmt structure to return No way to know exact size in advance though maximum is about dim_sz/2 */ int MAX_LMT_NBR=dmn_sz/2; if(aux_nbr > 0) lmt=(lmt_sct **)nco_malloc(MAX_LMT_NBR*sizeof(lmt_sct *)); /* Loop over user-specified bounding boxes */ for(aux_idx=0;aux_idx= lon_min && lon_crr <= lon_max && lat_crr >= lat_min && lat_crr <= lat_max){ if(cll_idx_min == -1){ /* First cell within current bounding box */ cll_idx_min=cll_idx; cll_nbr_cns=1; }else if(cll_idx == cll_idx_min+cll_nbr_cns){ /* Later, contiguous cell within current bounding box */ cll_nbr_cns++; } /* end found matching cell */ }else if(cll_idx_min != -1){ /* Current cell is not within bounding box though immediately previous cell is */ sprintf(cll_idx_sng,"%d",cll_idx_min); lmt_tpl.min_sng=(char *)strdup(cll_idx_sng); lmt_tpl.min_idx=lmt_tpl.srt=cll_idx_min; sprintf(cll_idx_sng,"%d",cll_idx_min+cll_nbr_cns-1); lmt_tpl.max_sng=(char *)strdup(cll_idx_sng); lmt_tpl.max_idx=lmt_tpl.end=cll_idx_min+cll_nbr_cns-1; lmt_tpl.cnt=cll_nbr_cns; (*aux_lmt_nbr)++; if(*aux_lmt_nbr > MAX_LMT_NBR) nco_err_exit(0,"%s: Number of slabs exceeds allocated mamory"); lmt[(*aux_lmt_nbr)-1]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); *lmt[(*aux_lmt_nbr)-1]=lmt_tpl; cll_grp_nbr++; cll_nbr_ttl+=cll_nbr_cns; /* Indicate that next cell, if any, in this bounding box requires new limit structure */ cll_idx_min=-1; } /* end if one or more consecutive matching cells */ } /* end loop over cells */ if(nco_dbg_lvl_get() > nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: %s reports bounding-box %g <= %s <= %g and %g <= %s <= %g brackets %d distinct group(s) comprising %d total gridpoint(s)\n",nco_prg_nm_get(),fnc_nm,lon_min,var_nm_lon,lon_max,lat_min,var_nm_lat,lat_max,cll_grp_nbr,cll_nbr_ttl); } } /* end loop over user supplied -X options */ /* Free allocated memory */ if(vp_lat) vp_lat=nco_free(vp_lat); if(vp_lon) vp_lon=nco_free(vp_lon); /* No limits found */ if(*aux_lmt_nbr == 0){ return NULL; } /* No limits found */ lmt=(lmt_sct **)nco_realloc(lmt,(*aux_lmt_nbr)*sizeof(lmt_sct *)); return lmt; } /* nco_aux_evl_trv */ nco_bool nco_find_lat_lon_trv (const int nc_id, /* I [ID] netCDF file ID */ const trv_sct * const var_trv, /* I [sct] Variable object that contains "standard_name" attribute */ const char * const attr_val, /* I [sng] Attribute value to find ( "latitude" or "longitude" ) */ char **var_nm_fll, /* I/O [sng] Full name of variable that has "latitude" or "longitude" attributes */ int *dmn_id, /* I/O [id] Dimension ID of the diension of "latitude" and "longitude" */ nc_type *crd_typ, /* I/O [enm] netCDF type of both "latitude" and "longitude" */ char units[]) /* I/O [sng] Units of both "latitude" and "longitude" */ { /* Purpose: Find auxiliary coordinate variables that map to latitude/longitude Find variables with standard_name = "latitude" and "longitude" Return true if both latitude and longitude standard names are found Also return needed information about these auxiliary coordinates Assumes that units and types for latitude and longitude are identical Caller responsible for memory management for variable names Memory for unit strings must be freed by caller */ const char fnc_nm[]="nco_find_lat_lon_trv()"; char att_nm[NC_MAX_NAME]; /* [sng] Attribute name */ char var_nm[NC_MAX_NAME]; int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ int var_dimid[NC_MAX_VAR_DIMS]; /* [enm] Dimension ID */ int var_att_nbr; /* [nbr] Number of attributes */ int var_dmn_nbr; /* [nbr] Number of dimensions */ nc_type var_typ; /* [enm] variable type */ assert(var_trv->nco_typ == nco_obj_typ_var); /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv->grp_nm_fll,&grp_id); /* Obtain variable ID */ (void)nco_inq_varid(grp_id,var_trv->nm,&var_id); /* Find number of attributes */ (void)nco_inq_var(grp_id,var_id,var_nm,&var_typ,&var_dmn_nbr,var_dimid,&var_att_nbr); assert(var_att_nbr == var_trv->nbr_att); /* Loop attributes */ for(int idx_att=0;idx_attnm_fll); /* Get units; assume same for both lat and lon */ int rcd=nco_inq_attlen_flg(grp_id,var_id,"units",&lenp); if(rcd != NC_NOERR){ if(nco_dbg_lvl_get() >= nco_dbg_var){ (void)fprintf(stdout,"nco_find_lat_lon() reports CF convention requires \"latitude\" to have units attribute\n"); } return False; } NCO_GET_ATT_CHAR(grp_id,var_id,"units",units); units[lenp]='\0'; if(var_dmn_nbr > 1) (void)fprintf(stderr,"%s: WARNING %s reports latitude variable %s has %d dimensions. NCO only supports hyperslabbing of auxiliary coordinate variables with a single dimension. Continuing with unpredictable results...\n",nco_prg_nm_get(),fnc_nm,var_nm,var_dmn_nbr); /* Assign type; assumed same for both lat and lon */ *crd_typ=var_typ; /* Export the dimension ID */ *dmn_id=var_dimid[0]; return True; } /* Match parameter name to find ( "latitude" or "longitude" ) */ } /* Loop attributes */ return False; } /* end nco_find_lat_lon_trv() */ ./nco-4.4.2/src/nco/ncap.c0000644000674300045400000012610712262576541014431 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncap.c,v 1.284 2014/01/06 19:00:49 zender Exp $ */ /* ncap -- netCDF arithmetic processor */ /* Purpose: Compute user-defined derived fields using forward algebraic notation applied to netCDF files */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncap -O -D 1 -S ${HOME}/nco/data/ncap.in ${HOME}/nco/data/in.nc ${HOME}/nco/data/foo.nc ncap -O -D 1 -s a=b+c -s "b=c-d/2." -S ncap.in in.nc ~/foo.nc ncap -O -D 1 -s two=one+two in.nc ~/foo.nc scp ~/nco/src/nco/ncap.c esmf.ess.uci.edu:nco/src/nco/ncap.c */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* assert() debugging macro */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #include /* POSIX stuff */ /* GNU getopt() is independent system header on FREEBSD, LINUX, LINUXALPHA, LINUXAMD, LINUXARM, WIN32 AT&T getopt() is in unistd.h or stdlib.h on AIX, CRAY, NECSX, SUNMP, SUN4SOL2 fxm: Unsure what ALPHA and SGI do */ #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "ncap.h" /* netCDF arithmetic processor-specific definitions (symbol table, ...) */ #include "libnco.h" /* netCDF Operator (NCO) library */ /* Global variables */ size_t ncap_ncl_dpt_crr=0UL; /* [nbr] Depth of current #include file (incremented in ncap_lex.l) */ size_t *ncap_ln_nbr_crr; /* [cnt] Line number (incremented in ncap_lex.l) */ char **ncap_fl_spt_glb=NULL; /* [fl] Script file */ void glb_init_free /* [fnc] Initialize and free global variables (line numbers and include stuff) */ (nco_bool action); /* I [flg] Initialize */ int main(int argc,char **argv) { extern int nco_yyparse(prs_sct *prs_arg); /* Prototype here as in bison.simple to avoid compiler warning */ /* Following declaration gets rid of implicit declaration compiler warning It is a condensation of the lexer declaration from lex.yy.c: YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); */ extern int nco_yy_scan_string(const char *); extern FILE *nco_yyin; /* [fl] Input script file */ /* fxm TODO nco652 */ double rnd_nbr(double); nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool PRN_FNC_TBL=False; /* Option f */ nco_bool PROCESS_ALL_VARS=True; /* Option v */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in; char **var_lst_in=NULL_CEWI; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *fl_spt_usr=NULL; /* Option s */ char *lmt_arg[NC_MAX_DIMS]; char *opt_crr=NULL; /* [sng] String representation of current long-option name */ #define NCAP_SPT_NBR_MAX 100 char *spt_arg[NCAP_SPT_NBR_MAX]; /* fxm: Arbitrary size, should be dynamic */ char *spt_arg_cat=NULL; /* [sng] User-specified script */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ const char * const CVS_Id="$Id: ncap.c,v 1.284 2014/01/06 19:00:49 zender Exp $"; const char * const CVS_Revision="$Revision: 1.284 $"; const char * const opt_sht_lst="3467ACcD:FfhL:l:n:Oo:p:Rrs:S:vx-:"; /* [sng] Single letter command line options */ cnk_dmn_sct **cnk_dmn=NULL_CEWI; #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ dmn_sct **dmn_in=NULL_CEWI; /* [lst] Dimensions in input file */ dmn_sct **dmn_out=NULL_CEWI; /* [lst] Dimensions written to output file */ dmn_sct **dmn_new=NULL_CEWI; /* [lst] Temporary dimensions to reduce referencing */ extern char *optarg; extern int optind; /* Math float prototypes required by AIX, Solaris, but not by Linux, IRIX */ /* Basic math: acos, asin, atan, cos, exp, fabs, log, log10, sin, sqrt, tan */ /* GNU g++ barfs at these float declartions -- remove if g++ used */ #ifndef __GNUG__ extern float acosf(float); extern float asinf(float); extern float atanf(float); extern float cosf(float); extern float expf(float); extern float fabsf(float); /* 20040629: Only AIX may need this */ extern float logf(float); extern float log10f(float); extern float rnd_nbrf(float); extern float sinf(float); extern float sqrtf(float); extern float tanf(float); /* Advanced math: erf, erfc, gamma */ extern float erff(float); extern float erfcf(float); extern float gammaf(float); /* Hyperbolic trigonometric: acosh, asinh, atanh, cosh, sinh, tanh */ extern float acoshf(float); extern float asinhf(float); extern float atanhf(float); extern float coshf(float); extern float sinhf(float); extern float tanhf(float); /* Basic Rounding: ceil, floor */ extern float ceilf(float); extern float floorf(float); /* Advanced Rounding: nearbyint, rint, round, trunc */ extern float nearbyintf(float); extern float rintf(float); extern float roundf(float); extern float truncf(float); #endif int abb_arg_nbr=0; int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_nbr=0; int fl_in_fmt; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx; int in_id; int jdx; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_att=0; /* [nbr] Number of attributes in script */ int nbr_dmn_ass=int_CEWI;/* Number of dimensions in temporary list */ int nbr_dmn_in=int_CEWI; /* Number of dimensions in dim_in */ int nbr_dmn_out=0; /* [nbr] Number of dimensions in list dmn_out */ int nbr_lst_a=0; /* size of xtr_lst_a */ int nbr_spt=0; /* Option s. NB: nbr_spt gets incremented */ int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl;/* number of vars in a file */ int nbr_var_prc; /* nbr_var_prc gets incremented */ int nbr_var_ycc=0; /* [nbr] Number of vars to be defined after 1st parse */ int xtr_nbr=0; /* xtr_nbr will not otherwise be set for -c with no -v */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int var_id; sym_sct **sym_tbl; /* [fnc] Symbol table for functions */ int sym_tbl_nbr; /* [nbr] Size of symbol table */ int sym_idx=0; /* [idx] Counter for symbols */ lmt_sct **lmt=NULL_CEWI; nm_id_sct *dmn_lst=NULL; nm_id_sct *xtr_lst=NULL; /* Non-processed variables to copy to OUTPUT */ nm_id_sct *xtr_lst_a=NULL; /* Initialize to ALL variables in OUTPUT file */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ size_t sng_lng; size_t spt_arg_lng=size_t_CEWI; var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc; var_sct **var_prc_out; var_sct **var_ycc=NULL; aed_sct **att_lst=NULL; prs_sct prs_arg; /* [sct] Global information required in parser routines */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"hdf_upk",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"hdf_unpack",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"fnc_tbl",no_argument,0,'f'}, {"prn_fnc_tbl",no_argument,0,'f'}, {"ftn",no_argument,0,'F'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"nintap",required_argument,0,'n'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"file",required_argument,0,'S'}, {"script-file",required_argument,0,'S'}, {"fl_spt",required_argument,0,'S'}, {"spt",required_argument,0,'s'}, {"script",required_argument,0,'s'}, {"units",no_argument,0,'u'}, {"variable",no_argument,0,'v'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdf_upk") || !strcmp(opt_crr,"hdf_unpack")) nco_upk_cnv=nco_upk_HDF; /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'f': /* Print function table */ PRN_FNC_TBL=True; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'n': /* NINTAP-style abbreviation of files to process */ /* Currently not used in ncap but should be to allow processing multiple input files by same script */ (void)fprintf(stderr,"%s: ERROR %s does not currently implement -n option\n",nco_prg_nm_get(),nco_prg_nm_get()); fl_lst_abb=nco_lst_prs_2D(optarg,",",&abb_arg_nbr); if(abb_arg_nbr < 1 || abb_arg_nbr > 3){ (void)fprintf(stderr,"%s: ERROR Incorrect abbreviation for file list\n",nco_prg_nm); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end if */ break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 's': /* Copy command script for later processing */ spt_arg[nbr_spt++]=(char *)strdup(optarg); if(nbr_spt == NCAP_SPT_NBR_MAX-1) (void)fprintf(stderr,"%s: WARNING No more than %d script arguments allowed. TODO #24\n",nco_prg_nm_get(),NCAP_SPT_NBR_MAX); break; case 'S': /* Read command script from file rather than from command line */ fl_spt_usr=(char *)strdup(optarg); break; case 'v': /* Variables to extract/exclude */ PROCESS_ALL_VARS=False; xtr_nbr=0; break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; if(EXCLUDE_INPUT_LIST) (void)fprintf(stderr,"%s: ERROR %s does not currently implement -x option\n",nco_prg_nm_get(),nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Append ";\n" to command-script arguments, then concatenate them */ for(idx=0;idxnm,(sym_tbl[idx]->fnc_flt ? 'y' : 'n'),(sym_tbl[idx]->fnc_dbl ? 'y' : 'n')); nco_exit(EXIT_SUCCESS); } /* end if PRN_FNC_TBL */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Make uniform list of user-specified chunksizes */ cnk_sz_byt+=0; /* CEWI */ if(cnk_nbr > 0) cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Make uniform list of user-specified dimension limits */ if(lmt_nbr > 0) lmt=nco_lmt_prs(lmt_nbr,lmt_arg); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); (void)nco_inq_format(in_id,&fl_in_fmt); /* Form list of all dimensions in file */ dmn_lst=nco_dmn_lst(in_id,&nbr_dmn_in); dmn_in=(dmn_sct **)nco_malloc(nbr_dmn_in*sizeof(dmn_sct *)); for(idx=0;idx 0) (void)nco_dmn_lmt_mrg(dmn_in,nbr_dmn_in,lmt,lmt_nbr); /* Make output and input files consanguinous */ if(fl_out_fmt == NCO_FORMAT_UNDEFINED) fl_out_fmt=fl_in_fmt; /* Verify output file format supports requested actions */ (void)nco_fl_fmt_vet(fl_out_fmt,cnk_nbr,dfl_lvl); /* Open output file */ fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&bfr_sz_hnt,RAM_CREATE,RAM_OPEN,WRT_TMP_FL,&out_id); /* Copy global attributes */ (void)nco_att_cpy(in_id,out_id,NC_GLOBAL,NC_GLOBAL,(nco_bool)True); /* Catenate time-stamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Set arguments for script execution */ prs_arg.fl_in=fl_in; /* [sng] Input data file */ prs_arg.in_id=in_id; /* [id] Input data file ID */ prs_arg.fl_out=fl_out; /* [sng] Output data file */ prs_arg.out_id=out_id; /* [id] Output data file ID */ prs_arg.att_lst=&att_lst; /* [sct] Attributes in script */ prs_arg.nbr_att=&nbr_att; /* [nbr] Number of attributes in script */ prs_arg.dmn_in=dmn_in; /* [dmn_in] List of all dimensions in input */ prs_arg.nbr_dmn_in=nbr_dmn_in; /* [nbr] Number of dimensions in input */ prs_arg.dmn_out=&dmn_out; /* pointer to list of dims in output */ prs_arg.nbr_dmn_out=&nbr_dmn_out; /* number of dims in above list */ prs_arg.sym_tbl=sym_tbl; /* [fnc] Symbol table for functions */ prs_arg.sym_tbl_nbr=sym_tbl_nbr; /* [nbr] Number of functions in table */ /* prs_arg.ntl_scn=False; [flg] Initial scan of script */ prs_arg.var_LHS=NULL; /* [var] LHS cast variable */ prs_arg.var_lst=&var_ycc; /* [sct] Variables to be defined after 1st parse */ prs_arg.nbr_var=&nbr_var_ycc; /* [nbr] Number of vars to be defined after 1st parse */ prs_arg.nco_op_typ=nco_op_nil; /* [enm] Operation type */ prs_arg.dfl_lvl=dfl_lvl; /* [enm] Deflate level */ /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; /* Parse twice: 1st parse defines variable dimensions in output file. 2nd parse initializes variable values */ for(jdx=0;jdx<2;jdx++){ prs_arg.ntl_scn=(jdx==0 ? True : False); if(fl_spt_usr == NULL){ /* No script file specified, look for command-line scripts */ if(nbr_spt == 0){ (void)fprintf(stderr,"%s: ERROR no script file or command line scripts specified\n",nco_prg_nm_get()); (void)fprintf(stderr,"%s: HINT Use, e.g., -s \"foo=bar\"\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ /* Print all command-line scripts */ if(nco_dbg_lvl_get() > nco_dbg_scl){ for(idx=0;idx 0) fl_spt_usr=(char *)nco_free(fl_spt_usr); (void)glb_init_free(False); if(!prs_arg.ntl_scn) continue; (void)nco_redef(out_id); for(idx=0;idx= nco_dbg_var) (void)fprintf(stdout,"%s: Checking var_ycc[%d]->undefined for variable %s...\n",nco_prg_nm_get(),idx,var_ycc[idx]->nm); if(var_ycc[idx]->undefined){ /* 20060225: TODO nco680 free() list at end or risk double-free()'ing*/ var_ycc[idx]=nco_var_free(var_ycc[idx]); continue; } /* endif */ (void)nco_def_var(out_id,var_ycc[idx]->nm,var_ycc[idx]->type,var_ycc[idx]->nbr_dim,var_ycc[idx]->dmn_id,&var_id); /* Set HDF Lempel-Ziv compression level, if requested */ if(dfl_lvl >= 0 && var_ycc[idx]->nbr_dim > 0) (void)nco_def_var_deflate(out_id,var_id,(int)True,(int)True,dfl_lvl); var_ycc[idx]->val.vp=nco_free(var_ycc[idx]->val.vp); } /* end loop over idx */ (void)nco_enddef(out_id); } /* end loop over jdx */ /* Get number of variables in output file */ rcd=nco_inq(out_id,(int *)NULL,&nbr_var_fl,(int *)NULL,(int*)NULL); /* Make list of all new variables in output_file */ xtr_lst_a=nco_var_lst_mk(out_id,nbr_var_fl,var_lst_in,False,False,&nbr_lst_a); if(PROCESS_ALL_VARS){ /* Get number of variables in input file */ rcd=nco_inq(in_id,(int *)NULL,&nbr_var_fl,(int *)NULL,(int *)NULL); /* Form initial list of all variables in input file */ xtr_lst=nco_var_lst_mk(in_id,nbr_var_fl,var_lst_in,False,False,&xtr_nbr); }else{ /* Make list of variables of new attributes whose parent variable is only in input file */ xtr_lst=nco_att_lst_mk(in_id,out_id,att_lst,nbr_att,&xtr_nbr); } /* endif */ /* Find dimensions associated with xtr_lst */ /* Write to O only new dims Add apropriate coordinate variables to extraction list options -c -process all cordinates i.e., add coordinates to var list Also add their dims options --none -process associated co-ords loop though dim_out and append to var list options -C no co-ordinates Do nothing */ /* Subtract list A again */ /* Finally extract variables on list */ /* Subtract list A */ if(nbr_lst_a > 0) xtr_lst=nco_var_lst_sub(xtr_lst,&xtr_nbr,xtr_lst_a,nbr_lst_a); /* Put file in define mode to allow metadata writing */ (void)nco_redef(out_id); /* Free current list of all dimensions in input file */ dmn_lst=nco_nm_id_lst_free(dmn_lst,nbr_dmn_in); /* Make list of dimensions of variables in xtr_lst */ if(xtr_nbr > 0) dmn_lst=nco_dmn_lst_ass_var(in_id,xtr_lst,xtr_nbr,&nbr_dmn_ass); /* Find and add any new dimensions to output */ for(idx=0;idxnm) && !dmn_in[jdx]->xrf){ /* Add dimension to output list dmn_prc */ dmn_new=nco_dmn_out_grow(&prs_arg); *dmn_new=nco_dmn_dpl(dmn_in[jdx]); (void)nco_dmn_xrf(*dmn_new,dmn_in[jdx]); /* Write dimension to output */ (void)nco_dmn_dfn(fl_out,out_id,dmn_new,1); break; } /* endif */ } /* end loop over jdx */ /* Free current list of all dimensions in input file */ dmn_lst=nco_nm_id_lst_free(dmn_lst,nbr_dmn_ass); /* Dimensions for manually specified extracted variables are now defined in output file Add coordinate variables to extraction list If EXTRACT_ALL_COORDINATES then write associated dimension to output */ if(EXTRACT_ASSOCIATED_COORDINATES){ for(idx=0;idxis_crd_dmn) continue; if(EXTRACT_ALL_COORDINATES && !dmn_in[idx]->xrf){ /* Add dimensions to output list dmn_out */ dmn_new=nco_dmn_out_grow(&prs_arg); *dmn_new=nco_dmn_dpl(dmn_in[idx]); (void)nco_dmn_xrf(*dmn_new,dmn_in[idx]); /* Write dimension to output */ (void)nco_dmn_dfn(fl_out,out_id,dmn_new,1); } /* end if */ /* Add coordinate variable to extraction list, dimension has already been output */ if(dmn_in[idx]->xrf){ for(jdx=0;jdxnm)) break; if(jdx != xtr_nbr) continue; /* If coordinate is not on list then add it to extraction list */ xtr_lst=(nm_id_sct *)nco_realloc(xtr_lst,(xtr_nbr+1)*sizeof(nm_id_sct)); xtr_lst[xtr_nbr].nm=(char *)strdup(dmn_in[idx]->nm); xtr_lst[xtr_nbr++].id=dmn_in[idx]->cid; } /* endif */ } /* end loop over idx */ } /* end if */ /* Is this a CCM/CCSM/CF-format history tape? */ CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id); /* Add coordinates defined by CF convention */ if(CNV_CCM_CCSM_CF && (EXTRACT_ALL_COORDINATES || EXTRACT_ASSOCIATED_COORDINATES)) xtr_lst=nco_cnv_cf_crd_add(in_id,xtr_lst,&xtr_nbr); /* Subtract list A again (it may contain re-defined coordinates) */ if(xtr_nbr > 0) xtr_lst=nco_var_lst_sub(xtr_lst,&xtr_nbr,xtr_lst_a,nbr_lst_a); /* Sort extraction list for faster I/O */ if(xtr_nbr > 1) xtr_lst=nco_lst_srt_nm_id(xtr_lst,xtr_nbr,False); /* Write "fixed" variables */ var=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); for(idx=0;idxvar_nm,&var_id); if(rcd != NC_NOERR) continue; att_lst[idx]->mode=aed_overwrite; (void)nco_aed_prc(out_id,var_id,*att_lst[idx]); } /* end for */ /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,(lmt_msa_sct **)NULL_CEWI,(int)0,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ (void)nco_enddef(out_id); /* Copy non-processed vars */ (void)nco_var_val_cpy(in_id,out_id,var_fix,nbr_var_fix); /* Close input netCDF file */ rcd=nco_close(in_id); /* Remove local copy of file */ if(FL_RTR_RMT_LCN && RM_RMT_FL_PST_PRC) (void)nco_fl_rm(fl_in); /* Close output file and move it from temporary to permanent location */ (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* ncap-specific memory */ /* fxm: ncap-specific memory freeing instructions go here */ for(idx=0;idxnm=(char *)nco_free(sym_tbl[idx]->nm); sym_tbl[idx]=(sym_sct *)nco_free(sym_tbl[idx]); } /* end loop */ sym_tbl=(sym_sct **)nco_free(sym_tbl); if(fl_spt_usr) fl_spt_usr=(char *)nco_free(fl_spt_usr); /* Free variable list: some in var_ycc may have been previously free()'d */ /* fxm: TODO nco680 */ if(nbr_var_ycc > 0) var_ycc=nco_var_lst_free(var_ycc,nbr_var_ycc); /* Free attribute list */ for(idx=0;idxatt_nm=(char *)nco_free(att_lst[idx]->att_nm); att_lst[idx]->var_nm=(char *)nco_free(att_lst[idx]->var_nm); att_lst[idx]->val.vp=(void *)nco_free(att_lst[idx]->val.vp); att_lst[idx]=(aed_sct *)nco_free(att_lst[idx]); } /* end loop */ if(nbr_att >0 ) att_lst=(aed_sct **)nco_free(att_lst); /* Free extraction lists */ xtr_lst=nco_nm_id_lst_free(xtr_lst,xtr_nbr); xtr_lst_a=nco_nm_id_lst_free(xtr_lst_a,nbr_lst_a); /* Free command line algebraic arguments, if any */ for(idx=0;idx 0) lmt=nco_lmt_lst_free(lmt,lmt_nbr); /* Free chunking information */ for(idx=0;idx 0) cnk_dmn=nco_cnk_lst_free(cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_in > 0) dmn_in=nco_dmn_lst_free(dmn_in,nbr_dmn_in); if(nbr_dmn_out > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_out); /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); if(xtr_nbr > 0) var_out=nco_var_lst_free(var_out,xtr_nbr); var_prc=(var_sct **)nco_free(var_prc); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix=(var_sct **)nco_free(var_fix); var_fix_out=(var_sct **)nco_free(var_fix_out); } /* !flg_cln */ /* End timer */ ddra_info.tmr_flg=nco_tmr_end; /* [enm] Timer flag */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); if(rcd != NC_NOERR) nco_err_exit(rcd,"main"); nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ void glb_init_free /* [fnc] Initialize and free global variables (line numbers and include stuff) */ (nco_bool action) /* I [flg] Initialize */ { /* Purpose: Initialize and free global variables (line numbers and include stuff) */ if(action){ ncap_ncl_dpt_crr=0UL; ncap_ln_nbr_crr=(size_t *)nco_realloc(ncap_ln_nbr_crr,(ncap_ncl_dpt_crr+1UL)*sizeof(size_t)); ncap_ln_nbr_crr[ncap_ncl_dpt_crr]=1UL; ncap_fl_spt_glb=(char **)nco_realloc(ncap_fl_spt_glb,(ncap_ncl_dpt_crr+1UL)*sizeof(char *)); } /* endif action */ if(!action){ ncap_ncl_dpt_crr=0UL; ncap_ln_nbr_crr=(size_t *)nco_free(ncap_ln_nbr_crr); ncap_fl_spt_glb=(char **)nco_free(ncap_fl_spt_glb); } /* endif not action */ } /* end glb_init_free() */ ./nco-4.4.2/src/nco/nco_aux.h0000644000674300045400000000572212264656661015154 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_aux.h,v 1.33 2014/01/13 03:29:53 pvicente Exp $ */ /* Purpose: Sub-set cell-based grids using auxiliary coordinate variable */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_aux.h" *//* Auxiliary coordinates */ #ifndef NCO_AUX_H #define NCO_AUX_H /* Standard header files */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, printf */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_lmt.h" /* Hyperslab limits */ #include "nco_sng_utl.h" /* String utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ lmt_sct ** nco_aux_evl (int in_id, int aux_nbr, char *aux_arg[], int *lmt_nbr, char *nm_dmn); /* O [sng] Dimension name */ nco_bool nco_find_lat_lon (int ncid, char var_nm_lat[], char var_nm_lon[], char **units, int *lat_id, int *lon_id, nc_type *crd_typ); int nco_get_dmn_info (int ncid, int varid, char dimname[], int *dimid, long *dmn_sz); void nco_aux_prs (const char *bnd_bx_sng, const char *units, float *lon_min, float *lon_max, float *lat_min, float *lat_max); lmt_sct ** /* O [lst] Auxiliary coordinate limits */ nco_aux_evl_trv (const int nc_id, /* I [ID] netCDF file ID */ int aux_nbr, /* I [sng] Number of auxiliary coordinates */ char *aux_arg[], /* I [sng] Auxiliary coordinates */ trv_sct *lat_trv, /* I [sct] "latitude" variable */ trv_sct *lon_trv, /* I [sct] "longitude" variable */ const nc_type crd_typ, /* I [nbr] netCDF type of both "latitude" and "longitude" */ const char * const units, /* I [sng] Units of both "latitude" and "longitude" */ int *aux_lmt_nbr); /* I/O [nbr] Number of coordinate limits */ nco_bool nco_find_lat_lon_trv (const int nc_id, /* I [ID] netCDF file ID */ const trv_sct * const var_trv, /* I [sct] Variable object that contains "standard_name" attribute */ const char * const attr_val, /* I [sng] Attribute value to find ( "latitude" or "longitude" ) */ char **var_nm_fll, /* I/O [sng] Full name of variable that has "latitude" or "longitude" attributes */ int *dmn_id, /* I/O [id] Dimension ID of the diension of "latitude" and "longitude" */ nc_type *crd_typ, /* I/O [enm] netCDF type of both "latitude" and "longitude" */ char units[]); /* I/O [sng] Units of both "latitude" and "longitude" */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_AUX_H */ ./nco-4.4.2/src/nco/nco_mmr.h0000644000674300045400000001406512260451232015131 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_mmr.h,v 1.37 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Memory management */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_mmr.h" *//* Memory management */ #ifndef NCO_MMR_H #define NCO_MMR_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* system/library error diagnostics, errno */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, getenv, exit */ #include /* strcmp() */ #ifdef MACOSX # include /* machine time (needed by Mac OS X for struct rusage) */ #endif /* !MACOSX */ #ifdef HAVE_GETRUSAGE # include /* Resource usage and limits */ #endif /* !HAVE_GETRUSAGE */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif /* !_MSC_VER */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* http://www.cs.tufts.edu/comp/111/assignments/a3/proc.c */ /* Number of fields in /proc/PID/stat output, same as Number of elements of prc_stt_sct structure */ #define PRC_STT_SCT_NBR 42 typedef struct{ /* prc_stt_sct */ int pid; // %d Member 01 char comm[256]; // %s Member 02 char state; // %c Member 03 int ppid; // %d Member 04 int pgrp; // %d Member 05 int session; // %d Member 06 int tty_nr; // %d Member 07 int tpgid; // %d Member 08 unsigned long flags; // %lu Member 09 unsigned long minflt; // %lu Member 10 unsigned long cminflt; // %lu Member 11 unsigned long majflt; // %lu Member 12 unsigned long cmajflt; // %lu Member 13 unsigned long utime; // %lu Member 14 unsigned long stime; // %lu Member 15 long cutime; // %ld Member 16 long cstime; // %ld Member 17 long priority; // %ld Member 18 long nice; // %ld Member 19 long num_threads; // %ld Member 20 long itrealvalue; // %ld Member 21 unsigned long starttime; // %lu Member 22 unsigned long vsize; // %lu Member 23 long rss; // %ld Member 24 unsigned long rlim; // %lu Member 25 unsigned long startcode; // %lu Member 26 unsigned long endcode; // %lu Member 27 unsigned long startstack; // %lu Member 28 unsigned long kstkesp; // %lu Member 29 unsigned long kstkeip; // %lu Member 30 unsigned long signal; // %lu Member 31 unsigned long blocked; // %lu Member 32 unsigned long sigignore; // %lu Member 33 unsigned long sigcatch; // %lu Member 34 unsigned long wchan; // %lu Member 35 unsigned long nswap; // %lu Member 36 unsigned long cnswap; // %lu Member 37 int exit_signal; // %d Member 38 int processor; // %d Member 39 unsigned long rt_priority; // %lu Member 40 unsigned long policy; // %lu Member 41 unsigned long long delayacct_blkio_ticks; // %llu Member 42 } prc_stt_sct; /* Number of fields in /proc/PID/statm output, same as Number of elements of prc_stm_sct structure */ #define PRC_STM_SCT_NBR 7 typedef struct{ /* prc_stm_sct */ unsigned long size; // %lu Member 1 unsigned long resident; // %lu Member 2 unsigned long share; // %lu Member 3 unsigned long text; // %lu Member 4 unsigned long lib;// %lu Member 5 unsigned long data; // %lu Member 6 unsigned long dt; // %lu Member 7 } prc_stm_sct; int /* Return code */ nco_prc_stt_get /* [fnc] Read /proc/PID/stat */ (const int pid, /* [enm] Process ID to read */ prc_stt_sct *prc_stt); /* [sct] Structure to hold results */ int /* Return code */ nco_prc_stm_get /* [fnc] Read /proc/PID/statm */ (const int pid, /* [enm] Process ID to read */ prc_stm_sct *prc_stm); /* [sct] Structure to hold results */ void * /* O [ptr] Pointer to calloc'd memory */ nco_calloc /* [fnc] Wrapper for calloc() */ (const size_t lmn_nbr, /* I [nbr] Number of elements to allocate */ const size_t lmn_sz); /* I [nbr] Size of each element */ void * /* O [ptr] Buffer after free'ing */ nco_free /* [fnc] Wrapper for free() */ (void *vp); /* I/O [ptr] Buffer to free() */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc /* [fnc] Wrapper for malloc() */ (const size_t size); /* I [B] Bytes to allocate */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc_flg /* [fnc] Wrapper for malloc(), forgives ENOMEM errors */ (const size_t size); /* I [B] Bytes to allocate */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc_dbg /* [fnc] Wrapper for malloc(), receives and prints more diagnostics */ (const size_t sz, /* I [B] Bytes to allocate */ const char *fnc_nm, /* I [sng] Function name */ const char *msg); /* I [sng] Supplemental error message */ void nco_malloc_err_hnt_prn /* [fnc] Explain meaning and workarounds for malloc() failures */ (void); long /* O [B] Maximum resident set size */ nco_mmr_usg_prn /* [fnc] Print rusage memory usage statistics */ (const int rusage_who); /* [enm] RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_LWP */ long /* O [nbr] Net memory currently allocated */ nco_mmr_stt /* [fnc] Track memory statistics */ (const nco_mmr_typ_enm nco_mmr_typ, /* I [enm] Memory allocation type */ const size_t sz); /* I [B] Bytes allocated, deallocated, or reallocated */ const char * /* O [sng] String describing memory type */ nco_mmr_typ_sng /* [fnc] Convert NCO memory management type enum to string */ (const nco_mmr_typ_enm nco_mmr_typ); /* I [enm] NCO memory management type */ void * /* O [ptr] Pointer to re-allocated memory */ nco_realloc /* [fnc] Wrapper for realloc() */ (void *ptr, /* I/O [ptr] Buffer to reallocate */ const size_t size); /* I [B] Bytes required */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_MMR_H */ ./nco-4.4.2/src/nco/nco_omp.c0000644000674300045400000002777212301227244015135 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_omp.c,v 1.69 2014/02/19 22:22:28 zender Exp $ */ /* Purpose: OpenMP utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_omp.h" /* OpenMP utilities */ #ifndef _OPENMP /* OpenMP is not available with this compiler Declare harmless stub routines for Uni-Processor (UP) code These stubs reduce pre-processor proliferation */ int omp_get_dynamic(void){return 0;} int omp_get_max_threads(void){return 1;} int omp_get_nested(void){return 0;} int omp_get_num_procs(void){return 1;} int omp_get_num_threads(void){return 1;} int omp_get_thread_num(void){return 0;} int omp_in_parallel(void){return 0;} /* Fake work code in these functions to avoid C++ warnings, i.e., CEWI */ void omp_set_dynamic(int dynamic_threads){int foo=0;dynamic_threads+=foo;} void omp_set_nested(int nested){int foo=0;nested+=foo;} void omp_set_num_threads(int num_threads){int foo=0;num_threads+=foo;} #endif /* _OPENMP */ int /* O [nbr] Thread number */ nco_openmp_ini /* [fnc] Initialize OpenMP threading environment */ (const int thr_nbr) /* I [nbr] User-requested thread number */ { /* Purpose: Initialize OpenMP multi-threading environment Honor user-requested thread number, balance against known code efficiency, print diagnostics Returns thr_nbr=1 in three situations: 1. UP codes (not threaded) 2. SMP codes compiled with compilers which lack OpenMP support 3. SMP codes where single thread requested/advised Otherwise returns system-dependent thr_nbr */ /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ char *nvr_OMP_NUM_THREADS; /* [sng] Environment variable OMP_NUM_THREADS */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ nco_bool USR_SPC_THR_RQS=False; int dyn_thr=1; /* [flg] Allow system to dynamically set number of threads */ int ntg_OMP_NUM_THREADS=int_CEWI; // [nbr] OMP_NUM_THREADS environment variable int prc_nbr_max; /* [nbr] Maximum number of processors available */ int thr_nbr_act; /* O [nbr] Number of threads NCO uses */ int thr_nbr_max_fsh=4; /* [nbr] Maximum number of threads program can use efficiently */ int thr_nbr_max=int_CEWI; /* [nbr] Maximum number of threads system allows */ int thr_nbr_rqs=int_CEWI; /* [nbr] Number of threads to request */ #ifndef _OPENMP if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO Build compiler lacked (or user turned off) OpenMP support. Code will execute with single thread in Uni-Processor (UP) mode.\n",nco_prg_nm_get()); return (int)1; #endif /* !_OPENMP */ /* Strategy: 0. Determine maximum number of threads system will allocate (thr_nbr_max) 1. Command-line thread request, if any, overrides automatic algorithm 2. If no command-line request then system allocates OMP_NUM_THREADS if possible 3. Reduce maximum number of threads available to system to thr_nbr_max_fsh Many operators cannot use more than thr_nbr_max_fsh ~ 2--4 threads efficiently Play nice: Set dynamic threading so that system can make efficiency decisions When dynamic threads are set, system never allocates more than thr_nbr_max_fsh */ if(thr_nbr < 0){ (void)fprintf(fp_stderr,"%s: ERROR User-requested thread number = %d is less than zero\n",nco_prg_nm_get(),thr_nbr); nco_exit(EXIT_FAILURE); } /* endif err */ if(thr_nbr == 0) if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(fp_stderr,"%s: INFO User did not specify thread request > 0 on command line. NCO will automatically assign threads based on OMP_NUM_THREADS environment and machine capabilities.\nHINT: Not specifiying any --thr_nbr (or specifying --thr_nbr=0) causes NCO to try to pick the optimal thread number. Specifying --thr_nbr=1 tells NCO to execute in Uni-Processor (UP) (i.e., single-threaded) mode.\n",nco_prg_nm_get()); if(thr_nbr > 0) USR_SPC_THR_RQS=True; prc_nbr_max=omp_get_num_procs(); /* [nbr] Maximum number of processors available */ if(omp_in_parallel()){ (void)fprintf(fp_stderr,"%s: ERROR Attempted to get maximum thread number from within parallel region\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); }else{ thr_nbr_max=omp_get_max_threads(); /* [nbr] Maximum number of threads system allows */ } /* end error */ if(nco_dbg_lvl_get() >= nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ if((nvr_OMP_NUM_THREADS=getenv("OMP_NUM_THREADS"))) ntg_OMP_NUM_THREADS=(int)strtol(nvr_OMP_NUM_THREADS,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); /* [sng] Environment variable OMP_NUM_THREADS */ if(nvr_OMP_NUM_THREADS && *sng_cnv_rcd) nco_sng_cnv_err(nvr_OMP_NUM_THREADS,"strtol",sng_cnv_rcd); (void)fprintf(fp_stderr,"%s: INFO Environment variable OMP_NUM_THREADS ",nco_prg_nm_get()); if(ntg_OMP_NUM_THREADS > 0) (void)fprintf(fp_stderr,"= %d\n",ntg_OMP_NUM_THREADS); else (void)fprintf(fp_stderr,"does not exist\n"); (void)fprintf(fp_stderr,"%s: INFO Number of processors available is %d\n",nco_prg_nm_get(),prc_nbr_max); (void)fprintf(fp_stderr,"%s: INFO Maximum number of threads system allows is %d\n",nco_prg_nm_get(),thr_nbr_max); } /* endif dbg */ if(USR_SPC_THR_RQS){ /* Always try to honor user-specified thread request... */ thr_nbr_rqs=thr_nbr; /* [nbr] Number of threads to request */ /* ...if possible... */ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(fp_stderr,"%s: INFO User command-line-requested %d thread%s\n",nco_prg_nm_get(),thr_nbr,(thr_nbr > 1) ? "s" : ""); if(thr_nbr > thr_nbr_max){ (void)fprintf(fp_stderr,"%s: WARNING Reducing user-requested thread number = %d to maximum thread number allowed = %d\n",nco_prg_nm_get(),thr_nbr,thr_nbr_max); thr_nbr_rqs=thr_nbr_max; /* [nbr] Number of threads to request */ } /* endif */ }else{ /* !USR_SPC_THR_RQS */ /* Otherwise use automatic thread allocation algorithm */ /* Request maximum number of threads permitted */ thr_nbr_rqs=thr_nbr_max; /* [nbr] Number of threads to request */ /* Restrict threading on per-program basis to play nicely with others */ switch(nco_prg_id_get()){ /* Operators with pre-set thread limit NB: All operators currently have default restrictions Only ncwa and ncap2 have a chance to scale on non-parallel filesystems ncap2 may, one day, see a big performance boost from threading However, as of 20090327, ncap2 threading may be buggy due to ANTLR Moreover, we want to prevent hogging processes on 32-way nodes until/unless clear benefits of threading are demonstrated. */ case ncap: /* 20090327: Restrict ncap2 to one thread until ANTLR threading resolved */ thr_nbr_max_fsh=1; break; case ncecat: case ncrcat: /* ncecat and ncrcat are extremely I/O intensive Maximum efficiency when one thread reads from input file while other writes to output file */ // 20140219: Turn-off OpenMP until thoroughly tested // thr_nbr_max_fsh=2; thr_nbr_max_fsh=1; break; /* Operators with higher maximum pre-set thread limit (NB: not all of these are threaded!) */ case ncbo: case ncatted: case ncfe: case ncflint: case ncks: case ncpdq: case ncra: case ncrename: case ncwa: case ncge: // 20140219: Turn-off OpenMP until thoroughly tested // thr_nbr_max_fsh=4; thr_nbr_max_fsh=1; break; default: nco_dfl_case_prg_id_err(); break; } /* end case */ /* Automatic algorithm tries to play nice with others */ (void)omp_set_dynamic(dyn_thr); /* [flg] Allow system to dynamically set number of threads */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO %s OS to dynamically set threads\n",nco_prg_nm_get(),(dyn_thr ? "Allowing" : "Not allowing")); dyn_thr=omp_get_dynamic(); /* [flg] Allow system to dynamically set number of threads */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO System will%s utilize dynamic threading\n",nco_prg_nm_get(),(dyn_thr ? "" : " not")); /* Apply program/system limitations */ if(thr_nbr_max > thr_nbr_max_fsh){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO Reducing default thread number from %d to %d, an operator-dependent \"play-nice\" number set in nco_openmp_ini()\n",nco_prg_nm_get(),thr_nbr_max,thr_nbr_max_fsh); thr_nbr_rqs=thr_nbr_max_fsh; /* [nbr] Number of threads to request */ } /* endif */ } /* !USR_SPC_THR_RQS */ #ifdef ENABLE_NETCDF4 if(thr_nbr_rqs > 1){ if(USR_SPC_THR_RQS && nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stdout,"%s: WARNING This is TODO nco939. Requested threading with netCDF4 (HDF5) support. The NCO thread request algorithm considers user-input, environment variables, and software and hardware limitations in determining the number of threads to request, thr_nbr_rqs. At this point NCO would request result %d threads from a netCDF3-based library. However, this NCO was built with netCDF4, which relies on HDF5. netCDF4 is not thread-safe unless HDF5 is configured with the (non-default) --enable-threadsafe option. NCO currently has no way to know whether HDF5 was built thread-safe. Hence, all netCDF4-based operators are currently restricted to a single thread. The program will now automatically set thr_nbr_rqs = 1.\nThis unfortunate limitation is necessary to keep the NCO developers sane. If you want/need threading in netCDF4-based NCO, please politely yet firmly request of the Unidata netCDF developers that better thread support be built into netCDF4, and request of the HDF5 developers that they make the --enable-threadsafe option compatible with all HDF5 libraries and APIs, including Fortran (which, as of HDF5 1.8.0 in 2008, is incompatible with --enable-threadsafe).\n",nco_prg_nm_get(),thr_nbr_rqs); thr_nbr_rqs=1; } /* endif */ #endif /* !ENABLE_NETCDF4 */ /* Set thread number */ if(omp_in_parallel()){ (void)fprintf(fp_stderr,"%s: ERROR Attempted to set thread number from within parallel region\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); }else{ (void)omp_set_num_threads(thr_nbr_rqs); if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO omp_set_num_threads() used to set execution environment to spawn teams of %d threads\n",nco_prg_nm_get(),thr_nbr_rqs); } /* end error */ thr_nbr_act=omp_get_max_threads(); if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(fp_stderr,"%s: INFO After using omp_set_num_threads() to adjust for any user requests/NCO optimizations, omp_get_max_threads() reports that a parallel construct here/now would spawn %d threads\n",nco_prg_nm_get(),thr_nbr_act); #ifdef _OPENMP if(nco_dbg_lvl_get() >= nco_dbg_scl){ #pragma omp parallel default(none) shared(thr_nbr_act) { /* begin OpenMP parallel */ #pragma omp single nowait { /* begin OpenMP single */ thr_nbr_act=omp_get_num_threads(); /* [nbr] Number of threads NCO uses */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO Small parallel test region spawned team of %d threads\n",nco_prg_nm_get(),thr_nbr_act); } /* end OpenMP single */ } /* end OpenMP parallel */ } /* end dbg */ #endif /* !_OPENMP */ return thr_nbr_act; /* O [nbr] Number of threads NCO uses */ } /* end nco_openmp_ini() */ int /* O [enm] Return code */ nco_var_prc_crr_prn /* [fnc] Print name of current variable */ (const int idx, /* I [idx] Index of current variable */ const char * const var_nm) /* I [sng] Variable name */ { /* Purpose: Print name of current variable */ int rcd=0; /* [rcd] Return code */ #ifdef _OPENMP (void)fprintf(stderr,"%s: INFO main loop thread #%d processing var_prc[%d] = \"%s\"\n",nco_prg_nm_get(),omp_get_thread_num(),idx,var_nm); #else /* !_OPENMP */ rcd+=idx*0; /* CEWI */ (void)fprintf(stderr,"%s: INFO main loop processing var_prc[%d] = \"%s\"\n",nco_prg_nm_get(),idx,var_nm); #endif /* !_OPENMP */ return rcd; } /* end nco_var_prc_crr_prn() */ ./nco-4.4.2/src/nco/nco_mmr.c0000644000674300045400000007330712260451232015130 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_mmr.c,v 1.64 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Memory management */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage of NCO memory allocation routines nco_malloc(), nco_malloc_flg(), and nco_malloc_dbg(): nco_malloc(): Use this for small memory requests nco_malloc() dies and exits with generic malloc() error for all error conditions nco_malloc() plug-in replacements are malloc() and nco_malloc_flg() nco_malloc_flg(): Use this for large memory requests when it is useful for calling routine to handle ENOMEM errors (e.g., calling routine has important debug information). nco_malloc_flg() dies and exits with generic malloc() error unless error is ENOMEM nco_malloc_flg() prints warning for ENOMEM errors, then returns control to calling routine nco_malloc_flg() plug-in replacements are malloc() and nco_malloc() nco_malloc_dbg(): Use this for large memory requests when calling routine supplies its name and useful supplemental error message nco_malloc_dbg() prints name of calling function, supplemental error message, and then dies and exits for all error conditions. nco_malloc_dbg() has no plug-in replacements (since it requires two extra arguments) None of these routines call malloc() when sz == 0 */ #include "nco_mmr.h" /* Memory management */ void * /* O [ptr] Pointer to calloc'd memory */ nco_calloc /* [fnc] Wrapper for calloc() */ (const size_t lmn_nbr, /* I [nbr] Number of elements to allocate */ const size_t lmn_sz) /* I [nbr] Size of each element */ { /* Purpose: Custom wrapper for calloc(), modified from nco_malloc() Routine prints error when calloc() returns a NULL pointer Routine does not call calloc() when lmn_sz == 0 or lmn_nbr == 0 */ void *ptr; /* [ptr] Pointer to new buffer */ /* Circumvent calloc() calls when lmn_sz == 0 */ if(lmn_sz == 0 || lmn_nbr == 0) return NULL; ptr=calloc(lmn_nbr,lmn_sz); /* [ptr] Pointer to new buffer */ if(ptr == NULL){ (void)fprintf(stdout,"%s: ERROR nco_calloc() unable to allocate %lu elements of %lu bytes each totaling %lu B = %lu kB = %lu MB = %lu GB\n",nco_prg_nm_get(),(unsigned long)lmn_nbr,(unsigned long)lmn_sz,(unsigned long)(lmn_nbr*lmn_sz),(unsigned long)(lmn_nbr*lmn_sz)/NCO_BYT_PER_KB,(unsigned long)(lmn_nbr*lmn_sz)/NCO_BYT_PER_MB,(unsigned long)(lmn_nbr*lmn_sz)/NCO_BYT_PER_GB); nco_exit(EXIT_FAILURE); } /* endif */ #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_calloc,lmn_nbr*lmn_sz); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return ptr; /* [ptr] Pointer to new buffer */ } /* nco_calloc() */ void * /* O [ptr] Buffer after free'ing */ nco_free /* [fnc] Wrapper for free() */ (void *vp) /* I/O [ptr] Buffer to free() */ { /* Purpose: Custom wrapper for free() Free memory and set pointer to NULL Routine does not call free() when vp == NULL Usage: vp=nco_free(vp) */ if(vp) free(vp); #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_free,(size_t)0L); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return NULL; /* [ptr] Pointer to new buffer */ } /* nco_free() */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc /* [fnc] Wrapper for malloc() */ (const size_t sz) /* I [B] Bytes to allocate */ { /* Purpose: Custom plugin wrapper for malloc() Top of nco_mmr.c explains usage of nco_malloc(), nco_malloc_flg(), and nco_malloc_dbg() Test memory debugging infrastructure with, e.g., export NCO_MMR_DBG=1;nces -O -D 3 -d time,0,2 -p ~ big_bug5.nc ~/big_avg.nc export NCO_MMR_DBG=1;ncrcat -O -D 3 -p ~ big_bug.nc big_bug.nc big_bug.nc big_bug.nc big_bug.nc ~/big_bug5.nc fxm: Infrastucture does not (yet) report requests made with nco_malloc_flg() and nco_malloc_dbg() */ const char fnc_nm[]="nco_malloc()"; /* [sng] Function name */ char *nvr_NCO_MMR_DBG; /* [sng] Environment variable NCO_MMR_DBG */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ int ntg_NCO_MMR_DBG=int_CEWI; // [nbr] NCO_MMR_DBG environment variable size_t sz_thr=1024UL*1024UL; /* I [B] Bytes to allocate threshold size for reporting */ size_t sz_max=(size_t)-1; /* I [B] Maximum value of size_t */ void *ptr; /* [ptr] Pointer to new buffer */ /* malloc(0) is ANSI-legal, albeit unnecessary NCO sometimes employs this degenerate case behavior of malloc() to simplify code Some debugging tools like Electric Fence consider any NULL returned by malloc() to be an error So circumvent malloc() calls when sz == 0 */ if(sz == 0) return NULL; /* Only poll memory if debug level set otherwise getenv() would be called on every nco_malloc() reading */ if(nco_dbg_lvl_get() >= nco_dbg_scl){ if((nvr_NCO_MMR_DBG=getenv("NCO_MMR_DBG"))) ntg_NCO_MMR_DBG=(int)strtol(nvr_NCO_MMR_DBG,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); /* [sng] Environment variable NCO_MMR_DBG */ } /* endif dbg */ if(ntg_NCO_MMR_DBG && sz > sz_thr) (void)fprintf(stdout,"%s: INFO %s received request to allocate %zu B = %zu kB = %zu MB = %zu GB\n",nco_prg_nm_get(),fnc_nm,sz,sz/NCO_BYT_PER_KB,sz/NCO_BYT_PER_MB,sz/NCO_BYT_PER_GB); if(sz > sz_max) (void)fprintf(stdout,"%s: WARNING %s received request to allocate %zu B = %zu kB = %zu MB = %zu GB = %zu TB\n",nco_prg_nm_get(),fnc_nm,sz,sz/NCO_BYT_PER_KB,sz/NCO_BYT_PER_MB,sz/NCO_BYT_PER_GB,sz/NCO_BYT_PER_TB); ptr=malloc(sz); /* [ptr] Pointer to new buffer */ if(ptr == NULL){ (void)fprintf(stdout,"%s: ERROR %s unable to allocate %zu B = %zu kB = %zu MB = %zu GB\n",nco_prg_nm_get(),fnc_nm,sz,sz/NCO_BYT_PER_KB,sz/NCO_BYT_PER_MB,sz/NCO_BYT_PER_GB); (void)nco_malloc_err_hnt_prn(); /* fxm: Should be exit(8) on ENOMEM errors? */ nco_exit(EXIT_FAILURE); } /* endif */ #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_malloc,sz); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return ptr; /* [ptr] Pointer to new buffer */ } /* nco_malloc() */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc_flg /* [fnc] Wrapper for malloc(), forgives ENOMEM errors */ (const size_t sz) /* I [B] Bytes to allocate */ { /* Purpose: Custom plugin wrapper for malloc() that allows ENOMEM errors Top of nco_mmr.c explains usage of nco_malloc(), nco_malloc_flg(), and nco_malloc_dbg() */ #ifndef __GNUG__ extern int errno; /* [enm] Error code in errno.h */ #endif /* __GNUG__ */ void *ptr; /* [ptr] Pointer to new buffer */ /* malloc(0) is ANSI-legal, albeit unnecessary NCO sometimes employs this degenerate case behavior of malloc() to simplify code Some debugging tools like Electric Fence consider any NULL returned by malloc() to be an error So circumvent malloc() calls when sz == 0 */ if(sz == 0) return NULL; ptr=malloc(sz); /* [ptr] Pointer to new buffer */ if(ptr == NULL){ (void)fprintf(stdout,"%s: ERROR nco_malloc_flg() unable to allocate %lu B = %lu kB = %lu MB = %lu GB\n",nco_prg_nm_get(),(unsigned long)sz,(unsigned long)sz/NCO_BYT_PER_KB,(unsigned long)sz/NCO_BYT_PER_MB,(unsigned long)sz/NCO_BYT_PER_GB); #ifndef __GNUG__ /* 20051205: Triggers G++ error: undefined reference to `__errno_location()' */ (void)fprintf(stdout,"%s: malloc() error is \"%s\"\n",nco_prg_nm_get(),strerror(errno)); if(errno == ENOMEM) return NULL; /* Unlike nco_malloc(), allow simple OOM errors */ #else return NULL; /* Unlike nco_malloc(), allow simple OOM errors */ #endif /* __GNUG__ */ (void)fprintf(stdout,"%s: ERROR is not ENOMEM, exiting...\n",nco_prg_nm_get()); (void)nco_malloc_err_hnt_prn(); nco_exit(EXIT_FAILURE); } /* endif */ #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_malloc,sz); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return ptr; /* [ptr] Pointer to new buffer */ } /* nco_malloc_flg() */ void * /* O [ptr] Pointer to allocated memory */ nco_malloc_dbg /* [fnc] Wrapper for malloc(), receives and prints more diagnostics */ (const size_t sz, /* I [B] Bytes to allocate */ const char *fnc_nm, /* I [sng] Function name */ const char *msg) /* I [sng] Supplemental error message */ { /* Purpose: Custom wrapper for malloc(), non-plugin, receives and prints more diagnostics Top of nco_mmr.c explains usage of nco_malloc(), nco_malloc_flg(), and nco_malloc_dbg() */ #ifndef __GNUG__ extern int errno; /* [enm] Error code in errno.h */ #endif /* __GNUG__ */ void *ptr; /* [ptr] Pointer to new buffer */ /* malloc(0) is ANSI-legal, albeit unnecessary NCO sometimes employs this degenerate case behavior of malloc() to simplify code Some debugging tools like Electric Fence consider any NULL returned by malloc() to be an error So circumvent malloc() calls when sz == 0 */ if(sz == 0) return NULL; ptr=malloc(sz); /* [ptr] Pointer to new buffer */ if(ptr == NULL){ (void)fprintf(stdout,"%s: ERROR malloc() returns error on %s request for %lu B = %lu kB = %lu MB = %lu GB\n",nco_prg_nm_get(),fnc_nm,(unsigned long)sz,(unsigned long)sz/NCO_BYT_PER_KB,(unsigned long)sz/NCO_BYT_PER_MB,(unsigned long)sz/NCO_BYT_PER_GB); #ifndef __GNUG__ /* 20051205: Triggers G++ error: undefined reference to `__errno_location()' */ (void)fprintf(stdout,"%s: malloc() error is \"%s\"\n",nco_prg_nm_get(),strerror(errno)); #endif /* __GNUG__ */ (void)fprintf(stdout,"%s: User-supplied supplemental error message is \"%s\"\n",nco_prg_nm_get(),msg); (void)nco_malloc_err_hnt_prn(); nco_exit(EXIT_FAILURE); } /* endif */ #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_malloc,sz); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return ptr; /* [ptr] Pointer to new buffer */ } /* nco_malloc_dbg() */ void nco_malloc_err_hnt_prn /* [fnc] Explain meaning and workarounds for malloc() failures */ (void) { /* Purpose: Explain meaning and workarounds for malloc() failures */ (void)fprintf(stdout,"%s: INFO NCO has reported a malloc() failure. malloc() failures usually indicate that your machine does not have enough free memory (RAM+swap) to perform the requested operation. As such, malloc() failures result from the physical limitations imposed by your hardware. Read http://nco.sf.net/nco.html#mmr for a description of NCO memory usage. The likiest case is that this problem is caused by inadequate RAM on your system, and is not an NCO bug. If so, there are two potential workarounds: First is to process your data in smaller chunks, e.g., smaller or more hyperslabs. The second is to use a machine with more free memory, so that malloc() succeeds.\n\nLarge tasks may uncover memory leaks in NCO. This is likeliest to occur with ncap2. ncap2 scripts are completely dynamic and may be of arbitrary length and complexity. A script that contains many thousands of operations may uncover a slow memory leak even though each single operation consumes little additional memory. Memory leaks are usually identifiable by their memory usage signature. Leaks cause peak memory usage to increase monotonically with time regardless of script complexity. Slow leaks are very difficult to find. Sometimes a malloc() failure is the only noticeable clue to their existance. If you have good reasons to believe that your malloc() failure is ultimately due to an NCO memory leak (rather than inadequate RAM on your system), then we would like to receive a detailed bug report.",nco_prg_nm_get()); } /* nco_malloc_err_hnt_prn() */ /* fxm: when are const qualifiers on return values legal? is this a GNUism? */ const char * /* O [sng] String describing memory type */ nco_mmr_typ_sng /* [fnc] Convert NCO memory management type enum to string */ (const nco_mmr_typ_enm nco_mmr_typ) /* I [enm] NCO memory management type */ { /* Purpose: Return name of memory function invoked */ switch(nco_mmr_typ){ case nco_mmr_calloc: return "nco_mmr_calloc"; case nco_mmr_free: return "nco_mmr_free"; case nco_mmr_malloc: return "nco_mmr_malloc"; case nco_mmr_realloc: return "nco_mmr_realloc"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* fxm: any advantage to this form? defining with file scope in header? static const char * const nco_mmr_calloc_sng="nco_mmr_calloc_sng"; static const char * const nco_mmr_free_sng="nco_mmr_free_sng"; static const char * const nco_mmr_malloc_sng="nco_mmr_malloc_sng"; static const char * const nco_mmr_realloc_sng="nco_mmr_realloc_sng"; switch(nco_mmr_typ){ case nco_mmr_calloc: return nco_mmr_calloc_sng; case nco_mmr_free: return nco_mmr_free_sng; case nco_mmr_malloc: return nco_mmr_malloc_sng; case nco_mmr_realloc: return nco_mmr_realloc_sng; default: nco_dfl_case_nc_type_err(); break; } *//* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_mmr_typ_sng() */ void * /* O [ptr] Pointer to re-allocated memory */ nco_realloc /* [fnc] Wrapper for realloc() */ (void *ptr, /* I/O [ptr] Buffer to reallocate */ const size_t sz) /* I [B] Bytes required */ { /* Purpose: Custom wrapper for realloc() Routine prints error when realloc() returns a NULL pointer Routine does not call realloc() when sz == 0 */ void *new_ptr; /* [ptr] Pointer to new buffer */ /* This degenerate case sometimes occurs Performing realloc() call here would be ANSI-legal but would trigger Electric Fence */ if(ptr == NULL && sz == 0) return ptr; if(ptr && sz == 0){ ptr=nco_free(ptr); ptr=NULL; return ptr; } /* endif */ /* Passing NULL to realloc() is ANSI-legal, but may cause portability problems */ if(ptr == NULL && sz != 0){ new_ptr=nco_malloc(sz); /* [ptr] Pointer to new buffer */ }else{ new_ptr=realloc(ptr,sz); /* [ptr] Pointer to new buffer */ } /* endif */ if(new_ptr == NULL && sz != 0){ (void)fprintf(stdout,"%s: ERROR nco_realloc() unable to realloc() %lu bytes\n",nco_prg_nm_get(),(unsigned long)sz); /* fxm: Should be exit(8) on ENOMEM errors? */ nco_exit(EXIT_FAILURE); } /* endif */ #ifdef NCO_MMR_STT (void)nco_mmr_stt(nco_mmr_realloc,sz); /* fxm dbg */ #endif /* !NCO_MMR_STT */ return new_ptr; /* [ptr] Pointer to new buffer */ } /* nco_realloc() */ long /* O [nbr] Net memory currently allocated */ nco_mmr_stt /* [fnc] Track memory statistics */ (const nco_mmr_typ_enm nco_mmr_typ, /* I [enm] Memory management type */ const size_t sz) /* I [B] Bytes allocated, deallocated, or reallocated */ { /* Purpose: Track memory statistics 20130618: Maing problem with this is the nco_free() and nco_realloc() do not provide sufficent information to adjust the total. Workarounds are to poll /proc/self/stat here, or to modify nco_free() and nco_realloc() to optionally propagate net memory used or freed. */ static long mll_nbr=0L; /* [nbr] Number of malloc() invocations */ static long fre_nbr=0L; /* [nbr] Number of free() invocations */ static long mmr_mll_ttl=0L; /* [B] Total memory malloc()'d */ static long mmr_fre_ttl=0L; /* [B] Total memory free()'d */ static long mmr_net_crr=0L; /* [B] Net memory currently allocated */ long sz_lng; /* [B] Bytes allocated, deallocated, or reallocated, long */ sz_lng=(long)sz; /* [B] Bytes allocated, deallocated, or reallocated */ switch(nco_mmr_typ){ case nco_mmr_calloc: mll_nbr++; /* [nbr] Number of malloc() invocations */ mmr_mll_ttl+=sz_lng; /* [B] Total memory malloc()'d */ mmr_net_crr+=sz_lng; /* [B] Net memory currently allocated */ break; case nco_mmr_free: fre_nbr++; /* [nbr] Number of free() invocations */ mmr_fre_ttl-=sz_lng; /* [B] Total memory free()'d */ mmr_net_crr-=sz_lng; /* [B] Net memory currently allocated */ break; case nco_mmr_malloc: mll_nbr++; /* [nbr] Number of malloc() invocations */ mmr_mll_ttl+=sz_lng; /* [B] Total memory malloc()'d */ mmr_net_crr+=sz_lng; /* [B] Net memory currently allocated */ break; case nco_mmr_realloc: mll_nbr++; /* [nbr] Number of malloc() invocations */ mmr_mll_ttl+=sz_lng; /* [B] Total memory malloc()'d */ mmr_net_crr+=sz_lng; /* [B] Net memory currently allocated */ break; default: nco_exit(EXIT_FAILURE); break; } /* end case */ if(True){ (void)fprintf(stdout,"%s: INFO nco_mmr_stt() called by %s(): fre_nbr=%li, mll_nbr=%li, mmr_mll_ttl=%li, mmr_fre_ttl=%li, mmr_net_crr=%li bytes\n",nco_prg_nm_get(),nco_mmr_typ_sng(nco_mmr_typ),fre_nbr,mll_nbr,mmr_mll_ttl,mmr_fre_ttl,mmr_net_crr); } /* endif */ return mmr_net_crr; /* [B] Net memory currently allocated */ } /* nco_mmr_stt() */ int /* Return code */ nco_prc_stt_get /* [fnc] Read /proc/PID/stat */ (const int pid, /* [enm] Process ID to read */ prc_stt_sct *prc_stt) /* [sct] Structure to hold results */ { /* Purpose: Decode output of /proc/PID/stat, place in structure, and optionally print out */ /* 201306: Unfortunately, format of /proc/self/stat is system-dependent Contents of /proc/self/stat defined in man 5 proc Have found _slightly_ different scanf() formats for fields looking at different Linux documentation Definitive answer seems to examining contents of /usr/src/linux/fs/proc/array.c:do_task_stat() Fully documented sources at http://www.cs.tufts.edu/comp/111/assignments/a3/proc.c */ const char fnc_nm[]="nco_prc_stt_get()"; /* [sng] Function name */ char fl_slf[]="/proc/self/stat"; /* [sng] Process status pseudo-file name */ char fl_pid[256]; /* [sng] Process status pseudo-file name */ char *fl_prc; /* [sng] Process status pseudo-file name */ const char *prc_stt_fmt="%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu"; const char *prc_stt_fmt_out="pid = %d, comm = %s, state = %c, ppid = %d, pgrp = %d, session = %d, tty_nr = %d, tpgid = %d, flags = %lu, minflt = %lu, cminflt = %lu, majflt = %lu, cmajflt = %lu, utime = %lu, stime = %lu, cutime = %ld, cstime = %ld, priority = %ld, nice = %ld, num_threads = %ld, itrealvalue = %ld, starttime = %lu, vsize = %lu, rss = %ld, rlim = %lu, startcode = %lu, endcode = %lu, startstack = %lu, kstkesp = %lu, kstkeip = %lu, signal = %lu, blocked = %lu, sigignore = %lu, sigcatch = %lu, wchan = %lu, nswap = %lu, cnswap = %lu, exit_signal = %d, processor = %d, rt_priority = %lu, policy = %lu, delayacct_blkio_ticks = %llu\n"; FILE *fp_prc=NULL; /* [fl] Process status file handle */ int rcd_sys; if(pid) (void)sprintf(fl_pid,"/proc/%d/stat",pid); if(pid) fl_prc=fl_pid; else fl_prc=fl_slf; fp_prc=fopen(fl_prc,"r"); /* Unable to open fp_prc */ if(!fp_prc) return NCO_ERR; rcd_sys=fscanf (fp_prc, prc_stt_fmt, &prc_stt->pid, prc_stt->comm, &prc_stt->state, &prc_stt->ppid, &prc_stt->pgrp, &prc_stt->session, &prc_stt->tty_nr, &prc_stt->tpgid, &prc_stt->flags, &prc_stt->minflt, &prc_stt->cminflt, &prc_stt->majflt, &prc_stt->cmajflt, &prc_stt->utime, &prc_stt->stime, &prc_stt->cutime, &prc_stt->cstime, &prc_stt->priority, &prc_stt->nice, &prc_stt->num_threads, &prc_stt->itrealvalue, &prc_stt->starttime, &prc_stt->vsize, &prc_stt->rss, &prc_stt->rlim, &prc_stt->startcode, &prc_stt->endcode, &prc_stt->startstack, &prc_stt->kstkesp, &prc_stt->kstkeip, &prc_stt->signal, &prc_stt->blocked, &prc_stt->sigignore, &prc_stt->sigcatch, &prc_stt->wchan, &prc_stt->nswap, &prc_stt->cnswap, &prc_stt->exit_signal, &prc_stt->processor, &prc_stt->rt_priority, &prc_stt->policy, &prc_stt->delayacct_blkio_ticks); /* Were expected number of fields read? */ if(rcd_sys != PRC_STT_SCT_NBR) (void)fprintf(stdout,"%s: ERROR scanning %s returned %d fields, expected %d fields",nco_prg_nm_get(),fl_prc,rcd_sys,PRC_STT_SCT_NBR); (void)fclose(fp_prc); if(nco_dbg_lvl_get() > nco_dbg_std){ char *prc_stt_sng; prc_stt_sng=(char *)nco_malloc(2048UL*sizeof(char)); sprintf(prc_stt_sng,prc_stt_fmt_out,prc_stt->pid,prc_stt->comm,prc_stt->state,prc_stt->ppid,prc_stt->pgrp,prc_stt->session,prc_stt->tty_nr,prc_stt->tpgid,prc_stt->flags,prc_stt->minflt,prc_stt->cminflt,prc_stt->majflt,prc_stt->cmajflt,prc_stt->utime,prc_stt->stime,prc_stt->cutime,prc_stt->cstime,prc_stt->priority,prc_stt->nice,prc_stt->num_threads,prc_stt->itrealvalue,prc_stt->starttime,prc_stt->vsize,prc_stt->rss,prc_stt->rlim,prc_stt->startcode,prc_stt->endcode,prc_stt->startstack,prc_stt->kstkesp,prc_stt->kstkeip,prc_stt->signal,prc_stt->blocked,prc_stt->sigignore,prc_stt->sigcatch,prc_stt->wchan,prc_stt->nswap,prc_stt->cnswap,prc_stt->exit_signal,prc_stt->processor,prc_stt->rt_priority,prc_stt->policy,prc_stt->delayacct_blkio_ticks); (void)fprintf(stdout,"%s: INFO %s polled %s and found: %s\n",nco_prg_nm_get(),fnc_nm,fl_prc,prc_stt_sng); if(prc_stt_sng) prc_stt_sng=(char *)nco_free(prc_stt_sng); } /* endif dbg */ /* Were expected number of fields read? */ if(rcd_sys == PRC_STT_SCT_NBR) return NCO_NOERR; else return NCO_ERR; } /* nco_prc_stt_get() */ int /* Return code */ nco_prc_stm_get /* [fnc] Read /proc/PID/statm */ (const int pid, /* [enm] Process ID to read */ prc_stm_sct *prc_stm) /* [sct] Structure to hold results */ { /* Purpose: Decode output of /proc/PID/stat, place in structure, and optionally print out */ /* 201306: Unfortunately, format of /proc/self/statm is system-dependent Contents of /proc/self/statm defined in man 5 proc Fully documented sources at http://www.cs.tufts.edu/comp/111/assignments/a3/proc.c */ const char fnc_nm[]="nco_prc_stm_get()"; /* [sng] Function name */ char fl_slf[]="/proc/self/statm"; /* [sng] Process status pseudo-file name */ char fl_pid[256]; /* [sng] Process status pseudo-file name */ char *fl_prc; /* [sng] Process status pseudo-file name */ const char *prc_stm_fmt="%lu %lu %lu %lu %lu %lu %lu"; const char *prc_stm_fmt_out="size = %lu, resident = %lu, share = %lu, text = %lu, lib = %lu, data = %lu, dt = %lu\n"; FILE *fp_prc=NULL; /* [fl] Process status file handle */ int rcd_sys; if(pid) (void)sprintf(fl_pid,"/proc/%d/stat",pid); if(pid) fl_prc=fl_pid; else fl_prc=fl_slf; fp_prc=fopen(fl_prc,"r"); /* Unable to open fp_prc */ if(!fp_prc) return NCO_ERR; rcd_sys=fscanf (fp_prc, prc_stm_fmt, &prc_stm->size, &prc_stm->resident, &prc_stm->share, &prc_stm->text, &prc_stm->lib, &prc_stm->data, &prc_stm->dt); /* Were expected number of fields read? */ if(rcd_sys != PRC_STM_SCT_NBR) (void)fprintf(stdout,"%s: ERROR scanning %s returned %d fields, expected %d fields",nco_prg_nm_get(),fl_prc,rcd_sys,PRC_STM_SCT_NBR); (void)fclose(fp_prc); if(nco_dbg_lvl_get() > nco_dbg_std){ char *prc_stm_sng; prc_stm_sng=(char *)nco_malloc(2048UL*sizeof(char)); sprintf(prc_stm_sng,prc_stm_fmt_out,prc_stm->size,prc_stm->resident,prc_stm->share,prc_stm->text,prc_stm->lib,prc_stm->data,prc_stm->dt); (void)fprintf(stdout,"%s: INFO %s polled %s and found: %s\n",nco_prg_nm_get(),fnc_nm,fl_prc,prc_stm_sng); if(prc_stm_sng) prc_stm_sng=(char *)nco_free(prc_stm_sng); } /* endif dbg */ /* Were expected number of fields read? */ if(rcd_sys == PRC_STM_SCT_NBR) return NCO_NOERR; else return NCO_ERR; } /* nco_prc_stm_get() */ long /* O [B] Maximum resident set size */ nco_mmr_usg_prn /* [fnc] Print rusage memory usage statistics */ (const int rusage_who) /* [enm] RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_LWP */ { /* Purpose: Track memory statistics */ /* Routine is intended to be purely diagnostic Currently only accessed with ncks --sysconf rss [B] = RSS = Resident Set Size = Portion of process's memory in RAM. Rest is in swap or not loaded. vsize [B] = Virtual Memory Size rsslim [B] = Soft limit on process RSS, as per getrlimit() */ /* 20130617: Remik Ziemlinski's ncx has _SC_PAGE_SIZE example in ezNcUtil.hpp */ const char fnc_nm[]="nco_mmr_usg_prn()"; /* [sng] Function name */ int rcd_stm; /* [enm] Return code for /proc/PID/statm call */ int rcd_stt; /* [enm] Return code for /proc/PID/stat call */ int rcd_sys; /* [enm] Return code for system call */ #ifndef __GNUG__ extern int errno; /* [enm] Error code in errno.h */ #endif /* __GNUG__ */ /* Get page size. NECSX does not have getpagesize(). */ int sz_pg; /* [B] Page size in Bytes */ sz_pg=rusage_who; /* CEWI */ #ifdef HAVE_GETPAGESIZE /* 20130617: Deprecate getpagesize() in favor of sysconf() because Linux man pages say that "Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize()" sysconf() tells us to first use, if it exists, the PAGESIZE environment variable Otherwise use the sysconf() macro on _SC_PAGESIZE */ // sz_pg=getpagesize(); # ifdef PAGESIZE sz_pg=PAGESIZE; # else /* !PAGESIZE */ sz_pg=sysconf(_SC_PAGESIZE); # ifndef __GNUG__ if(sz_pg < 0) (void)fprintf(stdout,"%s: sysconf() error is \"%s\"\n",nco_prg_nm_get(),strerror(errno)); # endif /* __GNUG__ */ if(sz_pg < 0) nco_exit(EXIT_FAILURE); # endif /* !PAGESIZE */ #endif /* !HAVE_GETPAGESIZE */ /* Interrorgate /proc/self/stat for current memory usage */ prc_stt_sct prc_stt; rcd_stt=nco_prc_stt_get((int)0,&prc_stt); if(rcd_stt == NCO_ERR) (void)fprintf(stdout,"%s: WARNING call to nco_prc_stt_get() failed, proceeding anyway...\n",nco_prg_nm_get()); if(nco_dbg_lvl_get() > nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s thinks pid = %d, comm = %s, ppid = %d, rlim = %lu B = %lu kB = %lu MB, rss = %ld B = %ld kB = %ld MB, vsize = %lu B = %lu kB = %lu MB = %lu GB\n",nco_prg_nm_get(),fnc_nm,prc_stt.pid,prc_stt.comm,prc_stt.ppid,prc_stt.rlim,prc_stt.rlim/NCO_BYT_PER_KB,prc_stt.rlim/NCO_BYT_PER_MB,prc_stt.rss,prc_stt.rss/NCO_BYT_PER_KB,prc_stt.rss/NCO_BYT_PER_MB,prc_stt.vsize,prc_stt.vsize/NCO_BYT_PER_KB,prc_stt.vsize/NCO_BYT_PER_MB,prc_stt.vsize/NCO_BYT_PER_GB); prc_stm_sct prc_stm; rcd_stm=nco_prc_stm_get((int)0,&prc_stm); if(rcd_stm == NCO_ERR) (void)fprintf(stdout,"%s: WARNING call to nco_prc_stm_get() failed, proceeding anyway...\n",nco_prg_nm_get()); if(nco_dbg_lvl_get() > nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s thinks size = %lu B = %lu kB = %lu MB = %lu GB, resident = %lu B = %lu kB = %lu MB = %lu GB\n",nco_prg_nm_get(),fnc_nm,prc_stm.size,prc_stm.size/NCO_BYT_PER_KB,prc_stm.size/NCO_BYT_PER_MB,prc_stm.size/NCO_BYT_PER_GB,prc_stm.resident,prc_stm.resident/NCO_BYT_PER_KB,prc_stm.resident/NCO_BYT_PER_MB,prc_stm.resident/NCO_BYT_PER_GB); #ifdef HAVE_GETRUSAGE /* getrusage() reports size and time in OS-dependent units: AIX getrusage() uses kilobytes [kB] for size [sz] and seconds [s] for time [tm]: ru_maxrss [kB], ru_ixrss [kB s], ru_idrss [kB], ru_idrss [kB] http://publib.boulder.ibm.com/infocenter/pseries/index.jsp?topic=/com.ibm.aix.doc/libs/basetrf1/getrusage_64.htm IRIX getrusage() uses bytes [B] for size [sz] and ru_maxrss [kB], ru_ixrss [pg tck], ru_idrss [pg], ru_idrss [pg] Linux getrusage() uses kilobytes [kB] for size [sz] In 201306 (kernel 3.9) Linux (_still_) does not implement ru_ixrss, ru_idrss, ru_idrss As of 200912 (kernel 2.6.32) Linux implements ru_maxrss [kB] I first tried Linux getrusage() in 200503, on kernel 2.6.9 In 200410 (kernel 2.6.9), Linux did not implement ru_maxrss, ru_ixrss, ru_idrss, or ru_idrs In 200410 (kernel 2.6.9), Linux only maintained rusage fields ru_utime, ru_stime, ru_minflt, ru_majflt, and ru_nswap Solaris getrusage() uses pages [pg] for size and ticks [tck] for time: ru_maxrss [pg], ru_ixrss [pg tck], ru_idrss [pg], ru_idrss [pg] http://docs.sun.com/app/docs/doc/816-5168/6mbb3hr9o?a=view */ struct rusage usg; #ifdef AIX (void)fprintf(stdout,"%s: INFO %s reports system type is AIX so getrusage() uses kilobytes [kB] for size and seconds [s] for time. Page size is %d kB.\n",nco_prg_nm_get(),fnc_nm,sz_pg); #endif /* !AIX */ #ifdef CRAY (void)fprintf(stdout,"%s: INFO %s reports system type is CRAY so getrusage() units for page size and time are unknown.\n",nco_prg_nm_get(),fnc_nm); #endif /* !CRAY */ #if (defined LINUX) || (defined LINUXAMD64) (void)fprintf(stdout,"%s: INFO %s reports system type is LINUX so getrusage() does implement ru_maxrss [kB] and DOES NOT implement ru_ixrss, ru_idrss, and ru_idrss. Page size is %d B.\n",nco_prg_nm_get(),fnc_nm,sz_pg); #endif /* !LINUX */ #ifdef NECSX (void)fprintf(stdout,"%s: INFO %s reports system type is NECSX so getrusage() units for page size and time are unknown.\n",nco_prg_nm_get(),fnc_nm); #endif /* !NECSX */ #ifdef SGIMP64 (void)fprintf(stdout,"%s: INFO %s reports system type is SGIMP64 so getrusage() uses bytes [B] for size, while time units are unknown. Page size is %d B.\n",nco_prg_nm_get(),fnc_nm,sz_pg); #endif /* !SGIMP64 */ #ifdef SUNMP (void)fprintf(stdout,"%s: INFO %s reports system type is SUNMP so getrusage() uses pages [pg] for size and ticks [tck] for time. Page size is %d B.\n",nco_prg_nm_get(),fnc_nm,sz_pg); #endif /* !SUNMP */ /* fxm: CEWI, not necessary */ rcd_sys=rusage_who; /* fxm: use input argument rusage_who instead of RUSAGE_SELF */ rcd_sys=0*rcd_sys+getrusage(RUSAGE_SELF,&usg); if(nco_dbg_lvl_get() > nco_dbg_io) (void)fprintf(stdout,"%s: INFO %s reports: rusage.ru_utime.tv_sec = user time used = %li s, rusage.ru_utime.tv_usec = user time used = %li us, rusage.ru_stime.tv_sec = system time used = %li s, rusage.ru_stime.tv_usec = system time used = %li us, rusage.ru_maxrss = maximum resident set size = %li [sz], rusage.ru_ixrss = integral shared memory size = %li [sz tm], rusage.ru_idrss = integral unshared data size = %li [sz], rusage.ru_isrss = integral unshared stack size = %li [sz], rusage.ru_minflt = page reclaims = %li, rusage.ru_majflt = page faults = %li, rusage.ru_nswap = swaps = %li\n",nco_prg_nm_get(),fnc_nm,usg.ru_utime.tv_sec,usg.ru_utime.tv_usec,usg.ru_stime.tv_sec,usg.ru_stime.tv_usec,usg.ru_maxrss,usg.ru_ixrss,usg.ru_idrss,usg.ru_isrss,usg.ru_minflt,usg.ru_majflt,usg.ru_nswap); return (long)usg.ru_maxrss; /* [B] Maximum resident set size */ #else /* !HAVE_GETRUSAGE */ return (long)0; /* [B] Fake return value */ #endif /* !HAVE_GETRUSAGE */ } /* nco_mmr_usg_prn() */ ./nco-4.4.2/src/nco/ncap_yacc.y0000644000674300045400000007452412274266124015457 0ustar zendercgdcsm%{ /* $Header: /cvsroot/nco/nco/src/nco/ncap_yacc.y,v 1.67 2014/02/04 22:40:20 zender Exp $ -*-C-*- */ /* Begin C declarations section */ /* Purpose: Grammar parser for ncap */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: bison --output=${HOME}/nco/src/nco/ncap_yacc.c -d ~/nco/src/nco/ncap_yacc.y */ /* Example yacc text: Nie02 "A Compact Guide to Lex & Yacc" by Thomas Niemann, ePaper Press, URL:http://epaperpress.com/lexandyacc/index.html LMB92 ${DATA}/ora/lexyacc/ch3-05.y GCC c-parse.y GCC parser_build_binary_op() c-typeck.c Unidata ncgen.y */ /* Standard header files */ #include /* sin cos cos sin 3.14159 */ #include /* va_start, va_arg, va_end */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "ncap.h" /* netCDF arithmetic processor-specific definitions (symbol table, ...) */ /* Bison adds routines which reference YY*LEX token to ncap_yacc.c These routines generate warnings unless YY*LEX prototype appears above YYLEX prototype generates error unless YYSTYPE token is defined Thus must #include ncap_yacc.h solely to pre-define YY*STYPE for YY*LEX prototype There is no other reason for ncap_yacc.h to appear in ncap_yacc.y Yes, this is rather circular */ /* Get YYSTYPE prior to prototyping scanner */ #include "ncap_yacc.h" /* ncap_yacc.h (ncap.tab.h) is produced from ncap_yacc.y by parser generator */ #define YY_DECL int yylex(YYSTYPE *lval_ptr,prs_sct *prs_arg) YY_DECL; /* Turn on parser debugging option (Bison manual p. 85) */ #define YYDEBUG 0 int yydebug=0; /* 0: Normal operation. 1: Print parser rules during execution */ /* Turns on more verbose errors than just plain "parse error" when yyerror() is called by parser */ #define YYERROR_VERBOSE 1 /* Bison manual p. 60 describes how to call yyparse() with arguments Following two statements superceded 20051213 by parse-param and lex-param below */ /* #define YYPARSE_PARAM prs_arg */ /* #define YYLEX_PARAM prs_arg */ int rcd; /* [enm] Return value for function calls */ /* Global variables */ extern size_t ncap_ncl_dpt_crr; /* [nbr] Depth of current #include file (declared in ncap.c) */ extern size_t *ncap_ln_nbr_crr; /* [cnt] Line number (declared in ncap.c) */ extern char **ncap_fl_spt_glb; /* [fl] Script file (declared in ncap.c) */ extern char ncap_err_sng[200]; /* [sng] Buffer for error string (declared in ncap_lex.l) */ /* End C declarations section */ %} /* Begin parser declaration section */ /* Request pure, re-entrant parser, so we can pass a structure to parser fxm: 20020122 ncap16: Code breaks on Linux when pure_parser is _not_ used---why? e.g., ncap -O -D 5 -S ${HOME}/dst/dst.nco ${DATA}/${caseid}/${caseid}_${yr_sng}_xy.nc ${DATA}/${caseid}/${caseid}_${yr_sng}_xy.nc Possibly because hardcoded yy* function prototypes change? */ %pure-parser %parse-param {prs_sct *prs_arg} %lex-param {prs_sct *prs_arg} /* NB: "terminal symbol" is just a fancy name for token produced by lexer Symbols defined on LHS of rules are called "non-terminal symbols" or "non-terminals" Examples of non-terminals are xpr, stt, stt_lst Examples of terminal symbols, or tokens, are NAME, NUMBER Convention is to make token names all uppercase, and non-terminals lowercase */ /* Define YYSTYPE union (type of lex variable yylval value) This specifies all possible data types for semantic values */ %union{ char *sng; /* [sng] String value */ char *var_nm_LHS; /* [sng] Variables on LHS */ char *var_nm_RHS; /* [sng] Variables on RHS */ aed_sct aed; /* [sct] Attribute */ sym_sct *sym; /* [sct] Intrinsic function name */ scv_sct scv; /* [sct] Scalar value */ var_sct *var; /* [sct] Variable */ nm_lst_sct *sbs_lst; /* [sct] Subscript list */ int nco_rlt_opr; /* [enm] Comparison operator type */ nc_type cnv_type; /* [enm] Used for type conversion functions */ } /* end YYSTYPE union (type of yylval value) */ /* Tell parser which kind of values each token takes Token name (traditionally in all caps) becomes #define directive in parser so we can refer to token name rather than token's numeric code */ %token OUT_ATT %token COMPARISON %token LHS_SBS %token SCV %token SNG %token FUNCTION %token OUT_VAR %token VAR %token CNV_TYPE %token ABS ATOSTR EPROVOKE IGNORE NAMED_CONSTANT PACK POWER RDC UNPACK %token IF PRINT /* "type" declaration sets type for non-terminal symbols which otherwise need no declaration Format of "type" declaration is %type RHS_xpr RHS expression type RHS_xpr is same type as YYSTYPE union member with name in <> */ %type scv_xpr %type sng_xpr %type var_xpr %type out_var_xpr %type out_att_xpr /* "left", "right", and "nonassoc" perform same function as "token" and, in addition, specify associativity and relative precedence of symbols. Each successive line has higher precedence than preceding lines */ /* fxm: 20020608 AND, NOT, OR not implemented in lexer yet */ %left AND NOT OR /* && ! || */ %left COMPARISON /* == != < > <= >= */ %left '+' '-' %left '*' '/' '%' %right '^' %nonassoc UMINUS %nonassoc LOWER_THAN_ELSE %nonassoc ELSE /* End parser declaration section */ %% /* Begin Rules section Format is rule: action Comments OK in space between C code but must be indented */ program: stmt_lst ; /* end program */ stmt_lst: ';' { ;} /* collect extra ; */ | stmt_lst ';' { ;} /* collect extra ; */ | stmt_lst stmt ';' { /* Purpose: Actions to be performed at end-of-statement go here */ /* Clean up from and exit LHS_cst mode */ (void)nco_var_free_wrp(&((prs_sct *)prs_arg)->var_LHS); } /* end stmt ';' */ | stmt_lst error ';' {(void)nco_var_free_wrp(&((prs_sct *)prs_arg)->var_LHS);} | stmt ';' {(void)nco_var_free_wrp(&((prs_sct *)prs_arg)->var_LHS);} | error ';' {(void)nco_var_free_wrp(&((prs_sct *)prs_arg)->var_LHS);} /* Catch most errors then read up to next semi-colon */ ; /* end stmt_lst */ stmt: /* Statement is definition of out_att_xpr or out_var_xpr (LHS tokens) in terms of scv_xpr, var_xpr, and sng_xpr (RHS tokens). All permutations are valid so this rule has six possible actions */ IF '(' bln_xpr ')' stmt %prec LOWER_THAN_ELSE { /* LMB92 p. 234 */ ; } /* end IF bln_xpr stmt */ | IF '(' bln_xpr ')' stmt ELSE stmt { /* LMB92 p. 234 */ ; } /* end IF bln_xpr stmt ELSE stmt */ PRINT '(' scv_xpr ')' ';' { ; } /* end PRINT '(' scv_xpr ')' */ PRINT '(' var_xpr ')' ';' { ; } /* end PRINT '(' var_xpr ')' */ | out_att_xpr '=' scv_xpr { aed_sct *ptr_aed; ptr_aed=ncap_aed_lookup($1.var_nm,$1.att_nm,((prs_sct *)prs_arg),True); ptr_aed->val=ncap_scv_2_ptr_unn($3); ptr_aed->type=$3.type; ptr_aed->sz=1L; (void)cast_nctype_void(ptr_aed->type,&ptr_aed->val); if(nco_dbg_lvl_get() >= nco_dbg_std) (void)sprintf(ncap_err_sng,"Saving attribute %s@%s to %s",$1.var_nm,$1.att_nm,((prs_sct *)prs_arg)->fl_out); (void)nco_yyerror(prs_arg,ncap_err_sng); if(nco_dbg_lvl_get() >= nco_dbg_fl){ (void)fprintf(stderr,"Saving in array attribute %s@%s=",$1.var_nm,$1.att_nm); switch($3.type){ /* NB: Format depends on opaque type of nco_int Until 200911, nco_int was C-type long, and now nco_int is C-type int case NC_INT: (void)fprintf(stderr,"%ld\n",$3.val.i); break; */ case NC_FLOAT: (void)fprintf(stderr,"%G\n",$3.val.f); break; case NC_DOUBLE: (void)fprintf(stderr,"%.5G\n",$3.val.d);break; case NC_INT: (void)fprintf(stderr,"%d\n",$3.val.i); break; case NC_SHORT: (void)fprintf(stderr,"%hi\n",$3.val.s); break; case NC_BYTE: (void)fprintf(stderr,"%hhi\n",$3.val.b); break; case NC_UBYTE: (void)fprintf(stderr,"%hhu\n",$3.val.ub); break; case NC_USHORT: (void)fprintf(stderr,"%hu\n",$3.val.us); break; case NC_UINT: (void)fprintf(stderr,"%u\n",$3.val.ui); break; case NC_INT64: (void)fprintf(stderr,"%lld\n",$3.val.i64); break; case NC_UINT64: (void)fprintf(stderr,"%llu\n",$3.val.ui64); break; case NC_CHAR: (void)fprintf(stderr,"%c\n",$3.val.c); break; case NC_STRING: (void)fprintf(stderr,"%s\n",$3.val.sng); break; default: break; } /* end switch */ } /* end if */ $1.var_nm=(char *)nco_free($1.var_nm); $1.att_nm=(char *)nco_free($1.att_nm); } /* end out_att_xpr '=' scv_xpr */ | out_att_xpr '=' sng_xpr { aed_sct *ptr_aed; size_t sng_lng; sng_lng=strlen($3); ptr_aed=ncap_aed_lookup($1.var_nm,$1.att_nm,((prs_sct *)prs_arg),True); ptr_aed->type=NC_CHAR; ptr_aed->sz=(long int)((sng_lng+1)*nco_typ_lng(NC_CHAR)); ptr_aed->val.cp=(nco_char *)nco_malloc((sng_lng+1)*nco_typ_lng(NC_CHAR)); strcpy((char *)(ptr_aed->val.cp),$3); (void)cast_nctype_void((nc_type)NC_CHAR,&ptr_aed->val); if(nco_dbg_lvl_get() >= nco_dbg_std) (void)sprintf(ncap_err_sng,"Saving attribute %s@%s=%s",$1.var_nm,$1.att_nm,$3); (void)nco_yyerror(prs_arg,ncap_err_sng); $1.var_nm=(char *)nco_free($1.var_nm); $1.att_nm=(char *)nco_free($1.att_nm); $3=(char *)nco_free($3); } /* end out_att_xpr '=' sng_xpr */ | out_att_xpr '=' var_xpr { /* Storing 0-dimensional variables in attribute is OK */ aed_sct *ptr_aed; if($3->nbr_dim < 2){ ptr_aed=ncap_aed_lookup($1.var_nm,$1.att_nm,((prs_sct *)prs_arg),True); ptr_aed->sz=$3->sz; ptr_aed->type=$3->type; /* if inital scan then fill attribute with zeros */ if( ((prs_sct*)prs_arg)->ntl_scn) { ptr_aed->val.vp=(void*)nco_calloc( ptr_aed->sz,nco_typ_lng(ptr_aed->type)); } else { ptr_aed->val.vp=(void*)nco_malloc((ptr_aed->sz)*nco_typ_lng(ptr_aed->type)); (void)nco_var_copy(ptr_aed->type,ptr_aed->sz,$3->val,ptr_aed->val); } /* cast_nctype_void($3->type,&ptr_aed->val); */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)sprintf(ncap_err_sng,"Saving attribute %s@%s %d dimensional variable",$1.var_nm,$1.att_nm,$3->nbr_dim); (void)yyerror(prs_arg,ncap_err_sng); }else{ (void)sprintf(ncap_err_sng,"Warning: Cannot store in attribute %s@%s a variable with dimension %d",$1.var_nm,$1.att_nm,$3->nbr_dim); (void)yyerror(prs_arg,ncap_err_sng); } /* endif */ $1.var_nm=(char *)nco_free($1.var_nm); $1.att_nm=(char *)nco_free($1.att_nm); (void)nco_var_free($3); } /* end out_att_xpr '=' var_xpr */ | out_var_xpr '=' var_xpr { ($3->nm)=(char*)nco_free($3->nm); $3->nm=strdup($1); (void)ncap_var_write($3,(prs_sct *)prs_arg); /* Print mess only for defined variables */ if(nco_dbg_lvl_get() >= nco_dbg_std && !$3->undefined){(void)sprintf(ncap_err_sng,"Saving variable %s to %s",$1,((prs_sct *)prs_arg)->fl_out); (void)yyerror(prs_arg,ncap_err_sng); } /* endif */ $1=(char *)nco_free($1); } /* end out_var_xpr '=' var_xpr */ | out_var_xpr '=' scv_xpr { var_sct *var; var_sct *var_tmp; if(nco_dbg_lvl_get() > 5) (void)fprintf(stderr,"%s: DEBUG out_var_xpr = scv_xpr rule for %s\n",nco_prg_nm_get(),$1); /* Turn attribute into temporary variable for writing */ var=(var_sct *)nco_malloc(sizeof(var_sct)); /* Set defaults */ (void)var_dfl_set(var); /* [fnc] Set defaults for each member of variable structure */ /* Overwrite with attribute expression information */ var->nm=strdup($1); var->nbr_dim=0; var->sz=1; var->type=$3.type; var->val=ncap_scv_2_ptr_unn($3); if(((prs_sct *)prs_arg)->var_LHS != NULL){ /* User intends LHS to cast RHS to same dimensionality Stretch newly initialized variable to size of LHS template */ /* (void)ncap_var_cnf_dmn(&$$,&(((prs_sct *)prs_arg)->var_LHS));*/ var_tmp=var; (void)ncap_var_stretch(&var_tmp,&(((prs_sct *)prs_arg)->var_LHS)); if(var_tmp != var) { var=nco_var_free(var); var=var_tmp; } if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: Stretching former scv_xpr defining %s with LHS template: Template var->nm %s, var->nbr_dim %d, var->sz %li\n",nco_prg_nm_get(),$1,((prs_sct *)prs_arg)->var_LHS->nm,((prs_sct *)prs_arg)->var_LHS->nbr_dim,((prs_sct *)prs_arg)->var_LHS->sz); } /* endif LHS_cst */ var->undefined=False; (void)ncap_var_write(var,(prs_sct *)prs_arg); if(nco_dbg_lvl_get() >= nco_dbg_std ) (void)sprintf(ncap_err_sng,"Saving variable %s to %s",$1,((prs_sct *)prs_arg)->fl_out); (void)yyerror(prs_arg,ncap_err_sng); $1=(char *)nco_free($1); } /* end out_var_xpr '=' scv_xpr */ | out_var_xpr '=' sng_xpr { var_sct *var; var=(var_sct *)nco_calloc((size_t)1,sizeof(var_sct)); var->nm=strdup($1); var->nbr_dim=0; var->dmn_id=(int *)NULL; var->sz=strlen($3)+1; var->val.cp=(nco_char *)strdup($3); var->type=NC_CHAR; var->undefined=False; (void)cast_nctype_void((nc_type)NC_CHAR,&var->val); (void)ncap_var_write(var,(prs_sct *)prs_arg); if(nco_dbg_lvl_get() >= nco_dbg_std) (void)sprintf(ncap_err_sng,"Saving variable %s to %s",$1,((prs_sct *)prs_arg)->fl_out); (void)yyerror(prs_arg,ncap_err_sng); $1=(char *)nco_free($1); $3=(char *)nco_free($3); } /* end out_var_xpr '=' sng_xpr */ ; /* end stmt */ scv_xpr: /* scv_xpr results from RHS action which involves only scv_xpr's One action exists for each binary and unary attribute-valid operator */ scv_xpr '+' scv_xpr { (void)ncap_scv_scv_cnf_typ_hgh_prc(&$1,&$3); $$=ncap_scv_clc($1,'+',$3); } | scv_xpr '-' scv_xpr { (void)ncap_scv_scv_cnf_typ_hgh_prc(&$1,&$3); $$=ncap_scv_clc($1,'-',$3); } | scv_xpr '*' scv_xpr { (void)ncap_scv_scv_cnf_typ_hgh_prc(&$1,&$3); $$=ncap_scv_clc($1,'*',$3); } | scv_xpr '/' scv_xpr { (void)ncap_scv_scv_cnf_typ_hgh_prc(&$1,&$3); $$=ncap_scv_clc($1,'/',$3); } | scv_xpr '%' scv_xpr { (void)ncap_scv_scv_cnf_typ_hgh_prc(&$1,&$3); $$=ncap_scv_clc($1,'%',$3); } | '-' scv_xpr %prec UMINUS { (void)ncap_scv_minus(&$2); $$=$2; } | '+' scv_xpr %prec UMINUS { $$=$2; } | scv_xpr '^' scv_xpr { if(nco_rth_prc_rnk($1.type) <= nco_rth_prc_rnk_float && nco_rth_prc_rnk($3.type) <= nco_rth_prc_rnk_float) { (void)nco_scv_cnf_typ((nc_type)NC_FLOAT,&$1); (void)nco_scv_cnf_typ((nc_type)NC_FLOAT,&$3); $$.val.f=powf($1.val.f,$3.val.f); $$.type=NC_FLOAT; }else{ (void)nco_scv_cnf_typ((nc_type)NC_DOUBLE,&$1); (void)nco_scv_cnf_typ((nc_type)NC_DOUBLE,&$3); $$.val.d=pow($1.val.d,$3.val.d); $$.type=NC_DOUBLE; } /* end else */ } /* end scv_xpr '^' scv_xpr */ | POWER '(' scv_xpr ',' scv_xpr ')' { /* fxm: ncap52 this is identical to previous clause except for argument numbering, should be functionalized to use common code */ if(nco_rth_prc_rnk($3.type) <= nco_rth_prc_rnk_float && nco_rth_prc_rnk($5.type) <= nco_rth_prc_rnk_float) { (void)nco_scv_cnf_typ((nc_type)NC_FLOAT,&$3); (void)nco_scv_cnf_typ((nc_type)NC_FLOAT,&$5); $$.val.f=powf($3.val.f,$5.val.f); $$.type=NC_FLOAT; }else{ (void)nco_scv_cnf_typ((nc_type)NC_DOUBLE,&$3); (void)nco_scv_cnf_typ((nc_type)NC_DOUBLE,&$5); $$.val.d=pow($3.val.d,$5.val.d); $$.type=NC_DOUBLE; } /* end else */ } /* end POWER '(' scv_xpr ',' scv_xpr ')' */ | ABS '(' scv_xpr ')' { $$=ncap_scv_abs($3); } | FUNCTION '(' scv_xpr ')' { if(nco_rth_prc_rnk($3.type) <= nco_rth_prc_rnk_float) { (void)nco_scv_cnf_typ((nc_type)NC_FLOAT,&$3); $$.val.f=(*($1->fnc_flt))($3.val.f); $$.type=NC_FLOAT; }else{ $$.val.d=(*($1->fnc_dbl))($3.val.d); $$.type=NC_DOUBLE; } /* end else */ } /* end FUNCTION '(' scv_xpr ')' */ | CNV_TYPE '(' scv_xpr ')' { (void)nco_scv_cnf_typ($1,&$3); $$=$3; } | '(' scv_xpr ')' {$$=$2;} | SCV {$$=$1;} ; /* end scv_xpr */ out_var_xpr: OUT_VAR {$$=$1;} ; out_att_xpr: OUT_ATT {$$=$1;} ; sng_xpr: /* sng_xpr is any combination of sng_xpr or attribute */ sng_xpr '+' sng_xpr { size_t sng_lng; sng_lng=strlen($1)+strlen($3); $$=(char*)nco_malloc((sng_lng+1)*sizeof(char)); strcpy($$,$1); strcat($$,$3); $1=(char *)nco_free($1); $3=(char *)nco_free($3); } /* end sng_xpr '+' sng_xpr */ | ATOSTR '(' scv_xpr ')' { char bfr[50]; switch ($3.type){ /* NB: Format depends on opaque type of nco_int Until 200911, nco_int was C-type long, and now nco_int is C-type int case NC_INT: sprintf(bfr,"%ld",$3.val.i); break; */ case NC_DOUBLE: sprintf(bfr,"%.10G",$3.val.d); break; case NC_FLOAT: sprintf(bfr,"%G",$3.val.f); break; case NC_INT: sprintf(bfr,"%d",$3.val.i); break; case NC_SHORT: sprintf(bfr,"%hi",$3.val.s); break; case NC_BYTE: sprintf(bfr,"%hhi",$3.val.b); break; case NC_UBYTE: sprintf(bfr,"%hhu",$3.val.ub); break; case NC_USHORT: sprintf(bfr,"%hu",$3.val.us); break; case NC_UINT: sprintf(bfr,"%u",$3.val.ui); break; case NC_INT64: sprintf(bfr,"%lld",$3.val.i64); break; case NC_UINT64: sprintf(bfr,"%llu",$3.val.ui64); break; case NC_CHAR: sprintf(bfr,"%c",$3.val.c); break; case NC_STRING: sprintf(bfr,"%s",$3.val.sng); break; default: break; } /* end switch */ $$=strdup(bfr); } /* end ATOSTR '(' scv_xpr ')' */ | ATOSTR '(' scv_xpr ',' sng_xpr ')' { char bfr[150]; /* Format string according to string expression */ /* User decides which format corresponds to which type */ switch ($3.type){ case NC_DOUBLE: sprintf(bfr,$5,$3.val.d); break; case NC_FLOAT: sprintf(bfr,$5,$3.val.f); break; case NC_INT: sprintf(bfr,$5,$3.val.i); break; case NC_SHORT: sprintf(bfr,$5,$3.val.s); break; case NC_BYTE: sprintf(bfr,$5,$3.val.b); break; case NC_UBYTE: sprintf(bfr,$5,$3.val.ub); break; case NC_USHORT: sprintf(bfr,$5,$3.val.us); break; case NC_UINT: sprintf(bfr,$5,$3.val.ui); break; case NC_INT64: sprintf(bfr,$5,$3.val.i64); break; case NC_UINT64: sprintf(bfr,$5,$3.val.ui64); break; case NC_CHAR: sprintf(bfr,$5,$3.val.c); break; case NC_STRING: sprintf(bfr,$5,$3.val.sng); break; default: break; } /* end switch */ $5=(char *)nco_free($5); $$=strdup(bfr); } /* end ATOSTR '(' scv_xpr ',' sng_xpr ')' */ | SNG {$$=$1;} /* Terminal symbol action */ ; /* end sng_xpr */ bln_xpr: /* bln_xpr results from comparison of var_xpr's and scv_xpr's */ var_xpr COMPARISON var_xpr { } | scv_xpr COMPARISON scv_xpr { } | var_xpr COMPARISON scv_xpr { } | scv_xpr COMPARISON var_xpr { } ; /* end bln_xpr */ var_xpr: /* var_xpr results from RHS action which involves a var_xpr, i.e., OP var, var OP var, var OP att, att OP var */ var_xpr '+' var_xpr { /* Begin Addition */ $$=ncap_var_var_add($1,$3); } | var_xpr '+' scv_xpr { $$=ncap_var_scv_add($1,$3); } | scv_xpr '+' var_xpr { /* Addition commutes so swap arguments and use S+V = V+S */ $$=ncap_var_scv_add($3,$1); } /* End Addition */ | var_xpr '-' var_xpr { /* Begin Subtraction */ $$=ncap_var_var_sub($1,$3); } | var_xpr '-' scv_xpr { $$=ncap_var_scv_sub($1,$3); } | scv_xpr '-' var_xpr { /* Subtraction is non-commutative, do not swap arguments and/or re-use V-S subtraction function Use anti-symmetric property that V-S=-(S-V) */ scv_sct minus; minus.val.b=-1; minus.type=NC_BYTE; (void)nco_scv_cnf_typ($3->type,&minus); (void)ncap_var_scv_sub($3,$1); $$=ncap_var_scv_mlt($3,minus); } /* End Subtraction */ | var_xpr '*' var_xpr { /* Begin Multiplication */ $$=ncap_var_var_mlt($1,$3); } | var_xpr '*' scv_xpr { $$=ncap_var_scv_mlt($1,$3); } | scv_xpr '*' var_xpr { /* Addition commutes so swap arguments and use S*V = V*S */ $$=ncap_var_scv_mlt($3,$1); } /* End Multiplication */ | var_xpr '/' var_xpr { /* Begin Division */ /* NB: Order was important (keeping denominator as I/O variable) This is no longer true with ncbo Maybe rewrite to keep argument ordering consitent with multiplication, addition */ $$=ncap_var_var_dvd($3,$1); } | var_xpr '/' scv_xpr { /* Keep V as I/O */ $$=ncap_var_scv_dvd($1,$3); } | scv_xpr '/' var_xpr { /* Division is non-commutative, use S/V not V/S division function */ $$=ncap_scv_var_dvd($1,$3); } /* End Division */ | var_xpr '%' var_xpr { /* Begin Modulo */ $$=ncap_var_var_mod($1,$3); } | var_xpr '%' scv_xpr { $$=ncap_var_scv_mod($1,$3); } | scv_xpr '%' var_xpr { /* Modulo is non-commutative, use S%V not V%S modulo function */ $$=ncap_scv_var_mod($1,$3); } /* End Modulo */ | var_xpr '^' var_xpr { /* Begin Empowerment of form x^y */ $$=ncap_var_var_pwr($1,$3); } | var_xpr '^' scv_xpr { $$=ncap_var_scv_pwr($1,$3); } | scv_xpr '^' var_xpr { /* Empowerment is non-commutative, use S^V not V^S empowerment function */ $$=ncap_scv_var_pwr($1,$3); } | POWER '(' var_xpr ',' var_xpr ')' { /* Begin Empowerment of form pow(x,y) */ /* fxm: TODO ncap52 Combine pow() with ^ parsing in parser ncap_yacc.y */ $$=ncap_var_var_pwr($3,$5); } | POWER '(' var_xpr ',' scv_xpr ')' { $$=ncap_var_scv_pwr($3,$5); } | POWER '(' scv_xpr ',' var_xpr ')' { /* Empowerment is non-commutative, use S^V not V^S empowerment function */ $$=ncap_scv_var_pwr($3,$5); } /* End Empowerment */ | '-' var_xpr %prec UMINUS { /* Begin Unary Subtraction */ scv_sct minus; minus.val.b=-1; minus.type=NC_BYTE; $$=ncap_var_scv_mlt($2,minus); } /* End Unary Subtraction */ | '+' var_xpr %prec UMINUS { /* Begin Unary Addition */ $$=$2; } /* End Unary Addition */ | ABS '(' var_xpr ')' { $$=ncap_var_abs($3); } /* end ABS */ | RDC '(' var_xpr ')' { $$=ncap_var_abs($3); /* fxm Finish avg,min,max,ttl */ /* $$=nco_var_avg($3,dim,dmn_nbr,nco_op_typ); */ /* if(prs_arg->nco_op_typ == nco_op_avg) (void)nco_var_dvd(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->has_mss_val,var_prc_out[idx]->mss_val,wgt_avg->val,var_prc_out[idx]->val); */ (void)fprintf(stderr,"%s: WARNING RDC tokens not implemented yet\n",nco_prg_nm_get()); /* $3 is freed in nco_var_avg() */ } /* end ABS */ | PACK '(' var_xpr ')' { /* Packing variable does not create duplicate so DO NOT free $3 */ const nc_type nc_typ_pck_dfl=NC_SHORT; /* [enm] Default type to pack to */ nco_bool PCK_VAR_WITH_NEW_PCK_ATT; if(((prs_sct*)prs_arg)->ntl_scn){ $3->undefined=True; $$=$3; }else{ $$=nco_var_pck($3,nc_typ_pck_dfl,&PCK_VAR_WITH_NEW_PCK_ATT); PCK_VAR_WITH_NEW_PCK_ATT=PCK_VAR_WITH_NEW_PCK_ATT+0; /* CEWI */ } /* end else */ } /* end PACK */ | UNPACK '(' var_xpr ')' { /* Unpacking variable does not create duplicate so DO NOT free $3 */ /* Do not unpack on first pass */ if(((prs_sct*)prs_arg)->ntl_scn){ $3->undefined=True; $$=$3; }else{ $$=nco_var_upk($3); } /* end else */ } /* end UNPACK */ | FUNCTION '(' var_xpr ')' { $$=ncap_var_fnc($3,$1); } | '(' var_xpr ')' { $$=$2; } | CNV_TYPE '(' var_xpr ')' { $$=nco_var_cnf_typ($1,$3); } | NAMED_CONSTANT { /* Terminal symbol action */ /* fxm: Allow commands like a=M_PI*rds^2; to work */ } | VAR { /* Terminal symbol action */ var_sct *var; var_sct *var_tmp; prs_sct *prs_drf; /*Pointer for de-referencing */ prs_drf=(prs_sct*)prs_arg; var=ncap_var_init($1,prs_drf); var->undefined=False; if(prs_drf->ntl_scn == True && prs_drf->var_LHS != NULL){ var_tmp=nco_var_dpl(prs_drf->var_LHS); var_tmp->id=var->id; var_tmp->nm=(char*)nco_free(var_tmp->nm); var_tmp->nm=strdup($1); var_tmp->type=var->type; var_tmp->typ_dsk=var->typ_dsk; var_tmp->undefined=False; var_tmp->val.vp=(void*)NULL; var=nco_var_free(var); var=var_tmp; } /* endif ntl_scn */ if(prs_drf->ntl_scn == False && prs_drf->var_LHS != NULL){ /* User intends LHS to cast RHS to same dimensionality Stretch newly initialized variable to size of LHS template */ /* (void)ncap_var_cnf_dmn(&$$,&(((prs_sct *)prs_arg)->var_LHS));*/ var_tmp=var; (void)ncap_var_stretch(&var_tmp,&(prs_drf->var_LHS)); if(var_tmp != var) { var=nco_var_free(var); var=var_tmp; } if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: Stretching variable %s with LHS template: Template var->nm %s, var->nbr_dim %d, var->sz %li\n",nco_prg_nm_get(),var->nm,prs_drf->var_LHS->nm,prs_drf->var_LHS->nbr_dim,prs_drf->var_LHS->sz); var->undefined=False; } /* endif LHS_cst */ $1=(char*)nco_free($1); $$=var; /* Sanity check */ if ($$==(var_sct *)NULL) YYERROR; } /* end VAR terminal symbol */ ; /* end var_xpr */ /* End Rules section */ %% /* Begin User Functions section */ aed_sct * /* O [idx] Location of attribute in list */ ncap_aed_lookup /* [fnc] Find location of existing attribute or add new attribute */ (const char * const var_nm, /* I [sng] Variable name */ const char * const att_nm, /* I [sng] Attribute name */ prs_sct * prs_arg, /* contains attribute list */ const nco_bool update) /* I [flg] Delete existing value or add new attribute to list */ { int idx; int size; aed_sct *ptr_aed; size=*(prs_arg->nbr_att); for(idx=0;idxatt_lst))[idx]; if(strcmp(ptr_aed->att_nm,att_nm) || strcmp(ptr_aed->var_nm,var_nm)) continue; if(update) ptr_aed->val.vp=nco_free(ptr_aed->val.vp); /* Return pointer to list element */ return ptr_aed; } /* end for */ if(!update) return (aed_sct *)NULL; *(prs_arg->att_lst)=(aed_sct **)nco_realloc(*(prs_arg->att_lst),(size+1)*sizeof(aed_sct*)); ++*(prs_arg->nbr_att); (*(prs_arg->att_lst))[size]=(aed_sct *)nco_malloc(sizeof(aed_sct)); (*(prs_arg->att_lst))[size]->var_nm=strdup(var_nm); (*(prs_arg->att_lst))[size]->att_nm=strdup(att_nm); return (*(prs_arg->att_lst))[size]; } /* end ncap_aed_lookup() */ var_sct * /*I [sct] varibale in list */ ncap_var_lookup (var_sct *var, /* I [sct] variable */ prs_sct *prs_arg, /* I/O [sct] contains var list */ const nco_bool add) /* I if not in list then add to list */ { int idx; int size; var_sct *ptr_var; size = *(prs_arg->nbr_var); for(idx=0;idxvar_lst))[idx]; /* assert(var->nm); assert(ptr_var->nm); if(!strcmp(var->nm,ptr_var->nm)) return ptr_var; */ if(ptr_var==NULL || strcmp(var->nm,ptr_var->nm) ) continue; return ptr_var; } /* end loop over idx */ if(!add) return (var_sct *)NULL; *(prs_arg->var_lst)=(var_sct **)nco_realloc(*(prs_arg->var_lst),(size+1)*sizeof(var_sct*)); ++*(prs_arg->nbr_var); (*(prs_arg->var_lst))[size]=var; return (var_sct *)NULL; } /* end ncap_var_lookup() */ int /* [rcd] Return code */ yyerror /* [fnc] Print error/warning/info messages generated by parser */ (prs_sct *prs_arg, const char * const err_sng_lcl) /* [sng] Message to print */ { /* Purpose: Print error/warning/info messages generated by parser Use eprokoke_skip to skip error message after sending error message from yylex() Stop provoked error message from yyparse being printed */ static nco_bool eprovoke_skip; prs_arg=prs_arg+0; /* CEWI otherwise unused parameter error */ /* if(eprovoke_skip){eprovoke_skip=False ; return 0;} */ if(nco_dbg_lvl_get() >= nco_dbg_std){ (void)fprintf(stderr,"%s: %s line %lu",nco_prg_nm_get(),ncap_fl_spt_glb[ncap_ncl_dpt_crr],(unsigned long)ncap_ln_nbr_crr[ncap_ncl_dpt_crr]); if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stderr," %s",err_sng_lcl); (void)fprintf(stderr,"\n"); (void)fflush(stderr); } /* endif dbg */ if(err_sng_lcl[0] == '#') eprovoke_skip=True; eprovoke_skip=eprovoke_skip+0; /* CEWI Do nothing except avoid compiler warnings */ return 0; } /* end yyerror() */ void nco_var_free_wrp /* [fnc] Safely free variable */ (var_sct **var) /* I/O [sct] Variable */ { /* Purpose: Safely free variable Routine is wrapper for nco_var_free() that simplifies code in calling routine */ if(*var != NULL) *var=nco_var_free(*var); } /* end nco_var_free_wrp() */ nodeType * /* O [unn] Syntax tree node */ opr_ctl /* [fnc] Operation controller function Nie02 opr() */ (int opr_tkn, /* I [enm] Operator token */ int arg_nbr, /* I [nbr] Number of optional arguments to malloc() wrapper */ ...) /* I [llp] Ellipsis defined in stdarg.h */ { /* Purpose: Create and return syntax tree node */ va_list arg_lst; /* [] Variable argument list */ nodeType *nod; /* [sct] Syntax tree node */ size_t nod_sz; /* [nbr] Node size */ int arg_idx; /* [idx] Argument index */ /* Operator node requires space for token and arguments */ nod_sz=sizeof(opr_nod_sct)+(arg_nbr-1)*sizeof(nodeType *); nod=(nodeType *)nco_malloc(nod_sz); /* Copy information into new node */ nod->nod_typ=typ_opr; /* [enm] Node type */ nod->opr.opr_tkn=opr_tkn; /* [enm] Operator token */ nod->opr.arg_nbr=arg_nbr; /* [nbr] Number of arguments */ /* Begin variable argument list access */ va_start(arg_lst,arg_nbr); for(arg_idx=0;arg_idxopr.arg_nbr;arg_idx++) nod->opr.arg[arg_idx]=va_arg(arg_lst,nodeType); /* NB: Nie02 p. 27 has typo in va_arg() */ /* End variable argument list access */ va_end(arg_lst); return nod; } /* end opr_ctl() */ void freeNode /* [fnc] Free syntax tree node Nie02 freeNode() */ (nodeType *nod) /* I/O [sct] Syntax tree node to free */ { /* Purpose: Free syntax tree node */ int arg_idx; /* [idx] Argument index */ if(!nod) return; /* Operator nodes have copies of arguments. Free these first. */ if(nod->nod_typ == typ_opr){ /* Recursive call to freeNode continue until statement is reduced */ for(arg_idx=0;arg_idxopr.arg_nbr;arg_idx++) freeNode(nod->opr.arg+arg_idx); /* Nie02 p. 28 has typo and passes node not node pointer */ } /* endif */ /* Free node itself */ nod=(nodeType *)nco_free(nod); return; /* 20050109: fxm added return to void function to squelch erroneous gcc-3.4.2 warning */ } /* end freeNode() */ /* End User Functions section */ ./nco-4.4.2/src/nco/nco_scl_utl.h0000644000674300045400000000515312260451232016001 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_scl_utl.h,v 1.24 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Scalar utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_scl_utl.h" *//* Scalar utilities */ #ifndef NCO_SCL_UTL_H #define NCO_SCL_UTL_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, exit */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_cnf_typ.h" /* Conform variable types */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_mmr.h" /* Memory management */ #include "nco_var_utl.h" /* Variable utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ var_sct * /* O [sct] netCDF variable structure representing val */ scl_dbl_mk_var /* [fnc] Convert scalar double into netCDF variable */ (const double val); /* I [frc] Double precision value to turn into netCDF variable */ var_sct * /* O [sct] Output netCDF variable structure representing val */ scl_mk_var /* [fnc] Convert scalar value of any type into NCO variable */ (val_unn val, /* I [frc] Scalar value to turn into netCDF variable */ const nc_type val_typ); /* I [enm] netCDF type of value */ var_sct * /* O [sct] Output NCO variable structure representing value */ scl_ptr_mk_var /* [fnc] Convert void pointer to scalar of any type into NCO variable */ (const ptr_unn val_ptr_unn, /* I [unn] Scalar value to turn into netCDF variable */ const nc_type val_typ); /* I [enm] netCDF type of existing pointer/value */ double /* O [frc] Double precision representation of var->val.?p[0] */ ptr_unn_2_scl_dbl /* [fnc] Convert first element of NCO variable to a scalar double */ (const ptr_unn val, /* I [sct] Pointer union to convert to scalar double */ const nc_type type); /* I [enm] Type of values pointed to by pointer union */ scv_sct /* O [sct] Scalar value structure representing val */ ptr_unn_2_scv /* [fnc] Convert ptr_unn to scalar value structure */ (const nc_type type, /* I [enm] netCDF type of value */ ptr_unn val); /* I [sct] Value to convert to scalar value structure */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_SCL_UTL_H */ ./nco-4.4.2/src/nco/nco_cnv_arm.c0000644000674300045400000001477612260451231015766 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnv_arm.c,v 1.35 2013/12/31 05:14:01 zender Exp $ */ /* Purpose: ARM conventions, e.g., http://www.arm.gov/data/time.stm */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_cnv_arm.h" /* ARM conventions */ nco_bool /* O [flg] File obeys ARM conventions */ nco_cnv_arm_inq /* O [fnc] Check if file obeys ARM conventions */ (const int nc_id) /* I [id] netCDF file ID */ { /* Purpose: Check whether file adheres to ARM time format defined http://www.arm.gov/data/time.stm */ nco_bool CNV_ARM; const char time_sng[]="time"; /* CEWI */ const char base_time_sng[]="base_time"; /* CEWI */ const char time_offset_sng[]="time_offset"; /* CEWI */ int time_dmn_id; int base_time_id; int time_offset_id; int rcd=NC_NOERR; /* [rcd] Return code */ /* Look for ARM file signature */ rcd+=nco_inq_dimid_flg(nc_id,time_sng,&time_dmn_id); rcd+=nco_inq_varid_flg(nc_id,base_time_sng,&base_time_id); rcd+=nco_inq_varid_flg(nc_id,time_offset_sng,&time_offset_id); /* All three IDs must be valid to handle ARM format */ if(rcd != NC_NOERR){ CNV_ARM=False; }else{ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: CONVENTION File convention is DOE ARM\n",nco_prg_nm_get()); CNV_ARM=True; } /* end else */ return CNV_ARM; } /* end nco_cnv_arm_inq */ double /* O [s] base_time + current time_offset */ nco_cnv_arm_time_mk /* [fnc] Return time corresponding to current time offset */ (const int nc_id, /* I [id] netCDF file ID */ const double time_offset) /* I [s] Current time offset */ { /* NB: nco_cnv_arm_time_mk() with same nc_id contains OpenMP critical region */ /* Purpose: Return time corresponding to current time offset */ double arm_time; int base_time_id; int rcd=NC_NOERR; /* [rcd] Return code */ nco_int base_time; /* Find base_time variable (NC_INT: base UNIX time of file) */ rcd=nco_inq_varid_flg(nc_id,"base_time",&base_time_id); if(rcd != NC_NOERR){ (void)fprintf(stderr,"%s: WARNING ARM file does not have variable \"base_time\", exiting nco_cnv_arm_time_mk()...\n",nco_prg_nm_get()); return -1; } /* end if */ { /* begin potential OpenMP critical */ /* Block is critical/thread-safe for identical/distinct in_id's */ (void)nco_get_var1(nc_id,base_time_id,0L,&base_time,NC_INT); } /* end potential OpenMP critical */ arm_time=base_time+time_offset; return arm_time; } /* end nco_cnv_arm_time_mk() */ void nco_cnv_arm_time_install /* [fnc] Add time variable to concatenated ARM files */ (const int nc_id, /* I [id] netCDF file ID */ const nco_int base_time_srt, /* I [s] base_time of first input file */ const int dfl_lvl) /* I [enm] Deflate level [0..9] */ { /* NB: nco_cnv_arm_time_install() contains OpenMP critical region */ /* Purpose: Add time variable to concatenated ARM files */ const char att_long_name[]="UNIX time"; const char att_units[]="seconds since 1970/01/01 00:00:00.00"; const char long_name_sng[]="long_name"; /* CEWI */ const char time_sng[]="time"; /* CEWI */ const char units_sng[]="units"; /* CEWI */ double *time_offset; int rcd=NC_NOERR; /* [rcd] Return code */ int time_id; int time_dmn_id; int time_offset_id; long idx; long srt=0L; long cnt; /* Synchronize output file */ (void)nco_sync(nc_id); /* Find time_offset variable */ rcd=nco_inq_varid_flg(nc_id,"time_offset",&time_offset_id); if(rcd != NC_NOERR){ (void)fprintf(stderr,"%s: WARNING ARM file does not have variable \"time_offset\", exiting nco_cnv_arm_time_install()...\n",nco_prg_nm_get()); return; } /* endif */ /* See if time variable already exists */ rcd=nco_inq_varid_flg(nc_id,time_sng,&time_id); if(rcd == NC_NOERR){ (void)fprintf(stderr,"%s: WARNING ARM file already has variable \"time\"\n",nco_prg_nm_get()); return; } /* endif */ /* See if time dimension exists */ rcd=nco_inq_dimid_flg(nc_id,time_sng,&time_dmn_id); if(rcd != NC_NOERR){ (void)fprintf(stderr,"%s: WARNING ARM file does not have dimension \"time\"\n",nco_prg_nm_get()); return; } /* endif */ /* Get dimension size */ (void)nco_inq_dimlen(nc_id,time_dmn_id,&cnt); /* If the time coordinate does not already exist, create it */ time_offset=(double *)nco_malloc(cnt*nco_typ_lng(NC_DOUBLE)); { /* begin potential OpenMP critical */ /* Block is critical/thread-safe for identical/distinct in_id's */ (void)nco_get_vara(nc_id,time_offset_id,&srt,&cnt,(void *)time_offset,NC_DOUBLE); } /* end potential OpenMP critical */ for(idx=0L;idx= 0) (void)nco_def_var_deflate(nc_id,time_id,(int)True,(int)True,dfl_lvl); /* Add attributes for time variable */ (void)nco_put_att(nc_id,time_id,units_sng,NC_CHAR,(long int)(strlen(att_units)+1UL),(const void *)att_units); (void)nco_put_att(nc_id,time_id,long_name_sng,NC_CHAR,(long int)(strlen(att_long_name)+1UL),(const void *)att_long_name); /* Catenate time-stamped reminder onto "history" global attribute */ (void)nco_hst_att_cat(nc_id,"ncrcat added variable time=base_time+time_offset"); /* Take file out of define mode */ (void)nco_enddef(nc_id); /* Block is always critical */ { /* begin OpenMP critical */ /* Write time variable */ (void)nco_put_vara(nc_id,time_id,&srt,&cnt,(void *)time_offset,NC_DOUBLE); } /* end OpenMP critical */ /* Free time_offset buffer */ time_offset=(double *)nco_free(time_offset); return; /* 20050109: fxm added return to void function to squelch erroneous gcc-3.4.2 warning */ } /* end nco_cnv_arm_time_install */ nco_int /* O [s] Value of base_time variable */ nco_cnv_arm_base_time_get /* [fnc] Get base_time variable from ARM file */ (const int nc_id) /* I [id] netCDF file ID */ { /* NB: nco_cnv_arm_base_time_get() with same nc_id contains OpenMP critical region */ /* Purpose: Get base_time variable from ARM file */ int base_time_id; nco_int base_time; (void)nco_inq_varid(nc_id,"base_time",&base_time_id); /* Block is critical/thread-safe for identical/distinct in_id's */ { /* begin potential OpenMP critical */ (void)nco_get_var1(nc_id,base_time_id,0L,&base_time,NC_INT); } /* end potential OpenMP critical */ return base_time; } /* end nco_cnv_arm_base_time_get */ ./nco-4.4.2/src/nco/nco_omp.h0000644000674300045400000000377212260451232015134 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_omp.h,v 1.31 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: OpenMP utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_omp.h" *//* OpenMP utilities */ #ifndef NCO_OMP_H #define NCO_OMP_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, getenv, exit */ #include /* strcmp() */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ #ifdef _OPENMP # include /* OpenMP pragmas */ #endif /* !_OPENMP */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef _OPENMP /* OpenMP is not available with this compiler Prototype harmless stub routines for Uni-Processor (UP) code These stubs reduce pre-processor proliferation */ int omp_get_dynamic(void); int omp_get_max_threads(void); int omp_get_nested(void); int omp_get_num_procs(void); int omp_get_num_threads(void); int omp_get_thread_num(void); int omp_in_parallel(void); void omp_set_dynamic(int dynamic_threads); void omp_set_nested(int nested); void omp_set_num_threads(int num_threads); #endif /* _OPENMP */ int /* O [nbr] Thread number */ nco_openmp_ini /* [fnc] Initialize OpenMP threading environment */ (int thr_nbr); /* I [nbr] Thread number */ int /* O [enm] Return code */ nco_var_prc_crr_prn /* [fnc] Print name of current variable */ (const int idx, /* I [idx] Index of current variable */ const char * const var_nm); /* I [sng] Variable name */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_OMP_H */ ./nco-4.4.2/src/nco/nco_rth_flt.h0000644000674300045400000001301112260451232015766 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_rth_flt.h,v 1.51 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Float-precision arithmetic, MSVC macros */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_rth_flt.h" *//* Float-precision arithmetic, MSVC macros */ #ifndef NCO_RTH_FLT_H #define NCO_RTH_FLT_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* sin cos cos sin 3.14159 */ #ifdef _MSC_VER # include /* isfinite(), isinf(), isnan() */ #endif /* !_MSC_VER */ /* fxm stdio only needed for TODO ncap57 on UNIX */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* time() seed for random()/rand() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Home-brewed functions like rnd_nbr() need no pre-processor token protection since they will never be defined in system-supplied libraries/headers */ double /* O [frc] Random fraction in [0,1] */ rnd_nbr /* [fnc] Generate random fraction in [0,1] */ (double x); /* I [frc] Immaterial */ float /* O [frc] Random fraction in [0,1] */ rnd_nbrf /* [fnc] Generate random fraction in [0,1] */ (float); /* I [frc] Immaterial */ /* Remaining definitions are system-dependent */ /* MSVC does not define isnormal(), isnan(), isinf(), isfinite() http://stackoverflow.com/questions/2249110/how-do-i-make-a-portable-isnan-isinf-function */ #ifdef _MSC_VER /* isnormal() may be in MSVC 2012 with header amp_math.h. fxm: verify and utilize if true. */ # define isnormal /* Following functions are in MSVC 2008+ and require float.h */ # define isnan(x) _isnan(x) # define isfinite(x) _finite(x) # define isinf(x) (!_finite(x)) #endif /* !_MSC_VER */ #ifdef _MSC_VER /* _snprintf() is in MSVC 2005+ and requires stdio.h */ # define snprintf _snprintf #endif /* !_MSC_VER */ /* MSVC does not define lround(), lroundf(), lroundl(), llround(), llroundf(), llroundl(): Round to nearest integer, halfway cases round away from 0 MSVC does not define lrint(), lrintf(), lrintl(), llrint(), llrintf(), llrintl(): Round to nearest even integer, raise exceptions Summary of POSIX, ISO, and MSVC math intrinsics at http://www.johndcook.com/math_h.html */ #ifdef _MSC_VER long long int llrint(double x); long long int llrintf(float x); long int lrint(double x); long int lrintf(float x); long long int llround(double x); long long int llroundf(float x); long int lround(double x); long int lroundf(float x); #endif /* !_MSC_VER */ #ifdef _MSC_VER /* 20130227: Hard-code these because MSVC does not have access to config.h Lack of double-precision version implies lack of single-precision version Hence single-precision ("float") tokens are set in double-precision prototypes below */ # define NEED_RINT # define NEED_NEARBYINT # define NEED_ROUND # define NEED_TRUNC #endif /* !_MSC_VER */ #ifdef NEED_RINT # define NEED_RINTF double /* O [frc] Rounded value of x */ rint /* [fnc] Round x to nearest even integer, raise exceptions */ (double x); /* I [frc] Value to round */ #endif /* !NEED_RINT */ #ifdef NEED_NEARBYINT # define NEED_NEARBYINTF double /* O [frc] Rounded value of x */ nearbyint /* [fnc] Round x to nearest even integer, do not raise exceptions */ (double x); /* I [frc] Value to round */ #endif /* !NEED_NEARBYINT */ #ifdef NEED_ROUND # define NEED_ROUNDF double /* O [frc] Rounded value of x */ round /* [fnc] Round x to nearest integer, half-way cases round away from zero */ (double x); /* I [frc] Value to round */ #endif /* !NEED_ROUND */ #ifdef NEED_TRUNC # define NEED_TRUNCF double /* O [frc] Truncated value of x */ trunc /* [fnc] Truncate x to nearest integer not larger in absolute value */ (double x); /* I [frc] Value to truncate */ #endif /* !NEED_TRUNC */ #if !defined(HPUX) && !defined(__INTEL_COMPILER) && !defined(LINUXAMD64) /* Math float prototypes required by AIX, Solaris, but not by Linux, IRIX 20040708: HP-UX does not like these 20090223: Intel compilers version 11.x complains about these 20130724: Yellowstone chokes on these when compiling ncap2 with g++ */ /* Basic math: acos, asin, atan, atan2, cos, exp, fabs, log, log10, pow, sin, sqrt, tan */ float acosf(float); float asinf(float); float atanf(float); float atan2f(float,float); float cosf(float); float expf(float); float fabsf(float); float logf(float); float log10f(float); float powf(float,float); float sinf(float); float sqrtf(float); float tanf(float); /* Advanced math: erf, erfc, gamma, rnd_nbr */ float erff(float); float erfcf(float); float gammaf(float); /* Hyperbolic trigonometric: acosh, asinh, atanh, cosh, sinh, tanh */ float acoshf(float); float asinhf(float); float atanhf(float); float coshf(float); float sinhf(float); float tanhf(float); /* Basic Rounding: ceil, floor */ float ceilf(float); float floorf(float); /* Advanced Rounding: nearbyint, rint, round, trunc */ float nearbyintf(float); float rintf(float); float roundf(float); float truncf(float); #endif /* !defined(HPUX) && !defined(__INTEL_COMPILER) && !defined(LINUXAMD64) */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_RTH_FLT_H */ ./nco-4.4.2/src/nco/ncrename.c0000644000674300045400000007527312274544336015307 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncrename.c,v 1.191 2014/02/05 23:27:26 pvicente Exp $ */ /* ncrename -- netCDF renaming operator */ /* Purpose: Rename dimensions, variables, and attributes of a netCDF file */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncrename -O -g g1,obama ~/nco/data/in_grp.nc ~/foo.nc ncrename -O -a Conventions,Geneva ~/nco/data/in.nc ~/foo.nc ncrename -O -a HDFEOSVersion,Geneva ${DATA}/hdf/MOD10CM.A2007001.005.2007108111758.hdf ~/foo.nc ncrename -O -d old_dim1,new_dim1 -v old_var1,new_var1 -v old_var2,new_var2 -a old_att1,new_att1 ~/nco/data/in.nc ~/foo.nc ncrename -O -d lon,new_lon -v scalar_var,new_scalar_var -a long_name,new_long_name ~/nco/data/in.nc ~/foo.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { #ifndef __GNUG__ extern int errno; /* [enm] Error code in errno.h */ #endif /* __GNUG__ */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool IS_GLB_GRP_ATT=False; /* [flg] Attribute is Global or Group attribute */ nco_bool FL_OUT_NEW=False; nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option a */ char **fl_lst_in; char *att_rnm_arg[NC_MAX_ATTRS]; char *cmd_ln; char *dmn_rnm_arg[NC_MAX_DIMS]; char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *grp_rnm_arg[NC_MAX_DIMS]; char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char *var_rnm_arg[NC_MAX_VARS]; char trv_pth[]="/"; /* [sng] Root path of traversal tree */ char var_nm[NC_MAX_NAME+1]; const char * const CVS_Id="$Id: ncrename.c,v 1.191 2014/02/05 23:27:26 pvicente Exp $"; const char * const CVS_Revision="$Revision: 1.191 $"; const char * const opt_sht_lst="a:D:d:g:hl:Oo:p:rv:-:"; const char dlm_chr='@'; /* Character delimiting variable from attribute name */ const char opt_chr='.'; /* Character indicating presence of following variable/dimension/attribute in file is optional */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ extern char *optarg; extern int optind; int abb_arg_nbr=0; int fl_nbr=0; int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_att_rnm=0; /* Option a. NB: nbr_att_rnm gets incremented */ int nbr_dmn_rnm=0; /* Option d. NB: nbr_dmn_rnm gets incremented */ int nbr_grp_rnm=0; /* Option g. NB: nbr_grp_rnm gets incremented */ int nbr_var_rnm=0; /* Option v. NB: nbr_var_rnm gets incremented */ int nc_id; int grp_id; int opt; int rcd=NC_NOERR; /* [rcd] Return code */ rnm_sct *var_rnm_lst=NULL_CEWI; rnm_sct *dmn_rnm_lst=NULL_CEWI; rnm_sct *grp_rnm_lst=NULL_CEWI; rnm_sct *att_rnm_lst=NULL_CEWI; size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ trv_tbl_sct *trv_tbl; /* [lst] Traversal table */ static struct option opt_lng[] = { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"attribute",required_argument,0,'a'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"group",required_argument,0,'g'}, {"grp",required_argument,0,'g'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"revision",no_argument,0,'r'}, {"variable",required_argument,0,'v'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; int opt_idx=0; /* Index of current long option into opt_lng array */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Copy argument for later processing */ att_rnm_arg[nbr_att_rnm]=(char *)strdup(optarg); nbr_att_rnm++; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy argument for later processing */ dmn_rnm_arg[nbr_dmn_rnm]=(char *)strdup(optarg); nbr_dmn_rnm++; break; case 'g': /* Copy argument for later processing */ grp_rnm_arg[nbr_grp_rnm]=(char *)strdup(optarg); nbr_grp_rnm++; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 'v': /* Copy argument for later processing */ var_rnm_arg[nbr_var_rnm]=(char *)strdup(optarg); nbr_var_rnm++; break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); if(fl_out) FL_OUT_NEW=True; else fl_out=(char *)strdup(fl_lst_in[0]); if(!nbr_var_rnm && !nbr_att_rnm && !nbr_grp_rnm && !nbr_dmn_rnm){ (void)fprintf(stdout,"%s: ERROR must specify something to rename\n",nco_prg_nm); nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end if */ /* Make uniform list of user-specified rename structures */ if(nbr_att_rnm > 0) att_rnm_lst=nco_prs_rnm_lst(nbr_att_rnm,att_rnm_arg); if(nbr_dmn_rnm > 0) dmn_rnm_lst=nco_prs_rnm_lst(nbr_dmn_rnm,dmn_rnm_arg); if(nbr_grp_rnm > 0) grp_rnm_lst=nco_prs_rnm_lst(nbr_grp_rnm,grp_rnm_arg); if(nbr_var_rnm > 0) var_rnm_lst=nco_prs_rnm_lst(nbr_var_rnm,var_rnm_arg); /* We have final list of variables, dimensions, and attributes to rename */ /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(FL_OUT_NEW){ /* Obtain user consent, if needed, to overwrite output file (or die trying) */ if(!FORCE_OVERWRITE) nco_fl_overwrite_prm(fl_out); /* Copy input file to output file and then search through output, changing names on the fly. This avoids possible XDR translation performance penalty of copying each variable with netCDF. */ (void)nco_fl_cp(fl_in,fl_out); /* Ensure output file is user/owner-writable */ (void)nco_fl_chmod(fl_out); } /* end if FL_OUT_NEW */ /* Open file enabled for writing. Place file in define mode for renaming. */ if(RAM_OPEN) md_open=NC_WRITE|NC_DISKLESS; else md_open=NC_WRITE; rcd+=nco_fl_open(fl_out,md_open,&bfr_sz_hnt,&nc_id); (void)nco_redef(nc_id); /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; /* Initialize traversal table */ trv_tbl_init(&trv_tbl); /* Construct GTT (Group Traversal Table), check -v and -g input names and create extraction list*/ (void)nco_bld_trv_tbl(nc_id,trv_pth,(int)0,NULL,(int)0,NULL,False,False,NULL,(int)0,NULL,(int) 0,False,False,False,True,NULL,trv_tbl); /* Loop input variable names */ for(int idx_var=0;idx_varnco_typ == nco_obj_typ_var && is_opt == True){ (void)nco_inq_grp_full_ncid(nc_id,obj_trv->grp_nm_fll,&grp_id); /* Use the pair group ID/relative object name found (instead of var_rnm_lst[idx_var].old_nm) */ rcd=nco_inq_varid(grp_id,obj_trv->nm,&var_rnm_lst[idx_var].id); (void)nco_rename_var(grp_id,var_rnm_lst[idx_var].id,var_rnm_lst[idx_var].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed variable \'%s\' to \'%s\'\n",nco_prg_nm,var_rnm_lst[idx_var].old_nm+1L,var_rnm_lst[idx_var].new_nm); /* Optional case with no object found */ }else if (obj_trv == NULL) { (void)fprintf(stdout,"%s: WARNING Variable \'%s\' not present in %s, skipping it.\n",nco_prg_nm,var_rnm_lst[idx_var].old_nm+1L,fl_in); /* Reset error code */ rcd=NC_NOERR; /* Variable name does not contain opt_chr so variable presence is required */ }else if (obj_trv && obj_trv->nco_typ == nco_obj_typ_var && is_opt == False){ (void)nco_inq_grp_full_ncid(nc_id,obj_trv->grp_nm_fll,&grp_id); /* Use the pair group ID/relative object name found (instead of var_rnm_lst[idx_var].old_nm) */ rcd=nco_inq_varid(grp_id,obj_trv->nm,&var_rnm_lst[idx_var].id); (void)nco_rename_var(grp_id,var_rnm_lst[idx_var].id,var_rnm_lst[idx_var].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed variable \'%s\' to \'%s\'\n",nco_prg_nm,var_rnm_lst[idx_var].old_nm,var_rnm_lst[idx_var].new_nm); } /* Variable name does not contain opt_chr so variable presence is required */ } /* Loop input variable names */ /* Loop input group names */ for(int idx_grp=0;idx_grpnco_typ == nco_obj_typ_grp && is_opt == True){ (void)nco_inq_grp_full_ncid(nc_id,obj_trv->grp_nm_fll,&grp_id); (void)nco_rename_grp(grp_id,grp_rnm_lst[idx_grp].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed group \'%s\' to \'%s\'\n",nco_prg_nm,grp_rnm_lst[idx_grp].old_nm+1L,grp_rnm_lst[idx_grp].new_nm); /* Optional case with no object found */ }else if (obj_trv == NULL){ (void)fprintf(stdout,"%s: WARNING Group \'%s\' not present in %s, skipping it.\n",nco_prg_nm,grp_rnm_lst[idx_grp].old_nm+1L,fl_in); /* Reset error code */ rcd=NC_NOERR; /* Group name does not contain opt_chr so group presence is required */ }else if (obj_trv && obj_trv->nco_typ == nco_obj_typ_grp && is_opt == False){ (void)nco_inq_grp_full_ncid(nc_id,obj_trv->grp_nm_fll,&grp_id); (void)nco_rename_grp(grp_id,grp_rnm_lst[idx_grp].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed group \'%s\' to \'%s\'\n",nco_prg_nm,grp_rnm_lst[idx_grp].old_nm,grp_rnm_lst[idx_grp].new_nm); } /* Group name does not contain opt_chr so group presence is required */ } /* Loop input group names */ /* Loop input dimension names */ for(int idx_dmn=0;idx_dmngrp_nm_fll,&grp_id); /* Use the pair group ID/relative dimension name found (instead of dmn_rnm_lst[idx_dmn].old_nm) */ rcd=nco_inq_dimid(grp_id,dmn_trv->nm,&dmn_rnm_lst[idx_dmn].id); (void)nco_rename_dim(grp_id,dmn_rnm_lst[idx_dmn].id,dmn_rnm_lst[idx_dmn].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed dimension \'%s\' to \'%s\'\n",nco_prg_nm,dmn_rnm_lst[idx_dmn].old_nm+1L,dmn_rnm_lst[idx_dmn].new_nm); /* Optional case with no dimension found */ }else if (dmn_trv == NULL) { (void)fprintf(stdout,"%s: WARNING Dimension \'%s\' not present in %s, skipping it.\n",nco_prg_nm,dmn_rnm_lst[idx_dmn].old_nm+1L,fl_in); /* Reset error code */ rcd=NC_NOERR; /* ! Optional case */ }else if (dmn_trv && is_opt == False){ (void)nco_inq_grp_full_ncid(nc_id,dmn_trv->grp_nm_fll,&grp_id); /* Use the pair group ID/relative dimension name found (instead of dmn_rnm_lst[idx_dmn].old_nm) */ rcd=nco_inq_dimid(grp_id,dmn_trv->nm,&dmn_rnm_lst[idx_dmn].id); (void)nco_rename_dim(grp_id,dmn_rnm_lst[idx_dmn].id,dmn_rnm_lst[idx_dmn].new_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed dimension \'%s\' to \'%s\'\n",nco_prg_nm,dmn_rnm_lst[idx_dmn].old_nm,dmn_rnm_lst[idx_dmn].new_nm); } /* ! Optional case */ } /* Loop input dimension names */ /* Loop input attribute names */ for(int idx_att=0;idx_attnco_typ == nco_obj_typ_grp){ var_id=NC_GLOBAL; } /* Object found that matches "var_nm" */ if (trv_obj || IS_GLB_GRP_ATT){ /* If object found get group ID, else groud ID is root (cases of "global") */ if (trv_obj) (void)nco_inq_grp_full_ncid(nc_id,trv_obj->grp_nm_fll,&grp_id); else grp_id=nc_id; /* Get var_id of variable */ if(IS_GLB_GRP_ATT){ (void)fprintf(stdout,"%s: INFO Assuming \"%s\" refers to a Global or Group attribute\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm); var_id=NC_GLOBAL; }else{ /* !IS_GLB_GRP_ATT */ if(var_nm[0] == opt_chr){ rcd=nco_inq_varid_flg(grp_id,var_nm+1L,&var_id); if(rcd != NC_NOERR){ (void)fprintf(stdout,"%s: WARNING Variable \'%s\' not present in %s, skipping it.\n",nco_prg_nm,var_nm+1L,fl_in); /* Reset error code */ rcd=NC_NOERR; /* Optional variable not found, continue to next attribute in list */ continue; } /* end if */ }else{ /* Variable name does not contain opt_chr so variable presence is required */ /* Get ID only if object is variable (not group). NB: use relative name found */ if(trv_obj->nco_typ == nco_obj_typ_var){ rcd=nco_inq_varid(grp_id,trv_obj->nm,&var_id); } /* Get ID only if object is variable (not group) */ } /* end if */ } /* !IS_GLB_GRP_ATT */ if(rcd == NC_NOERR){ if(att_rnm_lst[idx_att].old_nm[0] == opt_chr){ /* Preceding opt_chr means attribute need not be present */ rcd=nco_inq_attid_flg(grp_id,var_id,att_rnm_lst[idx_att].old_nm+1L,&att_rnm_lst[idx_att].id); if(rcd == NC_NOERR){ (void)nco_rename_att(grp_id,var_id,att_rnm_lst[idx_att].old_nm+1L,att_rnm_lst[idx_att].new_nm); nbr_rnm++; if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed attribute \'%s\' to \'%s\' for variable \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm+1L,att_rnm_lst[idx_att].new_nm,(var_nm[0] == opt_chr ? var_nm+1L : var_nm)); }else{ (void)fprintf(stdout,"%s: WARNING Attribute \'%s\' not present in variable \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm+1L,(var_nm[0] == opt_chr ? var_nm+1L : var_nm)); } /* endelse */ }else{ /* Attribute must be present */ rcd=nco_inq_attid(grp_id,var_id,att_rnm_lst[idx_att].old_nm,&att_rnm_lst[idx_att].id); if(rcd == NC_NOERR){ (void)nco_rename_att(grp_id,var_id,att_rnm_lst[idx_att].old_nm,att_rnm_lst[idx_att].new_nm); nbr_rnm++; if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed attribute \'%s\' to \'%s\' for variable \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm,att_rnm_lst[idx_att].new_nm,(var_nm[0] == opt_chr ? var_nm+1L : var_nm)); } /* endif attribute is present */ } /* endelse attribute must be present */ }else{ /* variable not present */ (void)fprintf(stdout,"%s: WARNING variable \'%s\' not present in %s\n",nco_prg_nm,var_nm,fl_in); } /* variable not present */ /* end if renaming single variable */ } /* Match variable by name */ }else{ /* ...or rename attribute for all variables... */ /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ (void)nco_inq_grp_full_ncid(nc_id,trv_tbl->lst[idx_tbl].grp_nm_fll,&grp_id); /* We are in NC_GLOBAL zone if group */ if (trv_tbl->lst[idx_tbl].nco_typ == nco_obj_typ_grp){ var_id=NC_GLOBAL; }else { (void)nco_inq_varid(grp_id,trv_tbl->lst[idx_tbl].nm,&var_id); } if(att_rnm_lst[idx_att].old_nm[0] == opt_chr){ /* Rename attribute if variable contains attribute else do nothing */ rcd=nco_inq_attid_flg(grp_id,var_id,att_rnm_lst[idx_att].old_nm+1L,&att_rnm_lst[idx_att].id); if(rcd == NC_NOERR){ (void)nco_rename_att(grp_id,var_id,att_rnm_lst[idx_att].old_nm+1L,att_rnm_lst[idx_att].new_nm); nbr_rnm++; /* Inform user which variable had attribute renamed */ if(var_id > NC_GLOBAL){ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed attribute \'%s\' to \'%s\' for variable \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm+1L,att_rnm_lst[idx_att].new_nm,var_nm); }else{ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed global or group attribute \'%s\' to \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm+1L,att_rnm_lst[idx_att].new_nm); } /* end else */ }else{ /* end if attribute was found */ /* Reset error code */ rcd=NC_NOERR; } /* end else */ }else{ /* !opt_chr */ /* Rename attribute or die trying */ rcd=nco_inq_attid_flg(grp_id,var_id,att_rnm_lst[idx_att].old_nm,&att_rnm_lst[idx_att].id); if(rcd == NC_NOERR){ (void)nco_rename_att(grp_id,var_id,att_rnm_lst[idx_att].old_nm,att_rnm_lst[idx_att].new_nm); nbr_rnm++; /* Inform user which variable had attribute renamed */ if(var_id > NC_GLOBAL){ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed attribute \'%s\' to \'%s\' for variable \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm,att_rnm_lst[idx_att].new_nm,var_nm); }else{ IS_GLB_GRP_ATT=True; /* [flg] Attribute is Global or Group attribute */ if(IS_GLB_GRP_ATT) (void)fprintf(stdout,"%s: INFO found and renamed global or group attribute \'%s\' so not requiring its presence in every variable.\n",nco_prg_nm_get(),att_rnm_lst[idx_att].old_nm); if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stdout,"%s: Renamed global or group attribute \'%s\' to \'%s\'\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm,att_rnm_lst[idx_att].new_nm); } /* end else */ }else{ /* !NC_NOERR */ /* Reset error code or print informative message and die */ if(IS_GLB_GRP_ATT){ /* Forgive omission of period for global/group attributes. Users aren't perfect :) */ rcd=NC_NOERR; }else{ /* !IS_GLB_GRP_ATT */ (void)fprintf(stdout,"%s: ERROR User specified that presence of attribute \'%s\' is required. However, the %s%s does not contain it. HINT: If attribute presence is intended to be optional, then prefix attribute name with the period character \'%c\', e.g., %catt_nm. With this syntax %s would succeed even if no variables or groups contained the attribute. If attribute is intended to be renamed only in a specific variable, then prepend the variable name plus an at-sign \'%c\' to the attribute name, e.g., var_nm%catt_nm. If attribute presence is required only for global or group attributes, then prefix attribute name with \"global\" and an at-sign, e.g., global%catt_nm.\n",nco_prg_nm_get(),att_rnm_lst[idx_att].old_nm,(var_id > NC_GLOBAL) ? "variable " : "root group",(var_id > NC_GLOBAL) ? var_nm : "",opt_chr,opt_chr,nco_prg_nm_get(),dlm_chr,dlm_chr,dlm_chr); /* Exit now rather than completing variable loop and printing lengthy error message above each iteration */ nco_err_exit(rcd,"main"); } /* !IS_GLB_GRP_ATT */ } /* !NC_NOERR */ } /* !opt_chr */ } /* Loop table */ } /* end if renaming attribute for all variables */ /* See to it that any mandatory renaming was performed, else abort */ if(nbr_rnm == 0){ if(att_rnm_lst[idx_att].old_nm[0] == opt_chr){ (void)fprintf(stdout,"%s: WARNING Attribute \'%s\' not renamed because not found in searched variable(s)\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm+1L); }else{ (void)fprintf(stdout,"%s: ERROR Attribute \'%s\' not present in %s, aborting.\n",nco_prg_nm,att_rnm_lst[idx_att].old_nm,fl_in); nco_exit(EXIT_FAILURE); } /* end else */ } /* nbr_rnm */ } /* end loop over attributes to rename */ /* Catenate timestamped command line to "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(nc_id,cmd_ln); #ifdef _OPENMP /* fxm: hack to get libxlsmp library linked in */ (void)omp_in_parallel(); #endif /* !_OPENMP */ /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(nc_id); }else{ (void)nco__enddef(nc_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Close the open netCDF file */ nco_close(nc_id); /* Remove local copy of file */ if(FL_RTR_RMT_LCN && RM_RMT_FL_PST_PRC) (void)nco_fl_rm(fl_in); /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* ncrename-specific memory */ for(int idx=0;idx 0) att_rnm_lst=(rnm_sct *)nco_free(att_rnm_lst); if(nbr_dmn_rnm > 0) dmn_rnm_lst=(rnm_sct *)nco_free(dmn_rnm_lst); if(nbr_grp_rnm > 0) grp_rnm_lst=(rnm_sct *)nco_free(grp_rnm_lst); if(nbr_var_rnm > 0) var_rnm_lst=(rnm_sct *)nco_free(var_rnm_lst); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); (void)trv_tbl_free(trv_tbl); } /* !flg_cln */ /* End timer */ ddra_info.tmr_flg=nco_tmr_end; /* [enm] Timer flag */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); if(rcd != NC_NOERR) nco_err_exit(rcd,"main"); nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/nco_var_utl.c0000644000674300045400000024766412277324011016024 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_var_utl.c,v 1.357 2014/02/14 05:22:17 zender Exp $ */ /* Purpose: Variable utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_var_utl.h" /* Variable utilities */ void nco_cpy_var_val /* [fnc] Copy variable from input to output file, no limits */ (const int in_id, /* I [id] netCDF input file ID */ const int out_id, /* I [id] netCDF output file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ const char *var_nm) /* I [sng] Variable name */ { /* NB: nco_cpy_var_val() contains OpenMP critical region */ /* Purpose: Copy single variable from input netCDF file to output netCDF file Routine does not account for user-specified limits, it just copies what it finds Routine copies variable-by-variable, old-style, called only by ncks */ const char fnc_nm[]="nco_cpy_var_val()"; /* [sng] Function name */ int *dmn_id; int dmn_nbr; int idx; int nbr_dmn_in; int nbr_dmn_out; int var_in_id; int var_out_id; long *dmn_cnt; long *dmn_sz; long *dmn_srt; long var_sz=1L; nc_type var_typ; void *void_ptr; /* Get var_id for requested variable from both files */ (void)nco_inq_varid(in_id,var_nm,&var_in_id); (void)nco_inq_varid(out_id,var_nm,&var_out_id); /* Get type and number of dimensions for variable */ (void)nco_inq_var(out_id,var_out_id,(char *)NULL,&var_typ,&nbr_dmn_out,(int *)NULL,(int *)NULL); (void)nco_inq_var(in_id,var_in_id,(char *)NULL,&var_typ,&nbr_dmn_in,(int *)NULL,(int *)NULL); if(nbr_dmn_out != nbr_dmn_in){ (void)fprintf(stderr,"%s: ERROR attempt to write %d-dimensional input variable %s to %d-dimensional space in output file\nHINT: When using -A (append) option, all appended variables must be the same rank in the input file as in the output file. The ncwa operator is useful at ridding variables of extraneous (size = 1) dimensions. See how at http://nco.sf.net/nco.html#ncwa\nIf you wish to completely replace the existing output file definition and values of the variable %s by those in the input file, then first remove %s from the output file using, e.g., ncks -x -v %s. See more on subsetting at http://nco.sf.net/nco.html#sbs",nco_prg_nm_get(),nbr_dmn_in,var_nm,nbr_dmn_out,var_nm,var_nm,var_nm); nco_exit(EXIT_FAILURE); } /* endif */ dmn_nbr=nbr_dmn_out; /* Allocate space to hold dimension IDs */ dmn_cnt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); dmn_sz=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_srt=(long *)nco_malloc(dmn_nbr*sizeof(long)); /* Get dimension IDs from input file */ (void)nco_inq_vardimid(in_id,var_in_id,dmn_id); /* Get dimension sizes from input file */ for(idx=0;idx 0){ /* Allow for zero-size record variables */ nco_get_vara(in_id,var_in_id,dmn_srt,dmn_cnt,void_ptr,var_typ); nco_put_vara(out_id,var_out_id,dmn_srt,dmn_cnt,void_ptr,var_typ); } /* end if var_sz */ } /* end if variable is an array */ /* Perform MD5 digest of input and output data if requested */ if(md5) (void)nco_md5_chk(md5,var_nm,var_sz*nco_typ_lng(var_typ),out_id,dmn_srt,dmn_cnt,void_ptr); /* Write unformatted binary data */ if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); /* 20111130 Fixes TODO nco1029: Warn on ncks -A when dim(old_record) != dim(new_record) */ if(dmn_nbr > 0){ int rec_dmn_id=NCO_REC_DMN_UNDEFINED; /* [id] Record dimension ID in input file */ int rcd=NC_NOERR; /* [rcd] Return code */ long rec_dmn_sz=0L; /* [nbr] Record dimension size in output file */ rcd+=nco_inq_unlimdim(in_id,&rec_dmn_id); /* If input file has record dimension ... */ if(rec_dmn_id != NCO_REC_DMN_UNDEFINED){ /* ... used as record dimension of this variable... */ if(rec_dmn_id == dmn_id[0]){ rcd+=nco_inq_unlimdim(out_id,&rec_dmn_id); /* ... and if output file has record dimension ... */ if(rec_dmn_id != NCO_REC_DMN_UNDEFINED){ (void)nco_inq_dimlen(out_id,rec_dmn_id,&rec_dmn_sz); /* ... and record dimension size in output file is non-zero (meaning at least one record has been written) ... */ if(rec_dmn_sz > 0){ /* ... then check input vs. output record dimension sizes ... */ if(rec_dmn_sz != dmn_cnt[0]){ (void)fprintf(stderr,"%s: WARNING record dimension size of %s changes between input and output files from %ld to %ld. Appended variable %s may (likely) be corrupt.\n",nco_prg_nm_get(),var_nm,dmn_cnt[0],rec_dmn_sz,var_nm); } /* endif sizes are incommensurate */ } /* endif records exist in output file */ } /* endif output file has record dimension */ } /* endif this variable uses input file record dimension */ } /* endif input file has record dimension */ } /* endif this variable is not a scalar */ /* Free space that held dimension IDs */ dmn_cnt=(long *)nco_free(dmn_cnt); dmn_id=(int *)nco_free(dmn_id); dmn_sz=(long *)nco_free(dmn_sz); dmn_srt=(long *)nco_free(dmn_srt); /* Free space that held variable */ void_ptr=nco_free(void_ptr); } /* end nco_cpy_var_val() */ nco_bool /* O [flg] Faster copy on Multi-record Multi-variable netCDF3 files */ nco_use_mm3_workaround /* [fnc] Use faster copy on Multi-record Multi-variable netCDF3 files? */ (const int in_id, /* I [id] Input file ID */ const int fl_out_fmt) /* I [enm] Output file format */ { /* Purpose: Determine whether to use copy algorithm designed to speed writes on netCDF3 files containing multiple record variables. In such cases massive slowdowns are common on Multi-record Multi-variable netCDF3 files Also the problem can occur with normal (4096 B) Blocksize Filesystems Based on Russ Rew's code in nccopy.c 20120306 Testing: ncks -O -C -D 4 -v one,two,one_dmn_rec_var,two_dmn_rec_var ~/nco/data/in.nc ~/foo.nc 20120307: NCO Open Discussion Forum exchanges with Russ Rew: "When accessing data from netCDF classic or 64-bit offset format files that have multiple record variables and a lot of records on a file system with large disk block size relative to a record's worth of data for one or more record variables, access the data a record at a time instead of a variable at a time." 20120312: "Hi Russ, I'm tidying up that patch in NCO, and have some further questions. In order to prioritize patching more of NCO, I want to know how the slowdown reading compares to the slowdown writing. To simplify my questions, let's use the abbreviations MM3 and MM4 for netCDF3 and netCDF4 Multi-record Multi-variable files, respectively. My understanding is that MM3s are susceptible to the slowdown, while MM4s are not, and that writing MM3s without the patch incurs incurs more of a penalty than reading MM3s. So this is how I prioritize implementing the MM3 patch: 1. When copying MM3 to MM3. Done in ncks 4.1.0, TBD in others. 2. When copying MM4 to MM3. Done in ncks 4.1.0, TBD in others. 3. When copying MM3 to MM4. Done in ncks 4.2.6, TBD in others. 4. When reading MM3 and not writing anything. Not done anywhere. Currently ncks always uses the algorithm for cases 1 and 2 (i.e., whenever writing to an MM3), but not for cases 3 and 4. The rest of NCO does not yet use the MM3 algorithm, yet there are many places where it would potentially benefit. I've heard through the years that sometimes ncecat slows to a crawl. Perhaps the MM3 slowdown is responsible. On the bright side, ncra and ncrcat are immune from the slowdown because they already read/write all record variables record-by-record. Does the prioritization above make sense? If so I will next patch the rest of NCO to do cases 1 and 2, before patching anything to do cases 3 and 4." 20120315: "Hi Charlie, That sounds right to me, because when you're just reading a small portion of a disk block, you only incur the extra time for reading data you won't use., but when you're writing, you have to read it all in and rewrite the part you're changing as well as the data you didn't change. So writing with large disk blocks would seem to require twice the I/O of reading. In nccopy, I just implemented the algorithm in cases 1 and 3; case 4 doesn't occur. I had thought case 2 currently wasn't very common, so it could wait, but your question has led me to rethink this. A fairly common use of case 2 is converting a compressed netCDF-4 classic model file to an uncompressed classic file, for use with applications that haven't been linked to a netCDF-4 library or in archives that will continue to use classic format. I've been trying to figure out whether implementing case 2 for compressed input could require significantly more chunk cache than not using the MM3 algorithm, if you want to avoid uncompressing the same data over and over again. But I think just having enough chunk cache to hold the largest compressed chunk for any record variable would be sufficient, so I've tentatively concluded that it's not an issue. (Where things get complicated is copying MM4 to MM4 while rechunking, to improve access times for read access patterns that don't match the way the data was written.) Thanks for presenting your prioritization. It looks like I've got some more work to do, implementing case 2 in nccopy." */ int dmn_nbr; int fl_in_fmt; /* [enm] Input file format */ int idx; int rec_dmn_id=NCO_REC_DMN_UNDEFINED; int rcd=NC_NOERR; /* [rcd] Return code */ int rec_var_nbr=0; /* [nbr] Number of record variables */ int var_nbr=0; /* [nbr] Number of variables */ int *dmn_id; nco_bool USE_MM3_WORKAROUND=False; /* [flg] Faster copy on Multi-record Multi-variable netCDF3 files */ (void)nco_inq_format(in_id,&fl_in_fmt); /* No advantage to workaround unless reading from or writing to netCDF3 file */ if( (fl_out_fmt == NC_FORMAT_CLASSIC || fl_out_fmt == NC_FORMAT_64BIT) || /* Cases 1 & 2 above, i.e., MM3->MM3 & MM4->MM3 */ ((fl_in_fmt == NC_FORMAT_CLASSIC || fl_in_fmt == NC_FORMAT_64BIT) && /* Case 3 above, i.e., MM3->MM4 */ (fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC)) || False) { /* Subsequently, assume output is netCDF3 or classic-compatible netCDF4 If file contains record dimension (and netCDF3 files can have only one record dimension) NB: fxm Following check only detects cases where MM3 conditions exist root group (not sub-groups) Copying MM3-worthy subgroup from netCDF4 file to netCDF3 flat file produces false-negative */ rcd=nco_inq_unlimdim(in_id,&rec_dmn_id); if(rec_dmn_id != NCO_REC_DMN_UNDEFINED){ /* Slowdown only occurs in files with more than one record variable */ rcd+=nco_inq_nvars(in_id,&var_nbr); if(var_nbr > 0){ for(idx=0;idx 0){ dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); rcd+=nco_inq_vardimid(in_id,idx,dmn_id); /* netCDF3 requires record dimension to be first dimension */ if(dmn_id[0] == rec_dmn_id){ rec_var_nbr++; if(rec_var_nbr > 1) USE_MM3_WORKAROUND=True; } /* endif record dimnesion */ if(dmn_id) dmn_id=(int*)nco_free(dmn_id); } /* endif dmn_nbr > 0 */ if(USE_MM3_WORKAROUND) break; } /* end loop over variables */ } /* endif var_nbr > 0 */ } /* endif file contains record dimnsion */ } /* endif file is netCDF3 */ return USE_MM3_WORKAROUND; } /* end nco_use_mm3_workaround() */ void nco_cpy_rec_var_val /* [fnc] Copy all record variables, record-by-record, from input to output file, no limits */ (const int in_id, /* I [id] netCDF input file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ const md5_sct * const md5, /* I [flg] MD5 Configuration */ CST_X_PTR_CST_PTR_CST_Y(nm_id_sct,var_lst), /* I [sct] Record variables to be extracted */ const int var_nbr) /* I [nbr] Number of record variables */ { /* Purpose: Copy all record variables from input netCDF file to output netCDF file Routine does not account for user-specified limits, it just copies what it finds Routine copies record-by-record, for all variables, old-style, called only by ncks Used only by MM3 workaround and therefore routine assumes: 1. Input file is netCDF3 2. All variables in var_lst are record variables NB: Rationale for MM3 workaround is kept in header to routine nco_use_mm3_workaround() */ const char fnc_nm[]="nco_cpy_rec_var_val()"; /* [sng] Function name */ int *dmn_id; int dmn_idx; int dmn_nbr; int nbr_dmn_in; int nbr_dmn_out; int rec_dmn_id; int rec_dmn_out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int var_idx; int var_in_id; int var_out_id; long *dmn_cnt; long *dmn_sz; long *dmn_srt; long rec_idx; long rec_sz; /* [nbr] Size of record-dimension in input file */ long rec_out_sz; /* [nbr] Size of record-dimension in output file */ long var_sz=1L; nc_type var_typ; void *void_ptr; /* Assume file contains record dimension (and netCDF3 files can have only one record dimension) */ rcd+=nco_inq_unlimdim(in_id,&rec_dmn_id); assert(rec_dmn_id != NCO_REC_DMN_UNDEFINED); rcd+=nco_inq_dimlen(in_id,rec_dmn_id,&rec_sz); for(rec_idx=0;rec_idx= nco_dbg_var && !fp_bnr && rec_idx == 0) (void)fprintf(stderr,"%s, ",var_lst[var_idx]->nm); if(nco_dbg_lvl_get() >= nco_dbg_var && rec_idx == 0) (void)fflush(stderr); /* Get ID of requested variable from both files */ (void)nco_inq_varid(var_lst[var_idx]->grp_id_in,var_lst[var_idx]->nm,&var_in_id); (void)nco_inq_varid(var_lst[var_idx]->grp_id_out,var_lst[var_idx]->nm,&var_out_id); (void)nco_inq_var(var_lst[var_idx]->grp_id_out,var_out_id,(char *)NULL,&var_typ,&nbr_dmn_out,(int *)NULL,(int *)NULL); (void)nco_inq_var(var_lst[var_idx]->grp_id_in,var_in_id,(char *)NULL,&var_typ,&nbr_dmn_in,(int *)NULL,(int *)NULL); if(nbr_dmn_out != nbr_dmn_in){ (void)fprintf(stderr,"%s: ERROR attempt to write %d-dimensional input variable %s to %d-dimensional space in output file\nHINT: When using -A (append) option, all appended variables must be the same rank in the input file as in the output file. The ncwa operator is useful at ridding variables of extraneous (size = 1) dimensions. See how at http://nco.sf.net/nco.html#ncwa\nIf you wish to completely replace the existing output file definition and values of the variable %s by those in the input file, then first remove %s from the output file using, e.g., ncks -x -v %s. See more on subsetting at http://nco.sf.net/nco.html#sbs",nco_prg_nm_get(),nbr_dmn_in,var_lst[var_idx]->nm,nbr_dmn_out,var_lst[var_idx]->nm,var_lst[var_idx]->nm,var_lst[var_idx]->nm); nco_exit(EXIT_FAILURE); } /* endif */ dmn_nbr=nbr_dmn_out; /* Allocate space to hold dimension IDs */ dmn_cnt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); dmn_sz=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_srt=(long *)nco_malloc(dmn_nbr*sizeof(long)); /* Get dimension IDs from input file */ (void)nco_inq_vardimid(var_lst[var_idx]->grp_id_in,var_in_id,dmn_id); /* Get non-record dimension sizes from input file */ for(dmn_idx=1;dmn_idxgrp_id_in,dmn_id[dmn_idx],dmn_cnt+dmn_idx); /* Initialize indicial offset and stride arrays */ dmn_srt[dmn_idx]=0L; var_sz*=dmn_cnt[dmn_idx]; } /* end loop over dim */ /* Configure hyperslab access for current record */ dmn_id[0]=rec_dmn_id; dmn_cnt[0]=1L; dmn_srt[0]=rec_idx; /* Allocate enough space to hold one record of this variable */ void_ptr=(void *)nco_malloc_dbg(var_sz*nco_typ_lng(var_typ),"Unable to malloc() value buffer when copying hypserslab from input to output file",fnc_nm); /* Get and put one record of variable */ if(var_sz > 0){ /* Allow for zero-size record variables */ nco_get_vara(var_lst[var_idx]->grp_id_in,var_in_id,dmn_srt,dmn_cnt,void_ptr,var_typ); nco_put_vara(var_lst[var_idx]->grp_id_out,var_out_id,dmn_srt,dmn_cnt,void_ptr,var_typ); } /* end if var_sz */ /* 20111130 TODO nco1029 warn on ncks -A when dim(old_record) != dim(new_record) One check of this condition, per variable, is enough In regular (non-MM3 workaround) case, we check this condition after reading/writing whole variable In MM3 workaround-case, check condition after writing last record 20130127: fxm bug here when user eliminates record variables using --fix_rec_dmn In that case output netCDF3 file does not have record variable so nco_inq_unlimdim() and nco_inq_dimlen() fail Since following code is purely diagnostic, assume that these failures are due to using --fix_rec_dmn And therefore, well, ignore them :) */ if(rec_idx == rec_sz-1){ rcd=nco_inq_unlimdim(var_lst[var_idx]->grp_id_out,&rec_dmn_out_id); if(rec_dmn_out_id != NCO_REC_DMN_UNDEFINED){ /* ... and if output file has record dimension ... */ (void)nco_inq_dimlen(var_lst[var_idx]->grp_id_out,rec_dmn_out_id,&rec_out_sz); /* ... and record dimension size in output file is non-zero (meaning at least one record has been written) ... */ if(rec_out_sz > 0){ /* ... then check input vs. output record dimension sizes ... */ if(rec_sz != rec_out_sz){ (void)fprintf(stderr,"%s: WARNING record dimension size of %s changes between input and output files from %ld to %ld. Appended variable %s may (likely) be corrupt.\n",nco_prg_nm_get(),var_lst[var_idx]->nm,rec_sz,rec_out_sz,var_lst[var_idx]->nm); } /* endif sizes are incommensurate */ } /* endif records have already been written to output file */ } /* endif record dimension exists in output file */ } /* endif last record in variable in input file */ /* Free space that held dimension IDs */ dmn_cnt=(long *)nco_free(dmn_cnt); dmn_id=(int *)nco_free(dmn_id); dmn_sz=(long *)nco_free(dmn_sz); dmn_srt=(long *)nco_free(dmn_srt); /* Free space that held variable */ void_ptr=nco_free(void_ptr); } /* end loop over variables */ } /* end loop over records */ /* Corner cases require a loop over variables but not records */ if(md5 || fp_bnr){ for(var_idx=0;var_idxgrp_id_in,var_lst[var_idx]->nm,&var_in_id); (void)nco_inq_var(var_lst[var_idx]->grp_id_in,var_in_id,(char *)NULL,&var_typ,&dmn_nbr,(int *)NULL,(int *)NULL); /* Allocate space to hold dimension IDs */ dmn_cnt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); dmn_sz=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_srt=(long *)nco_malloc(dmn_nbr*sizeof(long)); /* Get dimension IDs from input file */ (void)nco_inq_vardimid(var_lst[var_idx]->grp_id_in,var_in_id,dmn_id); /* Get dimension sizes from input file */ for(dmn_idx=0;dmn_idxgrp_id_in,dmn_id[dmn_idx],dmn_cnt+dmn_idx); /* Initialize indicial offset and stride arrays */ dmn_srt[dmn_idx]=0L; var_sz*=dmn_cnt[dmn_idx]; } /* end loop over dim */ /* Allocate enough space to hold this entire variable */ void_ptr=(void *)nco_malloc_dbg(var_sz*nco_typ_lng(var_typ),"Unable to malloc() value buffer when doing MD5 or binary write on variable",fnc_nm); /* Get variable */ if(var_sz > 0) nco_get_vara(var_lst[var_idx]->grp_id_in,var_in_id,dmn_srt,dmn_cnt,void_ptr,var_typ); /* Perform MD5 digest of input and output data if requested */ if(md5) (void)nco_md5_chk(md5,var_lst[var_idx]->nm,var_sz*nco_typ_lng(var_typ),var_lst[var_idx]->grp_id_out,dmn_srt,dmn_cnt,void_ptr); /* Write unformatted binary data */ if(fp_bnr) nco_bnr_wrt(fp_bnr,var_lst[var_idx]->nm,var_sz,var_typ,void_ptr); /* Free space that held dimension IDs */ dmn_cnt=(long *)nco_free(dmn_cnt); dmn_id=(int *)nco_free(dmn_id); dmn_sz=(long *)nco_free(dmn_sz); dmn_srt=(long *)nco_free(dmn_srt); /* Free space that held variable */ void_ptr=nco_free(void_ptr); } /* end loop over variables */ } /* end if */ } /* end nco_cpy_rec_var_val() */ void nco_cpy_var_val_lmt /* [fnc] Copy variable data from input to output file, simple hyperslabs */ (const int in_id, /* I [id] netCDF input file ID */ const int out_id, /* I [id] netCDF output file ID */ FILE * const fp_bnr, /* I [fl] Unformatted binary output file handle */ char *var_nm, /* I [sng] Variable name */ const lmt_sct * const lmt, /* I [sct] Hyperslab limits */ const int lmt_nbr) /* I [nbr] Number of hyperslab limits */ { /* NB: nco_cpy_var_val_lmt() contains OpenMP critical region */ /* Purpose: Copy variable data from input netCDF file to output netCDF file Truncate dimensions in variable definition in output file according to user-specified limits Copy variable-by-variable, old-style, Routine was used by ncks until MSA implementation in ~2005 Functionality now extended and superceded by nco_cpy_var_val_mlt_lmt() */ nco_bool SRD=False; nco_bool WRP=False; const char fnc_nm[]="nco_cpy_var_val_lmt()"; /* [sng] Function name */ int *dmn_id; int dmn_idx; int dmn_nbr; int lmt_idx; int nbr_dmn_in; int nbr_dmn_out; int var_in_id; int var_out_id; /* For regular data */ long *dmn_cnt; long *dmn_in_srt; long *dmn_map; long *dmn_out_srt; long *dmn_srd; long *dmn_sz; long var_sz=1L; nc_type var_typ; void *void_ptr; /* Get var_id for requested variable from both files */ nco_inq_varid(in_id,var_nm,&var_in_id); nco_inq_varid(out_id,var_nm,&var_out_id); /* Get type and number of dimensions for variable */ (void)nco_inq_var(out_id,var_out_id,(char *)NULL,&var_typ,&nbr_dmn_out,(int *)NULL,(int *)NULL); (void)nco_inq_var(in_id,var_in_id,(char *)NULL,&var_typ,&nbr_dmn_in,(int *)NULL,(int *)NULL); if(nbr_dmn_out != nbr_dmn_in){ (void)fprintf(stderr,"%s: ERROR attempt to write %d-dimensional input variable %s to %d-dimensional space in output file\nHINT: When using -A (append) option, all appended variables must be the same rank in the input file as in the output file. The ncwa operator is useful at ridding variables of extraneous (size = 1) dimensions. See how at http://nco.sf.net/nco.html#ncwa\nIf you wish to completely replace the existing output file definition and values of the variable %s by those in the input file, then first remove %s from the output file using, e.g., ncks -x -v %s. See more on subsetting at http://nco.sf.net/nco.html#sbs",nco_prg_nm_get(),nbr_dmn_in,var_nm,nbr_dmn_out,var_nm,var_nm,var_nm); nco_exit(EXIT_FAILURE); } /* endif */ dmn_nbr=nbr_dmn_out; /* Allocate space to hold dimension IDs */ dmn_cnt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_id=(int *)nco_malloc(dmn_nbr*sizeof(int)); dmn_in_srt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_map=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_out_srt=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_srd=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_sz=(long *)nco_malloc(dmn_nbr*sizeof(long)); /* Get dimension IDs from input file */ (void)nco_inq_vardimid(in_id,var_in_id,dmn_id); /* Get dimension sizes from input file */ for(dmn_idx=0;dmn_idx lmt[lmt_idx].end) WRP=True; if(lmt[lmt_idx].srd != 1L) SRD=True; break; } /* end if */ } /* end loop over lmt_idx */ var_sz*=dmn_cnt[dmn_idx]; } /* end loop over dim */ /* Allocate enough space to hold variable */ void_ptr=(void *)nco_malloc_dbg(var_sz*nco_typ_lng(var_typ),"Unable to malloc() value buffer when copying hypserslab from input to output file",fnc_nm); /* Copy variable */ if(dmn_nbr == 0){ /* Copy scalar */ nco_get_var1(in_id,var_in_id,0L,void_ptr,var_typ); nco_put_var1(out_id,var_out_id,0L,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); }else if(!WRP){ /* Copy contiguous array */ if(!SRD) nco_get_vara(in_id,var_in_id,dmn_in_srt,dmn_cnt,void_ptr,var_typ); else nco_get_varm(in_id,var_in_id,dmn_in_srt,dmn_cnt,dmn_srd,(long *)NULL,void_ptr,var_typ); nco_put_vara(out_id,var_out_id,dmn_out_srt,dmn_cnt,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); }else if(WRP){ /* Copy wrapped array */ /* For wrapped data */ long *dmn_in_srt_1=NULL; long *dmn_in_srt_2=NULL; long *dmn_out_srt_1=NULL; long *dmn_out_srt_2=NULL; long *dmn_cnt_1=NULL; long *dmn_cnt_2=NULL; dmn_in_srt_1=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_in_srt_2=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_out_srt_1=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_out_srt_2=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_cnt_1=(long *)nco_malloc(dmn_nbr*sizeof(long)); dmn_cnt_2=(long *)nco_malloc(dmn_nbr*sizeof(long)); /* Variable contains a wrapped dimension, requires two reads */ /* For each dimension in the input variable */ for(dmn_idx=0;dmn_idx lmt[lmt_idx].end){ /* WRP true for this dimension */ WRP=True; if(lmt[lmt_idx].srd != 1L){ /* SRD true for this dimension */ long greatest_srd_multiplier_1st_hyp_slb; /* greatest integer m such that srt+m*srd < dmn_sz */ long last_good_idx_1st_hyp_slb; /* C-index of last valid member of 1st hyperslab (= srt+m*srd) */ long left_over_idx_1st_hyp_slb; /* # elements from first hyperslab to count towards current stride */ /* long first_good_idx_2nd_hyp_slb; *//* C-index of first valid member of 2nd hyperslab, if any */ /* NB: Perform these operations with integer arithmetic or else! */ dmn_cnt_1[dmn_idx]=1L+(dmn_sz[dmn_idx]-lmt[lmt_idx].srt-1L)/lmt[lmt_idx].srd; /* Wrapped dimensions with stride may not start at idx 0 on second read */ greatest_srd_multiplier_1st_hyp_slb=(dmn_sz[dmn_idx]-lmt[lmt_idx].srt-1L)/lmt[lmt_idx].srd; last_good_idx_1st_hyp_slb=lmt[lmt_idx].srt+lmt[lmt_idx].srd*greatest_srd_multiplier_1st_hyp_slb; left_over_idx_1st_hyp_slb=dmn_sz[dmn_idx]-last_good_idx_1st_hyp_slb-1L; /* first_good_idx_2nd_hyp_slb=(last_good_idx_1st_hyp_slb+lmt[lmt_idx].srd)%dmn_sz[dmn_idx];*/ /* Variable is unused but instructive anyway */ dmn_in_srt_2[dmn_idx]=lmt[lmt_idx].srd-left_over_idx_1st_hyp_slb-1L; }else{ /* !SRD */ dmn_in_srt_2[dmn_idx]=0L; dmn_cnt_1[dmn_idx]=dmn_sz[dmn_idx]-lmt[lmt_idx].srt; } /* end else */ dmn_cnt_2[dmn_idx]=dmn_cnt[dmn_idx]-dmn_cnt_1[dmn_idx]; dmn_out_srt_2[dmn_idx]=dmn_cnt_1[dmn_idx]; } /* end if WRP */ break; /* Move on to next dimension in variable */ } /* end if */ } /* end loop over lmt */ } /* end loop over dim */ if(nco_dbg_lvl_get() >= 5){ (void)fprintf(stderr,"\nvar = %s\n",var_nm); (void)fprintf(stderr,"dim\tcnt\tsrtin1\tcnt1\tsrtout1\tsrtin2\tcnt2\tsrtout2\n"); for(dmn_idx=0;dmn_idx wrp_max) val_dbl-=wrp_spn; } /* end loop over idx */ } /* endif CRD && MNT */ } /* endif False */ /* fxm: Binary writes will not work for wrapped and stride variables until var_sz is changed to reflect actual size */ if(!SRD){ (void)nco_get_vara(in_id,var_in_id,dmn_in_srt_1,dmn_cnt_1,void_ptr,var_typ); (void)nco_put_vara(out_id,var_out_id,dmn_out_srt_1,dmn_cnt_1,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); (void)nco_get_vara(in_id,var_in_id,dmn_in_srt_2,dmn_cnt_2,void_ptr,var_typ); (void)nco_put_vara(out_id,var_out_id,dmn_out_srt_2,dmn_cnt_2,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); }else{ /* SRD */ (void)nco_get_varm(in_id,var_in_id,dmn_in_srt_1,dmn_cnt_1,dmn_srd,(long *)NULL,void_ptr,var_typ); (void)nco_put_vara(out_id,var_out_id,dmn_out_srt_1,dmn_cnt_1,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); (void)nco_get_varm(in_id,var_in_id,dmn_in_srt_2,dmn_cnt_2,dmn_srd,(long *)NULL,void_ptr,var_typ); (void)nco_put_vara(out_id,var_out_id,dmn_out_srt_2,dmn_cnt_2,void_ptr,var_typ); if(fp_bnr) nco_bnr_wrt(fp_bnr,var_nm,var_sz,var_typ,void_ptr); } /* end else SRD */ dmn_in_srt_1=(long *)nco_free(dmn_in_srt_1); dmn_in_srt_2=(long *)nco_free(dmn_in_srt_2); dmn_out_srt_1=(long *)nco_free(dmn_out_srt_1); dmn_out_srt_2=(long *)nco_free(dmn_out_srt_2); dmn_cnt_1=(long *)nco_free(dmn_cnt_1); dmn_cnt_2=(long *)nco_free(dmn_cnt_2); } /* end if WRP */ /* Free space that held metadata */ dmn_map=(long *)nco_free(dmn_map); dmn_srd=(long *)nco_free(dmn_srd); dmn_cnt=(long *)nco_free(dmn_cnt); dmn_id=(int *)nco_free(dmn_id); dmn_in_srt=(long *)nco_free(dmn_in_srt); dmn_out_srt=(long *)nco_free(dmn_out_srt); dmn_sz=(long *)nco_free(dmn_sz); /* Free space that held variable */ void_ptr=nco_free(void_ptr); } /* end nco_cpy_var_val_lmt() */ var_sct * /* O [sct] Copy of input variable */ nco_var_dpl /* [fnc] Duplicate input variable */ (const var_sct * const var) /* I [sct] Variable to duplicate */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: nco_malloc() and return duplicate of input var_sct Duplicate is deep-copy of original so original may always be free()'d */ const char fnc_nm[]="nco_var_dpl()"; /* [sng] Function name */ var_sct *var_cpy; var_cpy=(var_sct *)nco_malloc(sizeof(var_sct)); /* Shallow-copy structure itself */ (void)memcpy((void *)var_cpy,(const void *)var,sizeof(var_sct)); /* Make sure var_free() frees names when variable is destructed */ if(var->nm) var_cpy->nm=(char *)strdup(var->nm); if(var->nm_fll) var_cpy->nm_fll=(char *)strdup(var->nm_fll); /* Deep-copy dyamically allocated arrays from original to copy */ if(var->val.vp){ var_cpy->val.vp=(void *)nco_malloc_dbg(var_cpy->sz*nco_typ_lng(var_cpy->type),"Unable to malloc() value buffer in variable deep-copy",fnc_nm); (void)memcpy((void *)(var_cpy->val.vp),(void *)(var->val.vp),var_cpy->sz*nco_typ_lng(var_cpy->type)); /* Deep-copy string data, if any */ if(var->type == (nc_type)NC_STRING){ ptr_unn val_in; ptr_unn val_out; long idx; long sz; sz=var->sz; val_in=var->val; val_out=var_cpy->val; /* Typecast pointer to values before access Use local copies of pointer unions to maintain const-ness of var */ (void)cast_void_nctype((nc_type)NC_STRING,&val_in); (void)cast_void_nctype((nc_type)NC_STRING,&val_out); for(idx=0;idxmss_val.vp){ var_cpy->mss_val.vp=(void *)nco_malloc(nco_typ_lng(var_cpy->type)); (void)memcpy((void *)(var_cpy->mss_val.vp),(void *)(var->mss_val.vp),nco_typ_lng(var_cpy->type)); } /* end if */ if(var->tally){ var_cpy->tally=(long *)nco_malloc_dbg(var_cpy->sz*sizeof(long),"Unable to malloc() tally buffer in variable deep-copy",fnc_nm); (void)memcpy((void *)(var_cpy->tally),(void *)(var->tally),var_cpy->sz*sizeof(long)); } /* end if */ if(var->dim){ var_cpy->dim=(dmn_sct **)nco_malloc(var_cpy->nbr_dim*sizeof(dmn_sct *)); (void)memcpy((void *)(var_cpy->dim),(void *)(var->dim),var_cpy->nbr_dim*sizeof(var->dim[0])); } /* end if */ if(var->dmn_id){ var_cpy->dmn_id=(int *)nco_malloc(var_cpy->nbr_dim*sizeof(int)); (void)memcpy((void *)(var_cpy->dmn_id),(void *)(var->dmn_id),var_cpy->nbr_dim*sizeof(var->dmn_id[0])); } /* end if */ if(var->cnk_sz){ var_cpy->cnk_sz=(size_t *)nco_malloc(var_cpy->nbr_dim*sizeof(size_t)); (void)memcpy((void *)(var_cpy->cnk_sz),(void *)(var->cnk_sz),var_cpy->nbr_dim*sizeof(var->cnk_sz[0])); } /* end if */ if(var->cnt){ var_cpy->cnt=(long *)nco_malloc(var_cpy->nbr_dim*sizeof(long)); (void)memcpy((void *)(var_cpy->cnt),(void *)(var->cnt),var_cpy->nbr_dim*sizeof(var->cnt[0])); } /* end if */ if(var->srt){ var_cpy->srt=(long *)nco_malloc(var_cpy->nbr_dim*sizeof(long)); (void)memcpy((void *)(var_cpy->srt),(void *)(var->srt),var_cpy->nbr_dim*sizeof(var->srt[0])); } /* end if */ if(var->end){ var_cpy->end=(long *)nco_malloc(var_cpy->nbr_dim*sizeof(long)); (void)memcpy((void *)(var_cpy->end),(void *)(var->end),var_cpy->nbr_dim*sizeof(var->end[0])); } /* end if */ if(var->srd){ var_cpy->srd=(long *)nco_malloc(var_cpy->nbr_dim*sizeof(long)); (void)memcpy((void *)(var_cpy->srd),(void *)(var->srd),var_cpy->nbr_dim*sizeof(var->srd[0])); } /* end if */ if(var->scl_fct.vp){ var_cpy->scl_fct.vp=(void *)nco_malloc(nco_typ_lng(var_cpy->typ_upk)); (void)memcpy((void *)(var_cpy->scl_fct.vp),(void *)(var->scl_fct.vp),nco_typ_lng(var_cpy->typ_upk)); } /* end if */ if(var->add_fst.vp){ var_cpy->add_fst.vp=(void *)nco_malloc(nco_typ_lng(var_cpy->typ_upk)); (void)memcpy((void *)(var_cpy->add_fst.vp),(void *)(var->add_fst.vp),nco_typ_lng(var_cpy->typ_upk)); } /* end if */ return var_cpy; } /* end nco_var_dpl() */ void nco_var_get /* [fnc] Allocate, retrieve variable hyperslab from disk to memory */ (const int nc_id, /* I [id] netCDF file ID */ var_sct *var) /* I [sct] Variable to get */ { /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ /* Purpose: Allocate and retrieve given variable hyperslab from disk into memory If variable is packed on disk then inquire about scale_factor and add_offset */ int idx; long srd_prd=1L; /* [nbr] Product of strides */ const char fnc_nm[]="nco_var_get()"; /* [sng] Function name */ var->val.vp=(void *)nco_malloc_dbg(var->sz*nco_typ_lng(var->typ_dsk),"Unable to malloc() value buffer when retrieving variable from disk",fnc_nm); if(False) (void)fprintf(stdout,"%s: DEBUG: fxm TODO nco354. Calling nco_get_vara() for %s with nc_id=%d, var_id=%d, var_srt=%li, var_cnt = %li, var_val = %g, var_typ = %s\n",nco_prg_nm_get(),var->nm,nc_id,var->id,var->srt[0],var->cnt[0],var->val.fp[0],nco_typ_sng(var->typ_dsk)); /* 20051021: Removed this potentially critical region by parallelizing over in_id's in calling code */ /* 20051019: nco_get_var*() routines are potentially SMP-critical netCDF library allows parallel reads by different processes, not threads Parallel reads to the same nc_id by different threads are critical because the underlying UNIX file open has limited stdin caching Parallel reads to different nc_id's for same underlying file work because each UNIX file open (for same file) creates own stdin caching */ /* 20050629: Removing this critical region and calling with identical nc_id's causes multiple ncwa/ncra regressions */ { /* begin potential OpenMP critical */ /* Block is critical/thread-safe for identical/distinct in_id's */ /* Is stride > 1? */ for(idx=0;idxnbr_dim;idx++) srd_prd*=var->srd[idx]; if(srd_prd == 1L){ if(var->sz > 1L) (void)nco_get_vara(nc_id,var->id,var->srt,var->cnt,var->val.vp,var->typ_dsk); else (void)nco_get_var1(nc_id,var->id,var->srt,var->val.vp,var->typ_dsk); }else{ (void)nco_get_varm(nc_id,var->id,var->srt,var->cnt,var->srd,(long *)NULL,var->val.vp,var->typ_dsk); } /* endif non-unity stride */ } /* end potential OpenMP critical */ /* Packing properties initially obtained by nco_pck_dsk_inq() in nco_var_fll() Multi-file operators (MFOs) call nco_var_get() multiple times for each variable In between subsequent calls to nco_var_get(), variable may be unpacked When this occurs, packing flags in variable structure will not match disk Thus it is important to refresh (some) packing attributes on each read */ /* Synchronize missing value type with (possibly) new disk type */ /* fxm nco427: pck_dbg potential big bug on non-packed types in ncra here, due to potential double conversion of missing_value First conversion to typ_dsk occurs when nco_var_fll() reads in mss_val Second conversion occurs here mss_val again converted to typ_dsk fxm nco457: Why not always convert missing_value to variable type, even when variable is not packed? Answer: because doing this appears to break some ncra tests */ if(var->pck_dsk) var=nco_cnv_mss_val_typ(var,var->typ_dsk); /* var=nco_cnv_mss_val_typ(var,var->typ_dsk);*/ /* Type of variable and missing value in memory are now same as type on disk */ var->type=var->typ_dsk; /* [enm] Type of variable in RAM */ /* Packing in RAM is now same as packing on disk pck_dbg fxm: Following call to nco_pck_dsk_inq() is never necessary for non-packed variables */ (void)nco_pck_dsk_inq(nc_id,var); /* Packing/Unpacking */ if(nco_is_rth_opr(nco_prg_id_get())){ /* Arithmetic operators must unpack variables before performing arithmetic Otherwise arithmetic will produce garbage results */ /* 20050519: Not sure why I originally made nco_var_upk() call SMP-critical 20050629: Making this region multi-threaded causes no problems */ if(var->pck_dsk) var=nco_var_upk(var); } /* endif arithmetic operator */ } /* end nco_var_get() */ void nco_xrf_dmn /* [fnc] Switch pointers to dimension structures so var->dim points to var->dim->xrf */ (var_sct * const var) /* I [sct] Variable to manipulate */ { /* Purpose: Switch pointers to dimension structures so var->dim points to var->dim->xrf Routine makes dim element of variable structure from nco_var_dpl() refer to counterparts of dimensions directly associated with variable it was duplicated from */ int idx; for(idx=0;idxnbr_dim;idx++){ var->dim[idx]=var->dim[idx]->xrf; } } /* end nco_xrf_dmn() */ void nco_xrf_var /* [fnc] Make xrf elements of variable structures point to eachother */ (var_sct * const var_1, /* I/O [sct] Variable */ var_sct * const var_2) /* I/O [sct] Related variable */ { /* Purpose: Make xrf elements of variable structures point to eachother */ var_1->xrf=var_2; var_2->xrf=var_1; } /* end nco_xrf_var() */ var_sct * /* O [sct] Pointer to free'd variable */ nco_var_free /* [fnc] Free all memory associated with variable structure */ (var_sct *var) /* I/O [sct] Variable to free */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with a dynamically allocated variable structure */ /* String values must be deep-free'd, everything else is a flat buffer */ if(var->type == (nc_type)NC_STRING){ /* 20140212: ncwa may free this memory twice because reduced variable not created correctly in nco_var_avg() Temporarily only free string variables during debugging */ if(nco_dbg_lvl_get() == nco_dbg_crr) if(var->val.vp) var->val.vp=(void *)nco_sng_lst_free((char **)var->val.vp,var->sz); }else{ if(var->val.vp) var->val.vp=nco_free(var->val.vp); } /* endif */ var->nm=(char *)nco_free(var->nm); var->nm_fll=(char *)nco_free(var->nm_fll); var->mss_val.vp=nco_free(var->mss_val.vp); var->tally=(long *)nco_free(var->tally); var->dmn_id=(int *)nco_free(var->dmn_id); var->cnk_sz=(size_t *)nco_free(var->cnk_sz); var->dim=(dmn_sct **)nco_free(var->dim); var->srt=(long *)nco_free(var->srt); var->end=(long *)nco_free(var->end); var->cnt=(long *)nco_free(var->cnt); var->srd=(long *)nco_free(var->srd); var->scl_fct.vp=nco_free(var->scl_fct.vp); var->add_fst.vp=nco_free(var->add_fst.vp); /* Free structure pointer last */ var=(var_sct *)nco_free(var); return NULL; } /* end nco_var_free() */ var_sct ** /* O [sct] Pointer to free'd structure list */ nco_var_lst_free /* [fnc] Free memory associated with variable structure list */ (var_sct **var_lst, /* I/O [sct] Variable structure list to free */ const int var_nbr) /* I [nbr] Number of variable structures in list */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with dynamically allocated variable structure list */ int idx; for(idx=0;idxnm=NULL; var->nm_fll=NULL; var->id=-1; var->nc_id=-1; var->type=NC_NAT; /* Type of variable in RAM */ var->typ_dsk=NC_NAT; /* Type of variable on disk */ var->typ_pck=NC_NAT; /* Type of variable when packed (on disk). This should be same as typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ var->typ_upk=NC_NAT; /* Type of variable when unpacked (expanded) (in memory) */ var->is_rec_var=False; var->is_crd_var=False; /* nco_var_fll() assumes size of 1 */ var->sz=1L; var->sz_rec=1L; var->cid=-1; var->has_dpl_dmn=False; var->has_mss_val=False; var->mss_val.vp=NULL; var->val.vp=NULL; var->tally=NULL; var->xrf=NULL; var->nbr_dim=-1; var->nbr_att=-1; var->dim=(dmn_sct **)NULL; var->dmn_id=(int *)NULL; var->cnk_sz=(size_t *)NULL; var->cnt=(long *)NULL; var->srt=(long *)NULL; var->end=(long *)NULL; var->srd=(long *)NULL; var->undefined=False; /* [flg] Used by ncap parser */ var->is_fix_var=True; /* Is this a fixed (non-processed) variable? */ var->dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ var->shuffle=False; /* [flg] Turn on shuffle filter */ /* Members related to packing */ var->has_scl_fct=False; /* [flg] Valid scale_factor attribute exists */ var->has_add_fst=False; /* [flg] Valid add_offset attribute exists */ var->pck_dsk=False; /* [flg] Variable is packed on disk */ var->pck_ram=False; /* [flg] Variable is packed in memory */ var->scl_fct.vp=NULL; /* [ptr] Value of scale_factor attribute, if any */ var->add_fst.vp=NULL; /* [ptr] Value of add_offset attribute, if any */ return rcd; /* [enm] Return code */ } /* end var_dfl_set() */ void nco_var_copy /* [fnc] Copy hyperslab variables of type var_typ from op1 to op2 */ (const nc_type var_typ, /* I [enm] netCDF type */ const long sz, /* I [nbr] Number of elements to copy */ const ptr_unn op1, /* I [sct] Values to copy */ ptr_unn op2) /* O [sct] Destination to copy values to */ { /* Purpose: Copy hyperslab variables of type var_typ from op1 to op2 Assumes memory area in op2 has already been malloc()'d nco_var_copy(): Does nothing with missing values and tallies nco_var_copy_tll(): Accounts for missing values in tally */ (void)memcpy((void *)(op2.vp),(void *)(op1.vp),sz*nco_typ_lng(var_typ)); } /* end nco_var_copy() */ void nco_var_dfn /* [fnc] Define variables and write their attributes to output file */ (const int in_id, /* I [enm] netCDF input-file ID */ const char * const fl_out, /* I [sng] Name of output file */ const int out_id, /* I [enm] netCDF output-file ID */ var_sct * const * const var, /* I/O [sct] Variables to be defined in output file */ const int nbr_var, /* I [nbr] Number of variables to be defined */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_ncl), /* I [sct] Dimensions included in output file */ const int nbr_dmn_ncl, /* I [nbr] Number of dimensions in list */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ const int dfl_lvl) /* I [enm] Deflate level [0..9] */ { /* Purpose: Define variables in output file, copy their attributes */ /* This function is unusual (for me) in that dimension arguments are only intended to be used by certain programs---those that alter the rank of input variables. Programs that do not alter input variable rank (dimensionality) should call this function with NULL dimension list and nbr_dmn_ncl=0. Otherwise, this routine attempts to define variable correctly in output file (allowing variable to be defined with only those dimensions that are in dimension inclusion list) without altering variable structures. Moreover, this function is intended to be called with var_prc_out, not var_prc So local variable var usually refers to var_prc_out in calling function Hence names may look reversed in this function, and xrf is frequently used 20060217: Packed fixed (non-processed) variables are now passed through unaltered */ nco_bool PCK_ATT_CPY=True; /* [flg] Copy attributes "scale_factor", "add_offset" */ const char fnc_nm[]="nco_var_dfn()"; /* [sng] Function name */ int dmn_nbr=0; int dmn_id_vec[NC_MAX_DIMS]; int idx; int dmn_idx; int fl_fmt; /* [enm] Output file format */ int nco_prg_id; /* [enm] Program ID */ int rcd=NC_NOERR; /* [rcd] Return code */ nc_type typ_out; /* [enm] Type in output file */ nco_prg_id=nco_prg_id_get(); /* [enm] Program ID */ for(idx=0;idxnm,&var[idx]->id); /* If variable has not been defined, define it */ if(rcd != NC_NOERR){ /* TODO #116: There is a problem here in that var_out[idx]->nbr_dim is never explicitly set to the actual number of output dimensions, rather, it is simply copied from var[idx]. When var_out[idx] actually has 0 dimensions, the loop executes once anyway, and an erroneous index into the dmn_out[idx] array is attempted. Fix is to explicitly define var_out[idx]->nbr_dim. Until this is done, anything in ncwa that explicitly depends on var_out[idx]->nbr_dim is suspect. The real problem is that, in ncwa, nco_var_avg() expects var_out[idx]->nbr_dim to contain the input, rather than output, number of dimensions. The routine, nco_var_dfn() was designed to call the simple branch when dmn_ncl == 0, i.e., for operators besides ncwa. However, when ncwa averages all dimensions in output file, nbr_dmn_ncl == 0 so the wrong branch would get called unless we specifically use this branch whenever ncwa is calling. */ if(dmn_ncl || nco_prg_id == ncwa){ /* ...operator is ncwa and/or changes variable rank... */ int idx_ncl; /* Initialize number of dimensions for current variable */ dmn_nbr=0; for(dmn_idx=0;dmn_idxnbr_dim;dmn_idx++){ /* Is dimension allowed in output file? */ for(idx_ncl=0;idx_nclxrf->dim[dmn_idx]->id == dmn_ncl[idx_ncl]->xrf->id){ break; } } /* end loop over idx_ncl */ if(idx_ncl != nbr_dmn_ncl){ dmn_id_vec[dmn_nbr++]=var[idx]->dim[dmn_idx]->id; } } /* end loop over dmn_idx */ }else{ /* ...operator does not change variable rank so handle normally... */ /* More straightforward definition used by operators besides ncwa */ for(dmn_idx=0;dmn_idxnbr_dim;dmn_idx++){ dmn_id_vec[dmn_idx]=var[idx]->dim[dmn_idx]->id; } /* end loop over dmn_idx */ dmn_nbr=var[idx]->nbr_dim; } /* end else */ if(nco_dbg_lvl_get() > 3 && nco_prg_id != ncwa){ /* fxm TODO nco374 diagnostic information fails for ncwa since var[idx]->dim[dmn_idx]->nm contains _wrong name_ when variables will be averaged. ncwa does contain write name information now if retain_degenerate_dimensions option is in effect, but this is the exception rather than the rule. */ (void)fprintf(stdout,"%s: DEBUG %s about to define variable %s with %d dimension%s%s",nco_prg_nm_get(),fnc_nm,var[idx]->nm,dmn_nbr,(dmn_nbr == 1) ? "" : "s",(dmn_nbr > 0) ? " (ordinal,output ID): " : ""); for(dmn_idx=0;dmn_idxdim[dmn_idx]->nm,dmn_idx,"unknown",(dmn_idx < dmn_nbr-1) ? ", " : ""); } /* end loop over dmn */ (void)fprintf(stdout,"\n"); } /* endif dbg */ /* The all-important variable definition call itself... */ (void)nco_def_var(out_id,var[idx]->nm,typ_out,dmn_nbr,dmn_id_vec,&var[idx]->id); /* Set HDF Lempel-Ziv compression level, if requested */ rcd=nco_inq_format(out_id,&fl_fmt); if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ /* Deflation */ if(dmn_nbr > 0){ int shuffle; /* [flg] Turn on shuffle filter */ int deflate; /* [flg] Turn on deflate filter */ int dfl_lvl_in; /* [enm] Deflate level [0..9] */ int var_in_id; /* Uncertain that output name always exists in input file */ rcd=nco_inq_varid_flg(in_id,var[idx]->nm,&var_in_id); if(rcd == NC_NOERR){ /* When output name is in input file, inquire input deflation level */ rcd=nco_inq_var_deflate(in_id,var_in_id,&shuffle,&deflate,&dfl_lvl_in); /* Copy original deflation settings */ if(deflate || shuffle) (void)nco_def_var_deflate(out_id,var[idx]->id,deflate,shuffle,dfl_lvl_in); } /* endif */ /* Overwrite HDF Lempel-Ziv compression level, if requested */ if(dfl_lvl == 0) deflate=(int)False; else deflate=(int)True; /* Turn-off shuffle when uncompressing otherwise chunking requests may fail */ if(dfl_lvl == 0) shuffle=(int)False; if(dfl_lvl >= 0) (void)nco_def_var_deflate(out_id,var[idx]->id,shuffle,deflate,dfl_lvl); } /* endif */ } /* endif netCDF4 */ if(nco_dbg_lvl_get() > 3 && nco_prg_id != ncwa){ /* fxm TODO nco374 diagnostic information fails for ncwa since var[idx]->dim[dmn_idx]->nm contains _wrong name_ when variables will be averaged. ncwa does contain write name information now if retain_degenerate_dimensions option is in effect, but this is the exception rather than the rule. */ (void)fprintf(stdout,"%s: DEBUG %s defined variable %s with %d dimension%s%s",nco_prg_nm_get(),fnc_nm,var[idx]->nm,dmn_nbr,(dmn_nbr == 1) ? "" : "s",(dmn_nbr > 0) ? " (ordinal,output ID): " : ""); for(dmn_idx=0;dmn_idxdim[dmn_idx]->nm,dmn_idx,dmn_id_vec[dmn_idx],(dmn_idx < dmn_nbr-1) ? ", " : ""); } /* end loop over dmn */ (void)fprintf(stdout,"\n"); } /* endif dbg */ /* endif variable has not yet been defined in output file */ }else{ /* Variable is already in output file---use existing definition This branch is executed, e.g., by operators in append mode */ (void)fprintf(stdout,"%s: WARNING Using existing definition of variable \"%s\" in %s\n",nco_prg_nm_get(),var[idx]->nm,fl_out); } /* end if variable is already in output file */ /* Copy all attributes except in cases where packing/unpacking is involved 0. Variable is unpacked on input, unpacked on output --> Copy all attributes 1. Variable is packed on input, is not altered, and remains packed on output --> Copy all attributes 2. Variable is packed on input, is unpacked for some reason, and will be unpacked on output --> Copy all attributes except scale_factor and add_offset 3. Variable is packed on input, is unpacked for some reason, and will be packed on output (possibly with new packing attributes) --> Copy all attributes, but scale_factor and add_offset must be overwritten later with new values 4. Variable is not packed on input, packing is performed, and output is packed --> Copy all attributes, define dummy values for scale_factor and add_offset now, and write those values later, when they are known */ /* Do not copy packing attributes "scale_factor" and "add_offset" if variable is packed in input file and unpacked in output file Arithmetic operators calling nco_var_dfn() with fixed variables should leave them fixed Currently ncap calls nco_var_dfn() only for fixed variables, so handle exception with ncap-specific condition */ /* Copy exising packing attributes, if any, unless... */ if(nco_is_rth_opr(nco_prg_id) && /* ...operator is arithmetic... */ nco_prg_id != ncap && /* ...and is not ncap (hence it must be, e.g., ncra, ncbo)... */ !var[idx]->is_fix_var && /* ...and variable is processed (not fixed)... */ var[idx]->xrf->pck_dsk) /* ...and variable is packed in input file... */ PCK_ATT_CPY=False; /* Do not copy packing attributes when unpacking variables ncpdq is currently only operator that passes values other than nco_pck_plc_nil */ if(nco_pck_plc == nco_pck_plc_upk) /* ...and variable will be _unpacked_ ... */ PCK_ATT_CPY=False; /* Recall that: var refers to output variable structure var->xrf refers to input variable structure ncpdq may pre-define packing attributes below regardless of PCK_ATT_CPY */ (void)nco_att_cpy(in_id,out_id,var[idx]->xrf->id,var[idx]->id,PCK_ATT_CPY); /* Create dummy packing attributes for ncpdq if necessary Must apply nearly same logic at end of ncpdq when writing final attributes Recall ncap calls ncap_var_write() to define newly packed LHS variables If variable is not fixed (e.g., coordinate variables)...*/ if(!var[idx]->is_fix_var){ /* ...and operator will attempt to pack some variables... */ if(nco_pck_plc != nco_pck_plc_nil && nco_pck_plc != nco_pck_plc_upk){ /* ...and expanded variable is pack-able... */ if(nco_pck_plc_typ_get(nco_pck_map,var[idx]->typ_upk,(nc_type *)NULL)){ /* ...and operator will pack this particular variable... */ if( /* ...either because operator newly packs all variables... */ (nco_pck_plc == nco_pck_plc_all_new_att) || /* ...or because operator newly packs un-packed variables like this one... */ (nco_pck_plc == nco_pck_plc_all_xst_att && !var[idx]->pck_ram) || /* ...or because operator re-packs packed variables like this one... */ (nco_pck_plc == nco_pck_plc_xst_new_att && var[idx]->pck_ram) ){ /* ...then add/overwrite dummy scale_factor and add_offset attributes Overwrite these with correct values once known Adding dummy attributes of maximum possible size (NC_DOUBLE) now reduces likelihood that netCDF layer will impose file copy penalties when final attribute values are written later Either add_offset or scale_factor may be removed in nco_pck_val() if nco_var_pck() packing algorithm did not require utilizing it */ const char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ const char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ val_unn zero_unn; /* [frc] Generic container for value 0.0 */ var_sct *zero_var; /* [sct] NCO variable for value 0.0 */ zero_unn.d=0.0; /* [frc] Generic container for value 0.0 */ zero_var=scl_mk_var(zero_unn,typ_out); /* [sct] NCO variable for value 0.0 */ (void)nco_put_att(out_id,var[idx]->id,scl_fct_sng,typ_out,1,zero_var->val.vp); (void)nco_put_att(out_id,var[idx]->id,add_fst_sng,typ_out,1,zero_var->val.vp); zero_var=(var_sct *)nco_var_free(zero_var); } /* endif this variable will be packed or re-packed */ } /* !nco_pck_plc_alw */ } /* endif nco_pck_plc involves packing */ } /* endif variable is processed (not fixed) */ } /* end loop over idx variables to define */ } /* end nco_var_dfn() */ void nco_var_val_cpy /* [fnc] Copy variables data from input to output file */ (const int in_id, /* I [enm] netCDF file ID */ const int out_id, /* I [enm] netCDF output file ID */ var_sct ** const var, /* I/O [sct] Variables to copy to output file */ const int nbr_var) /* I [nbr] Number of variables */ { /* NB: nco_var_val_cpy() contains OpenMP critical region */ /* Purpose: Copy every variable in input variable structure list from input file to output file. Only data (not metadata) are copied. */ int idx; int dmn_idx; long srd_prd=1L; /* [nbr] Product of strides */ for(idx=0;idxxrf->val.vp=var[idx]->val.vp=(void *)nco_malloc(var[idx]->sz*nco_typ_lng(var[idx]->type)); if(var[idx]->nbr_dim == 0){ nco_get_var1(in_id,var[idx]->id,var[idx]->srt,var[idx]->val.vp,var[idx]->type); nco_put_var1(out_id,var[idx]->xrf->id,var[idx]->xrf->srt,var[idx]->xrf->val.vp,var[idx]->type); }else{ /* end if variable is scalar */ if(var[idx]->sz > 0){ /* Do nothing for zero-size record variables */ /* Is stride > 1? */ for(dmn_idx=0;dmn_idxnbr_dim;dmn_idx++) srd_prd*=var[idx]->srd[dmn_idx]; if(srd_prd == 1L){ nco_get_vara(in_id,var[idx]->id,var[idx]->srt,var[idx]->cnt,var[idx]->val.vp,var[idx]->type); nco_put_vara(out_id,var[idx]->xrf->id,var[idx]->xrf->srt,var[idx]->xrf->cnt,var[idx]->xrf->val.vp,var[idx]->type); }else{ (void)nco_get_varm(in_id,var[idx]->id,var[idx]->srt,var[idx]->cnt,var[idx]->srd,(long *)NULL,var[idx]->val.vp,var[idx]->type); (void)nco_put_varm(out_id,var[idx]->xrf->id,var[idx]->xrf->srt,var[idx]->xrf->cnt,var[idx]->xrf->srd,(long *)NULL,var[idx]->xrf->val.vp,var[idx]->type); } /* endif variable has non-unity stride */ } /* end if var_sz */ } /* end if variable is an array */ var[idx]->val.vp=var[idx]->xrf->val.vp=nco_free(var[idx]->val.vp); } /* end loop over idx */ } /* end nco_var_val_cpy() */ nco_bool /* [flg] Variable is listed in a "coordinates" attribute */ nco_is_spc_in_crd_att /* [fnc] Variable is listed in a "coordinates" attribute */ (const int nc_id, /* I [id] netCDF file ID */ const int var_trg_id) /* I [id] Variable ID */ { /* Purpose: Is variable specified in a "coordinates" attribute? Typical variables that appear in a "coordinates" attribute include ... If so, it may be a "multi-dimensional coordinate" that should undergo special treatment by arithmetic operators. */ nco_bool IS_SPC_IN_CRD_ATT=False; /* [flg] Variable is listed in a "coordinates" attribute */ const char dlm_sng[]=" "; /* [sng] Delimiter string */ const char fnc_nm[]="nco_is_spc_in_crd_att()"; /* [sng] Function name */ char **crd_lst; /* [sng] 1D array of list elements */ char *att_val; char att_nm[NC_MAX_NAME]; char var_nm[NC_MAX_NAME]; char var_trg_nm[NC_MAX_NAME]; int idx_att; int idx_crd; int idx_var; int nbr_att; int nbr_crd; /* [nbr] Number of coordinates specified in "coordinates" attribute */ int nbr_var; /* [nbr] Number of variables in file */ int rcd=NC_NOERR; /* [rcd] Return code */ int var_id; /* [id] Variable ID */ long att_sz; nc_type att_typ; /* May need variable name for later comparison to "coordinates" attribute */ rcd+=nco_inq_varname(nc_id,var_trg_id,var_trg_nm); rcd+=nco_inq_nvars(nc_id,&nbr_var); for(idx_var=0;idx_var 0) rcd=nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ crd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_crd); /* ...for each coordinate in "coordinates" attribute... */ for(idx_crd=0;idx_crd 0) rcd=nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ bnd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_bnd); /* ...for each coordinate in "bounds" attribute... */ for(idx_bnd=0;idx_bndnc_id=nc_id; /* 20050519: Not sure why I originally made next four lines SMP-critical 20050629: Making next four lines multi-threaded causes no problems */ /* Refresh variable ID first */ rcd+=nco_inq_varid(var->nc_id,var->nm,&var->id); /* fxm: Not sure if/why necessary to refresh number of dimensions...though it should not hurt */ /* Refresh number of dimensions in variable */ nbr_dim_old=var->nbr_dim; rcd+=nco_inq_varndims(var->nc_id,var->id,&var->nbr_dim); if(nbr_dim_old != var->nbr_dim){ (void)fprintf(stdout,"%s: ERROR Variable \"%s\" changed number of dimensions from %d to %d\n",nco_prg_nm_get(),var->nm,nbr_dim_old,var->nbr_dim); nco_err_exit(0,"nco_var_mtd_refresh()"); } /* endif err */ /* 20100923: Any need to refresh storage properties (shuffle,deflate,dfl_lvl,cnk_sz) here? Certainly they can change between files, that alone is not reason to refresh them Unlike missing values, storage properties in input are transparent to arithmetic The netCDF/HDF5 I/O layer handles all this transparently Moreover, output storage properties must be set just after variable definition, long before nco_var_mtd_refresh() So storage properties of variable in current file cannot affect arithmetic, nor output Hence there is no reason to track current storage properties in var_sct However, if that ever changes, here are hooks to do so */ if(False && var->nbr_dim > 0){ int deflate; /* [flg] Turn on deflate filter */ int srg_typ; /* [enm] Storage type */ rcd+=nco_inq_var_deflate(var->nc_id,var->id,&var->shuffle,&deflate,&var->dfl_lvl); rcd+=nco_inq_var_chunking(var->nc_id,var->id,&srg_typ,var->cnk_sz); } /* endif */ /* Set variable type so following nco_mss_val_get() casts missing_value to correct type */ rcd+=nco_inq_vartype(var->nc_id,var->id,&var->type); /* Refresh number of attributes and missing value attribute, if any */ var->has_mss_val=nco_mss_val_get(var->nc_id,var); #if 0 /* PJR requested warning to be added when multiple file operators worked on variables with missing_value since so many things could go wrong Now un-necessary since multi-file packing ostensibly works Leave code here in case we find it does not work */ if(nco_is_rth_opr(nco_prg_id_get()) && var->pck_dsk){ if(var->has_mss_val) (void)fprintf(stdout,"%s: WARNING Variable \"%s\" is packed and has valid \"NCO_MSS_VAL_SNG\" attribute in multi-file arithmetic operator. Arithmetic on this variable will only be correct if...\n",nco_prg_nm_get(),var_nm); } /* endif variable is packed */ #endif /* endif False */ } /* end nco_var_mtd_refresh() */ void nco_var_srd_srt_set /* [fnc] Assign zero to start and unity to stride vectors in variables */ (var_sct ** const var, /* I [sct] Variables whose subcycle, start, and stride arrays to set */ const int nbr_var) /* I [nbr] Number of structures in variable structure list */ { /* Purpose: Zero start (srt) and stride (srd) arrays of variable This is useful for setting variables to default output state, in which data is written in a block with no offset */ int idx; int idx_dmn; for(idx=0;idxnbr_dim;idx_dmn++){ var[idx]->srt[idx_dmn]=0L; var[idx]->srd[idx_dmn]=1L; } /* end loop over dimensions */ } /* end loop over variables */ } /* end nco_var_srd_srt_set() */ void nco_var_dmn_refresh /* [fnc] Refresh var hyperslab info with var->dim[] info */ (var_sct ** const var, /* I [sct] Variables to refresh */ const int nbr_var) /* I [nbr] Number of structures in variable structure list */ { int idx; int jdx; for(idx=0;idxnbr_dim;jdx++){ var_tmp->srt[jdx]=var_tmp->dim[jdx]->srt; var_tmp->end[jdx]=var_tmp->dim[jdx]->end; var_tmp->cnt[jdx]=var_tmp->dim[jdx]->cnt; var_tmp->srd[jdx]=var_tmp->dim[jdx]->srd; sz*=var_tmp->dim[jdx]->cnt; if(jdx > 0) sz_rec*=var_tmp->dim[jdx]->cnt; } /* end loop over dimensions */ var_tmp->sz=sz; var_tmp->sz_rec=sz_rec; } /* end loop over variables */ } /* end nco_var_dmn_refresh() */ var_sct * /* O [sct] Variable structure */ nco_var_fll /* [fnc] Allocate variable structure and fill with metadata */ (const int nc_id, /* I [id] netCDF file ID */ const int var_id, /* I [id] Variable ID */ const char * const var_nm, /* I [sng] Variable name */ dmn_sct * const * const dim, /* I [sct] Dimensions available to variable */ const int nbr_dim) /* I [nbr] Number of dimensions in list */ { /* Purpose: nco_malloc() and return a completed var_sct */ char dmn_nm[NC_MAX_NAME]; int fl_fmt; int dmn_idx; int idx; int rec_dmn_id; var_sct *var; /* Get file format */ (void)nco_inq_format(nc_id,&fl_fmt); /* Get record dimension ID */ (void)nco_inq(nc_id,(int *)NULL,(int *)NULL,(int *)NULL,&rec_dmn_id); /* Allocate space for variable structure */ var=(var_sct *)nco_malloc(sizeof(var_sct)); (void)var_dfl_set(var); /* [fnc] Set defaults for each member of variable structure */ /* Fill-in known fields */ /* Make sure var_free() frees names when variable is destroyed */ var->nm_fll=NULL; var->nm=(char *)strdup(var_nm); var->id=var_id; var->nc_id=nc_id; /* Get type and number of dimensions and attributes for variable */ (void)nco_inq_var(var->nc_id,var->id,(char *)NULL,&var->typ_dsk,&var->nbr_dim,(int *)NULL,&var->nbr_att); /* Allocate space for dimension information */ if(var->nbr_dim > 0) var->dim=(dmn_sct **)nco_malloc(var->nbr_dim*sizeof(dmn_sct *)); else var->dim=(dmn_sct **)NULL; if(var->nbr_dim > 0) var->dmn_id=(int *)nco_malloc(var->nbr_dim*sizeof(int)); else var->dmn_id=(int *)NULL; if(var->nbr_dim > 0) var->cnk_sz=(size_t *)nco_malloc(var->nbr_dim*sizeof(size_t)); else var->cnk_sz=(size_t *)NULL; if(var->nbr_dim > 0) var->cnt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->cnt=(long *)NULL; if(var->nbr_dim > 0) var->srt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srt=(long *)NULL; if(var->nbr_dim > 0) var->end=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->end=(long *)NULL; if(var->nbr_dim > 0) var->srd=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srd=(long *)NULL; /* Get dimension IDs from input file */ (void)nco_inq_vardimid(var->nc_id,var->id,var->dmn_id); /* Type in memory begins as same type as on disk */ var->type=var->typ_dsk; /* [enm] Type of variable in RAM */ /* Type of packed data on disk */ var->typ_pck=var->type; /* [enm] Type of variable when packed (on disk). This should be same as typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ /* Refresh number of attributes and missing value attribute, if any */ var->has_mss_val=nco_mss_val_get(var->nc_id,var); /* Check variable for duplicate dimensions */ for(idx=0;idxnbr_dim;idx++){ for(dmn_idx=0;dmn_idxnbr_dim;dmn_idx++){ if(idx != dmn_idx){ if(var->dmn_id[idx] == var->dmn_id[dmn_idx]){ /* Dimensions are duplicated when IDs for different ordinal dimensions are equal */ var->has_dpl_dmn=True; break; } /* endif IDs are equal */ } /* endif navel gazing */ } /* endif inner dimension */ /* Found a duplicate, so stop looking */ if(dmn_idx != var->nbr_dim) break; } /* endif outer dimension */ /* Size defaults to 1 in var_dfl_set(), and set to 1 here for extra safety */ var->sz=1L; for(idx=0;idxnbr_dim;idx++){ (void)nco_inq_dimname(nc_id,var->dmn_id[idx],dmn_nm); /* Search input dimension list for matching name */ for(dmn_idx=0;dmn_idxnm)) break; if(dmn_idx == nbr_dim){ (void)fprintf(stdout,"%s: ERROR dimension %s is not in list of dimensions available to nco_var_fll()\n",nco_prg_nm_get(),dmn_nm); if(nco_prg_id_get() == ncap) (void)fprintf(stdout,"%s: HINT This could be a symptom of TODO nco1045. Workaround is avoid use of append mode (i.e., -A switch) in ncap2.\n",nco_prg_nm_get()); else (void)fprintf(stdout,"%s: HINT This could be a symptom of TODO nco111. Workaround is to make sure each dimension in the weighting and masking variable(s) appears in a variable to be processed.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ /* fxm: hmb, what is this for? */ /* Re-define dmn_id so that if dim is dimension list from output file then we get correct dmn_id. Should not affect normal running of routine as usually dim is dimension list from input file */ var->dmn_id[idx]=dim[dmn_idx]->id; var->dim[idx]=dim[dmn_idx]; var->cnt[idx]=dim[dmn_idx]->cnt; var->srt[idx]=dim[dmn_idx]->srt; var->end[idx]=dim[dmn_idx]->end; var->srd[idx]=dim[dmn_idx]->srd; if(var->dmn_id[idx] == rec_dmn_id) var->is_rec_var=True; else var->sz_rec*=var->cnt[idx]; /* NB: dim[idx]->cid will be uninitialized unless dim[idx] is a coordinate Hence divide this into to sequential if statements so valgrind does not complain about relying on uninitialized values */ if(var->dim[idx]->is_crd_dmn){ if(var->id == var->dim[idx]->cid){ var->is_crd_var=True; var->cid=var->dmn_id[idx]; } /* end if */ } /* end if */ /* NB: This assumes default var->sz begins as 1 */ var->sz*=var->cnt[idx]; } /* end loop over dim */ /* 20130112: Variables associated with "bounds" and "coordinates" attributes should, in most cases, be treated as coordinates */ if(nco_is_spc_in_bnd_att(var->nc_id,var->id)) var->is_crd_var=True; if(nco_is_spc_in_crd_att(var->nc_id,var->id)) var->is_crd_var=True; /* Portions of variable structure depend on packing properties, e.g., typ_upk nco_pck_dsk_inq() fills in these portions harmlessly */ (void)nco_pck_dsk_inq(nc_id,var); /* Set deflate and chunking to defaults */ var->dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ var->shuffle=False; /* [flg] Turn on shuffle filter */ for(idx=0;idxnbr_dim;idx++) var->cnk_sz[idx]=(size_t)0L; /* Read deflate levels and chunking (if any) */ if(fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC){ int deflate; /* [enm] Deflate filter is on */ int srg_typ; /* [enm] Storage type */ (void)nco_inq_var_deflate(nc_id,var->id,&var->shuffle,&deflate,&var->dfl_lvl); (void)nco_inq_var_chunking(nc_id,var->id,&srg_typ,var->cnk_sz); } /* endif */ var->undefined=False; /* [flg] Used by ncap parser */ return var; } /* end nco_var_fll() */ nc_type nco_get_typ /* [fnc] Obtain netCDF type to define variable from NCO program ID */ (const var_sct * const var) /* I [sct] Variable to be defined in output file */ { int nco_prg_id; /* [enm] Program ID */ nc_type typ_out=NC_NAT; /* [enm] Type in output file */ nco_prg_id=nco_prg_id_get(); /* [enm] Program ID */ /* Checking only nco_is_rth_opr() is too simplistic 1. All variables handled by arithmetic operators are currently unpacked on reading 2. However "fixed variables" appear in many arithemetic operators ncbo treats coordinate variables as fixed (does not subtract them) ncra treats non-record variables as fixed (does not average them) ncwa treats variables without averaging dimensions as fixed (does not average them) It is best not to alter [un-]pack fixed (non-processed) variables 3. ncap, an arithmetic operator, also has "fixed variables", i.e., pre-existing non-LHS variables copied directly to output. These "fixed" ncap variables should remain unaltered However, this is not presently done nco_var_dfn() needs more information to handle "fixed" variables correctly because Some ncap "fixed" variables appear on RHS in definitions of LHS variables These RHS fixed variables must be separately unpacked during RHS algebra Currently, ncap only calls nco_var_dfn() for fixed variables ncap uses its own routine, ncap_var_write(), for RHS variable definitions 4. All variables in non-arithmetic operators (except ncpdq) should remain un-altered 5. ncpdq is non-arithmetic operator However, ncpdq specially handles fine-grained control [un-]packing options */ if(nco_is_rth_opr(nco_prg_id)){ /* Arithmetic operators store values as unpacked... */ typ_out=var->typ_upk; /* ...with two exceptions... ncap [un-]packing precedes nco_var_dfn() call, sets var->type appropriately */ if(nco_prg_id == ncap) typ_out=var->type; /* ...and pass through fixed (non-processed) variables untouched... */ if(var->is_fix_var) typ_out=var->type; }else{ /* Non-arithmetic operators leave things alone by default ncpdq first modifies var_out->type, then calls nco_var_dfn(), then [un-]packs */ typ_out=var->type; } /* endif arithmetic operator */ return typ_out; } /* nco_get_typ() */ ./nco-4.4.2/src/nco/nco_cnv_arm.h0000644000674300045400000000345112260451231015757 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnv_arm.h,v 1.29 2013/12/31 05:14:01 zender Exp $ */ /* Purpose: ARM conventions */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_cnv_arm.h" *//* ARM conventions */ #ifndef NCO_CNV_ARM_H #define NCO_CNV_ARM_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_att_utl.h" /* Attribute utilities */ #include "nco_mmr.h" /* Memory management */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ nco_bool /* O [flg] File obeys ARM conventions */ nco_cnv_arm_inq /* O [fnc] Check if file obeys ARM conventions */ (const int nc_id); /* I [id] netCDF file ID */ double /* O [s] base_time + current time_offset */ nco_cnv_arm_time_mk /* [fnc] Return time corresponding to current time offset */ (const int nc_id, /* I [id] netCDF file ID */ const double time_offset); /* I [s] Current time offset */ void nco_cnv_arm_time_install /* [fnc] Add time variable to concatenated ARM files */ (const int nc_id, /* I [id] netCDF file ID */ const nco_int base_time_srt, /* I [s] base_time of first input file */ const int dfl_lvl); /* I [enm] Deflate level [0..9] */ nco_int /* O [s] Value of base_time variable */ nco_cnv_arm_base_time_get /* [fnc] Get base_time variable from ARM file */ (const int nc_id); /* I [id] netCDF file ID */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_CNV_ARM_H */ ./nco-4.4.2/src/nco/ncpdq.c0000644000674300045400000012753612276446424014625 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncpdq.c,v 1.391 2014/02/11 16:17:24 zender Exp $ */ /* ncpdq -- netCDF pack, re-dimension, query */ /* Purpose: Pack, re-dimension, query single netCDF file and output to a single file */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncpdq -O -D 3 -a lat,lev,lon -v three_dmn_var ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -a lon,lev,lat -v three_dmn_var ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -a lon,time -x -v three_double_dmn ~/nco/data/in.nc ~/foo.nc;ncks -P ~/foo.nc ncpdq -O -D 3 -P all_new ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P all_xst ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P xst_new ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -P upk ~/nco/data/in.nc ~/foo.nc ncpdq -O -D 3 -a lon,lat -g g21,g22 ~/nco/data/in_grp_3.nc ~/foo.nc ncpdq -O -D 3 -g g1 -v v1 --union -G dude -p ~/nco/data in_grp.nc ~/foo.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { aed_sct *aed_lst_add_fst=NULL_CEWI; aed_sct *aed_lst_scl_fct=NULL_CEWI; nco_bool dmn_rvr_rdr[NC_MAX_DIMS]; /* [flg] Reverse dimensions */ nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool GRP_VAR_UNN=False; /* [flg] Select union of specified groups and variables */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool IS_REORDER=False; /* Re-order mode */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order*/ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=True; /* [flg] Clean memory prior to exit */ char **dmn_rdr_lst_in=NULL_CEWI; /* Option a */ char **dmn_rdr_lst_in_rvr=NULL_CEWI; /* Option a (same list, keep the '-' )*/ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in=NULL_CEWI; char **var_lst_in=NULL_CEWI; char **grp_lst_in=NULL_CEWI; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *nco_pck_plc_sng=NULL_CEWI; /* [sng] Packing policy Option P */ char *nco_pck_map_sng=NULL_CEWI; /* [sng] Packing map Option M */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncpdq.c,v 1.391 2014/02/11 16:17:24 zender Exp $"; const char * const CVS_Revision="$Revision: 1.391 $"; const char * const opt_sht_lst="3467Aa:CcD:d:Fg:G:hL:l:M:Oo:P:p:Rrt:v:UxZ-:"; cnk_sct cnk; /* [sct] Chunking structure */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ dmn_sct **dim=NULL_CEWI; dmn_sct **dmn_out; dmn_sct **dmn_rdr=NULL; /* [sct] Dimension structures to be re-ordered */ extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ gpe_sct *gpe=NULL; /* [sng] Group Path Editing (GPE) structure */ int *in_id_arr; int abb_arg_nbr=0; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int dmn_rdr_nbr=0; /* [nbr] Number of dimension to re-order */ int dmn_rdr_nbr_in=0; /* [nbr] Original number of dimension to re-order */ int fl_idx=int_CEWI; int fl_nbr=0; int fl_in_fmt; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int idx=int_CEWI; int idx_rdr=int_CEWI; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_xtr; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int nco_pck_map=nco_pck_map_flt_sht; /* [enm] Packing map */ int nco_pck_plc=nco_pck_plc_nil; /* [enm] Packing policy */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; int grp_lst_in_nbr=0; /* [nbr] Number of groups explicitly specified by user */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc; var_sct **var_prc_out; trv_tbl_sct *trv_tbl=NULL; /* [lst] Traversal table */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"hdf_upk",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"hdf_unpack",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"mrd",no_argument,0,0}, /* [enm] Multiple Record Dimension convention */ {"multiple_record_dimension",no_argument,0,0}, /* [enm] Multiple Record Dimension convention */ {"msa_usr_rdr",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"msa_user_order",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"intersection",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"nsx",no_argument,0,0}, /* [flg] Select intersection of specified groups and variables */ {"union",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"unn",no_argument,0,0}, /* [flg] Select union of specified groups and variables */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"append",no_argument,0,'A'}, {"arrange",required_argument,0,'a'}, {"permute",required_argument,0,'a'}, {"reorder",required_argument,0,'a'}, {"rdr",required_argument,0,'a'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"gpe",required_argument,0,'G'}, /* [sng] Group Path Edit (GPE) */ {"grp",required_argument,0,'g'}, {"group",required_argument,0,'g'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"pack_map",required_argument,0,'M'}, {"pck_map",required_argument,0,'M'}, {"map",required_argument,0,'M'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"pack_policy",required_argument,0,'P'}, {"pck_plc",required_argument,0,'P'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"unpack",no_argument,0,'U'}, {"upk",no_argument,0,'U'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ /* Initialize traversal table */ trv_tbl_init(&trv_tbl); /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdf_upk") || !strcmp(opt_crr,"hdf_unpack")) nco_upk_cnv=nco_upk_HDF; /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"mrd") || !strcmp(opt_crr,"multiple_record_dimension")) nco_mrd_cnv=nco_mrd_allow; /* [enm] Multiple Record Dimension convention */ if(!strcmp(opt_crr,"msa_usr_rdr") || !strcmp(opt_crr,"msa_user_order")) MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"unn") || !strcmp(opt_crr,"union")) GRP_VAR_UNN=True; if(!strcmp(opt_crr,"nsx") || !strcmp(opt_crr,"intersection")) GRP_VAR_UNN=False; if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Re-order dimensions */ dmn_rdr_lst_in=nco_lst_prs_2D(optarg,",",&dmn_rdr_nbr_in); dmn_rdr_lst_in_rvr=nco_lst_prs_2D(optarg,",",&dmn_rdr_nbr_in); dmn_rdr_nbr=dmn_rdr_nbr_in; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'G': /* Apply Group Path Editing (GPE) to output group */ /* NB: GNU getopt() optional argument syntax is ugly (requires "=" sign) so avoid it http://stackoverflow.com/questions/1052746/getopt-does-not-parse-optional-arguments-to-parameters */ gpe=nco_gpe_prs_arg(optarg); fl_out_fmt=NC_FORMAT_NETCDF4; break; case 'g': /* Copy group argument for later processing */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); grp_lst_in=nco_lst_prs_2D(optarg_lcl,",",&grp_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'M': /* Packing map */ nco_pck_map_sng=(char *)strdup(optarg); nco_pck_map=nco_pck_map_get(nco_pck_map_sng); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'P': /* Packing policy */ nco_pck_plc_sng=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'U': /* Unpacking switch */ nco_pck_plc_sng=(char *)strdup("upk"); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Set re-order flag */ if(dmn_rdr_nbr > 0) IS_REORDER=True; /* No re-order dimensions specified implies packing request */ if(dmn_rdr_nbr == 0){ if(nco_pck_plc == nco_pck_plc_nil) nco_pck_plc=nco_pck_plc_get(nco_pck_plc_sng); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: DEBUG Packing map is %s and packing policy is %s\n",nco_prg_nm_get(),nco_pck_map_sng_get(nco_pck_map),nco_pck_plc_sng_get(nco_pck_plc)); } /* dmn_rdr_nbr != 0 */ /* From this point forward, assume ncpdq operator packs or re-orders, not both */ if(dmn_rdr_nbr > 0 && nco_pck_plc != nco_pck_plc_nil){ (void)fprintf(fp_stdout,"%s: ERROR %s does not support simultaneous dimension re-ordering (-a switch) and packing (-P switch).\nHINT: Invoke %s twice, once to re-order (with -a), and once to pack (with -P).\n",nco_prg_nm,nco_prg_nm,nco_prg_nm); nco_exit(EXIT_FAILURE); } /* endif */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); /* Get file format */ (void)nco_inq_format(in_id,&fl_in_fmt); /* Construct GTT, Group Traversal Table (groups,variables,dimensions, limits) */ (void)nco_bld_trv_tbl(in_id,trv_pth,lmt_nbr,lmt_arg,aux_nbr,aux_arg,MSA_USR_RDR,FORTRAN_IDX_CNV,grp_lst_in,grp_lst_in_nbr,var_lst_in,xtr_nbr,EXTRACT_ALL_COORDINATES,GRP_VAR_UNN,EXCLUDE_INPUT_LIST,EXTRACT_ASSOCIATED_COORDINATES,&flg_dne,trv_tbl); /* Check if all input -d dimensions were found */ (void)nco_chk_dmn(lmt_nbr,flg_dne); /* Create reversed dimension list */ if(dmn_rdr_nbr_in > 0){ int dmn_rdr_nbr_trv=0; /* [nbr] Number of dimensions in all variables to extract that match -a names */ int idx_dmn_rdr_nbr_trv=0; /* [nbr] Index to number of dimensions in all variables to extract that match -a names */ for(int idx_dmn=0;idx_dmnnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Is variable to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_dmn=0;idx_dmn 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); /* Determine and set new dimensionality in metadata of each re-ordered variable */ if(IS_REORDER) (void)nco_var_dmn_rdr_mtd_trv(trv_tbl,nbr_var_prc,var_prc,var_prc_out,nbr_var_fix,var_fix,dmn_rdr,dmn_rdr_nbr,dmn_rvr_rdr); /* Alter metadata for variables that will be packed */ if(nco_pck_plc != nco_pck_plc_nil){ if(nco_pck_plc != nco_pck_plc_upk){ /* Allocate attribute list container for maximum number of entries */ aed_lst_add_fst=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); aed_lst_scl_fct=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); } /* endif packing */ for(idx=0;idx 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Assign zero to start and unity to stride vectors in output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr); /* Copy variable data for non-processed variables */ (void)nco_cpy_fix_var_trv(in_id,out_id,gpe,trv_tbl); /* Close first input netCDF file */ nco_close(in_id); /* Loop over input files (not currently used, fl_nbr == 1) */ for(fl_idx=0;fl_idx= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Input file %d is %s",nco_prg_nm_get(),fl_idx,fl_in); /* Make sure file is on local system and is readable or die trying */ if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(nco_dbg_lvl >= nco_dbg_fl && FL_RTR_RMT_LCN) (void)fprintf(stderr,", local file is %s",fl_in); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ for(thr_idx=0;thr_idxnc_id=in_id; if(nco_dbg_lvl >= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_prc[idx]->nm_fll,trv_tbl); /* Retrieve variable from disk into memory */ (void)nco_msa_var_get_trv(in_id,var_prc[idx],trv_tbl); /* If re-ordering */ if(IS_REORDER){ if((var_prc_out[idx]->val.vp=(void *)nco_malloc_flg(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type))) == NULL){ (void)fprintf(fp_stdout,"%s: ERROR Unable to malloc() %ld*%lu bytes for value buffer for variable %s in main()\n",nco_prg_nm_get(),var_prc_out[idx]->sz,(unsigned long)nco_typ_lng(var_prc_out[idx]->type),var_prc_out[idx]->nm); nco_exit(EXIT_FAILURE); } /* endif err */ /* Change dimensionionality of values */ (void)nco_var_dmn_rdr_val_trv(var_prc[idx],var_prc_out[idx],trv_tbl); /* Re-ordering required two value buffers, time to free input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* IS_REORDER */ /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; if(nco_pck_plc != nco_pck_plc_nil){ /* Copy input variable buffer to processed variable buffer */ /* fxm: this is dangerous and leads to double free()'ing variable buffer */ var_prc_out[idx]->val=var_prc[idx]->val; /* (Un-)Pack variable according to packing specification */ nco_pck_val(var_prc[idx],var_prc_out[idx],nco_pck_map,nco_pck_plc,aed_lst_add_fst+idx,aed_lst_scl_fct+idx); } /* endif nco_pck_plc != nco_pck_plc_nil */ #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ { /* begin OpenMP critical */ /* Copy variable to output file then free value buffer */ if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); }else{ /* end if variable is scalar */ (void)nco_put_vara(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end if variable is array */ } /* end OpenMP critical */ /* Free current output buffer */ var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); } /* end (OpenMP parallel for) loop over idx */ if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(fp_stderr,"\n"); /* Write/overwrite packing attributes for newly packed and re-packed variables Logic here should nearly mimic logic in nco_var_dfn() */ if(nco_pck_plc != nco_pck_plc_nil && nco_pck_plc != nco_pck_plc_upk){ /* ...put file in define mode to allow metadata writing... */ (void)nco_redef(out_id); /* ...loop through all variables that may have been packed... */ for(idx=0;idxnm_fll,trv_tbl); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* nco_var_dfn() pre-defined dummy packing attributes in output file only for "packable" input variables */ if(nco_pck_plc_typ_get(nco_pck_map,var_prc[idx]->typ_upk,(nc_type *)NULL)){ /* Verify input variable was newly packed by this operator Writing pre-existing (non-re-packed) attributes here would fail because nco_pck_dsk_inq() never fills in var->scl_fct.vp and var->add_fst.vp Logic is same as in nco_var_dfn() (except var_prc[] instead of var[]) If operator newly packed this particular variable... */ if( /* ...either because operator newly packs all variables... */ (nco_pck_plc == nco_pck_plc_all_new_att) || /* ...or because operator newly packs un-packed variables like this one... */ (nco_pck_plc == nco_pck_plc_all_xst_att && !var_prc[idx]->pck_ram) || /* ...or because operator re-packs packed variables like this one... */ (nco_pck_plc == nco_pck_plc_xst_new_att && var_prc[idx]->pck_ram) ){ /* Replace dummy packing attributes with final values, or delete them */ if(nco_dbg_lvl >= nco_dbg_io) (void)fprintf(stderr,"%s: main() replacing dummy packing attribute values for variable %s\n",nco_prg_nm,var_prc[idx]->nm); (void)nco_aed_prc(grp_out_id,aed_lst_add_fst[idx].id,aed_lst_add_fst[idx]); (void)nco_aed_prc(grp_out_id,aed_lst_scl_fct[idx].id,aed_lst_scl_fct[idx]); } /* endif variable is newly packed by this operator */ } /* !nco_pck_plc_alw */ } /* end loop over var_prc */ /* Take output file out of define mode */ if(hdr_pad == 0UL) (void)nco_enddef(out_id); else (void)nco__enddef(out_id,hdr_pad); } /* nco_pck_plc == nco_pck_plc_nil || nco_pck_plc == nco_pck_plc_upk */ /* Close input netCDF file */ for(thr_idx=0;thr_idx 0){ if(dmn_rdr_nbr_in > 0) { dmn_rdr_lst_in=nco_sng_lst_free(dmn_rdr_lst_in,dmn_rdr_nbr_in); dmn_rdr_lst_in_rvr=nco_sng_lst_free(dmn_rdr_lst_in_rvr,dmn_rdr_nbr_in); } /* Free dimension list pointers */ dmn_rdr=(dmn_sct **)nco_free(dmn_rdr); /* Dimension structures in dmn_rdr are owned by dmn and dmn_out, free'd later */ } /* endif dmn_rdr_nbr > 0 */ if(nco_pck_plc != nco_pck_plc_nil){ if(nco_pck_plc_sng) nco_pck_plc_sng=(char *)nco_free(nco_pck_plc_sng); if(nco_pck_map_sng) nco_pck_map_sng=(char *)nco_free(nco_pck_map_sng); if(nco_pck_plc != nco_pck_plc_upk){ /* No need for loop over var_prc variables to free attribute values Variable structures and attribute edit lists share same attribute values Free them only once, and do it in nco_var_free() */ aed_lst_add_fst=(aed_sct *)nco_free(aed_lst_add_fst); aed_lst_scl_fct=(aed_sct *)nco_free(aed_lst_scl_fct); } /* nco_pck_plc == nco_pck_plc_upk */ } /* nco_pck_plc == nco_pck_plc_nil */ /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_arr) in_id_arr=(int *)nco_free(in_id_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) cnk.cnk_dmn=(cnk_dmn_sct **)nco_cnk_lst_free(cnk.cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); if(xtr_nbr > 0) var_out=nco_var_lst_free(var_out,xtr_nbr); var_prc=(var_sct **)nco_free(var_prc); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix=(var_sct **)nco_free(var_fix); var_fix_out=(var_sct **)nco_free(var_fix_out); trv_tbl_free(trv_tbl); for(idx=0;idx /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, printf */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_mmr.h" /* Memory management */ #ifdef _MSC_VER # include "nco_rth_flt.h" /* Float-precision arithmetic, MSVC macros */ #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void cast_void_nctype /* [fnc] Cast generic pointer to netCDF type */ (const nc_type type, /* I [enm] netCDF type to cast void pointer to */ ptr_unn * const ptr); /* I/O [ptr] Pointer to pointer union whose vp element will be cast to type type*/ void cast_nctype_void /* [fnc] Cast generic pointer in ptr_unn structure from type type to type void */ (const nc_type type, /* I [enm] netCDF type of pointer */ ptr_unn * const ptr); /* I/O pointer to pointer union which to cast from type type to type void */ var_sct * /* O [var] Variable after (possible) conversion */ nco_typ_cnv_rth /* [fnc] Convert char, short, long, int types to doubles before arithmetic */ (var_sct *var, /* I/O [var] Variable to be considered for conversion */ const int nco_op_typ); /* I [enm] Operation type */ var_sct * /* O [sct] Variable reverted to on-disk type */ nco_cnv_var_typ_dsk /* [fnc] Revert variable to on-disk type */ (var_sct *var); /* I [sct] Variable to be reverted */ var_sct * /* O [sct] Pointer to variable structure of type var_out_typ */ nco_var_cnf_typ /* [fnc] Return copy of input variable typecast to desired type */ (const nc_type var_out_typ, /* I [enm] Type to convert variable structure to */ var_sct * const var_in); /* I/O [enm] Pointer to variable structure (may be destroyed) */ var_sct * /* O [sct] Pointer to variable structure of type var_out_typ */ nco_var_cnf_typ_tst /* [fnc] Return copy of input variable typecast to desired type */ (const nc_type var_out_typ, /* I [enm] Type to convert variable structure to */ var_sct * const var_in); /* I/O [enm] Pointer to variable structure (may be destroyed) */ var_sct * /* O [sct] Variable with mss_val converted to typ_upk */ nco_cnv_mss_val_typ /* [fnc] Convert missing_value, if any, to mss_val_out_typ */ (var_sct *var, /* I [sct] Variable with missing_value to convert */ const nc_type mss_val_out_typ); /* I [enm] Type of mss_val on output */ void nco_val_cnf_typ /* [fnc] Copy val_in and typecast from typ_in to typ_out */ (const nc_type typ_in, /* I [enm] Type of input value */ ptr_unn val_in, /* I [ptr] Pointer to input value */ const nc_type typ_out, /* I [enm] Type of output value */ ptr_unn val_out); /* I [ptr] Pointer to output value */ int /* O [enm] Dummy return */ nco_scv_cnf_typ /* [fnc] Convert scalar attribute to typ_new using C implicit coercion */ (const nc_type typ_new, /* I [enm] Type to convert scv_old to */ scv_sct * const scv_old); /* I/O [sct] Scalar value to convert */ nc_type /* O [enm] Return Highest type */ ncap_typ_hgh /* [fnc] Promote variable to higher common precision */ (nc_type typ_1, /* I [enm] type */ nc_type typ_2); /* I [enm] type */ nc_type /* O [enm] Highest precision of input variables */ ncap_var_retype /* [fnc] Promote variable to higher common precision */ (var_sct *var_1, /* I/O [sct] Variable */ var_sct *var_2); /* I/O [sct] Variable */ nc_type /* O [enm] Highest precision of arguments */ ncap_scv_scv_cnf_typ_hgh_prc /* [fnc] Promote arguments to higher precision if necessary */ (scv_sct * const scv_1, /* I/O [sct] Scalar value */ scv_sct * const scv_2); /* I/O [sct] Scalar value */ nc_type /* O [enm] Highest precision of arguments */ ncap_var_scv_cnf_typ_hgh_prc /* [fnc] Promote arguments to higher precision if necessary */ (var_sct ** const var, /* I/O [sct] Variable */ scv_sct * const scv); /* I/O [sct] Scalar value */ nco_bool /* O [flg] Input is signed type */ nco_typ_sgn /* [fnc] Identify signed types */ (const nc_type typ_in); /* I [enm] Type to check for signedness */ nco_bool /* O [flg] Input is netCDF3 atomic type */ nco_typ_nc3 /* [fnc] Identify netCDF3 atomic types */ (const nc_type typ_in); /* I [enm] Type to check netCDF3 compliance */ nc_type /* O [enm] netCDF3 type */ nco_typ_nc4_nc3 /* [fnc] Convert netCDF4 to netCDF3 atomic type */ (const nc_type typ_nc4); /* I [enm] netCDF4 type */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_CNF_TYP_H */ ./nco-4.4.2/src/nco/nco_srm.h0000644000674300045400000000260112260451232015130 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_srm.h,v 1.2 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Streams */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_srm.h" *//* Streams */ #ifndef NCO_SRM_H #define NCO_SRM_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_cnf_typ.h" /* Conform variable types */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_mmr.h" /* Memory management */ #include "nco_sng_utl.h" /* String utilities */ typedef unsigned char nco_srm_mgc_t; /* ncstream MAGIC primitives are 4-bytes long */ typedef struct nco_srm_sct{ nco_srm_mgc_t mgc_srt[4]; nco_srm_mgc_t mgc_end[4]; } nco_srm_t; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void nco_srm_hdr /* [fnc] Write header to stream */ (void); #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_SRM_H */ ./nco-4.4.2/src/nco/nco_md5.c0000644000674300045400000004737412260451232015027 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_md5.c,v 1.21 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: NCO utilities for MD5 digests */ /* Copyright (C) 2012--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: ncecat -O -D 1 --md5 -p ~/nco/data in.nc in.nc ~/foo.nc ncrcat -O -D 1 --md5 -p ~/nco/data in.nc in.nc ~/foo.nc ncks -O -D 1 -H -C -m --md5 -v md5_a,md5_abc ~/nco/data/in.nc ncks -O -D 1 -H -C -m --md5 -v md5_a,md5_abc -p http://thredds-test.ucar.edu/thredds/dodsC/testdods in.nc ncks -O -D 1 -C -m --md5 -v md5_a,md5_abc,one_dmn_rec_var ~/nco/data/in.nc ncks -O -D 1 -C -d lev,0 -m --md5 -v md5_a,md5_abc,one_dmn_rec_var ~/nco/data/in.nc */ /* This NCO file contains the entirety of the MD5 implementation by L. Peter Deutsch of Aladdin Software (aka author of Ghostscript). NCO-specific functions are defined first. The NCO-copyright applies only to the NCO-specific functions. LPD's md5.c is included in a nearly unaltered state. That code is covered by LPD's copyright. */ #include "nco_md5.h" /* MD5 digests */ md5_sct * /* [sct] MD5 configuration */ nco_md5_ini(void) /* [fnc] Initialize and return MD5 configuration structure */ { /* Purpose: Initialize and return MD5 configuration structure */ md5_sct *md5; /* [sct] MD5 configuration */ md5=(md5_sct *)nco_malloc(sizeof(md5_sct)); md5->att_nm=(char *)strdup("MD5"); md5->dgs=False; md5->wrt=False; return md5; } /* end nco_md5_ini() */ md5_sct * /* [sct] MD5 configuration */ nco_md5_free /* [fnc] Free MD5 configuration structure */ (md5_sct *md5) /* [sct] MD5 configuration structure to free */ { /* Purpose: Initialize and return MD5 configuration structure */ if(md5->att_nm) md5->att_nm=(char *)nco_free(md5->att_nm); if(md5) md5=(md5_sct *)nco_free(md5); return md5; } /* end nco_md5_ini() */ void nco_md5_chk /* [fnc] Perform and optionally compare MD5 digest(s) on hyperslab */ (const md5_sct * const md5, /* I [sct] MD5 Configuration */ const char * const var_nm, /* I [sng] Input variable name */ const long var_sz_byt, /* I [nbr] Size (in bytes) of hyperslab in RAM */ const int nc_id, /* I [id] netCDF file ID */ const long * const dmn_srt, /* I [idx] Contiguous vector of indices to start of hyperslab on disk */ const long * const dmn_cnt, /* I [nbr] Contiguous vector of lengths of hyperslab on disk */ void * const vp) /* I/O [val] Values to digest */ { /* Purpose: Perform MD5 digest on hyperslab in RAM Optionally do same for hyperslab written to disk and compare with RAM digest NB: Input argument var_sz_byt is independent of dmn_srt and dmn_cnt Routine uses var_sz_byt _only_ for MD5 digest of RAM variable That is why this input is const Iff MD5 of disk hyperslab is requested, then routine uses nc_id and var_nm to obtain var_id, dmn_nbr, var_typ_dsk of variable on disk. From these we obtain var_sz_dsk and var_sz_byt In other words, MD5(RAM) depends only on information provided in RAM while MD5(disk) utilizes netCDF layer to assemble hyperslab data. Idea is that this provides the best comparison of RAM vs. disk hyperslabs */ int nco_prg_id; /* [enm] Program ID */ char md5_dgs_hxd_sng_ram[NCO_MD5_DGS_SZ*2+1]; nco_bool MD5_DGS_DSK=False; /* [flg] Perform MD5 digest of variable written to disk */ nco_prg_id=nco_prg_id_get(); /* [enm] Program ID */ /* MD5 digest of hyperslab already in RAM */ (void)nco_md5_chk_ram(var_sz_byt,vp,md5_dgs_hxd_sng_ram); if((nco_prg_id == ncks && nco_dbg_lvl_get() >= nco_dbg_std) || ((nco_prg_id == ncecat || nco_prg_id == ncrcat) && nco_dbg_lvl_get() >= nco_dbg_var) || False) (void)fprintf(stderr,"%s: INFO MD5(%s) = %s\n",nco_prg_nm_get(),var_nm,md5_dgs_hxd_sng_ram); /* Write MD5 attributes */ if(md5->wrt){ /* Test with: ncks -O -C -4 -D 1 --md5_wrt -v md5_.? ~/nco/data/in.nc ~/foo.nc */ aed_sct aed_md5; aed_md5.att_nm=md5->att_nm; aed_md5.var_nm=NULL; (void)nco_inq_varid(nc_id,var_nm,&aed_md5.id); aed_md5.sz=NCO_MD5_DGS_SZ*2L; aed_md5.type=NC_CHAR; aed_md5.val.cp=md5_dgs_hxd_sng_ram; aed_md5.mode=aed_overwrite; if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stderr,"%s: INFO Writing MD5 digest to attribute %s of variable %s\n",nco_prg_nm_get(),aed_md5.att_nm,var_nm); (void)nco_aed_prc(nc_id,aed_md5.id,aed_md5); } /* !wrt */ /* NB: Setting this flag significantly increases execution time Comparing RAM to disk requires reading hyperslab from disk Hence it essentially doubles numbers of disk reads, e.g., ncrcat reads/writes only one record of one variable at a time, and will perform an extra read to digest each write. Default strategy is to turn on MD5 disk-checking only when user is concatenating files */ if(nco_prg_id == ncrcat || nco_prg_id == ncecat) MD5_DGS_DSK=True; /* [flg] Perform MD5 digest of variable written to disk */ /* Compare this digest to what is read in from output netCDF file This implementation re-uses vp to hold data read from disk Advantages of this include lower overall memory usage Assumptions include: 1. Original vp data are written to disk just before MD5 digest above 2. Original vp data are no longer needed in calling routine, i.e., ncks or ncrcat Hence calls to nco_md5_chk() should occur just after put_vara() and prior to free() 3. vp data are contiguous and may be read with a single get_vara() call */ if(MD5_DGS_DSK){ char md5_dgs_hxd_sng_dsk[NCO_MD5_DGS_SZ*2+1]; int dmn_idx; int dmn_nbr; int var_id; long var_sz_dsk=1L; /* [nbr] Size (in elements) of variable on disk */ long var_sz_byt_dsk; /* [nbr] Size (in bytes) of variable (hyperslab) on disk */ nc_type var_typ_dsk; /* [enm] netCDF type of variable on disk */ /* Get var_id for requested variable */ (void)nco_inq_varid(nc_id,var_nm,&var_id); /* Get type and number of dimensions for variable */ (void)nco_inq_var(nc_id,var_id,(char *)NULL,&var_typ_dsk,&dmn_nbr,(int *)NULL,(int *)NULL); for(dmn_idx=0;dmn_idx= nco_dbg_var) (void)fprintf(stderr,"%s: INFO MD5 digests of RAM and disk contents for %s agree\n",nco_prg_nm_get(),var_nm); } /* endif digests agree */ } /* !MD5_DGS_DSK */ } /* end nco_md5_chk() */ void nco_md5_chk_ram /* [fnc] Perform MD5 digest on hyperslab in RAM */ (const long var_sz_byt, /* I [nbr] Size (in bytes) of hyperslab */ const void * const vp, /* I [val] Values to digest */ char md5_dgs_hxd_sng[NCO_MD5_DGS_SZ*2+1]) /* O [sng] MD5 digest */ { /* Purpose: Perform MD5 digest on hyperslab */ int idx_dgs; md5_state_t md5_stt; md5_byte_t md5_dgs_byt[NCO_MD5_DGS_SZ]; /* Sequence of MD5 digest determined by LPD's implementation */ md5_init(&md5_stt); md5_append(&md5_stt,(const md5_byte_t *)vp,var_sz_byt); md5_finish(&md5_stt,md5_dgs_byt); for(idx_dgs=0;idx_dgs. Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + F(b,c,d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + G(b,c,d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti) \ t = a + H(b,c,d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti) \ t = a + I(b,c,d) + X[k] + Ti; \ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } ./nco-4.4.2/src/nco/nco_cnk.c0000644000674300045400000015125212301224440015077 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnk.c,v 1.119 2014/02/19 21:58:56 zender Exp $ */ /* Purpose: NCO utilities for chunking */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: ncks -O -4 -D 4 --cnk_scl=8 ~/nco/data/in.nc ~/foo.nc ncks -O -4 -D 4 --cnk_scl=8 ${DATA}/dstmch90/dstmch90_clm.nc ~/foo.nc ncks -O -4 -D 4 --cnk_dmn time,10 ~/nco/data/in.nc ~/foo.nc ncks -O -4 -D 4 --cnk_dmn time,10 --cnk_map=dmn ~/nco/data/in.nc ~/foo.nc ncks -O -4 -D 4 --cnk_map=dmn -d time,0,3 ~/nco/data/in.nc ~/foo.nc ncks -O -4 -D 4 --cnk_dmn lat,64 --cnk_dmn lon,128 ${DATA}/dstmch90/dstmch90_clm.nc ~/foo.nc ncks -O -4 -D 4 --cnk_plc=uck ~/foo.nc ~/foo.nc ncks -O -4 -D 4 --cnk_plc=g2d --cnk_map=rd1 --cnk_dmn lat,64 --cnk_dmn lon,128 ${DATA}/dstmch90/dstmch90_clm.nc ~/foo.nc ncks -O -4 -D 4 --cnk_plc=all ~/nco/data/in.nc ~/foo.nc # Chunk unchunked data ncks -O -4 -D 4 --cnk_plc=uck ~/foo.nc ~/foo.nc # Unchunk chunked data ncks -O -4 -D 4 --cnk_plc=all ~/foo.nc ~/foo.nc # Chunk chunked data ncks -O -4 -D 4 --cnk_plc=uck ~/nco/data/in.nc ~/foo.nc # Unchunk unchunked data ncks -O -C --cnk_plc=xst --cnk_map=xst -g g13 -v one,two,three,four -p ~/nco/data in_grp.nc ~/foo.nc ncks -O -4 -C --cnk_plc=all --cnk_map=lfp ~/nco/data/in.nc ~/foo.nc ncks -C -m --hdn --cdl ~/foo.nc ncecat testing: ncecat -O -4 -D 4 --cnk_plc=all -p ~/nco/data in.nc in.nc ~/foo.nc ncecat -O -4 -D 4 --cnk_plc=g2d --cnk_map=rd1 --cnk_dmn lat,64 --cnk_dmn lon,128 -p ${DATA}/dstmch90 dstmch90_clm.nc dstmch90_clm.nc ~/foo.nc ncwa testing: ncwa -O -4 -D 4 -a time --cnk_plc=g2d --cnk_map=rd1 --cnk_dmn lat,32 --cnk_dmn lon,128 -p ${DATA}/dstmch90 dstmch90_clm_0112.nc ~/foo.nc Advanced Chunking: http://hdfeos.org/workshops/ws13/presentations/day1/HDF5-EOSXIII-Advanced-Chunking.ppt http://www.hdfgroup.org/HDF5/doc/H5.user/Chunking.html http://www.unidata.ucar.edu/blogs/developer/en/entry/chunking_data_why_it_matters http://www.unidata.ucar.edu/blogs/developer/en/entry/chunking_data_choosing_shapes http://www.unidata.ucar.edu/software/netcdf/docs/default_chunking_4_0_1.html http://www.unidata.ucar.edu/software/netcdf/docs_rc/default_chunking_4_1.html */ #include "nco_cnk.h" /* Chunking */ const char * /* O [sng] Chunking map string */ nco_cnk_map_sng_get /* [fnc] Convert chunking map enum to string */ (const int nco_cnk_map) /* I [enm] Chunking map */ { /* Purpose: Convert chunking map enum to string */ switch(nco_cnk_map){ case nco_cnk_map_nil: return "nil"; case nco_cnk_map_dmn: return "dmn"; case nco_cnk_map_rd1: return "rd1"; case nco_cnk_map_scl: return "scl"; case nco_cnk_map_prd: return "prd"; case nco_cnk_map_lfp: return "lfp"; case nco_cnk_map_xst: return "xst"; case nco_cnk_map_rew: return "rew"; default: nco_dfl_case_cnk_map_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_cnk_map_sng_get() */ const char * /* O [sng] Chunking policy string */ nco_cnk_plc_sng_get /* [fnc] Convert chunking policy enum to string */ (const int nco_cnk_plc) /* I [enm] Chunking policy */ { /* Purpose: Convert chunking policy enum to string */ switch(nco_cnk_plc){ case nco_cnk_plc_nil: return "nil"; case nco_cnk_plc_all: return "all"; case nco_cnk_plc_g2d: return "g2d"; case nco_cnk_plc_g3d: return "g3d"; case nco_cnk_plc_xpl: return "xpl"; case nco_cnk_plc_xst: return "xst"; case nco_cnk_plc_uck: return "uck"; default: nco_dfl_case_cnk_plc_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_cnk_plc_sng_get() */ void nco_dfl_case_cnk_map_err(void) /* [fnc] Print error and exit for illegal switch(cnk_map) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(cnk_map) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_cnk_map_err()"; (void)fprintf(stdout,"%s: ERROR switch(cnk_map) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(cnk_map) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_cnk_map_err() */ void nco_dfl_case_cnk_plc_err(void) /* [fnc] Print error and exit for illegal switch(cnk_plc) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(cnk_plc) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_cnk_plc_err()"; (void)fprintf(stdout,"%s: ERROR switch(cnk_plc) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(cnk_plc) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_cnk_plc_err() */ int /* [rcd] Return code */ nco_cnk_ini /* [fnc] Create structure with all chunking information */ (const char * const fl_out, /* I [sng] Output filename */ CST_X_PTR_CST_PTR_CST_Y(char,cnk_arg), /* I [sng] List of user-specified chunksizes */ const int cnk_nbr, /* I [nbr] Number of chunksizes specified */ const int cnk_map, /* I [enm] Chunking map */ const int cnk_plc, /* I [enm] Chunking policy */ const size_t cnk_sz_byt, /* I [B] Chunk size in bytes */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ cnk_sct * const cnk) /* O [sct] Chunking structure */ { /* Purpose: Create structure with all chunking information */ int rcd=0; /* [enm] Return code */ size_t fl_sys_blk_sz=0UL; /* [nbr] File system blocksize for I/O */ /* Initialize */ cnk->flg_usr_rqs=False; cnk->cnk_dmn=NULL_CEWI; cnk->cnk_nbr=cnk_nbr; cnk->cnk_map=cnk_map; cnk->cnk_plc=cnk_plc; cnk->cnk_sz_scl=cnk_sz_scl; cnk->cnk_sz_byt=cnk_sz_byt; /* For now, let cnk_sz_scl play double duty */ /* Did user explicitly request chunking? */ if(cnk_nbr > 0 || cnk_sz_byt > 0UL || cnk_sz_scl > 0UL || cnk_map != nco_cnk_map_nil || cnk_plc != nco_cnk_plc_nil) cnk->flg_usr_rqs=True; /* Chunks are atomic unit of HDF5 read/write Variables are compressed and check-summed one chunk at-a-time Set NCO_CNK_SZ_BYT_DFL to system blocksize, if known Setting chunksize equal to system blocksize thought to minimize disk head movement, be most efficient Blocksize is related to default buffer; check this with ncks -O -4 -D 6 -v one ~/nco/data/in.nc ~/foo.nc Buffer is at least twice and sometimes sixteen times Blocksize: Blocksize Buffer Linux default 4096 8192 Yellowstone /home 32768 524288 Yellowstong /glade 131072 524288 Yellowstong /tmp 4096 524288 <-- probably hardcoded default not actual blocksize reported */ /* Discover blocksize if possible */ fl_sys_blk_sz=nco_fl_blocksize(fl_out); /* Linux default blocksize is 4096 B */ #define NCO_CNK_SZ_BYT_DFL 4096 if(cnk_sz_byt > 0ULL){ /* Use user-specified chunk size if available */ cnk->cnk_sz_byt=cnk_sz_byt; }else{ /* Otherwise use filesystem blocksize if valid, otherwise use Linux default */ cnk->cnk_sz_byt= (fl_sys_blk_sz > 0ULL) ? fl_sys_blk_sz : NCO_CNK_SZ_BYT_DFL; } /* end else */ if(cnk_sz_byt <= 0ULL) cnk->cnk_sz_byt=NCO_CNK_SZ_BYT_DFL; /* Make uniform list of user-specified per-dimension chunksizes */ if(cnk->cnk_nbr > 0) cnk->cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Set actual chunk policy and map to defaults as necessary */ if(cnk_map == nco_cnk_map_nil) cnk->cnk_map=nco_cnk_map_get((char *)NULL); if(cnk_plc == nco_cnk_plc_nil) cnk->cnk_plc=nco_cnk_plc_get((char *)NULL); return rcd; } /* end nco_cnk_ini() */ cnk_dmn_sct ** /* O [sct] Structure list with user-specified per-dimension chunking information */ nco_cnk_prs /* [fnc] Create chunking structures with name and chunksize elements */ (const int cnk_nbr, /* I [nbr] Number of chunksizes specified */ CST_X_PTR_CST_PTR_CST_Y(char,cnk_arg)) /* I [sng] List of user-specified chunksizes */ { /* Purpose: Determine name and per-dimension chunksize elements from user arguments Routine merely evaluates syntax of input expressions and does not attempt to validate dimensions or chunksizes against input file. Routine based on nco_lmt_prs() */ /* Valid syntax adheres to nm,cnk_sz */ void nco_usg_prn(void); char **arg_lst; char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ const char dlm_sng[]=","; cnk_dmn_sct **cnk_dmn=NULL_CEWI; int idx; int arg_nbr; if(cnk_nbr > 0) cnk_dmn=(cnk_dmn_sct **)nco_malloc(cnk_nbr*sizeof(cnk_dmn_sct *)); for(idx=0;idx 2 || /* Too much information */ arg_lst[0] == NULL || /* Dimension name not specified */ False){ (void)fprintf(stdout,"%s: ERROR in chunksize specification for dimension %s\n%s: HINT Conform request to chunksize documentation at http://nco.sf.net/nco.html#cnk\n",nco_prg_nm_get(),cnk_arg[idx],nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ /* Initialize structure */ /* cnk strings that are not explicitly set by user remain NULL, i.e., specifying default setting will appear as if nothing at all was set. Hopefully, in routines that follow, branch followed when dimension has all default settings specified (e.g.,"-d foo,,,,") yields same answer as branch for which no hyperslab along that dimension was set. */ cnk_dmn[idx]=(cnk_dmn_sct *)nco_malloc(sizeof(cnk_dmn_sct)); cnk_dmn[idx]->nm=NULL; cnk_dmn[idx]->nm_fll=NULL; cnk_dmn[idx]->is_usr_spc_cnk=True; /* True if any part of limit is user-specified, else False */ /* Parse input name into a temporary string and inquire if name is absolute or relative */ char *sng_tmp=arg_lst[0]; nco_bool is_fll_pth=nco_is_fll_pth(sng_tmp); if(is_fll_pth) cnk_dmn[idx]->nm_fll=(char *)strdup(sng_tmp); else cnk_dmn[idx]->nm=(char *)strdup(sng_tmp); /* 20130711: Debian Mayhem project bug #716602 shows unsanitized input can cause core-dump _inside_ strtoul() */ cnk_dmn[idx]->sz=strtoul(arg_lst[1],&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(arg_lst[1],"strtoul",sng_cnv_rcd); /* Free current pointer array to strings Strings themselves are untouched and will be free()'d with chunk structures in nco_cnk_lst_free() */ arg_lst=(char **)nco_free(arg_lst); } /* end loop over cnk structure list */ return cnk_dmn; } /* end nco_cnk_prs() */ cnk_dmn_sct ** /* O [sct] Pointer to free'd structure list */ nco_cnk_lst_free /* [fnc] Free memory associated with chunking structure list */ (cnk_dmn_sct **cnk_lst, /* I/O [sct] Chunking structure list to free */ const int cnk_nbr) /* I [nbr] Number of chunking structures in list */ { /* Threads: Routine is thread safe and calls no unsafe routines */ /* Purpose: Free all memory associated with dynamically allocated chunking structure list */ int idx; for(idx=0;idxnm) cnk_dmn->nm=(char *)nco_free(cnk_dmn->nm); if(cnk_dmn->nm_fll) cnk_dmn->nm_fll=(char *)nco_free(cnk_dmn->nm_fll); /* Free structure pointer last */ if(cnk_dmn) cnk_dmn=(cnk_dmn_sct *)nco_free(cnk_dmn); return NULL; } /* end nco_cnk_dmn_free() */ int /* O [enm] Chunking map */ nco_cnk_map_get /* [fnc] Convert user-specified chunking map to key */ (const char *nco_cnk_map_sng) /* [sng] User-specified chunking map */ { /* Purpose: Convert user-specified string to chunking map Return nco_cnk_map_rd1 by default */ const char fnc_nm[]="nco_cnk_map_get()"; /* [sng] Function name */ char *nco_prg_nm; /* [sng] Program name */ nco_prg_nm=nco_prg_nm_get(); /* [sng] Program name */ if(nco_cnk_map_sng == NULL){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s reports %s invoked without explicit chunking map. Defaulting to chunking map \"rd1\".\n",nco_prg_nm,fnc_nm,nco_prg_nm); return nco_cnk_map_rd1; } /* endif */ if(!strcmp(nco_cnk_map_sng,"nil")) return nco_cnk_map_nil; if(!strcmp(nco_cnk_map_sng,"cnk_map_nil")) return nco_cnk_map_nil; if(!strcmp(nco_cnk_map_sng,"dmn")) return nco_cnk_map_dmn; if(!strcmp(nco_cnk_map_sng,"cnk_map_dmn")) return nco_cnk_map_dmn; if(!strcmp(nco_cnk_map_sng,"rd1")) return nco_cnk_map_rd1; if(!strcmp(nco_cnk_map_sng,"cnk_map_rd1")) return nco_cnk_map_rd1; if(!strcmp(nco_cnk_map_sng,"scl")) return nco_cnk_map_scl; if(!strcmp(nco_cnk_map_sng,"cnk_map_scl")) return nco_cnk_map_scl; if(!strcmp(nco_cnk_map_sng,"prd")) return nco_cnk_map_prd; if(!strcmp(nco_cnk_map_sng,"cnk_map_prd")) return nco_cnk_map_prd; if(!strcmp(nco_cnk_map_sng,"lfp")) return nco_cnk_map_lfp; if(!strcmp(nco_cnk_map_sng,"cnk_map_lfp")) return nco_cnk_map_lfp; if(!strcmp(nco_cnk_map_sng,"xst")) return nco_cnk_map_xst; if(!strcmp(nco_cnk_map_sng,"cnk_map_xst")) return nco_cnk_map_xst; if(!strcmp(nco_cnk_map_sng,"rew")) return nco_cnk_map_rew; if(!strcmp(nco_cnk_map_sng,"cnk_map_rew")) return nco_cnk_map_rew; (void)fprintf(stderr,"%s: ERROR %s reports unknown user-specified chunking map %s\n",nco_prg_nm_get(),fnc_nm,nco_cnk_map_sng); nco_exit(EXIT_FAILURE); return nco_cnk_map_nil; /* Statement should not be reached */ } /* end nco_cnk_map_get() */ int /* O [enm] Chunking policy */ nco_cnk_plc_get /* [fnc] Convert user-specified chunking policy to key */ (const char *nco_cnk_plc_sng) /* [sng] User-specified chunking policy */ { /* Purpose: Convert user-specified string to chunking operation type Return nco_cnk_plc_g2d by default */ const char fnc_nm[]="nco_cnk_plc_get()"; /* [sng] Function name */ char *nco_prg_nm; /* [sng] Program name */ nco_prg_nm=nco_prg_nm_get(); /* [sng] Program name */ if(nco_cnk_plc_sng == NULL){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s reports %s invoked without explicit chunking policy. Defaulting to chunking policy \"g2d\".\n",nco_prg_nm,fnc_nm,nco_prg_nm); return nco_cnk_plc_g2d; } /* endif */ if(!strcmp(nco_cnk_plc_sng,"nil")) return nco_cnk_plc_nil; if(!strcmp(nco_cnk_plc_sng,"cnk_nil")) return nco_cnk_plc_nil; if(!strcmp(nco_cnk_plc_sng,"plc_nil")) return nco_cnk_plc_nil; if(!strcmp(nco_cnk_plc_sng,"all")) return nco_cnk_plc_all; if(!strcmp(nco_cnk_plc_sng,"cnk_all")) return nco_cnk_plc_all; if(!strcmp(nco_cnk_plc_sng,"plc_all")) return nco_cnk_plc_all; if(!strcmp(nco_cnk_plc_sng,"g2d")) return nco_cnk_plc_g2d; if(!strcmp(nco_cnk_plc_sng,"cnk_g2d")) return nco_cnk_plc_g2d; if(!strcmp(nco_cnk_plc_sng,"plc_g2d")) return nco_cnk_plc_g2d; if(!strcmp(nco_cnk_plc_sng,"g3d")) return nco_cnk_plc_g3d; if(!strcmp(nco_cnk_plc_sng,"cnk_g3d")) return nco_cnk_plc_g3d; if(!strcmp(nco_cnk_plc_sng,"plc_g3d")) return nco_cnk_plc_g3d; if(!strcmp(nco_cnk_plc_sng,"xpl")) return nco_cnk_plc_xpl; if(!strcmp(nco_cnk_plc_sng,"cnk_xpl")) return nco_cnk_plc_xpl; if(!strcmp(nco_cnk_plc_sng,"plc_xpl")) return nco_cnk_plc_xpl; if(!strcmp(nco_cnk_plc_sng,"xst")) return nco_cnk_plc_xst; if(!strcmp(nco_cnk_plc_sng,"cnk_xst")) return nco_cnk_plc_xst; if(!strcmp(nco_cnk_plc_sng,"plc_xst")) return nco_cnk_plc_xst; if(!strcmp(nco_cnk_plc_sng,"uck")) return nco_cnk_plc_uck; if(!strcmp(nco_cnk_plc_sng,"cnk_uck")) return nco_cnk_plc_uck; if(!strcmp(nco_cnk_plc_sng,"plc_uck")) return nco_cnk_plc_uck; if(!strcmp(nco_cnk_plc_sng,"unchunk")) return nco_cnk_plc_uck; (void)fprintf(stderr,"%s: ERROR %s reports unknown user-specified chunking policy %s\n",nco_prg_nm_get(),fnc_nm,nco_cnk_plc_sng); nco_exit(EXIT_FAILURE); return nco_cnk_plc_nil; /* Statement should not be reached */ } /* end nco_cnk_plc_get() */ nco_bool /* O [flg] Variable is chunked on disk */ nco_cnk_dsk_inq /* [fnc] Check whether variable is chunked on disk */ (const int nc_id, /* I [idx] netCDF file ID */ const int var_id) /* I [id] Variable ID */ { /* Purpose: Check whether variable is chunked on disk */ /* nces -O -D 3 -v cnk ~/nco/data/in.nc ~/nco/data/foo.nc */ int srg_typ; /* [enm] Storage type */ (void)nco_inq_var_chunking(nc_id,var_id,&srg_typ,(size_t *)NULL); if(srg_typ == NC_CONTIGUOUS) return False; else return True; } /* end nco_cnk_dsk_inq() */ #if 0 /* NB: Following routines are placeholders, currently not used */ size_t * /* O [nbr] Chunksize array for variable */ nco_cnk_sz_get /* [fnc] Determine chunksize array */ (const int nc_id, /* I [id] netCDF file ID */ const char * const var_nm, /* I [sng] Variable name */ const int cnk_map, /* I [enm] Chunking map */ const int cnk_plc, /* I [enm] Chunking policy */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ CST_X_PTR_CST_PTR_CST_Y(cnk_dmn_sct,cnk_dmn), /* I [sct] Chunking information */ const int cnk_nbr) /* I [nbr] Number of dimensions with user-specified chunking */ { /* Purpose: Use chunking map and policy to determine chunksize list */ int dmn_nbr; /* [nbr] Number of dimensions in variable */ int dmn_idx; int idx; int rec_dmn_id; size_t *cnk_sz; /* [nbr] Chunksize list */ /* Get record dimension ID */ (void)nco_inq(nc_id,(int *)NULL,(int *)NULL,(int *)NULL,&rec_dmn_id); /* Get type and number of dimensions and attributes for variable */ cnk_sz=(size_t *)nco_malloc(dmn_nbr*sizeof(size_t)); return cnk_sz; } /* end nco_cnk_sz_get() */ nco_bool /* O [flg] NCO will attempt to chunk variable */ nco_is_chunkable /* [fnc] Will NCO attempt to chunk variable? */ (const nc_type nc_typ_in) /* I [enm] Type of input variable */ { /* Purpose: Determine whether NCO should attempt to chunk a given type Chunking certain variable types is not recommended, e.g., chunking NC_CHAR and NC_BYTE makes no sense, because precision would needlessly be lost. Routine should be consistent with nco_cnk_plc_typ_get() NB: Routine is deprecated in favor of more flexible nco_cnk_plc_typ_get() */ const char fnc_nm[]="nco_is_chunkable()"; /* [sng] Function name */ (void)fprintf(stdout,"%s: ERROR deprecated routine %s should not be called\n",nco_prg_nm_get(),fnc_nm); nco_exit(EXIT_FAILURE); switch(nc_typ_in){ case NC_FLOAT: case NC_DOUBLE: case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: return True; break; case NC_SHORT: case NC_USHORT: case NC_CHAR: case NC_BYTE: case NC_UBYTE: case NC_STRING: return False; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return False; } /* end nco_is_chunkable() */ #endif /* endif 0 */ void nco_cnk_sz_set /* [fnc] Set chunksize parameters */ (const int nc_id, /* I [id] netCDF file ID */ CST_X_PTR_CST_PTR_CST_Y(lmt_msa_sct,lmt_all_lst), /* I [sct] Hyperslab limits */ const int lmt_all_lst_nbr, /* I [nbr] Number of hyperslab limits */ int * const cnk_map_ptr, /* I/O [enm] Chunking map */ int * const cnk_plc_ptr, /* I/O [enm] Chunking policy */ const size_t cnk_sz_scl, /* I [nbr] Chunk size scalar */ CST_X_PTR_CST_PTR_CST_Y(cnk_dmn_sct,cnk_dmn), /* I [sct] Chunking information */ const int cnk_nbr) /* I [nbr] Number of dimensions with user-specified chunking */ { /* Purpose: Use chunking map and policy to determine chunksize list */ const char fnc_nm[]="nco_cnk_sz_set()"; /* [sng] Function name */ char dmn_nm[NC_MAX_NAME+1L]; char var_nm[NC_MAX_NAME+1L]; int *dmn_id; int cnk_idx; int dmn_idx; int cnk_map; /* [enm] Chunking map */ int cnk_plc; /* [enm] Chunking policy */ int chk_typ; /* [enm] Checksum type */ int deflate; /* [enm] Deflate filter is on */ int dmn_nbr; /* [nbr] Number of dimensions in variable */ int fl_fmt; /* [enm] Input file format */ int lmt_idx; int lmt_idx_rec=int_CEWI; int rcd_dmn_id; int srg_typ; /* [enm] Storage type */ int var_idx; int var_nbr; long dmn_sz; nco_bool flg_cnk=False; /* [flg] Chunking requested */ nco_bool is_rec_var; /* [flg] Record variable */ nco_bool is_chk_var; /* [flg] Check-summed variable */ nco_bool is_cmp_var; /* [flg] Compressed variable */ nco_bool is_chunked; /* [flg] Chunked variable */ nco_bool must_be_chunked; /* [flg] Variable must be chunked */ nc_type var_typ_dsk; size_t *cnk_sz; /* [nbr] Chunksize list */ size_t cnk_sz_dfl; /* [nbr] Chunksize default */ /* Did user explicitly request chunking? */ if(cnk_nbr > 0 || cnk_sz_scl > 0UL || *cnk_map_ptr != nco_cnk_map_nil || *cnk_plc_ptr != nco_cnk_plc_nil) flg_cnk=True; if(!flg_cnk) return; /* Set actual chunk policy and map to defaults as necessary This rather arcane procedure saves a few lines of code in calling program (because defaults not set there) while maintaining correctness of arguments */ if(*cnk_map_ptr == nco_cnk_map_nil) *cnk_map_ptr=nco_cnk_map_get((char *)NULL); if(*cnk_plc_ptr == nco_cnk_plc_nil) *cnk_plc_ptr=nco_cnk_plc_get((char *)NULL); cnk_map=*cnk_map_ptr; cnk_plc=*cnk_plc_ptr; /* Bail on unsupported options */ if(cnk_plc == nco_cnk_plc_xpl){ (void)fprintf(stderr,"%s: ERROR cnk_plc = %s not yet supported\n",nco_prg_nm_get(),nco_cnk_plc_sng_get(cnk_plc)); nco_exit(EXIT_FAILURE); } /* endif */ /* Does output file support chunking? */ (void)nco_inq_format(nc_id,&fl_fmt); if(fl_fmt != NC_FORMAT_NETCDF4 && fl_fmt != NC_FORMAT_NETCDF4_CLASSIC){ (void)fprintf(stderr,"%s: WARNING Output file format is %s so chunking request will be ignored\n",nco_prg_nm_get(),nco_fmt_sng(fl_fmt)); return; } /* endif dbg */ /* Vet input */ if(cnk_map == nco_cnk_map_scl && cnk_sz_scl <= 0){ (void)fprintf(stderr,"%s: ERROR cnk_sz_scl = %lu must be greater than 0\n",nco_prg_nm_get(),(unsigned long)cnk_sz_scl); nco_exit(EXIT_FAILURE); } /* endif cnk_sz_scl */ if(nco_dbg_lvl_get() >= nco_dbg_fl) (void)fprintf(stderr,"%s: INFO Requested chunking or unchunking\n",nco_prg_nm_get()); if(nco_dbg_lvl_get() >= nco_dbg_scl){ (void)fprintf(stderr,"cnk_plc: %s\n",nco_cnk_plc_sng_get(cnk_plc)); (void)fprintf(stderr,"cnk_map: %s\n",nco_cnk_map_sng_get(cnk_map)); (void)fprintf(stderr,"cnk_sz_scl: %lu\n",(unsigned long)cnk_sz_scl); if(cnk_nbr > 0){ (void)fprintf(stderr,"idx dmn_nm\tcnk_sz:\n"); for(cnk_idx=0;cnk_idxnm,(unsigned long)cnk_dmn[cnk_idx]->sz); } /* cnk_nbr == 0 */ } /* endif dbg */ /* Get record dimension ID */ (void)nco_inq(nc_id,(int *)NULL,&var_nbr,(int *)NULL,&rcd_dmn_id); /* Find record dimension, if any, in limit structure list first This information may be needed below */ if(rcd_dmn_id != NCO_REC_DMN_UNDEFINED){ (void)nco_inq_dimname(nc_id,rcd_dmn_id,dmn_nm); for(lmt_idx=0;lmt_idxdmn_nm)){ lmt_idx_rec=lmt_idx; break; } /* end if */ } /* end loop over limit */ } /* NCO_REC_DMN_UNDEFINED */ /* NB: Assumes variable IDs range from [0..var_nbr-1] */ for(var_idx=0;var_idx= nco_dbg_var) (void)fprintf(stderr,"%s: INFO %s %s must be chunked (record, compressed, or check-summed variable)\n",nco_prg_nm_get(),fnc_nm,var_nm); }else{ /* Turn-off chunking for this variable */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stderr,"%s: INFO %s unchunking %s\n",nco_prg_nm_get(),fnc_nm,var_nm); (void)nco_def_var_chunking(nc_id,var_idx,srg_typ,cnk_sz); } /* !must_be_chunked */ }else{ /* !chunked */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stderr,"%s: INFO %s not unchunking %s because it is not chunked\n",nco_prg_nm_get(),fnc_nm,var_nm); } /* !chunked */ /* Free space holding dimension IDs before skipping to next variable */ dmn_id=(int *)nco_free(dmn_id); /* Skip to next variable in loop */ continue; } /* end if */ /* Variable will definitely be chunked */ srg_typ=NC_CHUNKED; /* [enm] Storage type */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stderr,"%s: INFO %s %schunking %s\n",nco_prg_nm_get(),fnc_nm,(is_chunked ? "re-" : "" ),var_nm); /* Allocate space to hold chunksizes */ cnk_sz=(size_t *)nco_malloc(dmn_nbr*sizeof(size_t)); /* Default "equal" chunksize for each dimension */ cnk_sz_dfl=cnk_sz_scl; if(cnk_map == nco_cnk_map_prd){ double cnk_sz_prd_dbl; /* [nbr] Chunksize product, double precision */ double cnk_sz_eql_dbl; /* [nbr] Chunksize equal, double precision */ double cnk_sz_dfl_dbl; /* [nbr] Chunksize default, double precision */ cnk_sz_prd_dbl=cnk_sz_scl; cnk_sz_eql_dbl=pow(cnk_sz_prd_dbl,1.0/dmn_nbr); cnk_sz_dfl_dbl=ceil(cnk_sz_eql_dbl); cnk_sz_dfl=(size_t)cnk_sz_dfl_dbl; } /* endif map_prd */ for(dmn_idx=0;dmn_idxBASIC_DMN){ /* When not hyperslabbed, use input record dimension size ... */ cnk_sz[dmn_idx]=lmt_all_lst[lmt_idx_rec]->dmn_sz_org; }else{ /* !BASIC_DMN */ /* ... and when hyperslabbed, use user-specified count */ cnk_sz[dmn_idx]=lmt_all_lst[lmt_idx_rec]->dmn_cnt; } /* !BASIC_DMN */ }else{ /* !record dimension */ /* Set non-record dimensions to default, possibly over-ride later */ cnk_sz[dmn_idx]=dmn_sz; if(dmn_sz == 0L){ (void)fprintf(stderr,"%s: ERROR %s reports variable %s has dim_sz == 0L for non-record dimension %s. This should not occur and it will cause chunking to fail...\n",nco_prg_nm_get(),fnc_nm,var_nm,dmn_nm); } /* endif err */ } /* !record dimension */ /* Propagate scalar chunksize, if specified */ if(cnk_sz_dfl > 0UL){ if(dmn_id[dmn_idx] == rcd_dmn_id){ if(lmt_all_lst[lmt_idx_rec]->BASIC_DMN){ /* When not hyperslabbed, use input record dimension size ... */ cnk_sz[dmn_idx]=(cnk_sz_dfl <= (size_t)lmt_all_lst[lmt_idx_rec]->dmn_sz_org) ? cnk_sz_dfl : (size_t)lmt_all_lst[lmt_idx_rec]->dmn_sz_org; }else{ /* !BASIC_DMN */ /* ... and when hyperslabbed, use user-specified count */ cnk_sz[dmn_idx]=(cnk_sz_dfl <= (size_t)lmt_all_lst[lmt_idx_rec]->dmn_cnt) ? cnk_sz_dfl : (size_t)lmt_all_lst[lmt_idx_rec]->dmn_cnt; } /* !BASIC_DMN */ }else{ /* !rcd_dmn_id */ /* Non-record sizes default to cnk_sz_dfl or to dimension size */ cnk_sz[dmn_idx]=(cnk_sz_dfl <= (size_t)dmn_sz) ? cnk_sz_dfl : (size_t)dmn_sz; } /* !rcd_dmn_id */ } /* !cnk_sz_dfl */ cnk_xpl_override: /* end goto */ /* Explicit chunk specifications override all else */ for(cnk_idx=0;cnk_idxnm,dmn_nm)){ cnk_sz[dmn_idx]=cnk_dmn[cnk_idx]->sz; if(dmn_id[dmn_idx] == rcd_dmn_id){ if(lmt_all_lst[lmt_idx_rec]->BASIC_DMN){ if(cnk_sz[dmn_idx] > (size_t)lmt_all_lst[lmt_idx_rec]->dmn_sz_org){ (void)fprintf(stderr,"%s: WARNING %s allowing user-specified record dimension chunksize = %lu for %s to exceed record dimension size in input file = %lu. May fail if output file is not concatenated from multiple inputs.\n",nco_prg_nm_get(),fnc_nm,(unsigned long)cnk_dmn[cnk_idx]->sz,dmn_nm,lmt_all_lst[lmt_idx_rec]->dmn_sz_org); } /* endif too big */ }else{ /* !BASIC_DMN */ if(cnk_sz[dmn_idx] > (size_t)lmt_all_lst[lmt_idx_rec]->dmn_cnt){ (void)fprintf(stderr,"%s: WARNING %s allowing user-specified record dimension chunksize = %lu for %s to exceed user-specified record dimension hyperslab size in input file = %lu. May fail if output file is not concatenated from multiple inputs.\n",nco_prg_nm_get(),fnc_nm,(unsigned long)cnk_dmn[cnk_idx]->sz,dmn_nm,lmt_all_lst[lmt_idx_rec]->dmn_cnt); } /* endif too big */ } /* !BASIC_DMN */ }else{ /* !rcd_dmn_id */ if(cnk_sz[dmn_idx] > (size_t)dmn_sz){ /* dmn_sz of record dimension may (will) be zero in output file Non-record dimensions, though, must have cnk_sz <= dmn_sz */ (void)fprintf(stderr,"%s: WARNING %s trimming user-specified chunksize = %lu to %s size = %lu\n",nco_prg_nm_get(),fnc_nm,(unsigned long)cnk_dmn[cnk_idx]->sz,dmn_nm,dmn_sz); /* Trim else out-of-bounds sizes will fail in HDF library in nc_enddef() */ cnk_sz[dmn_idx]=(size_t)dmn_sz; } /* endif */ } /* !rcd_dmn_id */ break; } /* cnk_nm != dmn_nm */ } /* end loop over cnk */ } /* end loop over dmn */ if(nco_dbg_lvl_get() >= nco_dbg_scl){ (void)fprintf(stderr,"idx nm\tdmn_sz\tcnk_sz for %s:\n",var_nm); for(dmn_idx=0;dmn_idxflg_usr_rqs; cnk_nbr=cnk->cnk_nbr; cnk_map=cnk->cnk_map; cnk_plc=cnk->cnk_plc; cnk_sz_scl=cnk->cnk_sz_scl; cnk_sz_byt=cnk->cnk_sz_byt; cnk_dmn=cnk->cnk_dmn; /* Only use NCO chunking when user explicitly sets a chunking option */ if(!flg_usr_rqs) return; /* Bail on unsupported options */ if(cnk_map == nco_cnk_map_nil){ (void)fprintf(stderr,"%s: ERROR cnk_map = %s not yet supported\n",nco_prg_nm_get(),nco_cnk_map_sng_get(cnk_map)); nco_exit(EXIT_FAILURE); } /* endif */ /* Does output file support chunking? */ (void)nco_inq_format(grp_id_out,&fl_fmt); if(fl_fmt != NC_FORMAT_NETCDF4 && fl_fmt != NC_FORMAT_NETCDF4_CLASSIC){ (void)fprintf(stderr,"%s: WARNING Output file format is %s so chunking request will be ignored\n",nco_prg_nm_get(),nco_fmt_sng(fl_fmt)); return; } /* endif dbg */ /* Vet input */ if(cnk_map == nco_cnk_map_scl && cnk_sz_scl <= 0UL){ (void)fprintf(stderr,"%s: ERROR cnk_sz_scl = %lu must be greater than 0\n",nco_prg_nm_get(),(unsigned long)cnk_sz_scl); nco_exit(EXIT_FAILURE); } /* endif cnk_sz_scl */ if(FIRST_CALL && nco_dbg_lvl_get() >= nco_dbg_fl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: INFO User requested chunking or unchunking\n",nco_prg_nm_get()); if(nco_dbg_lvl_get() >= nco_dbg_scl && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"cnk_plc, cnk_map: %s, %s\n",nco_cnk_plc_sng_get(cnk_plc),nco_cnk_map_sng_get(cnk_map)); (void)fprintf(stdout,"cnk_sz_scl, cnk_sz_byt: %lu, %lu\n",(unsigned long)cnk_sz_scl,(unsigned long)cnk_sz_byt); if(cnk_nbr > 0){ (void)fprintf(stdout,"idx dmn_nm\tcnk_sz:\n"); for(cnk_idx=0;cnk_idxnm,(unsigned long)cnk_dmn[cnk_idx]->sz); } /* cnk_nbr == 0 */ } /* endif dbg */ } /* endif dbg */ FIRST_CALL=False; /* Initialize storage type for this variable */ srg_typ=NC_CONTIGUOUS; /* [enm] Storage type */ is_rec_var=False; /* [flg] Record variable */ is_chk_var=False; /* [flg] Check-summed variable */ is_cmp_var=False; /* [flg] Compressed variable */ is_chunked=False; /* [flg] Chunked variable */ is_xpl_cnk=False; /* [flg] Explicitly chunked variable */ /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id_out,var_nm,&var_id_out); (void)nco_inq_varid(grp_id_in,var_nm,&var_id_in); /* Get type and number of dimensions for variable */ (void)nco_inq_var(grp_id_out,var_id_out,(char *)NULL,&var_typ_dsk,&dmn_nbr,var_dimid,(int *)NULL); typ_sz=nco_typ_lng(var_typ_dsk); if(dmn_nbr == 0){ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s skipping scalar...\n",nco_prg_nm_get(),fnc_nm); return; } /* dmn_nbr */ /* Does variable contain a record dimension? */ for(dmn_idx=0;dmn_idxnm_fll){ if(!strcmp(cnk_dmn[cnk_idx]->nm_fll,dmn_cmn[dmn_idx].nm_fll)) break; }else{ if(!strcmp(cnk_dmn[cnk_idx]->nm,dmn_cmn[dmn_idx].nm)) break; } /* end else */ } /* end loop over cnk_idx */ if(dmn_idx != dmn_nbr) is_xpl_cnk=True; } /* end plc_xpl */ if(must_be_chunked){ /* Some variables simply must be chunked */ if(nco_dbg_lvl_get() >= nco_dbg_var && nco_dbg_lvl_get() != nco_dbg_dev) (void)fprintf(stdout,"%s: INFO %s %s must be chunked (record, compressed, or check-summed variable)\n",nco_prg_nm_get(),fnc_nm,var_nm); }else{ /* Explicitly turn-off chunking for arrays that are... */ if((cnk_plc == nco_cnk_plc_xpl && !is_xpl_cnk) || /* ...not explicitly chunked... */ (cnk_plc == nco_cnk_plc_xst && !is_chunked) || /* ...not already chunked... */ (cnk_plc == nco_cnk_plc_g2d && dmn_nbr < 2) || /* ...much too small... */ (cnk_plc == nco_cnk_plc_g3d && dmn_nbr < 3) || /* ...too small... */ (cnk_plc == nco_cnk_plc_uck) || /* ...intentionally unchunked... */ False){ /* If variable is chunked */ if(is_chunked){ /* Turn-off chunking for this variable */ if(nco_dbg_lvl_get() >= nco_dbg_var && nco_dbg_lvl_get() != nco_dbg_dev) (void)fprintf(stdout,"%s: INFO %s unchunking %s\n",nco_prg_nm_get(),fnc_nm,var_nm); if(shuffle) (void)fprintf(stdout,"%s: WARNING %s reports variable %s has shuffle flag set before unchunking. Expect the worst.",nco_prg_nm_get(),fnc_nm,var_nm); (void)nco_def_var_chunking(grp_id_out,var_id_out,srg_typ,cnk_sz); }else{ /* !chunked */ if(nco_dbg_lvl_get() >= nco_dbg_var && nco_dbg_lvl_get() != nco_dbg_dev) (void)fprintf(stdout,"%s: INFO %s not unchunking %s because it is not chunked\n",nco_prg_nm_get(),fnc_nm,var_nm); } /* !chunked */ /* Return control to calling routine NB: Here is where loop in original nco_cnk_sz_set() continues to next variable */ return; } /* !turn-off chunking */ } /* !must_be_chunked */ /* Since routine has not returned yet, this variable will definitely be chunked */ srg_typ=NC_CHUNKED; /* [enm] Storage type */ if(nco_dbg_lvl_get() >= nco_dbg_var && nco_dbg_lvl_get() != nco_dbg_dev) (void)fprintf(stdout,"%s: INFO %s %schunking %s\n",nco_prg_nm_get(),fnc_nm,(is_chunked ? "re-" : "" ),var_nm); /* Allocate space to hold chunksizes */ cnk_sz=(size_t *)nco_malloc(dmn_nbr*sizeof(size_t)); if(cnk_map == nco_cnk_map_xst){ /* Set chunksizes to existing sizes for this variable */ if(is_chunked){ (void)nco_inq_var_chunking(grp_id_in,var_id_in,(int *)NULL,cnk_sz); /* Allow existing chunksizes to be over-ridden by explicitly specified chunksizes */ goto cnk_xpl_override; } /* !is_chunked */ } /* !nco_cnk_map_xst */ /* Default "equal" chunksize for each dimension */ cnk_sz_dfl=cnk_sz_scl; if(cnk_map == nco_cnk_map_prd){ double cnk_sz_prd_dbl; /* [nbr] Chunksize product, double precision */ double cnk_sz_eql_dbl; /* [nbr] Chunksize equal, double precision */ double cnk_sz_dfl_dbl; /* [nbr] Chunksize default, double precision */ cnk_sz_prd_dbl=cnk_sz_scl; cnk_sz_eql_dbl=pow(cnk_sz_prd_dbl,1.0/dmn_nbr); cnk_sz_dfl_dbl=ceil(cnk_sz_eql_dbl); cnk_sz_dfl=(size_t)cnk_sz_dfl_dbl; } /* endif map_prd */ /* Set "reasonable" defaults */ for(dmn_idx=0;dmn_idx=0;dmn_idx--) /* NB: reverse loop */ if(dmn_cmn[dmn_idx].is_rec_dmn) break; dmn_idx_1st_rec=dmn_idx; /* Find product of all righter chunksizes */ for(dmn_idx=dmn_nbr-1;dmn_idx>=dmn_idx_1st_rec+1;dmn_idx--) cnk_sz_prd_rgt*=cnk_sz[dmn_idx]; /* Derive product of all lefter chunksizes */ cnk_sz_prd_lft=cnk_val_nbr/cnk_sz_prd_rgt; /* How many lefter chunksizes are there? */ dmn_nbr_lft=dmn_idx_1st_rec+1; cnk_sz_lft_dbl=pow(cnk_sz_prd_lft,1.0/dmn_nbr_lft); cnk_sz_lft=(size_t)cnk_sz_lft_dbl; /* Assign remaining chunkspace equally amongst lefter dimensions */ for(dmn_idx=0;dmn_idx<=dmn_idx_1st_rec;dmn_idx++) cnk_sz[dmn_idx]=cnk_sz_lft; /* Allow existing chunksizes to be over-ridden by explicitly specified chunksizes */ goto cnk_xpl_override; } /* !nco_cnk_map_lfp */ if(cnk_map == nco_cnk_map_rew){ /* Described by Russ Rew at http://www.unidata.ucar.edu/staff/russ/public/chunk_shape_3D.py ncks -O -C -4 -D 6 -v four_dmn_rec_var --cnk_map=rew -p ~/nco/data in.nc ~/foo.nc */ double cnk_val_nbr; double dmn_sz_prd=1.0; /* [nbr] Number of elements in output variable */ double cnk_nbr_xct; /* [nbr] Exact number of ideal chunks needed to store variable */ double cnk_nbr_2D_axs; /* [nbr] Exact number of ideal chunks along each 2D axis */ double fct_ncr=1.0; /* [frc] Factor by which to increase chunk size */ size_t *var_shp; /* [nbr] Shape of variable */ /* Allocate space to hold variable shape */ var_shp=(size_t *)nco_malloc(dmn_nbr*sizeof(size_t)); cnk_val_nbr=cnk_sz_byt/(double)typ_sz; for(dmn_idx=0;dmn_idx<=dmn_nbr-1;dmn_idx++){ /* Store shape for future use */ /* 20140131: fxm this gets wrong value for input record dimension size unless hyperslabbed. Why? */ if(dmn_cmn[dmn_idx].is_rec_dmn) var_shp[dmn_idx]= (dmn_cmn[dmn_idx].BASIC_DMN) ? dmn_cmn[dmn_idx].dmn_cnt : dmn_cmn[dmn_idx].sz; else var_shp[dmn_idx]= (dmn_cmn[dmn_idx].BASIC_DMN) ? dmn_cmn[dmn_idx].sz : dmn_cmn[dmn_idx].dmn_cnt; assert(var_shp[dmn_idx] > 0L); /* Determine hyperslab size */ dmn_sz_prd*=var_shp[dmn_idx]; } /* end loop over dmn_idx */ cnk_nbr_xct=dmn_sz_prd/cnk_val_nbr; cnk_nbr_2D_axs=pow(cnk_nbr_xct,0.25); if(var_shp[0]/(cnk_nbr_2D_axs*cnk_nbr_2D_axs) < 1.0){ cnk_sz[0]=1L; cnk_nbr_2D_axs=1.0/sqrt((double)var_shp[0]); }else{ cnk_sz[0]=var_shp[0]/(cnk_nbr_2D_axs*cnk_nbr_2D_axs); } /* endif */ for(dmn_idx=1;dmn_idx<=dmn_nbr-1;dmn_idx++) /* NB: Start at 1 */ if(var_shp[dmn_idx]/cnk_nbr_2D_axs < 1.0) fct_ncr*=cnk_nbr_2D_axs/var_shp[dmn_idx]; for(dmn_idx=1;dmn_idx<=dmn_nbr-1;dmn_idx++) /* NB: Start at 1 */ if(var_shp[dmn_idx]/cnk_nbr_2D_axs < 1.0) cnk_sz[dmn_idx]=1L; else cnk_sz[dmn_idx]=fct_ncr*var_shp[dmn_idx]/cnk_nbr_2D_axs; if(nco_dbg_lvl_get() >= nco_dbg_var){ (void)fprintf(stdout,"map rew debugging:\n"); (void)fprintf(stdout,"cnk_nbr_xct = %g, cnk_val_nbr = %g, dmn_sz_prd = %g\n",cnk_nbr_xct,cnk_val_nbr,dmn_sz_prd); (void)fprintf(stdout,"idx dmn_nm\tdmn_sz\tvar_shp\tcnk_sz:\n"); for(dmn_idx=0;dmn_idx 0UL){ for(dmn_idx=0;dmn_idxnm_fll){ if(!strcmp(cnk_dmn[cnk_idx]->nm_fll,dmn_cmn[dmn_idx].nm_fll)) flg_mch[dmn_idx]=True; }else{ if(!strcmp(cnk_dmn[cnk_idx]->nm,dmn_cmn[dmn_idx].nm)) flg_mch[dmn_idx]=True; } /* end else */ /* Name match found */ if(flg_mch[dmn_idx]){ cnk_sz[dmn_idx]=cnk_dmn[cnk_idx]->sz; /* Is this a record dimension? */ if(dmn_cmn[dmn_idx].is_rec_dmn){ /* dmn_sz of record dimension can/will be zero in output file Allow (though warn) when cnk_sz > dmn_sz in such cases */ if(dmn_cmn[dmn_idx].BASIC_DMN){ if(cnk_sz[dmn_idx] > (size_t)dmn_cmn[dmn_idx].sz){ (void)fprintf(stderr,"%s: WARNING %s allowing user-specified record dimension %s chunksize %lu which exceeds current record dimension size in output file = %lu. May fail if output file is not concatenated from multiple inputs.\n",nco_prg_nm_get(),fnc_nm,dmn_cmn[dmn_idx].nm,(unsigned long)cnk_dmn[cnk_idx]->sz,(unsigned long)dmn_cmn[dmn_idx].sz); } /* endif too big */ }else{ /* !BASIC_DMN */ if(cnk_sz[dmn_idx] > (size_t)dmn_cmn[dmn_idx].dmn_cnt){ (void)fprintf(stderr,"%s: WARNING %s allowing user-specified record dimension %s chunksize = %lu which exceeds user-specified record dimension input hyperslab size = %lu. May fail if output file is not concatenated from multiple inputs.\n",nco_prg_nm_get(),fnc_nm,dmn_cmn[dmn_idx].nm,(unsigned long)cnk_dmn[cnk_idx]->sz,(unsigned long)dmn_cmn[dmn_idx].dmn_cnt); } /* endif too big */ } /* !BASIC_DMN */ }else{ /* !rcd_dmn_id */ if(cnk_sz[dmn_idx] > (size_t)dmn_cmn[dmn_idx].sz){ /* Unlike record dimensions, non-record dimensions must have cnk_sz <= dmn_sz */ (void)fprintf(stderr,"%s: WARNING %s trimming user-specified fixed dimension %s chunksize from %lu to %lu\n",nco_prg_nm_get(),fnc_nm,dmn_cmn[dmn_idx].nm,(unsigned long)cnk_dmn[cnk_idx]->sz,(unsigned long)dmn_cmn[dmn_idx].sz); /* Trim else out-of-bounds sizes will fail in HDF library in nc_enddef() */ cnk_sz[dmn_idx]=(size_t)dmn_cmn[dmn_idx].sz; } /* endif */ } /* !rcd_dmn_id */ break; } /* cnk_nm != dmn_nm */ } /* end loop over dimensions */ } /* end loop over cnk */ /* Status: Previous block implemented per-dimension checks on user-requested chunksizes only Block below implements similar final safety check for ALL dimensions and ALL chunking maps Check trims fixed (not record) dimension chunksize to never be larger than dimension size */ for(dmn_idx=0;dmn_idx (size_t)dmn_cmn[dmn_idx].sz){ if(!dmn_cmn[dmn_idx].is_rec_dmn){ /* Unlike record dimensions, non-record dimensions must have cnk_sz <= dmn_sz */ (void)fprintf(stderr,"%s: WARNING %s final check trimming %s chunksize from %lu to %lu\n",nco_prg_nm_get(),fnc_nm,dmn_cmn[dmn_idx].nm,(unsigned long)cnk_sz[dmn_idx],(unsigned long)dmn_cmn[dmn_idx].sz); /* Trim else out-of-bounds sizes will fail in HDF library in nc_enddef() */ cnk_sz[dmn_idx]=(size_t)dmn_cmn[dmn_idx].sz; } /* rcd_dmn_id */ } /* end if */ } /* end loop over dmn */ if(nco_dbg_lvl_get() >= nco_dbg_var && nco_dbg_lvl_get() != nco_dbg_dev){ /* Dimensions and chunksizes used by variable in output file */ (void)fprintf(stdout,"idx dmn_nm\tdmn_sz\tcnk_sz:\n"); for(dmn_idx=0;dmn_idx 12 || day < 0){ (void)fprintf(stdout,"%s: ERROR nco_nd2endm() reports mth = %d, day = %d\n",nco_prg_nm_get(),mth,day); nco_exit(EXIT_FAILURE); } /* end if */ nbr_day_2_mth_end=mdays[mth-1]-day; return nbr_day_2_mth_end; } /* nco_nd2endm */ nco_int /* O [YYMMDD] Date a specified number of days from input date */ nco_newdate /* [fnc] Compute date a specified number of days from input date */ (const nco_int date, /* I [YYMMDD] Date */ const nco_int day_srt) /* I [day] Days ahead of input date */ { /* Purpose: Find date a specified number of days (possibly negative) from given date Original fortran: Brian Eaton cal_util.F:newdate() C version: Charlie Zender */ /* Local */ const long mth_day_nbr[]= /* Number of days in each month */ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; long day_nbr_2_eom; /* Days to end of month */ long day_crr; /* Day of date */ long day_ncr; /* Running count of days to increment date by */ long mth_crr; /* Month of date */ long mth_idx; /* Index */ long mth_srt; /* Save the initial value of month */ long mth_tmp; /* Current month as we increment date */ long yr_crr; /* Year of date */ nco_int date_srt; /* Initial value of date (may change sign) */ nco_int newdate_YYMMDD; /* New date in YYMMDD format */ if(day_srt == 0L) return date; date_srt=date; yr_crr=date_srt/10000L; if(date_srt < 0L) date_srt=-date_srt; mth_crr=(date_srt%10000L)/100L; mth_srt=mth_crr; day_crr=date_srt%100L; if(day_srt > 0){ day_ncr=day_srt; yr_crr+=day_ncr/365L; day_ncr=day_ncr%365L; for(mth_idx=mth_srt;mth_idx<=mth_srt+12L;mth_idx++){ mth_tmp=mth_idx; if(mth_idx > 12L) mth_tmp=mth_idx-12L; day_nbr_2_eom=(long int)nco_nd2endm(mth_tmp,day_crr); if(day_ncr > day_nbr_2_eom){ mth_crr++; if(mth_crr > 12L){ mth_crr=1L; yr_crr++; } /* end if */ day_crr=1L; day_ncr-=day_nbr_2_eom+1L; if(day_ncr == 0L) break; }else{ day_crr=day_crr+day_ncr; break; } /* end if */ } /* end loop over mth */ /* Previous two breaks continue execution here */ }else if(day_srt < 0L){ day_ncr=-day_srt; yr_crr=yr_crr-day_ncr/365L; day_ncr=day_ncr%365L; mth_srt=mth_crr; for(mth_idx=mth_srt+12L;mth_idx>=mth_srt;mth_idx--){ if(day_ncr >= day_crr){ mth_crr--; if(mth_crr < 1L){ mth_crr=12L; yr_crr--; } /* end if */ day_ncr-=day_crr; day_crr=mth_day_nbr[mth_crr-1L]; if(day_ncr == 0L) break; }else{ day_crr-=day_ncr; break; } /* end if */ } /* end loop over mth */ /* Previous two breaks continue execution here */ } /* end if */ if(yr_crr >= 0){ newdate_YYMMDD=yr_crr*10000L+mth_crr*100L+day_crr; }else{ newdate_YYMMDD=-yr_crr*10000L+mth_crr*100L+day_crr; newdate_YYMMDD=-newdate_YYMMDD; } /* end if */ return newdate_YYMMDD; } /* end nco_newdate() */ #ifdef ENABLE_UDUNITS # ifdef HAVE_UDUNITS2_H /* UDUnits2 routines */ int /* [rcd] Return code */ nco_cln_clc_dff /* [fnc] UDUnits2 Compute difference between two coordinate units */ (const char *fl_unt_sng, /* I [ptr] units attribute string from disk */ const char *fl_bs_sng, /* I [ptr] units attribute string from disk */ double crr_val, double *og_val) /* O [] Difference between two units strings */ { const char fnc_nm[]="nco_cln_clc_dff()"; /* [sng] Function name */ cv_converter *ut_cnv; /* UDUnits converter */ int ut_rcd; /* [enm] UDUnits2 status */ ut_system *ut_sys; ut_unit *ut_sct_in; /* UDUnits structure, input units */ ut_unit *ut_sct_out; /* UDUnits structure, output units */ /* Quick return if units identical */ if(!strcmp(fl_unt_sng,fl_bs_sng)){ *og_val=crr_val; return NCO_NOERR; } /* end if */ /* When empty, ut_read_xml() uses environment variable UDUNITS2_XML_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ if(nco_dbg_lvl_get() >= nco_dbg_vrb) ut_set_error_message_handler(ut_write_to_stderr); else ut_set_error_message_handler(ut_ignore); ut_sys=ut_read_xml(NULL); if(ut_sys == NULL){ (void)fprintf(stdout,"%s: %s() failed to initialize UDUnits2 library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; /* Failure */ } /* end if err */ /* Units string to convert from */ ut_sct_in=ut_parse(ut_sys,fl_unt_sng,UT_ASCII); if(!ut_sct_in){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",fl_unt_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",fl_unt_sng); return NCO_ERR; /* Failure */ } /* endif coordinate on disk has no units attribute */ /* Units string to convert to */ ut_sct_out=ut_parse(ut_sys,fl_bs_sng,UT_ASCII); if(!ut_sct_out){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: Empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",fl_bs_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",fl_bs_sng); return NCO_ERR; /* Failure */ } /* endif */ /* Create converter */ ut_cnv=ut_get_converter(ut_sct_in,ut_sct_out); /* UDUnits converter */ if(!ut_cnv){ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"WARNING: One of units, %s or %s, is NULL\n",fl_bs_sng,fl_unt_sng); if(ut_rcd == UT_NOT_SAME_SYSTEM) (void)fprintf(stderr,"WARNING: Units %s and %s belong to different unit systems\n",fl_bs_sng,fl_unt_sng); if(ut_rcd == UT_MEANINGLESS) (void)fprintf(stderr,"WARNING: Conversion between user-specified unit \"%s\" and file units \"%s\" is meaningless\n",fl_bs_sng,fl_unt_sng); return NCO_ERR; /* Failure */ } /* endif */ /* Convert */ *og_val=cv_convert_double(ut_cnv,crr_val); if(nco_dbg_lvl_get() >= nco_dbg_var) fprintf(stderr, "%s: INFO %s() reports conversion between systems \"%s\" and \"%s\" is %f\n",nco_prg_nm_get(),fnc_nm,fl_unt_sng,fl_bs_sng,*og_val); ut_free(ut_sct_in); ut_free(ut_sct_out); cv_free(ut_cnv); ut_free_system(ut_sys); /* Free memory taken by UDUnits library */ return NCO_NOERR; } /* end UDUnits2 nco_cln_clc_dff() */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_prs_tm /* UDUnits2 Extract time stamp from parsed UDUnits string */ (const char *unt_sng, /* I [ptr] units attribute string */ tm_cln_sct *tm_in) /* O [sct] struct to be populated */ { const char fnc_nm[]="nco_cln_prs_tm()"; /* [sng] Function name */ char bfr[200]; char *dt_sng; int ut_rcd; /* [enm] UDUnits2 status */ ut_system *ut_sys; ut_unit *ut_sct_in; /* UDUnits structure, input units */ /* When empty, ut_read_xml() uses environment variable UDUNITS2_XML_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ if(nco_dbg_lvl_get() >= nco_dbg_vrb) ut_set_error_message_handler(ut_write_to_stderr); else ut_set_error_message_handler(ut_ignore); ut_sys=ut_read_xml(NULL); if(ut_sys == NULL){ (void)fprintf(stdout,"%s: %s failed to initialize UDUnits2 library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; /* Failure */ } /* end if err */ /* units string to convert from */ ut_sct_in=ut_parse(ut_sys,unt_sng,UT_ASCII); if(ut_sct_in == NULL){ /* Problem with 'units' attribute */ ut_rcd=ut_get_status(); /* [enm] UDUnits2 status */ if(ut_rcd == UT_BAD_ARG) (void)fprintf(stderr,"ERROR: empty units attribute string\n"); if(ut_rcd == UT_SYNTAX) (void)fprintf(stderr,"ERROR: units attribute \"%s\" has a syntax error\n",unt_sng); if(ut_rcd == UT_UNKNOWN) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is not listed in UDUnits2 SI system database\n",unt_sng); return NCO_ERR; /* Failure */ } /* endif coordinate on disk has no units attribute */ /* Print timestamp to buffer in standard, dependable format */ ut_format(ut_sct_in,bfr,sizeof(bfr), UT_ASCII|UT_NAMES); /* Extract parsed time units from print string (kludgy) */ dt_sng=strstr(bfr,"since"); sscanf(dt_sng,"%*s %d-%d-%d %d:%d:%f",&tm_in->year,&tm_in->month,&tm_in->day,&tm_in->hour,&tm_in->min,&tm_in->sec); ut_free_system(ut_sys); /* Free memory taken by UDUnits library */ ut_free(ut_sct_in); return NCO_NOERR; } /* end UDUnits2 nco_cln_prs_tm() */ # else /* !HAVE_UDUNITS2_H */ /* UDUnits1 routines */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_clc_dff /* [fnc] UDUnits1 Difference between two co-ordinate units */ (const char *fl_unt_sng, /* I [ptr] units attribute string from disk */ const char *fl_bs_sng, /* I [ptr] units attribute string from disk */ double crr_val, double *og_val) /* O [ptr] */ { const char fnc_nm[]="nco_cln_clc_dff()"; /* [sng] Function name */ double slp; double incpt; int rcd; utUnit udu_sct_in; /* UDUnits structure, input units */ utUnit udu_sct_out; /* UDUnits structure, output units */ /* Quick return if units identical */ if(!strcmp(fl_unt_sng,fl_bs_sng) ){ *og_val=crr_val; return NCO_NOERR; } /* endif */ #ifdef UDUNITS_PATH /* UDUNITS_PATH macro expands to where autoconf found database file */ rcd=utInit(UDUNITS_PATH); #else /* !UDUNITS_PATH */ /* When empty, utInit() uses environment variable UDUNITS_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ rcd=utInit(""); #endif /* !UDUNITS_PATH */ if(rcd != UDUNITS_NOERR){ (void)fprintf(stdout,"%s: %s failed to initialize UDUnits2 library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; } /* end if err */ /* units string to convert from */ rcd=utScan(fl_unt_sng,&udu_sct_in); if(rcd != UDUNITS_NOERR){ if(rcd == UT_EINVALID) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is invalid \n",fl_unt_sng); if(rcd == UT_ESYNTAX) (void)fprintf(stderr,"ERROR units attribute \"%s\" contains a syntax error",fl_unt_sng); if(rcd == UT_EUNKNOWN) (void)fprintf(stderr,"ERROR units attribute \"%s\" is not in udunits database",fl_unt_sng); (void)utTerm(); /* Free memory taken by UDUnits library */ return NCO_ERR; } /* endif unkown type */ /* units string to convert to */ rcd=utScan(fl_bs_sng,&udu_sct_out); if(rcd != UDUNITS_NOERR){ if(rcd == UT_EINVALID) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is invalid \n",fl_bs_sng); if(rcd == UT_ESYNTAX) (void)fprintf(stderr,"ERROR units attribute \"%s\" contains a syntax error",fl_bs_sng); if(rcd == UT_EUNKNOWN) (void)fprintf(stderr,"ERROR units attribute \"%s\" is not in udunits database",fl_bs_sng); (void)utTerm(); /* Free memory taken by UDUnits library */ return NCO_ERR; } /* endif unkown type */ rcd=utConvert(&udu_sct_in,&udu_sct_out,&slp,&incpt); if(rcd == UT_ECONVERT){ (void)fprintf(stderr,"ERROR: user specified unit \"%s\" cannot be converted to units \"%s\"\n",fl_unt_sng,fl_bs_sng); (void)utTerm(); return NCO_ERR; } /* endif */ *og_val=crr_val*slp+incpt; /* debug stuff */ if(nco_dbg_lvl_get() > nco_dbg_std) (void)fprintf(stderr,"%s: %s reports difference between systems \"%s\" and \"%s\" is %f\n",nco_prg_nm_get(),fnc_nm,fl_unt_sng,fl_bs_sng,*og_val); (void)utTerm(); return NCO_NOERR; } /* end UDUnits1 nco_cln_clc_dff() */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_prs_tm /* UDUnits1 Extract time stamp from a parsed udunits string */ (const char *unt_sng, /* I [ptr] units attribute string */ tm_cln_sct *tm_in) /* O [sct] struct to be populated */ { const char fnc_nm[]="nco_cln_prs_tm()"; /* [sng] Function name */ int rcd; utUnit udu_sct_in; /* UDUnits structure, input units */ #ifdef UDUNITS_PATH /* UDUNITS_PATH macro expands to where autoconf found database file */ rcd=utInit(UDUNITS_PATH); #else /* !UDUNITS_PATH */ /* When empty, utInit() uses environment variable UDUNITS_PATH, if any Otherwise it uses default initial location hardcoded when library was built */ rcd=utInit(""); #endif /* !UDUNITS_PATH */ if(rcd != UDUNITS_NOERR){ (void)fprintf(stdout,"%s: %s failed to initialize UDUnits library\n",nco_prg_nm_get(),fnc_nm); return NCO_ERR; } /* end if err */ /* units string to convert from */ rcd=utScan(unt_sng,&udu_sct_in); if(rcd != UDUNITS_NOERR){ if(rcd == UT_EINVALID) (void)fprintf(stderr,"ERROR: units attribute \"%s\" is invalid \n",unt_sng); if(rcd == UT_ESYNTAX) (void)fprintf(stderr,"ERROR units attribute \"%s\" contains a syntax error",unt_sng); if(rcd == UT_EUNKNOWN) (void)fprintf(stderr,"ERROR units attribute \"%s\" is not in udunits database",unt_sng); (void)utTerm(); /* Free memory taken by UDUnits library */ return NCO_ERR; } /* endif unkown type */ /* Extract time origin */ if(utIsTime(&udu_sct_in)){ utCalendar(0.0,&udu_sct_in,&tm_in->year,&tm_in->month,&tm_in->day,&tm_in->hour,&tm_in->min,&tm_in->sec); rcd=NCO_NOERR; }else{ rcd=NCO_ERR; } /* endelse */ (void)utTerm(); /* Free memory taken by UDUnits library */ return rcd; } /* end UDUnits1 nco_cln_prs_tm() */ # endif /*!HAVE_UDUNITS2 */ #else /* !ENABLE_UDUNITS */ /* No UDUnits implementation available */ /* Stubs to enable compilation without UDUnits */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_clc_dff( /* [fnc] Difference between two co-ordinate units */ const char *fl_unt_sng, /* I [ptr] units attribute string from disk */ const char *fl_bs_sng, /* I [ptr] units attribute string from disk */ double crr_val, double *og_val){ /* O [ptr] */ return NCO_NOERR; } int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_prs_tm( /* Extract time stamp from a parsed UDUnits string */ const char *unt_sng, /* I [ptr] units attribute string */ tm_cln_sct *tm_in){ /* O [sct] struct to be populated */ return NCO_NOERR; } #endif /* !ENABLE_UDUNITS */ /* End UDUnits-related routines*/ tm_typ /* [enum] Units type */ nco_cln_get_tm_typ /* Returns time unit type or tm_void if not found */ (const char *ud_sng){ /* I [ptr] units string */ int idx; int len; char *lcl_sng; tm_typ rcd_typ; lcl_sng=strdup(ud_sng); /* Initially set ret type to void */ rcd_typ=tm_void; /* Convert to lower case */ len=strlen(lcl_sng); for(idx=0;idxsc_cln){ case cln_360: data=DATA_360; cln_sct->value=data[0]*(cln_sct->year-1)+ data[1]*(cln_sct->month-1)+ data[2]*(cln_sct->day-1)+ data[3]*cln_sct->hour+ data[4]*cln_sct->min+ data[5]*(double)cln_sct->sec; break; case cln_365: data=DATA_365; cln_sct->value=data[0]*(cln_sct->year-1)+ data[2]*nco_cln_days_in_year_prior_to_given_month(cln_365,cln_sct->month)+ data[2]*(cln_sct->day-1)+ data[3]*cln_sct->hour+ data[4]*cln_sct->min+ data[5]*(double)cln_sct->sec; break; case cln_366: break; case cln_std: case cln_grg: case cln_jul: case cln_nil: break; } return; } /* end nco_cln_pop_val() */ double /* O [dbl] relative time */ nco_cln_rel_val (double offset, /* I [dbl] time in base units */ nco_cln_typ lmt_cln, /* I [enm] Calendar type */ tm_typ bs_tm_typ) /* I [enm] Time units */ { double *data=NULL_CEWI; double scl=double_CEWI; switch(lmt_cln) { case cln_360: data=DATA_360; break; case cln_365: data=DATA_365; break; case cln_366: break; case cln_std: case cln_grg: case cln_jul: case cln_nil: break; } /* Switch for type */ switch(bs_tm_typ){ case tm_year: scl=data[0]; break; case tm_month: scl=data[1]; break; case tm_day: scl=data[2]; break; case tm_hour: scl=data[3]; break; case tm_min: scl=data[4]; break; case tm_sec: case tm_void: scl=data[5]; break; } /* end switch */ return offset/scl; } /* end nco_cln_rel_val() */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_clc_tm /* [fnc] Difference between two coordinate units */ (const char *fl_unt_sng, /* I [ptr] units attribute string from disk */ const char *fl_bs_sng, /* I [ptr] units attribute string from disk */ nco_cln_typ lmt_cln, /* [enum] Calendar type of coordinate var */ double *og_val){ /* O [ptr] */ int rcd; int year; int month; char *lcl_unt_sng; char tmp_sng[100]; double crr_val; tm_typ bs_tm_typ; /* enum for units type in fl_bs_sng */ tm_cln_sct unt_cln_sct; tm_cln_sct bs_cln_sct; if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: nco_cln_clc_tm() reports unt_sng=%s bs_sng=%s\n",nco_prg_nm_get(),fl_unt_sng,fl_bs_sng); /* Does fl_unt_sng look like a regular timestamp? */ if(sscanf(fl_unt_sng,"%d-%d",&year,&month) == 2){ lcl_unt_sng=(char *)nco_malloc((strlen(fl_unt_sng)+3L)*sizeof(char)); strcpy(lcl_unt_sng,"s@"); strcat(lcl_unt_sng,fl_unt_sng); }else{ lcl_unt_sng=strdup(fl_unt_sng); } /* endelse */ /* Temporary until we handle more calendar types */ if(lmt_cln != cln_360 && lmt_cln != cln_365){ rcd=nco_cln_clc_dff(lcl_unt_sng,fl_bs_sng,0.0,og_val); lcl_unt_sng=(char *)nco_free(lcl_unt_sng); return rcd; } /* endif */ /* Obtain units type from fl_bs_sng */ if(sscanf(fl_bs_sng,"%s",tmp_sng) != 1) return NCO_ERR; bs_tm_typ=nco_cln_get_tm_typ(tmp_sng); /* Assume non-standard calendar */ if(nco_cln_prs_tm(lcl_unt_sng,&unt_cln_sct) == NCO_ERR) return NCO_ERR; if(nco_cln_prs_tm(fl_bs_sng,&bs_cln_sct) == NCO_ERR) return NCO_ERR; unt_cln_sct.sc_typ=bs_tm_typ; bs_cln_sct.sc_typ=bs_tm_typ; unt_cln_sct.sc_cln=lmt_cln; bs_cln_sct.sc_cln=lmt_cln; (void)nco_cln_pop_val(&unt_cln_sct); (void)nco_cln_pop_val(&bs_cln_sct); crr_val=nco_cln_rel_val(unt_cln_sct.value-bs_cln_sct.value,lmt_cln,bs_tm_typ); *og_val=crr_val; lcl_unt_sng=(char *)nco_free(lcl_unt_sng); return NCO_NOERR; } /* end nco_cln_clc_tm() */ int /* [rcd] Successful conversion returns NCO_NOERR */ nco_cln_clc_org /* [fnc] Difference between two generic co-ordinate units */ (const char *fl_unt_sng, /* I [ptr] Source value (optional) and source units */ const char *fl_bs_sng, /* I [ptr] Target units */ nco_cln_typ lmt_cln, /* [enm] Calendar type, if any, of coordinate variable */ double *og_val) /* O [ptr] Target value in units stored on disk */ { /* Purpose: Given a value expressed source units (fl_unit_sng) and target units to switch to, determine and return the value expressed in the target units. */ int rcd; char *usr_unt_sng; double crr_val; /* If units contain date or timestamp call special time-conversion routine */ if(strstr(fl_bs_sng," from ") || strstr(fl_bs_sng," since ") || strstr(fl_bs_sng," after ")){ rcd=nco_cln_clc_tm(fl_unt_sng,fl_bs_sng,lmt_cln,og_val); return rcd; } /* endif */ /* Regular conversion of fl_unt_sng of form , e.g., '10 inches', '100 ft' */ usr_unt_sng=(char *)nco_calloc(strlen(fl_unt_sng)+1L, sizeof(char)); sscanf(fl_unt_sng,"%lg %s",&crr_val,usr_unt_sng); rcd=nco_cln_clc_dff(usr_unt_sng,fl_bs_sng,crr_val,og_val); usr_unt_sng=(char *)nco_free(usr_unt_sng); return rcd; } /* end nco_cln_clc_org() */ ./nco-4.4.2/src/nco/nco_lst_utl.h0000644000674300045400000001605012262450455016030 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_lst_utl.h,v 1.54 2014/01/06 06:46:05 zender Exp $ */ /* Purpose: List utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_lst_utl.h" *//* List utilities */ #ifndef NCO_LST_UTL_H #define NCO_LST_UTL_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, qsort */ #include /* strcmp() */ #ifdef HAVE_REGEX_H /* 20120213: Linux GCC 4.6 man page says regex.h depends on (non-present) sys/types.h */ # ifdef MACOSX # include /*19950312: _res, 20040822: Mac OS X off_t required by regex.h */ # endif /* !MACOSX */ # include /* POSIX regular expressions library */ #endif /* HAVE_REGEX_H */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_grp_trv.h" /* Group traversal */ #include "nco_mmr.h" /* Memory management */ #include "nco_sng_utl.h" /* String utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ char * /* O [nbr] Format string with printf()-formats replaced */ nco_fmt_sng_printf_subst /* [fnc] Replace printf() format statements */ (const char * const fmt_sng); /* I [sng] Format string before processing */ int /* O [nbr] Number of matches found */ nco_lst_rx_search /* [fnc] Search for pattern matches in var string list */ (const int var_nbr_all, /* I [nbr] Size of var_lst_all and var_xtr_rqs */ nm_id_sct *var_lst_all, /* I [sct] All variables in input file (with IDs) */ char *rx_sng, /* I [sng] Regular expression pattern */ nco_bool *var_xtr_rqs); /* O [flg] Matched vars holder */ void nco_srt_ntg /* [fnc] Sort array of integers */ (const int lmn_nbr, /* I [nbr] Number of elements */ const int * const arr_in, /* I [idx] Array to sort */ int * const idx); /* O [idx] Indices to sorted array */ void nco_srt_lph /* [fnc] Sort array of strings */ (const int lmn_nbr, /* I [nbr] Number of elements */ char * const * const arr_in, /* I [sng] Strings to sort */ int * const idx); /* O [idx] Indices to sorted array */ char ** /* O [sng] Array of list elements */ nco_lst_prs_1D /* [fnc] Create 1D array of strings from given string and delimiter */ (char * const sng_in, /* I/O [sng] Delimited argument list (delimiters are changed to NULL on output */ const char * const dlm_sng, /* I [sng] Delimiter string */ int * const nbr_lst); /* O [nbr] Number of elements in list */ char ** /* O [sng] List of strings */ nco_lst_prs_2D /* [fnc] Create 2D list of strings from given string and delimiter */ (const char * const sng_in, /* I [sng] Delimited argument list */ const char * const dlm_sng, /* I [sng] Delimiter string */ int * const nbr_lst); /* O [nbr] Number of elements in list */ char ** /* O [sng] List of strings */ nco_lst_prs_sgl_2D /* [fnc] Create list of strings from given string and delimiter */ (const char * const sng_in, /* I [sng] Delimited argument list */ const char * const dlm_sng, /* I [sng] Delimiter string */ int * const nbr_lst); /* O [nbr] Number of elements in list */ nm_id_sct * /* O [sct] Sorted output list */ lst_heapsort /* [fnc] Heapsort input lists numerically or alphabetically */ (nm_id_sct *lst, /* I/O [sct] Current list (destroyed) */ const int nbr_lst, /* I [nbr] number of members in list */ const nco_bool ALPHABETIZE_OUTPUT); /* I [flg] Alphabetize extraction list */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_chr /* [fnc] Compare two characters */ (const void *val_1, /* I [chr] Character to compare */ const void *val_2); /* I [chr] Character to compare */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_int /* [fnc] Compare two integers */ (const void *val_1, /* I [nbr] Number to compare */ const void *val_2); /* I [nbr] Number to compare */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_sng /* [fnc] Compare two strings */ (const void *val_1, /* I [sng] String to compare */ const void *val_2); /* I [sng] String to compare */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_nm_id_nm /* [fnc] Compare two nm_id_sct's by name member */ (const void *val_1, /* I [sct] nm_id_sct to compare */ const void *val_2); /* I [sct] nm_id_sct to compare */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_nm_id_id /* [fnc] Compare two nm_id_sct's by ID member */ (const void *val_1, /* I [sct] nm_id_sct to compare */ const void *val_2); /* I [sct] nm_id_sct to compare */ int /* O [enm] Comparison result [<,=,>] 0 iff op1 [<,==,>] op2 */ nco_cmp_ptr_unn /* Compare values of two pointer unions of same type */ (const nc_type type, /* I [enm] netCDF type of operands */ const ptr_unn op1, /* I [sct] First operand to compare */ const ptr_unn op2); /* I [sct] Second operand to compare */ dmn_sct ** /* O [sct] Pointer to free'd structure list */ nco_dmn_lst_free /* [fnc] Free memory associated with dimension structure list */ (dmn_sct **dmn_lst, /* I/O [sct] Dimension structure list to free */ const int dmn_nbr); /* I [nbr] Number of dimension structures in list */ void nco_hash2comma /* [fnc] Replace hashes with commas */ (char * const rx_sng); /* [sng] Regular expression */ void nco_rx_comma2hash /* [fnc] Convert {...,...} to {...#...} in regular expressions */ (char * const rx_sng); /* [sng] Regular expression */ nm_id_sct * /* O [sct] Sorted output list */ nco_lst_srt_nm_id /* [fnc] Sort name/ID input list numerically or alphabetically */ (nm_id_sct * const lst, /* I/O [sct] Current list (destroyed) */ const int nbr_lst, /* I [nbr] number of members in list */ const nco_bool ALPHABETIZE_OUTPUT); /* I [flg] Alphabetize extraction list */ nm_id_sct * /* O [sct] Pointer to free'd structure list */ nco_nm_id_lst_free /* [fnc] Free memory associated with name-ID structure list */ (nm_id_sct *nm_id_lst, /* I/O [sct] Name-ID structure list to free */ const int nm_id_nbr); /* I [nbr] Number of name-ID structures in list */ char ** /* O [sng] Pointer to free'd string list */ nco_sng_lst_free /* [fnc] Free memory associated with string list */ (char **sng_lst, /* I/O [sng] String list to free */ const int sng_nbr); /* I [nbr] Number of strings in list */ char * /* O [sng] Concatenated string formed by joining all input strings */ sng_lst_cat /* [fnc] Join string list together into one string, delete originals */ (char ** const sng_lst, /* I/O [sng] List of pointers to strings to join together */ const long lmn_nbr, /* I [nbr] Number of strings in list */ const char * const dlm_sng); /* I [sng] Delimiter string to use as glue */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_LST_UTL_H */ ./nco-4.4.2/src/nco/nco_sng_utl.h0000644000674300045400000000746112260451232016013 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_sng_utl.h,v 1.44 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: String utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_sng_utl.h" *//* String utilities */ #ifndef NCO_SNG_UTL_H #define NCO_SNG_UTL_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strcmp() */ #ifdef HAVE_STRINGS_H # include /* strcasecmp() */ #endif /* !HAVE_STRINGS_H */ #ifdef _MSC_VER # define NEED_STRCASESTR #endif /* !_MSC_VER */ #if defined(NEED_STRCASECMP) || defined(NEED_STRCASESTR) # include /* tolower() */ #endif /* !NEED_STRCASECMP || !NEED_STRCASESTR */ /* 3rd party vendors */ /* Personal headers */ #include "nco_mmr.h" /* Memory management */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifdef NEED_STRCASECMP int /* O [enm] [-1,0,1] sng_1 [<,=,>] sng_2 */ strcasecmp /* [fnc] Lexicographical case-insensitive string comparison */ (const char * const sng_1, /* I [sng] First string */ const char * const sng_2); /* I [sng] Second string */ #endif /* !NEED_STRCASECMP */ /* 20130827 GNU g++ always provides strcasestr(), MSVC never does */ #ifndef __GNUG__ # ifdef NEED_STRCASESTR char * /* O [sng] Pointer to sng_2 in sng_1 */ strcasestr /* [fnc] Lexicographical case-insensitive string search */ (const char * const sng_1, /* I [sng] First string */ const char * const sng_2); /* I [sng] Second string */ # endif /* !NEED_STRCASESTR */ #endif /* __GNUG__ */ #ifdef NEED_STRDUP char * /* O [sng] Copy of input string */ strdup /* [fnc] Duplicate string */ (const char * const sng_in); /* I [sng] String to duplicate */ #endif /* !NEED_STRDUP */ #ifdef NEED_STRTOLL long long int /* O [nbr] String as long long integer */ strtoll /* [fnc] Convert string to a long long integer */ (const char * const nptr, char ** const endptr, const int base); #endif /* !NEED_STRTOLL */ char * /* O [sng] Parsed command line */ nco_cmd_ln_sng /* [fnc] Re-construct command line from arguments */ (const int argc, /* I [nbr] Argument count */ CST_X_PTR_CST_PTR_CST_Y(char,argv)); /* I [sng] Command line argument values */ /* char **argv); *//* I [sng] Command line argument values */ char * /* O [sng] CDL-compatible name */ nm2sng_cdl /* [fnc] Turn variable/dimension/attribute name into legal CDL */ (const char * const nm_sng); /* I [sng] Name to CDL-ize */ char * /* O [sng] String containing printable result */ chr2sng_cdl /* [fnc] Translate C language character to printable, visible ASCII bytes */ (const char chr_val, /* I [chr] Character to process */ char * const val_sng); /* I/O [sng] String to stuff printable result into */ char * /* O [sng] String containing printable result */ chr2sng_xml /* [fnc] Translate C language character to printable, visible ASCII bytes */ (const char chr_val, /* I [chr] Character to process */ char * const val_sng); /* I/O [sng] String to stuff printable result into */ int /* O [nbr] Number of escape sequences translated */ sng_ascii_trn /* [fnc] Replace C language '\X' escape codes in string with ASCII bytes */ (char * const sng); /* I/O [sng] String to process */ void sng_idx_dlm_c2f /* [fnc] Replace brackets with parentheses in a string */ (char *sng); /* [sng] String to change from C to Fortran notation */ void /* O [nbr] */ sng_trm_trl_zro /* [fnc] Trim zeros trailing the decimal point from floating point string */ (char * const sng, /* I/O [sng] String to process */ const int trl_zro_max); /* [nbr] Maximum number of trailing zeros allowed */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_SNG_UTL_H */ ./nco-4.4.2/src/nco/nco_sng_utl.c0000644000674300045400000004310012272265647016014 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_sng_utl.c,v 1.72 2014/01/29 20:59:19 pvicente Exp $ */ /* Purpose: String utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_sng_utl.h" /* String utilities */ #ifdef NEED_STRCASECMP int /* O [enm] [-1,0,1] sng_1 [<,=,>] sng_2 */ strcasecmp /* [fnc] Lexicographical case-insensitive string comparison */ (const char * const sng_1, /* I [sng] First string */ const char * const sng_2) /* I [sng] Second string */ { /* Copy of (const) input strings */ char *sng_1_c; char *sng_2_c; char chr_1; char chr_2; sng_1_c=(char *)sng_1; sng_2_c=(char *)sng_2; while(1){ chr_1=tolower(*sng_1_c++); chr_2=tolower(*sng_2_c++); if(chr_1 < chr_2){ return -1; } /* end if */ if(chr_1 > chr_2){ return 1; } /* end if */ if(chr_1 == 0){ return 0; } /* end if */ } /* end while */ } /* end strcasecmp() */ #endif /* !NEED_STRCASECMP */ /* 20130827 GNU g++ always provides strcasestr(), MSVC never does */ #ifndef __GNUG__ # ifdef NEED_STRCASESTR char * /* O [sng] Pointer to sng_2 in sng_1 */ strcasestr /* [fnc] Lexicographical case-insensitive string search */ (const char * const sng_1, /* I [sng] First string */ const char * const sng_2) /* I [sng] Second string */ { /* 20120706 Initial version discards const, triggers compiler warnings 20120803 Kludge with strdup() to try to keep const intact. Fail. 20130827 Add (char *) cast (compile error in MSVC) */ char *hys_ptr; /* Haystack pointer */ char *startn=0; char *np=0; /* Loop exits on NUL */ for(hys_ptr=(char *)sng_1;*hys_ptr;hys_ptr++){ if(np){ if(toupper(*hys_ptr) == toupper(*np)){ if(!*++np) return startn; }else{ np=0; } /* endif uppercases match */ }else if(toupper(*hys_ptr) == toupper(*sng_2)){ np=(char *)sng_2+1; startn=hys_ptr; } /* else if */ } /* end loop over haystack */ return 0; } /* end strcasestr() */ # endif /* !NEED_STRCASESTR */ #endif /* __GNUG__ */ #ifdef NEED_STRDUP char * /* [sng] Copy of input string */ strdup /* [fnc] Duplicate string */ (const char *sng_in) /* [sng] String to duplicate */ { /* Purpose: Provide strdup() for broken systems Input string must be NUL-terminated */ size_t sng_lng=strlen(sng_in)+1UL; /* Use nco_malloc() even though strdup() is system function This ensures all NCO code goes through nco_malloc() */ char *sng_out=(char *)nco_malloc(sng_lng*sizeof(char)); if(sng_out) strcpy(sng_out,sng_in); return sng_out; } /* end strdup() */ #endif /* !NEED_STRDUP */ #ifdef NEED_STRTOLL long long int /* O [nbr] String as long long integer */ strtoll /* [fnc] Convert string to a long long integer */ (const char * const nptr, char ** const endptr, const int base) { /* Purpose: Compatibility function for strtoll() Needed by some C++ compilers, e.g., AIX xlC 20120703: rewrite to cast result of strtol() to long long and return */ long long nbr_out; nbr_out=(long long)strtol(nptr,endptr,base); return nbr_out; } /* end strtoll() */ #endif /* !NEED_STRTOLL */ char * /* O [sng] Parsed command line */ nco_cmd_ln_sng /* [fnc] Re-construct command line from arguments */ (const int argc, /* I [nbr] Argument count */ CST_X_PTR_CST_PTR_CST_Y(char,argv)) /* I [sng] Command line argument values */ { /* Purpose: Re-construct command line from argument list and number */ char *cmd_ln; /* [sng] Parsed command line */ int cmd_ln_sz=0; int idx; for(idx=0;idx= 0x01 && *chr_in_ptr <= 0x20) || (*chr_in_ptr == 0x7f)){ (void)fprintf(stderr,"%s: ERROR name begins with space or control-character: %c\n",nco_prg_nm_get(),*chr_in_ptr); nco_exit(EXIT_FAILURE); } /* endif error */ /* Special case: leading number allowed, but we must escape it for CDL */ if((*chr_in_ptr >= '0' && *chr_in_ptr <= '9')) *chr_out_ptr++ = '\\'; while(*chr_in_ptr){ if(isascii(*chr_in_ptr)){ if(iscntrl(*chr_in_ptr)){ /* Render control chars as two hex digits, \%xx */ snprintf(chr_out_ptr,4,"\\%%%.2x",*chr_in_ptr); chr_out_ptr+=4; }else{ switch(*chr_in_ptr){ case ' ': case '!': case '"': case '#': case '$': case '&': case '\'': case '(': case ')': case '*': case ',': case ':': case ';': case '<': case '=': case '>': case '?': case '[': case ']': case '\\': case '^': case '`': case '{': case '|': case '}': case '~': *chr_out_ptr++='\\'; *chr_out_ptr++=*chr_in_ptr; break; default: /* NB: includes '/' */ *chr_out_ptr++=*chr_in_ptr; break; } /* end switch */ } /* not a control character */ }else{ /* not ascii, assume just UTF-8 byte */ *chr_out_ptr++=*chr_in_ptr; } /* end else not ascii */ /* Advance character */ chr_in_ptr++; } /* end while loop */ /* NUL-terminate */ *chr_out_ptr=0; /* Free memory */ nm_cpy=(char *)nco_free(nm_cpy); return nm_cdl; } /* end nm2sng_cdl */ char * /* O [sng] String containing printable result */ chr2sng_cdl /* [fnc] Translate C language character to printable, visible ASCII bytes */ (const char chr_val, /* I [chr] Character to process */ char * const val_sng) /* I/O [sng] String to stuff printable result into */ { /* Purpose: Translate character to C-printable, visible ASCII bytes for CDL Reference: netcdf-c/ncdump/ncdump.c:pr_att_string() */ switch(chr_val){ /* man ascii:Oct Dec Hex Char \X */ case '\a': strcpy(val_sng,"\\a"); break; /* 007 7 07 BEL '\a' Bell */ case '\b': strcpy(val_sng,"\\b"); break; /* 010 8 08 BS '\b' Backspace */ case '\f': strcpy(val_sng,"\\f"); break; /* 014 12 0C FF '\f' Formfeed */ case '\n': strcpy(val_sng,"\\n"); break; /* 012 10 0A LF '\n' Linefeed */ case '\r': strcpy(val_sng,"\\r"); break; /* 015 13 0D CR '\r' Carriage return */ case '\t': strcpy(val_sng,"\\t"); break; /* 011 9 09 HT '\t' Horizontal tab */ case '\v': strcpy(val_sng,"\\v"); break; /* 013 11 0B VT '\v' Vertical tab */ case '\\': strcpy(val_sng,"\\\\"); break; /* 134 92 5C \ '\\' */ case '\'': strcpy(val_sng,"\\\'"); break; /* Unsure why or if this works! */ case '\"': strcpy(val_sng,"\\\""); break; /* Unsure why or if this works! */ case '\0': break; default: sprintf(val_sng,"%c",chr_val); break; break; } /* end switch */ return val_sng; } /* end chr2sng_cdl */ char * /* O [sng] String containing printable result */ chr2sng_xml /* [fnc] Translate C language character to printable, visible ASCII bytes */ (const char chr_val, /* I [chr] Character to process */ char * const val_sng) /* I/O [sng] String to stuff printable result into */ { /* Purpose: Translate character to C-printable, visible ASCII bytes for XML Reference: netcdf-c/ncdump/ncdump.c:pr_attx_string() NB: Unclear whether and'ing with octal 0377 helps anything */ // unsigned char uchar; // switch(uchar=chr_val & 0377){ /* man ascii:Oct Dec Hex Char \X */ switch(chr_val){ /* man ascii:Oct Dec Hex Char \X */ case '\n': strcpy(val_sng," "); break; /* 012 10 0A LF '\n' Linefeed */ case '\r': strcpy(val_sng," "); break; /* 015 13 0D CR '\r' Carriage return */ case '\t': strcpy(val_sng," "); break; /* 011 9 09 HT '\t' Horizontal tab */ case '<': strcpy(val_sng,"<"); break; case '>': strcpy(val_sng,">"); break; case '&': strcpy(val_sng,"&"); break; case '\"': strcpy(val_sng,"""); break; case '\0': /* NB: Unidata handles NUL differently */ break; default: // if(iscntrl(uchar)) sprintf(val_sng,"&#%d;",uchar); else sprintf(val_sng,"%c",uchar); if(iscntrl(chr_val)) sprintf(val_sng,"&#%d;",chr_val); else sprintf(val_sng,"%c",chr_val); break; } /* end switch */ return val_sng; } /* end chr2sng_xml */ int /* O [nbr] Number of escape sequences translated */ sng_ascii_trn /* [fnc] Replace C language '\X' escape codes in string with ASCII bytes */ (char * const sng) /* I/O [sng] String to process */ { /* Purpose: Replace C language '\X' escape codes in string with ASCII bytes Return number of escape sequences found and actually translated This should be same as number of bytes by which string length has shrunk For example, consecutive characters "\n" are translated into ASCII '\n' = 10 Each such translation diminishes string length by one Function works for arbitrary number of escape codes in input string The escape sequence for NUL itself, \0, causes a warning and is not translated Input string must be NUL-terminated or NULL This procedure can only diminish, not lengthen, input string size Therefore it may safely be performed in-place, i.e., no string copy is necessary Translation is done in-place so copy original prior to calling sng_ascii_trn()!!! Address pointed to by sng does not change, but memory at that address is altered when characters are "moved to the left" if C language escape sequences are embedded. Thus string length may shrink */ const char fnc_nm[]="sng_ascii_trn()"; /* [sng] Function name */ nco_bool trn_flg; /* Translate this escape sequence */ char *backslash_ptr; /* [ptr] Pointer to backslash character */ char backslash_chr='\\'; /* [chr] Backslash character */ int esc_sqn_nbr=0; /* Number of escape sequences found */ int trn_nbr=0; /* Number of escape sequences translated */ /* ncatted allows character attributes of 0 length Such "strings" do not have NUL-terminator and so may not safely be tested by strchr() */ if(sng == NULL) return trn_nbr; /* C language '\X' escape codes are always preceded by a backslash */ /* Check if control codes are embedded once before entering loop */ backslash_ptr=strchr(sng,backslash_chr); while(backslash_ptr){ /* Default is to translate this escape sequence */ trn_flg=True; /* Replace backslash character by corresponding control code */ switch(*(backslash_ptr+1)){ /* man ascii:Oct Dec Hex Char \X */ case 'a': *backslash_ptr='\a'; break; /* 007 7 07 BEL '\a' Bell */ case 'b': *backslash_ptr='\b'; break; /* 010 8 08 BS '\b' Backspace */ case 'f': *backslash_ptr='\f'; break; /* 014 12 0C FF '\f' Formfeed */ case 'n': *backslash_ptr='\n'; break; /* 012 10 0A LF '\n' Linefeed */ case 'r': *backslash_ptr='\r'; break; /* 015 13 0D CR '\r' Carriage return */ case 't': *backslash_ptr='\t'; break; /* 011 9 09 HT '\t' Horizontal tab */ case 'v': *backslash_ptr='\v'; break; /* 013 11 0B VT '\v' Vertical tab */ case '\\': *backslash_ptr='\\'; break; /* 134 92 5C \ '\\' */ case '\?': *backslash_ptr='\?'; break; /* Unsure why or if this works! */ case '\'': *backslash_ptr='\''; break; /* Unsure why or if this works! */ case '\"': *backslash_ptr='\"'; break; /* Unsure why or if this works! */ case '0': /* Translating \0 to NUL makes subsequent portion of input string invisible to all string functions */ (void)fprintf(stderr,"%s: WARNING C language escape code %.2s found in string, not translating to NUL since this would make the subsequent portion of the string invisible to all C Standard Library string functions\n",nco_prg_nm_get(),backslash_ptr); trn_flg=False; /* 20101013: Tried changing above behavior to following, and it opened a Hornet's nest of problems... */ /* *backslash_ptr='\0'; *//* 000 0 00 NUL '\0' */ /* (void)fprintf(stderr,"%s: WARNING translating C language escape code \"\\0\" found in user-supplied string to NUL. This will make the subsequent portion of the string, if any, invisible to C Standard Library string functions. And that may cause unintended consequences.\n",nco_prg_nm_get());*/ break; default: (void)fprintf(stderr,"%s: WARNING No ASCII equivalent to possible C language escape code %.2s so no action taken\n",nco_prg_nm_get(),backslash_ptr); trn_flg=False; break; } /* end switch */ if(trn_flg){ /* Remove character after backslash character */ (void)memmove(backslash_ptr+1,backslash_ptr+2,(strlen(backslash_ptr+2)+1)*sizeof(char)); /* Count translations performed */ trn_nbr++; } /* end if */ /* Look for next backslash starting at character following current escape sequence (but remember that not all escape sequences are translated) */ if(trn_flg) backslash_ptr=strchr(backslash_ptr+1,backslash_chr); else backslash_ptr=strchr(backslash_ptr+2,backslash_chr); /* Count escape sequences */ esc_sqn_nbr++; } /* end if */ /* Usually there are no escape codes and sng still equals input value */ if(nco_dbg_lvl_get() > 3) (void)fprintf(stderr,"%s: DEBUG %s Found %d C-language escape sequences, translated %d of them\n",nco_prg_nm_get(),fnc_nm,esc_sqn_nbr,trn_nbr); return trn_nbr; } /* end sng_ascii_trn() */ void /* O [nbr] */ sng_trm_trl_zro /* [fnc] Trim zeros trailing the decimal point from floating point string */ (char * const sng, /* I/O [sng] String to process */ const int trl_zro_max) /* [nbr] Maximum number of trailing zeros allowed */ { /* Purpose: Trim zeros trailing decimal point from floating point string Allow trl_zro_max trailing zeros to remain */ char *trl_zro_ptr; /* [sng] Trailing zero pointer */ char *dcm_ptr; /* [sng] Decimal point pointer */ char *vld_ptr=NULL; /* [sng] Valid pointer */ char chr_val; /* [chr] Character value */ int cnt_zro_rmn; /* [nbr] Number of trailing zeros remaining until maximum reached */ /* Find decimal point, if any */ dcm_ptr=strchr(sng,'.'); if(dcm_ptr){ /* Find last zero after decimal point, if any */ trl_zro_ptr=strrchr(dcm_ptr,'0'); if(trl_zro_ptr){ chr_val=*(trl_zro_ptr+1); /* If the next character is a (non-zero) digit, then this is not a trailing zero */ if(isdigit(chr_val)) return; /* Next character is a NUL or exponent (d,D,e,E) or floating type suffix (d,D,f,F) */ /* This is a trailing zero. Allow given number of trailing zeros. */ cnt_zro_rmn=trl_zro_max; while(cnt_zro_rmn > 0){ cnt_zro_rmn--; /* Shift pointer back one character. If that is zero, continue else return. */ if(*trl_zro_ptr-- != '0') return; } /* end while */ /* All characters to right are valid */ vld_ptr=trl_zro_ptr+1; /* Trim all remaining consecutive zeros leftward */ while(*trl_zro_ptr == '0') *trl_zro_ptr--='\0'; /* Copy allowed zeros and/or exponent, if any, to current location */ strncpy(trl_zro_ptr+1UL,vld_ptr,strlen(vld_ptr)+1UL); } /* end if trl_zro_ptr */ } /* end if dcm_ptr */ return; } /* end sng_trm_trl_zro() */ ./nco-4.4.2/src/nco/nco_prn.h0000644000674300045400000001267212274555722015155 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_prn.h,v 1.52 2014/02/06 00:48:18 zender Exp $ */ /* Purpose: Print variables, attributes, metadata */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_prn.h" *//* Print variables, attributes, metadata */ #ifndef NCO_PRN_H #define NCO_PRN_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_cnf_typ.h" /* Conform variable types */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_grp_utl.h" /* Group utilities */ #include "nco_mmr.h" /* Memory management */ #ifdef _MSC_VER # include "nco_rth_flt.h" /* Float-precision arithmetic, MSVC macros */ #endif /* !_MSC_VER */ #include "nco_sng_utl.h" /* String utilities */ /* fxm: strings statically allocated with NCO_MAX_LEN_FMT_SNG chars are susceptible to buffer overflow attacks */ /* Length should be computed at run time but is a pain */ #define NCO_MAX_LEN_FMT_SNG 100ul /* Maximum length of single formatted value of atomic value type */ #define NCO_ATM_SNG_LNG 25ul #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void nco_prn_att /* [fnc] Print all attributes of single variable or group */ (const int grp_id, /* I [id] netCDF group ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const int var_id); /* I [id] netCDF input variable ID */ const char * /* O [sng] sprintf() format string for type typ */ nco_typ_fmt_sng /* [fnc] Provide sprintf() format string for specified type */ (const nc_type typ); /* I [enm] netCDF type to provide format string for */ const char * /* O [sng] sprintf() format string for CDL variable type typ */ nco_typ_fmt_sng_var_cdl /* [fnc] Provide sprintf() format string for specified variable type in CDL */ (const nc_type typ); /* I [enm] netCDF variable type to provide CDL format string for */ const char * /* O [sng] sprintf() format string for CDL attribute type typ */ nco_typ_fmt_sng_att_cdl /* [fnc] Provide sprintf() format string for specified attribute type in CDL */ (const nc_type typ); /* I [enm] netCDF attribute type to provide CDL format string for */ const char * /* O [sng] sprintf() format string for XML attribute type typ */ nco_typ_fmt_sng_att_xml /* [fnc] Provide sprintf() format string for specified attribute type in XML */ (const nc_type typ); /* I [enm] netCDF attribute type to provide XML format string for */ void nco_prn_var_val_lmt /* [fnc] Print variable data */ (const int in_id, /* I [id] netCDF input file ID */ const char * const var_nm, /* I [sng] Variable name */ const lmt_sct * const lmt, /* I [sct] Dimension limits */ const int lmt_nbr, /* I [nbr] number of dimensions with user-specified limits */ char * const dlm_sng, /* I [sng] User-specified delimiter string, if any */ const nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ const nco_bool PRN_DMN_UNITS, /* I [flg] Print units attribute, if any */ const nco_bool PRN_DMN_IDX_CRD_VAL); /* I [flg] Print dimension/coordinate indices/values */ void nco_prn_var_val_trv /* [fnc] Print variable data */ (const int nc_id, /* I [ID] netCDF file ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const trv_sct * const var_trv, /* I [sct] Object to print (variable) */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ void nco_prn_var_dfn /* [fnc] Print variable metadata */ (const int nc_id, /* I [id] netCDF file ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const trv_sct * const var_trv); /* I [sct] Object to print (variable) */ int /* [rcd] Return code */ nco_grp_prn /* [fnc] Recursively print group contents */ (const int nc_id, /* I [id] netCDF file ID */ const char * const grp_nm_fll, /* I [sng] Absolute group name (path) */ prn_fmt_sct * const prn_flg, /* I/O [sct] Print-format information */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ nco_bool /* O [flg] Variable is compound */ nco_prn_cpd_chk /* [fnc] Check whether variable is compound */ (const trv_sct * const var_trv, /* I [sct] Variable to check */ const trv_tbl_sct * const trv_tbl); /* I [sct] GTT (Group Traversal Table) */ nco_bool /* O [flg] Type requires hidden _FillValue attribute string */ nco_xml_typ_rqr_flv_att /* [fnc] Does type require hidden _FillValue attribute for XML representation? */ (const nc_type nco_typ); /* I [enm] netCDF type */ nco_bool /* O [flg] Type requires hidden attribute string */ nco_xml_typ_rqr_nsg_att /* [fnc] Does type require hidden _Unsigned attribute for XML representation? */ (const nc_type nco_typ); /* I [enm] netCDF type */ void nco_dfl_case_fmt_xtn_err /* [fnc] Print error and exit for illegal switch(nco_fmt_xtn) case */ (void); const char * /* O [sng] JSON file type */ jsn_fmt_xtn_nm /* [fnc] Return string describing JSON filetype */ (const int fl_fmt_xtn); /* I [enm] Extended filetype */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_PRN_H */ ./nco-4.4.2/src/nco/nco_cnv_csm.c0000644000674300045400000004647312301031277015770 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnv_csm.c,v 1.111 2014/02/19 04:27:43 zender Exp $ */ /* Purpose: CCM/CCSM/CF conventions */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_cnv_csm.h" /* CCM/CCSM/CF conventions */ nco_bool /* O [flg] File obeys CCM/CCSM/CF conventions */ nco_cnv_ccm_ccsm_cf_inq /* O [fnc] Check if file obeys CCM/CCSM/CF conventions */ (const int nc_id) /* I [id] netCDF file ID */ { /* Purpose: Check if file adheres to CCM/CCSM/CF history tape format */ nco_bool CNV_CCM_CCSM_CF=False; char *att_val; char *cnv_sng=NULL_CEWI; /* netCDF standard is uppercase Conventions, though some models user lowercase */ char cnv_sng_UC[]="Conventions"; /* Unidata standard string (uppercase) */ char cnv_sng_LC[]="conventions"; /* Unidata non-standard string (lowercase) */ int rcd; /* [rcd] Return code */ long att_sz; nc_type att_typ; /* Look for signature of a CCM/CCSM/CF-format file */ cnv_sng=cnv_sng_UC; rcd=nco_inq_att_flg(nc_id,NC_GLOBAL,cnv_sng,&att_typ,&att_sz); if(rcd != NC_NOERR){ /* Re-try with lowercase string because some models, e.g., CLM, user lowercase "conventions" */ cnv_sng=cnv_sng_LC; rcd=nco_inq_att_flg(nc_id,NC_GLOBAL,cnv_sng,&att_typ,&att_sz); } /* endif lowercase */ if(rcd == NC_NOERR && att_typ == NC_CHAR){ /* Add one for NUL byte */ att_val=(char *)nco_malloc(att_sz*nco_typ_lng(att_typ)+1); (void)nco_get_att(nc_id,NC_GLOBAL,cnv_sng,att_val,att_typ); /* NUL-terminate convention attribute before using strcmp() */ att_val[att_sz]='\0'; /* CCM3, CCSM1 conventions */ if(strstr(att_val,"NCAR-CSM")) CNV_CCM_CCSM_CF=True; /* Backwards compatibility */ /* Climate-Forecast conventions */ if(strstr(att_val,"CF-1.")) CNV_CCM_CCSM_CF=True; /* NB: Not fully implemented TODO nco145 */ /* As of 20060514, CLM 3.0 uses CF1.0 not CF-1.0 (CAM gets it right) */ if(strstr(att_val,"CF1.")) CNV_CCM_CCSM_CF=True; /* NB: Not fully implemented TODO nco145 */ if(CNV_CCM_CCSM_CF && nco_dbg_lvl_get() >= nco_dbg_std){ (void)fprintf(stderr,"%s: CONVENTION File \"%s\" attribute is \"%s\"\n",nco_prg_nm_get(),cnv_sng,att_val); if(cnv_sng == cnv_sng_LC) (void)fprintf(stderr,"%s: WARNING: This file uses a non-standard attribute (\"%s\") to indicate the netCDF convention. The correct attribute is \"%s\".\n",nco_prg_nm_get(),cnv_sng_LC,cnv_sng_UC); /* Only warn in arithmetic operators where conventions change behavior */ if(nco_dbg_lvl_get() >= nco_dbg_fl && nco_is_rth_opr(nco_prg_id_get())) (void)fprintf(stderr,"%s: INFO NCO has a unified (though incomplete) treatment of many related (official and unoffical) conventions including the older CCM and CCSM and newer CF conventions. To adhere to these conventions, NCO implements variable-specific exceptions in certain operators, e.g., ncbo will not subtract variables named \"date\" or \"gw\", and many operators will always leave coordinate variables unchanged. The full list of exceptions is in the manual http://nco.sf.net/nco.html#CF\n",nco_prg_nm_get()); } /* endif dbg */ att_val=(char *)nco_free(att_val); } /* endif */ return CNV_CCM_CCSM_CF; } /* end nco_cnv_ccm_ccsm_cf_inq */ void nco_cnv_ccm_ccsm_cf_date /* [fnc] Fix date variable in averaged CCM/CCSM/CF files */ (const int nc_id, /* I [id] netCDF file ID */ X_CST_PTR_CST_PTR_Y(var_sct,var), /* I/O [sct] Variables in output file */ const int nbr_var) /* I [nbr] Number of variables in list */ { /* Purpose: Fix date variable in averaged CCM/CCSM/CF files */ char wrn_sng[1000]; int date_idx; int idx; int rcd=NC_NOERR; /* [rcd] Return code */ int time_idx; int nbdate_id; nco_int day; nco_int date; nco_int nbdate; (void)sprintf(wrn_sng,"Most, but not all, CCM/CCSM/CF files which are in CCM format contain the fields \"nbdate\", \"time\", and \"date\". When the \"date\" field is present but either \"nbdate\" or \"time\" is missing, then %s is unable to construct a meaningful average \"date\" to store in the output file. Therefore the \"date\" variable in your output file may be meaningless.\n",nco_prg_nm_get()); /* Find date variable (NC_INT: current date as 6 digit integer (YYMMDD)) */ for(idx=0;idxnm,"date")) break; } /* end loop over idx */ if(idx == nbr_var) return; else date_idx=idx; // if(var[date_idx]->type != NC_INT) return; /* 20101026 TODO nco998 problem is that "date" type is NC_DOUBLE here */ /* Find scalar nbdate variable (NC_INT: base date date as 6 digit integer (YYMMDD)) */ rcd=nco_inq_varid_flg(nc_id,"nbdate",&nbdate_id); if(rcd != NC_NOERR){ (void)fprintf(stderr,"%s: WARNING CCM/CCSM/CF convention file output variable list contains \"date\" but not \"nbdate\"\n",nco_prg_nm_get()); (void)fprintf(stderr,"%s: %s",nco_prg_nm_get(),wrn_sng); return; } /* endif */ { /* begin potential OpenMP critical */ /* Block is critical/thread-safe for identical/distinct in_id's */ (void)nco_get_var1(nc_id,nbdate_id,0L,&nbdate,NC_INT); } /* end potential OpenMP critical */ /* Find time variable (NC_DOUBLE: current day since nbdate) */ for(idx=0;idxnm,"time")) break; } /* end loop over idx */ if(idx == nbr_var){ (void)fprintf(stderr,"%s: WARNING CCM/CCSM/CF convention file output variable list contains \"date\" and \"nbdate\" yet lacks \"time\"\n",nco_prg_nm_get()); (void)fprintf(stderr,"%s: %s",nco_prg_nm_get(),wrn_sng); return; }else{ time_idx=idx; } /* endif */ /* Assign current day to averaged day number */ day=(nco_int)(var[time_idx]->val.dp[0]); /* Recompute date variable based on new (averaged) day number */ date=nco_newdate(nbdate,day); if(var[date_idx]->type == NC_INT){ if(!var[date_idx]->val.ip) return; else var[date_idx]->val.ip[0]=date; }else if(var[date_idx]->type == NC_DOUBLE){ if(!var[date_idx]->val.dp) return; else var[date_idx]->val.dp[0]=date; }else{ (void)fprintf(stderr,"%s: WARNING CCM/CCSM/CF convention file output variable \"date\" is not NC_INT or NC_DOUBLE\n",nco_prg_nm_get()); } /* end else */ return; /* 20050109: fxm added return to void function to squelch erroneous gcc-3.4.2 warning */ } /* end nco_cnv_ccm_ccsm_cf_date */ nm_id_sct * /* O [sct] Extraction list */ nco_cnv_cf_crd_add /* [fnc] Add coordinates defined by CF convention */ (const int nc_id, /* I netCDF file ID */ nm_id_sct *xtr_lst, /* I/O current extraction list (destroyed) */ int * const xtr_nbr) /* I/O number of variables in current extraction list */ { /* Purpose: Detect coordinates specified by CF convention and add them to extraction list http://www.cgd.ucar.edu/cms/eaton/cf-metadata/CF-1.0.html#grid_ex2 */ const char dlm_sng[]=" "; /* [sng] Delimiter string */ const char fnc_nm[]="nco_cnv_cf_crd_add()"; /* [sng] Function name */ char **crd_lst; /* [sng] 1D array of list elements */ char *att_val; char att_nm[NC_MAX_NAME]; int crd_id; int idx_att; int idx_crd; int idx_var; int idx_var2; int nbr_att; int nbr_crd; /* [nbr] Number of coordinates specified in "coordinates" attribute */ int rcd=NC_NOERR; /* [rcd] Return code */ int var_id; long att_sz; nc_type att_typ; /* ...for each variable in extraction list... */ for(idx_var=0;idx_var<*xtr_nbr;idx_var++){ /* Eschew indirection */ var_id=xtr_lst[idx_var].id; /* Find number of attributes */ (void)nco_inq_varnatts(nc_id,var_id,&nbr_att); for(idx_att=0;idx_att 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names */ /* using nco_lst_prs_sgl_2D() and not nco_lst_prs_2D */ /* see TODO 944 */ crd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_crd); /* ...for each coordinate in "coordinates" attribute... */ for(idx_crd=0;idx_crdnm_fll,trv_tbl); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Initialize attribute-edit structure for this variable */ aed.var_nm=var_trv->nm; aed.id=var_out_id; aed.sz=0L; dmn_nbr_mch=0; /* Format: blank-separated phrases of form "dmn1[, dmn2[...]]: op_typ" */ for(dmn_idx_var=0;dmn_idx_varnbr_dmn;dmn_idx_var++){ for(dmn_idx_rdc=0;dmn_idx_rdcvar_dmn[dmn_idx_var].dmn_nm,dmn_rdc[dmn_idx_rdc]->nm)){ /* Add length of each matching dimension to accumulating attribute size */ aed.sz+=strlen(dmn_rdc[dmn_idx_rdc]->nm); dmn_mch[dmn_nbr_mch++]=dmn_idx_rdc; } /* !match */ } /* dmn_idx_rdc */ } /* dmn_idx_var */ assert(dmn_nbr_mch != 0); /* Preserve rule to always return averages (never extrema or other statistics) of coordinates */ if(var[var_idx]->is_crd_var) nco_op_typ_lcl=nco_op_avg; else nco_op_typ_lcl=nco_op_typ; /* NUL-terminate before concatenation */ att_op_sng[0]='\0'; switch(nco_op_typ_lcl){ /* Next four operations are defined in CF Conventions */ case nco_op_avg: strcpy(att_op_sng,"mean"); break; case nco_op_min: strcpy(att_op_sng,"minimum"); break; case nco_op_max: strcpy(att_op_sng,"maximum"); break; case nco_op_ttl: strcpy(att_op_sng,"sum"); break; /* Remaining operations are supported by NCO yet are not in CF Conventions */ case nco_op_sqravg: strcpy(att_op_sng,"sqravg"); break; /* Square of mean */ case nco_op_avgsqr: strcpy(att_op_sng,"avgsqr"); break; /* Mean of sum of squares */ case nco_op_sqrt: strcpy(att_op_sng,"sqrt"); break; /* Square root of mean */ case nco_op_rms: strcpy(att_op_sng,"rms"); break; /* Root-mean-square (normalized by N) */ case nco_op_rmssdn: strcpy(att_op_sng,"rmssdn"); break; /* Root-mean square normalized by N-1 */ case nco_op_nil: /* nco_op_nil, Undefined operation type */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: DEBUG %s reports variable %s cell_method not implemented for operation %d\n",nco_prg_nm_get(),fnc_nm,var_trv->nm_fll,nco_op_typ); continue; } /* End switch */ /* Initialize to size of ": " plus length of operation string */ aed.sz+=2L+strlen(att_op_sng); /* Add room for commas and spaces, i.e., "dmn1, dmn2, dmn3" */ if(dmn_nbr_mch > 1) aed.sz+=2*(dmn_nbr_mch-1); /* Add room for NUL-terminator */ aed.val.cp=(char *)nco_malloc((aed.sz+1L)*sizeof(char)); aed.val.cp[0]='\0'; /* Build single string by concatenating known matches */ for(int dmn_idx_mch=0;dmn_idx_mchnm); if(dmn_idx_mch=dmn_nbr_mch */ (void)strcat(aed.val.cp,": "); (void)strcat(aed.val.cp,att_op_sng); /* Does variable already have "cell_methods" attribute? */ rcd=nco_inq_att_flg(grp_out_id,var_out_id,"cell_methods",&att_typ,(long *)NULL); if(rcd == NC_NOERR){ aed.mode=aed_append; if(att_typ == NC_STRING) (void)fprintf(stderr,"%s: WARNING %s reports existing cell_methods attribute for variable %s is type NC_STRING. Unpredictable results...\n",nco_prg_nm_get(),fnc_nm,aed.var_nm); if(att_typ != NC_STRING && att_typ != NC_CHAR) (void)fprintf(stderr,"%s: WARNING %s reports existing cell_methods attribute for variable %s is type %s. Unpredictable results...\n",nco_prg_nm_get(),fnc_nm,aed.var_nm,nco_typ_sng(att_typ)); /* Insert space between existing attribute and appended attribute */ att_val_cpy=(char *)strdup(aed.val.cp); aed.val.cp=(char *)nco_realloc(aed.val.cp,(++aed.sz)*sizeof(char)); aed.val.cp[0]=' '; aed.val.cp[1]='\0'; (void)strcat(aed.val.cp,att_val_cpy); if(att_val_cpy) att_val_cpy=(char *)nco_free(att_val_cpy); }else{ aed.mode=aed_create; } /* endif attribute exists */ /* Edit attribute */ (void)nco_aed_prc(grp_out_id,var_out_id,aed); if(aed.val.cp) aed.val.cp=(char *)nco_free(aed.val.cp); } /* var_idx>=var_nbr */ if(aed.att_nm) aed.att_nm=(char *)nco_free(aed.att_nm); if(dmn_mch) dmn_mch=(int *)nco_free(dmn_mch); return NC_NOERR; } /* end nco_cnv_cf_cll_mth_add() */ int nco_rdc_sng_to_op_typ /* [fnc] Convert operation string to integer */ (const char * const att_op_sng) /* [fnc] Operation string */ { if(!strcmp(att_op_sng,"mean")) return nco_op_avg; if(!strcmp(att_op_sng,"minimum")) return nco_op_min; if(!strcmp(att_op_sng,"maximum")) return nco_op_max; if(!strcmp(att_op_sng,"sum")) return nco_op_ttl; if(!strcmp(att_op_sng,"sqravg")) return nco_op_sqravg; if(!strcmp(att_op_sng,"avgsqr")) return nco_op_avgsqr; if(!strcmp(att_op_sng,"sqrt")) return nco_op_sqrt; if(!strcmp(att_op_sng,"rms")) return nco_op_rms; if(!strcmp(att_op_sng,"rmssdn")) return nco_op_rmssdn; return False; /* Statement should not be reached */ } /* nco_rdc_sng_to_op_typ() */ const char * /* O [sng] String describing operation type */ nco_op_typ_to_rdc_sng /* [fnc] Convert operation type to string */ (const int nco_op_typ) /* I [enm] Operation type */ { switch(nco_op_typ){ case nco_op_avg: return "mean"; case nco_op_min: return "minimum"; case nco_op_max: return "maximum"; case nco_op_ttl: return "sum"; case nco_op_sqravg: return "sqravg"; case nco_op_avgsqr: return "avgsqr"; case nco_op_sqrt: return "sqrt"; case nco_op_rms: return "rms"; case nco_op_rmssdn: return "rmssdn"; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return False; /* Statement should not be reached */ } /* nco_op_typ_to_rdc_sng() */ ./nco-4.4.2/src/nco/nco_pck.c0000644000674300045400000016551712260451232015117 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_pck.c,v 1.98 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: NCO utilities for packing and unpacking variables */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_pck.h" /* Packing and unpacking variables */ /* Notes on packing/unpacking: Routines in this file must be used in correct order: nco_pck_dsk_inq(): called first, e.g., in nco_var_fll(), before var_prc copied to var_prc_out nco_var_upk(): called in data retrieval routine, e.g., in nco_var_get() nco_var_pck(): called just before writing output file, e.g., in main() Bookkeeping hassle is keeping flags in var_prc synchronized with flags in var_prc_out From netCDF User's Guide: scale_factor: If present for a variable, the data are to be multiplied by this factor after the data are read by the application that accesses the data add_offset: If present for a variable, this number is added to the data after the data are read by the application. If both scale_factor and add_offset attributes are present, the data are first scaled before the offset is added. When scale_factor and add_offset are used for packing, the associated variable (containing the packed data) is typically of type byte or short, whereas the unpacked values are intended to be of type float or double. Attribute's scale_factor and add_offset should both be of type intended for the unpacked data, e.g., float or double. 20101007 Dave Allured says that Unidata says this in NetCDF Best Practices: "The _FillValue attribute should have the same data type as the variable it describes. If the variable is packed using scale_factor and add_offset attributes, the _FillValue attribute should have the data type of the packed data." http://www.unidata.ucar.edu/software/netcdf/docs/BestPractices.html#Missing%20Data%20Values CF conventions say about the same thing. If there is a mismatch between the attribute type and the data type, or if an incorrect value was stored in the _FillValue attribute, then manual intervention is needed. However note that storing -999 in an attribute of type short vs. integer is not much of a problem, because the two are are numerically identical. The important question in this case is whether ncra has an automatic method to exclude missing values from being transformed by averaging, in the face of a packed variable. If so, how is it done, or where in the documentation is it described. */ const char * /* O [sng] Packing map string */ nco_pck_map_sng_get /* [fnc] Convert packing map enum to string */ (const int nco_pck_map) /* I [enm] Packing map */ { /* Purpose: Convert packing map enum to string */ switch(nco_pck_map){ case nco_pck_map_nil: return "nil"; case nco_pck_map_hgh_sht: return "hgh_sht"; case nco_pck_map_hgh_chr: return "hgh_chr"; case nco_pck_map_hgh_byt: return "hgh_byt"; case nco_pck_map_nxt_lsr: return "nxt_lsr"; case nco_pck_map_flt_sht: return "flt_sht"; case nco_pck_map_flt_chr: return "flt_chr"; case nco_pck_map_flt_byt: return "flt_byt"; default: nco_dfl_case_pck_map_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_pck_map_sng_get() */ const char * /* O [sng] Packing policy string */ nco_pck_plc_sng_get /* [fnc] Convert packing policy enum to string */ (const int nco_pck_plc) /* I [enm] Packing policy */ { /* Purpose: Convert packing policy enum to string */ switch(nco_pck_plc){ case nco_pck_plc_nil: return "nil"; case nco_pck_plc_all_xst_att: return "all_xst"; case nco_pck_plc_all_new_att: return "all_new"; case nco_pck_plc_xst_new_att: return "xst_new"; case nco_pck_plc_upk: return "upk"; default: nco_dfl_case_pck_plc_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return (char *)NULL; } /* end nco_pck_plc_sng_get() */ void nco_dfl_case_pck_map_err(void) /* [fnc] Print error and exit for illegal switch(pck_map) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(pck_map) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_pck_map_err()"; (void)fprintf(stdout,"%s: ERROR switch(pck_map) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(pck_map) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_pck_map_err() */ void nco_dfl_case_pck_plc_err(void) /* [fnc] Print error and exit for illegal switch(pck_plc) case */ { /* Purpose: Convenience routine for printing error and exiting when switch(pck_plc) statement receives an illegal default case Placing this in its own routine also has the virtue of saving many lines of code since this function is used in many many switch() statements. */ const char fnc_nm[]="nco_dfl_case_pck_plc_err()"; (void)fprintf(stdout,"%s: ERROR switch(pck_plc) statement fell through to default case, which is unsafe. This catch-all error handler ensures all switch(pck_plc) statements are fully enumerated. Exiting...\n",fnc_nm); nco_err_exit(0,fnc_nm); } /* end nco_dfl_case_pck_plc_err() */ nco_bool /* O [flg] NCO will attempt to pack variable */ nco_is_packable /* [fnc] Will NCO attempt to pack variable? */ (const nc_type nc_typ_in) /* I [enm] Type of input variable */ { /* Purpose: Determine whether NCO should attempt to pack a given type Packing certain variable types is not recommended, e.g., packing NC_CHAR and NC_BYTE makes no sense, because precision would needlessly be lost. Routine should be consistent with nco_pck_plc_typ_get() NB: Routine is deprecated in favor of more flexible nco_pck_plc_typ_get() */ const char fnc_nm[]="nco_is_packable()"; /* [sng] Function name */ (void)fprintf(stdout,"%s: ERROR deprecated routine %s should not be called\n",nco_prg_nm_get(),fnc_nm); nco_exit(EXIT_FAILURE); switch(nc_typ_in){ case NC_FLOAT: case NC_DOUBLE: case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: return True; break; case NC_SHORT: case NC_USHORT: case NC_CHAR: case NC_BYTE: case NC_UBYTE: case NC_STRING: return False; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Some compilers, e.g., SGI cc, need return statement to end non-void functions */ return False; } /* end nco_is_packable() */ int /* O [enm] Packing map */ nco_pck_map_get /* [fnc] Convert user-specified packing map to key */ (const char *nco_pck_map_sng) /* [sng] User-specified packing map */ { /* Purpose: Process ncpdq '-P' command line argument Convert user-specified string to packing map Return nco_pck_map_nil by default */ const char fnc_nm[]="nco_pck_map_get()"; /* [sng] Function name */ char *nco_prg_nm; /* [sng] Program name */ nco_prg_nm=nco_prg_nm_get(); /* [sng] Program name */ if(nco_pck_map_sng == NULL){ (void)fprintf(stderr,"%s: ERROR %s reports empty user-specified packing map string %s\n",nco_prg_nm,fnc_nm,nco_pck_map_sng); nco_exit(EXIT_FAILURE); } /* endif */ if(!strcmp(nco_pck_map_sng,"hgh_sht")) return nco_pck_map_hgh_sht; if(!strcmp(nco_pck_map_sng,"pck_map_hgh_sht")) return nco_pck_map_hgh_sht; if(!strcmp(nco_pck_map_sng,"hgh_chr")) return nco_pck_map_hgh_chr; if(!strcmp(nco_pck_map_sng,"pck_map_hgh_chr")) return nco_pck_map_hgh_chr; if(!strcmp(nco_pck_map_sng,"hgh_byt")) return nco_pck_map_hgh_byt; if(!strcmp(nco_pck_map_sng,"pck_map_hgh_byt")) return nco_pck_map_hgh_byt; if(!strcmp(nco_pck_map_sng,"nxt_lsr")) return nco_pck_map_nxt_lsr; if(!strcmp(nco_pck_map_sng,"pck_map_nxt_lsr")) return nco_pck_map_nxt_lsr; if(!strcmp(nco_pck_map_sng,"flt_sht")) return nco_pck_map_flt_sht; if(!strcmp(nco_pck_map_sng,"pck_map_flt_sht")) return nco_pck_map_flt_sht; if(!strcmp(nco_pck_map_sng,"flt_chr")) return nco_pck_map_flt_chr; if(!strcmp(nco_pck_map_sng,"pck_map_flt_chr")) return nco_pck_map_flt_chr; if(!strcmp(nco_pck_map_sng,"flt_byt")) return nco_pck_map_flt_byt; if(!strcmp(nco_pck_map_sng,"pck_map_flt_byt")) return nco_pck_map_flt_byt; (void)fprintf(stderr,"%s: ERROR %s reports unknown user-specified packing map %s\n",nco_prg_nm_get(),fnc_nm,nco_pck_map_sng); nco_exit(EXIT_FAILURE); return nco_pck_map_nil; /* Statement should not be reached */ } /* end nco_pck_map_get() */ int /* O [enm] Packing policy */ nco_pck_plc_get /* [fnc] Convert user-specified packing policy to key */ (const char *nco_pck_plc_sng) /* [sng] User-specified packing policy */ { /* Purpose: Process ncpdq '-P' command line argument Convert user-specified string to packing operation type Return nco_pck_plc_nil by default */ const char fnc_nm[]="nco_pck_plc_get()"; /* [sng] Function name */ char *nco_prg_nm; /* [sng] Program name */ nco_prg_nm=nco_prg_nm_get(); /* [sng] Program name */ if(nco_pck_plc_sng == NULL){ if(strstr(nco_prg_nm,"ncpdq")){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s reports %s invoked without explicit packing or dimension permutation options. Defaulting to packing policy \"all_new\".\n",nco_prg_nm,fnc_nm,nco_prg_nm); return nco_pck_plc_all_new_att; } /* endif */ if(strstr(nco_prg_nm,"ncpack")) return nco_pck_plc_all_new_att; if(strstr(nco_prg_nm,"ncunpack")) return nco_pck_plc_upk; (void)fprintf(stderr,"%s: ERROR %s reports empty user-specified packing string in conjunction with unknown or ambiguous executable name %s\n",nco_prg_nm,fnc_nm,nco_prg_nm); nco_exit(EXIT_FAILURE); } /* endif */ if(!strcmp(nco_pck_plc_sng,"all_xst")) return nco_pck_plc_all_xst_att; if(!strcmp(nco_pck_plc_sng,"pck_all_xst_att")) return nco_pck_plc_all_xst_att; if(!strcmp(nco_pck_plc_sng,"all_new")) return nco_pck_plc_all_new_att; if(!strcmp(nco_pck_plc_sng,"pck_all_new_att")) return nco_pck_plc_all_new_att; if(!strcmp(nco_pck_plc_sng,"xst_new")) return nco_pck_plc_xst_new_att; if(!strcmp(nco_pck_plc_sng,"pck_xst_new_att")) return nco_pck_plc_xst_new_att; if(!strcmp(nco_pck_plc_sng,"upk")) return nco_pck_plc_upk; if(!strcmp(nco_pck_plc_sng,"unpack")) return nco_pck_plc_upk; if(!strcmp(nco_pck_plc_sng,"pck_upk")) return nco_pck_plc_upk; (void)fprintf(stderr,"%s: ERROR %s reports unknown user-specified packing policy %s\n",nco_prg_nm_get(),fnc_nm,nco_pck_plc_sng); nco_exit(EXIT_FAILURE); return nco_pck_plc_nil; /* Statement should not be reached */ } /* end nco_pck_plc_get() */ nco_bool /* O [flg] Packing policy allows packing nc_typ_in */ nco_pck_plc_typ_get /* [fnc] Determine type, if any, to pack input type to */ (const int nco_pck_map, /* I [enm] Packing map */ const nc_type nc_typ_in, /* I [enm] Type of input variable */ nc_type *nc_typ_pck_out) /* O [enm] Type to pack variable to */ { /* Purpose: Determine type, if any, to pack input type to Routine enforces policy specified by nco_pck_map Replacement for simple deprecated routine nco_is_packable() There are two cases: 1. nco_pck_map allows packing nc_typ_in: Routine returns true and sets nc_typ_pck_out accordingly 2. nco_pck_map does not allow packing nc_typ_in: Routine returns false and sets nc_typ_pck_out=nc_typ_in In both cases, nc_typ_pck_out is only set if it is non-NULL */ const char fnc_nm[]="nco_pck_plc_typ_get()"; /* [sng] Function name */ nco_bool nco_pck_plc_alw; /* O [flg] Packing policy allows packing nc_typ_in */ nc_type nc_typ_pck_out_tmp; /* O [enm] Type to pack variable to */ /* Initialize output type to NAT and pack allow to False to help catch errors */ nc_typ_pck_out_tmp=NC_NAT; nco_pck_plc_alw=False; switch(nco_pck_map){ case nco_pck_map_nil: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; case nco_pck_map_hgh_sht: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: nc_typ_pck_out_tmp=NC_SHORT; nco_pck_plc_alw=True; break; case NC_SHORT: case NC_USHORT: case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_hgh_chr: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: case NC_SHORT: case NC_USHORT: nc_typ_pck_out_tmp=NC_CHAR; nco_pck_plc_alw=True; break; case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_hgh_byt: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: case NC_SHORT: case NC_USHORT: nc_typ_pck_out_tmp=NC_BYTE; nco_pck_plc_alw=True; break; case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_nxt_lsr: switch(nc_typ_in){ case NC_DOUBLE: case NC_INT64: case NC_UINT64: nc_typ_pck_out_tmp=NC_INT; nco_pck_plc_alw=True; break; case NC_FLOAT: case NC_INT: case NC_UINT: nc_typ_pck_out_tmp=NC_SHORT; nco_pck_plc_alw=True; break; case NC_SHORT: case NC_USHORT: nc_typ_pck_out_tmp=NC_BYTE; nco_pck_plc_alw=True; break; case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_flt_sht: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: nc_typ_pck_out_tmp=NC_SHORT; nco_pck_plc_alw=True; break; case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: case NC_SHORT: case NC_USHORT: case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_flt_chr: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: nc_typ_pck_out_tmp=NC_CHAR; nco_pck_plc_alw=True; break; case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: case NC_SHORT: case NC_USHORT: case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; case nco_pck_map_flt_byt: switch(nc_typ_in){ case NC_DOUBLE: case NC_FLOAT: nc_typ_pck_out_tmp=NC_BYTE; nco_pck_plc_alw=True; break; case NC_INT64: case NC_UINT64: case NC_INT: case NC_UINT: case NC_SHORT: case NC_USHORT: case NC_BYTE: case NC_UBYTE: case NC_CHAR: case NC_STRING: nc_typ_pck_out_tmp=nc_typ_in; nco_pck_plc_alw=False; break; default: nco_dfl_case_nc_type_err(); break; } /* end nc_type switch */ break; default: (void)fprintf(stdout,"%s: ERROR %s reports switch(nco_pck_map) statement fell through to default case\n",nco_prg_nm_get(),fnc_nm); nco_err_exit(0,fnc_nm); break; } /* end nco_pck_map switch */ /* Only fill in nc_typ_pck_out if it is non-NULL */ if(nc_typ_pck_out) *nc_typ_pck_out=nc_typ_pck_out_tmp; return nco_pck_plc_alw; /* O [flg] Packing policy allows packing nc_typ_in */ } /* end nco_pck_plc_typ_get() */ nco_bool /* O [flg] Variable is packed on disk */ nco_pck_dsk_inq /* [fnc] Check whether variable is packed on disk */ (const int nc_id, /* I [idx] netCDF file ID */ var_sct * const var) /* I/O [sct] Variable */ { /* Purpose: Check whether variable is packed on disk and set variable members pck_dsk, has_scl_fct, has_add_fst, and typ_upk accordingly nco_pck_dsk_inq() should be called early in application, e.g., in nco_var_fll() Call nco_pck_dsk_inq() before copying input list to output list Multi-file operators which handle packing must call this routine prior to each read of a variable, in case that variable has been unpacked. NB: See also nco_inq_var_packing(), a light-overhead alternative to nco_pck_dsk_inq() */ /* nces -O -D 3 -v pck ~/nco/data/in.nc ~/nco/data/foo.nc */ const char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ const char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ int rcd; /* [rcd] Return success code */ long add_fst_lng; /* [idx] Number of elements in add_offset attribute */ long scl_fct_lng; /* [idx] Number of elements in scale_factor attribute */ nc_type add_fst_typ; /* [idx] Type of add_offset attribute */ nc_type scl_fct_typ; /* [idx] Type of scale_factor attribute */ /* Set some defaults in variable structure for safety in case of early return Flags for variables without valid scaling information should appear same as flags for variables with _no_ scaling information Set has_scl_fct, has_add_fst in var_dfl_set() typ_upk: 1. is required by ncra nco_cnv_mss_val_typ() 2. depends on var->type and so should not be set in var_dfl_set() 3. is therefore set to default here */ var->typ_upk=var->type; /* [enm] Type of variable when unpacked (expanded) (in memory) */ /* Vet scale_factor */ rcd=nco_inq_att_flg(nc_id,var->id,scl_fct_sng,&scl_fct_typ,&scl_fct_lng); if(rcd != NC_ENOTATT){ if(scl_fct_typ == NC_BYTE || scl_fct_typ == NC_CHAR){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING nco_pck_dsk_inq() reports scale_factor for %s is NC_BYTE or NC_CHAR. Will not attempt to unpack using scale_factor.\n",nco_prg_nm_get(),var->nm); return False; } /* endif */ if(scl_fct_lng != 1){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING nco_pck_dsk_inq() reports %s has scale_factor of length %li. Will not attempt to unpack using scale_factor\n",nco_prg_nm_get(),var->nm,scl_fct_lng); return False; } /* endif */ var->has_scl_fct=True; /* [flg] Valid scale_factor attribute exists */ var->typ_upk=scl_fct_typ; /* [enm] Type of variable when unpacked (expanded) (in memory) */ } /* endif */ /* Vet add_offset */ rcd=nco_inq_att_flg(nc_id,var->id,add_fst_sng,&add_fst_typ,&add_fst_lng); if(rcd != NC_ENOTATT){ if(add_fst_typ == NC_BYTE || add_fst_typ == NC_CHAR){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING nco_pck_dsk_inq() reports add_offset for %s is NC_BYTE or NC_CHAR. Will not attempt to unpack using add_offset.\n",nco_prg_nm_get(),var->nm); return False; } /* endif */ if(add_fst_lng != 1){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING nco_pck_dsk_inq() reports %s has add_offset of length %li. Will not attempt to unpack.\n",nco_prg_nm_get(),var->nm,add_fst_lng); return False; } /* endif */ var->has_add_fst=True; /* [flg] Valid add_offset attribute exists */ var->typ_upk=add_fst_typ; /* [enm] Type of variable when unpacked (expanded) (in memory) */ } /* endif */ if(var->has_scl_fct && var->has_add_fst){ if(scl_fct_typ != add_fst_typ){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING nco_pck_dsk_inq() reports type of scale_factor does not equal type of add_offset. Will not attempt to unpack.\n",nco_prg_nm_get()); return False; } /* endif */ } /* endif */ if(var->has_scl_fct || var->has_add_fst){ /* Variable is considered packed iff either or both valid scale_factor or add_offset exist */ var->pck_dsk=True; /* [flg] Variable is packed on disk */ /* If variable is packed on disk and is in memory then variable is packed in memory */ var->pck_ram=True; /* [flg] Variable is packed in memory */ var->typ_upk=(var->has_scl_fct) ? scl_fct_typ : add_fst_typ; /* [enm] Type of variable when unpacked (expanded) (in memory) */ if(nco_is_rth_opr(nco_prg_id_get()) && nco_dbg_lvl_get() >= nco_dbg_var){ (void)fprintf(stdout,"%s: PACKING Variable %s is type %s packed into type %s\n",nco_prg_nm_get(),var->nm,nco_typ_sng(var->typ_upk),nco_typ_sng(var->typ_dsk)); (void)fprintf(stdout,"%s: DEBUG Packed variables processed by all arithmetic operators are unpacked automatically, and then stored unpacked in the output file. If you wish to repack them in the output file, use, e.g., ncap2 -O -s \"foo=pack(foo);\" out.nc out.nc. If you wish to pack all variables in a file, use, e.g., ncpdq -P all_new in.nc out.nc.\n",nco_prg_nm_get()); } /* endif print packing information */ }else{ /* Variable is not packed since neither scale factor nor add_offset exist Insert hooks which depend on variable not being packed here Currently this is no-op */ ; } /* end else */ return var->pck_dsk; /* [flg] Variable is packed on disk (valid scale_factor, add_offset, or both attributes exist) */ } /* end nco_pck_dsk_inq() */ void nco_pck_mtd /* [fnc] Alter metadata according to packing specification */ (const var_sct * const var_in, /* I [ptr] Variable in original disk state */ var_sct * const var_out, /* I/O [ptr] Variable whose metadata will be altered */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc) /* I [enm] Packing policy */ { /* Purpose: Alter metadata according to packing specification */ const char fnc_nm[]="nco_pck_mtd()"; /* [sng] Function name */ nc_type nc_typ_pck_out; /* [enm] Type to pack to */ switch(nco_pck_plc){ case nco_pck_plc_all_xst_att: /* If variable is already packed do nothing otherwise pack to default type */ if(var_in->pck_ram){ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: DEBUG %s keeping existing packing parameters and type (%s) for %s\n",nco_prg_nm_get(),fnc_nm,nco_typ_sng(var_in->type),var_in->nm); }else{ goto var_upk_try_to_pck; } /* endif */ break; case nco_pck_plc_xst_new_att: /* If variable is already packed then re-pack otherwise do nothing */ if(var_in->pck_ram){ goto var_pck_try_to_rpk; }else{ /* Variable is not packed so do nothing */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: INFO %s leaving variable %s of type %s as unpacked\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_out->typ_upk)); } /* endelse */ break; case nco_pck_plc_all_new_att: if(var_in->pck_ram){ goto var_pck_try_to_rpk; }else{ goto var_upk_try_to_pck; } /* endif */ break; case nco_pck_plc_upk: var_out->type=var_in->typ_upk; if(nco_dbg_lvl_get() >= nco_dbg_sbr){ if(var_in->pck_ram) (void)fprintf(stdout,"%s: DEBUG %s will unpack variable %s from %s to %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_in->type),nco_typ_sng(var_out->type)); else (void)fprintf(stdout,"%s: DEBUG %s variable %s is already unpacked and of type %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_in->type)); } /* endif dbg */ break; case nco_pck_plc_nil: default: nco_dfl_case_pck_plc_err(); break; } /* end case */ /* Return after finishing switch() statement and before falling through to code-saving goto branches */ return; var_upk_try_to_pck: /* end goto */ /* Variable is not yet packed---try to pack it */ if(nco_pck_plc_typ_get(nco_pck_map,var_in->type,&nc_typ_pck_out)){ var_out->type=nc_typ_pck_out; if(nco_dbg_lvl_get() >= nco_dbg_sbr) (void)fprintf(stdout,"%s: DEBUG %s will pack variable %s from %s to %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_in->type),nco_typ_sng(var_out->type)); }else{ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: INFO %s packing policy %s with packing map %s does not allow packing variable %s of type %s, skipping...\n",nco_prg_nm_get(),fnc_nm,nco_pck_plc_sng_get(nco_pck_plc),nco_pck_map_sng_get(nco_pck_map),var_in->nm,nco_typ_sng(var_in->type)); } /* !nco_pck_plc_alw */ return; var_pck_try_to_rpk: /* end goto */ /* Variable is already packed---try to re-pack it Final packed variable type may differ from original */ if(nco_pck_plc_typ_get(nco_pck_map,var_in->typ_upk,&nc_typ_pck_out)){ var_out->type=nc_typ_pck_out; if(nco_dbg_lvl_get() >= nco_dbg_sbr) (void)fprintf(stdout,"%s: DEBUG %s will re-pack variable %s of expanded type %s from current packing (type %s) into new packing of type %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_in->typ_upk),nco_typ_sng(var_in->type),nco_typ_sng(var_out->type)); }else{ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: WARNING %s variable %s of expanded type %s is already packed into type %s and re-packing is requested but packing policy %s and packing map %s does not allow re-packing variables of type %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_in->typ_upk),nco_typ_sng(var_in->type),nco_pck_plc_sng_get(nco_pck_plc),nco_pck_map_sng_get(nco_pck_map),nco_typ_sng(var_in->typ_upk)); } /* !nco_pck_plc_alw */ return; } /* end nco_pck_mtd() */ void nco_pck_val /* [fnc] Pack variable according to packing specification */ (var_sct * const var_in, /* I [ptr] Variable in original disk state */ var_sct * var_out, /* I/O [ptr] Variable after packing/unpacking operation */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ aed_sct * const aed_lst_add_fst, /* O [enm] Attribute edit structure, add_offset */ aed_sct * const aed_lst_scl_fct) /* O [enm] Attribute edit structure, scale_factor */ { /* Purpose: Alter metadata according to packing specification */ const char fnc_nm[]="nco_pck_val()"; /* [sng] Function name */ nco_bool PCK_VAR_WITH_NEW_PCK_ATT=False; /* [flg] Insert new scale_factor and add_offset into lists */ nc_type typ_out; /* [enm] Type in output file */ /* typ_out contains type of variable defined in output file as defined by var_out->type which was set in var_pck_mtd() We will temporarily set var_out->type to RAM type of variable Packing routine will re-set var_out->type to typ_out if necessary */ typ_out=var_out->type; /* [enm] Type in output file */ switch(nco_pck_plc){ case nco_pck_plc_all_xst_att: /* nco_var_pck() expects to alter var_out->type itself, if necessary */ var_out->type=var_in->typ_dsk; if(var_in->pck_ram){ if(nco_dbg_lvl_get() >= nco_dbg_sbr) (void)fprintf(stdout,"%s: INFO %s keeping existing packing attributes for variable %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm); /* Warn if packing attribute values are in memory for pre-packed variables */ if(var_out->scl_fct.vp || var_out->add_fst.vp) (void)fprintf(stdout,"%s: WARNING %s reports variable %s has packing attribute values in memory. This is not supposed to happen through known code paths, but is not necessarily dangerous.\n",nco_prg_nm_get(),fnc_nm,var_in->nm); /* Remove dangling pointer, see explanation below */ var_in->val.vp=NULL; }else{ goto var_upk_try_to_pck; /* end goto */ } /* endif input variable was not packed */ break; case nco_pck_plc_xst_new_att: if(var_in->pck_ram){ nco_var_upk_swp(var_in,var_out); goto var_upk_try_to_pck; }else{ /* Remove dangling pointer, see explanation below */ var_in->val.vp=NULL; } /* endif */ break; case nco_pck_plc_all_new_att: if(var_in->pck_ram){ /* Variable is already packed---unpack it before re-packing it */ nco_var_upk_swp(var_in,var_out); }else{ /* nco_var_pck() expects to alter var_out->type itself, if necessary */ var_out->type=var_in->typ_dsk; } /* endif */ goto var_upk_try_to_pck; break; case nco_pck_plc_upk: /* Unpack if possible, otherwise remove dangling pointer (explanation below) */ if(var_in->pck_ram) nco_var_upk_swp(var_in,var_out); else var_in->val.vp=NULL; break; case nco_pck_plc_nil: default: nco_dfl_case_pck_plc_err(); break; } /* end case */ /* Ensure code goes to final block before falling through to next goto */ goto put_new_pck_att_in_lst; var_upk_try_to_pck: /* end goto */ /* Variable is not yet packed---try to pack it */ if(nco_pck_plc_typ_get(nco_pck_map,var_out->type,(nc_type *)NULL)){ if(nco_dbg_lvl_get() >= nco_dbg_sbr) (void)fprintf(stdout,"%s: INFO %s packing variable %s values from %s to %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_out->typ_upk),nco_typ_sng(typ_out)); var_out=nco_var_pck(var_out,typ_out,&PCK_VAR_WITH_NEW_PCK_ATT); }else{ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: INFO %s packing policy %s with packing map %s does not allow packing variable %s of type %s, skipping...\n",nco_prg_nm_get(),fnc_nm,nco_pck_plc_sng_get(nco_pck_plc),nco_pck_map_sng_get(nco_pck_map),var_in->nm,nco_typ_sng(var_out->typ_upk)); } /* !nco_pck_plc_alw */ /* Packing function nco_var_pck() usually free()'s var_out->val.vp Hence var_in->val.vp is left with a dangling pointer In ncpdq, var_in->val.vp and var_out->val.vp point to same buffer This reduces peak memory consumption by ~50%, but is dangerous */ var_in->val.vp=NULL; /* Ensure code goes to final block before falling through to next goto */ goto put_new_pck_att_in_lst; put_new_pck_att_in_lst: /* end goto */ /* Fill attribute edit structures Use values directly from variable structures rather than copying Attribute structure dynamic memory will be free()'d in nco_var_free() call */ if(PCK_VAR_WITH_NEW_PCK_ATT){ aed_lst_add_fst->var_nm=aed_lst_scl_fct->var_nm=var_out->nm; aed_lst_add_fst->id=aed_lst_scl_fct->id=var_out->id; aed_lst_add_fst->sz=aed_lst_scl_fct->sz=1L; aed_lst_add_fst->type=aed_lst_scl_fct->type=var_out->typ_upk; /* Packing generates at least one of scale_factor or add_offset, but not necessarily both. Delete pre-defined attributes for those which were not created */ if(var_out->has_add_fst) aed_lst_add_fst->mode=aed_overwrite; else aed_lst_add_fst->mode=aed_delete; if(var_out->has_scl_fct) aed_lst_scl_fct->mode=aed_overwrite; else aed_lst_scl_fct->mode=aed_delete; /* Insert values into attribute structures */ aed_lst_add_fst->val=var_out->add_fst; aed_lst_scl_fct->val=var_out->scl_fct; } /* endif */ } /* end nco_pck_val() */ var_sct * /* O [sct] Packed variable */ nco_put_var_pck /* [fnc] Pack variable in memory and write packing attributes to disk */ (const int out_id, /* I [id] netCDF output file ID */ var_sct *var, /* I/O [sct] Variable to be packed */ const int nco_pck_plc) /* [enm] Packing operation type */ { /* Purpose: Pack variable in memory and write packing attributes to disk NB: Routine is not complete, debugged, or currently used ncpdq breaks up writing packed variables into multiple tasks, i.e., ncpdq separates variable value writes from packing attribute value writes. This routine is intended to write a packed variable in one routine */ nco_bool PCK_VAR_WITH_NEW_PCK_ATT=False; /* [flg] Insert new scale_factor and add_offset into lists */ switch(nco_pck_plc){ case nco_pck_plc_all_xst_att: break; case nco_pck_plc_xst_new_att: break; case nco_pck_plc_all_new_att: break; case nco_pck_plc_upk: break; case nco_pck_plc_nil: default: nco_dfl_case_pck_plc_err(); break; } /* end switch */ /* Pack variable */ if(var->xrf->pck_dsk && !var->xrf->pck_ram) var=nco_var_pck(var,var->typ_pck,&PCK_VAR_WITH_NEW_PCK_ATT); /* Write/overwrite scale_factor and add_offset attributes */ if(var->pck_ram){ /* [flg] Variable is packed in memory */ if(var->has_scl_fct){ /* [flg] Valid scale_factor attribute exists */ (void)nco_put_att(out_id,var->id,"scale_factor",var->typ_upk,1,var->scl_fct.vp); } /* endif has_scl_fct */ if(var->has_add_fst){ /* [flg] Valid add_offset attribute exists */ (void)nco_put_att(out_id,var->id,"add_offset",var->typ_upk,1,var->add_fst.vp); } /* endif has_add_fst */ } /* endif pck_ram */ return var; } /* end nco_put_var_pck() */ var_sct * /* O [sct] Packed variable */ nco_var_pck /* [fnc] Pack variable in memory */ (var_sct *var, /* I/O [sct] Variable to be packed */ const nc_type nc_typ_pck, /* I [enm] Type of variable when packed (on disk). This should be same as typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ nco_bool *PCK_VAR_WITH_NEW_PCK_ATT) /* O [flg] Routine generated new scale_factor/add_offset */ { /* Purpose: Pack variable Routine is inverse of nco_var_upk(): nco_var_pck[nco_var_upk(var)]=var Currently routine outputs same variable structure as given on input In other words, output structure may be neglected as all changes are made to input structure. NB: Value buffer var->val.vp is usually free()'d here Variables in calling routine which point to var->val.vp will be left dangling */ nco_bool PURE_MSS_VAL_FLD=False; /* [flg] Field is pure missing_value, i.e., no valid values */ const char fnc_nm[]="nco_var_pck()"; /* [sng] Function name */ double scl_fct_dbl=double_CEWI; /* [sct] Double precision value of scale_factor */ double add_fst_dbl=double_CEWI; /* [sct] Double precision value of add_offset */ /* Set flag true once new scale_factor/add_offset generated */ *PCK_VAR_WITH_NEW_PCK_ATT=False; /* Return if variable in memory is currently packed and should not be re-packed */ if(var->pck_ram) return var; /* Routine should be called with variable already in memory */ if(var->val.vp == NULL) (void)fprintf(stdout,"%s: ERROR %s called with empty var->val.vp\n",nco_prg_nm_get(),fnc_nm); /* Packed type must be NC_BYTE, NC_CHAR, NC_SHORT, or NC_INT */ if(nc_typ_pck == NC_FLOAT || nc_typ_pck == NC_DOUBLE || nc_typ_pck == NC_UINT || nc_typ_pck == NC_USHORT || nc_typ_pck == NC_UBYTE || nc_typ_pck == NC_STRING){ (void)fprintf(stdout,"%s: ERROR %s called to pack variable %s with invalid packed type nc_typ_pck = %s\n",nco_prg_nm_get(),fnc_nm,var->nm,nco_typ_sng(nc_typ_pck)); nco_exit(EXIT_FAILURE); } /* endif */ /* Variable must be packable (usually NC_INT, NC_FLOAT, or NC_DOUBLE) Definition of "packable" determined by nco_pck_plc_typ_get() Prefer not to make nco_var_pck() rely directly on nco_pck_plc_typ_get() However, certain types are never packable */ if(var->type == NC_BYTE || var->type == NC_UBYTE || var->type == NC_CHAR || var->type == NC_STRING){ (void)fprintf(stdout,"%s: ERROR %s is asked to pack variable %s of type %s\n",nco_prg_nm_get(),fnc_nm,var->nm,nco_typ_sng(var->type)); nco_exit(EXIT_FAILURE); } /* endif */ if(True){ /* Keep in own scope for eventual functionalization of core packing algorithm */ /* Compute packing parameters to apply to var Linear packing in a nutshell: scale_factor = (max-min)/ndrv <--> (max-min)/scale_factor = ndrv <--> scale_factor*ndrv = max-min add_offset = 0.5*(min+max) pck = (upk-add_offset)/scale_factor = (upk-0.5*(min+max))*ndrv/(max-min) upk = scale_factor*pck + add_offset = (max-min)*pck/ndrv + 0.5*(min+max) where ndrv = number of discrete representable values for given type of packed variable and ndrv = 256 iff var->typ_pck == NC_CHAR ndrv = 256*256 iff var->typ_pck == NC_SHORT ndrv = 256*256*256*256 = 2^32 iff var->typ_pck == NC_INT */ const double max_mns_min_dbl_wrn=1.0e10; /* [frc] Threshold value for warning */ double mss_val_dbl; /* [ptr] Missing value of variable expressed in double precision */ double ndrv_dbl=double_CEWI; /* [frc] Double precision value of number of discrete representable values */ double max_mns_min_dbl; /* [frc] Maximum value minus minimum value */ ptr_unn ptr_unn_min; /* [ptr] Pointer union to minimum value of variable */ ptr_unn ptr_unn_max; /* [ptr] Pointer union to maximum value of variable */ ptr_unn ptr_unn_mss_val_dbl; /* [ptr] Pointer union to missing value of variable */ var_sct *min_var; /* [sct] Minimum value of variable */ var_sct *max_var; /* [sct] Maximum value of variable */ var_sct *max_var_dpl; /* [sct] Copy of Maximum value of variable */ var_sct *hlf_var; /* [sct] NCO variable for value 0.5 */ var_sct *zero_var; /* [sct] NCO variable for value 0.0 */ var_sct *ndrv_var; /* [sct] NCO variable for number of discrete representable values */ val_unn hlf_unn; /* [frc] Generic container for value 0.5 */ val_unn zero_unn; /* [frc] Generic container for value 0.0 */ val_unn ndrv_unn; /* [nbr] Generic container for number of discrete representable values */ /* Initialize data */ hlf_unn.d=0.5; /* Generic container for value 0.5 */ zero_unn.d=0.0; /* Generic container for value 0.0 */ /* Derive scalar values for scale_factor and add_offset */ var->scl_fct.vp=nco_free(var->scl_fct.vp); var->add_fst.vp=nco_free(var->add_fst.vp); var->scl_fct.vp=(void *)nco_malloc(nco_typ_lng(var->type)); var->add_fst.vp=(void *)nco_malloc(nco_typ_lng(var->type)); ptr_unn_min.vp=(void *)nco_malloc(nco_typ_lng(var->type)); ptr_unn_max.vp=(void *)nco_malloc(nco_typ_lng(var->type)); /* Create double precision missing_value for use in min/max arithmetic */ ptr_unn_mss_val_dbl.vp=(void *)NULL; /* CEWI */ if(var->has_mss_val){ ptr_unn_mss_val_dbl.vp=(void *)nco_malloc(nco_typ_lng((nc_type)NC_DOUBLE)); (void)nco_val_cnf_typ(var->type,var->mss_val,(nc_type)NC_DOUBLE,ptr_unn_mss_val_dbl); } /* endif has_mss_val */ /* Find minimum and maximum values in data */ (void)nco_var_avg_rdc_max(var->type,var->sz,1L,var->has_mss_val,var->mss_val,var->val,ptr_unn_min); (void)nco_var_avg_rdc_min(var->type,var->sz,1L,var->has_mss_val,var->mss_val,var->val,ptr_unn_max); /* Convert to NC_DOUBLE before 0.5*(min+max) operation */ min_var=scl_ptr_mk_var(ptr_unn_min,var->type); min_var=nco_var_cnf_typ((nc_type)NC_DOUBLE,min_var); max_var=scl_ptr_mk_var(ptr_unn_max,var->type); max_var=nco_var_cnf_typ((nc_type)NC_DOUBLE,max_var); /* Copy max_var for use in scale_factor computation */ max_var_dpl=nco_var_dpl(max_var); hlf_var=scl_mk_var(hlf_unn,NC_DOUBLE); /* [sct] NCO variable for value one half */ /* Field is pure missing_value iff either extrema is missing_value */ if(var->has_mss_val) if(min_var->val.dp[0] == ptr_unn_mss_val_dbl.dp[0]) PURE_MSS_VAL_FLD=True; /* fxm TODO nco1003 20101129 */ /* Change value of missing value iff necessary to fit inside packed type */ if(var->has_mss_val && !PURE_MSS_VAL_FLD){ double mss_val_dfl_dbl=0.0; /* CEWI */ double pck_rng_min_dbl=0.0; /* CEWI */ double pck_rng_max_dbl=0.0; /* CEWI */ switch(nc_typ_pck){ case NC_FLOAT: mss_val_dfl_dbl=NC_FILL_FLOAT; pck_rng_min_dbl=NC_MIN_FLOAT; pck_rng_max_dbl=NC_MAX_FLOAT; break; case NC_DOUBLE: mss_val_dfl_dbl=NC_FILL_DOUBLE; pck_rng_min_dbl=NC_MIN_DOUBLE; pck_rng_max_dbl=NC_MAX_DOUBLE; break; case NC_INT: mss_val_dfl_dbl=NC_FILL_INT; pck_rng_min_dbl=NC_MIN_INT; pck_rng_max_dbl=NC_MAX_INT; break; case NC_SHORT: mss_val_dfl_dbl=NC_FILL_SHORT; pck_rng_min_dbl=NC_MIN_SHORT; pck_rng_max_dbl=NC_MAX_SHORT; break; case NC_USHORT: mss_val_dfl_dbl=NC_FILL_USHORT; pck_rng_min_dbl=0.0; pck_rng_max_dbl=NC_MAX_USHORT; break; case NC_UINT: mss_val_dfl_dbl=NC_FILL_UINT; pck_rng_min_dbl=0.0; pck_rng_max_dbl=NC_MAX_UINT; break; case NC_INT64: mss_val_dfl_dbl=NC_FILL_INT64; pck_rng_min_dbl=NC_MIN_INT64; pck_rng_max_dbl=NC_MAX_INT64; break; case NC_UINT64: mss_val_dfl_dbl=NC_FILL_UINT64; pck_rng_min_dbl=0.0; pck_rng_max_dbl=NC_MAX_UINT64; break; case NC_BYTE: mss_val_dfl_dbl=NC_FILL_BYTE; pck_rng_min_dbl=NC_MIN_BYTE; pck_rng_max_dbl=NC_MAX_BYTE; break; case NC_UBYTE: mss_val_dfl_dbl=NC_FILL_UBYTE; pck_rng_min_dbl=0.0; pck_rng_max_dbl=NC_MAX_UBYTE; break; case NC_CHAR: mss_val_dfl_dbl=NC_FILL_CHAR; pck_rng_min_dbl=0.0; pck_rng_max_dbl=NC_MAX_CHAR; break; case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ if(nco_dbg_lvl_get() >= nco_dbg_io) (void)fprintf(stdout,"%s: %s mss_val_dfl_dbl = %g, pck_rng_min_dbl = %g, pck_rng_max_dbl = %g, \n",nco_prg_nm_get(),fnc_nm,mss_val_dfl_dbl,pck_rng_min_dbl,pck_rng_max_dbl); mss_val_dbl=ptr_unn_mss_val_dbl.dp[0]; if(nc_typ_pck != NC_STRING && (mss_val_dbl < pck_rng_min_dbl || mss_val_dbl > pck_rng_max_dbl)){ (void)fprintf(stdout,"%s: WARNING %s reports mss_val_dbl (= %g) is outside range (%g <= x <= %g) represented by packed data type (= %s). Conversion of missing values is unpredictable and could lead to erroneous results. Workaround is to set _FillValue to be within packed range with, e.g.,\nncatted -O -a _FillValue,,o,f,%g inout.nc\nFor more information on this workaround, see\nhttp://nco.sf.net/nco.html#mss_val\n",nco_prg_nm_get(),fnc_nm,mss_val_dbl,pck_rng_min_dbl,pck_rng_max_dbl,nco_typ_sng(nc_typ_pck),mss_val_dfl_dbl); } /* NC_STRING */ } /* end if(var->has_mss_val && !PURE_MSS_VAL_FLD) */ if(nco_dbg_lvl_get() >= nco_dbg_io) (void)fprintf(stdout,"%s: %s: min_var = %g, max_var = %g\n",nco_prg_nm_get(),var->nm,min_var->val.dp[0],max_var->val.dp[0]); /* add_offset is 0.5*(min+max) */ /* max_var->val is overridden with add_offset answers, no longer valid as max_var */ (void)nco_var_add((nc_type)NC_DOUBLE,1L,var->has_mss_val,ptr_unn_mss_val_dbl,min_var->val,max_var->val); (void)nco_var_mlt((nc_type)NC_DOUBLE,1L,var->has_mss_val,ptr_unn_mss_val_dbl,hlf_var->val,max_var->val); /* Contents of max_var are actually add_offset */ (void)nco_val_cnf_typ((nc_type)NC_DOUBLE,max_var->val,var->type,var->add_fst); /* ndrv is 2^{bits per packed value} where bppv = 8 for NC_CHAR and bppv = 16 for NC_SHORT Subtract one to leave slop for rounding errors 20101130 Subtract two to leave room for missing_value */ if(nc_typ_pck == NC_BYTE || nc_typ_pck == NC_CHAR){ ndrv_dbl=256.0-2.0; /* [sct] Double precision value of number of discrete representable values */ }else if(nc_typ_pck == NC_SHORT){ /* 20110203 Griffith Young reports: "I have noticed some small inconsistencies with the _FillValue values. short int is [32767, -32768]. The default _FillValue is -32767. Therefore a reasonable range would be [32766, -32766] and a reasonable scale_factor becomes (max - min) -> 32766 - (-32766) -> 65532." */ ndrv_dbl=65536.0-4.0; /* [sct] Double precision value of number of discrete representable values */ }else if(nc_typ_pck == NC_INT){ ndrv_dbl=4294967295.0-2.0; /* [sct] Double precision value of number of discrete representable values */ } /* end else */ ndrv_unn.d=ndrv_dbl; /* Generic container for number of discrete representable values */ ndrv_var=scl_mk_var(ndrv_unn,NC_DOUBLE); /* [sct] Variable structure for number of discrete representable values */ /* scale_factor is (max-min)/ndrv If max-min == 0 then variable is constant value so scale_factor=0.0 and add_offset=var If max-min > ndrv then precision is worse than 1.0 If max-min < ndrv then precision is better than 1.0 */ (void)nco_var_sbt((nc_type)NC_DOUBLE,1L,var->has_mss_val,ptr_unn_mss_val_dbl,min_var->val,max_var_dpl->val); /* max-min is currently stored in max_var_dpl */ max_mns_min_dbl=ptr_unn_2_scl_dbl(max_var_dpl->val,max_var_dpl->type); /* Manually set max-min=0.0 for pure missing_value fields to set add_offset correctly */ if(PURE_MSS_VAL_FLD) max_mns_min_dbl=0.0; if(max_mns_min_dbl != 0.0){ (void)nco_var_dvd((nc_type)NC_DOUBLE,1L,var->has_mss_val,ptr_unn_mss_val_dbl,ndrv_var->val,max_var_dpl->val); /* Contents of max_var_dpl are actually scale_factor */ (void)nco_val_cnf_typ((nc_type)NC_DOUBLE,max_var_dpl->val,var->type,var->scl_fct); }else{ /* Variable is constant, i.e., equal values everywhere */ zero_var=scl_mk_var(zero_unn,var->type); /* [sct] NCO variable for value 0.0 */ /* Set scale_factor to 0.0 */ (void)memcpy(var->scl_fct.vp,zero_var->val.vp,nco_typ_lng(var->type)); if(zero_var) zero_var=nco_var_free(zero_var); /* Set add_offset to first variable value Variable is constant everywhere so particular value copied is unimportant */ (void)memcpy(var->add_fst.vp,var->val.vp,nco_typ_lng(var->type)); } /* end else */ if(max_mns_min_dbl > max_mns_min_dbl_wrn){ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING %s reports data range of variable %s is = %g. The linear data packing technique defined by netCDF's packing convention and implemented by NCO result in significant precision loss over such a great range.\n",nco_prg_nm_get(),fnc_nm,var->nm,max_mns_min_dbl); if(nco_dbg_lvl_get() >= nco_dbg_std) if(var->has_mss_val) (void)fprintf(stdout,"%s: HINT variable %s has %s = %g. Consider specifying new %s to reduce range of data needing packing. See http://nco.sf.net/nco.html#ncatted for examples of how to change the %s attribute.\n",nco_prg_nm_get(),var->nm,nco_mss_val_sng_get(),ptr_unn_mss_val_dbl.dp[0],nco_mss_val_sng_get(),nco_mss_val_sng_get()); } /* endif large data range */ /* Free minimum and maximum values */ ptr_unn_min.vp=nco_free(ptr_unn_min.vp); ptr_unn_max.vp=nco_free(ptr_unn_max.vp); /* Free temporary double missing_value */ if(var->has_mss_val) ptr_unn_mss_val_dbl.vp=nco_free(ptr_unn_mss_val_dbl.vp); /* Free variables */ if(min_var) min_var=nco_var_free(min_var); if(max_var) max_var=nco_var_free(max_var); if(max_var_dpl) max_var_dpl=nco_var_free(max_var_dpl); if(hlf_var) hlf_var=nco_var_free(hlf_var); if(ndrv_var) ndrv_var=nco_var_free(ndrv_var); /* Do not bother creating superfluous scale_factor (0.0 or 1.0) or add_offset (0.0) */ scl_fct_dbl=ptr_unn_2_scl_dbl(var->scl_fct,var->type); add_fst_dbl=ptr_unn_2_scl_dbl(var->add_fst,var->type); if(scl_fct_dbl != 0.0 && scl_fct_dbl != 1.0) var->has_scl_fct=True; /* [flg] Valid scale_factor attribute exists */ if(add_fst_dbl != 0.0) var->has_add_fst=True; /* [flg] Valid add_offset attribute exists */ /* However, must create either scale_factor or add_offset Otherwise, routine fails to pack field uniformly equal to zero (0.0) In zero corner case, create add_offset (avoids division by zero problems) */ if(scl_fct_dbl == 0.0 && add_fst_dbl == 0.0) var->has_add_fst=True; } /* endif True */ /* Create double precision value of scale_factor for diagnostics */ if(var->has_scl_fct){ /* [flg] Valid scale_factor attribute exists */ scl_fct_dbl=ptr_unn_2_scl_dbl(var->scl_fct,var->type); if(scl_fct_dbl == 0.0 && nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING %s reports scl_fct_dbl = 0.0\n",nco_prg_nm_get(),fnc_nm); } /* endif */ /* Create double precision value of add_offset for diagnostics */ if(var->has_add_fst){ /* [flg] Valid add_offset attribute exists */ add_fst_dbl=ptr_unn_2_scl_dbl(var->add_fst,var->type); } /* endif */ if(nco_dbg_lvl_get() >= nco_dbg_io) (void)fprintf(stdout,"%s: %s reports variable %s has scl_fct_dbl = %g, add_fst_dbl = %g\n",nco_prg_nm_get(),fnc_nm,var->nm,scl_fct_dbl,add_fst_dbl); /* Packing attributes now exist and are same type as variable in memory */ /* Apply scale_factor and add_offset to reduce variable size add_offset and scale_factor are always scalars so use var_scv_* functions var_scv_[sub,multiply] functions avoid cost of broadcasting attributes and doing element-by-element operations Using var_scv_[sub,multiply] instead of ncap_var_scv_[sub,multiply] avoids cost of deep copies Moreover, this keeps variable structure from changing (because ncap_var_scv_* functions all do deep copies before operations) and thus complicating memory management */ if(var->has_add_fst){ /* [flg] Valid add_offset attribute exists */ nco_bool has_mss_val_tmp; /* [flg] Temporary missing_value flag */ /* Subtract add_offset from var */ scv_sct add_fst_scv; add_fst_scv.type=NC_DOUBLE; add_fst_scv.val.d=add_fst_dbl; (void)nco_scv_cnf_typ(var->type,&add_fst_scv); /* Pass temporary missing_value flag to accomodate pure missing_value fields */ has_mss_val_tmp=var->has_mss_val; /* Dupe var_scv_sub() into subtracting missing values when all values are missing */ if(PURE_MSS_VAL_FLD){ has_mss_val_tmp=False; if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO %s reports variable %s is filled completely with %s = %g. Why do you store variables with no valid values?\n",nco_prg_nm_get(),fnc_nm,var->nm,nco_mss_val_sng_get(),add_fst_dbl); } /* !PURE_MSS_VAL_FLD */ (void)var_scv_sub(var->type,var->sz,has_mss_val_tmp,var->mss_val,var->val,&add_fst_scv); } /* endif */ if(var->has_scl_fct){ /* [flg] Valid scale_factor attribute exists */ /* Divide var by scale_factor */ scv_sct scl_fct_scv; scl_fct_scv.type=NC_DOUBLE; scl_fct_scv.val.d=scl_fct_dbl; (void)nco_scv_cnf_typ(var->type,&scl_fct_scv); if(scl_fct_dbl != 0.0) (void)var_scv_dvd(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scl_fct_scv); } /* endif */ if(!var->has_scl_fct && !var->has_add_fst){ (void)fprintf(stderr,"%s: ERROR Reached end of %s without packing variable\n",nco_prg_nm_get(),fnc_nm); nco_exit(EXIT_FAILURE); }else{ *PCK_VAR_WITH_NEW_PCK_ATT=True; /* O [flg] Routine generated new scale_factor/add_offset */ } /* endif */ /* Tell the world we packed the variable This is true if input variable satisfied nco_pck_plc_typ_get() criteria Variables that fail nco_pck_plc_typ_get() (e.g., type == NC_CHAR) are not packed and should not have their packing attributes set */ var->pck_ram=True; /* [flg] Variable is packed in memory */ var->typ_pck=nc_typ_pck; /* [enm] Type of variable when packed (on disk). This should be same as typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ var->typ_upk=var->type; /* [enm] Type of variable when unpacked (expanded) (in memory) */ /* Convert variable to user-specified packed type This is where var->type is changed from original to packed type */ var=nco_var_cnf_typ(nc_typ_pck,var); if(nco_dbg_lvl_get() >= nco_dbg_sbr) (void)fprintf(stdout,"%s: PACKING %s packed %s into %s\n",nco_prg_nm_get(),fnc_nm,var->nm,nco_typ_sng(var->type)); return var; } /* end nco_var_pck() */ var_sct * /* O [sct] Unpacked variable */ nco_var_upk /* [fnc] Unpack variable in memory */ (var_sct *var) /* I/O [sct] Variable to be unpacked */ { /* Threads: Routine is thread-safe */ /* Purpose: Unpack variable Routine is inverse of nco_var_pck(): nco_var_upk[nco_var_pck(var)]=var Routine handles missing_value's implicitly: nco_var_cnf_typ() automatically converts missing_value, if any, to unpacked type This may need to change when nco427 is addressed */ const char fnc_nm[]="nco_var_upk()"; const char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ const char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ /* Return if variable in memory is not currently packed */ if(!var->pck_ram) return var; /* Routine should be called with variable already in memory */ if(var->val.vp == NULL){ (void)fprintf(stdout,"%s: ERROR nco_var_upk() called with empty var->val.vp\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* endif */ /* Packed variables are not guaranteed to have both scale_factor and add_offset scale_factor is guaranteed to be of type NC_FLOAT or NC_DOUBLE and of size 1 (a scalar) Hence algorithm create scalar value structures from values of scale_factor, add_offset */ /* 20130729: Rumors are true: NASA HDF data, including NASA MODIS swaths, expect offsets to be _subtracted_ then scaled! http://modis-atmos.gsfc.nasa.gov/MOD08_D3/faq.html The netCDF convention for packing is opposite: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf/Attribute-Conventions.html Hence unpacking NASA SDS data requires re-ordering and re-defining the netCDF-standard unpacking algorithm */ /* Test unpacking conventions: ncpdq -O -C -U -v ^pck_.? ~/nco/data/in.nc ~/foo.nc # Unpack netCDF ncpdq -O -C -U --hdf -v ^pck_.? ~/nco/data/in.nc ~/foo.nc # Unpack HDF ncpdq -O -C -P --hdf -v ^pck_.? ~/nco/data/in.nc ~/foo.nc # Unpack HDF and re-pack netCDF */ if(nco_upk_cnv_get() == nco_upk_netCDF){ /* netCDF unpack definition: unpacked=(scale_factor*packed)+add_offset */ if(var->has_scl_fct){ /* [flg] Valid scale_factor attribute exists */ scv_sct scl_fct_scv; var->scl_fct.vp=(void *)nco_malloc(nco_typ_lng(var->typ_upk)); (void)nco_get_att(var->nc_id,var->id,scl_fct_sng,var->scl_fct.vp,var->typ_upk); scl_fct_scv=ptr_unn_2_scv(var->typ_upk,var->scl_fct); /* Convert var to type of scale_factor for expansion */ var=nco_var_cnf_typ(scl_fct_scv.type,var); /* Multiply var by scale_factor */ (void)var_scv_mlt(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scl_fct_scv); } /* endif has_scl_fct */ if(var->has_add_fst){ /* [flg] Valid add_offset attribute exists */ scv_sct add_fst_scv; var->add_fst.vp=(void *)nco_malloc(nco_typ_lng(var->typ_upk)); (void)nco_get_att(var->nc_id,var->id,add_fst_sng,var->add_fst.vp,var->typ_upk); add_fst_scv=ptr_unn_2_scv(var->typ_upk,var->add_fst); /* Convert var to type of scale_factor for expansion */ var=nco_var_cnf_typ(add_fst_scv.type,var); /* Add add_offset to var */ (void)var_scv_add(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&add_fst_scv); } /* endif has_add_fst */ }else{ /* !netCDF_unpack_convention */ /* 20130729: NASA HDF unpack definition: unpacked=scale_factor*(packed-add_offset) */ if(var->has_add_fst){ /* [flg] Valid add_offset attribute exists */ scv_sct add_fst_scv; var->add_fst.vp=(void *)nco_malloc(nco_typ_lng(var->typ_upk)); (void)nco_get_att(var->nc_id,var->id,add_fst_sng,var->add_fst.vp,var->typ_upk); add_fst_scv=ptr_unn_2_scv(var->typ_upk,var->add_fst); /* Convert var to type of scale_factor for expansion */ var=nco_var_cnf_typ(add_fst_scv.type,var); /* Subtract add_offset from var */ (void)var_scv_sub(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&add_fst_scv); } /* endif has_add_fst */ if(var->has_scl_fct){ /* [flg] Valid scale_factor attribute exists */ scv_sct scl_fct_scv; var->scl_fct.vp=(void *)nco_malloc(nco_typ_lng(var->typ_upk)); (void)nco_get_att(var->nc_id,var->id,scl_fct_sng,var->scl_fct.vp,var->typ_upk); scl_fct_scv=ptr_unn_2_scv(var->typ_upk,var->scl_fct); /* Convert var to type of scale_factor for expansion */ var=nco_var_cnf_typ(scl_fct_scv.type,var); /* Multiply var by scale_factor */ (void)var_scv_mlt(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scl_fct_scv); } /* endif has_scl_fct */ } /* !netCDF_unpack_convention */ if(var->has_mss_val) var=nco_cnv_mss_val_typ(var,var->type); /* Tell the world */ var->pck_ram=False; /* Clean up tell-tale signs that variable was ever packed */ var->has_scl_fct=False; /* [flg] Valid scale_factor attribute exists */ var->has_add_fst=False; /* [flg] Valid add_offset attribute exists */ var->scl_fct.vp=nco_free(var->scl_fct.vp); var->add_fst.vp=nco_free(var->add_fst.vp); if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: PACKING %s unpacked %s into %s\n",nco_prg_nm_get(),fnc_nm,var->nm,nco_typ_sng(var->type)); return var; } /* end nco_var_upk() */ void nco_var_upk_swp /* [fnc] Unpack var_in into var_out */ (var_sct * const var_in, /* I/O [sct] Variable to unpack */ var_sct * const var_out) /* I/O [sct] Variable to unpack into */ { /* Purpose: Unpack var_in into var_out Information flow in ncpdq prevents ncpdq from calling nco_var_upk() directly with either var_in or var_out. Need combination of var_in (for correct file and variable IDs) and var_out (so unpacked variable ends up in correct place) Accomplish this by unpacking into temporary variable and copying needed information from temporary (swap) variable to var_out. Routine hides gory details of swapped unpacking var_in is untouched except var_in->val buffer is free()'d nco_pck_val() uses this routine for two purposes: 1. Unpack already packed variable prior to re-packing them 2. Unpack already packed variables permanently */ const char fnc_nm[]="nco_var_upk_swp()"; var_sct *var_tmp; /* [sct] Temporary variable to be unpacked */ if(var_in->pck_ram){ if(nco_dbg_lvl_get() >= nco_dbg_io) (void)fprintf(stdout,"%s: DEBUG %s unpacking variable %s values from %s to %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_typ_sng(var_out->typ_pck),nco_typ_sng(var_out->typ_upk)); }else{ (void)fprintf(stderr,"%s: ERROR %s variable %s is already unpacked\n",nco_prg_nm_get(),fnc_nm,var_in->nm); nco_exit(EXIT_FAILURE); } /* endif not already packed */ /* Output file does not contain packing attributes yet Hence unpacking var_out directly is impossible Instead, make var_tmp a copy of var_in and unpack var_tmp Then copy needed elements of var_tmp to var_out Then delete the rest of var_tmp Fields modified in nco_var_upk() must be explicitly updated in var_out */ var_tmp=nco_var_dpl(var_in); /* Free current input buffer */ var_in->val.vp=nco_free(var_in->val.vp); /* Unpack temporary variable */ var_tmp=nco_var_upk(var_tmp); /* Save relevent parts of temporary variable into output variable */ var_out->type=var_tmp->type; var_out->val=var_tmp->val; var_out->pck_ram=var_tmp->pck_ram; /* nco_var_cnf_typ() in nco_var_upk() automatically converts missing_value, if any, to unpacked type */ if(var_out->has_mss_val){ /* Free current missing value before obtaining new one */ var_out->mss_val.vp=(void *)nco_free(var_out->mss_val.vp); var_out->mss_val=var_tmp->mss_val; /* var_out now owns mss_val, make sure nco_var_free(var_tmp) ignores it */ var_tmp->mss_val.vp=NULL; } /* endif */ var_out->has_scl_fct=var_tmp->has_scl_fct; var_out->has_add_fst=var_tmp->has_add_fst; var_out->scl_fct.vp=nco_free(var_out->scl_fct.vp); var_out->add_fst.vp=nco_free(var_out->add_fst.vp); /* var_tmp->val buffer now doubles as var_out->val buffer Prevent nco_var_free() from free()'ing var_tmp->val Setting var_tmp->val.vp=NULL accomplishes this Use var_out->val.vp to free() this buffer later with nco_var_free() */ var_tmp->val.vp=NULL; if(var_tmp) var_tmp=nco_var_free(var_tmp); } /* end nco_var_upk_swp() */ ./nco-4.4.2/src/nco/nco_var_lst.h0000644000674300045400000001676612262450455016032 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_var_lst.h,v 1.73 2014/01/06 06:46:05 zender Exp $ */ /* Purpose: Variable list utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_var_lst.h" *//* Variable list utilities */ #ifndef NCO_VAR_LST_H #define NCO_VAR_LST_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ #include /* assert() */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, exit */ #include /* strcmp() */ #ifdef HAVE_REGEX_H /* 20120213: Linux GCC 4.6 man page says regex.h depends on (non-present) sys/types.h */ # ifdef MACOSX # include /*19950312: _res, 20040822: Mac OS X off_t required by regex.h */ # endif /* !MACOSX */ # include /* POSIX regular expressions library */ #endif /* HAVE_REGEX_H */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_lst_utl.h" /* List utilities */ #include "nco_mmr.h" /* Memory management */ #include "nco_var_utl.h" /* Variable utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ nm_id_sct * /* O [sct] Variable extraction list */ nco_var_lst_mk /* [fnc] Create variable extraction list */ (const int nc_id, /* I [enm] netCDF file ID */ const int var_nbr_all, /* I [nbr] Number of variables in input file */ char * const * const var_lst_in, /* I [sng] User-specified list of variable names and rx's */ const nco_bool EXCLUDE_INPUT_LIST, /* I [flg] Exclude rather than extract */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ int * const var_xtr_nbr); /* I/O [nbr] Number of variables in current extraction list */ nm_id_sct * /* O [sct] Extraction list */ nco_var_lst_xcl /* [fnc] Convert exclusion list to extraction list */ (const int nc_id, /* I netCDF file ID */ const int nbr_var, /* I [nbr] Number of variables in input file */ nm_id_sct *xtr_lst, /* I/O [sct] Current exclusion list (destroyed) */ int * const xtr_nbr); /* I/O [nbr] Number of variables in exclusion/extraction list */ nm_id_sct * /* O [sct] Extraction list */ nco_var_lst_crd_add /* [fnc] Add all coordinates to extraction list */ (const int nc_id, /* I [id] netCDF file ID */ const int nbr_dim, /* I [nbr] Number of dimensions in input file */ const int nbr_var, /* I [nbr] Number of variables in input file */ nm_id_sct *xtr_lst, /* I/O [sct] Current extraction list (destroyed) */ int * const xtr_nbr, /* I/O [nbr] Number of variables in current extraction list */ const nco_bool CNV_CCM_CCSM_CF); /* I [flg] file obeys CCM/CCSM/CF conventions */ nm_id_sct * /* O [sct] Extraction list */ nco_var_lst_crd_ass_add /* [fnc] Add to extraction list all coordinates associated with extracted variables */ (const int nc_id, /* I netCDF file ID */ nm_id_sct *xtr_lst, /* I/O current extraction list (destroyed) */ int * const xtr_nbr, /* I/O number of variables in current extraction list */ const nco_bool CNV_CCM_CCSM_CF); /* I [flg] file obeys CCM/CCSM/CF conventions */ nm_id_sct * /* O [sct] List with coordinate excluded */ nco_var_lst_crd_xcl /* [fnc] Exclude given coordinates from extraction list */ (const int nc_id, /* I [id] netCDF file ID */ const int dmn_id, /* I [id] Dimension ID of coordinate to remove from extraction list */ nm_id_sct *xtr_lst, /* I/O [sct] Current extraction list (destroyed) */ int * const xtr_nbr); /* I/O [nbr] Number of variables in extraction list */ void nco_var_lst_fix_rec_dvd /* [fnc] Divide extraction list into fixed and record data */ (const int nc_id, /* I [id] netCDF file ID */ nm_id_sct *xtr_lst, /* I/O [sct] Extraction list (pointers to it are constructed) */ const int xtr_nbr, /* I [nbr] Number of variables in extraction list */ nm_id_sct ***fix_lst, /* O [sct] Fixed-length variables */ int * const fix_nbr, /* O [nbr] Number of fixed-length variables */ nm_id_sct ***rec_lst, /* O [sct] Record variables */ int * const rec_nbr); /* O [nbr] Number of record variables */ void nco_var_lst_convert /* [fnc] Make variable structure list from variable name ID list */ (const int nc_id, /* I [enm] netCDF file ID */ nm_id_sct *xtr_lst, /* I [sct] Current extraction list (destroyed) */ const int xtr_nbr, /* I [nbr] Number of variables in input file */ dmn_sct * const * const dim, /* I [sct] Dimensions associated with input variable list */ const int nbr_dmn_xtr, /* I [nbr] Number of dimensions in list */ var_sct *** const var_ptr, /* O [sct] Variable list (for input file) */ var_sct *** const var_out_ptr); /* O [sct] Duplicate variable list (for output file) */ void nco_var_lst_dvd /* [fnc] Divide input lists into output lists */ (var_sct * const * const var, /* I [sct] Variable list (input file) */ var_sct * const * const var_out, /* I [sct] Variable list (output file) */ const int nbr_var, /* I [nbr] Number of variables */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ var_sct *** const var_fix_ptr, /* O [sct] Fixed-variables (input file) */ var_sct *** const var_fix_out_ptr, /* O [sct] Fixed-variables (output file) */ int * const nbr_var_fix, /* O [nbr] Number of fixed variables */ var_sct *** const var_prc_ptr, /* O [sct] Processed-variables (input file) */ var_sct *** const var_prc_out_ptr, /* O [sct] Processed-variables (output file) */ int * const nbr_var_prc, /* O [nbr] Number of processed variables */ const trv_tbl_sct * const trv_tbl); /* I [sct] Traversal table */ int /* O [enm] Return code */ nco_var_lst_mrg /* [fnc] Merge two variable lists into same order */ (var_sct *** var_1_ptr, /* I/O [sct] Variable list 1 */ var_sct *** var_2_ptr, /* I/O [sct] Variable list 2 */ int * const var_nbr_1, /* I/O [nbr] Number of variables in list 1 */ int * const var_nbr_2); /* I/O [nbr] Number of variables in list 2 */ void nco_var_lst_dvd_trv /* [fnc] Divide input lists into output lists (ncbo only) */ (var_sct * const var, /* I [sct] Variable list (input file) */ var_sct * const var_out, /* I [sct] Variable list (output file) */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ const int nco_pck_map, /* I [enm] Packing map */ const int nco_pck_plc, /* I [enm] Packing policy */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ prc_typ_enm *prc); /* O [enm] Processing type */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_VAR_LST_H */ ./nco-4.4.2/src/nco/nco_scl_utl.c0000644000674300045400000001474012260451232015776 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_scl_utl.c,v 1.31 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Scalar utilities */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include "nco_scl_utl.h" /* Scalar utilities */ var_sct * /* O [sct] netCDF variable structure representing val */ scl_dbl_mk_var /* [fnc] Convert scalar double into netCDF variable */ (const double val) /* I [frc] Double precision value to turn into netCDF variable */ { /* Purpose: Convert scalar double into netCDF variable Routine duplicates most functions of nco_var_fll() Both functions should share as much initialization code as possible */ var_sct *var; var=(var_sct *)nco_malloc(sizeof(var_sct)); /* Set defaults */ (void)var_dfl_set(var); /* [fnc] Set defaults for each member of variable structure */ /* Overwrite defaults with values appropriate for artificial variable */ var->nm=(char *)strdup("Internally_generated_variable"); var->nm_fll=NULL; var->nbr_dim=0; var->type=NC_DOUBLE; var->val.vp=(void *)nco_malloc(nco_typ_lng(var->type)); (void)memcpy((void *)var->val.vp,(const void *)(&val),nco_typ_lng(var->type)); return var; } /* end scl_dbl_mk_var() */ var_sct * /* O [sct] Output netCDF variable structure representing val */ scl_mk_var /* [fnc] Convert scalar value of any type into NCO variable */ (val_unn val, /* I [frc] Scalar value to turn into netCDF variable */ const nc_type val_typ) /* I [enm] netCDF type of value */ { /* Purpose: Turn scalar value of any type into NCO variable Routine is just a wrapper for scl_ptr_mk_var() This routine creates the void * argument needed for scl_ptr_mk_var(), calls, scl_ptr_mk_var(), then passes back the result */ var_sct *var; ptr_unn val_ptr_unn; /* [ptr] void pointer to value */ switch(val_typ){ case NC_FLOAT: val_ptr_unn.fp=&val.f; break; case NC_DOUBLE: val_ptr_unn.dp=&val.d; break; case NC_INT: val_ptr_unn.ip=&val.i; break; case NC_SHORT: val_ptr_unn.sp=&val.s; break; case NC_CHAR: val_ptr_unn.cp=&val.c; break; case NC_BYTE: val_ptr_unn.bp=&val.b; break; case NC_UBYTE: val_ptr_unn.ubp=&val.ub; break; case NC_USHORT: val_ptr_unn.usp=&val.us; break; case NC_UINT: val_ptr_unn.uip=&val.ui; break; case NC_INT64: val_ptr_unn.i64p=&val.i64; break; case NC_UINT64: val_ptr_unn.ui64p=&val.ui64; break; case NC_STRING: val_ptr_unn.sngp=&val.sng; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ /* Un-typecast pointer to values after access */ (void)cast_nctype_void(val_typ,&val_ptr_unn); var=scl_ptr_mk_var(val_ptr_unn,val_typ); return var; } /* end scl_mk_var() */ var_sct * /* O [sct] Output NCO variable structure representing value */ scl_ptr_mk_var /* [fnc] Convert void pointer to scalar of any type into NCO variable */ (const ptr_unn val_ptr_unn, /* I [unn] Scalar value to turn into netCDF variable */ const nc_type val_typ) /* I [enm] netCDF type of existing pointer/value */ { /* Purpose: Convert void pointer to scalar of any type into NCO variable Routine duplicates many functions of nco_var_fll() Both functions should share as much initialization code as possible */ var_sct *var; var=(var_sct *)nco_malloc(sizeof(var_sct)); /* Set defaults */ (void)var_dfl_set(var); /* [fnc] Set defaults for each member of variable structure */ /* Overwrite defaults with values appropriate for artificial variable */ var->nm=(char *)strdup("Internally_generated_variable"); var->nm_fll=NULL; var->nbr_dim=0; var->type=val_typ; /* Allocate new space here so that variable can eventually be deleted and associated memory free()'d */ /* free(val_ptr_unn.vp) is unpredictable since val_ptr_unn may point to constant data, e.g., a constant in scl_mk_var */ var->val.vp=(void *)nco_malloc(nco_typ_lng(var->type)); /* Copy value into variable structure */ (void)memcpy((void *)var->val.vp,val_ptr_unn.vp,nco_typ_lng(var->type)); return var; } /* end scl_ptr_mk_var() */ double /* O [frc] Double precision representation of var->val.?p[0] */ ptr_unn_2_scl_dbl /* [fnc] Convert first element of NCO variable to a scalar double */ (const ptr_unn val, /* I [sct] Pointer union to convert to scalar double */ const nc_type type) /* I [enm] Type of values pointed to by pointer union */ { /* Purpose: Return first element of NCO variable converted to a scalar double */ double scl_dbl; /* [sct] Double precision value of scale_factor */ ptr_unn ptr_unn_scl_dbl; /* [unn] Pointer union to double precision value of first element */ /* Variable must be in memory already */ if(val.vp == NULL){ (void)fprintf(stdout,"%s: ERROR ptr_unn_2_scl_dbl() called with empty val.vp\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* endif */ /* Valid memory address exists */ ptr_unn_scl_dbl.vp=(void *)nco_malloc(nco_typ_lng(NC_DOUBLE)); /* [unn] Pointer union to double precision value of first element */ (void)nco_val_cnf_typ(type,val,NC_DOUBLE,ptr_unn_scl_dbl); scl_dbl=ptr_unn_scl_dbl.dp[0]; ptr_unn_scl_dbl.vp=nco_free(ptr_unn_scl_dbl.vp); return scl_dbl; } /* end ptr_unn_2_scl_dbl() */ scv_sct /* O [sct] Scalar value structure representing val */ ptr_unn_2_scv /* [fnc] Convert ptr_unn to scalar value structure */ (const nc_type type, /* I [enm] netCDF type of value */ ptr_unn val) /* I [sct] Value to convert to scalar value structure */ { /* Purpose: Convert ptr_unn to scalar value structure Assumes that val is initially cast to void Does not convert cp (strings) as these are not handled by scv_sct NB: netCDF attributes may contain multiple values Only FIRST value in memory block is converted */ scv_sct scv; (void)cast_void_nctype(type,&val); switch(type){ case NC_FLOAT: scv.val.f=*val.fp; break; case NC_DOUBLE: scv.val.d=*val.dp; break; case NC_INT: scv.val.i=*val.ip; break; case NC_SHORT: scv.val.s=*val.sp; break; case NC_BYTE: scv.val.b=*val.bp; break; case NC_CHAR: break; /* Do nothing */ case NC_UBYTE: scv.val.ub=*val.ubp; break; case NC_USHORT: scv.val.us=*val.usp; break; case NC_UINT: scv.val.ui=*val.uip; break; case NC_INT64: scv.val.i64=*val.i64p; break; case NC_UINT64: scv.val.ui64=*val.ui64p; break; case NC_STRING: scv.val.sng=*val.sngp; break; default: nco_dfl_case_nc_type_err(); break; } /* end switch */ scv.type=type; /* Do not uncast pointer as we are working with a copy */ return scv; } /* end ptr_unn_2_scv */ ./nco-4.4.2/src/nco/nco_typ.h0000644000674300045400000004126312260451232015152 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_typ.h,v 1.37 2013/12/31 05:14:02 zender Exp $ */ /* Purpose: Type definitions, opaque types */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_typ.h" *//* Type definitions, opaque types */ #ifndef NCO_TYP_H #define NCO_TYP_H #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard header files */ /* 3rd party vendors */ /* Personal headers */ /* Opaque types: NCO defines opaque types to abstract treatment of certain netCDF types NCO uses types nco_byte, nco_char, and nco_int to handle netCDF internal types NC_BYTE, NC_CHAR, and NC_INT, respectively Most routines need access to opaque type definitions, so nco.h is appropriate However, isolating opaque types definitions in nco_typ.h ensures that wrappers (e.g., nco_netcdf.[ch]) need not depend on nco.h. */ /* byte, char, and int/long types are the most confusing part of netCDF: netCDF manual p. 20: char: 8-bit characters intended for representing text byte: 8-bit signed or unsigned integers "It is possible to interpret byte data as either signed (-128 to 127) or unsigned (0 to 255). However, when reading byte data to be converted into other numeric types, it is interpreted as signed." By default (and subject to modification by manipulating the tokens below), NCO treats NC_BYTE as C-type "signed char". NCO treats NC_CHAR as C-type "char". C-Type "char" equals C-type "unsigned char" on most compilers/OSs NCO uses an opaque type nco_char to ease code portability Therefore, by default, NCO reads/writes NC_BYTE using nc_put/get_var*_schar() functions NCO reads/writes NC_CHAR using nc_put/get_var*_text() functions NCO does not use nc_put/get_var*_uchar() functions for anything netCDF manual p. 102: "The byte type differs from the char type in that it is intended for eight-bit data and the zero byte has no special significance, as it may for character data. The ncgen utility converts byte declarations to char declarations in the output C code." */ /* NCO_TYP_IO_FNC_MRG(x,y) function generates appropriate netCDF-layer I/O function call for given I/O operation (x) and (possibly opaque) type (y) fxm TODO nco549: Automagically generate function names when called with, e g., NCO_TYP_IO_FNC_MRG(nc_get_var1,NCO_TYP_BYTE_IO_SFX) Unfortunately this pre-precessor macro has never worked... */ #define NCO_TYP_IO_FNC_MRG(x,y) x##y /* Define compatibility tokens when user does not have netCDF4 netcdf.h Compatibility tokens for when NCO compiled with older netcdf.h It is hard to track where/when many tokens defined Easiest to individually check for pre-definition of each */ /* Datatypes referenced in nco_typ.h, nco_netcdf.c: */ #ifndef NC_UBYTE # define NC_UBYTE 7 /* unsigned 1 byte int */ #endif #ifndef NC_USHORT # define NC_USHORT 8 /* unsigned 2-byte int */ #endif #ifndef NC_UINT # define NC_UINT 9 /* unsigned 4-byte int */ #endif #ifndef NC_INT64 # define NC_INT64 10 /* signed 8-byte int */ #endif #ifndef NC_UINT64 # define NC_UINT64 11 /* unsigned 8-byte int */ #endif #ifndef NC_STRING # define NC_STRING 12 /* string */ #endif #ifndef NC_VLEN # define NC_VLEN 13 /* vlen */ #endif #ifndef NC_OPAQUE # define NC_OPAQUE 14 /* opaque */ #endif #ifndef NC_ENUM # define NC_ENUM 15 /* enum */ #endif #ifndef NC_COMPOUND # define NC_COMPOUND 16 /* compound */ #endif #ifndef NC_MAX_ATOMIC_TYPE #define NC_MAX_ATOMIC_TYPE NC_STRING #endif #ifndef NC_FIRSTUSERTYPEID #define NC_FIRSTUSERTYPEID 32 #endif /* Fill values for netCDF4 datatypes. Referenced in nco_mss_val.c: */ #ifndef NC_FILL_UBYTE # define NC_FILL_UBYTE (255) #endif #ifndef NC_FILL_USHORT # define NC_FILL_USHORT (65535) #endif #ifndef NC_FILL_UINT # define NC_FILL_UINT (4294967295U) #endif /* NB: These fill values are one shy of min(int64) and max(uint64) */ #ifndef NC_FILL_INT64 # define NC_FILL_INT64 ((long long int)-9223372036854775806LL) #endif #ifndef NC_FILL_UINT64 # define NC_FILL_UINT64 ((unsigned long long int)18446744073709551614ULL) #endif #ifndef NC_FILL_STRING # define NC_FILL_STRING "" #endif /* end define compatibility tokens when user does not have netCDF4 netcdf.h */ /* C pre-processor compares integers not strings Perform comparisons on enumerated integer values corresponding to each type */ #define NCO_TYP_CHAR 0 #define NCO_TYP_SCHAR 1 #define NCO_TYP_UCHAR 2 #define NCO_TYP_INT 3 #define NCO_TYP_LONG 4 #define NCO_TYP_UBYTE 5 #define NCO_TYP_USHORT 6 #define NCO_TYP_UINT 7 #define NCO_TYP_INT64 8 #define NCO_TYP_UINT64 9 #define NCO_TYP_STRING 10 /* Tokens to give semantic compatibility between easy- and hard-to-handle types i.e., nco_short is always short and easy-to-handle */ typedef short nco_short; /* [typ] NC_SHORT */ /* NC_BYTE handling */ #ifndef NCO_BYTE /* Valid options are NCO_TYP_CHAR, NCO_TYP_SCHAR, NCO_TYP_UCHAR Default is NCO_TYP_SCHAR, which treats NC_BYTE as C-type signed char */ # define NCO_BYTE NCO_TYP_SCHAR #endif /* NCO_BYTE */ #if NCO_BYTE == NCO_TYP_CHAR /* Treat NC_BYTE as C-type char */ typedef char nco_byte; /* [typ] NC_BYTE */ # define NCO_BYTE_SNG "char" # define NCO_BYTE_IO_SFX text # define NCO_GET_ATT_BYTE nc_get_att_text # define NCO_GET_VAR1_BYTE nc_get_var1_text # define NCO_GET_VARA_BYTE nc_get_vara_text # define NCO_GET_VARS_BYTE nc_get_vars_text # define NCO_GET_VARM_BYTE nc_get_varm_text # define NCO_PUT_ATT_BYTE nc_put_att_text # define NCO_PUT_VAR1_BYTE nc_put_var1_text # define NCO_PUT_VARA_BYTE nc_put_vara_text # define NCO_PUT_VARS_BYTE nc_put_vars_text # define NCO_PUT_VARM_BYTE nc_put_varm_text #elif NCO_BYTE == NCO_TYP_SCHAR /* Treat NC_BYTE as C-type signed char */ typedef signed char nco_byte; /* [typ] NC_BYTE */ # define NCO_BYTE_SNG "signed char" # define NCO_BYTE_IO_SFX schar # define NCO_GET_ATT_BYTE nc_get_att_schar # define NCO_GET_VAR1_BYTE nc_get_var1_schar # define NCO_GET_VARA_BYTE nc_get_vara_schar # define NCO_GET_VARS_BYTE nc_get_vars_schar # define NCO_GET_VARM_BYTE nc_get_varm_schar # define NCO_PUT_ATT_BYTE nc_put_att_schar # define NCO_PUT_VAR1_BYTE nc_put_var1_schar # define NCO_PUT_VARA_BYTE nc_put_vara_schar # define NCO_PUT_VARS_BYTE nc_put_vars_schar # define NCO_PUT_VARM_BYTE nc_put_varm_schar #elif NCO_BYTE == NCO_TYP_UCHAR /* Treat NC_BYTE as C-type unsigned char */ typedef unsigned char nco_byte; /* [typ] NC_BYTE */ # define NCO_BYTE_SNG "unsigned char" # define NCO_BYTE_IO_SFX uchar # define NCO_GET_ATT_BYTE nc_get_att_uchar # define NCO_GET_VAR1_BYTE nc_get_var1_uchar # define NCO_GET_VARA_BYTE nc_get_vara_uchar # define NCO_GET_VARS_BYTE nc_get_vars_uchar # define NCO_GET_VARM_BYTE nc_get_varm_uchar # define NCO_PUT_ATT_BYTE nc_put_att_uchar # define NCO_PUT_VAR1_BYTE nc_put_var1_uchar # define NCO_PUT_VARA_BYTE nc_put_vara_uchar # define NCO_PUT_VARS_BYTE nc_put_vars_uchar # define NCO_PUT_VARM_BYTE nc_put_varm_uchar #else # error "ERROR: Unrecognized NCO_BYTE token" #endif /* NCO_BYTE */ /* NC_UBYTE handling */ #ifndef NCO_UBYTE /* Only valid option is NCO_TYP_UCHAR Default is NCO_TYP_UCHAR, which treats NC_UBYTE as C-type unsigned char */ # define NCO_UBYTE NCO_TYP_UCHAR #endif /* NCO_UBYTE */ #if NCO_UBYTE == NCO_TYP_UCHAR /* Treat NC_UBYTE as C-type unsigned char */ typedef unsigned char nco_ubyte; /* [typ] NC_UBYTE */ # define NCO_UBYTE_SNG "unsigned char" # define NCO_UBYTE_IO_SFX ubyte # define NCO_GET_ATT_UBYTE nc_get_att_ubyte # define NCO_GET_VAR1_UBYTE nc_get_var1_ubyte # define NCO_GET_VARA_UBYTE nc_get_vara_ubyte # define NCO_GET_VARS_UBYTE nc_get_vars_ubyte # define NCO_GET_VARM_UBYTE nc_get_varm_ubyte # define NCO_PUT_ATT_UBYTE nc_put_att_ubyte # define NCO_PUT_VAR1_UBYTE nc_put_var1_ubyte # define NCO_PUT_VARA_UBYTE nc_put_vara_ubyte # define NCO_PUT_VARS_UBYTE nc_put_vars_ubyte # define NCO_PUT_VARM_UBYTE nc_put_varm_ubyte #else # error "ERROR: Unrecognized NCO_UBYTE token" #endif /* NCO_UBYTE */ /* NC_CHAR handling */ #ifndef NCO_CHAR /* Valid options are NCO_TYP_CHAR, NCO_TYP_SCHAR, NCO_TYP_UCHAR Default is NCO_TYP_CHAR, which treats NC_CHAR as C-type char */ # define NCO_CHAR NCO_TYP_CHAR #endif /* NCO_CHAR */ #if NCO_CHAR == NCO_TYP_CHAR /* Treat NC_CHAR as C-type char */ typedef char nco_char; /* [typ] NC_CHAR */ # define NCO_CHAR_SNG "char" # define NCO_CHAR_IO_SFX text # define NCO_GET_ATT_CHAR nc_get_att_text # define NCO_GET_VAR1_CHAR nc_get_var1_text # define NCO_GET_VARA_CHAR nc_get_vara_text # define NCO_GET_VARS_CHAR nc_get_vars_text # define NCO_GET_VARM_CHAR nc_get_varm_text /* nc_put_att_text() is unique---it uses strlen() to determine argument length */ # define NCO_PUT_ATT_CHAR(a,b,c,d,e,f) nc_put_att_text(a,b,c,e,f) # define NCO_PUT_VAR1_CHAR nc_put_var1_text # define NCO_PUT_VARA_CHAR nc_put_vara_text # define NCO_PUT_VARS_CHAR nc_put_vars_text # define NCO_PUT_VARM_CHAR nc_put_varm_text #elif NCO_CHAR == NCO_TYP_SCHAR /* Treat NC_CHAR as C-type signed char */ typedef signed char nco_char; /* [typ] NC_CHAR */ # define NCO_CHAR_SNG "signed char" # define NCO_CHAR_IO_SFX schar # define NCO_GET_ATT_CHAR nc_get_att_schar # define NCO_GET_VAR1_CHAR nc_get_var1_schar # define NCO_GET_VARA_CHAR nc_get_vara_schar # define NCO_GET_VARS_CHAR nc_get_vars_schar # define NCO_GET_VARM_CHAR nc_get_varm_schar # define NCO_PUT_ATT_CHAR nc_put_att_schar # define NCO_PUT_VAR1_CHAR nc_put_var1_schar # define NCO_PUT_VARS_CHAR nc_put_vars_schar # define NCO_PUT_VARM_CHAR nc_put_varm_schar #elif NCO_CHAR == NCO_TYP_UCHAR /* Treat NC_CHAR as C-type unsigned char */ typedef unsigned char nco_char; /* [typ] NC_CHAR */ # define NCO_CHAR_SNG "unsigned char" # define NCO_CHAR_IO_SFX uchar # define NCO_GET_ATT_CHAR nc_get_att_uchar # define NCO_GET_VAR1_CHAR nc_get_var1_uchar # define NCO_GET_VARA_CHAR nc_get_vara_uchar # define NCO_GET_VARS_CHAR nc_get_vars_uchar # define NCO_GET_VARM_CHAR nc_get_varm_uchar # define NCO_PUT_ATT_CHAR nc_put_att_uchar # define NCO_PUT_VAR1_CHAR nc_put_var1_uchar # define NCO_PUT_VARA_CHAR nc_put_vara_uchar # define NCO_PUT_VARS_CHAR nc_put_vars_uchar # define NCO_PUT_VARM_CHAR nc_put_varm_uchar #else # error "ERROR: Unrecognized NCO_CHAR token" #endif /* NCO_CHAR */ /* NC_USHORT handling */ #ifndef NCO_USHORT /* Only valid option is NCO_TYP_USHORT Default is NCO_TYP_USHORT, which treats NC_USHORT as C-type unsigned short */ # define NCO_USHORT NCO_TYP_USHORT #endif /* NCO_USHORT */ #if NCO_USHORT == NCO_TYP_USHORT /* Treat NC_USHORT as C-type unsigned short */ typedef unsigned short nco_ushort; /* [typ] NC_USHORT */ # define NCO_USHORT_SNG "unsigned short" # define NCO_USHORT_IO_SFX ushort # define NCO_GET_ATT_USHORT nc_get_att_ushort # define NCO_GET_VAR1_USHORT nc_get_var1_ushort # define NCO_GET_VARA_USHORT nc_get_vara_ushort # define NCO_GET_VARS_USHORT nc_get_vars_ushort # define NCO_GET_VARM_USHORT nc_get_varm_ushort # define NCO_PUT_ATT_USHORT nc_put_att_ushort # define NCO_PUT_VAR1_USHORT nc_put_var1_ushort # define NCO_PUT_VARA_USHORT nc_put_vara_ushort # define NCO_PUT_VARS_USHORT nc_put_vars_ushort # define NCO_PUT_VARM_USHORT nc_put_varm_ushort #else # error "ERROR: Unrecognized NCO_USHORT token" #endif /* NCO_USHORT */ /* NC_INT handling */ #ifndef NCO_INT /* Valid options are NCO_TYP_INT, NCO_TYP_LONG Before 20091030, default was NCO_TYP_LONG, which treats NC_INT as C-type long Since 20091030, default is NCO_TYP_INT, which treats NC_INT as C-type int */ # define NCO_INT NCO_TYP_INT #endif /* NCO_INT */ #if NCO_INT == NCO_TYP_INT /* Treat NC_INT as C-type int */ typedef int nco_int; /* [typ] NC_INT */ # define NCO_INT_SNG "int" # define NCO_INT_IO_SFX int # define NCO_GET_ATT_INT nc_get_att_int # define NCO_GET_VAR1_INT nc_get_var1_int # define NCO_GET_VARA_INT nc_get_vara_int # define NCO_GET_VARS_INT nc_get_vars_int # define NCO_GET_VARM_INT nc_get_varm_int # define NCO_PUT_ATT_INT nc_put_att_int # define NCO_PUT_VAR1_INT nc_put_var1_int # define NCO_PUT_VARA_INT nc_put_vara_int # define NCO_PUT_VARS_INT nc_put_vars_int # define NCO_PUT_VARM_INT nc_put_varm_int #elif NCO_INT == NCO_TYP_LONG /* Treat NC_INT as C-type long */ typedef long nco_int; /* [typ] NC_INT */ # define NCO_INT_SNG "long" # define NCO_INT_IO_SFX long # define NCO_GET_ATT_INT nc_get_att_long # define NCO_GET_VAR1_INT nc_get_var1_long # define NCO_GET_VARA_INT nc_get_vara_long # define NCO_GET_VARS_INT nc_get_vars_long # define NCO_GET_VARM_INT nc_get_varm_long # define NCO_PUT_ATT_INT nc_put_att_long # define NCO_PUT_VAR1_INT nc_put_var1_long # define NCO_PUT_VARA_INT nc_put_vara_long # define NCO_PUT_VARS_INT nc_put_vars_long # define NCO_PUT_VARM_INT nc_put_varm_long #else # error "ERROR: Unrecognized NCO_INT token" #endif /* NCO_INT */ /* NC_UINT handling */ #ifndef NCO_UINT /* Only valid option is NCO_TYP_UINT Default is NCO_TYP_UINT, which treats NC_UINT as C-type unsigned int */ # define NCO_UINT NCO_TYP_UINT #endif /* NCO_UINT */ #if NCO_UINT == NCO_TYP_UINT /* Treat NC_UINT as C-type unsigned int */ typedef unsigned int nco_uint; /* [typ] NC_UINT */ # define NCO_UINT_SNG "unsigned int" # define NCO_UINT_IO_SFX uint # define NCO_GET_ATT_UINT nc_get_att_uint # define NCO_GET_VAR1_UINT nc_get_var1_uint # define NCO_GET_VARA_UINT nc_get_vara_uint # define NCO_GET_VARS_UINT nc_get_vars_uint # define NCO_GET_VARM_UINT nc_get_varm_uint # define NCO_PUT_ATT_UINT nc_put_att_uint # define NCO_PUT_VAR1_UINT nc_put_var1_uint # define NCO_PUT_VARA_UINT nc_put_vara_uint # define NCO_PUT_VARS_UINT nc_put_vars_uint # define NCO_PUT_VARM_UINT nc_put_varm_uint #else # error "ERROR: Unrecognized NCO_UINT token" #endif /* NCO_UINT */ /* NC_INT64 handling */ #ifndef NCO_INT64 /* Only valid option is NCO_TYP_INT64 Default is NCO_TYP_INT64, which treats NC_INT64 as C-type long long */ # define NCO_INT64 NCO_TYP_INT64 #endif /* NCO_INT64 */ #if NCO_INT64 == NCO_TYP_INT64 /* Treat NC_INT64 as C-type long long */ typedef long long nco_int64; /* [typ] NC_INT64 */ # define NCO_INT64_SNG "long long" # define NCO_INT64_IO_SFX longlong # define NCO_GET_ATT_INT64 nc_get_att_longlong # define NCO_GET_VAR1_INT64 nc_get_var1_longlong # define NCO_GET_VARA_INT64 nc_get_vara_longlong # define NCO_GET_VARS_INT64 nc_get_vars_longlong # define NCO_GET_VARM_INT64 nc_get_varm_longlong # define NCO_PUT_ATT_INT64 nc_put_att_longlong # define NCO_PUT_VAR1_INT64 nc_put_var1_longlong # define NCO_PUT_VARA_INT64 nc_put_vara_longlong # define NCO_PUT_VARS_INT64 nc_put_vars_longlong # define NCO_PUT_VARM_INT64 nc_put_varm_longlong #else # error "ERROR: Unrecognized NCO_INT64 token" #endif /* NCO_INT64 */ /* NC_UINT64 handling */ #ifndef NCO_UINT64 /* Only valid option is NCO_TYP_UINT64 Default is NCO_TYP_UINT64, which treats NC_UINT64 as C-type unsigned long long */ # define NCO_UINT64 NCO_TYP_UINT64 #endif /* NCO_UINT64 */ #if NCO_UINT64 == NCO_TYP_UINT64 /* Treat NC_UINT64 as C-type unsigned long long */ typedef unsigned long long nco_uint64; /* [typ] NC_UINT64 */ # define NCO_UINT64_SNG "unsigned long long" # define NCO_UINT64_IO_SFX ulonglong # define NCO_GET_ATT_UINT64 nc_get_att_ulonglong # define NCO_GET_VAR1_UINT64 nc_get_var1_ulonglong # define NCO_GET_VARA_UINT64 nc_get_vara_ulonglong # define NCO_GET_VARS_UINT64 nc_get_vars_ulonglong # define NCO_GET_VARM_UINT64 nc_get_varm_ulonglong # define NCO_PUT_ATT_UINT64 nc_put_att_ulonglong # define NCO_PUT_VAR1_UINT64 nc_put_var1_ulonglong # define NCO_PUT_VARA_UINT64 nc_put_vara_ulonglong # define NCO_PUT_VARS_UINT64 nc_put_vars_ulonglong # define NCO_PUT_VARM_UINT64 nc_put_varm_ulonglong #else # error "ERROR: Unrecognized NCO_UINT64 token" #endif /* NCO_UINT64 */ /* NC_STRING handling */ #ifndef NCO_STRING /* 20070514: netcdf4-beta1 only supports nc_put_var_string() and nc_get_var_string() */ /* Only valid option is NCO_TYP_STRING Default is NCO_TYP_STRING, which treats NC_STRING as C-type char */ # define NCO_STRING NCO_TYP_STRING #endif /* NCO_STRING */ #if NCO_STRING == NCO_TYP_STRING /* Treat NC_STRING as C-type char * */ typedef char * nco_string; /* [typ] NC_STRING */ # define NCO_STRING_SNG "char *" # define NCO_STRING_IO_SFX string # define NCO_GET_ATT_STRING nc_get_att_string # define NCO_GET_VAR1_STRING nc_get_var1_string # define NCO_GET_VARA_STRING nc_get_vara_string # define NCO_GET_VARS_STRING nc_get_vars_string # define NCO_GET_VARM_STRING nc_get_varm_string /* nc_put_att_string() is unique---it uses strlen() to determine argument length */ # define NCO_PUT_ATT_STRING(a,b,c,d,e,f) nc_put_att_string(a,b,c,e,f) # define NCO_PUT_VAR1_STRING nc_put_var1_string # define NCO_PUT_VARA_STRING nc_put_vara_string # define NCO_PUT_VARS_STRING nc_put_vars_string # define NCO_PUT_VARM_STRING nc_put_varm_string #else # error "ERROR: Unrecognized NCO_STRING token" #endif /* NCO_STRING */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Hi */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_TYP_H */ ./nco-4.4.2/src/nco/mpncflint.c0000644000674300045400000013165112262450454015474 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/mpncflint.c,v 1.120 2014/01/06 06:46:04 zender Exp $ */ /* mpncflint -- netCDF file interpolator */ /* Purpose: Linearly interpolate a third netCDF file from two input files */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* Usage: ncflint -O -D 2 in.nc in.nc ~/foo.nc ncflint -O -i lcl_time_hr,9.0 -v lcl_time_hr /data/zender/arese/clm/951030_0800_arese_clm.nc /data/zender/arese/clm/951030_1100_arese_clm.nc ~/foo.nc; ncks -H foo.nc ncflint -O -w 0.66666,0.33333 -v lcl_time_hr /data/zender/arese/clm/951030_0800_arese_clm.nc /data/zender/arese/clm/951030_1100_arese_clm.nc ~/foo.nc; ncks -H foo.nc ncflint -O -w 0.66666 -v lcl_time_hr /data/zender/arese/clm/951030_0800_arese_clm.nc /data/zender/arese/clm/951030_1100_arese_clm.nc ~/foo.nc; ncks -H foo.nc ncdiff -O foo.nc /data/zender/arese/clm/951030_0900_arese_clm.nc foo2.nc;ncks -H foo2.nc | m */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #include /* POSIX stuff */ #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #ifdef ENABLE_MPI #include /* MPI definitions */ #include "nco_mpi.h" /* MPI utilities */ #endif /* !ENABLE_MPI */ #include /* netCDF definitions and C library */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { nco_bool CNV_CCM_CCSM_CF; nco_bool CMD_LN_NTP_VAR=False; /* Option i */ nco_bool CMD_LN_NTP_WGT=True; /* Option w */ nco_bool DO_CONFORM=False; /* Did nco_var_cnf_dmn() find truly conforming variables? */ nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FILE_1_RETRIEVED_FROM_REMOTE_LOCATION; nco_bool FILE_2_RETRIEVED_FROM_REMOTE_LOCATION; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order*/ nco_bool MUST_CONFORM=False; /* Must nco_var_cnf_dmn() find truly conforming variables? */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option a */ char **fl_lst_in; char **ntp_lst_in; char **var_lst_in=NULL_CEWI; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in_1=NULL; /* fl_in_1 is nco_realloc'd when not NULL */ char *fl_in_2=NULL; /* fl_in_2 is nco_realloc'd when not NULL */ char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL; /* MPI CEWI */ char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *lmt_arg[NC_MAX_DIMS]; char *ntp_nm=NULL; /* Option i */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ const char * const CVS_Id="$Id: mpncflint.c,v 1.120 2014/01/06 06:46:04 zender Exp $"; const char * const CVS_Revision="$Revision: 1.120 $"; const char * const opt_sht_lst="3467ACcD:d:Fhi:L:l:Oo:p:rRSt:v:xw:-:"; cnk_dmn_sct **cnk_dmn=NULL_CEWI; dmn_sct **dim; dmn_sct **dmn_out; double ntp_val_out=double_CEWI; /* Option i */ double wgt_val_1=0.5; /* Option w */ double wgt_val_2=0.5; /* Option w */ extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ int *in_id_1_arr; int *in_id_2_arr; int abb_arg_nbr=0; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_idx; int fl_nbr=0; int fl_in_fmt_1; /* [enm] Input file format */ int fl_in_fmt_2; /* [enm] Input file format */ int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int fll_md_old; /* [enm] Old fill mode */ int has_mss_val=False; int idx; int jdx; int in_id_1; int in_id_2; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_xtr; int nbr_ntp; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; lmt_sct **aux=NULL_CEWI; /* Auxiliary coordinate limits */ lmt_sct **lmt; lmt_all_sct **lmt_all_lst; /* List of *lmt_all structures */ nm_id_sct *dmn_lst; nm_id_sct *xtr_lst=NULL; /* xtr_lst may be alloc()'d from NULL with -c option */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ val_unn val_gnr_unn; /* Generic container for arrival point or weight */ var_sct *wgt_1=NULL_CEWI; var_sct *wgt_2=NULL_CEWI; var_sct *wgt_out_1=NULL; var_sct *wgt_out_2=NULL; var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out; var_sct **var_prc_1; var_sct **var_prc_2; var_sct **var_prc_out; #ifdef ENABLE_MPI /* Declare all MPI-specific variables here */ MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */ nco_bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */ int fl_nm_lng; /* [nbr] Output file name length */ int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */ int msg_tag_typ; /* [enm] MPI message tag type */ int prc_rnk; /* [idx] Process rank */ int prc_nbr=0; /* [nbr] Number of MPI processes */ int tkn_wrt_rsp; /* [enm] Response to request for write token */ int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */ int rnk_wrk; /* [idx] Worker rank */ int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */ #endif /* !ENABLE_MPI */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"7",no_argument,0,'7'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"interpolate",required_argument,0,'i'}, {"ntp",required_argument,0,'i'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"suspend", no_argument,0,'S'}, {"thr_nbr",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"weight",required_argument,0,'w'}, {"wgt_var",no_argument,0,'w'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ #ifdef ENABLE_MPI /* MPI Initialization */ MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr); MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk); #endif /* !ENABLE_MPI */ /* Start clock and save command line */ cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* The debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'i': /* Name of variable to guide interpolation. Default is none */ ntp_lst_in=nco_lst_prs_2D(optarg,",",&nbr_ntp); if(nbr_ntp > 2){ (void)fprintf(stdout,"%s: ERROR too many arguments to -i\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ ntp_nm=ntp_lst_in[0]; ntp_val_out=strtod(ntp_lst_in[1],&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtod",sng_cnv_rcd); CMD_LN_NTP_VAR=True; CMD_LN_NTP_WGT=False; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; #ifdef ENABLE_MPI case 'S': /* Suspend with signal handler to facilitate debugging */ if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stdout,"%s: ERROR Could not install suspend handler.\n",nco_prg_nm); while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */ break; #endif /* !ENABLE_MPI */ case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'w': /* Weight(s) for interpolation. Default is wgt_val_1=wgt_val_2=0.5 */ ntp_lst_in=nco_lst_prs_2D(optarg,",",&nbr_ntp); if(nbr_ntp > 2){ (void)fprintf(stdout,"%s: ERROR too many arguments to -w\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); }else if(nbr_ntp == 2){ wgt_val_1=strtod(ntp_lst_in[0],&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(ntp_lst_in[0],"strtod",sng_cnv_rcd); wgt_val_2=strtod(ntp_lst_in[1],&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(ntp_lst_in[1],"strtod",sng_cnv_rcd); }else if(nbr_ntp == 1){ wgt_val_1=strtod(ntp_lst_in[0],&sng_cnv_rcd); if(*sng_cnv_rcd) nco_sng_cnv_err(ntp_lst_in[0],"strtod",sng_cnv_rcd); wgt_val_2=1.0-wgt_val_1; } /* end else */ CMD_LN_NTP_WGT=True; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ if(CMD_LN_NTP_VAR && CMD_LN_NTP_WGT){ (void)fprintf(stdout,"%s: ERROR interpolating variable (-i) and fixed weight(s) (-w) both set\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); }else if(!CMD_LN_NTP_VAR && !CMD_LN_NTP_WGT){ (void)fprintf(stdout,"%s: ERROR interpolating variable (-i) or fixed weight(s) (-w) must be set\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end else */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Make uniform list of user-specified chunksizes */ if(cnk_nbr > 0) cnk_dmn=nco_cnk_prs(cnk_nbr,cnk_arg); /* Make uniform list of user-specified dimension limits */ lmt=nco_lmt_prs(lmt_nbr,lmt_arg); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_1_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); in_id_2_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filenames */ fl_idx=0; /* Input file _1 */ fl_in_1=nco_fl_nm_prs(fl_in_1,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_1); /* Make sure file is on local system and is readable or die trying */ fl_in_1=nco_fl_mk_lcl(fl_in_1,fl_pth_lcl,&FILE_1_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"local file %s:\n",fl_in_1); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx= nco_dbg_fl) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_2); /* Make sure file is on local system and is readable or die trying */ fl_in_2=nco_fl_mk_lcl(fl_in_2,fl_pth_lcl,&FILE_2_RETRIEVED_FROM_REMOTE_LOCATION); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"local file %s:\n",fl_in_2); /* Open file once per thread to improve caching */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; for(thr_idx=0;thr_idx 0){ int aux_idx_nbr; aux=nco_aux_evl(in_id_1,aux_nbr,aux_arg,&aux_idx_nbr); if(aux_idx_nbr > 0){ lmt=(lmt_sct **)nco_realloc(lmt,(lmt_nbr+aux_idx_nbr)*sizeof(lmt_sct *)); int lmt_nbr_new=lmt_nbr+aux_idx_nbr; int aux_idx=0; for(int lmt_idx=lmt_nbr;lmt_idx 1) xtr_lst=nco_lst_srt_nm_id(xtr_lst,xtr_nbr,False); /* We now have final list of variables to extract. Phew. */ /* Find coordinate/dimension values associated with user-specified limits NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ for(idx=0;idx 0) (void)nco_dmn_lmt_all_mrg(dmn_out,nbr_dmn_xtr,lmt_all_lst,nbr_dmn_fl); /* Fill-in variable structure list for all extracted variables */ var=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); var_out=(var_sct **)nco_malloc(xtr_nbr*sizeof(var_sct *)); for(idx=0;idx 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); #ifdef ENABLE_MPI /* Initialize MPI task information */ if(prc_nbr > 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr); #endif /* !ENABLE_MPI */ /* Define dimensions in output file */ (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_xtr); /* Define variables in output file, copy their attributes */ (void)nco_var_dfn(in_id_1,fl_out,out_id,var_out,xtr_nbr,(dmn_sct **)NULL,(int)0,nco_pck_plc_nil,nco_pck_map_nil,dfl_lvl); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ #ifdef ENABLE_MPI } /* prc_rnk != rnk_mgr */ /* Manager obtains output filename and broadcasts to workers */ if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); MPI_Bcast(&fl_nm_lng,1,MPI_INT,0,MPI_COMM_WORLD); if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char)); MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,0,MPI_COMM_WORLD); if(prc_rnk == rnk_mgr){ /* MPI manager code */ TKN_WRT_FREE=False; #endif /* !ENABLE_MPI */ /* Copy variable data for non-processed variables */ (void)nco_msa_var_val_cpy(in_id_1,out_id,var_fix,nbr_var_fix,lmt_all_lst,nbr_dmn_fl); #ifdef ENABLE_MPI /* Close output file so workers can open it */ nco_close(out_id); TKN_WRT_FREE=True; } /* prc_rnk != rnk_mgr */ #endif /* !ENABLE_MPI */ /* Perform various error-checks on input file */ if(False) (void)nco_fl_cmp_err_chk(); /* ncflint-specific stuff: */ /* Find the weighting variable in input file */ if(CMD_LN_NTP_VAR){ int ntp_id_1; int ntp_id_2; var_sct *ntp_1; var_sct *ntp_2; var_sct *ntp_var_out; /* Turn arrival point into pseudo-variable */ val_gnr_unn.d=ntp_val_out; /* Generic container for arrival point or weight */ ntp_var_out=scl_mk_var(val_gnr_unn,NC_DOUBLE); rcd=nco_inq_varid(in_id_1,ntp_nm,&ntp_id_1); rcd=nco_inq_varid(in_id_2,ntp_nm,&ntp_id_2); ntp_1=nco_var_fll(in_id_1,ntp_id_1,ntp_nm,dim,nbr_dmn_xtr); ntp_2=nco_var_fll(in_id_2,ntp_id_2,ntp_nm,dim,nbr_dmn_xtr); /* Currently, only support scalar variables */ if(ntp_1->sz > 1 || ntp_2->sz > 1){ (void)fprintf(stdout,"%s: ERROR interpolation variable %s must be scalar\n",nco_prg_nm_get(),ntp_nm); nco_exit(EXIT_FAILURE); } /* end if */ /* Retrieve interpolation variable */ /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_var_get(in_id_1,ntp_1); (void)nco_var_get(in_id_2,ntp_2); /* Weights must be NC_DOUBLE */ ntp_1=nco_var_cnf_typ((nc_type)NC_DOUBLE,ntp_1); ntp_2=nco_var_cnf_typ((nc_type)NC_DOUBLE,ntp_2); /* Check for degenerate case */ if(ntp_1->val.dp[0] == ntp_2->val.dp[0]){ (void)fprintf(stdout,"%s: ERROR Interpolation variable %s is identical (%g) in input files, therefore unable to interpolate.\n",nco_prg_nm_get(),ntp_nm,ntp_1->val.dp[0]); nco_exit(EXIT_FAILURE); } /* end if */ /* Turn weights into pseudo-variables */ wgt_1=nco_var_dpl(ntp_2); wgt_2=nco_var_dpl(ntp_var_out); /* Subtract to find interpolation distances */ (void)nco_var_sbt(ntp_1->type,ntp_1->sz,ntp_1->has_mss_val,ntp_1->mss_val,ntp_var_out->val,wgt_1->val); (void)nco_var_sbt(ntp_1->type,ntp_1->sz,ntp_1->has_mss_val,ntp_1->mss_val,ntp_1->val,wgt_2->val); (void)nco_var_sbt(ntp_1->type,ntp_1->sz,ntp_1->has_mss_val,ntp_1->mss_val,ntp_1->val,ntp_2->val); /* Normalize to obtain final interpolation weights */ (void)nco_var_dvd(wgt_1->type,wgt_1->sz,wgt_1->has_mss_val,wgt_1->mss_val,ntp_2->val,wgt_1->val); (void)nco_var_dvd(wgt_2->type,wgt_2->sz,wgt_2->has_mss_val,wgt_2->mss_val,ntp_2->val,wgt_2->val); if(ntp_1) ntp_1=nco_var_free(ntp_1); if(ntp_2) ntp_2=nco_var_free(ntp_2); if(ntp_var_out) ntp_var_out=nco_var_free(ntp_var_out); } /* end if CMD_LN_NTP_VAR */ if(CMD_LN_NTP_WGT){ val_gnr_unn.d=wgt_val_1; /* Generic container for arrival point or weight */ wgt_1=scl_mk_var(val_gnr_unn,NC_DOUBLE); val_gnr_unn.d=wgt_val_2; /* Generic container for arrival point or weight */ wgt_2=scl_mk_var(val_gnr_unn,NC_DOUBLE); } /* end if CMD_LN_NTP_WGT */ if(nco_dbg_lvl > nco_dbg_scl) (void)fprintf(stderr,"wgt_1 = %g, wgt_2 = %g\n",wgt_1->val.dp[0],wgt_2->val.dp[0]); /* Create structure list for second file */ var_prc_2=(var_sct **)nco_malloc(nbr_var_prc*sizeof(var_sct *)); /* Loop over each interpolated variable */ #ifdef ENABLE_MPI if(prc_rnk == rnk_mgr){ /* MPI manager code */ /* Compensate for incrementing on each worker's first message */ var_wrt_nbr=-prc_nbr+1; idx=0; /* While variables remain to be processed or written... */ while(var_wrt_nbr < nbr_var_prc){ /* Receive message from any worker */ MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); /* Obtain MPI message tag type */ msg_tag_typ=mpi_stt.MPI_TAG; /* Get sender's prc_rnk */ rnk_wrk=wrk_id_bfr[0]; /* Allocate next variable, if any, to worker */ if(msg_tag_typ == msg_tag_wrk_rqs){ var_wrt_nbr++; /* [nbr] Number of variables written */ /* Worker closed output file before sending msg_tag_wrk_rqs */ TKN_WRT_FREE=True; if(idx > nbr_var_prc-1){ msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ msg_bfr[1]=out_id; /* Output file ID */ }else{ /* Tell requesting worker to allocate space for next variable */ msg_bfr[0]=idx; /* [idx] Variable to be processed */ msg_bfr[1]=out_id; /* Output file ID */ msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ /* Point to next variable on list */ idx++; } /* endif idx */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); /* msg_tag_typ != msg_tag_wrk_rqs */ }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ /* Allocate token if free, else ask worker to try later */ if(TKN_WRT_FREE){ TKN_WRT_FREE=False; msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ }else{ msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ } /* !TKN_WRT_FREE */ MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ } /* end while var_wrt_nbr < nbr_var_prc */ }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ wrk_id_bfr[0]=prc_rnk; while(1){ /* While work remains... */ /* Send msg_tag_wrk_rqs */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); /* Receive msg_tag_wrk_rsp */ MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,0,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); idx=msg_bfr[0]; out_id=msg_bfr[1]; if(idx == idx_all_wrk_ass) break; else{ var_prc_out[idx]->id=msg_bfr[2]; /* Process this variable same as UP code */ #else /* !ENABLE_MPI */ #ifdef _OPENMP /* OpenMP notes: shared(): msk and wgt are not altered within loop private(): wgt_avg does not need initialization */ #pragma omp parallel for default(none) firstprivate(wgt_1,wgt_2,wgt_out_1,wgt_out_2) private(DO_CONFORM,idx,in_id_1,in_id_2,has_mss_val) shared(MUST_CONFORM,nco_dbg_lvl,dim,fl_in_1,fl_in_2,fl_out,in_id_1_arr,in_id_2_arr,nbr_dmn_xtr,nbr_var_prc,out_id,nco_prg_nm,var_prc_1,var_prc_2,var_prc_out,lmt_all_lst,nbr_dmn_fl) #endif /* !_OPENMP */ /* UP and SMP codes main loop over variables */ for(idx=0;idx= nco_dbg_var) (void)fprintf(fp_stderr,"%s, ",var_prc_1[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); in_id_1=in_id_1_arr[omp_get_thread_num()]; in_id_2=in_id_2_arr[omp_get_thread_num()]; var_prc_2[idx]=nco_var_dpl(var_prc_1[idx]); (void)nco_var_mtd_refresh(in_id_2,var_prc_2[idx]); /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ (void)nco_msa_var_get(in_id_1,var_prc_1[idx],lmt_all_lst,nbr_dmn_fl); (void)nco_msa_var_get(in_id_2,var_prc_2[idx],lmt_all_lst,nbr_dmn_fl); wgt_out_1=nco_var_cnf_dmn(var_prc_1[idx],wgt_1,wgt_out_1,MUST_CONFORM,&DO_CONFORM); wgt_out_2=nco_var_cnf_dmn(var_prc_2[idx],wgt_2,wgt_out_2,MUST_CONFORM,&DO_CONFORM); var_prc_1[idx]=nco_var_cnf_typ((nc_type)NC_DOUBLE,var_prc_1[idx]); var_prc_2[idx]=nco_var_cnf_typ((nc_type)NC_DOUBLE,var_prc_2[idx]); /* Allocate and, if necesssary, initialize space for processed variable */ var_prc_out[idx]->sz=var_prc_1[idx]->sz; /* NB: must not try to free() same tally buffer twice */ /* var_prc_out[idx]->tally=var_prc_1[idx]->tally=(long *)nco_malloc(var_prc_out[idx]->sz*sizeof(long int));*/ var_prc_out[idx]->tally=(long *)nco_malloc(var_prc_out[idx]->sz*sizeof(long int)); (void)nco_zero_long(var_prc_out[idx]->sz,var_prc_out[idx]->tally); /* Weight variable by taking product of weight with variable */ (void)nco_var_mlt(var_prc_1[idx]->type,var_prc_1[idx]->sz,var_prc_1[idx]->has_mss_val,var_prc_1[idx]->mss_val,wgt_out_1->val,var_prc_1[idx]->val); (void)nco_var_mlt(var_prc_2[idx]->type,var_prc_2[idx]->sz,var_prc_2[idx]->has_mss_val,var_prc_2[idx]->mss_val,wgt_out_2->val,var_prc_2[idx]->val); /* Change missing_value of var_prc_2, if any, to missing_value of var_prc_1, if any */ has_mss_val=nco_mss_val_cnf(var_prc_1[idx],var_prc_2[idx]); /* NB: fxm: use tally to determine when to "unweight" answer? TODO */ (void)nco_var_add_tll_ncflint(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,var_prc_1[idx]->mss_val,var_prc_out[idx]->tally,var_prc_1[idx]->val,var_prc_2[idx]->val); /* Re-cast output variable to original type */ var_prc_2[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc_2[idx]); #ifdef ENABLE_MPI /* Obtain token and prepare to write */ while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ wrk_id_bfr[0]=prc_rnk; MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); tkn_wrt_rsp=msg_bfr[0]; /* Wait then re-send request */ if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; } /* end while loop waiting for write token */ /* Worker has token---prepare to write */ if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ if(RAM_OPEN) md_open=NC_WRITE|NC_SHARE|NC_DISKLESS; else md_open=NC_WRITE|NC_SHARE; rcd=nco_fl_open(fl_out_tmp,md_open,&bfr_sz_hnt,&out_id); /* Set chunksize parameters */ if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC) (void)nco_cnk_sz_set(out_id,lmt_all_lst,nbr_dmn_fl,&cnk_map,&cnk_plc,cnk_sz_scl,cnk_dmn,cnk_nbr); /* Turn off default filling behavior to enhance efficiency */ nco_set_fill(out_id,NC_NOFILL,&fll_md_old); #else /* !ENABLE_MPI */ #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ #endif /* !ENABLE_MPI */ /* Common code for UP, SMP, and MPI */ { /* begin OpenMP critical */ /* Copy interpolations to output file */ if(var_prc_out[idx]->nbr_dim == 0){ (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_2[idx]->val.vp,var_prc_2[idx]->type); }else{ /* end if variable is scalar */ (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_2[idx]->val.vp,var_prc_2[idx]->type); } /* end else */ } /* end OpenMP critical */ /* Free dynamically allocated buffers */ if(var_prc_1[idx]) var_prc_1[idx]=nco_var_free(var_prc_1[idx]); if(var_prc_2[idx]) var_prc_2[idx]=nco_var_free(var_prc_2[idx]); if(var_prc_out[idx]) var_prc_out[idx]=nco_var_free(var_prc_out[idx]); #ifdef ENABLE_MPI /* Close output file and increment written counter */ nco_close(out_id); var_wrt_nbr++; } /* endif tkn_wrt_rqs_xcp */ } /* end else !idx_all_wrk_ass */ } /* end while loop requesting work/token */ } /* endif Worker */ #else /* !ENABLE_MPI */ } /* end (OpenMP parallel for) loop over idx */ #endif /* !ENABLE_MPI */ if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Close input netCDF files */ for(thr_idx=0;thr_idxlmt_dmn_nbr;jdx++) lmt_all_lst[idx]->lmt_dmn[jdx]=nco_lmt_free(lmt_all_lst[idx]->lmt_dmn[jdx]); if(nbr_dmn_fl > 0) lmt_all_lst=nco_lmt_all_lst_free(lmt_all_lst,nbr_dmn_fl); lmt=(lmt_sct**)nco_free(lmt); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) aux=(lmt_sct **)nco_free(aux); /* Free chunking information */ for(idx=0;idx 0) cnk_dmn=nco_cnk_lst_free(cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); /* Free variable lists */ /* ncflint free()s _prc variables at end of main loop */ var=(var_sct **)nco_free(var); var_out=(var_sct **)nco_free(var_out); var_prc_out=(var_sct **)nco_free(var_prc_out); if(nbr_var_fix > 0) var_fix=nco_var_lst_free(var_fix,nbr_var_fix); if(nbr_var_fix > 0) var_fix_out=nco_var_lst_free(var_fix_out,nbr_var_fix); } /* !flg_cln */ #ifdef ENABLE_MPI MPI_Finalize(); #endif /* !ENABLE_MPI */ if(rcd != NC_NOERR) nco_err_exit(rcd,"main"); nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/ncra.c0000644000674300045400000021657612301143755014434 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncra.c,v 1.515 2014/02/19 15:04:13 zender Exp $ */ /* This single source file compiles into three separate executables: ncra -- netCDF record averager nces -- netCDF ensemble statistics ncrcat -- netCDF record concatenator */ /* Purpose: Compute averages or extract series of specified hyperslabs of specfied variables of multiple input netCDF files and output them to a single file. */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 The full license text is at http://www.gnu.org/copyleft/gpl.html and in the file nco/doc/LICENSE in the NCO source distribution. As a special exception to the terms of the GPL, you are permitted to link the NCO source code with the HDF, netCDF, OPeNDAP, and UDUnits libraries and to distribute the resulting executables under the terms of the GPL, but in addition obeying the extra stipulations of the HDF, netCDF, OPeNDAP, and UDUnits licenses. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The original author of this software, Charlie Zender, seeks to improve it with your suggestions, contributions, bug-reports, and patches. Please contact the NCO project at http://nco.sf.net or write to Charlie Zender Department of Earth System Science University of California, Irvine Irvine, CA 92697-3100 */ /* URL: http://nco.cvs.sf.net/nco/nco/src/nco/ncra.c Usage: ncra -O -n 3,4,1 -p ${HOME}/nco/data h0001.nc ~/foo.nc ncra -O -n 3,4,1 -p ${HOME}/nco/data -l ${HOME} h0001.nc ~/foo.nc ncra -O -n 3,4,1 -p /ZENDER/tmp -l ${HOME}/nco/data h0001.nc ~/foo.nc ncrcat -O -C -d time,0,5,4,2 -v time -p ~/nco/data in.nc ~/foo.nc ncra -O -C -d time,0,5,4,2 -v time -p ~/nco/data in.nc ~/foo.nc ncra -O -C --mro -d time,0,5,4,2 -v time -p ~/nco/data in.nc ~/foo.nc scp ~/nco/src/nco/ncra.c esmf.ess.uci.edu:nco/src/nco nces in.nc in.nc ~/foo.nc nces -O -n 3,4,1 -p ${HOME}/nco/data h0001.nc ~/foo.nc nces -O -n 3,4,1 -p ${HOME}/nco/data -l ${HOME} h0001.nc ~/foo.nc nces -O -n 3,4,1 -p /ZENDER/tmp -l ${HOME} h0001.nc ~/foo.nc ncra -Y ncge -O -p ~/nco/data mdl.nc ~/foo.nc ncra -Y ncge -O --nsm_sfx=_avg -p ~/nco/data mdl.nc ~/foo.nc */ #ifdef HAVE_CONFIG_H # include /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* Internationalization i18n, Linux Journal 200211 p. 57--59 */ #ifdef I18N # include /* Internationalization i18n */ # include /* Locale setlocale() */ # define _(sng) gettext (sng) # define gettext_noop(sng) (sng) # define N_(sng) gettext_noop(sng) #endif /* I18N */ /* Supply stub gettext() function in case i18n failed */ #ifndef _LIBINTL_H # define gettext(foo) foo #endif /* _LIBINTL_H */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* Personal headers */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "libnco.h" /* netCDF Operator (NCO) library */ /* Define inline'd functions in header so source is visible to calling files C99 only: Declare prototype in exactly one header http://www.drdobbs.com/the-new-c-inline-functions/184401540 */ extern int min_int(int a, int b); extern int max_int(int a, int b); inline int min_int(int a, int b){return (a < b) ? a : b;} inline int max_int(int a, int b){return (a > b) ? a : b;} extern long min_lng(long a, long b); extern long max_lng(long a, long b); inline long min_lng(long a, long b){return (a < b) ? a : b;} inline long max_lng(long a, long b){return (a > b) ? a : b;} int main(int argc,char **argv) { char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in; char **grp_lst_in=NULL_CEWI; char **var_lst_in=NULL_CEWI; char *aux_arg[NC_MAX_DIMS]; char *cmd_ln; char *cnk_arg[NC_MAX_DIMS]; char *cnk_map_sng=NULL_CEWI; /* [sng] Chunking map */ char *cnk_plc_sng=NULL_CEWI; /* [sng] Chunking policy */ char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_out_tmp=NULL_CEWI; char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *grp_out_fll=NULL; /* [sng] Group name */ char *lmt_arg[NC_MAX_DIMS]; char *nco_op_typ_sng=NULL_CEWI; /* [sng] Operation type Option y */ char *nco_pck_plc_sng=NULL_CEWI; /* [sng] Packing policy Option P */ char *nsm_sfx=NULL; /* [sng] Ensemble suffix */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncra.c,v 1.515 2014/02/19 15:04:13 zender Exp $"; const char * const CVS_Revision="$Revision: 1.515 $"; const char * const opt_sht_lst="3467ACcD:d:FG:g:HhL:l:n:Oo:p:P:rRt:v:X:xY:y:-:"; cnk_sct cnk; /* [sct] Chunking structure */ #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ dmn_sct **dim=NULL; /* CEWI */ dmn_sct **dmn_out=NULL; /* CEWI */ extern char *optarg; extern int optind; /* Using naked stdin/stdout/stderr in parallel region generates warning Copy appropriate filehandle to variable scoped shared in parallel clause */ FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ gpe_sct *gpe=NULL; /* [sng] Group Path Editing (GPE) structure */ int *in_id_arr; int abb_arg_nbr=0; int aux_nbr=0; /* [nbr] Number of auxiliary coordinate hyperslabs specified */ int cnk_map=nco_cnk_map_nil; /* [enm] Chunking map */ int cnk_nbr=0; /* [nbr] Number of chunk sizes */ int cnk_plc=nco_cnk_plc_nil; /* [enm] Chunking policy */ int dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ int fl_idx; int fl_in_fmt; /* [enm] Input file format */ int fl_nbr=0; int fl_out_fmt=NCO_FORMAT_UNDEFINED; /* [enm] Output file format */ int flg_input_complete_nbr=0; /* [nbr] Number of record dimensions completed */ int fll_md_old; /* [enm] Old fill mode */ int grp_lst_in_nbr=0; /* [nbr] Number of groups explicitly specified by user */ int idx=int_CEWI; int in_id; int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ int md_open; /* [enm] Mode flag for nc_open() call */ int nbr_dmn_fl; int nbr_dmn_xtr=0; int nbr_var_fix; /* nbr_var_fix gets incremented */ int nbr_var_fl; int nbr_var_prc; /* nbr_var_prc gets incremented */ int nbr_rec; /* [nbr] (ncra) Number of record dimensions */ int dmn_rec_fl; int nco_op_typ=nco_op_avg; /* [enm] Default operation is averaging */ int nco_pck_plc=nco_pck_plc_nil; /* [enm] Default packing is none */ int opt; int out_id; int rcd=NC_NOERR; /* [rcd] Return code */ int thr_idx; /* [idx] Index of current thread */ int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ int var_lst_in_nbr=0; int xtr_nbr=0; /* xtr_nbr won't otherwise be set for -c with no -v */ int idx_rec=0; int grp_id; /* [ID] Group ID */ int grp_out_id; /* [ID] Group ID (output) */ int var_out_id; /* [ID] Variable ID (output) */ long idx_rec_crr_in; /* [idx] Index of current record in current input file */ long *idx_rec_out=NULL; /* [idx] Index of current record in output file (0 is first, ...) */ long *rec_in_cml=NULL; /* [nbr] Number of records, read or not, in all processed files */ long *rec_usd_cml=NULL; /* [nbr] Cumulative number of input records used (catenated by ncrcat or operated on by ncra) */ long rec_dmn_sz=0L; /* [idx] Size of record dimension, if any, in current file (increments by srd) */ long rec_rmn_prv_ssc=0L; /* [idx] Records remaining to be read in current subcycle group */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ nco_bool *REC_LST_DSR=NULL; /* [flg] Record is last desired from all input files */ nco_bool *flg_input_complete=NULL; /* [flg] All requested records in record dimension have been read */ nco_bool CNV_ARM; nco_bool CNV_CCM_CCSM_CF; nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ nco_bool FLG_BFR_NRM=False; /* [flg] Current output buffers need normalization */ nco_bool FLG_MRO=False; /* [flg] Multi-Record Output */ nco_bool FL_LST_IN_APPEND=True; /* Option H */ nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FL_RTR_RMT_LCN; nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool FORTRAN_IDX_CNV=False; /* Option F */ nco_bool GRP_VAR_UNN=False; /* [flg] Select union of specified groups and variables */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool MSA_USR_RDR=False; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ nco_bool RAM_CREATE=False; /* [flg] Create file in RAM */ nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool REC_APN=False; /* [flg] Append records directly to output file */ nco_bool REC_FRS_GRP=False; /* [flg] Record is first in current group */ nco_bool REC_LST_GRP=False; /* [flg] Record is last in current group */ nco_bool REC_SRD_LST=False; /* [flg] Record belongs to last stride of current file */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool WRT_TMP_FL=True; /* [flg] Write output to temporary file */ nco_bool flg_cll_mth=True; /* [flg] Add/modify cell_methods attributes */ nco_bool flg_cln=True; /* [flg] Clean memory prior to exit */ nco_bool flg_skp1; /* [flg] Current record is not dimension of this variable */ nco_bool flg_skp2; /* [flg] Current record is not dimension of this variable */ nco_int base_time_srt=nco_int_CEWI; nco_int base_time_crr=nco_int_CEWI; size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t cnk_sz_byt=0UL; /* [B] Chunk size in bytes */ size_t cnk_sz_scl=0UL; /* [nbr] Chunk size scalar */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ var_sct **var; var_sct **var_fix; var_sct **var_fix_out; var_sct **var_out=NULL_CEWI; var_sct **var_prc; var_sct **var_prc_out; trv_sct *var_trv; /* [sct] Variable GTT object */ trv_tbl_sct *trv_tbl; /* [lst] Traversal table */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ lmt_sct **lmt_rec=NULL; /* [lst] (ncra) Record dimensions */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cll_mth",no_argument,0,0}, /* [flg] Add/modify cell_methods attributes */ {"cell_methods",no_argument,0,0}, /* [flg] Add/modify cell_methods attributes */ {"no_cll_mth",no_argument,0,0}, /* [flg] Do not add/modify cell_methods attributes */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dbl",no_argument,0,0}, /* [flg] Arithmetic convention: promote float to double */ {"flt",no_argument,0,0}, /* [flg] Arithmetic convention: keep single-precision */ {"rth_dbl",no_argument,0,0}, /* [flg] Arithmetic convention: promote float to double */ {"rth_flt",no_argument,0,0}, /* [flg] Arithmetic convention: keep single-precision */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"hdf_upk",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"hdf_unpack",no_argument,0,0}, /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ {"md5_dgs",no_argument,0,0}, /* [flg] Perform MD5 digests */ {"md5_digest",no_argument,0,0}, /* [flg] Perform MD5 digests */ {"mro",no_argument,0,0}, /* [flg] Multi-Record Output */ {"multi_record_output",no_argument,0,0}, /* [flg] Multi-Record Output */ {"msa_usr_rdr",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"msa_user_order",no_argument,0,0}, /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ {"nsm_fl",no_argument,0,0}, {"nsm_grp",no_argument,0,0}, {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"rec_apn",no_argument,0,0}, /* [flg] Append records directly to output file */ {"record_append",no_argument,0,0}, /* [flg] Append records directly to output file */ {"wrt_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"write_tmp_fl",no_argument,0,0}, /* [flg] Write output to temporary file */ {"no_tmp_fl",no_argument,0,0}, /* [flg] Do not write output to temporary file */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"cnk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"chunk_map",required_argument,0,0}, /* [nbr] Chunking map */ {"cnk_plc",required_argument,0,0}, /* [nbr] Chunking policy */ {"chunk_policy",required_argument,0,0}, /* [nbr] Chunking policy */ {"cnk_byt",required_argument,0,0}, /* [B] Chunk size in bytes */ {"chunk_byte",required_argument,0,0}, /* [B] Chunk size in bytes */ {"cnk_scl",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"chunk_scalar",required_argument,0,0}, /* [nbr] Chunk size scalar */ {"cnk_dmn",required_argument,0,0}, /* [nbr] Chunk size */ {"chunk_dimension",required_argument,0,0}, /* [nbr] Chunk size */ {"fl_fmt",required_argument,0,0}, {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, {"nsm_sfx",required_argument,0,0}, {"ensemble_suffix",required_argument,0,0}, /* Long options with short counterparts */ {"3",no_argument,0,'3'}, {"4",no_argument,0,'4'}, {"64bit",no_argument,0,'4'}, {"netcdf4",no_argument,0,'4'}, {"append",no_argument,0,'A'}, {"coords",no_argument,0,'c'}, {"crd",no_argument,0,'c'}, {"no-coords",no_argument,0,'C'}, {"no-crd",no_argument,0,'C'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"dimension",required_argument,0,'d'}, {"dmn",required_argument,0,'d'}, {"fortran",no_argument,0,'F'}, {"ftn",no_argument,0,'F'}, {"fl_lst_in",no_argument,0,'H'}, {"file_list",no_argument,0,'H'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"dfl_lvl",required_argument,0,'L'}, /* [enm] Deflate level */ {"deflate",required_argument,0,'L'}, /* [enm] Deflate level */ {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"nintap",required_argument,0,'n'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"pack",required_argument,0,'P'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"revision",no_argument,0,'r'}, {"thr_nbr",required_argument,0,'t'}, {"threads",required_argument,0,'t'}, {"omp_num_threads",required_argument,0,'t'}, {"variable",required_argument,0,'v'}, {"auxiliary",required_argument,0,'X'}, {"exclude",no_argument,0,'x'}, {"xcl",no_argument,0,'x'}, {"pseudonym",required_argument,0,'Y'}, {"program",required_argument,0,'Y'}, {"prg_nm",required_argument,0,'Y'}, {"math",required_argument,0,'y'}, {"operation",required_argument,0,'y'}, {"op_typ",required_argument,0,'y'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ #ifdef _LIBINTL_H setlocale(LC_ALL,""); /* LC_ALL sets all localization tokens to same value */ bindtextdomain("nco","/home/zender/share/locale"); /* ${LOCALEDIR} is e.g., /usr/share/locale */ /* MO files should be in ${LOCALEDIR}/es/LC_MESSAGES */ textdomain("nco"); /* PACKAGE is name of program */ #endif /* not _LIBINTL_H */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_byt") || !strcmp(opt_crr,"chunk_byte")){ cnk_sz_byt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk_byt */ if(!strcmp(opt_crr,"cnk_dmn") || !strcmp(opt_crr,"chunk_dimension")){ /* Copy limit argument for later processing */ cnk_arg[cnk_nbr]=(char *)strdup(optarg); cnk_nbr++; } /* endif cnk */ if(!strcmp(opt_crr,"cnk_scl") || !strcmp(opt_crr,"chunk_scalar")){ cnk_sz_scl=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_map") || !strcmp(opt_crr,"chunk_map")){ /* Chunking map */ cnk_map_sng=(char *)strdup(optarg); cnk_map=nco_cnk_map_get(cnk_map_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cnk_plc") || !strcmp(opt_crr,"chunk_policy")){ /* Chunking policy */ cnk_plc_sng=(char *)strdup(optarg); cnk_plc=nco_cnk_plc_get(cnk_plc_sng); } /* endif cnk */ if(!strcmp(opt_crr,"cll_mth") || !strcmp(opt_crr,"cell_methods")) flg_cll_mth=True; /* [flg] Add/modify cell_methods attributes */ if(!strcmp(opt_crr,"no_cll_mth") || !strcmp(opt_crr,"no_cell_methods")) flg_cll_mth=False; /* [flg] Add/modify cell_methods attributes */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); if(!strcmp(opt_crr,"dbl") || !strcmp(opt_crr,"rth_dbl")) nco_rth_cnv=nco_rth_flt_dbl; /* [flg] Arithmetic convention: promote float to double */ if(!strcmp(opt_crr,"flt") || !strcmp(opt_crr,"rth_flt")) nco_rth_cnv=nco_rth_flt_flt; /* [flg] Arithmetic convention: keep single-precision */ if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdf_upk") || !strcmp(opt_crr,"hdf_unpack")) nco_upk_cnv=nco_upk_HDF; /* [flg] HDF unpack convention: unpacked=scale_factor*(packed-add_offset) */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"md5_dgs") || !strcmp(opt_crr,"md5_digest")){ if(!md5) md5=nco_md5_ini(); md5->dgs=True; if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Will perform MD5 digests of input and output hyperslabs\n",nco_prg_nm_get()); } /* endif "md5_dgs" */ if(!strcmp(opt_crr,"mro") || !strcmp(opt_crr,"multi_record_output")) FLG_MRO=True; /* [flg] Multi-Record Output */ if(!strcmp(opt_crr,"msa_usr_rdr") || !strcmp(opt_crr,"msa_user_order")) MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ if(!strcmp(opt_crr,"nsm_fl") || !strcmp(opt_crr,"nsm_file") || !strcmp(opt_crr,"ensemble_file")){ if(nco_prg_nm) nco_prg_nm=(char *)nco_free(nco_prg_nm); nco_prg_nm=nco_prg_prs("ncfe",&nco_prg_id); } /* endif nsm_fl */ if(!strcmp(opt_crr,"nsm_grp") || !strcmp(opt_crr,"nsm_group") || !strcmp(opt_crr,"ensemble_group")){ if(nco_prg_nm) nco_prg_nm=(char *)nco_free(nco_prg_nm); nco_prg_nm=nco_prg_prs("ncge",&nco_prg_id); } /* endif nsm_grp */ if(!strcmp(opt_crr,"nsm_sfx") || !strcmp(opt_crr,"ensemble_suffix")) nsm_sfx=(char *)strdup(optarg); if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"create_ram") || !strcmp(opt_crr,"diskless_all")) RAM_CREATE=True; /* [flg] Open (netCDF3) file(s) in RAM */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"rec_apn") || !strcmp(opt_crr,"record_append")){ REC_APN=True; /* [flg] Append records directly to output file */ FORCE_APPEND=True; } /* endif "rec_apn" */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ if(!strcmp(opt_crr,"wrt_tmp_fl") || !strcmp(opt_crr,"write_tmp_fl")) WRT_TMP_FL=True; if(!strcmp(opt_crr,"no_tmp_fl")) WRT_TMP_FL=False; } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case '3': /* Request netCDF3 output storage format */ fl_out_fmt=NC_FORMAT_CLASSIC; break; case '4': /* Catch-all to prescribe output storage format */ if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; break; case '6': /* Request netCDF3 64-bit offset output storage format */ fl_out_fmt=NC_FORMAT_64BIT; break; case '7': /* Request netCDF4-classic output storage format */ fl_out_fmt=NC_FORMAT_NETCDF4_CLASSIC; break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=True; break; case 'C': /* Extract all coordinates associated with extracted variables? */ EXTRACT_ASSOCIATED_COORDINATES=False; break; case 'c': EXTRACT_ALL_COORDINATES=True; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'd': /* Copy limit argument for later processing */ lmt_arg[lmt_nbr]=(char *)strdup(optarg); lmt_nbr++; break; case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; break; case 'G': /* Apply Group Path Editing (GPE) to output group */ /* NB: GNU getopt() optional argument syntax is ugly (requires "=" sign) so avoid it http://stackoverflow.com/questions/1052746/getopt-does-not-parse-optional-arguments-to-parameters */ gpe=nco_gpe_prs_arg(optarg); fl_out_fmt=NC_FORMAT_NETCDF4; break; case 'g': /* Copy group argument for later processing */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); grp_lst_in=nco_lst_prs_2D(optarg_lcl,",",&grp_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'H': /* Toggle writing input file list attribute */ FL_LST_IN_APPEND=!FL_LST_IN_APPEND; break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'L': /* [enm] Deflate level. Default is 0. */ dfl_lvl=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'n': /* NINTAP-style abbreviation of files to average */ fl_lst_abb=nco_lst_prs_2D(optarg,",",&abb_arg_nbr); if(abb_arg_nbr < 1 || abb_arg_nbr > 5){ (void)fprintf(stdout,gettext("%s: ERROR Incorrect abbreviation for file list\n"),nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end if */ break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'P': /* Packing policy */ nco_pck_plc_sng=(char *)strdup(optarg); nco_pck_plc=nco_pck_plc_get(nco_pck_plc_sng); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case 't': /* Thread number */ thr_nbr=(int)strtol(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtol",sng_cnv_rcd); break; case 'v': /* Variables to extract/exclude */ /* Replace commas with hashes when within braces (convert back later) */ optarg_lcl=(char *)strdup(optarg); (void)nco_rx_comma2hash(optarg_lcl); var_lst_in=nco_lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); optarg_lcl=(char *)nco_free(optarg_lcl); xtr_nbr=var_lst_in_nbr; break; case 'X': /* Copy auxiliary coordinate argument for later processing */ aux_arg[aux_nbr]=(char *)strdup(optarg); aux_nbr++; MSA_USR_RDR=True; /* [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ break; case 'x': /* Exclude rather than extract variables specified with -v */ EXCLUDE_INPUT_LIST=True; break; case 'Y': /* Pseudonym */ /* Call nco_prg_prs() to reset pseudonym */ optarg_lcl=(char *)strdup(optarg); if(nco_prg_nm) nco_prg_nm=(char *)nco_free(nco_prg_nm); nco_prg_nm=nco_prg_prs(optarg_lcl,&nco_prg_id); optarg_lcl=(char *)nco_free(optarg_lcl); break; case 'y': /* Operation type */ nco_op_typ_sng=(char *)strdup(optarg); if(nco_prg_id == ncra || nco_prg_id == ncfe) nco_op_typ=nco_op_typ_get(nco_op_typ_sng); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); break; } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); /* Initialize thread information */ thr_nbr=nco_openmp_ini(thr_nbr); in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); /* Open file using appropriate buffer size hints and verbosity */ if(RAM_OPEN) md_open=NC_NOWRITE|NC_DISKLESS; else md_open=NC_NOWRITE; rcd+=nco_fl_open(fl_in,md_open,&bfr_sz_hnt,&in_id); (void)nco_inq_format(in_id,&fl_in_fmt); /* Initialize traversal table */ trv_tbl_init(&trv_tbl); /* Construct GTT, Group Traversal Table (groups,variables,dimensions, limits) */ (void)nco_bld_trv_tbl(in_id,trv_pth,lmt_nbr,lmt_arg,aux_nbr,aux_arg,MSA_USR_RDR,FORTRAN_IDX_CNV,grp_lst_in,grp_lst_in_nbr,var_lst_in,var_lst_in_nbr,EXTRACT_ALL_COORDINATES,GRP_VAR_UNN,EXCLUDE_INPUT_LIST,EXTRACT_ASSOCIATED_COORDINATES,&flg_dne,trv_tbl); /* Check if all input -d dimensions were found */ (void)nco_chk_dmn(lmt_nbr,flg_dne); /* Store ncge ensemble suffix in table */ if(nco_prg_id == ncge && nsm_sfx) trv_tbl->nsm_sfx=nsm_sfx; /* Get number of variables, dimensions, and global attributes in file, file format */ (void)trv_tbl_inq((int *)NULL,(int *)NULL,(int *)NULL,&nbr_dmn_fl,&dmn_rec_fl,(int *)NULL,(int *)NULL,(int *)NULL,&nbr_var_fl,trv_tbl); /* Record handling operators only */ if(nco_prg_id == ncra || nco_prg_id == ncrcat){ /* Build record dimensions array */ (void)nco_bld_rec_dmn(in_id,FORTRAN_IDX_CNV,&lmt_rec,&nbr_rec,trv_tbl); /* Allocate arrays for multi-records cases */ flg_input_complete=(nco_bool *)nco_malloc(nbr_rec*sizeof(nco_bool)); idx_rec_out=(long *)nco_malloc(nbr_rec*sizeof(long)); rec_in_cml=(long *)nco_malloc(nbr_rec*sizeof(long)); rec_usd_cml=(long *)nco_malloc(nbr_rec*sizeof(long)); REC_LST_DSR=(nco_bool *)nco_malloc(nbr_rec*sizeof(nco_bool)); /* Initialize arrays for multi-records cases */ for(idx_rec=0;idx_rec 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); /* Add input file list global attribute */ if(FL_LST_IN_APPEND && HISTORY_APPEND && FL_LST_IN_FROM_STDIN) (void)nco_fl_lst_att_cat(out_id,fl_lst_in,fl_nbr); /* Turn off default filling behavior to enhance efficiency */ (void)nco_set_fill(out_id,NC_NOFILL,&fll_md_old); /* Add cell_methods attributes (before exiting define mode) */ if(nco_prg_id == ncra){ dmn_sct **dmn=NULL_CEWI; int nbr_dmn=nbr_rec; /* Allocate */ dmn=(dmn_sct **)nco_malloc(nbr_dmn*sizeof(dmn_sct *)); /* Make dimension array from limit records array */ (void)nco_dmn_lmt(lmt_rec,nbr_dmn,&dmn); /* Add cell_methods attributes (pass as dimension argument a records-only array) */ if(flg_cll_mth){ if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG dimension list to nco_cnv_cf_cll_mth_add()\n",nco_prg_nm_get()); for(idx=0;idxnm); for(idx=0;idxnm_fll); } /* endif dbg */ rcd+=nco_cnv_cf_cll_mth_add(out_id,var_prc_out,nbr_var_prc,dmn,nbr_dmn,nco_op_typ,gpe,trv_tbl); } /* !flg_cll_mth */ if(nbr_dmn > 0) dmn=nco_dmn_lst_free(dmn,nbr_dmn); } /* !ncra */ /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(out_id); }else{ (void)nco__enddef(out_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Zero start and stride vectors for all output variables */ (void)nco_var_srd_srt_set(var_out,xtr_nbr); /* Copy variable data for non-processed variables */ (void)nco_cpy_fix_var_trv(in_id,out_id,gpe,trv_tbl); /* Write ensemble fixed variables (False parameter) */ if(nco_prg_id_get() == ncge) (void)nco_nsm_dfn_wrt(in_id,out_id,&cnk,dfl_lvl,gpe,False,trv_tbl); /* Close first input netCDF file */ nco_close(in_id); /* Allocate and, if necesssary, initialize accumulation space for processed variables */ for(idx=0;idxsz=var_prc[idx]->sz_rec=var_prc_out[idx]->sz=var_prc_out[idx]->sz_rec; } /* endif */ if(nco_prg_id == ncra || nco_prg_id == ncfe || nco_prg_id == ncge){ var_prc_out[idx]->tally=var_prc[idx]->tally=(long *)nco_malloc(var_prc_out[idx]->sz*sizeof(long)); var_prc_out[idx]->val.vp=(void *)nco_malloc(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type)); if(nco_prg_id == ncfe || nco_prg_id == ncge){ (void)nco_zero_long(var_prc_out[idx]->sz,var_prc_out[idx]->tally); (void)nco_var_zero(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->val); } /* end if ncfe || ncge */ } /* end if */ } /* end loop over idx */ /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; /* Loop over input files */ for(fl_idx=0;fl_idx= nco_dbg_fl) (void)fprintf(stderr,gettext("%s: INFO Input file %d is %s"),nco_prg_nm_get(),fl_idx,fl_in); /* Make sure file is on local system and is readable or die trying */ if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(nco_dbg_lvl >= nco_dbg_fl && FL_RTR_RMT_LCN) (void)fprintf(stderr,gettext(", local file is %s"),fl_in); if(nco_dbg_lvl >= nco_dbg_fl) (void)fprintf(stderr,"\n"); /* Open file once per thread to improve caching */ for(thr_idx=0;thr_idx 0) (void)nco_nsm_ncr(in_id,trv_tbl); }else{ /* ! ncge */ /* Variables may have different ID, missing_value, type, in each file */ for(idx=0;idxnm_fll,trv_tbl); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(in_id,trv->grp_nm_fll,&grp_id); (void)nco_var_mtd_refresh(grp_id,var_prc[idx]); } /* end loop over variables */ } /* ! ncge */ if(nco_prg_id == ncra || nco_prg_id == ncrcat){ /* ncfe and ncge jump to else branch */ /* Loop over number of different record variables in file */ for(idx_rec=0;idx_recgrp_nm_fll,&grp_id); /* Fill record array */ (void)nco_lmt_evl(grp_id,lmt_rec[idx_rec],rec_usd_cml[idx_rec],FORTRAN_IDX_CNV); if(REC_APN){ /* Append records directly to output file */ int rec_dmn_out_id=NCO_REC_DMN_UNDEFINED; /* Get group ID using record group full name */ (void)nco_inq_grp_full_ncid(out_id,lmt_rec[idx_rec]->grp_nm_fll,&grp_out_id); /* Get the dimension ID (rec_dmn_out_id) of the current record, from its name */ (void)nco_inq_dimid(grp_out_id,lmt_rec[idx_rec]->nm,&rec_dmn_out_id); /* Get the size of the record */ (void)nco_inq_dimlen(grp_out_id,rec_dmn_out_id,&idx_rec_out[idx_rec]); } /* !REC_APN */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(fp_stdout,"%s: DEBUG record [%d] #%d<%s>(%ld)\n",nco_prg_nm_get(),idx_rec,lmt_rec[idx_rec]->id,lmt_rec[idx_rec]->nm_fll,lmt_rec[idx_rec]->rec_dmn_sz); /* Two distinct ways to specify MRO are --mro and -d dmn,a,b,c,d,[m,M] */ if(FLG_MRO) lmt_rec[idx_rec]->flg_mro=True; if(lmt_rec[idx_rec]->flg_mro) FLG_MRO=True; /* NB: nco_cnv_arm_base_time_get() with same nc_id contains OpenMP critical region */ if(CNV_ARM) base_time_crr=nco_cnv_arm_base_time_get(in_id); /* Perform various error-checks on input file */ if(False) (void)nco_fl_cmp_err_chk(); /* This file may be superfluous though valid data will be found in upcoming files */ if(nco_dbg_lvl >= nco_dbg_std) if((lmt_rec[idx_rec]->srt > lmt_rec[idx_rec]->end) && (lmt_rec[idx_rec]->rec_rmn_prv_ssc == 0L)) (void)fprintf(fp_stdout,gettext("%s: INFO %s (input file %d) is superfluous\n"),nco_prg_nm_get(),fl_in,fl_idx); rec_dmn_sz=lmt_rec[idx_rec]->rec_dmn_sz; rec_rmn_prv_ssc=lmt_rec[idx_rec]->rec_rmn_prv_ssc; /* Local copy may be decremented later */ idx_rec_crr_in= (rec_rmn_prv_ssc > 0L) ? 0L : lmt_rec[idx_rec]->srt; /* Master while loop over records in current file */ while(idx_rec_crr_in >= 0L && idx_rec_crr_in < rec_dmn_sz){ /* Following logic/assumptions built-in to this loop: idx_rec_crr_in points to valid record before loop is entered Loop is never entered if this file has no valid records Much conditional logic needed to prescribe group position and next record Index juggling: idx_rec_crr_in: Index of current record in current input file (increments by 1 for ssc then srd-ssc ...) idx_rec_out: Index of record in output file lmt_rec->rec_rmn_prv_ssc: Structure member, at start of this while loop, contains records remaining-to-be-read to complete subcycle group from previous file. Structure member remains constant until next file is read. rec_in_cml: Cumulative number of records, read or not, in all files opened so far. Similar to lmt_rec->rec_in_cml but augmented at end of record loop, rather than prior to record loop. rec_rmn_prv_ssc: Local copy initialized from lmt_rec structure member begins with above, and then is set to and tracks number of records remaining remaining in current group. This means it is decremented from ssc_nbr->0 for each group contained in current file. rec_usd_cml: Cumulative number of input records used (catenated by ncrcat or operated on by ncra) Flag juggling: REC_LST_DSR is "sloppy"---it is only set in last input file. If last file(s) is/are superfluous, REC_LST_DSR is never set and final normalization is done outside file and record loops (along with nces normalization). FLG_BFR_NRM indicates these situations and allow us to be "sloppy" in setting REC_LST_DSR. */ /* Last stride in file has distinct index-augmenting behavior */ if(idx_rec_crr_in >= lmt_rec[idx_rec]->end) REC_SRD_LST=True; else REC_SRD_LST=False; /* Even strides commence group beginnings */ if(rec_rmn_prv_ssc == 0L) REC_FRS_GRP=True; else REC_FRS_GRP=False; /* Each group comprises SSC records */ if(REC_FRS_GRP) rec_rmn_prv_ssc=lmt_rec[idx_rec]->ssc; /* Final record triggers normalization regardless of its location within group */ if(fl_idx == fl_nbr-1 && idx_rec_crr_in == min_int(lmt_rec[idx_rec]->end+lmt_rec[idx_rec]->ssc-1L,rec_dmn_sz-1L)) REC_LST_DSR[idx_rec]=True; /* ncra normalization/writing code must know last record in current group (LRCG) for both MRO and non-MRO */ if(rec_rmn_prv_ssc == 1L) REC_LST_GRP=True; else REC_LST_GRP=False; /* Process all variables in current record */ if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(fp_stdout,gettext("%s: INFO Record %ld of %s contributes to output record %ld\n"),nco_prg_nm_get(),idx_rec_crr_in,fl_in,idx_rec_out[idx_rec]); #ifdef _OPENMP #pragma omp parallel for default(none) private(idx,in_id) shared(CNV_ARM,base_time_crr,base_time_srt,nco_dbg_lvl,fl_in,fl_out,idx_rec_crr_in,idx_rec_out,rec_usd_cml,in_id_arr,REC_FRS_GRP,REC_LST_DSR,md5,nbr_var_prc,nco_op_typ,FLG_BFR_NRM,FLG_MRO,out_id,nco_prg_id,rcd,var_prc,var_prc_out,nbr_dmn_fl,trv_tbl,var_trv,grp_id,gpe,grp_out_fll,grp_out_id,var_out_id,idx_rec,flg_skp1,flg_skp2,lmt_rec,nbr_rec) #endif /* !_OPENMP */ for(idx=0;idxnm_fll,trv_tbl); if(flg_skp1) continue; in_id=in_id_arr[omp_get_thread_num()]; if(nco_dbg_lvl >= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm_fll); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_prc[idx]->nm_fll,trv_tbl); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(in_id,var_trv->grp_nm_fll,&grp_id); /* Edit group name for output */ grp_out_fll=NULL; if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=var_trv->grp_nm_fll; /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Memory management after current extracted group */ if(gpe && grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; /* Retrieve variable from disk into memory. NB: Using version that updates hyperslab start indices with idx_rec_crr_in */ (void)nco_msa_var_get_lmn_trv(in_id,var_prc[idx],lmt_rec[idx_rec]->nm_fll,idx_rec_crr_in,trv_tbl); if(nco_prg_id == ncra) FLG_BFR_NRM=True; /* [flg] Current output buffers need normalization */ /* Re-base record coordinate and bounds if necessary (e.g., time, time_bnds) */ if(lmt_rec[idx_rec]->origin != 0.0 && (var_prc[idx]->is_crd_var || nco_is_spc_in_bnd_att(grp_id,var_prc[idx]->id))){ var_sct *var_crd; scv_sct scv; /* De-reference */ var_crd=var_prc[idx]; scv.val.d=lmt_rec[idx_rec]->origin; scv.type=NC_DOUBLE; /* Convert scalar to variable type */ nco_scv_cnf_typ(var_crd->type,&scv); (void)var_scv_add(var_crd->type,var_crd->sz,var_crd->has_mss_val,var_crd->mss_val,var_crd->val,&scv); } /* end re-basing */ if(nco_prg_id == ncra){ nco_bool flg_rth_ntl; if(!rec_usd_cml[idx_rec] || (FLG_MRO && REC_FRS_GRP)) flg_rth_ntl=True; else flg_rth_ntl=False; /* Initialize tally and accumulation arrays when appropriate */ if(flg_rth_ntl){ (void)nco_zero_long(var_prc_out[idx]->sz,var_prc_out[idx]->tally); (void)nco_var_zero(var_prc_out[idx]->type,var_prc_out[idx]->sz,var_prc_out[idx]->val); } /* end if flg_rth_ntl */ if(var_prc[idx]->type == NC_CHAR || var_prc[idx]->type == NC_STRING){ /* Do not promote un-averagable types (NC_CHAR, NC_STRING) Stuff their first record into output buffer regardless of nco_op_typ, and ignore later records (rec_usd_cml > 1) Temporarily fixes TODO nco941 */ if(flg_rth_ntl) nco_opr_drv((long)0L,nco_op_min,var_prc[idx],var_prc_out[idx]); }else{ /* Convert char, short, long, int types to doubles before arithmetic Output variable type is "sticky" so only convert on first record */ if(flg_rth_ntl) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ if(flg_rth_ntl) nco_opr_drv((long)0L,nco_op_typ,var_prc[idx],var_prc_out[idx]); else nco_opr_drv((long)1L,nco_op_typ,var_prc[idx],var_prc_out[idx]); } /* end else */ } /* end if ncra */ /* All processed variables contain record dimension and both ncrcat and ncra write records singly */ var_prc_out[idx]->srt[0]=var_prc_out[idx]->end[0]=idx_rec_out[idx_rec]; var_prc_out[idx]->cnt[0]=1L; /* Append current record to output file */ if(nco_prg_id == ncrcat){ /* Replace this time_offset value with time_offset from initial file base_time */ if(CNV_ARM && !strcmp(var_prc[idx]->nm,"time_offset")) var_prc[idx]->val.dp[0]+=(base_time_crr-base_time_srt); #ifdef _OPENMP #pragma omp critical #endif /* _OPENMP */ if(var_prc_out[idx]->sz_rec > 1L) (void)nco_put_vara(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc[idx]->val.vp,var_prc_out[idx]->type); else (void)nco_put_var1(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc[idx]->val.vp,var_prc_out[idx]->type); /* Perform MD5 digest of input and output data if requested */ if(md5) (void)nco_md5_chk(md5,var_prc_out[idx]->nm,var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type),grp_out_id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc[idx]->val.vp); } /* end if ncrcat */ /* Warn if record coordinate, if any, is not monotonic */ if(nco_prg_id == ncrcat && var_prc[idx]->is_crd_var) (void)rec_crd_chk(var_prc[idx],fl_in,fl_out,idx_rec_crr_in,idx_rec_out[idx_rec]); /* Convert missing_value, if any, back to unpacked type Otherwise missing_value will be double-promoted when next record read Do not convert after last record otherwise normalization fails due to wrong missing_value type (needs promoted type, not unpacked type) */ if(var_prc[idx]->has_mss_val && var_prc[idx]->type != var_prc[idx]->typ_upk && !REC_LST_DSR[idx_rec]) var_prc[idx]=nco_cnv_mss_val_typ(var_prc[idx],var_prc[idx]->typ_upk); /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* end (OpenMP parallel for) loop over variables */ if(nco_prg_id == ncra && ((FLG_MRO && REC_LST_GRP) || REC_LST_DSR[idx_rec])){ /* Normalize, multiply, etc where necessary: ncra and nces normalization blocks are identical, except ncra normalizes after every ssc records, while nces normalizes once, after files loop. 20131210: nco_cnv_mss_val_typ() can cause type of var_prc to be out-of-sync with var_prc_out nco_cnv_mss_val_typ() above works correctly for case of packing/unpacking, not for rth_dbl Options: 1. Avoid nco_cnv_mss_val_typ() above if rth_dbl is invoked. Keep it for packing. 2. In nco_opr_nrm() below, use mss_val from var_prc_out not var_prc Problem is var_prc[idx]->mss_val is typ_upk while var_prc_out is type, so normalization sets missing var_prc_out value to var_prc[idx]->mss_val read as type */ (void)nco_opr_nrm(nco_op_typ,nbr_var_prc,var_prc,var_prc_out,lmt_rec[idx_rec]->nm_fll,trv_tbl); FLG_BFR_NRM=False; /* [flg] Current output buffers need normalization */ /* Copy averages to output file */ for(idx=0;idxnm_fll,trv_tbl); if(flg_skp2) continue; /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_prc_out[idx]->nm_fll,trv_tbl); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); var_prc_out[idx]=nco_var_cnf_typ(var_prc_out[idx]->typ_upk,var_prc_out[idx]); /* Packing/Unpacking */ if(nco_pck_plc == nco_pck_plc_all_new_att) var_prc_out[idx]=nco_put_var_pck(grp_out_id,var_prc_out[idx],nco_pck_plc); if(var_prc_out[idx]->nbr_dim == 0) (void)nco_put_var1(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); else (void)nco_put_vara(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); } /* end loop over idx */ idx_rec_out[idx_rec]++; /* [idx] Index of current record in output file (0 is first, ...) */ } /* end if normalize and write */ /* Prepare indices and flags for next iteration */ if(nco_prg_id == ncrcat) idx_rec_out[idx_rec]++; /* [idx] Index of current record in output file (0 is first, ...) */ rec_usd_cml[idx_rec]++; /* [nbr] Cumulative number of input records used (catenated by ncrcat or operated on by ncra) */ if(nco_dbg_lvl >= nco_dbg_var) (void)fprintf(fp_stderr,"\n"); /* Finally, set index for next record or get outta' Dodge */ if(REC_SRD_LST){ /* Last index depends on whether user-specified end was exact, sloppy, or caused truncation */ long end_max_crr; end_max_crr=min_lng(lmt_rec[idx_rec]->idx_end_max_abs-rec_in_cml[idx_rec],min_lng(lmt_rec[idx_rec]->end+lmt_rec[idx_rec]->ssc-1L,rec_dmn_sz-1L)); if(--rec_rmn_prv_ssc > 0L && idx_rec_crr_in < end_max_crr) idx_rec_crr_in++; else break; }else{ /* !REC_SRD_LST */ if(--rec_rmn_prv_ssc > 0L) idx_rec_crr_in++; else idx_rec_crr_in+=lmt_rec[idx_rec]->srd-lmt_rec[idx_rec]->ssc+1L; } /* !REC_SRD_LST */ } /* end idx_rec_crr_in master while loop over records in current file */ rec_in_cml[idx_rec]+=rec_dmn_sz; /* [nbr] Cumulative number of records in all files opened so far */ lmt_rec[idx_rec]->rec_rmn_prv_ssc=rec_rmn_prv_ssc; if(fl_idx == fl_nbr-1){ /* Warn if other than number of requested records were read */ if(lmt_rec[idx_rec]->lmt_typ == lmt_dmn_idx && lmt_rec[idx_rec]->is_usr_spc_min && lmt_rec[idx_rec]->is_usr_spc_max){ long ssc_grp_nbr_max; /* [nbr] Subcycle groups that start within range */ long rec_nbr_rqs; /* Number of records user requested */ long rec_nbr_rqs_max; /* [nbr] Records that would be used by ssc_grp_nbr_max groups */ long rec_nbr_spn_act; /* [nbr] Records available within user-specified range */ long rec_nbr_spn_max; /* [nbr] Minimum record number spanned by ssc_grp_nbr_max groups */ long rec_nbr_trn; /* [nbr] Records truncated in last group */ long srd_nbr_flr; /* [nbr] Whole strides that fit within specified range */ /* Number of whole strides that fit within specified range */ srd_nbr_flr=(lmt_rec[idx_rec]->max_idx-lmt_rec[idx_rec]->min_idx)/lmt_rec[idx_rec]->srd; ssc_grp_nbr_max=1L+srd_nbr_flr; /* Number of records that would be used by N groups */ rec_nbr_rqs_max=ssc_grp_nbr_max*lmt_rec[idx_rec]->ssc; /* Minimum record number spanned by N groups of size D is N-1 strides, plus D-1 trailing members of last group */ rec_nbr_spn_max=lmt_rec[idx_rec]->srd*(ssc_grp_nbr_max-1L)+lmt_rec[idx_rec]->ssc; /* Actual number of records available within range */ rec_nbr_spn_act=1L+lmt_rec[idx_rec]->max_idx-lmt_rec[idx_rec]->min_idx; /* Number truncated in last group */ rec_nbr_trn=max_int(rec_nbr_spn_max-rec_nbr_spn_act,0L); /* Records requested is maximum minus any truncated in last group */ rec_nbr_rqs=rec_nbr_rqs_max-rec_nbr_trn; if(rec_nbr_rqs != rec_usd_cml[idx_rec]) (void)fprintf(fp_stdout,gettext("%s: WARNING User requested %li records but only %li were found and used\n"),nco_prg_nm_get(),rec_nbr_rqs,rec_usd_cml[idx_rec]); } /* end if */ /* ... and die if no records were read ... */ if(rec_usd_cml[idx_rec] <= 0){ (void)fprintf(fp_stdout,gettext("%s: ERROR No records lay within specified hyperslab\n"),nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* end if */ } /* end if */ } /* end idx_rec loop over different record variables to process */ /* End ncra, ncrcat section */ }else if(nco_prg_id == ncfe){ /* ncfe */ #ifdef _OPENMP #pragma omp parallel for default(none) private(idx,in_id) shared(nco_dbg_lvl,fl_idx,FLG_BFR_NRM,in_id_arr,nbr_var_prc,nco_op_typ,rcd,var_prc,var_prc_out,nbr_dmn_fl,trv_tbl,var_trv,grp_id,gpe,grp_out_fll,grp_out_id,out_id,var_out_id) #endif /* !_OPENMP */ for(idx=0;idx= nco_dbg_var) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); if(nco_dbg_lvl >= nco_dbg_var) (void)fflush(fp_stderr); /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_prc[idx]->nm_fll,trv_tbl); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(in_id,var_trv->grp_nm_fll,&grp_id); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; /* Retrieve variable from disk into memory */ (void)nco_msa_var_get_trv(in_id,var_prc[idx],trv_tbl); /* Convert char, short, long, int types to doubles before arithmetic Output variable type is "sticky" so only convert on first record */ if(fl_idx == 0) var_prc_out[idx]=nco_typ_cnv_rth(var_prc_out[idx],nco_op_typ); var_prc[idx]=nco_var_cnf_typ(var_prc_out[idx]->type,var_prc[idx]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ /* Note: fl_idx not rec_usd_cml! */ nco_opr_drv(fl_idx,nco_op_typ,var_prc[idx],var_prc_out[idx]); FLG_BFR_NRM=True; /* [flg] Current output buffers need normalization */ /* Free current input buffer */ var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); } /* end (OpenMP parallel for) loop over idx */ /* End ncfe section */ }else if(nco_prg_id == ncge){ /* ncge */ trv_tbl_sct *trv_tbl1; /* [lst] Traversal table (needed for multi-file cases) */ /* Initialize traversal table */ trv_tbl_init(&trv_tbl1); /* Construct GTT using current file ID */ (void)nco_bld_trv_tbl(in_id,trv_pth,lmt_nbr,lmt_arg,aux_nbr,aux_arg,MSA_USR_RDR,FORTRAN_IDX_CNV,grp_lst_in,grp_lst_in_nbr,var_lst_in,var_lst_in_nbr,EXTRACT_ALL_COORDINATES,GRP_VAR_UNN,EXCLUDE_INPUT_LIST,EXTRACT_ASSOCIATED_COORDINATES,&flg_dne,trv_tbl1); /* Check if all input -d dimensions were found */ (void)nco_chk_dmn(lmt_nbr,flg_dne); /* Loop over ensembles in current file */ for(int idx_nsm=0;idx_nsmnsm_nbr;idx_nsm++){ if(nco_dbg_lvl > nco_dbg_std) (void)fprintf(stdout,"%s: ensemble %d: %s\n",nco_prg_nm_get(),idx_nsm,trv_tbl->nsm[idx_nsm].grp_nm_fll_prn); int mbr_srt=trv_tbl->nsm[idx_nsm].mbr_srt; int mbr_end=trv_tbl->nsm[idx_nsm].mbr_end; /* Loop over members of current ensemble (use start and end members, multi file cases) */ for(int idx_mbr=mbr_srt;idx_mbrnm_fll,trv_tbl); assert(var_trv); /* Skip if from different ensembles */ if(strcmp(var_trv->nsm_nm,trv_tbl->nsm[idx_nsm].grp_nm_fll_prn)) continue; /* Build new variable name */ char *grp_nm_fll=trv_tbl->nsm[idx_nsm].grp_mbr_fll[idx_mbr]; char *var_nm_fll=nco_bld_nm_fll(grp_nm_fll,var_prc[idx_prc]->nm);; char *nm_fll=strdup(var_prc[idx_prc]->nm_fll); var_prc[idx_prc]->nm_fll=(char *)nco_free(var_prc[idx_prc]->nm_fll); var_prc[idx_prc]->nm_fll=nco_bld_nm_fll(grp_nm_fll,var_prc[idx_prc]->nm); if(nco_dbg_lvl > nco_dbg_std) (void)fprintf(fp_stdout,"%s:\t variable <%s>\n",nco_prg_nm_get(),var_prc[idx_prc]->nm_fll); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(in_id,grp_nm_fll,&grp_id); (void)nco_var_mtd_refresh(grp_id,var_prc[idx_prc]); /* Retrieve variable from disk into memory. NB: Using table in file loop */ (void)nco_msa_var_get_trv(in_id,var_prc[idx_prc],trv_tbl1); /* Convert char, short, long, int types to doubles before arithmetic Output variable type is "sticky" so only convert on first member */ if(fl_idx == 0 && idx_mbr == 0) var_prc_out[idx_prc]=nco_typ_cnv_rth(var_prc_out[idx_prc],nco_op_typ); var_prc[idx_prc]=nco_var_cnf_typ(var_prc_out[idx_prc]->type,var_prc[idx_prc]); /* Perform arithmetic operations: avg, min, max, ttl, ... */ nco_opr_drv(fl_idx+idx_mbr,nco_op_typ,var_prc[idx_prc],var_prc_out[idx_prc]); FLG_BFR_NRM=True; /* [flg] Current output buffers need normalization */ /* Put old name back */ var_prc[idx_prc]->nm_fll=(char *)nco_free(var_prc[idx_prc]->nm_fll); var_prc[idx_prc]->nm_fll=strdup(nm_fll); /* Free current input buffer */ var_prc[idx_prc]->val.vp=nco_free(var_prc[idx_prc]->val.vp); /* Free built variable name */ var_nm_fll=(char *)nco_free(var_nm_fll); nm_fll=(char *)nco_free(nm_fll); } /* end loop over var_prc */ } /* end loop over mbr */ } /* Loop over ensembles in current file */ (void)trv_tbl_free(trv_tbl1); } /* End ncge section */ if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(fp_stderr,"\n"); /* Close input netCDF file */ for(thr_idx=0;thr_idxflg_input_complete)){ /* NB: TODO nco1066 move input_complete break to precede record loop but remember to close open filehandles */ /* 20131209: Rewritten so file skipped only once all record dimensions have flg_input_complete Warnings about superfluous files printed only once per dimension fxm: use flg_input_complete[idx_rec] to skip completed entries in main record dimension loop above */ if(nco_dbg_lvl >= nco_dbg_std) (void)fprintf(fp_stderr,"%s: INFO All requested records for record dimension #%d (%s) were found within the first %d input file%s, next file was opened then skipped, and remaining %d input file%s need not be opened\n",nco_prg_nm_get(),idx_rec,lmt_rec[idx_rec]->nm_fll,fl_idx,(fl_idx == 1) ? "" : "s",fl_nbr-fl_idx-1,(fl_nbr-fl_idx-1 == 1) ? "" : "s"); flg_input_complete_nbr++; } /* endif superfluous */ } /* endif not already known to be complete */ } /* end loop over record dimensions */ /* Once all record dimensions are complete, break-out of file loop */ if(flg_input_complete_nbr == nbr_rec) break; } /* endif ncra || ncrcat */ } /* end loop over fl_idx */ /* Subcycle argument warning */ if(nco_prg_id == ncra || nco_prg_id == ncrcat){ /* fxm: Remove this or make DBG when crd_val SSC/MRO is predictable? */ /* Loop records */ for(idx_rec=0;idx_recssc != 1L && (lmt_rec[idx_rec]->lmt_typ == lmt_crd_val || lmt_rec[idx_rec]->lmt_typ == lmt_udu_sng)){ (void)fprintf(stderr,"\n%s: WARNING Subcycle argument SSC used in hyperslab specification for %s which will be determined based on coordinate values rather than dimension indices. The behavior of the subcycle hyperslab argument is ambiguous for coordinate-based hyperslabs---it could mean select the first SSC elements that are within the min and max coordinate values beginning with each strided point, or it could mean always select the first _consecutive_ SSC elements beginning with each strided point (regardless of their values relative to min and max). For such hyperslabs, NCO adopts the latter definition and always selects the group of SSC records beginning with each strided point. Strided points are guaranteed to be within the min and max coordinates, but the subsequent members of each group are not, though this is only the case if the record coordinate is not monotonic. The record coordinate is almost always monotonic, so surprises are only expected in a corner case unlikely to affect the vast majority of users. You have been warned. Use at your own risk.\n",nco_prg_nm_get(),lmt_rec[idx_rec]->nm); } /* Check subcycle for each record */ } /* Loop records */ } /* Subcycle argument warning */ /* Normalize, multiply, etc where necessary: ncra and nces normalization blocks are identical, except ncra normalizes after every SSC records, while nces normalizes once, after all files. Occassionally last input file(s) is/are superfluous so REC_LST_DSR never set In such cases FLG_BFR_NRM is still true, indicating ncra still needs normalization FLG_BFR_NRM is always true here for ncfe and ncge */ if(FLG_BFR_NRM) (void)nco_opr_nrm(nco_op_typ,nbr_var_prc,var_prc,var_prc_out,(char *)NULL,(trv_tbl_sct *)NULL); /* Manually fix YYMMDD date which was mangled by averaging */ if(CNV_CCM_CCSM_CF && nco_prg_id == ncra) (void)nco_cnv_ccm_ccsm_cf_date(grp_out_id,var_out,xtr_nbr); /* Add time variable to output file NB: nco_cnv_arm_time_install() contains OpenMP critical region */ if(CNV_ARM && nco_prg_id == ncrcat) (void)nco_cnv_arm_time_install(grp_out_id,base_time_srt,dfl_lvl); /* Copy averages to output file for ncfe and ncge always and for ncra when trailing file(s) was/were superfluous */ if(FLG_BFR_NRM){ for(idx=0;idxnm_fll,trv_tbl); /* For ncge, group to save is ensemble parent group */ if(nco_prg_id == ncge){ /* Check if suffix needed. Appends to default name */ if(trv_tbl->nsm_sfx){ /* Define (append) then use and forget new name */ char *nm_fll_sfx=nco_bld_nsm_sfx(var_trv->grp_nm_fll_prn,trv_tbl); /* Use new name */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,nm_fll_sfx); else grp_out_fll=(char *)strdup(nm_fll_sfx); nm_fll_sfx=(char *)nco_free(nm_fll_sfx); }else{ /* Non suffix case */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->nsm_nm); else grp_out_fll=(char *)strdup(var_trv->nsm_nm); } /* !trv_tbl->nsm_sfx */ }else if(nco_prg_id == ncfe){ /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll); } /* end else */ /* Obtain output group ID using full group name */ (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id); /* Get output variable ID */ (void)nco_inq_varid(grp_out_id,var_prc_out[idx]->nm,&var_out_id); /* Store the output variable ID */ var_prc_out[idx]->id=var_out_id; var_prc_out[idx]=nco_var_cnf_typ(var_prc_out[idx]->typ_upk,var_prc_out[idx]); /* Packing/Unpacking */ if(nco_pck_plc == nco_pck_plc_all_new_att) var_prc_out[idx]=nco_put_var_pck(grp_out_id,var_prc_out[idx],nco_pck_plc); if(var_prc_out[idx]->nbr_dim == 0) (void)nco_put_var1(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); else (void)nco_put_vara(grp_out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); } /* end loop over idx */ } /* end if ncfe and ncge */ /* Free averaging and tally buffers */ if(nco_prg_id == ncra || nco_prg_id == ncfe || nco_prg_id == ncge){ #ifdef _OPENMP #pragma omp parallel for default(none) private(idx) shared(nbr_var_prc,nco_op_typ,var_prc,var_prc_out) #endif /* !_OPENMP */ for(idx=0;idxtally=var_prc[idx]->tally=(long *)nco_free(var_prc[idx]->tally); var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); } /* end loop over idx */ } /* endif ncra || nces */ /* Close output file and move it from temporary to permanent location */ (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(cnk_map_sng) cnk_map_sng=(char *)nco_free(cnk_map_sng); if(cnk_plc_sng) cnk_plc_sng=(char *)nco_free(cnk_plc_sng); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_out_tmp) fl_out_tmp=(char *)nco_free(fl_out_tmp); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); if(in_id_arr) in_id_arr=(int *)nco_free(in_id_arr); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); /* Free limits */ for(idx=0;idx 0) cnk.cnk_dmn=(cnk_dmn_sct **)nco_cnk_lst_free(cnk.cnk_dmn,cnk_nbr); /* Free dimension lists */ if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); /* Free variable lists */ if(xtr_nbr > 0) var=nco_var_lst_free(var,xtr_nbr); if(xtr_nbr > 0) var_out=nco_var_lst_free(var_out,xtr_nbr); var_prc=(var_sct **)nco_free(var_prc); var_prc_out=(var_sct **)nco_free(var_prc_out); var_fix=(var_sct **)nco_free(var_fix); var_fix_out=(var_sct **)nco_free(var_fix_out); if(md5) md5=(md5_sct *)nco_md5_free(md5); (void)trv_tbl_free(trv_tbl); for(idx=0;idxnbr_dim == wgt_crr->nbr_dim){ /* Test whether all wgt and var dimensions match in sequence */ for(idx=0;idxnbr_dim;idx++){ /* 20131002: nco_var_cnf_dmn() borken for groups as shown by dimension short-name strcmp() comparison here */ if(strcmp(wgt_crr->dim[idx]->nm,var->dim[idx]->nm)) break; } /* end loop over dimensions */ if(idx == var->nbr_dim) *DO_CONFORM=True; } /* end if ranks are equal */ /* 20060425: Weight re-use will not occur if wgt_crr is free()'d here Some DDRA benchmarks need to know cost of broadcasting weights To turn off weight re-use and cause broadcasting, execute "else" block below by (temporarily) using if(*DO_CONFORM && False){ ....instead of.... if(*DO_CONFORM){ in following condition */ if(*DO_CONFORM){ wgt_out=wgt_crr; }else{ wgt_crr=nco_var_free(wgt_crr); wgt_out=NULL; } /* !*DO_CONFORM */ } /* wgt_crr == NULL */ /* Does original weight (wgt) conform to variable's dimensions? */ if(wgt_out == NULL){ if(var->nbr_dim > 0){ /* Test that all dimensions in wgt appear in var */ for(idx=0;idxnbr_dim;idx++){ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Compare names, not dimension IDs */ /* 20131002: nco_var_cnf_dmn() borken for groups as shown by dimension short-name strcmp() comparison here */ if(!strcmp(wgt->dim[idx]->nm,var->dim[idx_dmn]->nm)){ wgt_var_dmn_shr_nbr++; /* wgt and var share this dimension */ break; } /* endif */ } /* end loop over var dimensions */ } /* end loop over wgt dimensions */ /* Decide whether wgt and var dimensions conform, are mutually exclusive, or are partially exclusive (an error) */ if(wgt_var_dmn_shr_nbr == wgt->nbr_dim){ /* wgt and var conform */ CONFORMABLE=True; }else if(wgt_var_dmn_shr_nbr == 0){ /* Dimensions in wgt and var are mutually exclusive */ CONFORMABLE=False; if(MUST_CONFORM){ (void)fprintf(stdout,"%s: ERROR %s and template %s share no dimensions\n",nco_prg_nm_get(),wgt->nm,var->nm); nco_exit(EXIT_FAILURE); }else{ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stdout,"\n%s: DEBUG %s and template %s share no dimensions: Not broadcasting %s to %s\n",nco_prg_nm_get(),wgt->nm,var->nm,wgt->nm,var->nm); USE_DUMMY_WGT=True; } /* endif */ }else if(wgt->nbr_dim > var->nbr_dim){ /* wgt is larger rank than var---no possibility of conforming */ CONFORMABLE=False; if(MUST_CONFORM){ (void)fprintf(stdout,"%s: ERROR %s is rank %d but template %s is rank %d: Impossible to broadcast\n",nco_prg_nm_get(),wgt->nm,wgt->nbr_dim,var->nm,var->nbr_dim); nco_exit(EXIT_FAILURE); }else{ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stdout,"\n%s: DEBUG %s is rank %d but template %s is rank %d: Not broadcasting %s to %s\n",nco_prg_nm_get(),wgt->nm,wgt->nbr_dim,var->nm,var->nbr_dim,wgt->nm,var->nm); USE_DUMMY_WGT=True; } /* endif */ }else if(wgt_var_dmn_shr_nbr > 0 && wgt_var_dmn_shr_nbr < wgt->nbr_dim){ /* Some, but not all, of wgt dimensions are in var */ CONFORMABLE=False; if(MUST_CONFORM){ (void)fprintf(stdout,"%s: ERROR %d dimensions of %s belong to template %s but %d dimensions do not\n",nco_prg_nm_get(),wgt_var_dmn_shr_nbr,wgt->nm,var->nm,wgt->nbr_dim-wgt_var_dmn_shr_nbr); nco_exit(EXIT_FAILURE); }else{ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stdout,"\n%s: DEBUG %d dimensions of %s belong to template %s but %d dimensions do not: Not broadcasting %s to %s\n",nco_prg_nm_get(),wgt_var_dmn_shr_nbr,wgt->nm,var->nm,wgt->nbr_dim-wgt_var_dmn_shr_nbr,wgt->nm,var->nm); USE_DUMMY_WGT=True; } /* endif */ } /* end if */ if(USE_DUMMY_WGT){ /* Variables do not truly conform, but this might be OK, depending on the application, so set DO_CONFORM flag to false and ... */ *DO_CONFORM=False; /* ... return a dummy weight of 1.0, which allows program logic to pretend variable is weighted, but does not change answers */ wgt_out=nco_var_dpl(var); (void)vec_set(wgt_out->type,wgt_out->sz,wgt_out->val,1.0); } /* endif */ if(CONFORMABLE){ if(var->nbr_dim == wgt->nbr_dim){ /* var and wgt conform and are same rank */ /* Test whether all wgt and var dimensions match in sequence */ for(idx=0;idxnbr_dim;idx++){ /* 20131002: nco_var_cnf_dmn() borken for groups as shown by dimension short-name strcmp() comparison here */ if(strcmp(wgt->dim[idx]->nm,var->dim[idx]->nm)) break; /* if(wgt->dmn_id[idx] != var->dmn_id[idx]) break;*/ } /* end loop over dimensions */ /* If so, take shortcut and copy wgt to wgt_out */ if(idx == var->nbr_dim) *DO_CONFORM=True; }else{ /* var and wgt conform but are not same rank, set flag to proceed to generic conform routine */ *DO_CONFORM=False; } /* end else */ } /* endif CONFORMABLE */ }else{ /* var is scalar, if wgt is also then set flag to copy wgt to wgt_out else proceed to generic conform routine */ if(wgt->nbr_dim == 0) *DO_CONFORM=True; else *DO_CONFORM=False; } /* end else */ if(CONFORMABLE && *DO_CONFORM){ wgt_out=nco_var_dpl(wgt); (void)nco_xrf_var(wgt,wgt_out); } /* end if */ } /* end if */ /* Set diagnostic DDRA information DDRA */ /* ddra_info->wgt_brd_flg=(wgt_out == NULL) ? True : False; *//* [flg] Broadcast weight for this variable */ if(wgt_out == NULL){ /* Expand original weight (wgt) to match size of current variable */ char * restrict wgt_cp; char * restrict wgt_out_cp; int idx_wgt_var[NC_MAX_DIMS]; int wgt_nbr_dim; int var_nbr_dmn_m1; long * restrict var_cnt; long dmn_ss[NC_MAX_DIMS]; long dmn_var_map[NC_MAX_DIMS]; long dmn_wgt_map[NC_MAX_DIMS]; long var_lmn; long wgt_lmn; long var_sz; size_t wgt_typ_sz; /* Copy main attributes of variable into output weight */ wgt_out=nco_var_dpl(var); (void)nco_xrf_var(wgt,wgt_out); /* wgt_out variable was copied from template var Modify key fields so its name and type are based on wgt, not var wgt_out will then be hybrid between wgt and var Remainder of routine fills wgt_out's var-dimensionality with wgt-values */ wgt_out->nm=(char *)nco_free(wgt_out->nm); wgt_out->nm=(char *)strdup(wgt->nm); wgt_out->id=wgt->id; wgt_out->type=wgt->type; wgt_out->val.vp=(void *)nco_free(wgt_out->val.vp); wgt_out->val.vp=(void *)nco_malloc(wgt_out->sz*nco_typ_lng(wgt_out->type)); wgt_cp=(char *)wgt->val.vp; wgt_out_cp=(char *)wgt_out->val.vp; wgt_typ_sz=nco_typ_lng(wgt_out->type); if(wgt_out->nbr_dim == 0){ /* Variable (and weight) are scalars, not arrays */ (void)memcpy(wgt_out_cp,wgt_cp,wgt_typ_sz); }else if(wgt->nbr_dim == 0){ /* Lesser-ranked input variable is scalar Expansion in this degenerate case needs no index juggling (reverse-mapping) Code as special case to speed-up important applications of ncap for synthetic file creation */ var_sz=var->sz; for(var_lmn=0;var_lmnnbr_dim;idx++){ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Compare names, not dimension IDs */ /* 20131002: nco_var_cnf_dmn() borken for groups as shown by dimension short-name strcmp() comparison here */ if(!strcmp(var->dim[idx_dmn]->nm,wgt->dim[idx]->nm)){ idx_wgt_var[idx]=idx_dmn; break; } /* end if */ /* Sanity check */ if(idx_dmn == var->nbr_dim-1){ (void)fprintf(stdout,"%s: ERROR wgt %s has dimension %s but var %s does not deep in nco_var_cnf_dmn()\n",nco_prg_nm_get(),wgt->nm,wgt->dim[idx]->nm,var->nm); nco_exit(EXIT_FAILURE); } /* end if err */ } /* end loop over variable dimensions */ } /* end loop over weight dimensions */ /* Figure out map for each dimension of variable */ for(idx=0;idxnbr_dim;idx++) dmn_var_map[idx]=1L; for(idx=0;idxnbr_dim-1;idx++) for(idx_dmn=idx+1;idx_dmnnbr_dim;idx_dmn++) dmn_var_map[idx]*=var->cnt[idx_dmn]; /* Figure out map for each dimension of weight */ for(idx=0;idxnbr_dim;idx++) dmn_wgt_map[idx]=1L; for(idx=0;idxnbr_dim-1;idx++) for(idx_dmn=idx+1;idx_dmnnbr_dim;idx_dmn++) dmn_wgt_map[idx]*=wgt->cnt[idx_dmn]; /* Define convenience variables to avoid repetitive indirect addressing */ wgt_nbr_dim=wgt->nbr_dim; var_sz=var->sz; var_cnt=var->cnt; var_nbr_dmn_m1=var->nbr_dim-1; /* var_lmn is offset into 1-D array corresponding to N-D indices dmn_ss */ for(var_lmn=0;var_lmnnbr_dim > var_2_org->nbr_dim){ var_tmp=nco_var_cnf_dmn(var_1_org,var_2_org,var_tmp,MUST_CONFORM,&DO_CONFORM); if(var_2_org != var_tmp){ var_2_org=nco_var_free(var_2_org); *var_2=var_tmp; } /* endif replace var_2 */ }else{ var_tmp=nco_var_cnf_dmn(var_2_org,var_1_org,var_tmp,MUST_CONFORM,&DO_CONFORM); if(var_1_org != var_tmp){ var_1_org=nco_var_free(var_1_org); *var_1=var_tmp; } /* endif replace var_1 */ } /* endif var_1 > var_2 */ if(!DO_CONFORM){ (void)fprintf(stderr,"%s: ncap_var_cnf_dmn() reports that variables %s and %s do not have have conforming dimensions. Cannot proceed with operation\n",nco_prg_nm_get(),(*var_1)->nm,(*var_2)->nm); nco_exit(EXIT_FAILURE); } /* endif */ return DO_CONFORM; /* [flg] Do var_1 and var_2 conform after processing? */ } /* end ncap_var_cnf_dmn() */ char * /* [sng] Name of record dimension, if any, required by re-order */ nco_var_dmn_rdr_mtd /* [fnc] Change dimension ordering of variable metadata */ (const var_sct * const var_in, /* I [ptr] Variable with metadata and data in original order */ var_sct * const var_out, /* I/O [ptr] Variable whose metadata will be re-ordered */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_rdr), /* I [sct] List of dimension structures in new order */ const int dmn_rdr_nbr, /* I [nbr] Number of dimension structures in structure list */ int * const dmn_idx_out_in, /* O [idx] Dimension correspondence, output->input */ const nco_bool * const dmn_rvr_rdr, /* I [idx] Reverse dimension */ nco_bool * const dmn_rvr_in) /* O [idx] Reverse dimension */ { /* Purpose: Re-order dimensions in a given variable dmn_rdr contains new dimension order for dimensions Currently routine allows only dimension permutations, i.e., re-arranging dimensions without changing their number (variable rank). Routine keeps track of two variables var_* whose abbreviations are: in: Input variable (already hyperslabbed) with old dimension ordering rdr: User-specified re-ordered dimension list. Possibly subset of dmn_in out: Output (re-ordered) dimensionality specific to each variable At first it seemed this routine could re-order input variable in place without copying it Multiple constraints keep this from being practical Constraints are dictated by the architectural decision to call nco_var_dmn_rdr_mtd() twice Decision to call nco_var_dmn_rdr_mtd() twice is based on: 1. Want to parallelize loop over variables to increase throughput Parallel writes to output file only possible if output file is defined in shape, order Output file only definable once variable shapes, i.e., re-ordered dimensions known Alternatives to calling nco_var_dmn_rdr_mtd() twice: A. Each thread enters redefine() mode and adds its variable to output file Internal data re-copying would be expensive and unnecessary Hence Alternative A is not viable B. Perform output file definition and all writes after all variable re-ordering Memory consumption would increase to O(fl_in_sz) to keep all re-ordered data in memory Hence Alternative B is not viable 2. The two calls to nco_var_dmn_rdr_mtd() accomplish the following A. First call: Create var_out->dim for call to nco_var_dfn() Main thread makes first call in serial mode just prior to nco_var_dfn() No input data (AOT metadata) have been allocated or read in at this point Routine exits after modifying var_out metadata for new dimension geometry B. Second call: Re-order var_in->val data and place in var_out Although var_out->dmn is retained between calls, intermediate information such as in_out dimension mapping arrays are lost and must be re-created Hence second call must re-do most of first call, then begin re-ordering Routine must access un-touched var_in->dim input structure during both parts of second call Hence var_in must be unmodified between first and second call dmn_rdr is user-specified list of dimensions to be re-arranged User specifies all or only a subset of all dimensions in input file For example, say user specifies -d lat,lon This ensures lat precedes lon in all variables in output file In this case dmn_rdr is (user-specified) list [lat,lon] Input 0-D variables dimensioned [] output with dmn_out=[] (unaltered) Input 1-D variables dimensioned [lat] output with dmn_out=[lat] (unaltered) Input 2-D variables dimensioned [lat,lon] output with dmn_out=[lat,lon] (unaltered) Input 2-D variables dimensioned [time,lev] output with dmn_out=[time,lev] (unaltered) Input 2-D variables dimensioned [lon,lat] output with dmn_out=[lon,lat] (transposed) Input 3-D variables dimensioned [lon,lat,time] output with dmn_out=[lat,lon,time] Input 3-D variables dimensioned [time,lon,lat] output with dmn_out=[time,lat,lon] Input 3-D variables dimensioned [lon,lev,lat] output with dmn_out=[lat,lev,lon] Input 4-D variables dimensioned [lon,lev,lat,time] output with dmn_out=[lat,lev,lon,time] Hence output dimension dmn_out list depends on each particular variable Some, or even all, dimensions in dmn_rdr may not be in dmn_in Re-ordering is only necessary for variables where dmn_in and dmn_rdr share at least two dimensions Dimension reversal: Users specify dimension reversal by prefixing dimension name with negative sign Host routine passes dimension reversing flags in dmn_rvr_rdr Dimensions may be re-ordered, reversed, or both */ /* 20070509 CEWI RUVICFFU: dmn_idx_rdr_in */ const char fnc_nm[]="nco_var_dmn_rdr_mtd()"; /* [sng] Function name */ char *rec_dmn_nm_out=NULL; /* [sng] Name of record dimension, if any, required by re-order */ dmn_sct **dmn_in=NULL; /* [sct] List of dimension structures in input order */ dmn_sct **dmn_out; /* [sct] List of dimension structures in output order */ int dmn_idx_in_shr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->share Purely diagnostic */ int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output */ int dmn_idx_in_rdr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->re-order NB: Purely diagnostic */ int dmn_idx_shr_rdr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->re-order */ int dmn_idx_shr_in[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->input */ int dmn_idx_shr_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->output */ int dmn_idx_rec_out=NCO_REC_DMN_UNDEFINED; /* [idx] Record dimension index in output variable */ int dmn_shr_nbr=0; /* [nbr] Number of dimensions dmn_in and dmn_rdr share */ int dmn_in_idx; /* [idx] Counting index for dmn_in */ int dmn_in_nbr; /* [nbr] Number of dimensions in input variable */ int dmn_out_idx; /* [idx] Counting index for dmn_out */ int dmn_out_nbr; /* [nbr] Number of dimensions in output variable */ int dmn_rdr_idx; /* [idx] Counting index for dmn_rdr */ int dmn_shr_idx; /* [idx] Counting index for dmn_shr */ int idx_err=-99999; /* [idx] Invalid index for debugging */ /* Initialize variables to reduce indirection */ /* NB: Number of input and output dimensions are equal for pure re-orders However, keep dimension numbers in separate variables to ease relax this rule in future */ dmn_in_nbr=var_in->nbr_dim; dmn_out_nbr=var_out->nbr_dim; /* Initialize dimension maps to missing_value to aid debugging */ for(dmn_out_idx=0;dmn_out_idxis_rec_var) rec_dmn_nm_out=var_in->dim[0]->nm; /* 20130613: if netCDF3 _only_! */ for(dmn_in_idx=0;dmn_in_idxdim[dmn_in_idx]->id == dmn_rdr[dmn_rdr_idx]->id){ dmn_idx_in_rdr[dmn_in_idx]=dmn_rdr_idx; dmn_idx_shr_rdr[dmn_shr_nbr]=dmn_rdr_idx; dmn_idx_shr_in[dmn_shr_nbr]=dmn_in_idx; dmn_idx_in_shr[dmn_in_idx]=dmn_shr_nbr; dmn_shr_nbr++; /* dmn_in and dmn_rdr share this dimension */ break; } /* endif */ } /* end loop over dmn_in */ } /* end loop over dmn_rdr */ /* Map permanent list of reversed dimensions to input variable */ for(dmn_shr_idx=0;dmn_shr_idx nco_dbg_scl){ (void)fprintf(stdout,"%s: DEBUG %s variable %s shares %d of its %d dimensions with the %d dimensions in the re-order list\n",nco_prg_nm_get(),fnc_nm,var_in->nm,dmn_shr_nbr,var_in->nbr_dim,dmn_rdr_nbr); (void)fprintf(stdout,"shr_idx\tshr_rdr\tshr_in\tshr_out\n"); for(dmn_shr_idx=0;dmn_shr_idxdim; dmn_out=(dmn_sct **)nco_malloc(dmn_out_nbr*sizeof(dmn_sct *)); /* Assign dimension structures to new dimension list in correct order Remember: dmn_in has dimension IDs relative to input file Copy dmn_in->xrf to get dimension IDs relative to output file (once they are defined) Oh come on, it only seems like cheating! */ for(dmn_out_idx=0;dmn_out_idxxrf; } /* Re-ordered output dimension list dmn_out now comprises correctly ordered but otherwise verbatim copies of dmn_out structures in calling routine */ /* Free var_out's old dimension list */ var_out->dim=(dmn_sct **)nco_free(var_out->dim); /* Replace old with new dimension list */ var_out->dim=dmn_out; /* NB: var_out is now in an inconsistent state var_out->dim refers to re-ordered dimensions However, var_out->dmn_id,cnt,srt,end,srd refer still duplicate var_in members They refer to old dimension ordering in input file nco_cnf_dmn_rdr_mtd() implicitly assumes that only nco_cnf_dmn_rdr_mtd() modifies var_out Call to nco_cnf_dmn_rdr_val() for this variable performs actual re-ordering The interim inconsistent state is required for dimension IDs because output dimension IDs are not known until nco_dmn_dfn() which cannot (or, at least, should not) occur until output record dimension is known. Interim modifications of var_out by any other routine are dangerous! */ /* This is clear at date written (20040727), but memories are short Hence we modify var_out->dmn_id,cnt,srt,end,srd to contain re-ordered values now This makes it safer to var_out->dmn_id,cnt,srt,end,srd before second call to nco_cnf_dmn_rdr() If dmn_out->id does depend on record dimension identity, then this update will do no good Hence, we must re-update dmn_out->id after nco_dmn_dfn() in nco_cnf_dmn_rdr_val() Structures should be completely consistent at that point Not updating these structures (at least dmn_out->id) is equivalent to assuming that dmn_out->id does not depend on record dimension identity, which is an ASSUMPTION that may currently be true, but netCDF API does not guarantee as always true. */ for(dmn_out_idx=0;dmn_out_idxdmn_id[dmn_out_idx]=dmn_out[dmn_out_idx]->id; var_out->cnt[dmn_out_idx]=dmn_out[dmn_out_idx]->cnt; var_out->srt[dmn_out_idx]=dmn_out[dmn_out_idx]->srt; var_out->end[dmn_out_idx]=dmn_out[dmn_out_idx]->end; var_out->srd[dmn_out_idx]=dmn_out[dmn_out_idx]->srd; } /* end loop over dmn_out */ if(var_out->is_rec_var){ /* Which dimension in output dimension list is scheduled to be record dimension? */ for(dmn_out_idx=0;dmn_out_idxis_rec_dmn) break; if(dmn_out_idx != dmn_out_nbr){ dmn_idx_rec_out=dmn_out_idx; /* Request that first dimension be record dimension */ rec_dmn_nm_out=dmn_out[0]->nm; if(nco_dbg_lvl_get() >= nco_dbg_scl && dmn_idx_rec_out != 0) (void)fprintf(stdout,"%s: INFO %s for variable %s reports old input record dimension %s is now ordinal dimension %d, new record dimension must be %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm,dmn_out[dmn_idx_rec_out]->nm,dmn_idx_rec_out,dmn_out[0]->nm); }else{ /* 20121009: This block only reached by variables that will change from record in input file to fixed in output file Leave is_rec_var as True here for those variables Change is_rec_var to false in "if(REDEFINED_RECORD_DIMENSION)" block of ncpdq.c instead Yes, this leaves the metadata in an inconsistent state However, changing all these flags in one place in ncpdq.c main() is clearer */ ; } /* end else */ } /* endif record variable */ if(nco_dbg_lvl_get() > nco_dbg_var){ for(dmn_in_idx=0;dmn_in_idxnm,var_in->dim[dmn_in_idx]->nm,dmn_in_idx,var_in->dmn_id[dmn_in_idx],dmn_idx_in_out[dmn_in_idx]); } /* endif dbg */ return rec_dmn_nm_out; } /* end nco_var_dmn_rdr_mtd() */ int /* O [enm] Return success code */ nco_var_dmn_rdr_val /* [fnc] Change dimension ordering of variable values */ (const var_sct * const var_in, /* I [ptr] Variable with metadata and data in original order */ var_sct * const var_out, /* I/O [ptr] Variable whose data will be re-ordered */ const int * const dmn_idx_out_in, /* I [idx] Dimension correspondence, output->input */ const nco_bool * const dmn_rvr_in) /* I [idx] Reverse dimension */ { /* Purpose: Re-order values in given variable according to supplied dimension map Description of re-ordering concepts is in nco_var_dmn_rdr_mtd() Description of actual re-ordering algorithm is in nco_var_dmn_rdr_val() */ /* 20070509 CEWI RUVICFFU: dmn_in, dmn_id_out */ nco_bool IDENTITY_REORDER=False; /* [flg] User requested identity re-ordering */ char *val_in_cp; /* [ptr] Input data location as char pointer */ char *val_out_cp; /* [ptr] Output data location as char pointer */ const char fnc_nm[]="nco_var_dmn_rdr_val()"; /* [sng] Function name */ /* dmn_sct **dmn_in=NULL; */ /* [sct] List of dimension structures in input order */ dmn_sct **dmn_out; /* [sct] List of dimension structures in output order */ /* int *dmn_id_out; */ /* [id] Contiguous vector of dimension IDs */ int dmn_idx; /* [idx] Index over dimensions */ int dmn_in_idx; /* [idx] Counting index for dmn_in */ int dmn_in_nbr; /* [nbr] Number of dimensions in input variable */ int dmn_in_nbr_m1; /* [nbr] Number of dimensions in input variable, less one */ int dmn_out_idx; /* [idx] Counting index for dmn_out */ int dmn_out_nbr; /* [nbr] Number of dimensions in output variable */ int rcd=0; /* [rcd] Return code */ int typ_sz; /* [B] Size of data element in memory */ long dmn_in_map[NC_MAX_DIMS]; /* [idx] Map for each dimension of input variable */ long dmn_out_map[NC_MAX_DIMS]; /* [idx] Map for each dimension of output variable */ long dmn_in_sbs[NC_MAX_DIMS]; /* [idx] Dimension subscripts into N-D input array */ long var_in_lmn; /* [idx] Offset into 1-D input array */ long var_out_lmn; /* [idx] Offset into 1-D output array */ long *var_in_cnt; /* [nbr] Number of valid elements in this dimension (including effects of stride and wrapping) */ long var_sz; /* [nbr] Number of elements (NOT bytes) in hyperslab (NOT full size of variable in input file!) */ /* Initialize variables to reduce indirection */ /* NB: Number of input and output dimensions are equal for pure re-orders However, keep dimension numbers in separate variables to ease relax this rule in future */ dmn_in_nbr=var_in->nbr_dim; dmn_out_nbr=var_out->nbr_dim; /* On entry to this section of code, we assume: 1. var_out metadata are re-ordered 2. var_out->val buffer has been allocated (calling routine must do this) */ /* Get ready to re-order */ /* dmn_id_out=var_out->dmn_id; */ /* dmn_in=var_in->dim; */ dmn_in_nbr_m1=dmn_in_nbr-1; dmn_out=var_out->dim; typ_sz=nco_typ_lng(var_out->type); val_in_cp=(char *)var_in->val.vp; val_out_cp=(char *)var_out->val.vp; var_in_cnt=var_in->cnt; var_sz=var_in->sz; /* As explained in nco_var_dmn_rdr_mtd(), "Hence, we must re-update dmn_out->id after nco_dmn_dfn() in nco_cnf_dmn_rdr_val() Structures should be completely consistent at that point Not updating these structures (at least dmn_out->id) is equivalent to assuming that dmn_out->id does not depend on record dimension identity, which is an ASSUMPTION that may currently be true, but is not guaranteed by the netCDF API to always be true." */ for(dmn_out_idx=0;dmn_out_idxdmn_id[dmn_out_idx]=dmn_out[dmn_out_idx]->id; var_out->cnt[dmn_out_idx]=dmn_out[dmn_out_idx]->cnt; var_out->srt[dmn_out_idx]=dmn_out[dmn_out_idx]->srt; var_out->end[dmn_out_idx]=dmn_out[dmn_out_idx]->end; var_out->srd[dmn_out_idx]=dmn_out[dmn_out_idx]->srd; } /* end loop over dmn_out */ /* Report full metadata re-order, if requested */ if(nco_dbg_lvl_get() > 3){ int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output */ /* Create reverse correspondence */ for(dmn_out_idx=0;dmn_out_idxnm,var_in->dim[dmn_in_idx]->nm,dmn_in_idx,var_in->dmn_id[dmn_in_idx],dmn_idx_in_out[dmn_in_idx],var_out->dmn_id[dmn_idx_in_out[dmn_in_idx]]); } /* endif dbg */ /* Is identity re-ordering requested? */ for(dmn_out_idx=0;dmn_out_idx= nco_dbg_scl) (void)fprintf(stdout,"%s: INFO %s reports re-order is identity transformation for variable %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm); /* Copy in one fell swoop then return */ (void)memcpy((void *)(var_out->val.vp),(void *)(var_in->val.vp),var_out->sz*nco_typ_lng(var_out->type)); return rcd; } /* !IDENTITY_REORDER */ if(var_in->has_dpl_dmn) (void)fprintf(stdout,"%s: WARNING %s reports non-identity re-order for variable with duplicate dimensions %s.\n%s does not support non-identity re-orders of variables with duplicate dimensions\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_prg_nm_get()); /* Compute map for each dimension of input variable */ for(dmn_in_idx=0;dmn_in_idxcnt[dmn_idx]; /* Compute map for each dimension of output variable */ for(dmn_out_idx=0;dmn_out_idxcnt[dmn_idx]; /* There is more than one method to re-order dimensions Output dimensionality is known in advance, unlike nco_var_avg() Hence outer loop may be over dimensions or over elements Method 1: Loop over input elements 1a. Loop over 1-D input array offsets 1b. Invert 1-D input array offset to get N-D input subscripts 1c. Turn N-D input subscripts into N-D output subscripts 1d. Map N-D output subscripts to get 1-D output element 1e. Copy input element to output element This method is simplified from method used in nco_var_avg() Method 2: Loop over input dimensions 1a. Loop over input dimensions, from slowest to fastest varying 1b. */ /* Begin Method 1: Loop over input elements */ /* var_in_lmn is offset into 1-D array */ for(var_in_lmn=0;var_in_lmn /* Autotools tokens */ #endif /* !HAVE_CONFIG_H */ /* Standard C headers */ #include /* sin cos cos sin 3.14159 */ #include /* stderr, FILE, NULL, etc. */ #include /* atof, atoi, malloc, getopt */ #include /* strcmp() */ #ifdef HAVE_STRINGS_H # include /* strcasecmp() */ #endif /* !HAVE_STRINGS_H */ #include /* stat() */ #include /* machine time */ #ifndef _MSC_VER # include /* POSIX stuff */ #endif #ifndef HAVE_GETOPT_LONG # include "nco_getopt.h" #else /* HAVE_GETOPT_LONG */ # ifdef HAVE_GETOPT_H # include # endif /* !HAVE_GETOPT_H */ #endif /* HAVE_GETOPT_LONG */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ /* #define MAIN_PROGRAM_FILE MUST precede #include libnco.h */ #define MAIN_PROGRAM_FILE #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "libnco.h" /* netCDF Operator (NCO) library */ int main(int argc,char **argv) { aed_sct *aed_lst=NULL_CEWI; nco_bool FL_RTR_RMT_LCN; nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ nco_bool FORCE_APPEND=False; /* Option A */ nco_bool FORCE_OVERWRITE=False; /* Option O */ nco_bool HISTORY_APPEND=True; /* Option h */ nco_bool FL_OUT_NEW=False; nco_bool RAM_OPEN=False; /* [flg] Open (netCDF3-only) file(s) in RAM */ nco_bool RM_RMT_FL_PST_PRC=True; /* Option R */ nco_bool flg_cln=False; /* [flg] Clean memory prior to exit */ char **fl_lst_abb=NULL; /* Option n */ char **fl_lst_in; char *aed_arg[NC_MAX_ATTRS]; char *cmd_ln; char *fl_in=NULL; char *fl_out=NULL; /* Option o */ char *fl_pth=NULL; /* Option p */ char *fl_pth_lcl=NULL; /* Option l */ char *opt_crr=NULL; /* [sng] String representation of current long-option name */ char *sng_cnv_rcd=NULL_CEWI; /* [sng] strtol()/strtoul() return code */ char trv_pth[]="/"; /* [sng] Root path of traversal tree */ const char * const CVS_Id="$Id: ncatted.c,v 1.185 2014/02/06 21:07:52 pvicente Exp $"; const char * const CVS_Revision="$Revision: 1.185 $"; const char * const opt_sht_lst="Aa:D:hl:Oo:p:Rr-:"; #if defined(__cplusplus) || defined(PGI_CC) ddra_info_sct ddra_info; ddra_info.flg_ddra=False; #else /* !__cplusplus */ ddra_info_sct ddra_info={.flg_ddra=False}; #endif /* !__cplusplus */ extern char *optarg; extern int optind; int abb_arg_nbr=0; int fl_nbr=0; int nbr_aed=0; /* Option a. NB: nbr_var_aed gets incremented */ int nbr_var_fl; int nc_id; int md_open; /* [enm] Mode flag for nc_open() call */ int opt; int rcd=NC_NOERR; /* [rcd] Return code */ size_t bfr_sz_hnt=NC_SIZEHINT_DEFAULT; /* [B] Buffer size hint */ size_t hdr_pad=0UL; /* [B] Pad at end of header section */ trv_tbl_sct *trv_tbl=NULL; /* [lst] Traversal table */ nco_dmn_dne_t *flg_dne=NULL; /* [lst] Flag to check if input dimension -d "does not exist" */ static struct option opt_lng[]= { /* Structure ordered by short option key if possible */ /* Long options with no argument, no short option counterpart */ {"cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"clean",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"mmr_cln",no_argument,0,0}, /* [flg] Clean memory prior to exit */ {"drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"dirty",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"mmr_drt",no_argument,0,0}, /* [flg] Allow dirty memory on exit */ {"hdf4",no_argument,0,0}, /* [flg] Treat file as HDF4 */ {"ram_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"create_ram",no_argument,0,0}, /* [flg] Create file in RAM */ {"open_ram",no_argument,0,0}, /* [flg] Open (netCDF3) file(s) in RAM */ {"diskless_all",no_argument,0,0}, /* [flg] Open (netCDF3) and create file(s) in RAM */ {"version",no_argument,0,0}, {"vrs",no_argument,0,0}, /* Long options with argument, no short option counterpart */ {"bfr_sz_hnt",required_argument,0,0}, /* [B] Buffer size hint */ {"buffer_size_hint",required_argument,0,0}, /* [B] Buffer size hint */ {"hdr_pad",required_argument,0,0}, {"header_pad",required_argument,0,0}, /* Long options with short counterparts */ {"append",no_argument,0,'A'}, {"attribute",required_argument,0,'a'}, {"debug",required_argument,0,'D'}, {"nco_dbg_lvl",required_argument,0,'D'}, {"history",no_argument,0,'h'}, {"hst",no_argument,0,'h'}, {"local",required_argument,0,'l'}, {"lcl",required_argument,0,'l'}, {"overwrite",no_argument,0,'O'}, {"ovr",no_argument,0,'O'}, {"output",required_argument,0,'o'}, {"fl_out",required_argument,0,'o'}, {"path",required_argument,0,'p'}, {"retain",no_argument,0,'R'}, {"rtn",no_argument,0,'R'}, {"help",no_argument,0,'?'}, {"hlp",no_argument,0,'?'}, {0,0,0,0} }; /* end opt_lng */ int opt_idx=0; /* Index of current long option into opt_lng array */ /* Start timer and save command line */ ddra_info.tmr_flg=nco_tmr_srt; rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_mtd; cmd_ln=nco_cmd_ln_sng(argc,argv); /* Get program name and set program enum (e.g., nco_prg_id=ncra) */ nco_prg_nm=nco_prg_prs(argv[0],&nco_prg_id); /* Parse command line arguments */ while(1){ /* getopt_long_only() allows one dash to prefix long options */ opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); /* NB: access to opt_crr is only valid when long_opt is detected */ if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ opt_crr=(char *)strdup(opt_lng[opt_idx].name); /* Process long options without short option counterparts */ if(opt == 0){ if(!strcmp(opt_crr,"bfr_sz_hnt") || !strcmp(opt_crr,"buffer_size_hint")){ bfr_sz_hnt=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif cnk */ if(!strcmp(opt_crr,"cln") || !strcmp(opt_crr,"mmr_cln") || !strcmp(opt_crr,"clean")) flg_cln=True; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"drt") || !strcmp(opt_crr,"mmr_drt") || !strcmp(opt_crr,"dirty")) flg_cln=False; /* [flg] Clean memory prior to exit */ if(!strcmp(opt_crr,"hdf4")) nco_fmt_xtn=nco_fmt_xtn_hdf4; /* [enm] Treat file as HDF4 */ if(!strcmp(opt_crr,"hdr_pad") || !strcmp(opt_crr,"header_pad")){ hdr_pad=strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); } /* endif "hdr_pad" */ if(!strcmp(opt_crr,"ram_all") || !strcmp(opt_crr,"open_ram") || !strcmp(opt_crr,"diskless_all")) RAM_OPEN=True; /* [flg] Create file in RAM */ if(!strcmp(opt_crr,"vrs") || !strcmp(opt_crr,"version")){ (void)nco_vrs_prn(CVS_Id,CVS_Revision); nco_exit(EXIT_SUCCESS); } /* endif "vrs" */ } /* opt != 0 */ /* Process short options */ switch(opt){ case 0: /* Long options have already been processed, return */ break; case 'A': /* Toggle FORCE_APPEND */ FORCE_APPEND=!FORCE_APPEND; break; case 'a': /* Copy argument for later processing */ aed_arg[nbr_aed]=(char *)strdup(optarg); nbr_aed++; break; case 'D': /* Debugging level. Default is 0. */ nco_dbg_lvl=(unsigned short int)strtoul(optarg,&sng_cnv_rcd,NCO_SNG_CNV_BASE10); if(*sng_cnv_rcd) nco_sng_cnv_err(optarg,"strtoul",sng_cnv_rcd); break; case 'h': /* Toggle appending to history global attribute */ HISTORY_APPEND=!HISTORY_APPEND; break; case 'l': /* Local path prefix for files retrieved from remote file system */ fl_pth_lcl=(char *)strdup(optarg); break; case 'O': /* Toggle FORCE_OVERWRITE */ FORCE_OVERWRITE=!FORCE_OVERWRITE; break; case 'o': /* Name of output file */ fl_out=(char *)strdup(optarg); break; case 'p': /* Common file path */ fl_pth=(char *)strdup(optarg); break; case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ RM_RMT_FL_PST_PRC=!RM_RMT_FL_PST_PRC; break; case 'r': /* Print CVS program information and copyright notice */ (void)nco_vrs_prn(CVS_Id,CVS_Revision); (void)nco_lbr_vrs_prn(); (void)nco_cpy_prn(); (void)nco_cnf_prn(); nco_exit(EXIT_SUCCESS); break; case '?': /* Print proper usage */ (void)nco_usg_prn(); nco_exit(EXIT_SUCCESS); break; case '-': /* Long options are not allowed */ (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; default: /* Print proper usage */ (void)fprintf(stdout,"%s ERROR in command-line syntax/options. Please reformulate command accordingly.\n",nco_prg_nm_get()); (void)nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end switch */ if(opt_crr) opt_crr=(char *)nco_free(opt_crr); } /* end while loop */ /* Process positional arguments and fill in filenames */ fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); if(fl_out) FL_OUT_NEW=True; else fl_out=(char *)strdup(fl_lst_in[0]); if(nbr_aed == 0){ (void)fprintf(stdout,"%s: ERROR must specify an attribute to edit\n",nco_prg_nm); nco_usg_prn(); nco_exit(EXIT_FAILURE); } /* end if */ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: DEBUG attribute assumed to hold missing data is named \"%s\"\n",nco_prg_nm_get(),nco_mss_val_sng_get()); /* Make uniform list of user-specified attribute edit structures */ if(nbr_aed > 0) aed_lst=nco_prs_aed_lst(nbr_aed,aed_arg); /* We now have final list of attributes to edit */ /* Parse filename */ fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); /* Make sure file is on local system and is readable or die trying */ fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FL_RTR_RMT_LCN); if(FL_OUT_NEW){ /* Obtain user consent, if needed, to overwrite output file (or die trying) */ if(!FORCE_OVERWRITE) nco_fl_overwrite_prm(fl_out); /* Copy input file to output file and then search through output, changing names on the fly. This avoids possible XDR translation performance penalty of copying each variable with netCDF. */ (void)nco_fl_cp(fl_in,fl_out); /* Ensure output file is user/owner-writable */ (void)nco_fl_chmod(fl_out); } /* end if FL_OUT_NEW */ /* Open file. Writing must be enabled and file should be in define mode for renaming */ /* if(nco_dbg_lvl == 8) md_open|=NC_SHARE;*/ if(RAM_OPEN) md_open=NC_WRITE|NC_DISKLESS; else md_open=NC_WRITE; rcd+=nco_fl_open(fl_out,md_open,&bfr_sz_hnt,&nc_id); (void)nco_redef(nc_id); /* Get number of variables in file */ (void)nco_inq(nc_id,(int *)NULL,&nbr_var_fl,(int *)NULL,(int *)NULL); /* Initialize traversal table */ trv_tbl_init(&trv_tbl); /* Construct GTT (Group Traversal Table) */ (void)nco_bld_trv_tbl(nc_id,trv_pth,(int)0,NULL,(int)0,NULL,False,False,NULL,(int)0,NULL,(int) 0,False,False,False,True,&flg_dne,trv_tbl); /* Timestamp end of metadata setup and disk layout */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); ddra_info.tmr_flg=nco_tmr_rgl; /* Loop input names */ for(int idx_aed=0;idx_aed+?|{}")){ /* Variable name contains a "regular expression" (rx) ... */ trv_tbl_sct *trv_tbl_rx; char **var_lst_in; /* I [sng] User-specified list of variables */ int var_lst_in_nbr; /* I [nbr] Number of variables in list */ var_lst_in=nco_lst_prs_2D(aed_lst[idx_aed].var_nm,",",&var_lst_in_nbr); trv_tbl_init(&trv_tbl_rx); /* Construct GTT (Group Traversal Table) */ (void)nco_bld_trv_tbl(nc_id,trv_pth,(int)0,NULL,(int)0,NULL,False,False,NULL,(int)0,var_lst_in,var_lst_in_nbr,False,False,False,False,&flg_dne,trv_tbl_rx); /* Edit same attribute for all variables ... */ (void)nco_aed_prc_var_xtr(nc_id,aed_lst[idx_aed],trv_tbl_rx); trv_tbl_free(trv_tbl_rx); var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); }else if(!strcasecmp(aed_lst[idx_aed].var_nm,"group")){ /* Variable name indicates a group attribute ... */ (void)nco_aed_prc_grp(nc_id,aed_lst[idx_aed],trv_tbl); }else if(!strcasecmp(aed_lst[idx_aed].var_nm,"global")){ /* Variable name indicates a global attribute ... */ (void)nco_aed_prc_glb(nc_id,aed_lst[idx_aed],trv_tbl); }else{ /* Variable is a normal variable ... */ /* Inquire if any variable matches (absolute, relative) */ (void)nco_aed_prc_var_nm(nc_id,aed_lst[idx_aed],trv_tbl); } /* end var_nm */ } /* Loop input names */ /* Catenate the timestamped command line to the "history" global attribute */ if(HISTORY_APPEND) (void)nco_hst_att_cat(nc_id,cmd_ln); /* Take output file out of define mode */ if(hdr_pad == 0UL){ (void)nco_enddef(nc_id); }else{ (void)nco__enddef(nc_id,hdr_pad); if(nco_dbg_lvl >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO Padding header with %lu extra bytes\n",nco_prg_nm_get(),(unsigned long)hdr_pad); } /* hdr_pad */ /* Close the open netCDF file */ nco_close(nc_id); /* Remove local copy of file */ if(FL_RTR_RMT_LCN && RM_RMT_FL_PST_PRC) (void)nco_fl_rm(fl_in); /* Clean memory unless dirty memory allowed */ if(flg_cln){ /* ncatted-specific memory */ for(int idx=0;idx 0) aed_lst=(aed_sct *)nco_free(aed_lst); /* NCO-generic clean-up */ /* Free individual strings/arrays */ if(cmd_ln) cmd_ln=(char *)nco_free(cmd_ln); if(fl_in) fl_in=(char *)nco_free(fl_in); if(fl_out) fl_out=(char *)nco_free(fl_out); if(fl_pth) fl_pth=(char *)nco_free(fl_pth); if(fl_pth_lcl) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); /* Free lists of strings */ if(fl_lst_in && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); if(fl_lst_in && fl_lst_abb) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); if(fl_lst_abb) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); trv_tbl_free(trv_tbl); } /* !flg_cln */ /* End timer */ ddra_info.tmr_flg=nco_tmr_end; /* [enm] Timer flag */ rcd+=nco_ddra((char *)NULL,(char *)NULL,&ddra_info); if(rcd != NC_NOERR) nco_err_exit(rcd,"main"); nco_exit_gracefully(); return EXIT_SUCCESS; } /* end main() */ ./nco-4.4.2/src/nco/nco_cnf_dmn.h0000644000674300045400000000707012260451231015737 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_cnf_dmn.h,v 1.39 2013/12/31 05:14:01 zender Exp $ */ /* Purpose: Conform dimensions */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Usage: #include "nco_cnf_dmn.h" *//* Conform dimensions */ #ifndef NCO_CNF_DMN_H #define NCO_CNF_DMN_H /* Standard header files */ #include /* stderr, FILE, NULL, printf */ #include /* strtod, strtol, malloc, getopt, qsort */ #include /* strcmp() */ /* 3rd party vendors */ #include /* netCDF definitions and C library */ #include "nco_netcdf.h" /* NCO wrappers for netCDF C library */ /* Personal headers */ #include "nco.h" /* netCDF Operator (NCO) definitions */ #include "nco_ctl.h" /* Program flow control functions */ #include "nco_lst_utl.h" /* List utilities */ #include "nco_mmr.h" /* Memory management */ #include "nco_rth_utl.h" /* Arithmetic controls and utilities */ #include "nco_var_utl.h" /* Variable utilities */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ var_sct * /* O [sct] Pointer to conforming variable structure */ nco_var_cnf_dmn /* [fnc] Stretch second variable to match dimensions of first variable */ (const var_sct * const var, /* I [ptr] Pointer to variable structure to serve as template */ var_sct * const wgt, /* I [ptr] Pointer to variable structure to make conform to var */ var_sct *wgt_crr, /* I/O [ptr] pointer to existing conforming variable structure, if any (destroyed when does not conform to var) */ const nco_bool MUST_CONFORM, /* I [flg] Must wgt and var conform? */ nco_bool *DO_CONFORM); /* O [flg] Do wgt and var conform? */ nco_bool /* [flg] var_1 and var_2 conform after processing */ ncap_var_cnf_dmn /* [fnc] Broadcast smaller variable into larger */ (var_sct **var_1, /* I/O [ptr] First variable */ var_sct **var_2); /* I/O [ptr] Second variable */ dmn_sct ** /* O [sct] Dimension structures to be re-ordered */ nco_dmn_avg_rdr_prp /* [fnc] Process dimension string list into dimension structure list */ (dmn_sct ** const dmn_in, /* I [sct] Dimension list for input file */ char **dmn_rdr_lst, /* I [sng] Names of dimensions to be re-ordered */ const int dmn_rdr_nbr); /* I [nbr] Number of dimension structures in re-order list */ char * /* [sng] Name of record dimension, if any, required by re-order */ nco_var_dmn_rdr_mtd /* [fnc] Change dimension ordering of variable metadata */ (const var_sct * const var_in, /* I [ptr] Variable with metadata and data in original order */ var_sct * const var_out, /* I/O [ptr] Variable whose metadata will be re-ordered */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_rdr), /* I [sct] List of dimension structures in new order */ const int dmn_rdr_nbr, /* I [nbr] Number of dimension structures in structure list */ int * const dmn_idx_out_in, /* O [idx] Dimension correspondence, output->input */ const nco_bool * const dmn_rvr_rdr, /* I [idx] Reverse dimension */ nco_bool * const dmn_rvr_in); /* O [idx] Reverse dimension */ int /* O [enm] Return success code */ nco_var_dmn_rdr_val /* [fnc] Change dimension ordering of variable values */ (const var_sct * const var_in, /* I [ptr] Variable with metadata and data in original order */ var_sct * const var_out, /* I/O [ptr] Variable whose data will be re-ordered */ const int * const dmn_idx_out_in, /* I [idx] Dimension correspondence, output->input */ const nco_bool * const dmn_rvr_in); /* I [idx] Reverse dimension */ #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ #endif /* NCO_CNF_DMN_H */ ./nco-4.4.2/src/nco/ncap_utl.c0000644000674300045400000014435112274266124015312 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/ncap_utl.c,v 1.158 2014/02/04 22:40:20 zender Exp $ */ /* Purpose: netCDF arithmetic processor */ /* Copyright (C) 1995--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ #include #include "ncap.h" /* netCDF arithmetic processor */ extern char ncap_err_sng[200]; /* [sng] Buffer for error string (declared in ncap_lex.l) */ var_sct * /* fxm: which prototype to use? */ /* ncap_var_init(const char * const var_nm,prs_sct *prs_arg) */ ncap_var_init(char *var_nm,prs_sct *prs_arg) { /* Purpose: Initialize variable structure, retrieve variable values from disk Parser calls ncap_var_init() when it encounters a new RHS variable */ /* const char fnc_nm[]="ncap_var_init()"; *//* [sng] Function name */ int idx; int jdx; int dmn_var_nbr; int *dim_id=NULL; int var_id; int rcd; int fl_id; nco_bool DEF_VAR=False; dmn_sct *dmn_in; dmn_sct **dim_new=NULL_CEWI; var_sct var_lkp; var_sct *var; var_sct *var_lst; /* Several possiblilties here: var NOT in I or O var in I var in O (defined and filled) var in 0 (defined but empty) Must handle case var in I, var in O (defined & empty) with care This occurs when var is on LHS and RHS, e.g., two=two^6 INITIAL SCAN check var list for var -- if present fill with nulls and return Not present check output then input FINAL SCAN check var list for var -- if present & defined + filled return var from output if present & defined + unfilled reurn var from input if defined Not present check output then input */ var_lkp.nm=strdup(var_nm); var_lst=ncap_var_lookup(&var_lkp,((prs_sct*)prs_arg),False); (void)nco_free(var_lkp.nm); if(prs_arg->ntl_scn && var_lst){ var=nco_var_dpl(var_lst); var->val.vp=NULL; return var; } /* endif */ /* Check if var in list has been defined but NOT filled */ if(!prs_arg->ntl_scn && var_lst && var_lst->sz >0 ) DEF_VAR=True; /* Check output file for var */ rcd=nco_inq_varid_flg(prs_arg->out_id,var_nm,&var_id); if(rcd == NC_NOERR && !DEF_VAR){ fl_id=prs_arg->out_id; }else{ /* Check input file for ID */ rcd=nco_inq_varid_flg(prs_arg->in_id,var_nm,&var_id); if(rcd != NC_NOERR){ /* Return NULL if variable not in input or output file */ (void)fprintf(stderr,"WARNING unable to find %s in %s or %s\n",var_nm,prs_arg->fl_in,prs_arg->fl_out); return (var_sct *)NULL; } /* end if */ /* Find dimensions used in var Learn which are not already in output list prs_arg->dmn_out and output file Add these to output list and output file */ (void)nco_redef(prs_arg->out_id); fl_id=prs_arg->in_id; (void)nco_inq_varndims(fl_id,var_id,&dmn_var_nbr); if(dmn_var_nbr>0){ dim_id=(int *)nco_malloc(dmn_var_nbr*sizeof(int)); (void)nco_inq_vardimid(fl_id,var_id,dim_id); for(idx=0;idxnbr_dmn_in;jdx++){ /* De-reference */ dmn_in=prs_arg->dmn_in[jdx]; if(dim_id[idx] != dmn_in->id || dmn_in->xrf) continue; /* Define new dimension in (prs_arg->dmn_out) */ dim_new=nco_dmn_out_grow(prs_arg); *dim_new=nco_dmn_dpl(dmn_in); (void)nco_dmn_xrf(*dim_new,dmn_in); /* Write new dimension to output file */ (void)nco_dmn_dfn(prs_arg->fl_out,prs_arg->out_id,dim_new,1); if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: DEBUG Found new dimension %s in input variable %s in file %s. Defining dimension %s in output file %s\n",nco_prg_nm_get(),(*dim_new)->nm,var_nm,prs_arg->fl_in,(*dim_new)->nm,prs_arg->fl_out); break; } /* end loop over dimensions in current output dimension list */ (void)nco_free(dim_id); } /* end loop over dimension in current input variable */ (void)nco_enddef(prs_arg->out_id); } /* end else */ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: parser VAR action called ncap_var_init() to retrieve %s from disk\n",nco_prg_nm_get(),var_nm); var=nco_var_fll(fl_id,var_id,var_nm,*(prs_arg->dmn_out),*(prs_arg->nbr_dmn_out)); /* var->nm=(char *)nco_malloc((strlen(var_nm)+1UL)*sizeof(char)); (void)strcpy(var->nm,var_nm); */ /* Tally is not required yet since ncap does not perform cross-file operations (yet) */ /* var->tally=(long *)nco_malloc_dbg(var->sz*sizeof(long int),"Unable to malloc() tally buffer in variable initialization",fnc_nm); (void)nco_zero_long(var->sz,var->tally); */ var->tally=(long *)NULL; /* Retrieve variable values from disk into memory */ if(prs_arg->ntl_scn) { var->val.vp=(void*)NULL; }else{ (void)nco_var_get(fl_id,var); } /* end else */ /* (void)nco_var_free(var_nm);*/ /* (void)nco_free(var_nm->nm);*/ /* var=nco_var_upk(var); */ return var; } /* end ncap_var_init() */ dmn_sct ** nco_dmn_out_grow (prs_sct * prs_arg) { /* Purpose: Expand dimension list by one and return pointer to newly created member */ int *sz; sz=prs_arg->nbr_dmn_out; *(prs_arg->dmn_out)=(dmn_sct **)nco_realloc(*(prs_arg->dmn_out),(++*sz)*sizeof(dmn_sct *)); return (*(prs_arg->dmn_out)+(*sz-1)); } /* end nco_dmn_out_grow() */ int ncap_var_write (var_sct *var, prs_sct *prs_arg) { /* Purpose: Define variable in output file and write variable */ /* const char mss_val_sng[]="missing_value"; *//* [sng] Unidata standard string for missing value */ const char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ const char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ int rcd; /* [rcd] Return code */ int var_out_id; var_sct *ptr_var; var_sct *var_dpl; nco_bool DEF_VAR; /* True if var has been defined in O in initial scan */ #ifdef NCO_RUSAGE_DBG long maxrss; /* [B] Maximum resident set size */ #endif /* !NCO_RUSAGE_DBG */ /* If inital scan duplicate then save in list, free val.vp */ if(prs_arg->ntl_scn){ var->val.vp=nco_free(var->val.vp); var_dpl=nco_var_dpl(var); assert(var_dpl->nm); if(ncap_var_lookup(var_dpl,((prs_sct*)prs_arg),True)) (void)fprintf(stdout,"%s: variable %s defined\n",nco_prg_nm_get(),var->nm); (void)nco_var_free(var); return True; } /* endif ntl_scn */ /* Check if var is in table AND has been defined NB: var and ptr_var are different */ ptr_var=ncap_var_lookup(var,((prs_sct*)prs_arg),False); DEF_VAR=(ptr_var && ptr_var->sz > 0 ? True : False); rcd=nco_inq_varid_flg(((prs_sct *)prs_arg)->out_id,var->nm,&var_out_id); if(!DEF_VAR){ /* Check to see if variable has already been defined and written */ if(rcd == NC_NOERR){ (void)sprintf(ncap_err_sng,"Warning: Variable %s has aleady been saved in %s",var->nm,((prs_sct *)prs_arg)->fl_out); (void)nco_yyerror(prs_arg,ncap_err_sng); var = nco_var_free(var); return False; } } /* DEF_VAR */ if(DEF_VAR && (var->pck_ram || var->has_mss_val)){ /* Put file in define mode to allow metadata writing */ (void)nco_redef(prs_arg->out_id); /* Put missing value */ if(var->has_mss_val) (void)nco_put_att(prs_arg->out_id,var_out_id,nco_mss_val_sng_get(),var->type,1,var->mss_val.vp); /* Write/overwrite scale_factor and add_offset attributes */ if(var->pck_ram){ /* Variable is packed in memory */ if(var->has_scl_fct) (void)nco_put_att(prs_arg->out_id,var_out_id,scl_fct_sng,var->typ_upk,1,var->scl_fct.vp); if(var->has_add_fst) (void)nco_put_att(prs_arg->out_id,var_out_id,add_fst_sng,var->typ_upk,1,var->add_fst.vp); } /* endif pck_ram */ /* Take output file out of define mode */ (void)nco_enddef(prs_arg->out_id); } /* endif DEF_VAR... */ if(!DEF_VAR){ /* Put file in define mode to allow metadata writing */ (void)nco_redef(prs_arg->out_id); /* Define variable */ (void)nco_def_var(prs_arg->out_id,var->nm,var->type,var->nbr_dim,var->dmn_id,&var_out_id); /* Set HDF Lempel-Ziv compression level, if requested */ if(prs_arg->dfl_lvl >= 0 && var->nbr_dim > 0) (void)nco_def_var_deflate(prs_arg->out_id,var_out_id,(int)True,(int)True,prs_arg->dfl_lvl); /* Set chunk sizes, if requested */ if(prs_arg->cnk_sz && var->nbr_dim > 0) (void)nco_def_var_chunking(prs_arg->out_id,var_out_id,(int)NC_CHUNKED,prs_arg->cnk_sz); /* Put missing value */ if(var->has_mss_val) (void)nco_put_att(prs_arg->out_id,var_out_id,nco_mss_val_sng_get(),var->type,1,var->mss_val.vp); /* Write/overwrite scale_factor and add_offset attributes */ if(var->pck_ram){ /* Variable is packed in memory */ if(var->has_scl_fct) (void)nco_put_att(prs_arg->out_id,var_out_id,scl_fct_sng,var->typ_upk,1,var->scl_fct.vp); if(var->has_add_fst) (void)nco_put_att(prs_arg->out_id,var_out_id,add_fst_sng,var->typ_upk,1,var->add_fst.vp); } /* endif pck_ram */ /* Take output file out of define mode */ (void)nco_enddef(prs_arg->out_id); } /* end if */ /* Write variable */ if(var->nbr_dim == 0){ (void)nco_put_var1(prs_arg->out_id,var_out_id,0L,var->val.vp,var->type); }else{ (void)nco_put_vara(prs_arg->out_id,var_out_id,var->srt,var->cnt,var->val.vp,var->type); } /* end else */ #ifdef NCO_RUSAGE_DBG /* Compile: cd ~/nco/bld;make 'USR_TKN=-DNCO_RUSAGE_DBG';cd - */ /* Print rusage memory usage statistics */ if(nco_dbg_lvl_get() >= 0) (void)fprintf(stdout,"%s: INFO ncap_var_write() writing variable %s\n",nco_prg_nm_get(),var->nm); maxrss=nco_mmr_usg_prn((int)0); #endif /* !NCO_RUSAGE_DBG */ /* Free varible */ var=nco_var_free(var); /* Use sz to keep track of defined and written variables */ if(DEF_VAR) ptr_var->sz=-1; return rcd; } /* end ncap_var_write() */ sym_sct * ncap_sym_init (const char * const sym_nm, double (*fnc_dbl)(double), float (*fnc_flt)(float)) { /* Purpose: Allocate space for sym_sct then initialize */ sym_sct *symbol; symbol=(sym_sct *)nco_malloc(sizeof(sym_sct)); symbol->nm=(char *)strdup(sym_nm); symbol->fnc_dbl=fnc_dbl; symbol->fnc_flt=fnc_flt; return symbol; } /* end ncap_sym_init() */ ptr_unn ncap_scv_2_ptr_unn (scv_sct scv) { /* Purpose: Convert scv_sct to ptr_unn malloc() appropriate space for single type NB: Does not work on strings */ ptr_unn val; nc_type type=scv.type; val.vp=(void *)nco_malloc(nco_typ_lng(type)); (void)cast_void_nctype(type,&val); switch(type){ case NC_FLOAT: *val.fp=scv.val.f; break; case NC_DOUBLE: *val.dp=scv.val.d; break; case NC_INT: *val.ip=scv.val.i; break; case NC_SHORT: *val.sp=scv.val.s; break; case NC_USHORT: *val.usp=scv.val.us; break; case NC_UINT: *val.uip=scv.val.ui; break; case NC_INT64: *val.i64p=scv.val.i64; break; case NC_UINT64: *val.ui64p=scv.val.ui64; break; case NC_BYTE: *val.bp=scv.val.b; break; case NC_UBYTE: *val.ubp=scv.val.ub; break; case NC_CHAR: break; /* do nothing */ case NC_STRING: break; /* do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ (void)cast_nctype_void(type,&val); return val; } /* end ncap_scv_2_ptr_unn() */ var_sct * /* O [sct] Sum of input variables (var_1+var_2) */ ncap_var_var_add /* [fnc] Add two variables */ (var_sct *var_1, /* I [sct] Input variable structure containing first operand */ var_sct *var_2) /* I [sct] Input variable structure containing second operand */ { /* Purpose: Add two variables */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); // if(var_1 != var_chk1) var_chk1 = (var_sct*)nco_var_free(var_chk1); //if(var_2 != var_chk2) var_chk2 = (var_sct*)nco_var_free(var_chk2); /* fxm: bug in nco_var_add()? missing_value is not carried over to var_2 in result when var_1->has_mss_val is true */ if(var_1->has_mss_val){ (void)nco_var_add(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_add(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); } /* end if */ var_1=nco_var_free(var_1); return var_2; } /* end ncap_var_var_add() */ var_sct * /* O [sct] Quotient of input variables (var_2/var_1) */ ncap_var_var_dvd /* [fnc] Divide two variables (var_2/var_1) */ (var_sct *var_1, /* I [sct] Variable structure containing denominator */ var_sct *var_2) /* I [sct] Variable structure containing numerator */ { /* Purpose: Divide two variables (var_2/var_1) */ /* Purpose: Divide two variables */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); if(var_1->has_mss_val){ (void)nco_var_dvd(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_dvd(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); } /* end else */ var_1=nco_var_free(var_1); return var_2; } /* end ncap_var_var_dvd() */ var_sct * /* O [sct] Product of input variables (var_1*var_2) */ ncap_var_var_mlt /* [fnc] Multiply two variables */ (var_sct *var_1, /* I [sct] Variable structure containing first operand */ var_sct *var_2) /* I [sct] Variable structure containing second operand */ { /* Purpose: Multiply two variables */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); if(var_1->has_mss_val){ (void)nco_var_mlt(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_mlt(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); } /* end else */ var_1=nco_var_free(var_1); return var_2; } /* end ncap_var_var_mlt() */ var_sct * /* O [sct] Remainder of modulo operation of input variables (var_1%var_2) */ ncap_var_var_mod /* [fnc] Remainder (modulo) operation of two variables */ (var_sct *var_1, /* I [sct] Variable structure containing field */ var_sct *var_2) /* I [sct] Variable structure containing divisor */ { /* Purpose: Remainder (modulo) operation of two variables (var_1%var_2) */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); if(var_1->has_mss_val){ (void)nco_var_mod(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_mod(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); } /* end else */ var_1=nco_var_free(var_1); return var_2; } /* end ncap_var_var_mod() */ var_sct * /* O [sct] Empowerment of input variables (var_1^var_2) */ ncap_var_var_pwr /* [fnc] Empowerment of two variables */ (var_sct *var_1, /* I [sct] Variable structure containing base */ var_sct *var_2) /* I [sct] Variable structure containing exponent */ { /* Purpose: Empower two variables (var_1^var_2) */ /* Purpose: Add two variables */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } /* Make sure vars are at least float precision */ if(nco_rth_prc_rnk(var_1->type) < nco_rth_prc_rnk_float && nco_rth_prc_rnk(var_2->type < nco_rth_prc_rnk_float)) var_1=nco_var_cnf_typ((nc_type)NC_FLOAT,var_1); (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); if(var_1->has_mss_val){ (void)nco_var_pwr(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_pwr(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); } /* end else */ return var_2; } /* end ncap_var_var_pwr() */ var_sct * /* O [frc] Remainder of input variables (var_2-var_1) */ ncap_var_var_sub /* [fnc] Subtract two variables (var_2-var_1) */ (var_sct *var_2, /* I [sct] Variable structure containing second operand */ /* fxm TODO: 19 non-standard argument order */ var_sct *var_1) /* I [sct] Variable structure containing first operand */ { /* Purpose: Subtract a variable from another variable */ /* Purpose: Add two variables */ /* Store result in var_2 */ if(var_1->undefined) var_2->undefined=True; if(var_2->undefined) { var_1=nco_var_free(var_1); return var_2; } (void)ncap_var_retype(var_1,var_2); /* Handle initial scan */ if(var_1->val.vp==(void*)NULL ) { if(var_1->nbr_dim > var_2->nbr_dim) { var_2=nco_var_free(var_2); return var_1; }else{ var_1=nco_var_free(var_1); return var_2; } } (void)ncap_var_cnf_dmn(&var_1,&var_2); if(var_1->has_mss_val){ (void)nco_var_sbt(var_1->type,var_1->sz,var_1->has_mss_val,var_1->mss_val,var_1->val,var_2->val); }else{ (void)nco_var_sbt(var_1->type,var_1->sz,var_2->has_mss_val,var_2->mss_val,var_1->val,var_2->val); }/* end else */ var_1=nco_var_free(var_1); return var_2; } /* end ncap_var_var_sub() */ var_sct * ncap_var_fnc(var_sct *var_in,sym_sct *app) { /* Purpose: Evaluate fnc_dbl(var) or fnc_flt(var) for each value in variable Float and double functions are in app */ long idx; long sz; ptr_unn op1; if(var_in->undefined) return var_in; /* Promote variable to NC_FLOAT */ if(nco_rth_prc_rnk(var_in->type) < nco_rth_prc_rnk_float) var_in=nco_var_cnf_typ((nc_type)NC_FLOAT,var_in); /* Handle initial scan differently */ if(var_in->val.vp==NULL) return var_in; op1=var_in->val; sz=var_in->sz; (void)cast_void_nctype(var_in->type,&op1); if(var_in->has_mss_val) (void)cast_void_nctype(var_in->type,&(var_in->mss_val)); switch(var_in->type){ case NC_DOUBLE: { if(!var_in->has_mss_val){ for(idx=0;idxfnc_dbl))(op1.dp[idx]); }else{ double mss_val_dbl=*(var_in->mss_val.dp); /* Temporary variable reduces de-referencing */ for(idx=0;idxfnc_dbl))(op1.dp[idx]); } /* end for */ } /* end else */ break; } case NC_FLOAT: { if(!var_in->has_mss_val){ for(idx=0;idxfnc_flt))(op1.fp[idx]); }else{ float mss_val_flt=*(var_in->mss_val.fp); /* Temporary variable reduces de-referencing */ for(idx=0;idxfnc_flt))(op1.fp[idx]); } /* end for */ } /* end else */ break; } default: nco_dfl_case_nc_type_err(); break; }/* end switch */ if(var_in->has_mss_val) (void)cast_nctype_void(var_in->type,&(var_in->mss_val)); return var_in; } /* end ncap_var_fnc() */ var_sct * ncap_var_scv_add(var_sct *var,scv_sct scv) { /* Purpose: add the value in scv to each element of var */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)var_scv_add(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* end ncap_var_scv_add() */ var_sct * ncap_var_scv_sub(var_sct *var,scv_sct scv) { /* Purpose: Subtract value in scv from each element of var */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)ncap_scv_minus(&scv); (void)var_scv_add(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* end ncap_var_scv_sub() */ var_sct * ncap_var_scv_mlt(var_sct *var,scv_sct scv) { /* Purpose: Multiply variable by value in scv */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)var_scv_mlt(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* end ncap_var_scv_mlt */ var_sct * ncap_var_scv_dvd(var_sct *var,scv_sct scv) { /* Purpose: Divide each element of var by value in scv */ (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)var_scv_dvd(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* end ncap_var_scv_dvd */ var_sct * ncap_scv_var_dvd(scv_sct scv,var_sct *var) { /* Purpose: Divide scv by value of each element in var */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)scv_var_dvd(var->type,var->sz,var->has_mss_val,var->mss_val,&scv,var->val); return var; } /* end ncap_scv_var_dvd */ var_sct * ncap_var_scv_mod(var_sct *var,scv_sct scv) { /* Purpose: Modulus of each element of var with scv */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)var_scv_mod(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* ncap_var_scv_mod */ var_sct * ncap_scv_var_mod(scv_sct scv,var_sct *var) { /* Purpose: Modulus of scv with each element of var */ if(var->undefined) return var; (void)ncap_var_scv_cnf_typ_hgh_prc(&var,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)scv_var_mod(var->type,var->sz,var->has_mss_val,var->mss_val,&scv,var->val); return var; } /* ncap_var_scv_mod */ var_sct * ncap_var_scv_pwr(var_sct *var,scv_sct scv) { /* Purpose: Empower each element in var by scv */ /* Promote scv and var to NC_FLOAT if necessary since C has no integer empowerment This reduces type conversion warnings (it is not done to avoid overflow) */ if(nco_rth_prc_rnk(var->type) < nco_rth_prc_rnk_float) var=nco_var_cnf_typ((nc_type)NC_FLOAT,var); (void)nco_scv_cnf_typ(var->type,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)var_scv_pwr(var->type,var->sz,var->has_mss_val,var->mss_val,var->val,&scv); return var; } /* end ncap_var_scv_pwr */ var_sct * ncap_scv_var_pwr(scv_sct scv,var_sct *var) { /* Purpose: Empower each element in scv by var */ /* Promote scv and var to NC_FLOAT if necessary since C has no integer empowerment This reduces type conversion warnings (it is not done to avoid overflow) */ if(var->undefined) return var; if(nco_rth_prc_rnk(var->type) < nco_rth_prc_rnk_float) var=nco_var_cnf_typ((nc_type)NC_FLOAT,var); (void)nco_scv_cnf_typ(var->type,&scv); /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)scv_var_pwr(var->type,var->sz,var->has_mss_val,var->mss_val,&scv,var->val); return var; } /* end ncap_var_scv_pwr */ var_sct * ncap_var_abs(var_sct *var) { /* Purpose: Find absolute value of each element of var */ if(var->undefined) return var; /* deal with inital scan */ if(var->val.vp==NULL) return var; (void)nco_var_abs(var->type,var->sz,var->has_mss_val,var->mss_val,var->val); return var; } /* end ncap_var_abs */ scv_sct ncap_scv_clc (scv_sct scv_1, const char op, scv_sct scv_2) { /* Purpose: Calculate (scv_1 op scv_2) NB: Scalar values must be of same type */ /* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html __GNUC__ : Defined by gcc __GNUG__ : Defined by g++, equivalent to (__GNUC__ && __cplusplus) */ #ifndef __GNUG__ extern float fmodf(float,float); /* Cannot insert fmodf in ncap_sym_init() because it takes two arguments TODO #20 */ extern float fabsf(float); /* Sun math.h does not include fabsf() prototype */ #endif /* __GNUG__ */ scv_sct scv_out; scv_out.type=scv_1.type; /* if(scv_1.undefined || scv_2.undefined ) { scv_out.undefined=True; return scv_out; } */ switch(scv_out.type){ case NC_FLOAT: switch(op){ case '+': scv_out.val.f=scv_1.val.f+scv_2.val.f;break; case '-': scv_out.val.f=scv_1.val.f-scv_2.val.f;break; case '/': scv_out.val.f=scv_1.val.f/scv_2.val.f;break; case '*': scv_out.val.f=scv_1.val.f*scv_2.val.f;break; case '%': scv_out.val.f=fmodf(scv_1.val.f,fabsf(scv_2.val.f));break; } break; case NC_DOUBLE: switch(op){ case '+': scv_out.val.d=scv_1.val.d+scv_2.val.d;break; case '-': scv_out.val.d=scv_1.val.d-scv_2.val.d;break; case '/': scv_out.val.d=scv_1.val.d/scv_2.val.d;break; case '*': scv_out.val.d=scv_1.val.d*scv_2.val.d;break; case '%': scv_out.val.d=fmod(scv_1.val.d,fabs(scv_2.val.d));break; } break; case NC_INT: switch(op){ case '+': scv_out.val.i=scv_1.val.i+scv_2.val.i;break; case '-': scv_out.val.i=scv_1.val.i-scv_2.val.i;break; case '/': scv_out.val.i=scv_1.val.i/scv_2.val.i;break; case '*': scv_out.val.i=scv_1.val.i*scv_2.val.i;break; case '%': scv_out.val.i=scv_1.val.i%scv_2.val.i;break; } break; case NC_SHORT: switch(op){ case '+': scv_out.val.s=scv_1.val.s+scv_2.val.s;break; case '-': scv_out.val.s=scv_1.val.s-scv_2.val.s;break; case '/': scv_out.val.s=scv_1.val.s/scv_2.val.s;break; case '*': scv_out.val.s=scv_1.val.s*scv_2.val.s;break; case '%': scv_out.val.s=scv_1.val.s%scv_2.val.s;break; } break; case NC_USHORT: switch(op){ case '+': scv_out.val.us=scv_1.val.us+scv_2.val.us;break; case '-': scv_out.val.us=scv_1.val.us-scv_2.val.us;break; case '/': scv_out.val.us=scv_1.val.us/scv_2.val.us;break; case '*': scv_out.val.us=scv_1.val.us*scv_2.val.us;break; case '%': scv_out.val.us=scv_1.val.us%scv_2.val.us;break; } break; case NC_UINT: switch(op){ case '+': scv_out.val.ui=scv_1.val.ui+scv_2.val.ui;break; case '-': scv_out.val.ui=scv_1.val.ui-scv_2.val.ui;break; case '/': scv_out.val.ui=scv_1.val.ui/scv_2.val.ui;break; case '*': scv_out.val.ui=scv_1.val.ui*scv_2.val.ui;break; case '%': scv_out.val.ui=scv_1.val.ui%scv_2.val.ui;break; } break; case NC_INT64: switch(op){ case '+': scv_out.val.i64=scv_1.val.i64+scv_2.val.i64;break; case '-': scv_out.val.i64=scv_1.val.i64-scv_2.val.i64;break; case '/': scv_out.val.i64=scv_1.val.i64/scv_2.val.i64;break; case '*': scv_out.val.i64=scv_1.val.i64*scv_2.val.i64;break; case '%': scv_out.val.i64=scv_1.val.i64%scv_2.val.i64;break; } break; case NC_UINT64: switch(op){ case '+': scv_out.val.ui64=scv_1.val.ui64+scv_2.val.ui64;break; case '-': scv_out.val.ui64=scv_1.val.ui64-scv_2.val.ui64;break; case '/': scv_out.val.ui64=scv_1.val.ui64/scv_2.val.ui64;break; case '*': scv_out.val.ui64=scv_1.val.ui64*scv_2.val.ui64;break; case '%': scv_out.val.ui64=scv_1.val.ui64%scv_2.val.ui64;break; } break; case NC_BYTE: switch(op){ case '+': scv_out.val.b=scv_1.val.b+scv_2.val.b;break; case '-': scv_out.val.b=scv_1.val.b-scv_2.val.b;break; case '/': scv_out.val.b=scv_1.val.b/scv_2.val.b;break; case '*': scv_out.val.b=scv_1.val.b*scv_2.val.b;break; case '%': scv_out.val.b=scv_1.val.b%scv_2.val.b;break; } break; case NC_UBYTE: switch(op){ case '+': scv_out.val.ub=scv_1.val.ub+scv_2.val.ub;break; case '-': scv_out.val.ub=scv_1.val.ub-scv_2.val.ub;break; case '/': scv_out.val.ub=scv_1.val.ub/scv_2.val.ub;break; case '*': scv_out.val.ub=scv_1.val.ub*scv_2.val.ub;break; case '%': scv_out.val.ub=scv_1.val.ub%scv_2.val.ub;break; } break; case NC_CHAR: break; /* Do nothing */ case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; }/* end switch */ return scv_out; } /* end ncap_scv_clc_type */ scv_sct ncap_scv_abs(scv_sct scv) { /* Purpose: Find the absolute value of a scalar value */ #ifndef __GNUG__ extern float fabsf(float); /* Sun math.h does not include fabsf() prototype */ #endif scv_sct scv_out; scv_out.type=scv.type; switch(scv.type){ case NC_FLOAT: scv_out.val.f=fabsf(scv.val.f); break; case NC_DOUBLE: scv_out.val.d=fabs(scv.val.d); break; case NC_INT: scv_out.val.i=labs(scv.val.i); break; /* int abs(int), long labs(long int) */ break; case NC_SHORT: scv_out.val.s=((scv.val.s >= 0) ? scv.val.s : -scv.val.s); break; case NC_USHORT: scv_out.val.us=scv.val.us; break; case NC_UINT: scv_out.val.ui=scv.val.ui; break; case NC_INT64: scv_out.val.i64=llabs(scv.val.i64); break; case NC_UINT64: scv_out.val.ui64=scv.val.ui64; break; case NC_BYTE: scv_out.val.b=((scv.val.b >= 0) ? scv.val.b : -scv.val.b); break; case NC_UBYTE: scv_out.val.ub=scv.val.ub; break; case NC_CHAR: break; /* Do nothing */ case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return scv_out; } /* end ncap_scv_abs */ int ncap_scv_minus(scv_sct *scv) { /* Purpose: Return negative of input */ switch(scv->type){ case NC_FLOAT: scv->val.f=-scv->val.f; break; case NC_DOUBLE: scv->val.d=-scv->val.d; break; case NC_INT: scv->val.i=-scv->val.i; break; case NC_SHORT: scv->val.s=-scv->val.s; break; case NC_INT64: scv->val.i64=-scv->val.i64; break; case NC_BYTE: scv->val.b=-scv->val.b; break; case NC_USHORT: /* NB: Unsigned */ case NC_UINT: /* NB: Unsigned */ case NC_UINT64: /* NB: Unsigned */ case NC_UBYTE: /* NB: Unsigned */ (void)fprintf(stdout,"%s: ERROR ncap_scr_minus() reports attempt to convert unsigned integer type to a negative number\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; case NC_CHAR: break; /* Do nothing */ case NC_STRING: break; /* Do nothing */ default: nco_dfl_case_nc_type_err(); break; } /* end switch */ return scv->type; } /* end ncap_scv_minus() */ nm_id_sct * nco_var_lst_copy(nm_id_sct *xtr_lst,int lst_nbr) { /* Purpose: Copy xtr_lst and return new list */ int idx; nm_id_sct *xtr_new_lst; if(lst_nbr == 0) return NULL; xtr_new_lst=(nm_id_sct *)nco_malloc(lst_nbr*sizeof(nm_id_sct)); for(idx=0;idx 0){ xtr_new_lst=(nm_id_sct *)nco_malloc((size_t)(*xtr_nbr)*sizeof(nm_id_sct)); for(idx=0;idxvar_nm,&var_id); if(rcd== NC_NOERR) continue; rcd=nco_inq_varid_flg(in_id,att_lst[idx]->var_nm,&var_id); if(rcd == NC_NOERR){ /* eliminate any duplicates from list */ for(jdx=0;jdxvar_nm)) break; if(jdx!=size) continue; /* fxm mmr TODO 491: memory leak xtr_lst */ xtr_lst=(nm_id_sct *)nco_realloc(xtr_lst,(size+1)*sizeof(nm_id_sct)); xtr_lst[size].id=var_id; xtr_lst[size++].nm=(char *)strdup(att_lst[idx]->var_nm); } /* end if */ } /* end loop over att */ *nbr_lst=size; return xtr_lst; } /* end nco_att_lst_mk() */ nco_bool /* O [flg] Variables now conform */ ncap_var_stretch /* [fnc] Stretch variables */ (var_sct **var_1, /* I/O [ptr] First variable */ var_sct **var_2) /* I/O [ptr] Second variable */ { /* Purpose: Make input variables conform or die var_1 and var_2 are considered completely symmetrically No assumption is made about var_1 relative to var_2 Main difference betwee ncap_var_stretch() and nco_var_cnf_dmn() is If variables conform, then ncap_var_stretch() will broadcast If variables share no dimensions, then ncap_var_stretch() will convolve Terminology--- Broadcast: Inflate smaller conforming variable to larger variable Conform: Dimensions of one variable are subset of other variable Convolve: Construct array whose rank is sum of non-duplicated dimensions Stretch: Union of broadcast and convolve Logic is pared down version of nco_var_cnf_dmn() 1. USE_DUMMY_WGT has been eliminated: ncap has no reason not to stretch input variables because grammar ensures only arithmetic variables will be stretched. 2. wgt_crr has been eliminated: ncap never does anything multiple times so no equivalent to wgt_crr exists 3. ncap_var_stretch(), unlike nco_var_cnf_dmn(), performs memory management Variables are var_free'd if they are superceded (replaced) 4. Conformance logic is duplicated from nco_var_cnf_dmn() var_gtr plays role of var var_lsr plays role of wgt var_lsr_out plays role of wgt_out var_lsr_out=var_lsr only if variables already conform var_gtr_out is required since both variables may change var_gtr_out=var_gtr unless convolution is required */ nco_bool CONFORMABLE=False; /* [flg] Whether var_lsr can be made to conform to var_gtr */ nco_bool CONVOLVE=False; /* [flg] var_1 and var_2 had to be convolved */ nco_bool DO_CONFORM; /* [flg] Did var_1 and var_2 conform? */ nco_bool MUST_CONFORM=False; /* [flg] Must var_1 and var_2 conform? */ int idx; int idx_dmn; int var_lsr_var_gtr_dmn_shr_nbr=0; /* [nbr] Number of dimensions shared by var_lsr and var_gtr */ var_sct *var_gtr=NULL; /* [ptr] Pointer to variable structure of greater rank */ var_sct *var_lsr=NULL; /* [ptr] Pointer to variable structure to lesser rank */ var_sct *var_gtr_out=NULL; /* [ptr] Pointer to stretched version of greater rank variable */ var_sct *var_lsr_out=NULL; /* [ptr] Pointer to stretched version of lesser rank variable */ /* Initialize flag to false. Overwrite by true after successful conformance */ DO_CONFORM=False; /* Determine which variable is greater and which lesser rank */ if((*var_1)->nbr_dim >= (*var_2)->nbr_dim){ var_gtr=*var_1; var_lsr=*var_2; }else{ var_gtr=*var_2; var_lsr=*var_1; } /* endif */ /* var_gtr_out=var_gtr unless convolution is required */ var_gtr_out=var_gtr; /* Does lesser variable (var_lsr) conform to greater variable's dimensions? */ if(var_lsr_out == NULL){ if(var_gtr->nbr_dim > 0){ /* Test that all dimensions in var_lsr appear in var_gtr */ for(idx=0;idxnbr_dim;idx++){ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Compare names, not dimension IDs */ if(!strcmp(var_lsr->dim[idx]->nm,var_gtr->dim[idx_dmn]->nm)){ var_lsr_var_gtr_dmn_shr_nbr++; /* var_lsr and var_gtr share this dimension */ break; } /* endif */ } /* end loop over var_gtr dimensions */ } /* end loop over var_lsr dimensions */ /* Decide whether var_lsr and var_gtr dimensions conform, are mutually exclusive, or are partially exclusive */ if(var_lsr_var_gtr_dmn_shr_nbr == var_lsr->nbr_dim){ /* var_lsr and var_gtr conform */ /* fxm: Variables do not conform when dimension list of one is subset of other if order of dimensions differs, i.e., a(lat,lev,lon) !~ b(lon,lev) */ CONFORMABLE=True; }else if(var_lsr_var_gtr_dmn_shr_nbr == 0){ /* Dimensions in var_lsr and var_gtr are mutually exclusive */ CONFORMABLE=False; if(MUST_CONFORM){ (void)fprintf(stdout,"%s: ERROR %s and template %s share no dimensions\n",nco_prg_nm_get(),var_lsr->nm,var_gtr->nm); nco_exit(EXIT_FAILURE); }else{ if(nco_dbg_lvl_get() >= 1) (void)fprintf(stdout,"\n%s: DEBUG %s and %s share no dimensions: Attempting to convolve...\n",nco_prg_nm_get(),var_lsr->nm,var_gtr->nm); CONVOLVE=True; } /* endif */ }else if(var_lsr_var_gtr_dmn_shr_nbr > 0 && var_lsr_var_gtr_dmn_shr_nbr < var_lsr->nbr_dim){ /* Some, but not all, of var_lsr dimensions are in var_gtr */ CONFORMABLE=False; if(MUST_CONFORM){ (void)fprintf(stdout,"%s: ERROR %d dimensions of %s belong to template %s but %d dimensions do not\n",nco_prg_nm_get(),var_lsr_var_gtr_dmn_shr_nbr,var_lsr->nm,var_gtr->nm,var_lsr->nbr_dim-var_lsr_var_gtr_dmn_shr_nbr); nco_exit(EXIT_FAILURE); }else{ if(nco_dbg_lvl_get() >= 1) (void)fprintf(stdout,"\n%s: DEBUG %d dimensions of %s belong to template %s but %d dimensions do not: Not broadcasting %s to %s, could attempt stretching???\n",nco_prg_nm_get(),var_lsr_var_gtr_dmn_shr_nbr,var_lsr->nm,var_gtr->nm,var_lsr->nbr_dim-var_lsr_var_gtr_dmn_shr_nbr,var_lsr->nm,var_gtr->nm); CONVOLVE=True; } /* endif */ } /* end if */ if(CONFORMABLE){ if(var_gtr->nbr_dim == var_lsr->nbr_dim){ /* var_gtr and var_lsr conform and are same rank */ /* Test whether all var_lsr and var_gtr dimensions match in sequence */ for(idx=0;idxnbr_dim;idx++){ if(strcmp(var_lsr->dim[idx]->nm,var_gtr->dim[idx]->nm)) break; } /* end loop over dimensions */ /* If so, take shortcut and copy var_lsr to var_lsr_out */ if(idx == var_gtr->nbr_dim) DO_CONFORM=True; }else{ /* var_gtr and var_lsr conform but are not same rank, set flag to proceed to generic conform routine */ DO_CONFORM=False; } /* end else */ } /* endif CONFORMABLE */ }else{ /* nbr_dmn == 0 */ /* var_gtr is scalar, if var_lsr is also then set flag to copy var_lsr to var_lsr_out else proceed to generic conform routine */ if(var_lsr->nbr_dim == 0) DO_CONFORM=True; else DO_CONFORM=False; } /* end else nbr_dmn == 0 */ if(CONFORMABLE && DO_CONFORM){ var_lsr_out=nco_var_dpl(var_lsr); (void)nco_xrf_var(var_lsr,var_lsr_out); } /* end if */ } /* endif var_lsr_out == NULL */ if(var_lsr_out == NULL && CONVOLVE){ /* Convolve variables by returned stretched variables with minimum possible number of dimensions */ int dmn_nbr; /* Number of dimensions in convolution */ if(nco_dbg_lvl_get() >= 1) (void)fprintf(stdout,"\n%s: WARNING Convolution not yet implemented, results of operation between %s and %s are unpredictable\n",nco_prg_nm_get(),var_lsr->nm,var_gtr->nm); /* Dimensions in convolution are union of dimensions in variables */ dmn_nbr=var_lsr->nbr_dim+var_gtr->nbr_dim-var_lsr_var_gtr_dmn_shr_nbr; /* Number of dimensions in convolution */ dmn_nbr=dmn_nbr+0; /* CEWI: Avert compiler warning that variable is set but never used */ /* fxm: these should go away soon */ var_lsr_out=nco_var_dpl(var_lsr); var_gtr_out=nco_var_dpl(var_gtr); /* for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){;} if(var_lsr_var_gtr_dmn_shr_nbr == 0); else; */ /* Free calling variables */ var_lsr=nco_var_free(var_lsr); var_gtr=nco_var_free(var_gtr); } /* endif STRETCH */ if(var_lsr_out == NULL){ /* Expand lesser variable (var_lsr) to match size of greater variable */ const char fnc_nm[]="ncap_var_stretch()"; /* [sng] Function name */ char *var_lsr_cp; char *var_lsr_out_cp; int idx_var_lsr_var_gtr[NC_MAX_DIMS]; int var_lsr_nbr_dim; int var_gtr_nbr_dmn_m1; long *var_gtr_cnt; long dmn_ss[NC_MAX_DIMS]; long dmn_var_gtr_map[NC_MAX_DIMS]; long dmn_var_lsr_map[NC_MAX_DIMS]; long var_gtr_lmn; long var_lsr_lmn; long var_gtr_sz; size_t var_lsr_typ_sz; /* Copy main attributes of greater variable into lesser variable */ var_lsr_out=nco_var_dpl(var_gtr); (void)nco_xrf_var(var_lsr,var_lsr_out); /* Modify elements of lesser variable array */ var_lsr_out->nm=(char *)nco_free(var_lsr_out->nm); var_lsr_out->nm=(char *)strdup(var_lsr->nm); var_lsr_out->id=var_lsr->id; var_lsr_out->type=var_lsr->type; /* Added 20050323: Not quite sure why, but var->val.vp may already have values here when LHS-casting Perform safety free to guard against memory leaks */ var_lsr_out->val.vp=nco_free(var_lsr_out->val.vp); var_lsr_out->val.vp=(void *)nco_malloc_dbg(var_lsr_out->sz*nco_typ_lng(var_lsr_out->type),"Unable to malloc() value buffer in variable stretching",fnc_nm); var_lsr_cp=(char *)var_lsr->val.vp; var_lsr_out_cp=(char *)var_lsr_out->val.vp; var_lsr_typ_sz=nco_typ_lng(var_lsr_out->type); if(var_lsr_out->nbr_dim == 0){ /* Variables are scalars, not arrays */ (void)memcpy(var_lsr_out_cp,var_lsr_cp,var_lsr_typ_sz); }else if(var_lsr->nbr_dim == 0){ /* Lesser-ranked input variable is scalar Expansion in this degenerate case needs no index juggling (reverse-mapping) Code as special case to speed-up important applications of ncap for synthetic file creation */ var_gtr_sz=var_gtr->sz; for(var_gtr_lmn=0;var_gtr_lmnnbr_dim;idx++){ for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Compare names, not dimension IDs */ if(!strcmp(var_gtr->dim[idx_dmn]->nm,var_lsr->dim[idx]->nm)){ idx_var_lsr_var_gtr[idx]=idx_dmn; /* idx_var_gtr_var_lsr[idx_dmn]=idx;*/ break; } /* end if */ /* Sanity check */ if(idx_dmn == var_gtr->nbr_dim-1){ (void)fprintf(stdout,"%s: ERROR var_lsr %s has dimension %s but var_gtr %s does not deep in ncap_var_stretch()\n",nco_prg_nm_get(),var_lsr->nm,var_lsr->dim[idx]->nm,var_gtr->nm); nco_exit(EXIT_FAILURE); } /* end if err */ } /* end loop over greater variable dimensions */ } /* end loop over lesser variable dimensions */ /* Figure out map for each dimension of greater variable */ for(idx=0;idxnbr_dim;idx++) dmn_var_gtr_map[idx]=1L; for(idx=0;idxnbr_dim-1;idx++) for(idx_dmn=idx+1;idx_dmnnbr_dim;idx_dmn++) dmn_var_gtr_map[idx]*=var_gtr->cnt[idx_dmn]; /* Figure out map for each dimension of lesser variable */ for(idx=0;idxnbr_dim;idx++) dmn_var_lsr_map[idx]=1L; for(idx=0;idxnbr_dim-1;idx++) for(idx_dmn=idx+1;idx_dmnnbr_dim;idx_dmn++) dmn_var_lsr_map[idx]*=var_lsr->cnt[idx_dmn]; /* Define convenience variables to avoid repetitive indirect addressing */ var_lsr_nbr_dim=var_lsr->nbr_dim; var_gtr_sz=var_gtr->sz; var_gtr_cnt=var_gtr->cnt; var_gtr_nbr_dmn_m1=var_gtr->nbr_dim-1; /* var_gtr_lmn is offset into 1-D array corresponding to N-D indices dmn_ss */ for(var_gtr_lmn=0;var_gtr_lmnnbr_dim >= (*var_2)->nbr_dim){ *var_1=var_gtr_out; /* [ptr] First variable */ *var_2=var_lsr_out; /* [ptr] Second variable */ }else{ *var_1=var_lsr_out; /* [ptr] First variable */ *var_2=var_gtr_out; /* [ptr] Second variable */ } /* endif */ /* Variables now conform */ return DO_CONFORM; } /* end ncap_var_stretch() */ ./nco-4.4.2/src/nco/nco_grp_utl.c0000644000674300045400000143156612301235125016014 0ustar zendercgdcsm/* $Header: /cvsroot/nco/nco/src/nco/nco_grp_utl.c,v 1.1263 2014/02/19 23:12:21 pvicente Exp $ */ /* Purpose: Group utilities */ /* Copyright (C) 2011--2014 Charlie Zender License: GNU General Public License (GPL) Version 3 See http://www.gnu.org/copyleft/gpl.html for full license text */ /* Testing: eos52nc4 ~/nco/data/in.he5 ~/in.nc4 export HDF5_DISABLE_VERSION_CHECK=1 ncdump -h ~/in.nc4 ncks -D 1 -m ~/in.nc4 ncks -O -D 3 -g HIRDLS -m ~/in.nc4 ~/foo.nc ncks -O -D 3 -m ~/in_grp.nc ~/foo.nc ncks -O -D 3 -v 'Q.?' ~/nco/data/in.nc ~/foo.nc */ #include "nco_grp_utl.h" /* Group utilities */ void nco_flg_set_grp_var_ass /* [fnc] Set flags for groups and variables associated with matched object */ (const char * const grp_nm_fll, /* I [sng] Full name of group */ const nco_obj_typ obj_typ, /* I [enm] Object type (group or variable) */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Set flags for groups and variables associated with matched object */ trv_sct trv_obj; /* [sct] Traversal table object */ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++){ /* Create shallow copy to avoid indirection */ trv_obj=trv_tbl->lst[obj_idx]; /* If group was user-specified, flag all variables in group */ if(obj_typ == nco_obj_typ_grp && trv_obj.nco_typ == nco_obj_typ_var) if(!strcmp(grp_nm_fll,trv_obj.grp_nm_fll)) trv_tbl->lst[obj_idx].flg_vsg=True; /* If variable was user-specified, flag group containing variable */ if(obj_typ == nco_obj_typ_var && trv_obj.nco_typ == nco_obj_typ_grp) if(!strcmp(grp_nm_fll,trv_obj.grp_nm_fll)) trv_tbl->lst[obj_idx].flg_gcv=True; /* Flag ancestor groups of all user-specified groups and variables */ if(strstr(grp_nm_fll,trv_obj.grp_nm_fll)) trv_tbl->lst[obj_idx].flg_ncs=True; } /* end loop over obj_idx */ } /* end nco_flg_set_grp_var_ass() */ int /* [rcd] Return code */ nco_inq_grps_full /* [fnc] Discover and return IDs of apex and all sub-groups */ (const int grp_id, /* I [ID] Apex group */ int * const grp_nbr, /* O [nbr] Number of groups */ int * const grp_ids) /* O [ID] Group IDs of children */ { /* Purpose: Discover and return IDs of apex and all sub-groups If grp_nbr is NULL, it is ignored If grp_ids is NULL, it is ignored grp_ids must contain enough space to hold grp_nbr IDs */ int rcd=NC_NOERR; /* [rcd] Return code */ int grp_nbr_crr; /* [nbr] Number of groups counted so far */ int grp_id_crr; /* [ID] Current group ID */ grp_stk_sct *grp_stk; /* [sct] Group stack pointer */ /* Initialize variables that are incremented */ grp_nbr_crr=0; /* [nbr] Number of groups counted (i.e., stored in grp_ids array) so far */ /* Initialize and obtain group iterator */ rcd+=nco_grp_stk_get(grp_id,&grp_stk); /* Find and return next group ID */ rcd+=nco_grp_stk_nxt(grp_stk,&grp_id_crr); while(grp_id_crr != NCO_LST_GRP){ /* Store last popped value into group ID array */ if(grp_ids) grp_ids[grp_nbr_crr]=grp_id_crr; /* [ID] Group IDs of children */ /* Increment counter */ grp_nbr_crr++; /* Find and return next group ID */ rcd+=nco_grp_stk_nxt(grp_stk,&grp_id_crr); } /* end while */ if(grp_nbr) *grp_nbr=grp_nbr_crr; /* O [nbr] Number of groups */ /* Free group iterator */ nco_grp_itr_free(grp_stk); return rcd; /* [rcd] Return code */ } /* end nco_inq_grps_full() */ int /* O [rcd] Return code */ nco_def_grp_full /* [fnc] Ensure all components of group path are defined */ (const int nc_id, /* I [ID] netCDF output-file ID */ const char * const grp_nm_fll, /* I [sng] Full group name */ int * const grp_out_id) /* O [ID] Deepest group ID */ { /* Purpose: Ensure all components of full path name exist and return ID of deepest group */ char *grp_pth=NULL; /* [sng] Full group path */ char *grp_pth_dpl=NULL; /* [sng] Full group path memory duplicate */ char *sls_ptr; /* [sng] Pointer to slash */ int grp_id_prn; /* [ID] Parent group ID */ int rcd=NC_NOERR; /* Initialize defaults */ *grp_out_id=nc_id; grp_pth_dpl=(char *)strdup(grp_nm_fll); grp_pth=grp_pth_dpl; /* No need to try to define root group */ if(grp_pth[0] == '/') grp_pth++; /* Define everything necessary beneath root group */ while(strlen(grp_pth)){ /* Terminate path at next slash, if any */ sls_ptr=strchr(grp_pth,'/'); /* Replace slash by NUL */ if(sls_ptr) *sls_ptr='\0'; /* Identify parent group */ grp_id_prn=*grp_out_id; /* If current group is not defined, define it */ if(nco_inq_ncid_flg(grp_id_prn,grp_pth,grp_out_id)) nco_def_grp(grp_id_prn,grp_pth,grp_out_id); /* Point to next group, if any */ if(sls_ptr) grp_pth=sls_ptr+1; else break; } /* end while */ grp_pth_dpl=(char *)nco_free(grp_pth_dpl); return rcd; } /* end nco_def_grp_full() */ void nco_grp_itr_free /* [fnc] Free group iterator */ (grp_stk_sct * const grp_stk) /* O [sct] Group stack pointer */ { /* Purpose: Free group iterator Call a function that hides the iterator implementation behind the API */ nco_grp_stk_free(grp_stk); } /* end nco_grp_itr_free() */ int /* [rcd] Return code */ nco_grp_stk_get /* [fnc] Initialize and obtain group iterator */ (const int grp_id, /* I [ID] Apex group */ grp_stk_sct ** const grp_stk) /* O [sct] Group stack pointer */ { /* Purpose: Initialize and obtain group iterator Routine pushes apex group onto stack The "Apex group" is normally (though not necessarily) the netCDF file ID, aka, root ID, and is the top group in the hierarchy. Returned iterator contains one valid group, the apex group, and the stack counter equals one */ int rcd=NC_NOERR; /* [rcd] Return code */ rcd+=nco_inq_grps(grp_id,(int *)NULL,(int *)NULL); /* These error codes would cause an abort in the netCDF wrapper layer anyway, so this condition is purely for defensive programming. */ if(rcd != NC_EBADID && rcd != NC_EBADGRPID){ *grp_stk=nco_grp_stk_ntl(); /* [fnc] Push group ID onto stack */ (void)nco_grp_stk_psh(*grp_stk,grp_id); } /* endif */ return rcd; /* [rcd] Return code */ } /* end nco_grp_stk_get() */ int /* [rcd] Return code */ nco_grp_stk_nxt /* [fnc] Find and return next group ID */ (grp_stk_sct * const grp_stk, /* O [sct] Group stack pointer */ int * const grp_id) /* O [ID] Group ID */ { /* Purpose: Find and return next group ID Next group ID is popped off stack If this group contains sub-groups, these sub-groups are pushed onto stack before return Hence routine ensures every group is eventually examined for sub-groups */ int *grp_ids; /* [ID] Group IDs of children */ int idx; int grp_nbr; /* I [nbr] Number of sub-groups */ int rcd=NC_NOERR; /* [rcd] Return code */ /* Is stack empty? */ if(grp_stk->grp_nbr == 0){ /* Return flag showing iterator has reached the end, i.e., no more groups */ *grp_id=NCO_LST_GRP; }else{ /* Return current stack top */ *grp_id=nco_grp_stk_pop(grp_stk); /* Replenish stack with sub-group IDs, if available */ rcd+=nco_inq_grps(*grp_id,&grp_nbr,(int *)NULL); if(grp_nbr > 0){ /* Add sub-groups of current stack top */ grp_ids=(int *)nco_malloc(grp_nbr*sizeof(int)); rcd+=nco_inq_grps(*grp_id,(int *)NULL,grp_ids); /* Push sub-group IDs in reverse order so when popped will come out in original order */ for(idx=grp_nbr-1;idx>=0;idx--) (void)nco_grp_stk_psh(grp_stk,grp_ids[idx]); /* Clean up memory */ grp_ids=(int *)nco_free(grp_ids); } /* endif sub-groups exist */ } /* endelse */ return rcd; /* [rcd] Return code */ } /* end nco_grp_stk_nxt() */ grp_stk_sct * /* O [sct] Group stack pointer */ nco_grp_stk_ntl /* [fnc] Initialize group stack */ (void) { /* Purpose: Initialize dynamic array implementation of group stack */ grp_stk_sct *grp_stk; /* O [sct] Group stack pointer */ grp_stk=(grp_stk_sct *)nco_malloc(sizeof(grp_stk)); /* O [sct] Group stack pointer */ grp_stk->grp_nbr=0; /* [nbr] Number of items in stack = number of elements in grp_id array */ grp_stk->grp_id=NULL; /* [ID] Group ID */ return grp_stk;/* O [sct] Group stack pointer */ } /* end nco_grp_stk_ntl() */ void nco_grp_stk_psh /* [fnc] Push group ID onto stack */ (grp_stk_sct * const grp_stk, /* I/O [sct] Group stack pointer */ const int grp_id) /* I [ID] Group ID to push */ { /* Purpose: Push group ID onto dynamic array implementation of stack */ grp_stk->grp_nbr++; /* [nbr] Number of items in stack = number of elements in grp_id array */ grp_stk->grp_id=(int *)nco_realloc(grp_stk->grp_id,(grp_stk->grp_nbr)*sizeof(int)); /* O [sct] Pointer to group IDs */ grp_stk->grp_id[grp_stk->grp_nbr-1]=grp_id; /* [ID] Group ID */ } /* end nco_grp_stk_psh() */ int /* O [ID] Group ID that was popped */ nco_grp_stk_pop /* [fnc] Remove and return group ID from stack */ (grp_stk_sct * const grp_stk) /* I/O [sct] Pointer to top of stack */ { /* Purpose: Remove and return group ID from dynamic array implementation of stack */ int grp_id; /* [ID] Group ID that was popped */ grp_id=grp_stk->grp_id[grp_stk->grp_nbr-1]; /* [ID] Group ID that was popped */ if(grp_stk->grp_nbr == 0){ (void)fprintf(stderr,"%s: ERROR nco_grp_stk_pop() asked to pop empty stack\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } /* endif */ grp_stk->grp_nbr--; /* [nbr] Number of items in stack = number of elements in grp_id array */ grp_stk->grp_id=(int *)nco_realloc(grp_stk->grp_id,(grp_stk->grp_nbr)*sizeof(int)); /* O [sct] Pointer to group IDs */ return grp_id; /* [ID] Group ID that was popped */ } /* end nco_grp_stk_pop() */ void nco_grp_stk_free /* [fnc] Free group stack */ (grp_stk_sct * const grp_stk) /* O [sct] Group stack pointer */ { /* Purpose: Free dynamic array implementation of stack */ grp_stk->grp_id=(int *)nco_free(grp_stk->grp_id); } /* end nco_grp_stk_free() */ void nco_prn_grp_nm_fll /* [fnc] Debug function to print group full name from ID */ (const int grp_id) /* I [ID] Group ID */ { #if defined(HAVE_NETCDF4_H) size_t grp_nm_lng; char *grp_nm_fll; (void)nco_inq_grpname_full(grp_id,&grp_nm_lng,NULL); grp_nm_fll=(char*)nco_malloc(grp_nm_lng+1L); (void)nco_inq_grpname_full(grp_id,&grp_nm_lng,grp_nm_fll); (void)fprintf(stdout,"<%s>",grp_nm_fll); grp_nm_fll=(char*)nco_free(grp_nm_fll); #endif } /* nco_prn_grp_nm_fll() */ int /* [rcd] Return code */ nco_grp_dfn /* [fnc] Define groups in output file */ (const int out_id, /* I [ID] netCDF output-file ID */ nm_id_sct *grp_xtr_lst, /* [grp] Groups to be defined */ const int grp_nbr) /* I [nbr] Number of groups to be defined */ { /* Purpose: Define groups in output file */ int idx; int rcd=NC_NOERR; /* [rcd] Return code */ int rcr_lvl=1; /* [nbr] Recursion level */ if(nco_dbg_lvl_get() >= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO nco_grp_dfn() reports file level = 0 parent group = / (root group) will have %d sub-group%s\n",nco_prg_nm_get(),grp_nbr,(grp_nbr == 1) ? "" : "s"); /* For each (possibly user-specified) top-level group ... */ for(idx=0;idx= nco_dbg_scl) (void)fprintf(stderr,"%s: INFO nco_def_grp_rcr() reports file level = %d parent group = %s will have %d sub-group%s\n",nco_prg_nm_get(),rcr_lvl,prn_nm,grp_nbr,(grp_nbr == 1) ? "" : "s"); /* Define each group, recursively, in output file */ for(idx=0;idxnm_fll); Alloc str_pth_lst_var=(sng_pth_sct **)nco_malloc(nbr_sls_chr_var*sizeof(sng_pth_sct *)); Get token list in variable full name (void)nco_get_sng_pth_sct(var_trv->nm_fll,&str_pth_lst_var); */ char *ptr_chr; /* [sng] Pointer to character '/' in full name */ char *ptr_chr_tok; /* [sng] Pointer to character */ int nbr_sls_chr=0; /* [nbr] Number of of slash characterrs in string path */ int psn_chr; /* [nbr] Position of character '/' in in full name */ /* Duplicate original, since strtok() changes it */ char *str=strdup(nm_fll); if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"Splitting \"%s\" into tokens:\n",str); /* Get first token */ ptr_chr_tok=strtok (str,"/"); ptr_chr=strchr(nm_fll,'/'); while(ptr_chr){ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"#%s ",ptr_chr_tok); psn_chr=ptr_chr-nm_fll; /* Store token and position */ (*str_pth_lst)[nbr_sls_chr]=(sng_pth_sct *)nco_malloc(1*sizeof(sng_pth_sct)); (*str_pth_lst)[nbr_sls_chr]->nm=strdup(ptr_chr_tok); (*str_pth_lst)[nbr_sls_chr]->psn=psn_chr; /* Point where last token was found is kept internally by function */ ptr_chr_tok=strtok(NULL,"/"); ptr_chr=strchr(ptr_chr+1,'/'); nbr_sls_chr++; } /* end while */ if(nco_dbg_lvl_get() == nco_dbg_old)(void)fprintf(stdout,"\n"); str=(char *)nco_free(str); return nbr_sls_chr; } /* nco_get_sls_chr_cnt() */ void nco_prn_att_trv /* [fnc] Traverse tree to print all group and global attributes */ (const int nc_id, /* I [id] netCDF file ID */ const prn_fmt_sct * const prn_flg, /* I [sct] Print-format information */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { int grp_id; /* [ID] Group ID */ int nbr_att; /* [nbr] Number of attributes */ int nbr_dmn; /* [nbr] Number of dimensions */ int nbr_var; /* [nbr] Number of variables */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct trv=trv_tbl->lst[uidx]; if(trv.nco_typ == nco_obj_typ_grp && trv.flg_xtr){ /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,trv.nm_fll,&grp_id); /* Obtain info for group */ (void)nco_inq(grp_id,&nbr_dmn,&nbr_var,&nbr_att,(int *)NULL); /* List attributes using obtained group ID */ if(nbr_att){ if(trv.grp_dpt > 0) (void)fprintf(stdout,"Group %s attributes:\n",trv.nm_fll); else (void)fprintf(stdout,"Global attributes:\n"); (void)nco_prn_att(grp_id,prn_flg,NC_GLOBAL); } /* nbr_att */ } /* end nco_obj_typ_grp */ } /* end uidx */ } /* end nco_prn_att_trv() */ int /* O [nbr] Number of matches to current rx */ nco_trv_rx_search /* [fnc] Search for pattern matches in traversal table */ (const char * const rx_sng, /* I [sng] Regular expression pattern */ const nco_obj_typ obj_typ, /* I [enm] Object type (group or variable) */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Set flags indicating whether each list member matches given regular expression NB: This function only writes True to match flag, it never writes False Input flags are assumed to be stateful, and may contain Trues from previous calls */ int mch_nbr=0; #ifndef NCO_HAVE_REGEX_FUNCTIONALITY (void)fprintf(stdout,"%s: ERROR: Sorry, wildcarding (extended regular expression matches to variables) was not built into this NCO executable, so unable to compile regular expression \"%s\".\nHINT: Make sure libregex.a is on path and re-build NCO.\n",nco_prg_nm_get(),rx_sng); nco_exit(EXIT_FAILURE); #else /* NCO_HAVE_REGEX_FUNCTIONALITY */ char *sng2mch; /* [sng] String to match to regular expression */ const char sls_chr='/'; /* [chr] Slash character */ int err_id; int flg_cmp; /* Comparison flags */ int flg_exe; /* Execution flages */ regmatch_t *result; regex_t *rx; size_t obj_idx; size_t rx_prn_sub_xpr_nbr; rx=(regex_t *)nco_malloc(sizeof(regex_t)); /* Choose RE_SYNTAX_POSIX_EXTENDED regular expression type */ flg_cmp=(REG_EXTENDED | REG_NEWLINE); /* Set execution flags */ flg_exe=0; /* Compile regular expression */ if((err_id=regcomp(rx,rx_sng,flg_cmp))){ /* Compile regular expression */ char const * rx_err_sng; /* POSIX regcomp return error codes */ switch(err_id){ case REG_BADPAT: rx_err_sng="Invalid pattern"; break; case REG_ECOLLATE: rx_err_sng="Not implemented"; break; case REG_ECTYPE: rx_err_sng="Invalid character class name"; break; case REG_EESCAPE: rx_err_sng="Trailing backslash"; break; case REG_ESUBREG: rx_err_sng="Invalid back reference"; break; case REG_EBRACK: rx_err_sng="Unmatched left bracket"; break; case REG_EPAREN: rx_err_sng="Parenthesis imbalance"; break; case REG_EBRACE: rx_err_sng="Unmatched {"; break; case REG_BADBR: rx_err_sng="Invalid contents of { }"; break; case REG_ERANGE: rx_err_sng="Invalid range end"; break; case REG_ESPACE: rx_err_sng="Ran out of memory"; break; case REG_BADRPT: rx_err_sng="No preceding re for repetition op"; break; default: rx_err_sng="Invalid pattern"; break; } /* end switch */ (void)fprintf(stdout,"%s: ERROR nco_trv_rx_search() error in regular expression \"%s\" %s\n",nco_prg_nm_get(),rx_sng,rx_err_sng); nco_exit(EXIT_FAILURE); } /* end if err */ rx_prn_sub_xpr_nbr=rx->re_nsub+1L; /* Number of parenthesized sub-expressions */ /* Search string */ result=(regmatch_t *)nco_malloc(sizeof(regmatch_t)*rx_prn_sub_xpr_nbr); /* Check each object string for match to rx */ for(obj_idx=0;obj_idxnbr;obj_idx++){ /* Check apples against apples and oranges against oranges */ if(trv_tbl->lst[obj_idx].nco_typ == obj_typ){ /* NB: Here is where match flag would be set to False if input were stateless */ /* Regular expressions embedded in simple strings (without forward slashes) apply to stubs Presence of slash indicates that regular expression applies to full pathname */ if(strchr(rx_sng,sls_chr)) sng2mch=trv_tbl->lst[obj_idx].nm_fll; else sng2mch=trv_tbl->lst[obj_idx].nm; if(!regexec(rx,sng2mch,rx_prn_sub_xpr_nbr,result,flg_exe)){ trv_tbl->lst[obj_idx].flg_mch=True; mch_nbr++; } /* end if match */ } /* end if obj_typ */ } /* end loop over variables */ regfree(rx); /* Free regular expression data structure */ rx=(regex_t *)nco_free(rx); result=(regmatch_t *)nco_free(result); #endif /* NCO_HAVE_REGEX_FUNCTIONALITY */ return mch_nbr; } /* end nco_trv_rx_search() */ nco_bool /* O [flg] All names are in file */ nco_xtr_mk /* [fnc] Check -v and -g input names and create extraction list */ (char ** grp_lst_in, /* I [sng] User-specified list of groups */ const int grp_xtr_nbr, /* I [nbr] Number of groups in list */ char ** var_lst_in, /* I [sng] User-specified list of variables */ const int var_xtr_nbr, /* I [nbr] Number of variables in list */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ const nco_bool flg_unn, /* I [flg] Select union of specified groups and variables */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Verify all user-specified objects exist in file and create extraction list Verify both variables and groups Handle regular expressions Set flags in traversal table to help generate extraction list Tests: ncks -O -D 5 -g / ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g '' ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g g1 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g /g1 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g /g1/g1 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g g1.+ ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -v v1 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g g1.+ -v v1,sc. ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -v scl,/g1/g1g1/v1 ~/nco/data/in_grp.nc ~/foo.nc ncks -O -D 5 -g g3g.+,g9/ -v scl,/g1/g1g1/v1 ~/nco/data/in_grp.nc ~/foo.nc */ const char fnc_nm[]="nco_xtr_mk()"; /* [sng] Function name */ const char sls_chr='/'; /* [chr] Slash character */ char **obj_lst_in; /* [sng] User-specified list of objects */ char *sbs_end; /* [sng] Location of user-string match end in object path */ char *sbs_srt; /* [sng] Location of user-string match start in object path */ char *sbs_srt_nxt; /* [sng] String to search next for match */ char *usr_sng; /* [sng] User-supplied object name */ char *var_mch_srt; /* [sng] Location of variable short name in user-string */ int obj_nbr; /* [nbr] Number of objects in list */ #ifdef NCO_HAVE_REGEX_FUNCTIONALITY int rx_mch_nbr; #endif /* !NCO_HAVE_REGEX_FUNCTIONALITY */ nco_bool flg_ncr_mch_crr; /* [flg] Current group meets anchoring properties of this user-supplied string */ nco_bool flg_ncr_mch_grp; /* [flg] User-supplied string anchors at root */ nco_bool flg_pth_end_bnd; /* [flg] String ends at path component boundary */ nco_bool flg_pth_srt_bnd; /* [flg] String begins at path component boundary */ nco_bool flg_rcr_mch_crr; /* [flg] Current group meets recursion criteria of this user-supplied string */ nco_bool flg_rcr_mch_grp; /* [flg] User-supplied string will match groups recursively */ nco_bool flg_unn_ffc; /* [flg] Union or Effective Union (not intersection) */ nco_bool flg_usr_mch_obj; /* [flg] One or more objects match each user-supplied string */ nco_bool flg_var_cnd; /* [flg] Match meets addition condition(s) for variable */ nco_obj_typ obj_typ; /* [enm] Object type (group or variable) */ size_t usr_sng_lng; /* [nbr] Length of user-supplied string */ trv_sct grp_obj; /* [sct] Traversal table object assumed to be group */ trv_sct trv_obj; /* [sct] Traversal table object */ trv_sct var_obj; /* [sct] Traversal table object assumed to be variable */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s Extraction list will be formed as %s of group and variable specifications if both are given\n",nco_prg_nm_get(),fnc_nm,(flg_unn) ? "union" : "intersection"); /* Specifying no groups or variables is equivalent to requesting all */ if(!grp_xtr_nbr && !var_xtr_nbr && !EXTRACT_ALL_COORDINATES) for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++) trv_tbl->lst[obj_idx].flg_dfl=True; for(unsigned int itr_idx=0;itr_idx<2;itr_idx++){ /* Set object type (group or variable) */ if(itr_idx == 0){ obj_typ=nco_obj_typ_grp; obj_lst_in=(char **)grp_lst_in; obj_nbr=grp_xtr_nbr; }else if(itr_idx == 1){ obj_typ=nco_obj_typ_var; obj_lst_in=(char **)var_lst_in; obj_nbr=var_xtr_nbr; } /* endelse */ for(int obj_idx=0;obj_idx 1L && usr_sng[usr_sng_lng-1L] == sls_chr){ /* Remove trailing slash for subsequent searches since canonical group names do not end with slash */ flg_rcr_mch_grp=False; usr_sng[usr_sng_lng-1L]='\0'; usr_sng_lng--; } /* flg_rcr_mch_grp */ /* Turn-on root-anchoring for groups? */ if(obj_typ == nco_obj_typ_grp) if(usr_sng[0L] == sls_chr) flg_ncr_mch_grp=True; /* Convert pound signs (back) to commas */ nco_hash2comma(usr_sng); /* If usr_sng is regular expression ... */ if(strpbrk(usr_sng,".*^$\\[]()<>+?|{}")){ /* ... and regular expression library is present */ #ifdef NCO_HAVE_REGEX_FUNCTIONALITY if((rx_mch_nbr=nco_trv_rx_search(usr_sng,obj_typ,trv_tbl))) flg_usr_mch_obj=True; if(!rx_mch_nbr) (void)fprintf(stdout,"%s: WARNING: Regular expression \"%s\" does not match any %s\nHINT: See regular expression syntax examples at http://nco.sf.net/nco.html#rx\n",nco_prg_nm_get(),usr_sng,(obj_typ == nco_obj_typ_grp) ? "group" : "variable"); continue; #else /* !NCO_HAVE_REGEX_FUNCTIONALITY */ (void)fprintf(stdout,"%s: ERROR: Sorry, wildcarding (extended regular expression matches to variables) was not built into this NCO executable, so unable to compile regular expression \"%s\".\nHINT: Make sure libregex.a is on path and re-build NCO.\n",nco_prg_nm_get(),usr_sng); nco_exit(EXIT_FAILURE); #endif /* !NCO_HAVE_REGEX_FUNCTIONALITY */ } /* end if regular expression */ /* usr_sng is not rx, so manually search for multicomponent matches */ for(unsigned int tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Create shallow copy to avoid indirection */ trv_obj=trv_tbl->lst[tbl_idx]; if(trv_obj.nco_typ == obj_typ){ /* Initialize defaults for current candidate path to match */ flg_pth_srt_bnd=False; flg_pth_end_bnd=False; flg_var_cnd=False; flg_rcr_mch_crr=True; flg_ncr_mch_crr=True; /* Look for partial match, not necessarily on path boundaries */ /* 20130829: Variables and group names may be proper subsets of ancestor group names e.g., variable named g9 in group named g90 is /g90/g9 e.g., group named g1 in group named g10 is g10/g1 Search algorithm must test same full name multiple times in such cases For variables, only final match (closest to end full name) need be fully tested */ sbs_srt=NULL; sbs_srt_nxt=trv_obj.nm_fll; while((sbs_srt_nxt=strstr(sbs_srt_nxt,usr_sng))){ /* Object name contains usr_sng at least once */ /* Complete path-check below will begin at this substring ... */ sbs_srt=sbs_srt_nxt; /* ...for groups always at first occurence of substring... */ if(obj_typ == nco_obj_typ_grp) break; /* ...and also here for variables unless match is found in next iteration after advancing substring... */ if(sbs_srt_nxt+usr_sng_lng <= trv_obj.nm_fll+trv_obj.nm_fll_lng) sbs_srt_nxt+=usr_sng_lng; else break; } /* end while */ /* Does object name contain usr_sng? */ if(sbs_srt){ /* Ensure match spans (begins and ends on) whole path-component boundaries Full path-check starts at current substring */ /* Does match begin at path component boundary ... directly on a slash? */ if(*sbs_srt == sls_chr) flg_pth_srt_bnd=True; /* ...or one after a component boundary? */ if((sbs_srt > trv_obj.nm_fll) && (*(sbs_srt-1L) == sls_chr)) flg_pth_srt_bnd=True; /* Does match end at path component boundary ... directly on a slash? */ sbs_end=sbs_srt+usr_sng_lng-1L; if(*sbs_end == sls_chr) flg_pth_end_bnd=True; /* ...or one before a component boundary? */ if(sbs_end <= trv_obj.nm_fll+trv_obj.nm_fll_lng-1L) if((*(sbs_end+1L) == sls_chr) || (*(sbs_end+1L) == '\0')) flg_pth_end_bnd=True; /* Additional condition for variables is user-supplied string must end with short form of variable name */ if(obj_typ == nco_obj_typ_var){ if(trv_obj.nm_lng <= usr_sng_lng){ var_mch_srt=usr_sng+usr_sng_lng-trv_obj.nm_lng; if(!strcmp(var_mch_srt,trv_obj.nm)) flg_var_cnd=True; } /* endif */ if(nco_dbg_lvl_get() >= nco_dbg_sbr && nco_dbg_lvl_get() != nco_dbg_dev) (void)fprintf(stderr,"%s: INFO %s reports variable %s %s additional conditions for variable match with %s.\n",nco_prg_nm_get(),fnc_nm,usr_sng,(flg_var_cnd) ? "meets" : "fails",trv_obj.nm_fll); } /* endif var */ /* If anchoring, match must begin at root */ if(flg_ncr_mch_grp && *sbs_srt != sls_chr) flg_ncr_mch_crr=False; /* If no recursion, match must terminate user-supplied string */ if(!flg_rcr_mch_grp && *(sbs_end+1L)) flg_rcr_mch_crr=False; /* Set traversal table flags */ if(obj_typ == nco_obj_typ_var){ /* Variables must meet necessary flags for variables */ if(flg_pth_srt_bnd && flg_pth_end_bnd && flg_var_cnd){ trv_tbl->lst[tbl_idx].flg_mch=True; trv_tbl->lst[tbl_idx].flg_rcr=False; /* Was matched variable specified as full path (i.e., beginning with slash?) */ if(*usr_sng == sls_chr) trv_tbl->lst[tbl_idx].flg_vfp=True; } /* end flags */ }else{ /* !nco_obj_typ_var */ /* Groups must meet necessary flags for groups */ if(flg_pth_srt_bnd && flg_pth_end_bnd && flg_ncr_mch_crr && flg_rcr_mch_crr){ trv_tbl->lst[tbl_idx].flg_mch=True; trv_tbl->lst[tbl_idx].flg_rcr=flg_rcr_mch_grp; } /* end flags */ } /* !nco_obj_typ_var */ /* Set function return condition */ if(trv_tbl->lst[tbl_idx].flg_mch) flg_usr_mch_obj=True; if(nco_dbg_lvl_get() == nco_dbg_old){ /* Redundant call to nco_flg_set_grp_var_ass() here in debugging mode only to set flags for following print statements Essential call to nco_flg_set_grp_var_ass() occurs after itr loop Most debugging info is available in debugging section at routine end However, group boundary/anchoring/recursion info is only available here */ if(trv_tbl->lst[tbl_idx].flg_mch) nco_flg_set_grp_var_ass(trv_obj.grp_nm_fll,obj_typ,trv_tbl); (void)fprintf(stderr,"%s: INFO %s reports %s %s matches filepath %s. Begins on boundary? %s. Ends on boundary? %s. Extract? %s.",nco_prg_nm_get(),fnc_nm,(obj_typ == nco_obj_typ_grp) ? "group" : "variable",usr_sng,trv_obj.nm_fll,(flg_pth_srt_bnd) ? "Yes" : "No",(flg_pth_end_bnd) ? "Yes" : "No",(trv_tbl->lst[tbl_idx].flg_mch) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_grp) (void)fprintf(stderr," Anchored? %s.",(flg_ncr_mch_grp) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_grp) (void)fprintf(stderr," Recursive? %s.",(trv_tbl->lst[tbl_idx].flg_rcr) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_grp) (void)fprintf(stderr," flg_gcv? %s.",(trv_tbl->lst[tbl_idx].flg_gcv) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_grp) (void)fprintf(stderr," flg_ncs? %s.",(trv_tbl->lst[tbl_idx].flg_ncs) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_var) (void)fprintf(stderr," flg_vfp? %s.",(trv_tbl->lst[tbl_idx].flg_vfp) ? "Yes" : "No"); if(obj_typ == nco_obj_typ_var) (void)fprintf(stderr," flg_vsg? %s.",(trv_tbl->lst[tbl_idx].flg_vsg) ? "Yes" : "No"); (void)fprintf(stderr,"\n"); } /* end if dbg */ } /* endif strstr() */ } /* endif nco_obj_typ */ } /* end loop over tbl_idx */ if(!flg_usr_mch_obj){ (void)fprintf(stderr,"%s: ERROR %s reports user-supplied %s name or regular expression %s is not in and/or does not match contents of input file\n",nco_prg_nm_get(),fnc_nm,(obj_typ == nco_obj_typ_grp) ? "group" : "variable",usr_sng); nco_exit(EXIT_FAILURE); } /* flg_usr_mch_obj */ /* Free dynamic memory */ if(usr_sng) usr_sng=(char *)nco_free(usr_sng); } /* obj_idx */ if(nco_dbg_lvl_get() >= nco_dbg_sbr && nco_dbg_lvl_get() != nco_dbg_dev){ (void)fprintf(stdout,"%s: INFO %s reports following %s match sub-setting and regular expressions:\n",nco_prg_nm_get(),fnc_nm,(obj_typ == nco_obj_typ_grp) ? "groups" : "variables"); trv_tbl_prn_flg_mch(trv_tbl,obj_typ); } /* endif dbg */ } /* itr_idx */ /* Compute intersection of groups and variables if necessary Intersection criteria flag, flg_nsx, is satisfied by default. Unset later when necessary. */ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++) trv_tbl->lst[obj_idx].flg_nsx=True; /* Each object with flg_mch set needs to have its associated objects set An object (group or variable) may have had its flg_mch set multiple times, e.g., once via rx and once via explicit listing And since rx's often match multiple objects, no sense in flagging associated objects inside rx loop Now all -g and -v constraints have been evaluated (after itr loop) Now speed through table once and set associated objects for all groups and variable flagged with flg_mch */ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++) if(trv_tbl->lst[obj_idx].flg_mch) nco_flg_set_grp_var_ass(trv_tbl->lst[obj_idx].grp_nm_fll,trv_tbl->lst[obj_idx].nco_typ,trv_tbl); /* Union is same as intersection if either variable or group list is empty, otherwise check intersection criteria */ if(flg_unn || !grp_xtr_nbr || !var_xtr_nbr) flg_unn_ffc=True; else flg_unn_ffc=False; if(!flg_unn_ffc){ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++){ var_obj=trv_tbl->lst[obj_idx]; if(var_obj.nco_typ == nco_obj_typ_var){ /* Cancel (non-full-path) variable intersection match unless variable is also in user-specified group */ if(var_obj.flg_mch && !var_obj.flg_vfp){ for(unsigned int obj2_idx=0;obj2_idxnbr;obj2_idx++){ grp_obj=trv_tbl->lst[obj2_idx]; if(grp_obj.nco_typ == nco_obj_typ_grp && !strcmp(var_obj.grp_nm_fll,grp_obj.grp_nm_fll)) break; } /* end loop over obj2_idx */ if(!grp_obj.flg_mch) trv_tbl->lst[obj_idx].flg_nsx=False; } /* flg_mch && flg_vfp */ } /* nco_obj_typ_grp */ } /* end loop over obj_idx */ } /* flg_unn */ /* Does matched or default group contain only metadata? Flag used in nco_xtr_grp_mrk() to preserve metadata-only groups on extraction list */ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++) if(trv_tbl->lst[obj_idx].nco_typ == nco_obj_typ_grp) if(trv_tbl->lst[obj_idx].flg_mch || trv_tbl->lst[obj_idx].flg_dfl) if(!trv_tbl->lst[obj_idx].nbr_var) trv_tbl->lst[obj_idx].flg_mtd=True; /* Combine previous flags into initial extraction flag */ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++){ /* Extract object if ... */ if( (flg_unn_ffc && trv_tbl->lst[obj_idx].flg_mch) || /* ...union mode object matches user-specified string... */ (flg_unn_ffc && trv_tbl->lst[obj_idx].flg_vsg) || /* ...union mode variable selected because group matches... */ (flg_unn_ffc && trv_tbl->lst[obj_idx].flg_gcv) || /* ...union mode contains matched variable... */ (trv_tbl->lst[obj_idx].flg_dfl) || /* ...user-specified no sub-setting... */ (!flg_unn_ffc && trv_tbl->lst[obj_idx].flg_mch && trv_tbl->lst[obj_idx].flg_nsx) || /* ...intersection mode variable matches group... */ False) trv_tbl->lst[obj_idx].flg_xtr=True; } /* end loop over obj_idx */ if(nco_dbg_lvl_get() == nco_dbg_old){ for(unsigned int obj_idx=0;obj_idxnbr;obj_idx++){ /* Create shallow copy to avoid indirection */ trv_obj=trv_tbl->lst[obj_idx]; (void)fprintf(stderr,"%s: INFO %s final flags of %s %s:\n",nco_prg_nm_get(),fnc_nm,(trv_obj.nco_typ == nco_obj_typ_grp) ? "group" : "variable",trv_obj.nm_fll); (void)fprintf(stderr," flg_dfl? %s.",(trv_obj.flg_dfl) ? "Yes" : "No"); (void)fprintf(stderr," flg_mch? %s.",(trv_obj.flg_mch) ? "Yes" : "No"); (void)fprintf(stderr," flg_xtr? %s.",(trv_obj.flg_xtr) ? "Yes" : "No"); if(trv_obj.nco_typ == nco_obj_typ_var) (void)fprintf(stderr," flg_vfp? %s.",(trv_obj.flg_vfp) ? "Yes" : "No"); if(trv_obj.nco_typ == nco_obj_typ_var) (void)fprintf(stderr," flg_vsg? %s.",(trv_obj.flg_vsg) ? "Yes" : "No"); if(trv_obj.nco_typ == nco_obj_typ_grp) (void)fprintf(stderr," flg_gcv? %s.",(trv_obj.flg_gcv) ? "Yes" : "No"); if(trv_obj.nco_typ == nco_obj_typ_grp) (void)fprintf(stderr," flg_ncs? %s.",(trv_obj.flg_ncs) ? "Yes" : "No"); if(trv_obj.nco_typ == nco_obj_typ_grp) (void)fprintf(stderr," flg_nsx? %s.",(trv_obj.flg_nsx) ? "Yes" : "No"); (void)fprintf(stderr,"\n"); } /* end loop over obj_idx */ } /* endif dbg */ /* Print extraction list in debug mode */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)trv_tbl_prn_xtr(trv_tbl,fnc_nm); return (nco_bool)True; } /* end nco_xtr_mk() */ void nco_xtr_xcl /* [fnc] Convert extraction list to exclusion list */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Convert extraction list to exclusion list NB: Exclusion is ambiguous for groups Consider, e.g., ncks -x -v /g1/v1 Should that exclude g1 completely? what about other variables like /g1/v2? Hence, the exclusion flag should not always be used to permanant exclude groups On the other hand, there are some uses where the exclusion flag should exclude groups Consider, e.g., ncks -x -g g1 In this case g1 and all descendents should be excluded Given that, here is how this routine and NCO actually uses flg_xcl: For variables, -x sets the exclusion flag and is "permanent", i.e., removes variable from extraction list For groups, -x sets the exclusion flag but is not "permanent"---it does not group from extraction list Instead it is used to help determine whether group should be excluded for metadata-only containing groups Group extraction is reset and done from scratch (except for flg_xcl/flg_mtd) in nco_xtr_grp_mrk() */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_tbl->lst[uidx].flg_xtr=!trv_tbl->lst[uidx].flg_xtr; /* Toggle extraction flag */ trv_tbl->lst[uidx].flg_xcl=!trv_tbl->lst[uidx].flg_xcl; /* Mark that this object was explicitly excluded */ } /* end for */ return; } /* end nco_xtr_xcl() */ void nco_xtr_crd_add /* [fnc] Add all coordinates to extraction list */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Add all coordinates to extraction list Find all coordinates (variables with same names and sizes as dimensions) and ensure they are marked for extraction */ const char fnc_nm[]="nco_xtr_crd_add()"; /* [sng] Function name */ /* If variable is coordinate variable then mark it for extraction */ for(unsigned idx_var=0;idx_varnbr;idx_var++) if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var) if(trv_tbl->lst[idx_var].is_crd_var) trv_tbl->lst[idx_var].flg_xtr=True; /* Print extraction list in debug mode */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)trv_tbl_prn_xtr(trv_tbl,fnc_nm); return; } /* end nco_xtr_crd_add() */ void nco_xtr_cf_add /* [fnc] Add to extraction list variables associated with CF convention */ (const int nc_id, /* I [ID] netCDF file ID */ const char * const cf_nm, /* I [sng] CF convention ("coordinates" or "bounds") */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Add to extraction list all variables associated with specified CF convention Driver routine for nco_xtr_cf_prv_add() Detect associated coordinates specified by CF "bounds" and "coordinates" conventions http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.1/cf-conventions.html#coordinate-system */ const char fnc_nm[]="nco_xtr_cf_add()"; /* [sng] Function name */ /* Search for and add CF-compliant bounds and coordinates to extraction list */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct trv_obj=trv_tbl->lst[uidx]; /* Filter extracted variables */ if(trv_obj.nco_typ == nco_obj_typ_var && trv_obj.flg_xtr){ (void)nco_xtr_cf_prv_add(nc_id,&trv_obj,cf_nm,trv_tbl); } /* Filter extracted variables */ } /* end loop over table */ /* Print extraction list in debug mode */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)trv_tbl_prn_xtr(trv_tbl,fnc_nm); return; } /* nco_xtr_cf_add() */ void nco_xtr_cf_prv_add /* [fnc] Add specified CF-compliant coordinates of specified variable to extraction list */ (const int nc_id, /* I [ID] netCDF file ID */ const trv_sct * const var_trv, /* I [sct] Variable (object) */ const char * const cf_nm, /* I [sng] CF convention ( "coordinates" or "bounds") */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Detect associated coordinates specified by CF "bounds" or "coordinates" convention for single variable Private routine called by nco_xtr_cf_add() http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.1/cf-conventions.html#coordinate-system */ char **cf_lst; /* [sng] 1D array of list elements */ char att_nm[NC_MAX_NAME]; /* [sng] Attribute name */ const char dlm_sng[]=" "; /* [sng] Delimiter string */ int grp_id; /* [id] Group ID */ int nbr_att; /* [nbr] Number of attributes */ int nbr_cf; /* [nbr] Number of coordinates specified in "bounds" or "coordinates" attribute */ int var_id; /* [id] Variable ID */ assert(var_trv->nco_typ == nco_obj_typ_var); /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv->grp_nm_fll,&grp_id); /* Obtain variable ID */ (void)nco_inq_varid(grp_id,var_trv->nm,&var_id); /* Find number of attributes */ (void)nco_inq_varnatts(grp_id,var_id,&nbr_att); assert(nbr_att == var_trv->nbr_att); /* Loop attributes */ for(int idx_att=0;idx_attnm_fll,nco_typ_sng(att_typ),nco_typ_sng(NC_CHAR)); return; } /* end if */ att_val=(char *)nco_malloc((att_sz+1L)*sizeof(char)); if(att_sz > 0L) (void)nco_get_att(grp_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ cf_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_cf); /* ...for each coordinate in CF convention attribute, i.e., "bounds" or "coordinate"... */ for(int idx_cf=0;idx_cfgrp_nm_fll)+strlen(cf_lst_var)+2L); strcpy(cf_lst_var_nm_fll,var_trv->grp_nm_fll); if(strcmp(var_trv->grp_nm_fll,sls_sng)) strcat(cf_lst_var_nm_fll,sls_sng); strcat(cf_lst_var_nm_fll,cf_lst_var); /* Find last occurence of '/' */ ptr_chr=strrchr(cf_lst_var_nm_fll,sls_chr); psn_chr=ptr_chr-cf_lst_var_nm_fll; while(ptr_chr){ /* If variable is on list */ if(trv_tbl_fnd_var_nm_fll(cf_lst_var_nm_fll,trv_tbl)){ /* Mark it for extraction */ (void)trv_tbl_mrk_xtr(cf_lst_var_nm_fll,True,trv_tbl); /* Exclude ancestor with lower scope (closer to root) variables, add only the most in scope (usually in same group) */ break; } /* If variable is on list, mark it for extraction */ cf_lst_var_nm_fll[psn_chr]='\0'; ptr_chr=strrchr(cf_lst_var_nm_fll,sls_chr); /* Re-add variable name to shortened path */ if(ptr_chr){ psn_chr=ptr_chr-cf_lst_var_nm_fll; cf_lst_var_nm_fll[psn_chr]='\0'; if(strcmp(var_trv->grp_nm_fll,sls_sng)) strcat(cf_lst_var_nm_fll,sls_sng); strcat(cf_lst_var_nm_fll,cf_lst_var); ptr_chr=strrchr(cf_lst_var_nm_fll,sls_chr); psn_chr=ptr_chr-cf_lst_var_nm_fll; } /* !ptr_chr */ } /* end while */ /* Free allocated */ if(cf_lst_var_nm_fll) cf_lst_var_nm_fll=(char *)nco_free(cf_lst_var_nm_fll); } /* end loop over idx_cf */ /* Free allocated memory */ att_val=(char *)nco_free(att_val); cf_lst=nco_sng_lst_free(cf_lst,nbr_cf); } /* end strcmp() */ } /* end loop over attributes */ return; } /* nco_xtr_cf_prv_add() */ nm_id_sct * /* O [sct] Extraction list */ nco_trv_tbl_nm_id /* [fnc] Create extraction list of nm_id_sct from traversal table */ (const int nc_id_in, /* I [ID] netCDF input file ID */ const int nc_id_out, /* I [ID] netCDF output file ID */ const gpe_sct * const gpe, /* I [sct] GPE structure */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: Create extraction list of nm_id_sct from traversal table */ nm_id_sct *xtr_lst; /* [sct] Extraction list */ int nbr_tbl=0; for(unsigned uidx=0;uidxnbr;uidx++) if(trv_tbl->lst[uidx].nco_typ == nco_obj_typ_var && trv_tbl->lst[uidx].flg_xtr) nbr_tbl++; xtr_lst=(nm_id_sct *)nco_malloc(nbr_tbl*sizeof(nm_id_sct)); nbr_tbl=0; for(unsigned uidx=0;uidxnbr;uidx++){ if(trv_tbl->lst[uidx].nco_typ == nco_obj_typ_var && trv_tbl->lst[uidx].flg_xtr){ int var_id; int grp_id_in; int grp_id_out; char *grp_out_fll; /* Get input group ID */ (void)nco_inq_grp_full_ncid(nc_id_in,trv_tbl->lst[uidx].grp_nm_fll,&grp_id_in); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,trv_tbl->lst[uidx].grp_nm_fll); else grp_out_fll=(char *)strdup(trv_tbl->lst[uidx].grp_nm_fll); /* Get output group ID */ (void)nco_inq_grp_full_ncid(nc_id_out,grp_out_fll,&grp_id_out); /* Get variable ID */ (void)nco_inq_varid(grp_id_in,trv_tbl->lst[uidx].nm,&var_id); /* 20130213: Necessary to allow MM3->MM4 and MM4->MM3 workarounds Store in/out group IDs as determined in nco_xtr_dfn() In MM3/4 cases, either grp_in_id or grp_out_id are always root Other is always root unless GPE is used */ xtr_lst[nbr_tbl].grp_id_in=grp_id_in; xtr_lst[nbr_tbl].grp_id_out=grp_id_out; xtr_lst[nbr_tbl].id=var_id; xtr_lst[nbr_tbl].nm=(char *)strdup(trv_tbl->lst[uidx].nm); nbr_tbl++; } /* end flg == True */ } /* end loop over uidx */ *xtr_nbr=nbr_tbl; return xtr_lst; } /* end nco_trv_tbl_nm_id() */ void nco_xtr_crd_ass_add /* [fnc] Add to extraction list all coordinates associated with extracted variables */ (const int nc_id, /* I [ID] netCDF file ID */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Add to extraction list all coordinates associated with extracted variables */ char dmn_nm_var[NC_MAX_NAME]; /* [sng] Dimension name for *variable* */ int dmn_id_var[NC_MAX_DIMS]; /* [ID] Dimensions IDs array for variable */ int grp_id; /* [ID] Group ID */ int nbr_dmn_var; /* [nbr] Number of dimensions associated with current matched variable */ int var_id; /* [ID] Variable ID */ long dmn_sz; /* [nbr] Dimension size */ /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* Filter variables to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Get number of dimensions for *variable* */ (void)nco_inq_varndims(grp_id,var_id,&nbr_dmn_var); assert(nbr_dmn_var == var_trv.nbr_dmn); /* Get dimension IDs for variable */ (void)nco_inq_vardimid(grp_id,var_id,dmn_id_var); /* Loop over dimensions of variable */ for(int idx_var_dim=0;idx_var_dimnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; if(var_trv.flg_xtr && var_trv.nco_typ == nco_obj_typ_var){ /* Print full name of variable */ if(var_trv.grp_dpt > 0) (void)fprintf(stdout,"%s\n",var_trv.nm_fll); /* Print variable metadata */ (void)nco_prn_var_dfn(nc_id,prn_flg,&var_trv); int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Print variable attributes */ (void)nco_prn_att(grp_id,prn_flg,var_id); } /* end flg_xtr */ } /* end uidx */ return; } /* end nco_prn_xtr_mtd() */ void nco_prn_xtr_val /* [fnc] Print variable data */ (const int nc_id, /* I netCDF file ID */ prn_fmt_sct * const prn_flg, /* I/O [sct] Print-format information */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: Print variable data */ /* Loop variables in table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; if(var_trv.flg_xtr && var_trv.nco_typ == nco_obj_typ_var){ /* Print full name of variable */ if(!prn_flg->dlm_sng && var_trv.grp_dpt > 0) (void)fprintf(stdout,"%s\n",var_trv.nm_fll); /* Print variable values */ (void)nco_prn_var_val_trv(nc_id,prn_flg,&var_trv,trv_tbl); } /* End flg_xtr */ } /* End Loop variables in table */ return; } /* end nco_prn_xtr_val() */ void nco_xtr_dmn_mrk /* [fnc] Mark extracted dimensions */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Set flag for dimensions to be extracted ncks print functions need dimension extraction flag to print CDL files */ unsigned int dmn_idx; /* [idx] Index over dimensions */ unsigned int dmn_nbr; /* [nbr] Number of dimensions defined in file */ unsigned int dmn_var_idx; /* [idx] Index over dimensions in variable */ unsigned int dmn_var_nbr; /* [nbr] Number of dimensions in variable */ unsigned int obj_idx; /* [idx] Index over objects */ unsigned int obj_nbr; /* [nbr] Number of objects in table */ dmn_nbr=trv_tbl->nbr_dmn; obj_nbr=trv_tbl->nbr; /* Set extraction flag for groups if ancestors of extracted variables */ for(dmn_idx=0;dmn_idxlst_dmn[dmn_idx].flg_xtr=False; for(obj_idx=0;obj_idxlst[obj_idx]; /* For each variable to be extracted ... */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ dmn_var_nbr=var_trv.nbr_dmn; for(dmn_var_idx=0;dmn_var_idxlst_dmn[dmn_idx].dmn_id){ trv_tbl->lst_dmn[dmn_idx].flg_xtr=True; /* Break from loop over dmn_var_idx into loop over obj_idx */ break; } /* endif match */ } /* end loop over dmn_var_idx */ } /* endif extracted variable */ /* Break from loop over obj_idx into loop over dmn_idx */ if(trv_tbl->lst_dmn[dmn_idx].flg_xtr) break; } /* end loop over obj_idx */ } /* end loop over dmn_idx */ } /* end nco_xtr_dmn_mrk() */ void nco_xtr_grp_mrk /* [fnc] Mark extracted groups */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Set flag for groups to be extracted Could be performed before or after writing variables Used to be part of nco_xtr_dfn() However, ncks print functions need group extraction flag set for printing As of 20130716 we isolate this flag-setting in nco_xtr_grp_mrk() Actual group copying still done in nco_xtr_dfn() */ const char sls_sng[]="/"; /* [sng] Slash string */ char *grp_fll_sls; /* [sng] Full group name with slash appended */ char *sbs_srt; /* [sng] Location of user-string match start in object path */ nco_bool flg_pth_srt_bnd; /* [flg] String begins at path component boundary */ nco_bool flg_pth_end_bnd; /* [flg] String ends at path component boundary */ unsigned int grp_idx; unsigned int obj_idx; /* Goal here is to annotate which groups will appear in output Need to know in order to efficiently copy their metadata Definition of flags in extraction table is operational Could create a new flag just for this Instead, we re-purpose the extraction flag, flg_xtr, for groups Could re-purpose flg_ncs too with same effect nco_xtr_mk() sets flg_xtr for groups, like variables, that match user-specified strings Later processing makes flg_xtr for groups unreliable For instance, the exclusion flag (-x) is ambiguous for groups Also identification of associated coordinates and auxiliary coordinates occurs after nco_xtr_mk() Associated and auxiliary coordinates may be in distant groups Hence no better place than nco_xtr_grp_mrk() to finally identify ancestor groups */ /* Set extraction flag for groups if ancestors of extracted variables */ for(grp_idx=0;grp_idxnbr;grp_idx++){ /* For each group ... */ if(trv_tbl->lst[grp_idx].nco_typ == nco_obj_typ_grp){ /* Metadata-only containing groups already have flg_mtd set in nco_xtr_mk() Variable ancestry may not affect such groups, especially if they are leaf groups Set extraction flag to True (then continue) iff matching groups contain only metadata Otherwise set initialize extraction flag to False and overwrite later based on descendent variables */ if((trv_tbl->lst[grp_idx].flg_xtr=(!trv_tbl->lst[grp_idx].flg_xcl && trv_tbl->lst[grp_idx].flg_mtd))) continue; if(!strcmp(trv_tbl->lst[grp_idx].grp_nm_fll,sls_sng)){ /* Manually mark root group as extracted because matching algorithm below fails for root group (it looks for "//" in variable names) */ trv_tbl->lst[grp_idx].flg_xtr=True; continue; } /* endif root group */ grp_fll_sls=(char *)strdup(trv_tbl->lst[grp_idx].nm_fll); grp_fll_sls=(char *)nco_realloc(grp_fll_sls,(trv_tbl->lst[grp_idx].nm_fll_lng+2L)*sizeof(char)); strcat(grp_fll_sls,sls_sng); /* ... loop through ... */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* ... all variables to be extracted ... */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var && trv_tbl->lst[idx_var].flg_xtr){ /* ... finds that full path to current group is contained in an extracted variable path ... */ if((sbs_srt=strstr(trv_tbl->lst[idx_var].nm_fll,grp_fll_sls))){ flg_pth_srt_bnd=False; flg_pth_end_bnd=False; /* ... and _begins_ a full group path of that variable ... */ if(sbs_srt == trv_tbl->lst[idx_var].nm_fll) flg_pth_srt_bnd=True; /* Match ends on path component boundary, directly on a slash, because we added slash before matching */ flg_pth_end_bnd=True; if(flg_pth_srt_bnd && flg_pth_end_bnd){ /* ... and mark _only_ those groups for extraction... */ trv_tbl->lst[grp_idx].flg_xtr=True; break; } /* endif */ } /* endif full group path */ } /* endif extracted variable */ } /* end loop over idx_var */ if(grp_fll_sls) grp_fll_sls=(char *)nco_free(grp_fll_sls); } /* endif group */ } /* end loop over grp_idx */ /* Current status of flg_xtr for groups is that it has been set 1. For all user-specified groups 2. For default (non user-specified) groups 3. For metadata-only groups that do not conflict with the above What is lacking here is extraction flags for ancestors of all extracted groups Ancestor flags have been set in nco_xtr_mk() but must be discarded and reset for same reasons that group flags in nco_xtr_mk() are unreliable for final list. This loop ensures groups are marked for extraction if any descendents are marked Mainly (only?) this catches ancestors of metadata only groups This loop is not necessary for _copying_ files because nco_xtr_dfn() algorithm handles ancestors This loop _is_ necessary for _printing_ files because nco_grp_prn() algorithm does not handle ancestors Set extraction flag for groups if ancestors of extracted groups */ for(grp_idx=0;grp_idxnbr;grp_idx++){ /* For each group that is not yet on extraction list ... */ if(trv_tbl->lst[grp_idx].nco_typ == nco_obj_typ_grp && !trv_tbl->lst[grp_idx].flg_xtr){ grp_fll_sls=(char *)strdup(trv_tbl->lst[grp_idx].nm_fll); grp_fll_sls=(char *)nco_realloc(grp_fll_sls,(trv_tbl->lst[grp_idx].nm_fll_lng+2L)*sizeof(char)); strcat(grp_fll_sls,sls_sng); /* Search for its path as a component of an extracted group path */ for(obj_idx=0;obj_idxnbr;obj_idx++){ if(trv_tbl->lst[obj_idx].nco_typ == nco_obj_typ_grp && trv_tbl->lst[obj_idx].flg_xtr){ if((sbs_srt=strstr(trv_tbl->lst[obj_idx].nm_fll,grp_fll_sls))){ flg_pth_srt_bnd=False; flg_pth_end_bnd=False; /* Ancestor groups must match start of extracted group */ if(sbs_srt == trv_tbl->lst[obj_idx].nm_fll) flg_pth_srt_bnd=True; /* Match ends on path component boundary, directly on a slash, because we added slash before matching */ flg_pth_end_bnd=True; if(flg_pth_srt_bnd && flg_pth_end_bnd){ trv_tbl->lst[grp_idx].flg_ncs=True; trv_tbl->lst[grp_idx].flg_xtr=True; continue; } /* endif current group is ancestor of extracted group */ } /* endif current group may be ancestor of extracted group */ } /* endif extracted group */ } /* end loop over obj_idx */ if(grp_fll_sls) grp_fll_sls=(char *)nco_free(grp_fll_sls); } /* endif group */ } /* end loop over grp_idx */ } /* end nco_xtr_grp_mrk() */ void nco_xtr_dfn /* [fnc] Define extracted groups, variables, and attributes in output file */ (const int nc_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ const md5_sct * const md5, /* I [sct] MD5 configuration */ const nco_bool CPY_GRP_METADATA, /* I [flg] Copy group metadata (attributes) */ const nco_bool CPY_VAR_METADATA, /* I [flg] Copy variable metadata (attributes) */ const int nco_pck_plc, /* I [enm] Packing policy */ const char * const rec_dmn_nm, /* I [sng] Record dimension name */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Define groups, variables, and attributes in output file rec_dmn_nm, if any, is name requested for (netCDF3) sole record dimension */ const char fnc_nm[]="nco_xtr_dfn()"; /* [sng] Function name */ char *grp_out_fll; /* [sng] Group name */ gpe_nm_sct *gpe_nm; /* [sct] GPE name duplicate check array */ int fl_fmt; /* [enm] netCDF file format */ int grp_id; /* [ID] Group ID in input file */ int grp_out_id; /* [ID] Group ID in output file */ int nbr_gpe_nm; /* [nbr] Number of GPE entries */ int var_out_id; /* [ID] Variable ID in output file */ int nco_prg_id; /* [enm] Program ID */ nco_bool PCK_ATT_CPY; /* [flg] Copy attributes "scale_factor", "add_offset" */ /* Get Program ID */ nco_prg_id=nco_prg_id_get(); nbr_gpe_nm=0; gpe_nm=NULL; /* Get file format */ (void)nco_inq_format(nc_out_id,&fl_fmt); /* Isolate extra complexity of copying group metadata */ if(CPY_GRP_METADATA){ /* Extraction flag for groups was set in nco_xtr_grp_mrk() This loop defines those groups in output file and copies their metadata */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct grp_trv=trv_tbl->lst[uidx]; /* If object is group ancestor of extracted variable */ if(grp_trv.nco_typ == nco_obj_typ_grp && grp_trv.flg_xtr){ /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,grp_trv.grp_nm_fll,&grp_id); /* ncge case */ if(nco_prg_id_get() == ncge){ if(grp_trv.flg_nsm_prn){ /* Ensemble parent groups */ if(trv_tbl->nsm_sfx){ /* Define new name by appending suffix (e.g., /cesm + _avg) */ char *nm_fll_sfx=nco_bld_nsm_sfx(grp_trv.grp_nm_fll_prn,trv_tbl); /* Use then delete new name */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,nm_fll_sfx); else grp_out_fll=(char *)strdup(nm_fll_sfx); nm_fll_sfx=(char *)nco_free(nm_fll_sfx); }else{ if(gpe) grp_out_fll=nco_gpe_evl(gpe,grp_trv.grp_nm_fll_prn); else grp_out_fll=(char *)strdup(grp_trv.grp_nm_fll_prn); } /* !nsm_sfx */ }else if(grp_trv.flg_nsm_mbr){ /* If group is ensemble member, do not create it in same location as input */ continue; }else{ /* Regular group */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,grp_trv.grp_nm_fll); else grp_out_fll=(char *)strdup(grp_trv.grp_nm_fll); } /* !flg_nsm_prn */ }else{ /* Non ncge case: Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,grp_trv.grp_nm_fll); else grp_out_fll=(char *)strdup(grp_trv.grp_nm_fll); } /* !ncge */ /* If output group does not exist, create it */ if(nco_inq_grp_full_ncid_flg(nc_out_id,grp_out_fll,&grp_out_id)) nco_def_grp_full(nc_out_id,grp_out_fll,&grp_out_id); /* Copy group attributes */ if(grp_trv.nbr_att){ PCK_ATT_CPY=True; (void)nco_att_cpy(grp_id,grp_out_id,NC_GLOBAL,NC_GLOBAL,PCK_ATT_CPY); } /* Copy group attributes */ /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); } /* end if group and flg_xtr */ } /* end loop to define group attributes */ } /* !CPY_GRP_METADATA */ /* Define variables */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* If object is an extracted variable... */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* ncge */ if(nco_prg_id_get() == ncge){ /* If variable is in an ensemble member, do not create it in same location as input */ if(var_trv.flg_nsm_mbr){ if(trv_tbl->nsm_sfx){ /* Define new name by appending suffix (e.g., /cesm + _avg) */ char *nm_fll_sfx=nco_bld_nsm_sfx(var_trv.grp_nm_fll_prn,trv_tbl); /* Use then delete new name */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,nm_fll_sfx); else grp_out_fll=(char *)strdup(nm_fll_sfx); nm_fll_sfx=(char *)nco_free(nm_fll_sfx); }else{ /* Non suffix case */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv.nsm_nm); else grp_out_fll=(char *)strdup(var_trv.nsm_nm); } /* !trv_tbl->nsm_sfx */ }else{ /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv.grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv.grp_nm_fll); } /* !flg_nsm_mbr */ }else{ /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv.grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv.grp_nm_fll); } /* !ncge */ /* If output group does not exist, create it */ if(nco_inq_grp_full_ncid_flg(nc_out_id,grp_out_fll,&grp_out_id)) nco_def_grp_full(nc_out_id,grp_out_fll,&grp_out_id); /* ncge */ if(nco_prg_id_get() == ncge){ /* Is requested variable in output file? */ int rcd=nco_inq_varid_flg(grp_out_id,var_trv.nm,&var_out_id); /* Yes, get outta' Dodge... avoid GPE failure on duplicate definition */ if(rcd == 0) continue; } /* ncge */ /* Detect duplicate GPE names in advance, then exit() with helpful error */ if(gpe) nco_gpe_chk(grp_out_fll,var_trv.nm,&gpe_nm,&nbr_gpe_nm); /* Define variable in output file */ var_out_id=nco_cpy_var_dfn_trv(nc_id,nc_out_id,cnk,grp_out_fll,dfl_lvl,gpe,rec_dmn_nm,&var_trv,trv_tbl); /* Copy variable's attributes */ if(CPY_VAR_METADATA){ int var_id; /* [id] Variable ID */ var_sct *var_prc; /* [sct] Variable to process */ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Allocate variable structure and fill with metadata */ var_prc=nco_var_fll_trv(grp_id,var_id,&var_trv,trv_tbl); PCK_ATT_CPY=nco_pck_cpy_att(nco_prg_id,nco_pck_plc,var_prc); (void)nco_att_cpy(grp_id,grp_out_id,var_id,var_out_id,PCK_ATT_CPY); var_prc=(var_sct *)nco_var_free(var_prc); } /* !CPY_VAR_METADATA */ /* Pre-allocate space for MD5 attributes */ if(md5){ if(md5->wrt){ /* Save time with netCDF3 files by pre-allocating header space */ aed_sct aed_md5; char md5_dgs_hxd_sng_ram[]="01234567890123456789012345678901"; /* [sng] Placeholder name for actual digest */ aed_md5.att_nm=md5->att_nm; aed_md5.var_nm=var_trv.nm; aed_md5.id=var_out_id; aed_md5.sz=NCO_MD5_DGS_SZ*2L; aed_md5.type=NC_CHAR; aed_md5.val.cp=md5_dgs_hxd_sng_ram; aed_md5.mode=aed_overwrite; (void)nco_aed_prc(grp_out_id,var_out_id,aed_md5); } /* !wrt */ } /* !md5 */ /* Memory management after current extracted variable */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); } /* end if variable and flg_xtr */ } /* end loop over uidx */ /* Memory management for GPE names */ for(int idx=0;idx= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Using MM3-workaround to hasten copying of record variables\n",nco_prg_nm_get()); /* Convert extraction list from traversal table to nm_id_sct format to re-use old code */ xtr_lst=nco_trv_tbl_nm_id(nc_id_in,nc_id_out,gpe,&xtr_nbr,trv_tbl); /* Split list into fixed-length and record variables */ (void)nco_var_lst_fix_rec_dvd(nc_id_in,xtr_lst,xtr_nbr,&fix_lst,&fix_nbr,&rec_lst,&rec_nbr); /* Copy fixed-length data variable-by-variable */ for(idx_var=0;idx_var= nco_dbg_var && !fp_bnr) (void)fprintf(stderr,"%s, ",fix_lst[idx_var]->nm); if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fflush(stderr); (void)nco_cpy_var_val(fix_lst[idx_var]->grp_id_in,fix_lst[idx_var]->grp_id_out,fp_bnr,md5,fix_lst[idx_var]->nm); } /* end loop over idx_var */ /* Copy record data record-by-record */ (void)nco_cpy_rec_var_val(nc_id_in,fp_bnr,md5,rec_lst,rec_nbr); /* Extraction lists no longer needed */ if(fix_lst) fix_lst=(nm_id_sct **)nco_free(fix_lst); if(rec_lst) rec_lst=(nm_id_sct **)nco_free(rec_lst); if(xtr_lst) xtr_lst=nco_nm_id_lst_free(xtr_lst,xtr_nbr); }else{ /* !USE_MM3_WORKAROUND */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct trv=trv_tbl->lst[uidx]; /* If object is an extracted variable... */ if(trv.nco_typ == nco_obj_typ_var && trv.flg_xtr){ int grp_id_in; int grp_id_out; char *grp_out_fll; /* Get input group ID */ (void)nco_inq_grp_full_ncid(nc_id_in,trv_tbl->lst[uidx].grp_nm_fll,&grp_id_in); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,trv_tbl->lst[uidx].grp_nm_fll); else grp_out_fll=(char *)strdup(trv_tbl->lst[uidx].grp_nm_fll); /* Get output group ID */ (void)nco_inq_grp_full_ncid(nc_id_out,grp_out_fll,&grp_id_out); if(nco_dbg_lvl_get() >= nco_dbg_vrb){ (void)fprintf(stdout,"%s: INFO %s writing variable <%s> from ",nco_prg_nm_get(),fnc_nm,trv.nm_fll); (void)nco_prn_grp_nm_fll(grp_id_in); (void)fprintf(stdout," to "); (void)nco_prn_grp_nm_fll(grp_id_out); (void)fprintf(stdout,"\n"); } /* endif dbg */ /* Copy variable data from input netCDF file to output netCDF file */ (void)nco_cpy_var_val_mlt_lmt_trv(grp_id_in,grp_id_out,fp_bnr,md5,&trv); } /* endif */ } /* end loop over uidx */ } /* !USE_MM3_WORKAROUND */ /* Print extraction list in developer mode */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)trv_tbl_prn_xtr(trv_tbl,fnc_nm); } /* end nco_xtr_wrt() */ void nco_prn_dmn /* [fnc] Print dimensions for a group */ (const int nc_id, /* I [ID] File ID */ const char * const grp_nm_fll) /* I [sng] Full name of group */ { char dmn_nm[NC_MAX_NAME]; /* [sng] Dimension name */ int *dmn_ids; /* [nbr] Dimensions IDs array */ int dmn_ids_ult[NC_MAX_DIMS]; /* [nbr] Unlimited dimensions IDs array */ int grp_id; /* [ID] Group ID */ int nbr_dmn; /* [nbr] Number of dimensions */ int nbr_dmn_ult; /* [nbr] Number of unlimited dimensions */ long dmn_sz; /* [nbr] Dimension size */ /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,grp_nm_fll,&grp_id); /* Obtain unlimited dimensions for group */ (void)nco_inq_unlimdims(grp_id,&nbr_dmn_ult,dmn_ids_ult); /* Obtain dimensions IDs for group */ dmn_ids=nco_dmn_malloc(nc_id,grp_nm_fll,&nbr_dmn); /* List dimensions using obtained group ID */ for(int dnm_idx=0;dnm_idxnbr;idx_var++){ /* Filter variables */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var){ trv_sct var_trv=trv_tbl->lst[idx_var]; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s reports variable dimensions\n",nco_prg_nm_get(),fnc_nm); (void)fprintf(stdout,"%s:",var_trv.nm_fll); (void)fprintf(stdout," %d dimensions:\n",var_trv.nbr_dmn); } /* endif dbg */ /* Full dimension names for each variable */ for(int idx_dmn_var=0;idx_dmn_var\n",dmn_trv->nm_fll); } /* endif dbg */ if(strcmp(var_trv.var_dmn[idx_dmn_var].dmn_nm,dmn_trv->nm)){ /* Test case generates duplicated dimension IDs in netCDF file ncks -O -v two_dmn_rec_var in_grp.nc out.nc defines new dimensions for the file, as ID=0 index [0]: ID=1 index [1]: ID=2 index [0]: ID=3 index [1]: ID=4 index [1]: but the resulting file, when read, has the following IDs dimensions: #0,time = UNLIMITED ; // (10 currently) #1,lev = 3 ; #4,vrt_nbr = 2 ; group: g8 { dimensions: #0,lev = 3 ; #1,vrt_nbr = 2 ; From: "Unidata netCDF Support" To: Sent: Tuesday, March 12, 2013 5:02 AM Subject: [netCDF #SHH-257980]: Re: [netcdfgroup] Dimensions IDs > Your Ticket has been received, and a Unidata staff member will review it and reply accordingly. Listed below are details of this new Ticket. Please make sure the Ticket ID remains in the Subject: line on all correspondence related to this Ticket. > > Ticket ID: SHH-257980 > Subject: Re: [netcdfgroup] Dimensions IDs > Department: Support netCDF > Priority: Normal > Status: Open */ (void)fprintf(stdout,"%s: INFO %s reports variable <%s> with duplicate dimensions\n",nco_prg_nm_get(),fnc_nm,var_trv.nm_fll); (void)fprintf(stdout,"%s: ERROR netCDF file with duplicate dimension IDs detected. Please use netCDF version at least 4.3.0.\n",nco_prg_nm_get()); (void)nco_prn_trv_tbl(nc_id,trv_tbl); nco_exit(EXIT_FAILURE); } /* Store full dimension name */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].dmn_nm_fll=strdup(dmn_trv->nm_fll); /* Store full group name where dimension is located */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].grp_nm_fll=strdup(dmn_trv->grp_nm_fll); /* Mark as record dimension if so */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].is_rec_dmn=dmn_trv->is_rec_dmn; } } /* Filter variables */ } /* Variables */ } /* end nco_blb_dmn_ids_trv() */ int /* [rcd] Return code */ nco_grp_itr /* [fnc] Populate traversal table by examining, recursively, subgroups of parent */ (const int grp_id, /* I [ID] Group ID */ char * const grp_nm_fll_prn, /* I [sng] Absolute group name of parent (path) */ char * const grp_nm_fll, /* I [sng] Absolute group name (path) */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Populate traversal table by examining, recursively, subgroups of parent */ const char sls_sng[]="/"; /* [sng] Slash string */ char grp_nm[NC_MAX_NAME+1]; /* [sng] Group name */ char var_nm[NC_MAX_NAME+1]; /* [sng] Variable name */ char dmn_nm[NC_MAX_NAME+1]; /* [sng] Dimension name */ char rec_nm[NC_MAX_NAME+1]; /* [sng] Record dimension name */ char *var_nm_fll; /* [sng] Full path for variable */ char *dmn_nm_fll; /* [sng] Full path for dimension */ char *sls_psn; /* [sng] Current position of group path search */ const int flg_prn=0; /* [flg] All the dimensions in all parent groups will also be retrieved */ int dmn_ids_grp[NC_MAX_DIMS]; /* [ID] Dimension IDs array for group */ int dmn_ids_grp_ult[NC_MAX_DIMS];/* [ID] Unlimited (record) dimensions IDs array for group */ int dmn_id_var[NC_MAX_DIMS]; /* [ID] Dimensions IDs array for variable */ int *grp_ids; /* [ID] Sub-group IDs array */ int grp_dpt=0; /* [nbr] Depth of group (root = 0) */ int nbr_att; /* [nbr] Number of attributes */ int nbr_dmn_grp; /* [nbr] Number of dimensions for group */ int nbr_dmn_var; /* [nbr] Number of dimensions for variable */ int nbr_grp; /* [nbr] Number of sub-groups in this group */ int nbr_rec; /* [nbr] Number of record dimensions in this group */ int nbr_var; /* [nbr] Number of variables */ int rcd=NC_NOERR; /* [rcd] Return code */ long dmn_sz; /* [nbr] Dimension size */ long rec_sz; /* [nbr] Record dimension size */ nc_type var_typ; /* O [enm] NetCDF type */ nco_obj_typ obj_typ; /* [enm] Object type (group or variable) */ /* Get all information for this group */ /* Get group name */ rcd+=nco_inq_grpname(grp_id,grp_nm); /* Get number of sub-groups */ rcd+=nco_inq_grps(grp_id,&nbr_grp,(int *)NULL); /* Obtain number of dimensions/variable/attributes for group; NB: ignore record dimension ID */ rcd+=nco_inq(grp_id,&nbr_dmn_grp,&nbr_var,&nbr_att,(int *)NULL); /* Obtain dimensions IDs for group */ rcd+=nco_inq_dimids(grp_id,&nbr_dmn_grp,dmn_ids_grp,flg_prn); /* Obtain unlimited dimensions for group */ rcd+=nco_inq_unlimdims(grp_id,&nbr_rec,dmn_ids_grp_ult); /* Compute group depth */ sls_psn=grp_nm_fll; if(!strcmp(grp_nm_fll,sls_sng)) grp_dpt=0; else grp_dpt=1; while((sls_psn=strchr(sls_psn+1,'/'))) grp_dpt++; if(nco_dbg_lvl_get() == nco_dbg_crr) (void)fprintf(stderr,"%s: INFO Group %s is at level %d\n",nco_prg_nm_get(),grp_nm_fll,grp_dpt); /* Keep the old table objects size for insertion */ unsigned int idx; idx=trv_tbl->nbr; /* Add one more element to GTT (nco_realloc nicely handles first time/not first time insertions) */ trv_tbl->nbr++; trv_tbl->lst=(trv_sct *)nco_realloc(trv_tbl->lst,trv_tbl->nbr*sizeof(trv_sct)); /* Add this element (a group) to table */ trv_tbl->lst[idx].nco_typ=nco_obj_typ_grp; /* [enm] netCDF4 object type: group or variable */ trv_tbl->lst[idx].nm=strdup(grp_nm); /* [sng] Relative name (i.e., variable name or last component of path name for groups) */ trv_tbl->lst[idx].grp_nm=strdup(grp_nm); /* [sng] Group name */ trv_tbl->lst[idx].nm_lng=strlen(grp_nm); /* [sng] Length of short name */ trv_tbl->lst[idx].grp_nm_fll=strdup(grp_nm_fll);/* [sng] Full group name (for groups, same as nm_fll) */ trv_tbl->lst[idx].nm_fll=strdup(grp_nm_fll); /* [sng] Fully qualified name (path) */ trv_tbl->lst[idx].nm_fll_lng=strlen(grp_nm_fll);/* [sng] Length of full name */ trv_tbl->lst[idx].flg_cf=False; /* [flg] Object matches CF-metadata extraction criteria */ trv_tbl->lst[idx].flg_crd=False; /* [flg] Object matches coordinate extraction criteria */ trv_tbl->lst[idx].flg_dfl=False; /* [flg] Object meets default subsetting criteria */ trv_tbl->lst[idx].flg_gcv=False; /* [flg] Group contains matched variable */ trv_tbl->lst[idx].flg_mch=False; /* [flg] Object matches user-specified strings */ trv_tbl->lst[idx].flg_mtd=False; /* [flg] Group contains only metadata */ trv_tbl->lst[idx].flg_ncs=False; /* [flg] Group is ancestor of specified group or variable */ trv_tbl->lst[idx].flg_nsx=False; /* [flg] Object matches intersection criteria */ trv_tbl->lst[idx].flg_rcr=False; /* [flg] Extract group recursively */ trv_tbl->lst[idx].flg_unn=False; /* [flg] Object matches union criteria */ trv_tbl->lst[idx].flg_vfp=False; /* [flg] Variable matches full path specification */ trv_tbl->lst[idx].flg_vsg=False; /* [flg] Variable selected because group matches */ trv_tbl->lst[idx].flg_xcl=False; /* [flg] Object matches exclusion criteria */ trv_tbl->lst[idx].flg_xtr=False; /* [flg] Extract object */ trv_tbl->lst[idx].flg_rdr=False; /* [flg] Variable has dimensions to re-order (ncpdq) */ trv_tbl->lst[idx].flg_aux=False; /* [flg] Variable contains auxiliary coordinates */ trv_tbl->lst[idx].flg_std_att_lat=False; /* [flg] Variable contains 'standard_name' attribute "latitude" */ trv_tbl->lst[idx].flg_std_att_lon=False; /* [flg] Variable contains 'standard_name' attribute "longitude" */ trv_tbl->lst[idx].rec_dmn_nm_out=NULL; /* [sng] Record dimension name, re-ordered */ trv_tbl->lst[idx].grp_dpt=grp_dpt; /* [nbr] Depth of group (root = 0) */ trv_tbl->lst[idx].nbr_dmn=nbr_dmn_grp; /* [nbr] Number of dimensions */ trv_tbl->lst[idx].nbr_att=nbr_att; /* [nbr] Number of attributes */ trv_tbl->lst[idx].nbr_grp=nbr_grp; /* [nbr] Number of sub-groups (for group) */ trv_tbl->lst[idx].nbr_rec=nbr_rec; /* [nbr] Number of record dimensions */ trv_tbl->lst[idx].nbr_var=nbr_var; /* [nbr] Number of variables (for group) */ trv_tbl->lst[idx].is_crd_var=nco_obj_typ_err; /* [flg] (For variables only) Is this a coordinate variable? (unique dimension exists in scope) */ trv_tbl->lst[idx].is_rec_var=nco_obj_typ_err; /* [flg] (For variables only) Is a record variable? (is_crd_var must be True) */ trv_tbl->lst[idx].var_typ=(nc_type)nco_obj_typ_err;/* [enm] (For variables only) NetCDF type */ trv_tbl->lst[idx].enm_prc_typ=err_typ; /* [enm] (For variables only) Processing type enumerator */ trv_tbl->lst[idx].var_typ_out=(nc_type)err_typ; /* [enm] (For variables only) NetCDF type in output file (used by ncflint, ncpdq) */ if(grp_nm_fll_prn) trv_tbl->lst[idx].grp_nm_fll_prn=strdup(grp_nm_fll_prn); /* [sng] (ncge) Parent group full name */ else trv_tbl->lst[idx].grp_nm_fll_prn=NULL; trv_tbl->lst[idx].flg_nsm_prn=False; /* [flg] (ncge) Group is, or variable is in, ensemble parent group */ trv_tbl->lst[idx].flg_nsm_mbr=False; /* [flg] (ncge ) Group is, or variable is in, ensemble member group */ trv_tbl->lst[idx].flg_nsm_tpl=False; /* [flg] Group is, or variable is in, template member group */ trv_tbl->lst[idx].nsm_nm=NULL; /* [sng] (ncge) Ensemble parent group name i.e., full path to ensemble parent */ /* Variable dimensions. For groups there are no variable dimensions */ trv_tbl->lst[idx].var_dmn=NULL; /* ncpdq dimension arrays */ trv_tbl->lst[idx].dmn_idx_out_in=NULL; trv_tbl->lst[idx].dmn_rvr_in=NULL; /* Iterate variables for this group */ for(int idx_var=0;idx_var NC_MAX_ATOMIC_TYPE */ obj_typ=nco_obj_typ_nonatomic_var; if(nco_dbg_lvl_get() >= nco_dbg_var){ (void)fprintf(stderr,"%s: WARNING NCO only supports netCDF4 atomic-type variables. Variable %s is type %d = %s, and will be ignored in subsequent processing.\n", nco_prg_nm_get(),var_nm_fll,var_typ,nco_typ_sng(var_typ)); } /* endif */ } /* > NC_MAX_ATOMIC_TYPE */ /* Keep the old table objects size for insertion */ idx=trv_tbl->nbr; /* Add one more element to GTT (nco_realloc nicely handles first time/not first time insertions) */ trv_tbl->nbr++; trv_tbl->lst=(trv_sct *)nco_realloc(trv_tbl->lst,trv_tbl->nbr*sizeof(trv_sct)); /* Add this element, a variable, to table. NB: nbr_var, nbr_grp, flg_rcr not valid here */ trv_tbl->lst[idx].nco_typ=obj_typ; trv_tbl->lst[idx].nm=strdup(var_nm); trv_tbl->lst[idx].nm_lng=strlen(var_nm); trv_tbl->lst[idx].grp_nm_fll=strdup(grp_nm_fll); trv_tbl->lst[idx].grp_nm=strdup(grp_nm); trv_tbl->lst[idx].nm_fll=strdup(var_nm_fll); trv_tbl->lst[idx].nm_fll_lng=strlen(var_nm_fll); trv_tbl->lst[idx].flg_cf=False; trv_tbl->lst[idx].flg_crd=False; trv_tbl->lst[idx].flg_dfl=False; trv_tbl->lst[idx].flg_gcv=False; trv_tbl->lst[idx].flg_mch=False; trv_tbl->lst[idx].flg_mtd=False; trv_tbl->lst[idx].flg_ncs=False; trv_tbl->lst[idx].flg_nsx=False; trv_tbl->lst[idx].flg_rcr=False; trv_tbl->lst[idx].flg_unn=False; trv_tbl->lst[idx].flg_vfp=False; trv_tbl->lst[idx].flg_vsg=False; trv_tbl->lst[idx].flg_xcl=False; trv_tbl->lst[idx].flg_xtr=False; trv_tbl->lst[idx].flg_rdr=False; trv_tbl->lst[idx].flg_aux=False; trv_tbl->lst[idx].flg_std_att_lat=False; trv_tbl->lst[idx].flg_std_att_lon=False; trv_tbl->lst[idx].rec_dmn_nm_out=NULL; trv_tbl->lst[idx].grp_dpt=grp_dpt; trv_tbl->lst[idx].nbr_att=nbr_att; trv_tbl->lst[idx].nbr_dmn=nbr_dmn_var; trv_tbl->lst[idx].nbr_grp=nco_obj_typ_err; trv_tbl->lst[idx].nbr_rec=nbr_rec; /* NB: broken fxm should be record dimensions used by this variable */ trv_tbl->lst[idx].nbr_var=nco_obj_typ_err; trv_tbl->lst[idx].is_crd_var=False; trv_tbl->lst[idx].is_rec_var=False; trv_tbl->lst[idx].var_typ=var_typ; trv_tbl->lst[idx].enm_prc_typ=err_typ; trv_tbl->lst[idx].var_typ_out=(nc_type)err_typ; if(grp_nm_fll_prn) trv_tbl->lst[idx].grp_nm_fll_prn=strdup(grp_nm_fll_prn); /* [sng] (ncge) Parent group full name */ else trv_tbl->lst[idx].grp_nm_fll_prn=NULL; trv_tbl->lst[idx].flg_nsm_prn=False; trv_tbl->lst[idx].flg_nsm_mbr=False; trv_tbl->lst[idx].flg_nsm_tpl=False; trv_tbl->lst[idx].nsm_nm=NULL; /* Variable dimensions */ trv_tbl->lst[idx].var_dmn=(var_dmn_sct *)nco_malloc(nbr_dmn_var*sizeof(var_dmn_sct)); trv_tbl->lst[idx].dmn_idx_out_in=NULL; trv_tbl->lst[idx].dmn_rvr_in=NULL; for(int idx_dmn_var=0;idx_dmn_varlst[idx].var_dmn[idx_dmn_var].dmn_nm=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].dmn_nm_fll=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].grp_nm_fll=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].is_crd_var=nco_obj_typ_err; trv_tbl->lst[idx].var_dmn[idx_dmn_var].is_rec_dmn=nco_obj_typ_err; trv_tbl->lst[idx].var_dmn[idx_dmn_var].crd=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].ncd=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].dmn_id=nco_obj_typ_err; /* Assume dimension is to keep on output */ trv_tbl->lst[idx].var_dmn[idx_dmn_var].flg_dmn_avg=False; trv_tbl->lst[idx].var_dmn[idx_dmn_var].flg_rdd=False; trv_tbl->lst[idx].var_dmn[idx_dmn_var].lat_crd=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].lon_crd=NULL; trv_tbl->lst[idx].var_dmn[idx_dmn_var].nbr_lat_crd=0; trv_tbl->lst[idx].var_dmn[idx_dmn_var].nbr_lon_crd=0; } /* Variable dimensions; store what we know at this time: relative name and ID */ for(int idx_dmn_var=0;idx_dmn_varlst[idx].var_dmn[idx_dmn_var].dmn_nm=strdup(dmn_nm_var); trv_tbl->lst[idx].var_dmn[idx_dmn_var].dmn_id=dmn_id_var[idx_dmn_var]; } /* Variable dimensions; store what we know at this time: relative name and ID */ /* Free constructed name */ var_nm_fll=(char *)nco_free(var_nm_fll); } /* Iterate variables for this group */ /* Add dimension objects */ /* Iterate dimensions (for group; dimensions are defined *for* groups) */ for(int idx_dmn=0;idx_dmnnbr_dmn; /* Add one more element to dimension list of GTT (nco_realloc nicely handles first time/not first time insertions) */ trv_tbl->nbr_dmn++; trv_tbl->lst_dmn=(dmn_trv_sct *)nco_realloc(trv_tbl->lst_dmn,trv_tbl->nbr_dmn*sizeof(dmn_trv_sct)); /* Initialize as non-record dimension */ trv_tbl->lst_dmn[idx].is_rec_dmn=False; /* Get dimension name */ rcd+=nco_inq_dim(grp_id,dmn_ids_grp[idx_dmn],dmn_nm,&dmn_sz); /* Iterate unlimited dimensions to detect if dimension is record */ for(int rec_idx=0;rec_idxlst_dmn[idx].is_rec_dmn=True; /* Exit record dimension loop; we found it */ break; } /* end match record dimension name */ } /* end record dimension loop */ /* Allocate path buffer and include space for trailing NUL */ dmn_nm_fll=(char *)nco_malloc(strlen(grp_nm_fll)+strlen(dmn_nm)+2L); /* Initialize path with current absolute group path */ strcpy(dmn_nm_fll,grp_nm_fll); /* If not root group, concatenate separator */ if(strcmp(grp_nm_fll,sls_sng)) strcat(dmn_nm_fll,sls_sng); /* Concatenate dimension name to absolute group path */ strcat(dmn_nm_fll,dmn_nm); /* Store object */ trv_tbl->lst_dmn[idx].nm=strdup(dmn_nm); trv_tbl->lst_dmn[idx].grp_nm_fll=strdup(grp_nm_fll); trv_tbl->lst_dmn[idx].nm_fll=strdup(dmn_nm_fll); trv_tbl->lst_dmn[idx].sz=dmn_sz; trv_tbl->lst_dmn[idx].lmt_msa.dmn_nm=strdup(dmn_nm); trv_tbl->lst_dmn[idx].lmt_msa.dmn_sz_org=dmn_sz; trv_tbl->lst_dmn[idx].lmt_msa.dmn_cnt=dmn_sz; trv_tbl->lst_dmn[idx].lmt_msa.WRP=False; trv_tbl->lst_dmn[idx].lmt_msa.BASIC_DMN=True; trv_tbl->lst_dmn[idx].lmt_msa.MSA_USR_RDR=False; trv_tbl->lst_dmn[idx].lmt_msa.lmt_dmn_nbr=0; trv_tbl->lst_dmn[idx].lmt_msa.lmt_crr=0; trv_tbl->lst_dmn[idx].lmt_msa.lmt_dmn=NULL; trv_tbl->lst_dmn[idx].crd_nbr=0; trv_tbl->lst_dmn[idx].crd=NULL; trv_tbl->lst_dmn[idx].dmn_id=dmn_ids_grp[idx_dmn]; trv_tbl->lst_dmn[idx].has_crd_scp=nco_obj_typ_err; /* Free constructed name */ dmn_nm_fll=(char *)nco_free(dmn_nm_fll); } /* end dimension loop */ /* Go to sub-groups */ grp_ids=(int *)nco_malloc(nbr_grp*sizeof(int)); rcd+=nco_inq_grps(grp_id,&nbr_grp,grp_ids); /* Heart of traversal construction: construct a new sub-group path and call function recursively with this new name; Voila */ for(int grp_idx=0;grp_idxnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Interested in variables only */ if(var_trv.nco_typ == nco_obj_typ_var){ /* Loop unique dimensions list in groups */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; /* Is there a variable with this dimension name anywhere? (relative name) */ if(!strcmp(dmn_trv.nm,var_trv.nm)){ /* Is variable in scope of dimension ? */ if(nco_crd_var_dmn_scp(&var_trv,&dmn_trv,trv_tbl)){ /* Mark this variable as a coordinate variable. NB: coordinate variables are 1D */ if(var_trv.nbr_dmn == 1) trv_tbl->lst[idx_var].is_crd_var=True; else trv_tbl->lst[idx_var].is_crd_var=False; /* If the group dimension is a record dimension then the variable is a record variable */ trv_tbl->lst[idx_var].is_rec_var=dmn_trv.is_rec_dmn; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s <%s> is ",nco_prg_nm_get(),fnc_nm,var_trv.nm_fll); if(dmn_trv.is_rec_dmn) (void)fprintf(stdout,"(record) "); (void)fprintf(stdout,"coordinate\n"); } /* Go to next variable */ break; }/* Is variable in scope of dimension ? */ } /* Is there a variable with this dimension name anywhere? (relative name) */ } /* Loop unique dimensions list in groups */ } /* Interested in variables only */ } /* Loop all variables */ } /* nco_blb_crd_var_trv() */ void nco_bld_crd_var_trv /* [fnc] Build GTT "crd_sct" coordinate variable structure */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Build GTT "crd_sct" coordinate variable structure */ const char fnc_nm[]="nco_blb_crd_var_trv()"; /* [sng] Function name */ /* Step 1) Find the total number of coordinate variables for every dimension */ /* Loop unique dimensions list in groups */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; /* Loop all objects */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Interested in variables only */ if(var_trv.nco_typ == nco_obj_typ_var){ /* Is there a variable with this dimension name anywhere? (relative name) */ if(strcmp(dmn_trv.nm,var_trv.nm) == 0 ){ /* Is variable in scope of dimension ? */ if(nco_crd_var_dmn_scp(&var_trv,&dmn_trv,trv_tbl)){ /* Increment the number of coordinate variables for this dimension */ trv_tbl->lst_dmn[idx_dmn].crd_nbr++; }/* Is variable in scope of dimension ? */ } /* Is there a variable with this dimension name anywhere? (relative name) */ } /* Interested in variables only */ } /* Loop all objects */ } /* Loop unique dimensions list in groups */ /* Step 2) Allocate coordinate variables array (crd_sct **) for every dimension */ /* Loop unique dimensions list in groups */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ /* Total number of coordinate variables for this dimension */ int crd_nbr=trv_tbl->lst_dmn[idx_dmn].crd_nbr; /* Alloc coordinate array if there are any coordinates */ if(crd_nbr) trv_tbl->lst_dmn[idx_dmn].crd=(crd_sct **)nco_malloc(crd_nbr*sizeof(crd_sct *)); } /* Loop unique dimensions list in groups */ /* Step 3) Allocate/Initialize every coordinate variable array for every dimension */ /* Loop unique dimensions list in groups */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; int crd_idx=0; /* [nbr] Coordinate index for current dimension */ /* Loop all objects */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Interested in variables only */ if(var_trv.nco_typ == nco_obj_typ_var){ /* Is there a variable with this dimension name anywhere? (relative name) */ if(strcmp(dmn_trv.nm,var_trv.nm) == 0 ){ /* Is variable in scope of dimension ? */ if(nco_crd_var_dmn_scp(&var_trv,&dmn_trv,trv_tbl)){ /* Alloc this coordinate */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]=(crd_sct *)nco_malloc(sizeof(crd_sct)); /* The coordinate full name is the variable full name found in scope */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->crd_nm_fll=strdup(var_trv.nm_fll); /* The coordinate dimension full name is the dimension full name */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->dmn_nm_fll=strdup(dmn_trv.nm_fll); /* The coordinate ID is the dimension unique ID */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->dmn_id=dmn_trv.dmn_id; /* Full group name where coordinate is located is the variable full group name */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->crd_grp_nm_fll=strdup(var_trv.grp_nm_fll); /* Full group name where dimension of *this* coordinate is located is the full group name of the dimension */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->dmn_grp_nm_fll=strdup(dmn_trv.grp_nm_fll); /* Store relative name (same for dimension and variable) */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->nm=strdup(var_trv.nm); /* Is a record dimension(variable) if the dimennsion is a record dimension */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->is_rec_dmn=dmn_trv.is_rec_dmn; /* Size is size */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->sz=dmn_trv.sz; /* Type */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->var_typ=var_trv.var_typ; /* Group depth */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->grp_dpt=var_trv.grp_dpt; /* MSA */ trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.dmn_nm=strdup(var_trv.nm); trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.dmn_cnt=dmn_trv.sz; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.dmn_sz_org=dmn_trv.sz; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.WRP=False; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.BASIC_DMN=True; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.MSA_USR_RDR=False; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.lmt_dmn_nbr=0; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.lmt_crr=0; trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]->lmt_msa.lmt_dmn=NULL; if(nco_dbg_lvl_get() == nco_dbg_old){ crd_sct *crd=trv_tbl->lst_dmn[idx_dmn].crd[crd_idx]; (void)fprintf(stdout,"%s: INFO %s variable <%s> has coordinate <%s> from dimension <%s>\n",nco_prg_nm_get(),fnc_nm, var_trv.nm_fll,crd->crd_nm_fll,crd->dmn_nm_fll); } /* Limits are initialized in build limits function */ /* Incrementr coordinate index for current dimension */ crd_idx++; }/* Is variable in scope of dimension ? */ } /* Is there a variable with this dimension name anywhere? (relative name) */ } /* Interested in variables only */ } /* Loop all objects */ } /* Loop unique dimensions list in groups */ } /* nco_blb_crd_var_trv() */ static void prt_lmt /* [fnc] Print limit */ (const int lmt_idx, /* I [sct] Index */ lmt_sct *lmt) /* I [sct] Limit */ { (void)fprintf(stdout," LIMIT[%d]%s(%li,%li,%li) ",lmt_idx,lmt->nm,lmt->srt,lmt->cnt,lmt->srd); } /* prt_lmt() */ void nco_prn_trv_tbl /* [fnc] Print GTT (Group Traversal Table) */ (const int nc_id, /* I [ID] File ID */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: print GTT (Group Traversal Table); usage ncks --get_grp_info ~/nco/data/in_grp.nc */ int nbr_dmn; /* [nbr] Total number of unique dimensions */ int nbr_crd; /* [nbr] Total number of coordinate variables */ int nbr_crd_var; /* [nbr] Total number of coordinate variables */ nbr_dmn=0; (void)fprintf(stdout,"%s: INFO reports group information\n",nco_prg_nm_get()); for(unsigned grp_idx=0;grp_idxnbr;grp_idx++){ /* Filter groups */ if(trv_tbl->lst[grp_idx].nco_typ == nco_obj_typ_grp){ trv_sct trv=trv_tbl->lst[grp_idx]; (void)fprintf(stdout,"%s: %d subgroups, %d dimensions, %d record dimensions, %d attributes, %d variables\n", trv.nm_fll,trv.nbr_grp,trv.nbr_dmn,trv.nbr_rec,trv.nbr_att,trv.nbr_var); /* Print dimensions for group */ (void)nco_prn_dmn(nc_id,trv.nm_fll); nbr_dmn+=trv.nbr_dmn; } /* Filter groups */ } /* Loop groups */ assert((unsigned int)nbr_dmn == trv_tbl->nbr_dmn); /* Variables */ nbr_crd=0; (void)fprintf(stdout,"\n"); (void)fprintf(stdout,"%s: INFO reports variable information\n",nco_prg_nm_get()); for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Filter variables */ if(var_trv.nco_typ == nco_obj_typ_var){ (void)fprintf(stdout,"%s:",var_trv.nm_fll); /* Filter output */ if(var_trv.is_crd_var){ (void)fprintf(stdout," (coordinate)"); nbr_crd++; } /* Filter output */ if(var_trv.is_rec_var) (void)fprintf(stdout," (record)"); /* If record variable must be coordinate variable */ if(var_trv.is_rec_var) assert(var_trv.is_crd_var); (void)fprintf(stdout," %d dimensions: ",var_trv.nbr_dmn); /* Dimensions */ for(int idx_dmn_var=0;idx_dmn_varlmt_msa.lmt_dmn_nbr;lmt_idx++){ (void)prt_lmt(lmt_idx,crd->lmt_msa.lmt_dmn[lmt_idx]); }/* Limits */ /* ! case where the dimension has coordinate variables */ } else { dmn_trv_sct *ncd=var_dmn.ncd; /* Limits */ for(int lmt_idx=0;lmt_idxlmt_msa.lmt_dmn_nbr;lmt_idx++){ (void)prt_lmt(lmt_idx,ncd->lmt_msa.lmt_dmn[lmt_idx]); }/* Limits */ } /* ! case where the dimension has coordinate variables */ } /* Dimensions */ /* End this variable */ (void)fprintf(stdout,"\n"); } /* Filter variables */ } /* Variables */ /* Unique dimension list, Coordinate variables stored in unique dimension list, limits */ nbr_crd_var=0; (void)fprintf(stdout,"\n"); (void)fprintf(stdout,"%s: INFO reports coordinate variables and limits listed by dimension:\n",nco_prg_nm_get()); for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; /* Dimension ID and full name */ (void)fprintf(stdout,"(#%d%s)",dmn_trv.dmn_id,dmn_trv.nm_fll); /* Filter output */ if(dmn_trv.is_rec_dmn) (void)fprintf(stdout," record dimension(%lu):: ",(unsigned long)dmn_trv.sz); else (void)fprintf(stdout," dimension(%lu):: ",(unsigned long)dmn_trv.sz); nbr_crd_var+=dmn_trv.crd_nbr; /* Loop coordinates */ for(int crd_idx=0;crd_idxcrd_nm_fll); /* Dimension full name */ (void)fprintf(stdout,"(#%d%s) ",crd->dmn_id,crd->dmn_nm_fll); /* Limits */ for(int lmt_idx=0;lmt_idxlmt_msa.lmt_dmn_nbr;lmt_idx++){ (void)prt_lmt(lmt_idx,crd->lmt_msa.lmt_dmn[lmt_idx]); }/* Limits */ /* Terminate this coordinate with "::" */ if(dmn_trv.crd_nbr>1) (void)fprintf(stdout,":: "); }/* Loop coordinates */ /* Terminate line */ (void)fprintf(stdout,"\n"); } /* Coordinate variables stored in unique dimension list */ assert(nbr_crd_var == nbr_crd); } /* nco_prn_trv_tbl() */ void nco_has_crd_dmn_scp /* [fnc] Is there a variable with same name in dimension's scope? */ (const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { const char fnc_nm[]="nco_has_crd_dmn_scp()"; /* [sng] Function name */ /* Unique dimension list */ if(nco_dbg_lvl_get() == nco_dbg_old)(void)fprintf(stdout,"%s: INFO reports dimension information with limits: %d dimensions\n",nco_prg_nm_get(),trv_tbl->nbr_dmn); for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; /* Dimension #/name first */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"#%d%s\n",dmn_trv.dmn_id,dmn_trv.nm_fll); nco_bool in_scp=False; /* Loop object table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* Filter variables */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Is there a variable with this dimension name (a coordinate varible) anywhere (relative name) */ if(!strcmp(dmn_trv.nm,var_trv.nm)){ /* Is variable in scope of dimension ? */ if(nco_crd_var_dmn_scp(&var_trv,&dmn_trv,trv_tbl)){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s reports variable <%s> in scope of dimension <%s>\n",nco_prg_nm_get(),fnc_nm, var_trv.nm_fll,dmn_trv.nm_fll); } /* endif dbg */ trv_tbl->lst_dmn[idx_dmn].has_crd_scp=True; /* Built before; variable must be a cordinate */ assert(var_trv.is_crd_var); in_scp=True; } /* Is variable in scope of dimension ? */ } /* Is there a variable with this dimension name anywhere? (relative name) */ } /* Filter variables */ } /* Loop object table */ if(nco_dbg_lvl_get() == nco_dbg_old) if(!in_scp) (void)fprintf(stdout,"%s: INFO %s dimension <%s> with no in scope variables\n",nco_prg_nm_get(),fnc_nm,dmn_trv.nm_fll); trv_tbl->lst_dmn[idx_dmn].has_crd_scp=in_scp; } /* Unique dimension list */ /* Unique dimension list */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn_trv=trv_tbl->lst_dmn[idx_dmn]; assert(dmn_trv.has_crd_scp != nco_obj_typ_err); } /* Unique dimension list */ } /* nco_has_crd_dmn_scp() */ nco_bool /* O [flg] True if variable is in scope of dimension */ nco_crd_var_dmn_scp /* [fnc] Is coordinate variable in dimension scope */ (const trv_sct * const var_trv, /* I [sct] GTT Object Variable */ const dmn_trv_sct * const dmn_trv, /* I [sct] GTT unique dimension */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: Find if variable is in scope of the dimension: Use case in scope: dimension /lon variable /g1/lon Use case not in scope: variable /lon dimension /g1/lon NOTE: deal with cases like dimension: /lon variable: /g8/lon dimension: /g8/lon */ const char fnc_nm[]="nco_crd_var_dmn_scp()"; /* [sng] Function name */ const char sls_chr='/'; /* [chr] Slash character */ char *sbs_srt; /* [sng] Location of user-string match start in object path */ char *sbs_end; /* [sng] Location of user-string match end in object path */ nco_bool flg_pth_srt_bnd=False; /* [flg] String begins at path component boundary */ nco_bool flg_pth_end_bnd=False; /* [flg] String ends at path component boundary */ size_t var_sng_lng; /* [nbr] Length of variable name */ size_t var_nm_fll_lng; /* [nbr] Length of full variable name */ size_t dmn_nm_fll_lng; /* [nbr] Length of of full dimension name */ /* Coordinate variables are 1D */ if(var_trv->nbr_dmn !=1 ){ return False; } /* Most common case is for the unique dimension full name to match the full variable name */ if(strcmp(var_trv->nm_fll,dmn_trv->nm_fll) == 0){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s found absolute match of variable <%s> and dimension <%s>:\n",nco_prg_nm_get(),fnc_nm, var_trv->nm_fll,dmn_trv->nm_fll); } return True; } /* Deal with in scope cases */ var_nm_fll_lng=strlen(var_trv->nm_fll); dmn_nm_fll_lng=strlen(dmn_trv->nm_fll); var_sng_lng=strlen(var_trv->nm); /* Look for partial match, not necessarily on path boundaries; locate variable (str2) in full dimension name (str1) */ if((sbs_srt=strstr(dmn_trv->nm_fll,var_trv->nm))){ /* Ensure match spans (begins and ends on) whole path-component boundaries */ /* Does match begin at path component boundary ... directly on a slash? */ if(*sbs_srt == sls_chr){ flg_pth_srt_bnd=True; } /* ...or one after a component boundary? */ if((sbs_srt > dmn_trv->nm_fll) && (*(sbs_srt-1L) == sls_chr)){ flg_pth_srt_bnd=True; } /* Does match end at path component boundary ... directly on a slash? */ sbs_end=sbs_srt+var_sng_lng-1L; if(*sbs_end == sls_chr){ flg_pth_end_bnd=True; } /* ...or one before a component boundary? */ if(sbs_end <= dmn_trv->nm_fll+dmn_nm_fll_lng-1L){ if((*(sbs_end+1L) == sls_chr) || (*(sbs_end+1L) == '\0')){ flg_pth_end_bnd=True; } } /* If match is on both ends of '/' then it's a "real" name, not for example "lat_lon" as a variable looking for "lon" */ if(flg_pth_srt_bnd && flg_pth_end_bnd){ /* Absolute match (equality redundant); strcmp deals cases like /g3/rlev/ and /g5/rlev */ if(var_nm_fll_lng == dmn_nm_fll_lng && strcmp(var_trv->nm_fll,dmn_trv->nm_fll) == 0){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s found absolute match of variable <%s> and dimension <%s>:\n",nco_prg_nm_get(),fnc_nm, var_trv->nm_fll,dmn_trv->nm_fll); } return True; /* Variable in scope of dimension */ }else if(var_nm_fll_lng>dmn_nm_fll_lng){ /* NOTE: deal with cases like dimension: /lon variable: /g8/lon dimension: /g8/lon */ /* Loop unique dimensions list in groups */ for(unsigned idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ dmn_trv_sct dmn=trv_tbl->lst_dmn[idx_dmn]; /* Loop all objects */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var=trv_tbl->lst[idx_var]; /* Interested in variables only */ if(var.nco_typ == nco_obj_typ_var){ /* Is there a *full* match already for the *input* dimension ? */ if(strcmp(var_trv->nm_fll,dmn.nm_fll) == 0 ){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s variable <%s> has another dimension full match <%s>:\n",nco_prg_nm_get(),fnc_nm, var_trv->nm_fll,dmn.nm_fll); } return False; } /* Is there a *full* match already? */ } /* Interested in variables only */ } /* Loop all objects */ } /* Loop unique dimensions list in groups */ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s found variable <%s> in scope of dimension <%s>:\n",nco_prg_nm_get(),fnc_nm, var_trv->nm_fll,dmn_trv->nm_fll); } return True; /* Variable out of scope of dimension */ }else if(var_nm_fll_lng < dmn_nm_fll_lng){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s found variable <%s> out of scope of dimension <%s>:\n",nco_prg_nm_get(),fnc_nm, var_trv->nm_fll,dmn_trv->nm_fll); } return False; } /* Absolute match */ } /* If match is on both ends of '/' then it's a "real" name, not for example "lat_lon" as a variable looking for "lon" */ }/* Look for partial match, not necessarily on path boundaries */ return False; } /* nco_crd_var_dmn_scp() */ int /* O [enm] Comparison result [<,=,>] 0 iff val_1 [<,==,>] val_2 */ nco_cmp_crd_dpt /* [fnc] Compare two crd_sct's by group depth */ (const void *val_1, /* I [sct] crd_sct * to compare */ const void *val_2) /* I [sct] crd_sct * to compare */ { /* Purpose: Compare two crd_sct's by group depth structure member Function is suitable for argument to ANSI C qsort() routine in stdlib.h crd_sct **crd is an array of pointers to unique dimension coordinates */ const crd_sct * const * const crd1=(const crd_sct * const *)val_1; const crd_sct * const * const crd2=(const crd_sct * const *)val_2; if((*crd1)->grp_dpt > (*crd2)->grp_dpt) return -1; else if((*crd1)->grp_dpt < (*crd2)->grp_dpt) return 1; else return 0; } /* end nco_cmp_crd_dpt() */ crd_sct * /* O [sct] Coordinate object */ nco_scp_var_crd /* [fnc] Return in scope coordinate for variable */ (trv_sct *var_trv, /* I [sct] Variable object */ dmn_trv_sct *dmn_trv) /* I [sct] Dimension object */ { /* Purpose: Choose one coordinate from the dimension object to assign as a valid coordinate to the variable dimension Scope definition: In the same group of the variable or beneath (closer to root) Above: out of scope (no luck) Use cases: dimension lon4; variable lon4_var(lon4) Variable /g16/g16g4/g16g4g4/g16g4g4g4/lon4_var 2 coordinates down in scope /g16/g16g4/g16g4g4/lon4 /g16/g16g4/lon4 */ /* If more than one coordinate, sort them by group depth */ if(dmn_trv->crd_nbr>1) qsort(dmn_trv->crd,(size_t)dmn_trv->crd_nbr,sizeof(crd_sct *),nco_cmp_crd_dpt); /* Loop over coordinates; they all have unique dimension ID of variable dimension */ for(int crd_idx=0;crd_idxcrd_nbr;crd_idx++){ crd_sct *crd=dmn_trv->crd[crd_idx]; /* Absolute match: in scope */ if(!strcmp(var_trv->nm_fll,crd->crd_nm_fll)){ /* Variable must be coordinate for this to happen */ assert(var_trv->is_crd_var); return crd; }else if(!strcmp(var_trv->grp_nm_fll,crd->crd_grp_nm_fll)){ /* Same group: in scope */ return crd; } else if(crd->grp_dpt < var_trv->grp_dpt){ /* Level below: in scope */ return crd; } } /* Loop coordinates */ return NULL; } /* nco_scp_var_crd() */ void nco_bld_var_dmn /* [fnc] Assign variables dimensions to either coordinates or dimension structs */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Fill variable dimensions with pointers to either a coordinate variable or dimension structs */ const char fnc_nm[]="nco_bld_var_dmn()"; /* [sng] Function name */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* Filter variables */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Loop dimensions for object (variable) */ for(int idx_dmn_var=0;idx_dmn_varcrd_nbr == 0){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s reports variable <%s> with *NON* coordinate dimension [%d]%s\n",nco_prg_nm_get(),fnc_nm, var_trv.nm_fll,idx_dmn_var,var_trv.var_dmn[idx_dmn_var].dmn_nm_fll); } /* endif dbg */ /* Mark as False the position of the bool array coordinate/non coordinate */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].is_crd_var=False; /* Store unique dimension (non coordinate ) */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].ncd=dmn_trv; }else if(dmn_trv->crd_nbr > 0){ /* There are coordinates; one must be chosen Scope definition: In the same group of the variable or beneath (closer to root) Above: out of scope */ crd_sct *crd=NULL; /* [sct] Coordinate to assign to dimension of variable */ /* Choose the "in scope" coordinate for the variable and assign it to the variable dimension */ crd=nco_scp_var_crd(&var_trv,dmn_trv); /* The "in scope" coordinate is returned */ if(crd){ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports dimension [%d]%s of variable <%s> in scope of coordinate <%s>\n",nco_prg_nm_get(),fnc_nm,idx_dmn_var,var_trv.var_dmn[idx_dmn_var].dmn_nm_fll,var_trv.nm_fll,crd->crd_nm_fll); /* Mark as True */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].is_crd_var=True; /* Deep-copy coordinate */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd=(crd_sct *)nco_malloc(sizeof(crd_sct)); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->crd_nm_fll=(char *)strdup(crd->crd_nm_fll); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->dmn_nm_fll=(char *)strdup(crd->dmn_nm_fll); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->crd_grp_nm_fll=(char *)strdup(crd->crd_grp_nm_fll); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->dmn_grp_nm_fll=(char *)strdup(crd->dmn_grp_nm_fll); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->nm=(char *)strdup(crd->nm); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->is_rec_dmn=crd->is_rec_dmn; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->sz=crd->sz; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->var_typ=crd->var_typ; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->dmn_id=crd->dmn_id; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->grp_dpt=crd->grp_dpt; /* MSA */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.BASIC_DMN=crd->lmt_msa.BASIC_DMN; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.dmn_cnt=crd->lmt_msa.dmn_cnt; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.dmn_nm=(char *)strdup(crd->lmt_msa.dmn_nm); trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.dmn_sz_org=crd->lmt_msa.dmn_sz_org; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.lmt_crr=crd->lmt_msa.lmt_crr; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.lmt_dmn=NULL; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.lmt_dmn_nbr=0; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.MSA_USR_RDR=crd->lmt_msa.MSA_USR_RDR; trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].crd->lmt_msa.WRP=crd->lmt_msa.WRP; }else{ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports dimension [%d]%s of variable <%s> with out of scope coordinate\n",nco_prg_nm_get(),fnc_nm,idx_dmn_var,var_trv.var_dmn[idx_dmn_var].dmn_nm_fll,var_trv.nm_fll); /* Mark as False */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].is_crd_var=False; /* Store the unique dimension as if it was a non coordinate */ trv_tbl->lst[idx_var].var_dmn[idx_dmn_var].ncd=dmn_trv; } /* None was found in scope */ } /* There are coordinates; one must be chosen */ } /* Loop dimensions for object (variable) */ } /* Filter variables */ } /* Loop table */ /* Check if bool array is all filled */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* Filter variables */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Loop dimensions for object (variable) */ for(int idx_dmn_var=0;idx_dmn_varlst[idx_var].var_dmn[idx_dmn_var].is_crd_var == nco_obj_typ_err) { if(nco_dbg_lvl_get() == nco_dbg_old ){ (void)fprintf(stdout,"%s: OOPSY %s reports variable <%s> with NOT filled dimension [%d]%s\n",nco_prg_nm_get(),fnc_nm, var_trv.nm_fll,idx_dmn_var,var_trv.var_dmn[idx_dmn_var].dmn_nm_fll); } /* endif dbg */ } } /* Loop dimensions for object (variable) */ } /* Filter variables */ } /* Loop table */ /* Check if bool array is all filled */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* Filter variables */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Loop dimensions for object (variable) */ for(int idx_dmn_var=0;idx_dmn_varlst[idx_var].var_dmn[idx_dmn_var].is_crd_var != nco_obj_typ_err); } /* Loop dimensions for object (variable) */ } /* Filter variables */ } /* Loop table */ } /* nco_bld_var_dmn() */ void nco_wrt_trv_tbl /* [fnc] Obtain file information from GTT (Group Traversal Table) for debugging */ (const int nc_id, /* I [ID] File ID */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ nco_bool use_flg_xtr) /* I [flg] Use flg_xtr in selection */ { const char fnc_nm[]="nco_wrt_trv_tbl()"; /* [sng] Function name */ int nbr_dmn_var; /* [nbr] Number of variables in group */ int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ int dmn_id_var[NC_MAX_DIMS]; /* [id] Dimensions IDs array for variable */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; nco_bool flg_xtr; if(use_flg_xtr)flg_xtr=var_trv.flg_xtr; else flg_xtr=True; /* If object is an extracted variable... */ if(var_trv.nco_typ == nco_obj_typ_var && flg_xtr){ if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO %s variable <%s>",nco_prg_nm_get(),fnc_nm,var_trv.nm_fll); } /* endif dbg */ /* Obtain group ID where variable is located using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Get type of variable and number of dimensions */ (void)nco_inq_var(grp_id,var_id,(char *)NULL,(nc_type *)NULL,&nbr_dmn_var,(int *)NULL,(int *)NULL); /* Get dimension IDs for variable */ (void)nco_inq_vardimid(grp_id,var_id,dmn_id_var); if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout," %d dimensions: ",nbr_dmn_var); } /* endif dbg */ /* Variable dimensions */ for(int idx_dmn_var=0;idx_dmn_varnco_typ == nco_obj_typ_var); if(*rec_dmn_nm){ nbr_rec=(*rec_dmn_nm)->nbr; } else { nbr_rec=0; (*rec_dmn_nm)=(nm_tbl_sct *)nco_malloc(sizeof(nm_tbl_sct)); (*rec_dmn_nm)->nbr=0; (*rec_dmn_nm)->lst=NULL; /* Must be NULL to nco_realloc() correct handling */ } /* Loop dimensions for object (variable) */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++) { /* Get unique dimension object from unique dimension ID, in input list */ dmn_trv=nco_dmn_trv_sct(var_trv->var_dmn[idx_dmn].dmn_id,trv_tbl); /* Dimension is a record dimension */ if(dmn_trv->is_rec_dmn){ /* Add one more element to table (nco_realloc nicely handles first time/not first time insertions) */ (*rec_dmn_nm)->lst=(nm_sct *)nco_realloc((*rec_dmn_nm)->lst,(nbr_rec+1)*sizeof(nm_sct)); /* Duplicate string into list */ (*rec_dmn_nm)->lst[nbr_rec].nm=strdup(dmn_trv->nm); nbr_rec++; } /* Dimension is a record dimension */ } /* Loop dimensions for object (variable) */ if(*rec_dmn_nm) (*rec_dmn_nm)->nbr=nbr_rec; } /* nco_get_rec_dmn_nm() */ var_sct ** /* O [sct] Variable list */ nco_fll_var_trv /* [fnc] Fill-in variable structure list for all extracted variables */ (const int nc_id, /* I [id] netCDF file ID */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { int grp_id; /* [ID] Group ID */ int var_id; /* [ID] Variable ID */ int idx_var; int nbr_xtr; var_sct **var=NULL; nbr_xtr=0; /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Filter variables to extract */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && trv_tbl->lst[tbl_idx].flg_xtr){ nbr_xtr++; } /* Filter variables */ } /* Loop table */ /* Fill-in variable structure list for all extracted variables */ var=(var_sct **)nco_malloc(nbr_xtr*sizeof(var_sct *)); idx_var=0; /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Filter variables */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && trv_tbl->lst[tbl_idx].flg_xtr){ trv_sct var_trv=trv_tbl->lst[tbl_idx]; /* Obtain group ID from API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Transfer from table to local variable array; nco_var_fll() needs location ID and name */ var[idx_var]=nco_var_fll_trv(grp_id,var_id,&var_trv,trv_tbl); idx_var++; } /* Filter variables */ } /* Loop table */ *xtr_nbr=nbr_xtr; return var; } /* nco_fll_var_trv() */ var_sct ** /* O [sct] Variable list */ nco_var_trv /* [fnc] Fill-in variable structure list for all variables named "var_nm" */ (const int nc_id, /* I [id] netCDF file ID */ const char * const var_nm, /* I [sng] Variable name (relative) */ int * const xtr_nbr, /* I/O [nbr] Number of variables in extraction list */ const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { int idx_var; int nbr_xtr; var_sct **var=NULL; nbr_xtr=0; /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Filter variables to extract */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && (strcmp(trv_tbl->lst[tbl_idx].nm,var_nm) == 0) ){ nbr_xtr++; } /* Filter variables */ } /* Loop table */ /* Fill-in variable structure list for all extracted variables */ var=(var_sct **)nco_malloc(nbr_xtr*sizeof(var_sct *)); idx_var=0; /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Filter variables */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && (strcmp(trv_tbl->lst[tbl_idx].nm,var_nm) == 0) ){ trv_sct var_trv=trv_tbl->lst[tbl_idx]; int grp_id; /* [ID] Group ID */ int var_id; /* [ID] Variable ID */ /* Obtain group ID from API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Transfer from table to local variable array; nco_var_fll() needs location ID and name */ var[idx_var]=nco_var_fll_trv(grp_id,var_id,&var_trv,trv_tbl); idx_var++; } /* Filter variables */ } /* Loop table */ *xtr_nbr=nbr_xtr; return var; } /* nco_var_trv() */ void nco_cpy_fix_var_trv /* [fnc] Copy fixed variables from input to output file */ (const int nc_id, /* I [ID] netCDF input file ID */ const int out_id, /* I [ID] netCDF output file ID */ const gpe_sct * const gpe, /* I [sng] GPE structure */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { char *grp_out_fll; /* [sng] Group name */ int grp_id_in; /* [ID] Group ID */ int grp_id_out; /* [ID] Group ID */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* If object is a fixed variable... */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.enm_prc_typ == fix_typ){ /* If variable is an ensemble member, do not create it in the same location as input */ if (var_trv.flg_nsm_mbr == True){ assert(nco_prg_id_get() == ncge); continue; } /* Obtain group IDs using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id_in); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv.grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv.grp_nm_fll); (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_id_out); if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: INFO writing fixed variable <%s> from ",nco_prg_nm_get(),var_trv.nm_fll); (void)nco_prn_grp_nm_fll(grp_id_in); (void)fprintf(stdout," to "); (void)nco_prn_grp_nm_fll(grp_id_out); (void)fprintf(stdout,"\n"); } /* endif dbg */ /* Copy variable data */ (void)nco_cpy_var_val_mlt_lmt_trv(grp_id_in,grp_id_out,(FILE *)NULL,md5,&var_trv); /* Memory management after current extracted group */ if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll); } /* If object is a fixed variable... */ } /* Loop table */ } /* nco_cpy_fix_var_trv() */ void nco_prc_cmn /* [fnc] Process objects (ncbo only) */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_id_2, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_sct * trv_1, /* I [sct] Table object */ trv_sct * trv_2, /* I [sct] Table object */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ nco_bool flg_grp_1, /* I [flg] Use table 1 as template for group creation on True, otherwise use table 2 */ const nco_bool flg_dfn) /* I [flg] Action type (True for define variables, False when write variables ) */ { const char fnc_nm[]="nco_prc_cmn()"; /* [sng] Function name */ char *grp_out_fll; /* [sng] Group name */ int fl_fmt; /* [enm] netCDF file format */ int grp_id_1; /* [id] Group ID in input file */ int grp_id_2; /* [id] Group ID in input file */ int grp_out_id; /* [id] Group ID in output file */ int nco_prg_id; /* [enm] Program ID */ int var_id_1; /* [id] Variable ID in input file */ int var_id_2; /* [id] Variable ID in input file */ int var_out_id; /* [id] Variable ID in output file */ var_sct *var_prc_1; /* [sct] Variable to process in file 1 */ var_sct *var_prc_2; /* [sct] Variable to process in file 2 */ var_sct *var_prc_out; /* [sct] Variable to process in output */ var_sct *var_prc_gtr; /* [sct] Greater rank variable to process */ var_sct *var_prc_lsr; /* [sct] Lesser rank variable to process */ nco_bool RNK_1_GTR; /* [flg] Rank of variable in file 1 variable greater than or equal to file 2 */ prc_typ_enm prc_typ_1; /* [enm] Processing type */ prc_typ_enm prc_typ_2; /* [enm] Processing type */ assert(trv_1->nco_typ == nco_obj_typ_var); assert(trv_1->flg_xtr); assert(trv_2->nco_typ == nco_obj_typ_var); assert(trv_2->flg_xtr); /* Get Program ID */ nco_prg_id=nco_prg_id_get(); /* Get output file format */ (void)nco_inq_format(nc_out_id,&fl_fmt); /* Edit group name for output */ if(flg_grp_1){ if(gpe) grp_out_fll=nco_gpe_evl(gpe,trv_1->grp_nm_fll); else grp_out_fll=(char *)strdup(trv_1->grp_nm_fll); }else{ /* !flg_grp_1 */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,trv_2->grp_nm_fll); else grp_out_fll=(char *)strdup(trv_2->grp_nm_fll); } /* !flg_grp_1 */ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id_1,trv_1->grp_nm_fll,&grp_id_1); (void)nco_inq_grp_full_ncid(nc_id_2,trv_2->grp_nm_fll,&grp_id_2); /* Get variable ID */ (void)nco_inq_varid(grp_id_1,trv_1->nm,&var_id_1); (void)nco_inq_varid(grp_id_2,trv_2->nm,&var_id_2); /* Allocate variable structure and fill with metadata */ var_prc_1=nco_var_fll_trv(grp_id_1,var_id_1,trv_1,trv_tbl_1); var_prc_2=nco_var_fll_trv(grp_id_2,var_id_2,trv_2,trv_tbl_2); if(var_prc_1->nbr_dim >= var_prc_2->nbr_dim) RNK_1_GTR=True; else RNK_1_GTR=False; var_prc_gtr= (RNK_1_GTR) ? var_prc_1 : var_prc_2; var_prc_lsr= (RNK_1_GTR) ? var_prc_2 : var_prc_1; var_prc_out= (RNK_1_GTR) ? nco_var_dpl(var_prc_1) : nco_var_dpl(var_prc_2); /* Get processing type */ (void)nco_var_lst_dvd_trv(var_prc_1,var_prc_out,CNV_CCM_CCSM_CF,FIX_REC_CRD,nco_pck_map_nil,nco_pck_plc_nil,dmn_xcl,nbr_dmn_xcl,&prc_typ_1); (void)nco_var_lst_dvd_trv(var_prc_2,var_prc_out,CNV_CCM_CCSM_CF,FIX_REC_CRD,nco_pck_map_nil,nco_pck_plc_nil,dmn_xcl,nbr_dmn_xcl,&prc_typ_2); /* Conform type and rank for processed variables */ if(prc_typ_1 == prc_typ && prc_typ_2 == prc_typ){ int dmn_idx_gtr; int dmn_idx_lsr; /* Check that all dims in var_prc_lsr are in var_prc_gtr */ for(dmn_idx_lsr=0;dmn_idx_lsrnbr_dim;dmn_idx_lsr++){ for(dmn_idx_gtr=0;dmn_idx_gtrnbr_dim;dmn_idx_gtr++) if(!strcmp(var_prc_lsr->dim[dmn_idx_lsr]->nm,var_prc_gtr->dim[dmn_idx_gtr]->nm)) break; if(dmn_idx_gtr == var_prc_gtr->nbr_dim){ (void)fprintf(stdout,"%s: ERROR Variables do not conform: variable %s has dimension %s not present in variable %s\n",nco_prg_nm_get(),var_prc_lsr->nm,var_prc_lsr->dim[dmn_idx_lsr]->nm,var_prc_gtr->nm); nco_exit(EXIT_FAILURE); } /* endif error */ } /* end loop over idx */ /* Read */ (void)nco_msa_var_get_trv(nc_id_1,var_prc_1,trv_tbl_1); (void)nco_msa_var_get_trv(nc_id_2,var_prc_2,trv_tbl_2); nc_type typ_hgh; typ_hgh=ncap_typ_hgh(var_prc_1->type,var_prc_2->type); /* Make sure variables conform in type */ if(var_prc_1->type != var_prc_2->type) if(nco_dbg_lvl_get() >= nco_dbg_std && flg_dfn) (void)fprintf(stderr,"%s: INFO Input variables do not conform in type: file 1 variable %s has type %s, file 2 variable %s has type %s, output variable %s will have type %s\n",nco_prg_nm_get(),var_prc_1->nm,nco_typ_sng(var_prc_1->type),var_prc_2->nm,nco_typ_sng(var_prc_2->type),var_prc_gtr->nm,nco_typ_sng(typ_hgh)); typ_hgh=ncap_var_retype(var_prc_1,var_prc_2); trv_1->var_typ=trv_2->var_typ=typ_hgh; /* Broadcast lesser to greater variable. NB: Pointers may change so _gtr, _lsr not valid */ if(var_prc_1->nbr_dim != var_prc_2->nbr_dim){ (void)ncap_var_cnf_dmn(&var_prc_1,&var_prc_2); }else{ /* Still possible that variables are mismatched even if ranks are equal One or more dimensions could be degenerate Before subtraction must make sure dimension sizes match Or re-code ncap_var_cnf_dmn() so that it understands how to broadcast degenerate dimensions */ for(int idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ if(var_prc_1->dim[idx_dmn]->sz != var_prc_2->dim[idx_dmn]->sz){ (void)fprintf(stdout,"%s: ERROR Variables do not conform: variable %s has dimension %s with sizes %ld and %ld in input files one and two, respectively\n",nco_prg_nm_get(),var_prc_1->nm_fll,var_prc_1->dim[idx_dmn]->nm,var_prc_1->dim[idx_dmn]->sz,var_prc_2->dim[idx_dmn]->sz); nco_exit(EXIT_FAILURE); } /* endif error */ } /* end loop over idx_dmn */ } /* end else */ /* var1 and var2 now conform in size and type to eachother and are in memory */ assert(var_prc_1->type == var_prc_2->type); assert(trv_1->var_typ == trv_2->var_typ); assert(trv_1->var_typ == var_prc_1->type); } /* Conform type and rank for process variables */ /* Define mode */ if(flg_dfn){ char *rec_dmn_nm=NULL; /* [sng] Record dimension name */ nm_tbl_sct *rec_dmn_nm_1=NULL; /* [sct] Record dimension names array */ nm_tbl_sct *rec_dmn_nm_2=NULL; /* [sct] Record dimension names array */ nco_bool PCK_ATT_CPY; /* [flg] Copy attributes "scale_factor", "add_offset" */ PCK_ATT_CPY=nco_pck_cpy_att(nco_prg_id,nco_pck_plc_nil,var_prc_1); /* If output group does not exist, create it */ if(nco_inq_grp_full_ncid_flg(nc_out_id,grp_out_fll,&grp_out_id)) nco_def_grp_full(nc_out_id,grp_out_fll,&grp_out_id); /* Detect duplicate GPE names in advance, then exit with helpful error */ if(gpe) (void)nco_gpe_chk(grp_out_fll,trv_1->nm,&gpe_nm,&nbr_gpe_nm); /* Get array of record names for object */ (void)nco_get_rec_dmn_nm(trv_1,trv_tbl_1,&rec_dmn_nm_1); (void)nco_get_rec_dmn_nm(trv_2,trv_tbl_2,&rec_dmn_nm_2); /* Use for record dimension name the first in array */ if(rec_dmn_nm_1->lst) rec_dmn_nm=(char *)strdup(rec_dmn_nm_1->lst[0].nm); if(!rec_dmn_nm && rec_dmn_nm_2->lst) rec_dmn_nm=(char *)strdup(rec_dmn_nm_2->lst[0].nm); /* Define variable in output file. NB: Use file/variable of greater rank as template */ var_out_id= (RNK_1_GTR) ? nco_cpy_var_dfn_trv(nc_id_1,nc_out_id,cnk,grp_out_fll,dfl_lvl,gpe,rec_dmn_nm,trv_1,trv_tbl_1) : nco_cpy_var_dfn_trv(nc_id_2,nc_out_id,cnk,grp_out_fll,dfl_lvl,gpe,rec_dmn_nm,trv_2,trv_tbl_2); /* Copy variable's attributes */ if(RNK_1_GTR) (void)nco_att_cpy(grp_id_1,grp_out_id,var_id_1,var_out_id,PCK_ATT_CPY); else (void)nco_att_cpy(grp_id_2,grp_out_id,var_id_2,var_out_id,PCK_ATT_CPY); /* Memory management for record dimension names */ if(rec_dmn_nm) rec_dmn_nm=(char *)nco_free(rec_dmn_nm); if(rec_dmn_nm_1){ for(int idx=0;idxnbr;idx++) rec_dmn_nm_1->lst[idx].nm=(char *)nco_free(rec_dmn_nm_1->lst[idx].nm); rec_dmn_nm_1=(nm_tbl_sct *)nco_free(rec_dmn_nm_1); } /* !rec_dmn_nm_1 */ if(rec_dmn_nm_2){ for(int idx=0;idxnbr;idx++) rec_dmn_nm_2->lst[idx].nm=(char *)nco_free(rec_dmn_nm_2->lst[idx].nm); rec_dmn_nm_2=(nm_tbl_sct *)nco_free(rec_dmn_nm_2); } /* !rec_dmn_nm_2 */ }else{ /* !flg_dfn */ /* Write mode */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ int has_mss_val; /* [flg] Variable has missing value */ ptr_unn mss_val; /* [sct] Missing value */ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_out_id,grp_out_fll,&grp_out_id); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,trv_1->nm,&var_out_id); if(nco_dbg_lvl_get() >= nco_dbg_vrb) (void)fprintf(stdout,"%s: INFO %s reports operation type <%d> for <%s>\n",nco_prg_nm_get(),fnc_nm,prc_typ_1,trv_1->nm_fll); /* Non-processed variable */ if(prc_typ_1 == fix_typ || prc_typ_2 == fix_typ){ if(RNK_1_GTR) (void)nco_cpy_var_val_mlt_lmt_trv(grp_id_1,grp_out_id,(FILE *)NULL,md5,trv_1); else (void)nco_cpy_var_val_mlt_lmt_trv(grp_id_2,grp_out_id,(FILE *)NULL,md5,trv_2); } /* endif fix */ /* Processed variable */ if(prc_typ_1 == prc_typ && prc_typ_2 == prc_typ){ var_prc_out->id=var_out_id; /* fxm: gtr or lsr? */ var_prc_out->srt=var_prc_gtr->srt; var_prc_out->cnt=var_prc_gtr->cnt; /* Set missing value */ has_mss_val=var_prc_gtr->has_mss_val; /* Change missing_value, if any, of lesser rank to missing_value, if any, of greater rank */ if(RNK_1_GTR) has_mss_val=nco_mss_val_cnf(var_prc_1,var_prc_2); else has_mss_val=nco_mss_val_cnf(var_prc_2,var_prc_1); /* mss_val of larger rank, if any, overrides mss_val of smaller rank */ if(has_mss_val) mss_val= (RNK_1_GTR) ? var_prc_1->mss_val : var_prc_2->mss_val; /* Perform specified binary operation */ switch(nco_op_typ){ case nco_op_add: /* [enm] Add file_1 to file_2 */ (void)nco_var_add(var_prc_1->type,var_prc_1->sz,has_mss_val,mss_val,var_prc_2->val,var_prc_1->val); break; case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */ (void)nco_var_mlt(var_prc_1->type,var_prc_1->sz,has_mss_val,mss_val,var_prc_2->val,var_prc_1->val); break; case nco_op_dvd: /* [enm] Divide file_1 by file_2 */ (void)nco_var_dvd(var_prc_1->type,var_prc_1->sz,has_mss_val,mss_val,var_prc_2->val,var_prc_1->val); break; case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */ (void)nco_var_sbt(var_prc_1->type,var_prc_1->sz,has_mss_val,mss_val,var_prc_2->val,var_prc_1->val); break; default: /* Other defined nco_op_typ values are valid for ncra(), ncrcat(), ncwa(), not ncbo() */ (void)fprintf(stdout,"%s: ERROR Illegal nco_op_typ in binary operation\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); break; } /* end case */ /* Copy result to output file */ if(var_prc_1->nbr_dim == 0) (void)nco_put_var1(grp_out_id,var_prc_out->id,var_prc_out->srt,var_prc_1->val.vp,var_prc_1->type); else (void)nco_put_vara(grp_out_id,var_prc_out->id,var_prc_out->srt,var_prc_out->cnt,var_prc_1->val.vp,var_prc_1->type); } /* !prc_typ */ } /* !flg_dfn */ /* Free allocated variable structures */ var_prc_1->val.vp=nco_free(var_prc_1->val.vp); var_prc_2->val.vp=nco_free(var_prc_2->val.vp); var_prc_1=(var_sct *)nco_free(var_prc_1); var_prc_2=(var_sct *)nco_free(var_prc_2); var_prc_out=(var_sct *)nco_free(var_prc_out); /* Free output path name */ grp_out_fll=(char *)nco_free(grp_out_fll); } /* nco_prc_cmn() */ void nco_cpy_fix /* [fnc] Copy fixed object (ncbo only) */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const nco_bool FIX_REC_CRD, /* I [flg] Do not interpolate/multiply record coordinate variables (ncflint only) */ CST_X_PTR_CST_PTR_CST_Y(dmn_sct,dmn_xcl), /* I [sct] Dimensions not allowed in fixed variables */ const int nbr_dmn_xcl, /* I [nbr] Number of altered dimensions */ trv_sct *trv_1, /* I/O [sct] Table object (nco_cpy_var_dfn_trv) */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ const nco_bool flg_dfn) /* I [flg] Action type (True for define variables, False when write variables ) */ { char *grp_out_fll; /* [sng] Group name */ int fl_fmt; /* [enm] netCDF file format */ int grp_id_1; /* [id] Group ID in input file */ int grp_out_id; /* [id] Group ID in output file */ int nco_prg_id; /* [enm] Program ID */ int var_id_1; /* [id] Variable ID in input file */ int var_out_id; /* [id] Variable ID in output file */ md5_sct *md5=NULL; /* [sct] MD5 configuration */ var_sct *var_prc_1; /* [sct] Variable to process in file 1 */ var_sct *var_prc_out; /* [sct] Variable to process in output */ prc_typ_enm prc_typ_1; /* [enm] Processing type */ assert(trv_1->nco_typ == nco_obj_typ_var); assert(trv_1->flg_xtr); /* Get Program ID */ nco_prg_id=nco_prg_id_get(); /* Get output file format */ (void)nco_inq_format(nc_out_id,&fl_fmt); /* Edit group name for output */ if(gpe) grp_out_fll=nco_gpe_evl(gpe,trv_1->grp_nm_fll); else grp_out_fll=(char *)strdup(trv_1->grp_nm_fll); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id_1,trv_1->grp_nm_fll,&grp_id_1); /* Get variable ID */ (void)nco_inq_varid(grp_id_1,trv_1->nm,&var_id_1); /* Allocate variable structure and fill with metadata */ var_prc_1=nco_var_fll_trv(grp_id_1,var_id_1,trv_1,trv_tbl_1); var_prc_out=nco_var_dpl(var_prc_1); (void)nco_var_lst_dvd_trv(var_prc_1,var_prc_out,CNV_CCM_CCSM_CF,FIX_REC_CRD,nco_pck_map_nil,nco_pck_plc_nil,dmn_xcl,nbr_dmn_xcl,&prc_typ_1); if(prc_typ_1 != fix_typ){ var_prc_1->val.vp=nco_free(var_prc_1->val.vp); var_prc_1=(var_sct *)nco_free(var_prc_1); var_prc_out=(var_sct *)nco_free(var_prc_out); grp_out_fll=(char *)nco_free(grp_out_fll); return; } /* endif */ if(flg_dfn){ /* Define mode */ nco_bool PCK_ATT_CPY; /* [flg] Copy attributes "scale_factor", "add_offset" */ PCK_ATT_CPY=nco_pck_cpy_att(nco_prg_id,nco_pck_plc_nil,var_prc_1); /* If output group does not exist, create it */ if(nco_inq_grp_full_ncid_flg(nc_out_id,grp_out_fll,&grp_out_id)) nco_def_grp_full(nc_out_id,grp_out_fll,&grp_out_id); /* Detect duplicate GPE names in advance, then exit with helpful error */ if(gpe)(void)nco_gpe_chk(grp_out_fll,trv_1->nm,&gpe_nm,&nbr_gpe_nm); /* Define variable in output file */ var_out_id=nco_cpy_var_dfn_trv(nc_id_1,nc_out_id,cnk,grp_out_fll,dfl_lvl,gpe,(char *)NULL,trv_1,trv_tbl_1); /* Copy variable's attributes */ (void)nco_att_cpy(grp_id_1,grp_out_id,var_id_1,var_out_id,PCK_ATT_CPY); }else{ /* !flg_dfn */ /* Write mode */ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_out_id,grp_out_fll,&grp_out_id); /* Get variable ID */ (void)nco_inq_varid(grp_out_id,trv_1->nm,&var_out_id); /* Copy non-processed variable */ (void)nco_cpy_var_val_mlt_lmt_trv(grp_id_1,grp_out_id,(FILE *)NULL,md5,trv_1); } /* !flg_dfn */ /* Free allocated variable structures */ var_prc_1->val.vp=nco_free(var_prc_1->val.vp); var_prc_1=(var_sct *)nco_free(var_prc_1); var_prc_out=(var_sct *)nco_free(var_prc_out); /* Free output path name */ grp_out_fll=(char *)nco_free(grp_out_fll); } /* nco_cpy_fix() */ nco_bool /* O [flg] Copy packing attributes */ nco_pck_cpy_att /* [fnc] Inquire about copying packing attributes */ (const int nco_prg_id, /* I [enm] Program ID */ const int nco_pck_plc, /* I [enm] Packing policy */ const var_sct * const var_prc) /* I [sct] Variable */ { nco_bool PCK_ATT_CPY=True; /* [flg] Copy attributes "scale_factor", "add_offset" */ /* Copy all attributes except in cases where packing/unpacking is involved 0. Variable is unpacked on input, unpacked on output --> Copy all attributes 1. Variable is packed on input, is not altered, and remains packed on output --> Copy all attributes 2. Variable is packed on input, is unpacked for some reason, and will be unpacked on output --> Copy all attributes except scale_factor and add_offset 3. Variable is packed on input, is unpacked for some reason, and will be packed on output (possibly with new packing attributes) --> Copy all attributes, but scale_factor and add_offset must be overwritten later with new values 4. Variable is not packed on input, packing is performed, and output is packed --> Copy all attributes, define dummy values for scale_factor and add_offset now, and write those values later, when they are known */ /* Do not copy packing attributes "scale_factor" and "add_offset" if variable is packed in input file and unpacked in output file Arithmetic operators calling nco_var_dfn() with fixed variables should leave them fixed Currently ncap calls nco_var_dfn() only for fixed variables, so handle exception with ncap-specific condition */ /* Copy exising packing attributes, if any, unless... */ if(nco_is_rth_opr(nco_prg_id) && /* ...operator is arithmetic... */ nco_prg_id != ncap && /* ...and is not ncap (hence it must be, e.g., ncra, ncbo)... */ !var_prc->is_fix_var && /* ...and variable is processed (not fixed)... */ var_prc->pck_dsk) /* ...and variable is packed in input file... */ PCK_ATT_CPY=False; /* Do not copy packing attributes when unpacking variables ncpdq is currently only operator that passes values other than nco_pck_plc_nil */ if(nco_pck_plc == nco_pck_plc_upk) /* ...and variable will be _unpacked_ ... */ PCK_ATT_CPY=False; return PCK_ATT_CPY; } /* nco_pck_cpy_att() */ nco_bool /* O [flg] True for match found */ nco_rel_mch /* [fnc] Relative match of object in table 1 to table 2 */ (const int nc_id_1, /* I [id] netCDF input-file ID from file 1 */ const int nc_id_2, /* I [id] netCDF input-file ID from file 2 */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_sct * var_trv, /* I [sct] Table variable object (can be from table 1 or 2) */ nco_bool flg_tbl_1, /* I [flg] Table variable object is from table1 for True, otherwise is from table 2 */ nco_bool flg_grp_1, /* I [flg] Use table 1 as template for group creation on True, otherwise use table 2 */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ const nco_bool flg_dfn) /* I [flg] Action type (True for define variables, False when write variables ) */ { nco_bool rel_mch; /* [flg] A match was found */ rel_mch=False; if(flg_tbl_1){ for(unsigned uidx=0;uidxnbr;uidx++){ if(trv_tbl_2->lst[uidx].nco_typ == nco_obj_typ_var && !strcmp(var_trv->nm,trv_tbl_2->lst[uidx].nm)){ trv_sct *trv_2=&trv_tbl_2->lst[uidx]; rel_mch=True; (void)nco_prc_cmn(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,nco_op_typ,var_trv,trv_2,trv_tbl_1,trv_tbl_2,flg_grp_1,flg_dfn); } /* A relative match was found */ } /* Loop table 2 */ }else if(!flg_tbl_1){ for(unsigned uidx=0;uidxnbr;uidx++){ if(trv_tbl_1->lst[uidx].nco_typ == nco_obj_typ_var && !strcmp(var_trv->nm,trv_tbl_1->lst[uidx].nm)){ trv_sct *trv_1=&trv_tbl_1->lst[uidx]; rel_mch=True; (void)nco_prc_cmn(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,nco_op_typ,trv_1,var_trv,trv_tbl_1,trv_tbl_2,flg_grp_1,flg_dfn); } /* A relative match was found */ } /* Loop table 2 */ } /* !flg_tbl_1 */ return rel_mch; } /* nco_rel_mch() */ void nco_prc_cmn_nm /* [fnc] Process common objects from a common mames list (ncbo only) */ (const int nc_id_1, /* I [id] netCDF input-file ID */ const int nc_id_2, /* I [id] netCDF input-file ID */ const int nc_out_id, /* I [id] netCDF output-file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ gpe_nm_sct *gpe_nm, /* I/O [sct] GPE name duplicate check array */ int nbr_gpe_nm, /* I/O [nbr] Number of GPE entries */ const nco_bool CNV_CCM_CCSM_CF, /* I [flg] File adheres to NCAR CCM/CCSM/CF conventions */ const int nco_op_typ, /* I [enm] Operation type (command line -y) */ trv_tbl_sct * const trv_tbl_1, /* I/O [sct] GTT (Group Traversal Table) */ trv_tbl_sct * const trv_tbl_2, /* I/O [sct] GTT (Group Traversal Table) */ const nco_cmn_t * const cmn_lst, /* I [sct] List of common names */ const int nbr_cmn_nm, /* I [nbr] Number of common names entries */ const nco_bool flg_dfn) /* I [flg] Action type (True for define variables, False when write variables ) */ { /* Purpose: Process common objects from a common mames list (ncbo only) */ const char fnc_nm[]="nco_prc_cmn_nm()"; /* [sng] Function name */ int nbr_grp_dpt_1; /* [nbr] Number of depth 1 groups (root = 0) */ int nbr_grp_dpt_2; /* [nbr] Number of depth 1 groups (root = 0) */ nbr_grp_dpt_1=trv_tbl_inq_dpt(trv_tbl_1); nbr_grp_dpt_2=trv_tbl_inq_dpt(trv_tbl_2); /* Process objects in list */ for(int idx=0;idxflg_xtr && trv_2->flg_xtr){ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports common element to output:%s\n",nco_prg_nm_get(),fnc_nm,trv_1->nm_fll); /* Process common object */ (void)nco_prc_cmn(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,nco_op_typ,trv_1,trv_2,trv_tbl_1,trv_tbl_2,True,flg_dfn); }else{ /* Object exists and is flagged for extraction only in one file */ /* Number of depth 1 groups in file 1 greater (typically model file) */ if(nbr_grp_dpt_1 > nbr_grp_dpt_2){ if(trv_1 && cmn_lst[idx].flg_in_fl[0] && !cmn_lst[idx].flg_in_fl[1] && trv_1->flg_xtr){ /* Object exists and is flagged for extraction only in file 1 */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports element in file 1 to output:%s\n",nco_prg_nm_get(),fnc_nm,trv_1->nm_fll); /* Try relative match in file 2 */ has_mch=nco_rel_mch(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_1,True,True,trv_tbl_1,trv_tbl_2,flg_dfn); /* Match not found in file 2, copy instead object from file 1 as fixed to output */ if(!has_mch) (void)nco_cpy_fix(nc_id_1,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,trv_1,trv_tbl_1,flg_dfn); }else if(trv_2 && cmn_lst[idx].flg_in_fl[0] == False && cmn_lst[idx].flg_in_fl[1] && trv_2->flg_xtr){ /* Object exists and is flagged for extraction only in file 2 */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports element in file 2 to output:%s\n",nco_prg_nm_get(),fnc_nm,trv_2->nm_fll); /* Try relative match in file 1 */ has_mch=nco_rel_mch(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_2,False,True,trv_tbl_1,trv_tbl_2,flg_dfn); /* Match not found in file 2, copy instead object from file 2 as fixed to output */ if(!has_mch) (void)nco_cpy_fix(nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,trv_2,trv_tbl_2,flg_dfn); } /* fl_2 */ }else{ /* nbr_grp_dpt_1 <= nbr_grp_dpt_2) */ /* Number of depth 1 groups in file 2 greater */ if(trv_1 && cmn_lst[idx].flg_in_fl[0] && !cmn_lst[idx].flg_in_fl[1] && trv_1->flg_xtr){ /* Object exists and is flagged for extraction only in file 1 */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports element in file 1 to output:%s\n",nco_prg_nm_get(),fnc_nm,trv_1->nm_fll); /* Try relative match in file 2 */ has_mch=nco_rel_mch(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_1,True,False,trv_tbl_1,trv_tbl_2,flg_dfn); /* Match was not found in file 2, copy instead object from file 1 as fixed to output */ if(!has_mch) (void)nco_cpy_fix(nc_id_1,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,trv_1,trv_tbl_1,flg_dfn); }else if(trv_2 && cmn_lst[idx].flg_in_fl[0] == False && cmn_lst[idx].flg_in_fl[1] && trv_2->flg_xtr){ /* Object exists and is flagged for extraction only in file 2 */ if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: INFO %s reports element in file 2 to output:%s\n",nco_prg_nm_get(),fnc_nm,trv_2->nm_fll); /* Try relative match in file 1 */ has_mch=nco_rel_mch(nc_id_1,nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,nco_op_typ,trv_2,False,False,trv_tbl_1,trv_tbl_2,flg_dfn); /* Match not found in file 2, copy instead object from file 2 as fixed to output */ if(!has_mch) (void)nco_cpy_fix(nc_id_2,nc_out_id,cnk,dfl_lvl,gpe,gpe_nm,nbr_gpe_nm,CNV_CCM_CCSM_CF,(nco_bool)False,(dmn_sct **)NULL,(int)0,trv_2,trv_tbl_2,flg_dfn); } /* fl_2 */ } /* nbr_grp_dpt_1 <= nbr_grp_dpt_2) */ } /* Object exists only in one file and is to extract */ } /* Process objects in list */ } /* nco_prc_cmn_nm() */ void nco_var_prc_fix_trv /* [fnc] Store processed and fixed variables info into GTT */ (const int nbr_var_prc, /* I [nbr] Number of processed variables */ var_sct **var_prc, /* I [sct] Array of processed variables */ const int nbr_var_fix, /* I [nbr] Number of fixed variables */ var_sct **var_fix, /* I [sct] Array of fixed variables */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Store processed and fixed variables info into GTT */ /* Store processed variables info into table */ for(int idx_var=0;idx_varnm_fll,trv_tbl); assert(var_trv); /* Mark fixed/processed flag in table for "var_nm_fll" */ (void)trv_tbl_mrk_prc_fix(var_prc[idx_var]->nm_fll,prc_typ,trv_tbl); } /* Store processed variables info into table */ /* Store fixed variables info into table */ for(int idx_var=0;idx_varnm_fll,trv_tbl); assert(var_trv); /* Mark fixed/processed flag in table for "var_nm_fll" */ (void)trv_tbl_mrk_prc_fix(var_fix[idx_var]->nm_fll,fix_typ,trv_tbl); } /* Store fixed variables info into table */ return; } /* end nco_var_prc_fix_trv() */ void nco_var_typ_trv /* [fnc] Transfer variable type into GTT */ (const int prc_nbr, /* I [nbr] Number of processed variables */ var_sct **var, /* I [sct] Array of extracted variables */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Transfer variable type to table */ /* Loop table. */ for(int idx_var=0;idx_varnbr;uidx++){ /* Match */ if(strcmp(var[idx_var]->nm_fll,trv_tbl->lst[uidx].nm_fll) == 0){ trv_tbl->lst[uidx].var_typ_out=typ_out; break; } /* Match */ } /* Mark output type in table for "nm_fll" */ } /* Loop table. */ return; } /* end nco_var_typ_trv() */ var_sct * /* O [sct] Variable structure */ nco_var_fll_trv /* [fnc] Allocate variable structure and fill with metadata */ (const int grp_id, /* I [id] Group ID */ const int var_id, /* I [id] Variable ID */ const trv_sct * const var_trv, /* I [sct] Object to write (variable) */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: nco_malloc() and return a completed var_sct; traversal version of nco_var_fll() */ char dmn_nm[NC_MAX_NAME]; /* [sng] Dimension name */ int fl_fmt; /* [enm] File format */ int dmn_in_id_var[NC_MAX_DIMS];/* [id] Dimension IDs array for variable */ int nco_prg_id; /* [enm] Program ID */ int dmn_id; /* [nbr] Dimension ID */ long dmn_cnt; /* [nbr] Dimensio hyperslabbed count (size) */ long dmn_sz; /* [nbr] Dimension size */ var_sct *var; /* [sct] Variable structure (output) */ dmn_trv_sct *dmn_trv; /* [sct] GTT unique dimension object */ dmn_sct *dim; /* [sct] Dimension structure */ /* Get Program ID */ nco_prg_id=nco_prg_id_get(); assert(var_trv->nco_typ == nco_obj_typ_var); /* Get file format */ (void)nco_inq_format(grp_id,&fl_fmt); /* Allocate space for variable structure */ var=(var_sct *)nco_malloc(sizeof(var_sct)); /* Set defaults for each member of variable structure */ (void)var_dfl_set(var); /* Fill-in known fields */ var->nm=(char *)strdup(var_trv->nm); var->nm_fll=(char *)strdup(var_trv->nm_fll); var->id=var_id; var->nc_id=grp_id; var->is_crd_var=var_trv->is_crd_var; /* Get type and number of dimensions and attributes for variable */ (void)nco_inq_var(var->nc_id,var->id,(char *)NULL,&var->typ_dsk,&var->nbr_dim,(int *)NULL,&var->nbr_att); if(nco_prg_id == ncks) assert(var->typ_dsk == var_trv->var_typ); assert(var->nbr_dim == var_trv->nbr_dmn); assert(var->nbr_att == var_trv->nbr_att); /* Get dimension IDs for *variable* */ (void)nco_inq_vardimid(var->nc_id,var->id,dmn_in_id_var); /* Allocate space for dimension information */ if(var->nbr_dim > 0) var->dim=(dmn_sct **)nco_malloc(var->nbr_dim*sizeof(dmn_sct *)); else var->dim=(dmn_sct **)NULL; if(var->nbr_dim > 0) var->dmn_id=(int *)nco_malloc(var->nbr_dim*sizeof(int)); else var->dmn_id=(int *)NULL; if(var->nbr_dim > 0) var->cnk_sz=(size_t *)nco_malloc(var->nbr_dim*sizeof(size_t)); else var->cnk_sz=(size_t *)NULL; if(var->nbr_dim > 0) var->cnt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->cnt=(long *)NULL; if(var->nbr_dim > 0) var->srt=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srt=(long *)NULL; if(var->nbr_dim > 0) var->end=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->end=(long *)NULL; if(var->nbr_dim > 0) var->srd=(long *)nco_malloc(var->nbr_dim*sizeof(long)); else var->srd=(long *)NULL; /* Get dimension IDs from input file */ (void)nco_inq_vardimid(var->nc_id,var->id,var->dmn_id); /* Size defaults to 1 in var_dfl_set(), and set to 1 here for extra safety */ var->sz=1L; var->sz_rec=1L; /* Uninitialized values */ var->cid=-1; var->fmt[0]='\0'; /* Loop dimensions */ for(int idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Dimension ID for variable, used to get dimension object in input list */ dmn_id=dmn_in_id_var[idx_dmn]; assert(var->dmn_id[idx_dmn] == dmn_id); /* Get unique dimension object from unique dimension ID, in input list */ dmn_trv=nco_dmn_trv_sct(dmn_id,trv_tbl); /* Get dimension name and size from ID in group */ (void)nco_inq_dim(grp_id,dmn_id,dmn_nm,&dmn_sz); assert((size_t)dmn_sz == dmn_trv->sz); assert(strcmp(dmn_nm,dmn_trv->nm) == 0); /* Get hyperslabbed count */ dmn_cnt=-1; if(var_trv->var_dmn[idx_dmn].crd){ dmn_cnt=var_trv->var_dmn[idx_dmn].crd->lmt_msa.dmn_cnt; } else if(var_trv->var_dmn[idx_dmn].ncd){ dmn_cnt=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.dmn_cnt; } var->cnt[idx_dmn]=dmn_cnt; var->end[idx_dmn]=dmn_cnt-1; var->srt[idx_dmn]=0L; var->srd[idx_dmn]=1L; var->sz*=dmn_cnt; /* This definition of "is_rec_var" says if any of the dimensions is a record then the variable is marked as so */ if(dmn_trv->is_rec_dmn){ var->is_rec_var=True; } else { var->sz_rec*=var->cnt[idx_dmn]; } /* Return a completed dmn_sct, use dimension ID and name from TRV object */ dim=nco_dmn_fll(grp_id,dmn_id,dmn_trv->nm); assert(strcmp(dim->nm,dmn_trv->nm) == 0); assert((size_t)dim->sz == dmn_trv->sz); assert(dim->id == var->dmn_id[idx_dmn]); /* Set the hyperslabbed size for this dimension */ dim->cnt=dmn_cnt; /* Set the *real* (NB: var->sz is hyperslabbed size) size for this dimension */ dim->sz=dmn_sz; /* Use info from GTT unique dimension */ dim->is_rec_dmn=dmn_trv->is_rec_dmn; /* Use info from GTT variable dimension */ dim->is_crd_dmn=var_trv->var_dmn[idx_dmn].is_crd_var; var->dim[idx_dmn]=(dmn_sct *)nco_malloc(sizeof(dmn_sct)); var->dim[idx_dmn]->nm=(char *)strdup(dim->nm); var->dim[idx_dmn]->id=dim->id; var->dim[idx_dmn]->cnk_sz=dim->cnk_sz; var->dim[idx_dmn]->srt=dim->srt; var->dim[idx_dmn]->end=dim->end; var->dim[idx_dmn]->srd=dim->srd; var->dim[idx_dmn]->cnt=dim->cnt; var->dim[idx_dmn]->sz=dmn_sz; var->dim[idx_dmn]->is_rec_dmn=dim->is_rec_dmn; var->dim[idx_dmn]->is_crd_dmn=dim->is_crd_dmn; dim->xrf=(dmn_sct *)nco_malloc(sizeof(dmn_sct)); dim->xrf->nm=(char *)strdup(dim->nm); dim->xrf->id=dim->id; dim->xrf->cnk_sz=dim->cnk_sz; dim->xrf->srt=dim->srt; dim->xrf->end=dim->end; dim->xrf->srd=dim->srd; dim->xrf->cnt=dim->cnt; dim->xrf->sz=dim->sz; dim->xrf->is_rec_dmn=dim->is_rec_dmn; dim->xrf->is_crd_dmn=dim->is_crd_dmn; var->dim[idx_dmn]->xrf=dim->xrf; } /* Loop dimensions */ /* Type in memory begins as same type as on disk */ /* Type of variable in RAM */ var->type=var->typ_dsk; /* Type of packed data on disk */ /* Type of variable when packed (on disk). This should be same as typ_dsk except in cases where variable is packed in input file and unpacked in output file. */ var->typ_pck=var->type; /* Refresh number of attributes and missing value attribute, if any */ var->has_mss_val=nco_mss_val_get(var->nc_id,var); /* Check variable for duplicate dimensions */ for(int idx_var=0;idx_varnbr_dim;idx_var++){ int idx_dmn; for(idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ if(idx_var != idx_dmn){ if(var->dmn_id[idx_var] == var->dmn_id[idx_dmn]){ /* Dimensions are duplicated when IDs for different ordinal dimensions are equal */ var->has_dpl_dmn=True; break; } /* endif IDs are equal */ } /* endif navel gazing */ } /* endif inner dimension */ /* Found a duplicate, so stop looking */ if(idx_dmn != var->nbr_dim) break; } /* Check variable for duplicate dimensions */ /* Variables associated with "bounds" and "coordinates" attributes should, in most cases, be treated as coordinates */ if(nco_is_spc_in_bnd_att(var->nc_id,var->id)) var->is_crd_var=True; if(nco_is_spc_in_crd_att(var->nc_id,var->id)) var->is_crd_var=True; /* Portions of variable structure depend on packing properties, e.g., typ_upk nco_pck_dsk_inq() fills in these portions harmlessly */ (void)nco_pck_dsk_inq(grp_id,var); /* Set deflate and chunking to defaults */ var->dfl_lvl=NCO_DFL_LVL_UNDEFINED; /* [enm] Deflate level */ var->shuffle=False; /* [flg] Turn on shuffle filter */ for(int idx=0;idxnbr_dim;idx++) var->cnk_sz[idx]=(size_t)0L; /* Read deflate levels and chunking (if any) */ if((nco_fmt_xtn_get() != nco_fmt_xtn_hdf4) && (fl_fmt == NC_FORMAT_NETCDF4 || fl_fmt == NC_FORMAT_NETCDF4_CLASSIC)){ int deflate; /* [enm] Deflate filter is on */ int srg_typ; /* [enm] Storage type */ (void)nco_inq_var_deflate(grp_id,var->id,&var->shuffle,&deflate,&var->dfl_lvl); (void)nco_inq_var_chunking(grp_id,var->id,&srg_typ,var->cnk_sz); } /* endif */ /* Get enm_prc_typ from GTT */ for(unsigned uidx=0;uidxnbr;uidx++){ if(!strcmp(var->nm_fll,trv_tbl->lst[uidx].nm_fll)){ if(trv_tbl->lst[uidx].enm_prc_typ == prc_typ){ var->is_fix_var=0; }else if(trv_tbl->lst[uidx].enm_prc_typ == fix_typ){ var->is_fix_var=1; } break; } } var->undefined=False; /* [flg] Used by ncap parser */ return var; } /* nco_var_fll_trv() */ int /* O [id] Output file variable ID */ nco_cpy_var_dfn_trv /* [fnc] Define specified variable in output file */ (const int nc_in_id, /* I [ID] netCDF input file ID */ const int nc_out_id, /* I [ID] netCDF output file ID */ const cnk_sct * const cnk, /* I [sct] Chunking structure */ const char * const grp_out_fll, /* I [sng] Output group name */ const int dfl_lvl, /* I [enm] Deflate level [0..9] */ const gpe_sct * const gpe, /* I [sct] GPE structure */ const char * const rec_dmn_nm_cst, /* I [sng] User-specified record dimension, if any, to create or fix in output file */ trv_sct *var_trv, /* I/O [sct] Object to write (variable) trv_map_dmn_set() is O */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Copy variable metadata from input netCDF file to output netCDF file Routine was based on nco_cpy_var_dfn_lmt(), and differed trivially from it Routine truncates dimensions in variable definition in output file according to user-specified limits Routine copies variable-by-variable 20130126: csz Behavior until today required rec_dmn_nm even if not changing it As of today, rec_dmn_nm passed only when user-specified Otherwise, re-use old record dimension name 20130222: csz Same routine is called with or without limits Routine works with GTT instead of plain names */ const char fnc_nm[]="nco_cpy_var_dfn_trv()"; /* [sng] Function name */ char var_nm[NC_MAX_NAME+1]; /* [sng] Variable name (local copy of object name) */ char *rec_dmn_nm=NULL; /* [sng] User-specified record dimension name */ char *rec_dmn_nm_mlc=NULL; /* [sng] Local copy of rec_dmn_nm_cst, which may be encoded */ char *grp_dmn_out_fll=NULL; /* [sng] Group name of dimension in output */ char dmn_nm[NC_MAX_NAME]; /* [sng] Dimension name */ char dmn_nm_grp[NC_MAX_NAME]; /* [sng] Dimension name for group */ int dmn_in_id_var[NC_MAX_DIMS]; /* [id] Dimension IDs array for input variable */ int dmn_out_id[NC_MAX_DIMS]; /* [id] Dimension IDs array for output variable */ int dmn_out_id_grp[NC_MAX_DIMS]; /* [id] Dimension IDs array in output group */ int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output (ncpdq) */ int dmn_out_id_tmp[NC_MAX_DIMS]; /* [idx] Copy of dmn_out_id (ncpdq) */ int rec_dmn_out_id; /* [id] Record dimension for output variable */ int var_in_id; /* [id] Variable ID */ int var_out_id; /* [id] Variable ID */ int fl_fmt; /* [enm] Output file format */ int nbr_dmn_var; /* [nbr] Number of dimensions for variable */ int nbr_dmn_var_out; /* [nbr] Number of dimensions for variable on output ( can change for ncwa) */ int rcd=NC_NOERR; /* [rcd] Return code */ int nco_prg_id; /* [enm] Program ID */ int rec_id_out; /* [id] Dimension ID for ncecat "record" dimension */ int grp_dmn_out_id; /* [id] Group ID where dimension visible to specified group is defined */ int rcd_lcl; /* [rcd] Return code */ int var_dim_id; /* [id] Variable dimension ID */ int dmn_id_out; /* [id] Dimension ID defined in outout group */ int nbr_dmn_out_grp; /* [id] Number of dimensions in group */ int grp_in_id; /* [id] Group ID */ int grp_out_id; /* [id] Group ID */ long dmn_cnt; /* [nbr] Hyperslabbed size of dimension */ long dmn_sz; /* [nbr] Size of dimension (on input) */ long dmn_sz_grp; /* [sng] Dimension size for group */ nc_type var_typ; /* [enm] netCDF type in input variable (usually same as output) */ nc_type var_typ_out; /* [enm] netCDF type in output variable (usually same as input) */ nco_bool CRR_DMN_IS_REC_IN_INPUT; /* [flg] Current dimension of variable is record dimension of variable in input file/group */ nco_bool DFN_CRR_DMN_AS_REC_IN_OUTPUT; /* [flg] Define current dimension as record dimension in output file */ nco_bool FIX_ALL_REC_DMN=False; /* [flg] Fix all record dimensions */ nco_bool FIX_REC_DMN=False; /* [flg] Fix record dimension (opposite of MK_REC_DMN) */ nco_bool NEED_TO_DEFINE_DIM; /* [flg] Dimension needs to be defined in *this* group */ nco_bool DEFINE_DIM[NC_MAX_DIMS]; /* [flg] Defined dimension (always True, except for ncwa) */ dmn_trv_sct *dmn_trv; /* [sct] Unique dimension object */ dmn_cmn_sct dmn_cmn[NC_MAX_DIMS]; /* [sct] Dimension information on output */ rec_dmn_out_id=NCO_REC_DMN_UNDEFINED; for(int idx_dmn=0;idx_dmnnm); /* Initialize output dimensions to input sizes */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ /* Dimensions exist */ if(var_trv->var_dmn){ dmn_trv=NULL; /* [sct] Unique dimension */ crd_sct *crd=NULL; /* [sct] Coordinate dimension */ dmn_cmn[idx_dmn].nm_fll=var_trv->var_dmn[idx_dmn].dmn_nm_fll; dmn_cmn[idx_dmn].id=nco_obj_typ_err; /* This dimension has a coordinate variable */ if(var_trv->var_dmn[idx_dmn].is_crd_var){ /* Get coordinate from table */ crd=var_trv->var_dmn[idx_dmn].crd; dmn_cmn[idx_dmn].sz=crd->sz; dmn_cmn[idx_dmn].is_rec_dmn=crd->is_rec_dmn; dmn_cmn[idx_dmn].BASIC_DMN=crd->lmt_msa.BASIC_DMN; dmn_cmn[idx_dmn].dmn_cnt=crd->lmt_msa.dmn_cnt; strcpy(dmn_cmn[idx_dmn].nm,crd->nm); }else{ /* Get unique dimension from table */ dmn_trv=var_trv->var_dmn[idx_dmn].ncd; dmn_cmn[idx_dmn].sz=dmn_trv->sz; dmn_cmn[idx_dmn].is_rec_dmn=dmn_trv->is_rec_dmn; dmn_cmn[idx_dmn].BASIC_DMN=dmn_trv->lmt_msa.BASIC_DMN; dmn_cmn[idx_dmn].dmn_cnt=dmn_trv->lmt_msa.dmn_cnt; strcpy(dmn_cmn[idx_dmn].nm,dmn_trv->nm); } /* This dimension has a coordinate variable */ } /* Dimensions exist */ } /* Loop over dimensions */ /* Recall: 1. Dimensions must be defined before variables 2. Variables must be defined before attributes */ /* Get output group ID */ (void)nco_inq_grp_full_ncid(nc_out_id,grp_out_fll,&grp_out_id); /* Is requested variable already in output file? */ rcd=nco_inq_varid_flg(grp_out_id,var_nm,&var_out_id); if(rcd == NC_NOERR) return var_out_id; /* Get input group ID */ (void)nco_inq_grp_full_ncid(nc_in_id,var_trv->grp_nm_fll,&grp_in_id); /* Is requested variable in input file? */ rcd=nco_inq_varid_flg(grp_in_id,var_nm,&var_in_id); if(rcd != NC_NOERR) (void)fprintf(stdout,"%s: %s reports ERROR unable to find variable \"%s\"\n",nco_prg_nm_get(),fnc_nm,var_nm); /* Get type of variable and number of dimensions from input */ (void)nco_inq_var(grp_in_id,var_in_id,(char *)NULL,&var_typ,&nbr_dmn_var,(int *)NULL,(int *)NULL); /* Get Program ID */ nco_prg_id=nco_prg_id_get(); if(nco_prg_id == ncks) assert(var_typ == var_trv->var_typ); assert(nbr_dmn_var == var_trv->nbr_dmn); nbr_dmn_var_out=nbr_dmn_var; var_typ=var_trv->var_typ; nbr_dmn_var=var_trv->nbr_dmn; /* Get dimension IDs for variable */ (void)nco_inq_vardimid(grp_in_id,var_in_id,dmn_in_id_var); if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: DEBUG %s defining variable <%s> with dimensions: ",nco_prg_nm_get(),fnc_nm,var_trv->nm_fll); for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++) (void)fprintf(stdout,"#%d<%s> : ",var_trv->var_dmn[idx_dmn].dmn_id,var_trv->var_dmn[idx_dmn].dmn_nm); (void)fprintf(stdout,"\n"); } /* endif */ /* Does user want a record dimension to receive special handling? */ if(rec_dmn_nm_cst){ /* Create (and later free()) local copy to preserve const-ness of passed value For simplicity, work with canonical name rec_dmn_nm */ rec_dmn_nm_mlc=strdup(rec_dmn_nm_cst); /* Parse rec_dmn_nm argument */ if(!strcmp("fix_all",rec_dmn_nm_mlc)){ FIX_ALL_REC_DMN=True; FIX_REC_DMN=True; rec_dmn_nm=rec_dmn_nm_mlc+4; }else if(!strncmp("fix_",rec_dmn_nm_mlc,(size_t)4)){ FIX_REC_DMN=True; /* [flg] Fix record dimension */ rec_dmn_nm=rec_dmn_nm_mlc+4; }else{ FIX_REC_DMN=False; /* [flg] Fix record dimension */ rec_dmn_nm=rec_dmn_nm_mlc; } /* strncmp() */ } /* !rec_dmn_nm_cst */ /* If variable has re-defined record dimension. NB: this implies passing NULL as user-specified record dimension parameter */ if(var_trv->rec_dmn_nm_out){ /* Must be ncpdq */ assert(nco_prg_id == ncpdq); rec_dmn_nm=(char *)strdup(var_trv->rec_dmn_nm_out); } /* endif */ /* Is requested record dimension in this group ? */ if(rec_dmn_nm){ if(nco_prg_id == ncks){ if(!FIX_ALL_REC_DMN){ int rec_dmn_id_dmy; rcd=nco_inq_dimid_flg(grp_in_id,rec_dmn_nm,&rec_dmn_id_dmy); /* Record name not found in this group */ if(rcd != NC_NOERR){ /* Nothing to do, error cheking for invalid dimension names was made at start */ } /* endif rcd != NC_NOERR */ if(rcd == NC_NOERR){ /* Does variable contain requested record dimension? */ for(int idx_dmn=0;idx_dmn\n",nco_prg_nm_get(),fnc_nm,rec_dmn_nm); (void)nco_def_dim(nc_out_id,rec_dmn_nm,NC_UNLIMITED,&rec_id_out); } /* !dimension */ } /* !ncecat */ } /* !rec_dmn_nm */ /* Loop over each dimension in variable */ for(int idx_dmn=0;idx_dmngrp_nm_fll); else grp_dmn_out_fll=(char *)strdup(dmn_trv->grp_nm_fll); } /* Test existence of group and create if not existent */ if(nco_inq_grp_full_ncid_flg(nc_out_id,grp_dmn_out_fll,&grp_dmn_out_id)) nco_def_grp_full(nc_out_id,grp_dmn_out_fll,&grp_dmn_out_id); /* Inquire if dimension defined in output using obtained group ID (return value not used in logic) */ rcd_lcl=nco_inq_dimid_flg(grp_dmn_out_id,dmn_nm,&dmn_id_out); if(nco_dbg_lvl_get() == nco_dbg_old){ if(rcd_lcl == NC_NOERR) (void)fprintf(stdout,"%s: DEBUG %s dimension is visible (by parents or group) #%d<%s>\n",nco_prg_nm_get(),fnc_nm,var_dim_id,dmn_trv->nm_fll); else (void)fprintf(stdout,"%s: DEBUG %s dimension is not visible (by parents or group) #%d<%s>\n",nco_prg_nm_get(),fnc_nm,var_dim_id,dmn_trv->nm_fll); } /* endif dbg */ /* Check output group (only) dimensions */ (void)nco_inq_dimids(grp_dmn_out_id,&nbr_dmn_out_grp,dmn_out_id_grp,0); /* Loop output group defined dimensions to check if dimension is already defined */ for(int idx_dmn_grp=0;idx_dmn_grpis_rec_dmn; if(FIX_ALL_REC_DMN){ DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; if(CRR_DMN_IS_REC_IN_INPUT && nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s is defining all input record dimensions including this one, %s, as fixed dimensions in output file per user request\n",nco_prg_nm_get(),fnc_nm,dmn_nm); }else if(rec_dmn_nm){ /* User requested (with --fix_rec_dmn or --mk_rec_dmn) to treat a certain dimension specially */ /* ... and this dimension is that dimension, i.e., the user-specified dimension ... */ if(!strcmp(dmn_nm,rec_dmn_nm)){ /* ... then honor user's request to define it as a fixed or record dimension ... */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s is defining dimension %s as %s dimension in output file per user request\n",nco_prg_nm_get(),fnc_nm,rec_dmn_nm,(FIX_REC_DMN) ? "fixed" : "record"); if(FIX_REC_DMN) DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; }else{ /* strcmp() */ if(FIX_REC_DMN){ /* ... fix_rec_dmn case is straightforward: output dimension has same format as input dimension */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; }else{ /* !FIX_REC_DMN */ /* ... otherwise we are in the --mk_rec_dmn case where things get complicated ... This dimension can be a record dimension only if it would not conflict with the requested record dimension being defined a record dimension, and that depends on file format. Uggh. 1. netCDF3 API allows only one record-dimension so conflicts are possible 2. netCDF4 API permits any number of unlimited dimensions so conflicts are impossible */ if(fl_fmt == NC_FORMAT_NETCDF4){ /* ... no conflicts possible so define dimension in output same as in input ... */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; }else{ /* !netCDF4 */ /* ... output file adheres to netCDF3 API so there can be only one record dimension. In other words, define all other dimensions as fixed, non-record dimensions, even if they are a record dimension in the input file ... */ if(CRR_DMN_IS_REC_IN_INPUT) (void)fprintf(stderr,"%s: INFO %s is defining dimension %s as fixed (non-record) in output file even though it is a record dimension in the input file. This is necessary to satisfy user request that %s be the record dimension in the output file which adheres to the netCDF3 API that permits only one record dimension.\n",nco_prg_nm_get(),fnc_nm,dmn_nm,rec_dmn_nm); DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; } /* !netCDF4 */ /* Impose special cases to limit production of excessive additional record dimensions How might excessive additional record dimensions be produced? ncpdq reorders try to preserve the "record" property of record variables ncpdq tries to define as a record dimension whichever dimension ends up first in a record variable, and, in netCDF4 files, this becomes an additional record dimension unless the original record dimension is changed to a fixed dimension (as must be done in netCDF3 files). ncecat (in record aggregate mode) defines a new leading record dimension In netCDF4 files this becomes an additional record dimension unless the original record dimension is changed to a fixed dimension (as must be done in netCDF3 files). Easier if ncpdq and ncecat do not increase number of record dimensions in a variable So NCO defaults to prevent production of additional record dimensions by ncecat, ncpdq User can override this with --mrd (multiple record dimension) switch */ /* Undefine dimension as record if current dimension (e.g., name "time") is also record */ if(nco_prg_id == ncecat || nco_prg_id == ncpdq) if(dmn_trv->is_rec_dmn && nco_mrd_cnv_get() == nco_mrd_restrict) DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; } /* !FIX_REC_DMN */ } /* strcmp() */ }else{ /* !rec_dmn_nm */ /* ... no user-specified record dimension so define dimension in output same as in input ... */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; } /* !rec_dmn_nm && !FIX_ALL_REC_DMN */ /* At long last ... */ /* Define current index dimension size */ /* If current dimension is to be defined as record dimension in output file */ if(DFN_CRR_DMN_AS_REC_IN_OUTPUT){ dmn_cnt=NC_UNLIMITED; long cnt; if(var_trv->var_dmn[idx_dmn].is_crd_var) cnt=var_trv->var_dmn[idx_dmn].crd->lmt_msa.dmn_cnt; else cnt=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.dmn_cnt; (void)nco_dmn_set_msa(var_dim_id,cnt,trv_tbl); /* Update output dimension info */ dmn_cmn[idx_dmn].is_rec_dmn=True; }else{ /* Get size from GTT */ /* Update output dimension info */ dmn_cmn[idx_dmn].is_rec_dmn=False; if(var_trv->var_dmn[idx_dmn].is_crd_var){ dmn_cnt=var_trv->var_dmn[idx_dmn].crd->lmt_msa.dmn_cnt; }else{ /* !is_crd_var */ dmn_cnt=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.dmn_cnt; } /* !is_crd_var */ /* 20140108: Converting variables with multiple record dimensions and empty input to all fixed dimensions and netCDF3 output Empty input means size is zero so dmn_cnt looks like NC_UNLIMITED, i.e., a record dimension In other words, there is no good way to "fix" a record dimension for a variable with no records/data Workaround is to arbitrarily assign such dimensions a size of 1 so they are fixed output, and still have no data This ugly hack seems to work and is only invoked in this extreme corner case so may be OK */ if(dmn_cnt == 0) dmn_cnt=1; /* Update GTT dimension */ (void)nco_dmn_set_msa(var_dim_id,dmn_cnt,trv_tbl); } /* !DFN_CRR_DMN_AS_REC_IN_OUTPUT */ /* ncwa */ if(nco_prg_id == ncwa){ nco_bool found_dim=False; /* Degenerate dimensions */ for(int idx_dmn_dgn=0;idx_dmn_dgnnbr_dmn_dgn;idx_dmn_dgn++){ /* Compare ID */ if(trv_tbl->dmn_dgn[idx_dmn_dgn].id == var_dim_id){ found_dim=True; dmn_cnt=trv_tbl->dmn_dgn[idx_dmn_dgn].cnt; /* If dimension is record keep it that way */ if(dmn_trv->is_rec_dmn) dmn_cnt=NC_UNLIMITED; break; } /* Compare ID */ } /* !Degenerate */ if(var_trv->var_dmn[idx_dmn].flg_rdd){ found_dim=True; /* If dimension was to be record keep it that way, otherwise define degenerate size of 1 */ if(DFN_CRR_DMN_AS_REC_IN_OUTPUT) dmn_cnt=NC_UNLIMITED; else dmn_cnt=1; } if(!found_dim){ DEFINE_DIM[idx_dmn]=False; nbr_dmn_var_out--; } /* found_dim */ } /* ncwa */ /* Always define, except maybe for ncwa */ if(DEFINE_DIM[idx_dmn]){ /* Define dimension and obtain dimension ID */ (void)nco_def_dim(grp_dmn_out_id,dmn_nm,dmn_cnt,&dmn_id_out); /* Redefine output dimension array for this dimension */ (void)nco_dfn_dmn(dmn_nm,dmn_cnt,dmn_id_out,dmn_cmn,var_trv->nbr_dmn); /* Assign defined ID to dimension ID array for the variable */ dmn_out_id[idx_dmn]=dmn_id_out; } /* !DEFINE_DIM */ /* Memory management after defining current output dimension */ if(grp_dmn_out_fll) grp_dmn_out_fll=(char *)nco_free(grp_dmn_out_fll); } /* end if dimension is not yet defined */ /* Die informatively if record dimension is not first dimension in netCDF3 output */ if(idx_dmn > 0 && dmn_out_id[idx_dmn] == rec_dmn_out_id && fl_fmt != NC_FORMAT_NETCDF4 && DEFINE_DIM[idx_dmn]){ (void)fprintf(stdout,"%s: ERROR User defined the output record dimension to be \"%s\". Yet in the variable \"%s\" this is dimension number %d. The output file adheres to the netCDF3 API which only supports the record dimension as the first (i.e., least rapidly varying) dimension. Consider using ncpdq to permute the location of the record dimension in the output file.\n",nco_prg_nm_get(),rec_dmn_nm,var_nm,idx_dmn+1); nco_exit(EXIT_FAILURE); } /* end if err */ } /* End of the very important dimension loop */ /* If variable needs dimension re-ordering */ if(var_trv->flg_rdr){ /* Must be ncpdq */ assert(nco_prg_id == ncpdq); for(int dmn_out_idx=0;dmn_out_idxdmn_idx_out_in[dmn_out_idx]]=dmn_out_idx; for(int dmn_out_idx=0;dmn_out_idxrdr */ if(nco_prg_id == ncecat && rec_dmn_nm && var_trv->enm_prc_typ == prc_typ){ /* Insert extra "record" dimension in dimension array if... ...is ncecat and ...user requested (with --fix_rec_dmn or --mk_rec_dmn) to treat a certain dimension specially and ...variable is processing type */ /* Temporary store for old IDs */ int dmn_tmp_id[NC_MAX_DIMS]; for(int idx_dmn=0;idx_dmnvar_typ_out != (nc_type)err_typ) var_typ_out=var_trv->var_typ_out; else var_typ_out=var_typ; }else if(nco_prg_id != ncbo){ int var_id; /* [id] Variable ID */ var_sct *var_prc; /* [sct] Variable to process */ /* Get variable ID */ (void)nco_inq_varid(grp_in_id,var_trv->nm,&var_id); /* Allocate variable structure and fill with metadata */ var_prc=nco_var_fll_trv(grp_in_id,var_id,var_trv,trv_tbl); /* Obtain netCDF type to define variable from NCO program ID */ var_typ_out=nco_get_typ(var_prc); var_prc=(var_sct *)nco_var_free(var_prc); } /* !(ncflint || ncpdq) */ /* Special case for ncwa */ if(nco_prg_id == ncwa){ int dmn_ids_out[NC_MAX_DIMS]; /* [id] Dimension IDs array for output variable (ncwa can skip some dimensions, rearrange) */ int idx_dmn_def=0; for(int idx_dmn=0;idx_dmn 0){ int deflate; /* [flg] Turn on deflate filter */ int dfl_lvl_in; /* [enm] Deflate level [0..9] */ int shuffle; /* [flg] Turn on shuffle filter */ rcd=nco_inq_var_deflate(grp_in_id,var_in_id,&shuffle,&deflate,&dfl_lvl_in); /* Copy original deflation settings */ if(deflate || shuffle) (void)nco_def_var_deflate(grp_out_id,var_out_id,shuffle,deflate,dfl_lvl_in); /* Overwrite HDF Lempel-Ziv compression level, if requested */ if(dfl_lvl == 0) deflate=(int)False; else deflate=(int)True; /* Turn-off shuffle when uncompressing otherwise chunking requests may fail */ if(dfl_lvl == 0) shuffle=(int)False; if(dfl_lvl >= 0) (void)nco_def_var_deflate(grp_out_id,var_out_id,shuffle,deflate,dfl_lvl); } /* endif */ /* Chunking routine called only when user explicitly sets a chunking option */ if(cnk && cnk->flg_usr_rqs){ /* Define extra dimension on output (e.g., ncecat adds "record" dimension) */ if(nco_prg_id == ncecat && rec_dmn_nm && var_trv->enm_prc_typ == prc_typ){ /* Temporary store for old dimensions */ dmn_cmn_sct dmn_cmn_tmp[NC_MAX_DIMS]; for(int idx_dmn=0;idx_dmngrp_nm_fll,rec_dmn_nm); /* Move up to make room for inserted dimension at 0 index */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ if(DEFINE_DIM[idx_dmn]){ /* Redefine the array */ dmn_cmn[idx_dmn_def]=dmn_cmn[idx_dmn]; idx_dmn_def++; } /* DEFINE_DIM[idx_dmn]) */ } /* Loop dimensions */ } /* !ncwa */ /* Special case for ncpdq */ if(nco_prg_id == ncpdq && nbr_dmn_var > 1){ int var_id_out; /* [id] Variable ID */ int var_dmn_nbr; /* [nbr] Number of dimensions */ int var_dimid[NC_MAX_VAR_DIMS]; /* [lst] Dimension IDs */ (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_id_out); (void)nco_inq_var(grp_out_id,var_id_out,var_nm,&var_typ,&var_dmn_nbr,var_dimid,NULL); /* Sanity check */ assert(nbr_dmn_var == var_trv->nbr_dmn); assert(nbr_dmn_var == var_dmn_nbr); /* Loop dimensions */ for(int idx_dmn=0;idx_dmnnm,dmn_cmn); if(nco_prg_id == ncecat && rec_dmn_nm && var_trv->enm_prc_typ == prc_typ) dmn_cmn[0].nm_fll=(char *)nco_free(dmn_cmn[0].nm_fll); } /* !flg_usr_rqs */ } /* !NC_FORMAT_NETCDF4 */ /* Free locally allocated space */ if(rec_dmn_nm_mlc) rec_dmn_nm_mlc=(char *)nco_free(rec_dmn_nm_mlc); return var_out_id; } /* end nco_cpy_var_dfn_trv() */ void nco_dmn_swap /* [fnc] Swap dimensions */ (const char * const dmn_nm_1, /* I [sng] Name of dimension 1 */ const char * const dmn_nm_2, /* I [sng] Name of dimension 2 */ dmn_cmn_sct *dmn_cmn, /* I/O [sct] Dimension structure array */ const int nbr_dmn) /* I [nbr] Number of dimensions (size of above array) */ { dmn_cmn_sct dmn_cmn_tmp; int dmn_nm_1_idx; int dmn_nm_2_idx; /* Loop dimensions */ for(int idx_dmn=0;idx_dmninput, output of nco_var_dmn_rdr_mtd() */ const int nbr_var_prc, /* I [nbr] Size of above array (number of processed variables) */ var_sct **var_prc_out, /* I [sct] Processed variables */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Transfer dimension structures to be re-ordered (ncpdq) into GTT */ assert(nco_prg_id_get() == ncpdq); /* Loop processed variables */ for(int idx_var_prc=0;idx_var_prcnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* If GTT variable object is to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Match by full variable name */ if(!strcmp(var_prc_out[idx_var_prc]->nm_fll,var_trv.nm_fll)){ /* Mark re-order flag */ trv_tbl->lst[idx_var].flg_rdr=True; assert(var_trv.nbr_dmn==var_prc_out[idx_var_prc]->nbr_dim); /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnlst[idx_var].dmn_idx_out_in[idx_var_dmn]=dmn_idx_out_in[idx_var_prc][idx_var_dmn]; } /* Loop variable dimensions */ } /* Match by full variable name */ } /* If GTT variable object is to extract */ } /* Loop table */ } /* Loop processed variables */ return; } /* end nco_dmn_rdr_trv() */ void nco_var_dmn_rdr_mtd_trv /* [fnc] Determine and set new dimensionality in metadata of each re-ordered variable (ncpdq) */ (trv_tbl_sct * const trv_tbl, /* I/O [sct] GTT (Group Traversal Table) */ const int nbr_var_prc, /* I [nbr] Number of processed variables */ var_sct **var_prc, /* I/O [sct] Processed variables */ var_sct **var_prc_out, /* I/O [sct] Processed variables */ const int nbr_var_fix, /* I [nbr] Number of processed variables */ var_sct **var_fix, /* I/O [sct] Fixed variables */ dmn_sct **dmn_rdr, /* I [sct] Dimension structures to be re-ordered */ const int dmn_rdr_nbr, /* I [nbr] Number of dimension to re-order */ const nco_bool *dmn_rvr_rdr) /* I [flg] Reverse dimension */ { /* Purpose: Determine and set new dimensionality in metadata of each re-ordered variable */ /* Based in nco_var_dmn_rdr_mtd(). LIMITATION: the first record dimension for the object variable is used */ /* Test case : ncpdq -O -a lev,time -v two_dmn_rec_var in.nc out.nc */ /* Mark lev as record and un-mark time as record (by setting the record name as lev) */ char *rec_dmn_nm_out_crr; /* [sng] Name of record dimension, if any, required by re-order */ char *rec_dmn_nm_in; /* [sng] Record dimension name, original */ char *rec_dmn_nm_out; /* [sng] Record dimension name, re-ordered */ int dmn_idx_out_in[NC_MAX_DIMS]; /* [idx] Dimension correspondence, output->input (Stored in GTT ) */ int nco_prg_id; /* [enm] Program ID */ nco_bool REDEFINED_RECORD_DIMENSION; /* [flg] Re-defined record dimension */ nco_bool dmn_rvr_in[NC_MAX_DIMS]; /* [flg] Reverse dimension (Stored in GTT ) */ nm_tbl_sct *rec_dmn_nm; /* [sct] Record dimension names array */ /* Get Program ID */ nco_prg_id=nco_prg_id_get(); assert(nco_prg_id == ncpdq); /* Loop processed variables */ for(int idx_var_prc=0;idx_var_prcnm_fll,trv_tbl); assert(var_trv->flg_xtr); assert(var_trv->nbr_dmn == var_prc_out[idx_var_prc]->nbr_dim); /* Initialize for this variable */ REDEFINED_RECORD_DIMENSION=False; /* Mark re-order flag */ var_trv->flg_rdr=True; /* Initialize record names for this object */ rec_dmn_nm=NULL; rec_dmn_nm_out_crr=NULL; rec_dmn_nm_in=NULL; rec_dmn_nm_out=NULL; /* Get array of record names for object */ (void)nco_get_rec_dmn_nm(var_trv,trv_tbl,&rec_dmn_nm); /* Use for record dimension name the first in array */ if(rec_dmn_nm && rec_dmn_nm->lst){ rec_dmn_nm_in=(char *)strdup(rec_dmn_nm->lst[0].nm); rec_dmn_nm_out=(char *)strdup(rec_dmn_nm->lst[0].nm); } /* !rec_dmn_nm->lst */ /* nco_var_dmn_rdr_mtd() does re-order heavy lifting */ rec_dmn_nm_out_crr=nco_var_dmn_rdr_mtd(var_prc[idx_var_prc],var_prc_out[idx_var_prc],dmn_rdr,dmn_rdr_nbr,dmn_idx_out_in,dmn_rvr_rdr,dmn_rvr_in); var_trv->dmn_idx_out_in=(int *)nco_malloc(var_trv->nbr_dmn*sizeof(int)); var_trv->dmn_rvr_in=(nco_bool *)nco_malloc(var_trv->nbr_dmn*sizeof(nco_bool)); /* Transfer dimension structures to be re-ordered into GTT */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ var_trv->dmn_idx_out_in[idx_dmn]=dmn_idx_out_in[idx_dmn]; var_trv->dmn_rvr_in[idx_dmn]=dmn_rvr_in[idx_dmn]; } /* end loop over dimensions */ /* If record dimension required by current variable re-order... ...and variable is multi-dimensional (one dimensional arrays cannot request record dimension changes)... */ if(rec_dmn_nm_in && rec_dmn_nm_out_crr && var_prc_out[idx_var_prc]->nbr_dim > 1){ /* ...differs from input and current output record dimension(s)... */ if(strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_in) && strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_out)){ /* ...and current output record dimension already differs from input record dimension... */ if(REDEFINED_RECORD_DIMENSION){ /* ...then requested re-order requires multiple record dimensions... */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: WARNING Re-order requests multiple record dimensions\n. Only first request will be honored (netCDF3 allows only one record dimension). Record dimensions involved [original,first change request (honored),latest change request (made by variable %s)]=[%s,%s,%s]\n",nco_prg_nm_get(),var_prc[idx_var_prc]->nm,rec_dmn_nm_in,rec_dmn_nm_out,rec_dmn_nm_out_crr); break; }else{ /* !REDEFINED_RECORD_DIMENSION */ /* ...otherwise, update output record dimension name... */ rec_dmn_nm_out=rec_dmn_nm_out_crr; /* ...and set new dimensions... */ var_prc_out[idx_var_prc]->dim[0]->is_rec_dmn=True; /* ...and set flag that record dimension has been re-defined... */ REDEFINED_RECORD_DIMENSION=True; /* ...store the name of the record dimension on output... */ var_trv->rec_dmn_nm_out=(char *)strdup(rec_dmn_nm_out); } /* !REDEFINED_RECORD_DIMENSION */ } /* endif new and old record dimensions differ */ } /* endif current variable is record variable */ /* Memory management for record dimension names */ if(rec_dmn_nm){ for(int idx=0;idxnbr;idx++) rec_dmn_nm->lst[idx].nm=(char *)nco_free(rec_dmn_nm->lst[idx].nm); rec_dmn_nm=(nm_tbl_sct *)nco_free(rec_dmn_nm); } /* !rec_dmn_nm */ if(rec_dmn_nm_in)rec_dmn_nm_in=(char *)nco_free(rec_dmn_nm_in); if(rec_dmn_nm_out)rec_dmn_nm_out=(char *)nco_free(rec_dmn_nm_out); } /* Loop processed variables */ /* Loop to deal with REDEFINED_RECORD_DIMENSION */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Changing record dimension may invalidate is_rec_var flag Updating is_rec_var flag to correct value, even if value is ignored, helps keep user appraised of unexpected dimension re-orders. is_rec_var may change both for "fixed" and "processed" variables When is_rec_var changes for processed variables, may also need to change ancillary information and to check for duplicate dimensions. Ancillary information (dmn_idx_out_in) is available only for var_prc! Hence must update is_rec_var flag for var_fix and var_prc separately */ /* Update is_rec_var flag for var_fix */ for(int idx_var_fix=0;idx_var_fixnm_fll,var_trv.nm_fll) == 0){ /* ...get the name of the record dimension on output... stored to GTT in first loop above */ rec_dmn_nm_out=trv_tbl->lst[idx_var].rec_dmn_nm_out; int dmn_out_idx; /* Search all dimensions in variable for new record dimension */ for(dmn_out_idx=0;dmn_out_idxnbr_dim;dmn_out_idx++){ if(rec_dmn_nm_out && !strcmp(var_fix[idx_var_fix]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)){ break; } } /* ...Will variable be record variable in output file?... */ if(dmn_out_idx == var_fix[idx_var_fix]->nbr_dim){ /* ...No. Variable will be non-record---does this change its status?... */ if(nco_dbg_lvl_get() >= nco_dbg_var){ if(var_fix[idx_var_fix]->is_rec_var) (void)fprintf(stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n", nco_prg_nm_get(),var_fix[idx_var_fix]->nm); } /* Assign record flag dictated by re-order */ var_fix[idx_var_fix]->is_rec_var=False; }else{ /* ...otherwise variable will be record variable... */ /* ...Yes. Variable will be record... */ /* ...Will becoming record variable change its status?... */ if(!var_fix[idx_var_fix]->is_rec_var){ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n", nco_prg_nm_get(),var_fix[idx_var_fix]->nm); /* Change record flag to status dictated by re-order */ var_fix[idx_var_fix]->is_rec_var=True; } /* endif status changing from non-record to record */ } /* endif variable will be record variable */ } /* Match by full variable name */ } /* end loop over var_fix */ } /* Loop table */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Update is_rec_var flag for var_prc */ for(int idx_var_prc=0;idx_var_prcnm_fll,var_trv.nm_fll) == 0){ /* ...get the name of the record dimension on output... stored to GTT in first loop above */ rec_dmn_nm_out=trv_tbl->lst[idx_var].rec_dmn_nm_out; /* Loop table, search for other variables that share the same dimension name */ for(unsigned idx_var_mrk=0;idx_var_mrknbr;idx_var_mrk++){ /* Looking for this variable */ trv_sct var_trv_mrk=trv_tbl->lst[idx_var_mrk]; /* Avoid same variable ... ...look if there is a record name to find ...and look for variables only ...and look for extracted variables only ...and look for variables with dimensions > 1 */ if(rec_dmn_nm_out && strcmp(var_trv.nm_fll,var_trv_mrk.nm_fll) != 0 && var_trv_mrk.nco_typ == nco_obj_typ_var && var_trv_mrk.flg_xtr && var_trv_mrk.nbr_dmn > 1){ nco_bool NEEDS_REORDER; /* [flg] Variable needs re-ordering */ int idx_var_prc_out; /* [nbr] Index of variable that needs re-ordering */ NEEDS_REORDER=False; /* Loop dimensions of to search variable */ for(int idx_dmn=0;idx_dmnnbr_dim;dmn_out_idx++){ if(!strcmp(var_prc_out[idx_var_prc_out]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)){ break; } } /* ...Will variable be record variable in output file?... */ if(dmn_out_idx == var_prc_out[idx_var_prc_out]->nbr_dim){ /* ...No. Variable will be non-record---does this change its status?... */ if(nco_dbg_lvl_get() >= nco_dbg_var){ if(var_prc_out[idx_var_prc_out]->is_rec_var) (void)fprintf(stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n", nco_prg_nm_get(),var_prc_out[idx_var_prc_out]->nm); } /* Assign record flag dictated by re-order */ var_prc_out[idx_var_prc_out]->is_rec_var=False; }else{ /* ...otherwise variable will be record variable... */ /* ...Yes. Variable will be record... */ /* ...must ensure new record dimension is not duplicate dimension... */ if(var_prc_out[idx_var_prc_out]->has_dpl_dmn){ int dmn_dpl_idx; for(dmn_dpl_idx=1;dmn_dpl_idxnbr_dim;dmn_dpl_idx++){ /* NB: loop starts from 1 */ if(var_prc_out[idx_var_prc_out]->dmn_id[0] == var_prc_out[idx_var_prc_out]->dmn_id[dmn_dpl_idx]){ (void)fprintf(stdout,"%s: ERROR Requested re-order turns duplicate non-record dimension %s in variable %s into output record dimension. netCDF does not support duplicate record dimensions in a single variable.\n%s: HINT: Exclude variable %s from extraction list with \"-x -v %s\".\n", nco_prg_nm_get(),rec_dmn_nm_out,var_prc_out[idx_var_prc_out]->nm,nco_prg_nm_get(),var_prc_out[idx_var_prc_out]->nm,var_prc_out[idx_var_prc_out]->nm); nco_exit(EXIT_FAILURE); } /* endif err */ } /* end loop over dmn_out */ } /* endif has_dpl_dmn */ /* ...Will becoming record variable change its status?... */ if(!var_prc_out[idx_var_prc_out]->is_rec_var){ if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n", nco_prg_nm_get(),var_prc_out[idx_var_prc_out]->nm); /* Change record flag to status dictated by re-order */ var_prc_out[idx_var_prc_out]->is_rec_var=True; /* ...Swap dimension information for multi-dimensional variables... */ if(var_prc_out[idx_var_prc_out]->nbr_dim > 1){ /* Swap dimension information when turning multi-dimensional non-record variable into record variable. Single dimensional non-record variables that turn into record variables already have correct dimension information */ dmn_sct *dmn_swp; /* [sct] Dimension structure for swapping */ int dmn_idx_rec_in; /* [idx] Record dimension index in input variable */ int dmn_idx_rec_out; /* [idx] Record dimension index in output variable */ int dmn_idx_swp; /* [idx] Dimension index for swapping */ /* If necessary, swap new record dimension to first position */ /* Label indices with standard names */ dmn_idx_rec_in=dmn_out_idx; dmn_idx_rec_out=0; /* Swap indices in map */ dmn_idx_swp=dmn_idx_out_in[dmn_idx_rec_out]; dmn_idx_out_in[dmn_idx_rec_out]=dmn_idx_rec_in; dmn_idx_out_in[dmn_idx_rec_in]=dmn_idx_swp; /* Transfer dimension structures (re-ordered again) into GTT */ for(int idx_dmn=0;idx_dmnlst[ idx_var_mrk ].dmn_idx_out_in[idx_dmn]=dmn_idx_out_in[idx_dmn]; } /* Swap dimensions in list */ dmn_swp=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]; var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]; var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]=dmn_swp; /* NB: Change dmn_id,cnt,srt,end,srd together to minimize chances of forgetting one */ /* Correct output variable structure copy of output record dimension information */ var_prc_out[idx_var_prc_out]->dmn_id[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]->id; var_prc_out[idx_var_prc_out]->cnt[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]->cnt; var_prc_out[idx_var_prc_out]->srt[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]->srt; var_prc_out[idx_var_prc_out]->end[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]->end; var_prc_out[idx_var_prc_out]->srd[dmn_idx_rec_out]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_out]->srd; /* Correct output variable structure copy of input record dimension information */ var_prc_out[idx_var_prc_out]->dmn_id[dmn_idx_rec_in]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]->id; var_prc_out[idx_var_prc_out]->cnt[dmn_idx_rec_in]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]->cnt; var_prc_out[idx_var_prc_out]->srt[dmn_idx_rec_in]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]->srt; var_prc_out[idx_var_prc_out]->end[dmn_idx_rec_in]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]->end; var_prc_out[idx_var_prc_out]->srd[dmn_idx_rec_in]=var_prc_out[idx_var_prc_out]->dim[dmn_idx_rec_in]->srd; } /* endif multi-dimensional */ } /* endif status changing from non-record to record */ } /* endif variable will be record variable */ } /* Loop table, search for other variables that share the same dimension name */ } /* NEEDS_REORDER */ } /* ...look if there is a record name to find */ } /* Match by full variable name */ } /* end loop over var_prc */ } /* Loop table */ /* Final step: search for all redefined record dimension variables and mark other variables */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Has re-defined record dimension */ if(var_trv.rec_dmn_nm_out){ rec_dmn_nm_out=trv_tbl->lst[idx_var].rec_dmn_nm_out; /* Loop table, search for other variables that share the same dimension name */ for(unsigned idx_var_mrk=0;idx_var_mrknbr;idx_var_mrk++){ /* Looking for this variable */ trv_sct var_trv_mrk=trv_tbl->lst[idx_var_mrk]; /* Avoid same variable ... ...and look for variables only ...and look for extracted variables only */ if(strcmp(var_trv.nm_fll,var_trv_mrk.nm_fll) != 0 && var_trv_mrk.nco_typ == nco_obj_typ_var && var_trv_mrk.flg_xtr){ /* Loop dimensions of to search variable */ for(int idx_dmn=0;idx_dmnlst[idx_var_mrk].rec_dmn_nm_out=(char *)strdup(rec_dmn_nm_out); } /* Match name */ /* Get unique dimension object from unique dimension ID, in input list */ dmn_trv=nco_dmn_trv_sct(var_trv_mrk.var_dmn[idx_dmn].dmn_id,trv_tbl); /* Is record ? */ if(dmn_trv->is_rec_dmn){ /* ...store the name of the record dimension on output... */ trv_tbl->lst[idx_var_mrk].rec_dmn_nm_out=(char *)strdup(rec_dmn_nm_out); } /* Is record ? */ } /* Loop variable dimensions */ } /* Avoid same */ } /* Loop table */ } /* Has re-defined record dimension */ } /* Loop table */ return; } /* nco_var_dmn_rdr_mtd_trv() */ nco_bool /* [flg] Name was found */ nco_var_prc_idx_trv /* [fnc] Find index of processed variable that matches full name */ (const char * const var_nm_fll, /* I [nbr] Full name of variable */ var_sct **var_prc_out, /* I [sct] Processed variables */ const int nbr_var_prc, /* I [nbr] Number of processed variables */ int * idx_var_prc_out) /* O [nbr] Number of dimension to re-order */ { /* Loop processed variables */ for(int idx_var_prc=0;idx_var_prcnm_fll,var_nm_fll) == 0){ *idx_var_prc_out=idx_var_prc; return True; } /* Match by full variable name */ } /* Loop processed variables */ assert(0); return False; } /* nco_var_prc_idx_trv() */ nco_bool /* O [flg] Re-define dimension ordering */ nco_rdf_dmn_trv /* [fnc] Re-define dimension ordering */ (trv_sct var_trv, /* I [sct] varible with record dimension name, re-ordered */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ int * idx_var_mrk_out) /* O [nbr] Index in GTT where name was found */ { if(var_trv.rec_dmn_nm_out == NULL) return False; /* Loop table, search for other variables that share the same dimension name */ for(unsigned idx_var_mrk=0;idx_var_mrknbr;idx_var_mrk++){ /* Looking for this variable */ trv_sct var_trv_mrk=trv_tbl->lst[idx_var_mrk]; /* Avoid same variable ... ...and look for variables only ...and look for extracted variables only ...and look for variables with dimensions > 1 */ if(strcmp(var_trv.nm_fll,var_trv_mrk.nm_fll) != 0 && var_trv_mrk.nco_typ == nco_obj_typ_var && var_trv_mrk.flg_xtr && var_trv_mrk.nbr_dmn > 1){ /* Loop dimensions of to search variable */ for(int idx_dmn=0;idx_dmninput (Stored in GTT ) */ nco_bool dmn_rvr_in[NC_MAX_DIMS];/* [flg] Reverse dimension (Stored in GTT ) */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Match by full variable name */ if(strcmp(var_out->nm_fll,var_trv.nm_fll) == 0){ assert(var_trv.nco_typ == nco_obj_typ_var); assert(var_trv.flg_xtr); assert(var_trv.nbr_dmn==var_out->nbr_dim); /* Transfer dimension structures to be re-ordered *from* GTT */ /* Loop variable dimensions */ for(int idx_dmn=0;idx_dmnlst[idx_var].dmn_idx_out_in[idx_dmn]; dmn_rvr_in[idx_dmn]=trv_tbl->lst[idx_var].dmn_rvr_in[idx_dmn]; } /* Loop variable dimensions */ /* Initialize variables to reduce indirection */ /* NB: Number of input and output dimensions are equal for pure re-orders However, keep dimension numbers in separate variables to ease relax this rule in future */ dmn_in_nbr=var_in->nbr_dim; dmn_out_nbr=var_out->nbr_dim; /* On entry to this section of code, we assume: 1. var_out metadata are re-ordered 2. var_out->val buffer has been allocated (calling routine must do this) */ /* Get ready to re-order */ /* dmn_id_out=var_out->dmn_id; */ /* dmn_in=var_in->dim; */ dmn_in_nbr_m1=dmn_in_nbr-1; dmn_out=var_out->dim; typ_sz=nco_typ_lng(var_out->type); val_in_cp=(char *)var_in->val.vp; val_out_cp=(char *)var_out->val.vp; var_in_cnt=var_in->cnt; var_sz=var_in->sz; /* As explained in nco_var_dmn_rdr_mtd(), "Hence, we must re-update dmn_out->id after nco_dmn_dfn() in nco_cnf_dmn_rdr_val() Structures should be completely consistent at that point Not updating these structures (at least dmn_out->id) is equivalent to assuming that dmn_out->id does not depend on record dimension identity, which is an ASSUMPTION that may currently be true, but is not guaranteed by the netCDF API to always be true." */ for(dmn_out_idx=0;dmn_out_idxdmn_id[dmn_out_idx]=dmn_out[dmn_out_idx]->id; var_out->cnt[dmn_out_idx]=dmn_out[dmn_out_idx]->cnt; var_out->srt[dmn_out_idx]=dmn_out[dmn_out_idx]->srt; var_out->end[dmn_out_idx]=dmn_out[dmn_out_idx]->end; var_out->srd[dmn_out_idx]=dmn_out[dmn_out_idx]->srd; } /* end loop over dmn_out */ /* Report full metadata re-order, if requested */ if(nco_dbg_lvl_get() > 3){ int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output */ /* Create reverse correspondence */ for(dmn_out_idx=0;dmn_out_idxnm,var_in->dim[dmn_in_idx]->nm,dmn_in_idx,var_in->dmn_id[dmn_in_idx],dmn_idx_in_out[dmn_in_idx],var_out->dmn_id[dmn_idx_in_out[dmn_in_idx]]); } /* endif dbg */ /* Is identity re-ordering requested? */ for(dmn_out_idx=0;dmn_out_idx= nco_dbg_scl) (void)fprintf(stdout,"%s: INFO %s reports re-order is identity transformation for variable %s\n",nco_prg_nm_get(),fnc_nm,var_in->nm); /* Copy in one fell swoop then return */ (void)memcpy((void *)(var_out->val.vp),(void *)(var_in->val.vp),var_out->sz*nco_typ_lng(var_out->type)); return; } /* !IDENTITY_REORDER */ if(var_in->has_dpl_dmn) (void)fprintf(stdout,"%s: WARNING %s reports non-identity re-order for variable with duplicate dimensions %s.\n%s does not support non-identity re-orders of variables with duplicate dimensions\n",nco_prg_nm_get(),fnc_nm,var_in->nm,nco_prg_nm_get()); /* Compute map for each dimension of input variable */ for(dmn_in_idx=0;dmn_in_idxcnt[dmn_idx]; /* Compute map for each dimension of output variable */ for(dmn_out_idx=0;dmn_out_idxcnt[dmn_idx]; /* There is more than one method to re-order dimensions Output dimensionality is known in advance, unlike nco_var_avg() Hence outer loop may be over dimensions or over elements Method 1: Loop over input elements 1a. Loop over 1-D input array offsets 1b. Invert 1-D input array offset to get N-D input subscripts 1c. Turn N-D input subscripts into N-D output subscripts 1d. Map N-D output subscripts to get 1-D output element 1e. Copy input element to output element This method is simplified from method used in nco_var_avg() Method 2: Loop over input dimensions 1a. Loop over input dimensions, from slowest to fastest varying 1b. */ /* Begin Method 1: Loop over input elements */ /* var_in_lmn is offset into 1-D array */ for(var_in_lmn=0;var_in_lmnnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* Filter variables */ if(var_trv.nco_typ == nco_obj_typ_var){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Edit attribute */ (void)nco_aed_prc(grp_id,var_id,aed_lst[idx_aed]); } /* Filter variables */ } /* Loop table */ } /* End Variable name is blank so edit same attribute for all variables ... */ /* Variable name contains a "regular expression" (rx) ... */ else if(strpbrk(aed_lst[idx_aed].var_nm,".*^$\\[]()<>+?|{}")){ /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* Filter variables */ if(var_trv.nco_typ == nco_obj_typ_var ){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Edit attribute */ (void)nco_aed_prc(grp_id,var_id,aed_lst[idx_aed]); } /* Filter variables */ } /* Loop table */ /* End Variable name contains a "regular expression" (rx) ... */ /* Variable name indicates a global attribute ... */ }else if(!strcasecmp(aed_lst[idx_aed].var_nm,"global")){ /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* Filter variables */ if(var_trv.nco_typ == nco_obj_typ_var && strcmp(aed_lst[idx_aed].var_nm,var_trv.nm) == 0){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Edit attribute */ (void)nco_aed_prc(grp_id,NC_GLOBAL,aed_lst[idx_aed]); } /* Filter variables */ } /* Loop table */ /* End Variable name indicates a global attribute ... */ }else{ /* Variable is a normal variable ... */ /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* Filter variables */ if(var_trv.nco_typ == nco_obj_typ_var && strcmp(aed_lst[idx_aed].var_nm,var_trv.nm) == 0){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Obtain variable ID using group ID */ (void)nco_inq_varid(grp_id,var_trv.nm,&var_id); /* Edit attribute */ (void)nco_aed_prc(grp_id,var_id,aed_lst[idx_aed]); } /* Filter variables */ } /* Loop table */ } /* End Variable is a normal variable ... */ } /* Loop all attribure structure entries */ } /* nco_aed_prc_trv() */ void nco_dmn_trv_msa_tbl /* [fnc] Update all GTT dimensions with hyperslabbed size */ (const int nc_id, /* I [ID] netCDF input file ID */ const char * const rec_dmn_nm, /* I [sng] Record dimension name */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { int grp_id; /* Loop table */ for(unsigned uidx=0;uidxnbr;uidx++){ trv_sct var_trv=trv_tbl->lst[uidx]; /* If object is an extracted variable... */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* Update for this variable */ (void)nco_dmn_msa_tbl(grp_id,rec_dmn_nm,&var_trv,trv_tbl); } /* If object is an extracted variable... */ } /* Loop table */ } /* end nco_dmn_trv_msa_tbl() */ void nco_dmn_msa_tbl /* [fnc] Update all GTT dimensions with hyperslabbed size */ (const int grp_in_id, /* I [id] netCDF input group ID */ const char * const rec_dmn_nm_cst, /* I [sng] User-specified record dimension, if any, to create or fix in output file */ trv_sct *var_trv, /* I/O [sct] Object to write (variable) trv_map_dmn_set() is O */ trv_tbl_sct * const trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { /* Purpose: Update all GTT dimensions with hyperslabbed size */ const char fnc_nm[]="nco_dmn_msa_tbl()"; /* [sng] Function name */ char var_nm[NC_MAX_NAME+1]; /* [sng] Variable name (local copy of object name) */ char *rec_dmn_nm=NULL; /* [sng] User-specified record dimension name */ char *rec_dmn_nm_mlc=NULL; /* [sng] Local copy of rec_dmn_nm_cst, which may be encoded */ char dmn_nm[NC_MAX_NAME]; /* [sng] Dimension names */ int dmn_in_id_var[NC_MAX_DIMS]; /* [id] Dimension IDs array for input variable */ int var_in_id; /* [id] Variable ID */ int fl_fmt; /* [enm] Output file format */ int nbr_dmn_var; /* [nbr] Number of dimensions for variable */ int rcd=NC_NOERR; /* [rcd] Return code */ int nco_prg_id; /* [enm] Program ID */ int var_dim_id; /* [id] Variable dimension ID */ long dmn_cnt; /* [sng] Hyperslabbed dimension size */ long dmn_sz; /* [sng] Dimension size */ nc_type var_typ; /* [enm] netCDF type in input variable (usually same as output) */ nco_bool CRR_DMN_IS_REC_IN_INPUT; /* [flg] Current dimension of variable is record dimension of variable in input file/group */ nco_bool DFN_CRR_DMN_AS_REC_IN_OUTPUT; /* [flg] Define current dimension as record dimension in output file */ nco_bool FIX_ALL_REC_DMN=False; /* [flg] Fix all record dimensions */ nco_bool FIX_REC_DMN=False; /* [flg] Fix record dimension (opposite of MK_REC_DMN) */ nco_bool NEED_TO_DEFINE_DIM; /* [flg] Dimension needs to be defined in *this* group */ dmn_trv_sct *dmn_trv; /* [sct] Unique dimension object */ /* File format needed for decision tree and to enable netCDF4 features */ (void)nco_inq_format(grp_in_id,&fl_fmt); /* Local copy of object name */ strcpy(var_nm,var_trv->nm); /* Is requested variable in input file? */ rcd=nco_inq_varid_flg(grp_in_id,var_nm,&var_in_id); if(rcd != NC_NOERR) (void)fprintf(stdout,"%s: %s reports ERROR unable to find variable \"%s\"\n",nco_prg_nm_get(),fnc_nm,var_nm); /* Get type of variable and number of dimensions from input */ (void)nco_inq_var(grp_in_id,var_in_id,(char *)NULL,&var_typ,&nbr_dmn_var,(int *)NULL,(int *)NULL); /* Get Program ID */ nco_prg_id=nco_prg_id_get(); if(nco_prg_id == ncks) assert(var_typ == var_trv->var_typ); assert(nbr_dmn_var == var_trv->nbr_dmn); var_typ=var_trv->var_typ; nbr_dmn_var=var_trv->nbr_dmn; /* Get dimension IDs for *variable* */ (void)nco_inq_vardimid(grp_in_id,var_in_id,dmn_in_id_var); /* Does user want a record dimension to receive special handling? */ if(rec_dmn_nm_cst){ /* Create (and later free()) local copy to preserve const-ness of passed value For simplicity, work with canonical name rec_dmn_nm */ rec_dmn_nm_mlc=strdup(rec_dmn_nm_cst); /* Parse rec_dmn_nm argument */ if(!strcmp("fix_all",rec_dmn_nm_mlc)){ FIX_ALL_REC_DMN=True; FIX_REC_DMN=True; rec_dmn_nm=rec_dmn_nm_mlc+4; }else if(!strncmp("fix_",rec_dmn_nm_mlc,(size_t)4)){ FIX_REC_DMN=True; /* [flg] Fix record dimension */ rec_dmn_nm=rec_dmn_nm_mlc+4; }else{ FIX_REC_DMN=False; /* [flg] Fix record dimension */ rec_dmn_nm=rec_dmn_nm_mlc; } /* strncmp() */ } /* !rec_dmn_nm_cst */ /* If variable has a re-defined record dimension. NOTE: this implies passing NULL as User-specified record dimension parameter */ if(var_trv->rec_dmn_nm_out){ /* Must be ncpdq */ assert(nco_prg_id == ncpdq); rec_dmn_nm=(char *)strdup(var_trv->rec_dmn_nm_out); } /* If variable has a re-defined record dimension */ /* Is requested record dimension in input file? */ if(rec_dmn_nm){ /* ncks */ if(nco_prg_id == ncks){ if(!FIX_ALL_REC_DMN){ int rec_dmn_id_dmy; rcd=nco_inq_dimid_flg(grp_in_id,rec_dmn_nm,&rec_dmn_id_dmy); /* Record name not found in this group */ if(rcd != NC_NOERR){ /* Nothing to do, error cheking for invalid dimension names was made at start */ } /* endif rcd != NC_NOERR */ if(rcd == NC_NOERR){ /* Does variable contain requested record dimension? */ for(int idx_dmn=0;idx_dmnis_rec_dmn; if(FIX_ALL_REC_DMN){ DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; if(CRR_DMN_IS_REC_IN_INPUT && nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s is defining all input record dimensions, including this one, %s, as fixed dimensions in output file per user request\n",nco_prg_nm_get(),fnc_nm,dmn_nm); }else if(rec_dmn_nm){ /* User requested (with --fix_rec_dmn or --mk_rec_dmn) to treat a certain dimension specially */ /* ... and this dimension is that dimension, i.e., the user-specified dimension ... */ if(!strcmp(dmn_nm,rec_dmn_nm)){ /* ... then honor user's request to define it as a fixed or record dimension ... */ if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO %s is defining dimension %s as %s dimension in output file per user request\n",nco_prg_nm_get(),fnc_nm,rec_dmn_nm,(FIX_REC_DMN) ? "fixed" : "record"); if(FIX_REC_DMN) DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; }else{ /* strcmp() */ if(FIX_REC_DMN){ /* ... fix_rec_dmn case is straightforward: output dimension has same format as input dimension */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; }else{ /* !FIX_REC_DMN */ /* ... otherwise we are in the --mk_rec_dmn case where things get complicated ... This dimension can be a record dimension only if it would not conflict with the requested record dimension being defined a record dimension, and that depends on file format. Uggh. 1. netCDF3 API allows only one record-dimension so conflicts are possible 2. netCDF4 API permits any number of unlimited dimensions so conflicts are impossible */ if(fl_fmt == NC_FORMAT_NETCDF4){ /* ... no conflicts possible so define dimension in output same as in input ... */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; }else{ /* !netCDF4 */ /* ... output file adheres to netCDF3 API so there can be only one record dimension. In other words, define all other dimensions as fixed, non-record dimensions, even if they are a record dimension in the input file ... */ if(CRR_DMN_IS_REC_IN_INPUT) (void)fprintf(stderr,"%s: INFO %s is defining dimension %s as fixed (non-record) in output file even though it is a record dimension in the input file. This is necessary to satisfy user request that %s be the record dimension in the output file which adheres to the netCDF3 API that permits only one record dimension.\n",nco_prg_nm_get(),fnc_nm,dmn_nm,rec_dmn_nm); DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; } /* !netCDF4 */ } /* !FIX_REC_DMN */ } /* strcmp() */ }else{ /* !rec_dmn_nm */ /* ... no user-specified record dimension so define dimension in output same as in input ... */ if(CRR_DMN_IS_REC_IN_INPUT) DFN_CRR_DMN_AS_REC_IN_OUTPUT=True; else DFN_CRR_DMN_AS_REC_IN_OUTPUT=False; } /* !rec_dmn_nm && !FIX_ALL_REC_DMN */ /* At long last ... */ /* Define current index dimension size */ /* If current dimension is to be defined as record dimension in output file */ if(DFN_CRR_DMN_AS_REC_IN_OUTPUT){ if(var_trv->var_dmn[idx_dmn].is_crd_var){ dmn_cnt=var_trv->var_dmn[idx_dmn].crd->lmt_msa.dmn_cnt; } else { dmn_cnt=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.dmn_cnt; } (void)nco_dmn_set_msa(var_dim_id,dmn_cnt,trv_tbl); /* ! DFN_CRR_DMN_AS_REC_IN_OUTPUT */ }else{ /* Get size from GTT */ if(var_trv->var_dmn[idx_dmn].is_crd_var){ /* Set size */ dmn_cnt=var_trv->var_dmn[idx_dmn].crd->lmt_msa.dmn_cnt; /* Update GTT dimension */ (void)nco_dmn_set_msa(var_dim_id,dmn_cnt,trv_tbl); }else { /* Set size */ dmn_cnt=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.dmn_cnt; /* Update GTT dimension */ (void)nco_dmn_set_msa(var_dim_id,dmn_cnt,trv_tbl); } } /* Define dimension size */ } /* end if dimension is not yet defined */ } /* End of the very important dimension loop */ } /* end nco_dmn_msa_tbl() */ void nco_dmn_dgn_tbl /* [fnc] Transfer degenerated dimensions information into GTT */ (dmn_sct **dmn_dgn, /* [sct] Degenerate (size 1) dimensions used by ncwa */ const int nbr_dmn_dgn, /* I [nbr] Total number of dimensions in list */ trv_tbl_sct *trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { trv_tbl->nbr_dmn_dgn=nbr_dmn_dgn; trv_tbl->dmn_dgn=(dmn_sct *)nco_malloc(nbr_dmn_dgn*sizeof(dmn_sct)); /* Loop dimensions */ for(int idx_dmn=0;idx_dmndmn_dgn[idx_dmn].id=dmn_dgn[idx_dmn]->id; trv_tbl->dmn_dgn[idx_dmn].cnt=dmn_dgn[idx_dmn]->cnt; } /* Loop dimensions */ } /* nco_dmn_dgn_tbl() */ void nco_dmn_lst_ass_var_trv /* [fnc] Create list of all dimensions associated with input variable list (ncpdq, ncwa) */ (const int nc_id, /* I [id] netCDF file ID */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ int *nbr_dmn_xtr, /* O [nbr] Number of dimensions associated with variables to be extracted */ dmn_sct ***dmn) /* O [sct] Array of dimensions associated with variables to be extracted */ { /* Purpose: Create list of all dimensions associated with input variable list */ const char fnc_nm[]="nco_dmn_lst_ass_var_trv()"; /* [sng] Function name */ int nbr_dmn; /* [nbr] Number of dimensions associated with variables to be extracted */ long dmn_cnt; /* [nbr] Hyperslabbed size of dimension */ long dmn_sz; /* [nbr] Size of dimension */ nco_bool dmn_flg; /* [flg] Is dimension already inserted in output array */ nbr_dmn=0; /* Traverse table and match relative dimension names */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* If GTT variable object is to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_dmn_var=0;idx_dmn_varnm,var_trv.var_dmn[idx_dmn_var].dmn_nm) == 0); /* Loop constructed array of output dimensions to see if already inserted */ for(int idx_dmn_out=0;idx_dmn_outid){ dmn_flg=True; break; } /* Match by ID */ } /* Loop constructed array of output dimensions to see if already inserted */ /* If this dimension is not in output array */ if(!dmn_flg){ /* Add one more element to array */ (*dmn)=(dmn_sct **)nco_realloc((*dmn),(nbr_dmn+1)*sizeof(dmn_sct *)); (*dmn)[nbr_dmn]=(dmn_sct *)nco_malloc(sizeof(dmn_sct)); /* Get size from GTT. NOTE use index idx_dmn_var */ if(var_trv.var_dmn[idx_dmn_var].is_crd_var){ dmn_cnt=var_trv.var_dmn[idx_dmn_var].crd->lmt_msa.dmn_cnt; dmn_sz=var_trv.var_dmn[idx_dmn_var].crd->sz; (*dmn)[nbr_dmn]->is_crd_dmn=True; }else { dmn_cnt=var_trv.var_dmn[idx_dmn_var].ncd->lmt_msa.dmn_cnt; dmn_sz=var_trv.var_dmn[idx_dmn_var].ncd->sz; (*dmn)[nbr_dmn]->is_crd_dmn=False; } (*dmn)[nbr_dmn]->nm=(char *)strdup(var_trv.var_dmn[idx_dmn_var].dmn_nm); (*dmn)[nbr_dmn]->id=var_trv.var_dmn[idx_dmn_var].dmn_id; (*dmn)[nbr_dmn]->nc_id=nc_id; (*dmn)[nbr_dmn]->xrf=NULL; (*dmn)[nbr_dmn]->val.vp=NULL; (*dmn)[nbr_dmn]->is_rec_dmn=dmn_trv->is_rec_dmn; (*dmn)[nbr_dmn]->cnt=dmn_cnt; (*dmn)[nbr_dmn]->sz=dmn_sz; (*dmn)[nbr_dmn]->srt=0L; (*dmn)[nbr_dmn]->end=dmn_cnt-1L; (*dmn)[nbr_dmn]->srd=1L; (*dmn)[nbr_dmn]->cid=-1; (*dmn)[nbr_dmn]->cnk_sz=0L; (*dmn)[nbr_dmn]->type=(nc_type)-1; nbr_dmn++; } /* If this dimension is not in output array */ } /* Loop variable dimensions */ } /* Filter variables */ } /* Loop table */ /* Export */ *nbr_dmn_xtr=nbr_dmn; if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG %s dimensions to export: ",nco_prg_nm_get(),fnc_nm); for(int idx_dmn=0;idx_dmn : ",(*dmn)[idx_dmn]->id,(*dmn)[idx_dmn]->nm); (void)fprintf(stdout,"\n"); } /* endif */ return; } /* end nco_dmn_lst_ass_var_trv() */ void nco_dmn_avg_mk /* [fnc] Build dimensions to average(ncwa)/re-order(ncpdq) array from input dimension names */ (const int nc_id, /* I [id] netCDF file ID */ char **obj_lst_in, /* I [sng] User-specified list of dimension names (-a names) */ const int nbr_dmn_in, /* I [nbr] Total number of dimensions in input list (size of above array) */ const nco_bool flg_rdd, /* I [flg] Retain degenerate dimensions */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ dmn_sct ***dmn_avg, /* O [sct] Array of dimensions to average */ int *nbr_dmn_avg) /* O [nbr] Number of dimensions to average (size of above array) */ { /* Purpose: Create list of dimensions from list of dimension name strings (function based in nco_xtr_mk() ) */ /* Dimensions to average/not average are built using these 3 functions: nco_dmn_avg_mk() Build dimensions to average array from input dimension names nco_dmn_out_mk() Build dimensions array to keep on output nco_dmn_id_mk() Mark flag average for all dimensions that have the input ID nco_dmn_avg_mk() parses -a names and exports an array of dmn_sct; it marks the flag "flg_dmn_avg" of "var_dmn_sct" as True, if the dimension is to be averaged. Since variables share dimensions, this flag has to be marked to all variable's dimensions that have it; This broadcast is made in nco_dmn_id_mk(), using the unique dimension ID as key. nco_dmn_out_mk() checks this flag, and if the dimension is not to be averaged, it is added to an array of dmn_sct, dimensions on output. */ const char fnc_nm[]="nco_dmn_avg_mk()"; /* [sng] Function name */ const char sls_chr='/'; /* [chr] Slash character */ char *sbs_srt; /* [sng] Location of user-string match start in object path */ char *sbs_end; /* [sng] Location of user-string match end in object path */ char *usr_sng; /* [sng] User-supplied object name */ char *var_mch_srt; /* [sng] Location of variable short name in user-string */ nco_bool flg_pth_end_bnd; /* [flg] String ends at path component boundary */ nco_bool flg_pth_srt_bnd; /* [flg] String begins at path component boundary */ nco_bool flg_var_cnd; /* [flg] Match meets addition condition(s) for dimension */ nco_bool flg_dmn_ins; /* [flg] Is dimension already inserted in output array */ int obj_nbr; /* [nbr] Number of objects in list */ int nbr_avg_dmn; /* [nbr] Number of dimensions to average (output) */ long dmn_cnt; /* [nbr] Hyperslabbed size of dimension */ long dmn_sz; /* [nbr] Size of dimension */ size_t usr_sng_lng; /* [nbr] Length of user-supplied string */ /* Used only by ncpdq , ncwa */ assert(nco_prg_id_get() == ncpdq || nco_prg_id_get() == ncwa); /* Initialize values */ obj_nbr=nbr_dmn_in; nbr_avg_dmn=0; /* Loop input dimension name list */ for(int idx_obj=0;idx_obj+?|{}")){ /* ... and regular expression library is present */ #ifdef NCO_HAVE_REGEX_FUNCTIONALITY /* fxm 20131217 TODO */ (void)fprintf(stdout,"%s: ERROR: Sorry, wildcarding (extended regular expression matches to variables) is not implemented for -a option.\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); #else /* !NCO_HAVE_REGEX_FUNCTIONALITY */ (void)fprintf(stdout,"%s: ERROR: Sorry, wildcarding (extended regular expression matches to variables) was not built into this NCO executable, so unable to compile regular expression \"%s\".\nHINT: Make sure libregex.a is on path and re-build NCO.\n",nco_prg_nm_get(),usr_sng); nco_exit(EXIT_FAILURE); #endif /* !NCO_HAVE_REGEX_FUNCTIONALITY */ } /* end if regular expression */ /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct trv_obj=trv_tbl->lst[idx_tbl]; /* Initialize defaults for current candidate path to match */ flg_pth_srt_bnd=False; flg_pth_end_bnd=False; flg_var_cnd=False; /* Variable to extract */ if(trv_obj.nco_typ == nco_obj_typ_var && trv_obj.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnnm,trv_obj.var_dmn[idx_var_dmn].dmn_nm) == 0); /* Dimension ID, used to avoid duplicate insertions */ int dmn_id=trv_obj.var_dmn[idx_var_dmn].dmn_id; /* Dimension name full */ char *dmn_nm_fll=trv_obj.var_dmn[idx_var_dmn].dmn_nm_fll; /* Dimension name full length */ size_t dmn_nm_fll_lng=strlen(dmn_nm_fll); /* Dimension name relative */ char *dmn_nm=trv_obj.var_dmn[idx_var_dmn].dmn_nm; /* Dimension name relative length */ size_t dmn_nm_lng=strlen(dmn_nm); /* Look for partial match, not necessarily on path boundaries */ if((sbs_srt=strstr(dmn_nm_fll,usr_sng))){ /* Ensure match spans (begins and ends on) whole path-component boundaries */ /* Does match begin at path component boundary ... directly on a slash? */ if(*sbs_srt == sls_chr) flg_pth_srt_bnd=True; /* ...or one after a component boundary? */ if((sbs_srt > dmn_nm_fll) && (*(sbs_srt-1L) == sls_chr)) flg_pth_srt_bnd=True; /* Does match end at path component boundary ... directly on a slash? */ sbs_end=sbs_srt+usr_sng_lng-1L; if(*sbs_end == sls_chr) flg_pth_end_bnd=True; /* ...or one before a component boundary? */ if(sbs_end <= dmn_nm_fll+dmn_nm_fll_lng-1L) if((*(sbs_end+1L) == sls_chr) || (*(sbs_end+1L) == '\0')) flg_pth_end_bnd=True; /* Additional condition is user-supplied string must end with short form of dimension name */ if(dmn_nm_lng <= usr_sng_lng){ var_mch_srt=usr_sng+usr_sng_lng-dmn_nm_lng; if(!strcmp(var_mch_srt,dmn_nm)) flg_var_cnd=True; } /* Additional condition */ /* Must meet necessary flags */ if(flg_pth_srt_bnd && flg_pth_end_bnd && flg_var_cnd){ flg_dmn_ins=False; /* Loop constructed array of averaged output dimensions to see if already inserted */ for(int idx_dmn_out=0;idx_dmn_outid){ flg_dmn_ins=True; break; } /* Match by ID */ } /* Loop constructed array of output dimensions to see if already inserted */ /* If this dimension is not in output array */ if(!flg_dmn_ins){ /* Change flag to mark that dimension is to be averaged instead of to keep on output */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].flg_dmn_avg=True; /* Add one more element to array */ (*dmn_avg)=(dmn_sct **)nco_realloc((*dmn_avg),(nbr_avg_dmn+1)*sizeof(dmn_sct *)); (*dmn_avg)[nbr_avg_dmn]=(dmn_sct *)nco_malloc(sizeof(dmn_sct)); /* Get size from GTT. NOTE use index idx_var_dmn */ if(trv_obj.var_dmn[idx_var_dmn].is_crd_var){ dmn_cnt=trv_obj.var_dmn[idx_var_dmn].crd->lmt_msa.dmn_cnt; dmn_sz=trv_obj.var_dmn[idx_var_dmn].crd->sz; (*dmn_avg)[nbr_avg_dmn]->is_crd_dmn=True; }else{ dmn_cnt=trv_obj.var_dmn[idx_var_dmn].ncd->lmt_msa.dmn_cnt; dmn_sz=trv_obj.var_dmn[idx_var_dmn].ncd->sz; (*dmn_avg)[nbr_avg_dmn]->is_crd_dmn=False; } (*dmn_avg)[nbr_avg_dmn]->nm=(char *)strdup(trv_obj.var_dmn[idx_var_dmn].dmn_nm); (*dmn_avg)[nbr_avg_dmn]->id=trv_obj.var_dmn[idx_var_dmn].dmn_id; (*dmn_avg)[nbr_avg_dmn]->nc_id=nc_id; (*dmn_avg)[nbr_avg_dmn]->xrf=NULL; (*dmn_avg)[nbr_avg_dmn]->val.vp=NULL; (*dmn_avg)[nbr_avg_dmn]->is_rec_dmn=dmn_trv->is_rec_dmn; (*dmn_avg)[nbr_avg_dmn]->cnt=dmn_cnt; (*dmn_avg)[nbr_avg_dmn]->sz=dmn_sz; (*dmn_avg)[nbr_avg_dmn]->srt=0L; (*dmn_avg)[nbr_avg_dmn]->end=dmn_cnt-1L; (*dmn_avg)[nbr_avg_dmn]->srd=1L; (*dmn_avg)[nbr_avg_dmn]->cid=-1; (*dmn_avg)[nbr_avg_dmn]->cnk_sz=0L; (*dmn_avg)[nbr_avg_dmn]->type=(nc_type)-1; /* Broadcast flag average/keep using dimension ID; variables share dimensions */ (void)nco_dmn_id_mk(dmn_id,flg_rdd,trv_tbl); /* Increment number of dimensions found */ nbr_avg_dmn++; } /* If this dimension is not in output array */ } /* Must meet necessary flags */ } /* Look for partial match, not necessarily on path boundaries */ } /* Loop variable dimensions */ } /* Variable to extract */ } /* Loop table */ } /* Loop input dimension name list */ /* Export */ *nbr_dmn_avg=nbr_avg_dmn; if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG %s dimensions to average: ",nco_prg_nm_get(),fnc_nm); for(int idx_dmn=0;idx_dmn : ",(*dmn_avg)[idx_dmn]->id,(*dmn_avg)[idx_dmn]->nm); (void)fprintf(stdout,"\n"); } /* endif dbg */ return; } /* nco_dmn_avg_mk() */ void nco_dmn_out_mk /* [fnc] Build dimensions array to keep on output */ (dmn_sct **dmn_xtr, /* I [sct] Array of dimensions associated with variables to be extracted */ const int nbr_dmn_xtr, /* I [nbr] Number of dimensions associated with variables to be extracted (size of above array) */ const trv_tbl_sct * const trv_tbl, /* I [sct] GTT (Group Traversal Table) */ dmn_sct ***dmn_out, /* O [sct] Array of dimensions on ouput */ int *nbr_dmn_out) /* O [nbr] Number of dimensions on output (size of above array) */ { /* Purpose: Create list of dimensions from list of dimension name strings (function based in nco_xtr_mk() ) */ const char fnc_nm[]="nco_dmn_out_mk()"; /* [sng] Function name */ int nbr_out_dmn; /* [nbr] Number of dimensions to keep in output */ nco_bool flg_dmn_ins; /* [flg] Is dimension already inserted in output array */ /* Used only by ncpdq , ncwa */ assert(nco_prg_id_get() == ncpdq || nco_prg_id_get() == ncwa); /* Initialize values */ nbr_out_dmn=0; /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct trv_obj=trv_tbl->lst[idx_tbl]; /* Variable to extract */ if(trv_obj.nco_typ == nco_obj_typ_var && trv_obj.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnid){ /* Assume dimension is not yet inserted in array */ flg_dmn_ins=False; /* Loop constructed array of output dimensions to see if already inserted */ for(int idx_dmn_out=0;idx_dmn_outid){ /* Mark as inserted in array */ flg_dmn_ins=True; break; } /* Match by ID */ } /* Loop constructed array of output dimensions to see if already inserted */ /* If this dimension is not in output array */ if(!flg_dmn_ins){ /* Output list comprises non-averaged and, if specified, degenerate dimensions */ (*dmn_out)[nbr_out_dmn]=nco_dmn_dpl(dmn_xtr[idx_xtr_dmn]); (void)nco_dmn_xrf(dmn_xtr[idx_xtr_dmn],(*dmn_out)[nbr_out_dmn]); nbr_out_dmn++; } /* If this dimension is not in output array */ } /* Match by ID */ } /* Search dimensions to be extracted */ } /* This dimension is not to be averaged, it is to be kept on output */ } /* Loop variable dimensions */ } /* Variable to extract */ } /* Loop table */ /* Export */ *nbr_dmn_out=nbr_out_dmn; if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG %s dimensions to keep on output: ",nco_prg_nm_get(),fnc_nm); for(int idx_dmn=0;idx_dmn : ",(*dmn_out)[idx_dmn]->id,(*dmn_out)[idx_dmn]->nm); (void)fprintf(stdout,"\n"); } /* endif dbg */ return; } /* nco_dmn_out_mk() */ void nco_dmn_id_mk /* [fnc] Mark flag average, optionally flag degenerate for all dimensions that have the input ID */ (const int dmn_id, /* I [nbr] Number of dimensions associated with variables to be extracted (size of above array) */ const nco_bool flg_rdd, /* I [flg] Mark flag retain degenerate dimension */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Purpose: Mark flag average, optionally flag degenerate for all dimensions that have the input ID */ /* Used only by ncpdq , ncwa */ assert(nco_prg_id_get() == ncpdq || nco_prg_id_get() == ncwa); /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct trv_obj=trv_tbl->lst[idx_tbl]; /* Variable to extract */ if(trv_obj.nco_typ == nco_obj_typ_var && trv_obj.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnlst[idx_tbl].var_dmn[idx_var_dmn].flg_dmn_avg=True; /* Change flag to retain degenerate dimension */ if(flg_rdd) trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].flg_rdd=True; } /* Match ID */ } /* Loop variable dimensions */ } /* Variable to extract */ } /* Loop table */ return; } /* nco_dmn_id_mk() */ void nco_bld_rec_dmn /* [fnc] Build record dimensions array */ (const int nc_id, /* I [ID] netCDF input file ID */ const nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ lmt_sct ***lmt_rec, /* I/O [lst] (ncra) Record dimensions */ int *nbr_rec, /* I/O [nbr] (ncra) Number of record dimensions (size of above array) */ trv_tbl_sct * trv_tbl) /* I/O [sct] GTT (Group Traversal Table) */ { const char fnc_nm[]="nco_bld_rec_dmn()"; /* [sng] Function name */ int var_id; /* [id] Variable ID */ int grp_id; /* [id] Group ID */ dmn_trv_sct *dmn_trv; /* [sct] Unique dimension object */ nco_bool flg_dmn_ins; /* [flg] Is dimension already inserted in output array */ int rec_nbr; /* [sct] Number of record dimensions to export */ #ifndef ENABLE_UDUNITS nco_bool flg_prn=False; #endif /* !ENABLE_UDUNITS */ /* Initialize */ rec_nbr=0; /* Used only by record operators ncra,ncrcat */ assert(nco_prg_id_get() == ncra || nco_prg_id_get() == ncrcat); /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Filter extracted variables */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnis_rec_dmn){ /* Loop constructed array of output dimensions to see if already inserted */ for(int idx_dmn_out=0;idx_dmn_outid){ /* Mark as inserted in array */ flg_dmn_ins=True; break; } /* Match by ID */ } /* Loop constructed array of output dimensions to see if already inserted */ /* If this dimension is not in output array */ if(!flg_dmn_ins){ /* Add one more element to array */ (*lmt_rec)=(lmt_sct **)nco_realloc((*lmt_rec),(rec_nbr+1)*sizeof(lmt_sct *)); (*lmt_rec)[rec_nbr]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Obtain group ID using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv.grp_nm_fll,&grp_id); /* a) case where the dimension has coordinate variables */ if(var_trv.var_dmn[idx_var_dmn].crd){ crd_sct *crd=var_trv.var_dmn[idx_var_dmn].crd; /* Create stand-alone limit structure for given dimension */ (*lmt_rec)[rec_nbr]=nco_lmt_sct_mk(grp_id,dmn_id,crd->lmt_msa.lmt_dmn,crd->lmt_msa.lmt_dmn_nbr,FORTRAN_IDX_CNV); /* Insert full group name, key for group ID match */ (*lmt_rec)[rec_nbr]->grp_nm_fll=(char *)strdup(crd->crd_grp_nm_fll); (*lmt_rec)[rec_nbr]->nm_fll=(char *)strdup(crd->dmn_nm_fll); /* b) case of dimension only (there is no coordinate variable for this dimension */ }else{ dmn_trv_sct *ncd=var_trv.var_dmn[idx_var_dmn].ncd; /* Create stand-alone limit structure for given dimension */ (*lmt_rec)[rec_nbr]=nco_lmt_sct_mk(grp_id,dmn_id,ncd->lmt_msa.lmt_dmn,ncd->lmt_msa.lmt_dmn_nbr,FORTRAN_IDX_CNV); /* Insert full group name, key for group ID match */ (*lmt_rec)[rec_nbr]->grp_nm_fll=(char *)strdup(ncd->grp_nm_fll); (*lmt_rec)[rec_nbr]->nm_fll=(char *)strdup(ncd->nm_fll); } /* b) case of dimension only (there is no coordinate variable for this dimension */ (*lmt_rec)[rec_nbr]->lmt_cln=cln_nil; (*lmt_rec)[rec_nbr]->origin=0.0; (*lmt_rec)[rec_nbr]->rbs_sng=NULL; /* Check if coordinate variable */ int rcd=nco_inq_varid_flg(grp_id,var_trv.var_dmn[idx_var_dmn].dmn_nm,&var_id); /* Obtain record coordinate metadata */ if(rcd == NC_NOERR){ char *cln_att_sng=NULL; (*lmt_rec)[rec_nbr]->rbs_sng=nco_lmt_get_udu_att(grp_id,var_id,"units"); cln_att_sng=nco_lmt_get_udu_att(grp_id,var_id,"calendar"); (*lmt_rec)[rec_nbr]->lmt_cln=nco_cln_get_cln_typ(cln_att_sng); if(cln_att_sng) cln_att_sng=(char*)nco_free(cln_att_sng); } /* Store ID */ (*lmt_rec)[rec_nbr]->id=dmn_id; #ifndef ENABLE_UDUNITS if(nco_dbg_lvl_get() >= nco_dbg_vrb && nco_dbg_lvl_get() != nco_dbg_dev && flg_prn == False){ if((*lmt_rec)[rec_nbr]->rbs_sng) (void)fprintf(stderr,"%s: WARNING Record coordinate %s has a \"units\" attribute but NCO was built without UDUnits. NCO is therefore unable to detect and correct for inter-file unit re-basing issues. See http://nco.sf.net/nco.html#rbs for more information.\n%s: HINT Re-build or re-install NCO enabled with UDUnits.\n", nco_prg_nm_get(),(*lmt_rec)[rec_nbr]->nm,nco_prg_nm_get()); flg_prn=True; } #endif /* !ENABLE_UDUNITS */ /* Increase array size */ rec_nbr++; } /* If this dimension is not in output array */ } /* Is record */ } /* Loop variable dimensions */ } /* Variable to extract */ } /* Loop table */ if(nco_dbg_lvl_get() >= nco_dbg_dev){ (void)fprintf(stdout,"%s: DEBUG %s record dimensions to process: ",nco_prg_nm_get(),fnc_nm); for(int idx_rec=0;idx_rec : ",(*lmt_rec)[idx_rec]->id,(*lmt_rec)[idx_rec]->grp_nm_fll,(*lmt_rec)[idx_rec]->nm); } (void)fprintf(stdout,"\n"); } /* Export */ *nbr_rec=rec_nbr; return; } /* nco_bld_rec_dmn() */ void nco_prn_tbl_lmt /* [fnc] Print table limits */ (trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { const char fnc_nm[]="nco_prn_tbl_lmt()"; /* [sng] Function name */ /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Is variable */ if(var_trv.nco_typ == nco_obj_typ_var){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnlst[idx_tbl].var_dmn[idx_var_dmn].crd; int lmt_dmn_nbr=crd->lmt_msa.lmt_dmn_nbr; if(lmt_dmn_nbr){ (void)fprintf(stdout,"%s: INFO %s : <%s> : %s : limits:%d ->",nco_prg_nm_get(),fnc_nm,var_trv.nm_fll,var_trv.var_dmn[idx_var_dmn].dmn_nm,lmt_dmn_nbr); for(int lmt_idx=0;lmt_idxlmt_msa.lmt_dmn[lmt_idx]; (void)fprintf(stdout," [%d]%s(%li,%li,%li) :",lmt_idx,lmt_dmn->nm,lmt_dmn->srt,lmt_dmn->cnt,lmt_dmn->srd); } (void)fprintf(stdout,"\n"); } /* b) case of dimension only (there is no coordinate variable for this dimension */ }else{ dmn_trv_sct *ncd=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd; int lmt_dmn_nbr=ncd->lmt_msa.lmt_dmn_nbr; if(lmt_dmn_nbr){ (void)fprintf(stdout,"%s: INFO %s : <%s> : %s :limits: %d->",nco_prg_nm_get(),fnc_nm,var_trv.nm_fll,var_trv.var_dmn[idx_var_dmn].dmn_nm,lmt_dmn_nbr); for(int lmt_idx=0;lmt_idxlmt_msa.lmt_dmn[lmt_idx]; (void)fprintf(stdout," [%d]%s(%li,%li,%li) :",lmt_idx,lmt_dmn->nm,lmt_dmn->srt,lmt_dmn->cnt,lmt_dmn->srd); } (void)fprintf(stdout,"\n"); } } /* b) case of dimension only (there is no coordinate variable for this dimension */ } /* Loop variable dimensions */ } /* Is variable */ } /* Loop table */ } /* nco_prn_tbl_lmt() */ void nco_bld_trv_tbl /* [fnc] Construct GTT, Group Traversal Table (groups,variables,dimensions, limits) */ (const int nc_id, /* I [ID] netCDF file ID */ char * const grp_pth, /* I [sng] Absolute group path where to start build (root typically) */ int lmt_nbr, /* I [nbr] number of dimensions with limits */ CST_X_PTR_CST_PTR_CST_Y(char,lmt_arg), /* I [sng] List of user-specified dimension limits */ const int aux_nbr, /* I [nbr] Number of auxiliary coordinates */ char *aux_arg[], /* I [sng] Auxiliary coordinates */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ char **grp_lst_in, /* I [sng] User-specified list of groups */ const int grp_lst_in_nbr, /* I [nbr] Number of groups in list */ char **var_lst_in, /* I [sng] User-specified list of variables */ const int var_xtr_nbr, /* I [nbr] Number of variables in list */ const nco_bool EXTRACT_ALL_COORDINATES, /* I [flg] Process all coordinates */ const nco_bool flg_unn, /* I [flg] Select union of specified groups and variables */ const nco_bool EXCLUDE_INPUT_LIST, /* I [flg] Exclude rather than extract groups and variables specified with -v */ const nco_bool EXTRACT_ASSOCIATED_COORDINATES, /* I [flg] Extract all coordinates associated with extracted variables? */ nco_dmn_dne_t **flg_dne, /* I/O [lst] Flag to check if input dimension -d "does not exist" */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Construct GTT, Group Traversal Table (groups, variables, dimensions, limits) Return value: Check for valid input; NC_NOERR (0) or > 0 for a user input error, used to go to close_and_free on main Notes: * Dimension limit structures are handled internally in this function and not exported * Call sequence is important: 1) nco_trv_hsh_bld() must be called after nco_grp_itr() because other functions use hash table 2) nco_grp_itr() must be first, main iterator function. Then nco_bld_dmn_ids_trv() nco_bld_crd_rec_var_trv() nco_bld_crd_var_trv() nco_has_crd_dmn_scp() nco_bld_var_dmn() complete structures for the traversal table to be completed. Then, user options functions are called: nco_xtr_mk() nco_xtr_xcl() nco_xtr_crd_add() nco_xtr_crd_ass_add() nco_xtr_cf_add() Limits related function must be called in order: nco_lmt_prs() nco_prs_aux_crd() nco_chk_dmn_in() Two functions called for specific operators are: ncbo: trv_tbl_srt() nces nco_bld_nsm() */ const char fnc_nm[]="nco_bld_trv_tbl()"; /* [sng] Function name */ nco_bool CNV_CCM_CCSM_CF; /* [flg] File adheres to NCAR CCM/CCSM/CF conventions */ lmt_sct **lmt=NULL_CEWI; /* [sct] User defined limits */ /* Construct traversal table objects (groups, variables) */ (void)nco_grp_itr(nc_id,(char *)NULL,grp_pth,trv_tbl); /* Build dimension information for all variables (match dimension IDs) */ (void)nco_bld_dmn_ids_trv(nc_id,trv_tbl); /* Build "is_crd_var" and "is_rec_var" members for all variables */ (void)nco_bld_crd_rec_var_trv(trv_tbl); /* Build GTT "crd_sct" coordinate variable structure */ (void)nco_bld_crd_var_trv(trv_tbl); /* Variables in dimension's scope? */ (void)nco_has_crd_dmn_scp(trv_tbl); /* Assign variables' dimensions to either coordinates or dimension structs */ (void)nco_bld_var_dmn(trv_tbl); /* ncbo co-sequential match algorithm requires alphabetical sorted full names. Do it here, to avoid rebuilding hash table */ if(nco_prg_id_get() == ncbo) (void)trv_tbl_srt(trv_tbl); /* Hash traversal table for faster access */ (void)nco_trv_hsh_bld(trv_tbl); /* Build auxiliary coordinates information into table */ if(aux_nbr) (void)nco_bld_crd_aux(nc_id,trv_tbl); /* Check -v and -g input names and create extraction list */ (void)nco_xtr_mk(grp_lst_in,grp_lst_in_nbr,var_lst_in,var_xtr_nbr,EXTRACT_ALL_COORDINATES,flg_unn,trv_tbl); /* Change included variables to excluded variables */ if(EXCLUDE_INPUT_LIST) (void)nco_xtr_xcl(trv_tbl); /* Add all coordinate variables to extraction list */ if(EXTRACT_ALL_COORDINATES) (void)nco_xtr_crd_add(trv_tbl); /* Extract coordinates associated with extracted variables */ if(EXTRACT_ASSOCIATED_COORDINATES) (void)nco_xtr_crd_ass_add(nc_id,trv_tbl); /* Is this a CCM/CCSM/CF-format history tape? */ CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(nc_id); if(CNV_CCM_CCSM_CF && EXTRACT_ASSOCIATED_COORDINATES){ /* Implement CF "coordinates" and "bounds" conventions */ (void)nco_xtr_cf_add(nc_id,"coordinates",trv_tbl); (void)nco_xtr_cf_add(nc_id,"bounds",trv_tbl); } /* CNV_CCM_CCSM_CF */ /* Mark extracted dimensions */ (void)nco_xtr_dmn_mrk(trv_tbl); /* Mark extracted groups */ (void)nco_xtr_grp_mrk(trv_tbl); /* Parse auxiliary coordinates and build found limits directly into table (auxiliary limits are not merged into regular limits ) */ if(aux_nbr) (void)nco_prs_aux_crd(nc_id,aux_nbr,aux_arg,FORTRAN_IDX_CNV,MSA_USR_RDR,EXTRACT_ASSOCIATED_COORDINATES,trv_tbl); /* Add dimension limits */ if(lmt_nbr){ lmt=nco_lmt_prs(lmt_nbr,lmt_arg); (void)nco_bld_lmt(nc_id,MSA_USR_RDR,lmt_nbr,lmt,FORTRAN_IDX_CNV,trv_tbl); } /* !lmt_nbr */ /* Build ensembles */ if(nco_prg_id_get() == ncge) (void)nco_bld_nsm(nc_id,trv_tbl); /* Check valid input (limits) */ if(lmt_nbr) (void)nco_chk_dmn_in(lmt_nbr,lmt,flg_dne,trv_tbl); /* Free limits */ if(lmt_nbr){ for(int idx=0;idxnm); (*dne_lst)[lmt_idx].dim_nm=(char *) strdup(lmt[lmt_idx]->nm); /* Match input relative name to dimension relative name */ for(unsigned int dmn_idx=0;dmn_idxnbr_dmn;dmn_idx++) if(!strcmp(lmt[lmt_idx]->nm,trv_tbl->lst_dmn[dmn_idx].nm)) (*dne_lst)[lmt_idx].flg_dne=False; } /* Loop input name list */ } /* nco_chk_dmn_in() */ void nco_bld_lmt /* [fnc] Assign user specified dimension limits to traversal table */ (const int nc_id, /* I [ID] netCDF file ID */ nco_bool MSA_USR_RDR, /* I [flg] Multi-Slab Algorithm returns hyperslabs in user-specified order */ int lmt_nbr, /* I [nbr] Number of user-specified dimension limits */ lmt_sct **lmt, /* I [sct] Limit array. Structure comming from nco_lmt_prs() */ nco_bool FORTRAN_IDX_CNV, /* I [flg] Hyperslab indices obey Fortran convention */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Assign user-specified dimension limits to traversal table At this point "lmt" was parsed from nco_lmt_prs(); only the relative names and min, max, stride are known Steps: Find the total numbers of matches for a dimension ncks -d lon,0,0,1 ~/nco/data/in_grp.nc Here "lmt_nbr" is 1 and there is 1 match at most ncks -d lon,0,0,1 -d lon,0,0,1 -d lat,0,0,1 ~/nco/data/in_grp.nc Here "lmt_nbr" is 3 and there are 2 matches at most for "lon" and 1 match at most for "lat" The limits have to be separated to a) case of coordinate variables b) case of dimension only (there is no coordinate variable for that dimension) Deep copy matches to table, match at the current index, increment current index Apply MSA for each Dimension in a new cycle (that now has all its limits in place :-) ) At this point lmt_sct is no longer needed; Tests: ncks -D 11 -d lon,0,0,1 -d lon,1,1,1 -d lat,0,0,1 -d time,1,2,1 -d time,6,7,1 -v lon,lat,time -H ~/nco/data/in_grp.nc ncks -D 11 -d time,8,9 -d time,0,2 -v time -H ~/nco/data/in_grp.nc ncks -D 11 -d time,8,2 -v time -H ~/nco/data/in_grp.nc # wrapped limit */ /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Is variable to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnnm,var_trv.var_dmn[idx_var_dmn].dmn_nm) == 0){ /* The limits have to be separated to */ /* a) case where the dimension has coordinate variables */ if(var_trv.var_dmn[idx_var_dmn].crd){ /* Increment number of dimension limits for this dimension */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn_nbr++; int nbr_lmt=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn_nbr; trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn=(lmt_sct **)nco_realloc( trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn,nbr_lmt*sizeof(lmt_sct *)); /* b) case of dimension only (there is no coordinate variable for this dimension */ }else{ /* Increment number of dimension limits for this dimension */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn_nbr++; int nbr_lmt=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn_nbr; trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn=(lmt_sct **)nco_realloc( trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn,nbr_lmt*sizeof(lmt_sct *)); } /* b) case of dimension only (there is no coordinate variable for this dimension */ } /* Match input relative name to dimension relative name */ } /* Loop input name list */ } /* Loop variable dimensions */ } /* Is variable to extract */ } /* Loop table */ /* Store matches in table, match at the current index, increment current index */ /* Loop table */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Is variable to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnnm,var_trv.var_dmn[idx_var_dmn].dmn_nm) == 0){ /* Divide limits into two different cases */ /* a) Dimension has coordinate variables */ if(var_trv.var_dmn[idx_var_dmn].crd){ crd_sct *crd=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd; /* Limit is same as dimension in input file? */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.BASIC_DMN=False; /* Parse user-specified limits into hyperslab specifications. NOTE: Use True parameter and "crd" */ (void)nco_lmt_evl_dmn_crd(nc_id,0L,FORTRAN_IDX_CNV,crd->crd_grp_nm_fll,crd->nm,crd->sz,crd->is_rec_dmn,True,lmt[lmt_idx]); /* Current index (lmt_crr) of dimension limits for this (idx_dmn) table dimension */ int lmt_crr=crd->lmt_msa.lmt_crr; /* Increment current index being initialized */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_crr++; /* Alloc this limit */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn[lmt_crr]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Initialize this entry */ (void)nco_lmt_init(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn[lmt_crr]); /* Store dimension ID */ lmt[lmt_idx]->id=crd->dmn_id; /* Store this valid input; deep-copy to table */ (void)nco_lmt_cpy(lmt[lmt_idx],trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn[lmt_crr]); }else{ /* b) Dimension only (no coordinate variable for this dimension) */ dmn_trv_sct *ncd=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd; /* Limit is same as dimension in input file ? */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.BASIC_DMN=False; /* Parse user-specified limits into hyperslab specifications. NOTE: Use False parameter and "dmn" */ (void)nco_lmt_evl_dmn_crd(nc_id,0L,FORTRAN_IDX_CNV,ncd->grp_nm_fll,ncd->nm,ncd->sz,ncd->is_rec_dmn,False,lmt[lmt_idx]); /* Current index (lmt_crr) of dimension limits for this (idx_dmn) table dimension */ int lmt_crr=ncd->lmt_msa.lmt_crr; /* Increment current index being initialized */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_crr++; /* Alloc this limit */ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn[lmt_crr]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Initialize this entry */ (void)nco_lmt_init(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn[lmt_crr]); /* Store dimension ID */ lmt[lmt_idx]->id=ncd->dmn_id; /* Store this valid input; deep-copy to table */ (void)nco_lmt_cpy(lmt[lmt_idx],trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn[lmt_crr]); } /* b) case of dimension only (there is no coordinate variable for this dimension */ } /* Match input relative name to dimension relative name */ } /* Loop input name list */ } /* Loop variable dimensions */ } /* Is variable to extract */ } /* Loop table step 2 */ /* Apply MSA for each Dimension in new cycle (that now has all its limits in place) */ /* Loop table step 3 */ for(unsigned int idx_tbl=0;idx_tblnbr;idx_tbl++){ trv_sct var_trv=trv_tbl->lst[idx_tbl]; /* Is variable to extract */ if(var_trv.nco_typ == nco_obj_typ_var && var_trv.flg_xtr){ /* Loop variable dimensions */ for(int idx_var_dmn=0;idx_var_dmnnm,var_trv.var_dmn[idx_var_dmn].dmn_nm) == 0){ /* Limits divide into two cases */ /* a) Dimension has coordinate variables */ if(var_trv.var_dmn[idx_var_dmn].crd){ /* Adapted from original MSA loop in nco_msa_lmt_all_ntl(); differences are marked GTT specific */ nco_bool flg_ovl; /* [flg] Limits overlap */ crd_sct *crd=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd; /* GTT: If this coordinate has no limits, continue */ if(crd->lmt_msa.lmt_dmn_nbr == 0) continue; /* ncra/ncrcat have only one limit for record dimension so skip evaluation otherwise this messes up multi-file operation */ if(crd->is_rec_dmn && (nco_prg_id_get() == ncra || nco_prg_id_get() == ncrcat)) continue; /* Split-up wrapped limits. NOTE: using deep copy version nco_msa_wrp_splt_cpy() */ (void)nco_msa_wrp_splt_cpy(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); /* Wrapped hyperslabs are dimensions broken into the "wrong" order, e.g., from -d time,8,2 broken into -d time,8,9 -d time,0,2 WRP flag set only when list contains dimensions split as above */ if(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.WRP){ /* Find and store size of output dim */ (void)nco_msa_clc_cnt(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); continue; } /* End WRP flag set */ /* Single slab---no analysis needed */ if(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.lmt_dmn_nbr == 1){ (void)nco_msa_clc_cnt(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); continue; } /* End Single slab */ /* Does Multi-Slab Algorithm returns hyperslabs in user-specified order? */ if(MSA_USR_RDR){ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa.MSA_USR_RDR=True; /* Find and store size of output dimension */ (void)nco_msa_clc_cnt(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); continue; } /* End MSA_USR_RDR */ /* Sort limits */ (void)nco_msa_qsort_srt(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); /* Check for overlap */ flg_ovl=nco_msa_ovl(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); /* Find and store size of output dimension */ (void)nco_msa_clc_cnt(&trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].crd->lmt_msa); if(nco_dbg_lvl_get() >= nco_dbg_fl){ if(flg_ovl) (void)fprintf(stdout,"%s: coordinate \"%s\" has overlapping hyperslabs\n",nco_prg_nm_get(),crd->nm); else (void)fprintf(stdout,"%s: coordinate \"%s\" has distinct hyperslabs\n",nco_prg_nm_get(),crd->nm); } /* endif */ }else{ /* b) Dimension only (no coordinate variable for this dimension) */ dmn_trv_sct *ncd=trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd; /* Adapted from the original MSA loop in nco_msa_lmt_all_ntl(); differences are marked GTT specific */ nco_bool flg_ovl; /* [flg] Limits overlap */ /* GTT: If this dimension has no limits, continue */ if(ncd->lmt_msa.lmt_dmn_nbr == 0) continue; /* ncra/ncrcat have only one limit for record dimension so skip evaluation otherwise this messes up multi-file operation */ if(ncd->is_rec_dmn && (nco_prg_id_get() == ncra || nco_prg_id_get() == ncrcat)) continue; /* Split-up wrapped limits */ (void)nco_msa_wrp_splt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); /* Wrapped hyperslabs are dimensions broken into the "wrong" order,e.g. from -d time,8,2 broken into -d time,8,9 -d time,0,2 WRP flag set only when list contains dimensions split as above */ if(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.WRP){ /* Find and store size of output dim */ (void)nco_msa_clc_cnt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); continue; } /* End WRP flag set */ /* Single slab---no analysis needed */ if(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.lmt_dmn_nbr == 1){ (void)nco_msa_clc_cnt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); continue; } /* End Single slab */ /* Does Multi-Slab Algorithm returns hyperslabs in user-specified order ? */ if(MSA_USR_RDR){ trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.MSA_USR_RDR=True; /* Find and store size of output dimension */ (void)nco_msa_clc_cnt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); continue; } /* End MSA_USR_RDR */ /* Sort limits */ (void)nco_msa_qsort_srt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); /* Check for overlap */ flg_ovl=nco_msa_ovl_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); if(!flg_ovl) trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd->lmt_msa.MSA_USR_RDR=True; /* Find and store size of output dimension */ (void)nco_msa_clc_cnt_trv(trv_tbl->lst[idx_tbl].var_dmn[idx_var_dmn].ncd); if(nco_dbg_lvl_get() >= nco_dbg_fl){ if(flg_ovl) (void)fprintf(stdout,"%s: dimension \"%s\" has overlapping hyperslabs\n",nco_prg_nm_get(),ncd->nm); else (void)fprintf(stdout,"%s: dimension \"%s\" has distinct hyperslabs\n",nco_prg_nm_get(),ncd->nm); } /* endif */ } /* b) case of dimension only (there is no coordinate variable for this dimension */ } /* Match input relative name to dimension relative name */ } /* Loop input name list */ } /* Loop variable dimensions */ } /* Is variable to extract */ } /* Loop table step 3 */ } /* nco_bld_lmt() */ void nco_msa_var_get_lmn_trv /* [fnc] Read a used defined limit */ (const int nc_id, /* I [ID] netCDF file ID */ var_sct *var_prc, /* I/O [sct] Variable */ const char * const rec_nm_fll, /* I [sng] Full name of record being done in loop ((*lmt_rec)[idx_rec]->nm_fll ) */ const long idx_rec_crr_in, /* [idx] Index of current record in current input file */ const trv_tbl_sct * const trv_tbl) /* I [sct] GTT (Group Traversal Table) */ { /* Define artificial MSA limit that corresponds to one record to read, since nco_msa_var_get_trv() reads all elements */ int lmt_dmn_nbr; nco_bool flg_lmt=False; /* [flg] Allocate custom limit */ trv_sct *var_trv; /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_prc->nm_fll,trv_tbl); /* Loop dimensions */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ /* NB: Match current record must be done by name, since ID may differ for records across files */ if(strcmp(var_trv->var_dmn[idx_dmn].dmn_nm_fll,rec_nm_fll) == 0){ /* Case of dimension being coordinate variable */ if(var_trv->var_dmn[idx_dmn].crd){ lmt_dmn_nbr=var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn_nbr; /* Case of previously existing limits */ if(lmt_dmn_nbr > 0){ /* Loop limits */ for(int idx_lmt=0;idx_lmtvar_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[idx_lmt]->srt=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[idx_lmt]->end=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[idx_lmt]->cnt=1; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[idx_lmt]->srd=1; } /* Loop limits */ /* ! Case of previously existing limits */ }else{ flg_lmt=True; /* Alloc 1 dummy limit */ var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn_nbr=1; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn=(lmt_sct **)nco_malloc(1*sizeof(lmt_sct *)); var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Initialize NULL/invalid */ (void)nco_lmt_init(var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]); /* And set start, count, stride to match current record ... */ var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]->srt=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]->end=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]->cnt=1; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]->srd=1; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]->nm=strdup("record_limit"); } /* ! Case of previously existing limits */ } /* Case of dimension being coordinate variable */ else{ assert(!var_trv->var_dmn[idx_dmn].is_crd_var); lmt_dmn_nbr=var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn_nbr; /* Case of previously existing limits */ if(lmt_dmn_nbr > 0){ /* Loop limits */ for(int idx_lmt=0;idx_lmtvar_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[idx_lmt]->srt=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[idx_lmt]->end=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[idx_lmt]->cnt=1; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[idx_lmt]->srd=1; } /* Loop limits */ /* ! Case of previously existing limits */ }else{ flg_lmt=True; /* Alloc 1 dummy limit */ var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn_nbr=1; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn=(lmt_sct **)nco_malloc(1*sizeof(lmt_sct *)); var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]=(lmt_sct *)nco_malloc(sizeof(lmt_sct)); /* Initialize NULL/invalid */ (void)nco_lmt_init(var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]); /* And set start,count,stride to match current record ...Jesuzz */ var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]->srt=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]->end=idx_rec_crr_in; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]->cnt=1; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]->srd=1; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]->nm=strdup("record_limit"); } /* ! Case of previously existing limits */ } /* Case of dimension not being coordinate variable */ break; } /* Match current record by name */ } /* Loop dimensions */ /* Retrieve variable from disk into memory */ (void)nco_msa_var_get_trv(nc_id,var_prc,trv_tbl); /* Free artificial limit and reset number of limits */ for(int idx_dmn=0;idx_dmnnbr_dmn;idx_dmn++){ /* NB: Match current record must be done by name, since ID may differ for records across files */ if(strcmp(var_trv->var_dmn[idx_dmn].dmn_nm_fll,rec_nm_fll) == 0){ /* Custom limit */ if(flg_lmt){ /* Case of dimension being coordinate variable */ if(var_trv->var_dmn[idx_dmn].is_crd_var){ var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn_nbr=0; var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]=(lmt_sct *)nco_lmt_free(var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn[0]); var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn=(lmt_sct **)nco_free(var_trv->var_dmn[idx_dmn].crd->lmt_msa.lmt_dmn); } /* Case of dimension being coordinate variable */ else if(!var_trv->var_dmn[idx_dmn].is_crd_var){ var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn_nbr=0; var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]=(lmt_sct *)nco_lmt_free(var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn[0]); var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn=(lmt_sct **)nco_free(var_trv->var_dmn[idx_dmn].ncd->lmt_msa.lmt_dmn); } /* Case of dimension not being coordinate variable */ break; } /* Custom limit */ } /* Match current record */ } /* Loop dimensions */ } /* nco_msa_var_get_lmn_trv() */ nco_bool /* O [flg] Skip variable */ nco_skp_var /* [fnc] Skip variable while doing record */ (const var_sct * const var_prc, /* I [sct] Processed variable */ const char * const rec_nm_fll, /* I [sng] Full name of record being done in loop */ const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { nco_bool flg_skp; /* [flg] Skip variable */ dmn_trv_sct *dmn_trv; /* [sct] GTT dimension structure */ /* Variable must contain one record */ assert(var_prc->is_rec_var); flg_skp=False; /* Loop dimensions */ for(int idx_dmn=0;idx_dmnnbr_dim;idx_dmn++){ /* Is this the record dimension ? */ if(var_prc->dim[idx_dmn]->is_rec_dmn){ /* Get unique dimension object from unique dimension ID, in input list (NB: this is needed because dmn_sct does not have name full) */ dmn_trv=nco_dmn_trv_sct(var_prc->dim[idx_dmn]->id,trv_tbl); /* And it is not the same as the input record dimension name currently being done then skip it */ if(strcmp(dmn_trv->nm_fll,rec_nm_fll)) flg_skp=True; } /* Is this the record dimension */ } /* Loop dimensions */ return flg_skp; } /* nco_skp_var() */ var_sct * /* O [sct] Variable (weight/mask) */ nco_var_get_wgt_trv /* [fnc] Retrieve weighting or mask variable */ (const int nc_id, /* I [id] netCDF file ID */ const char * const wgt_nm, /* I [sng] Weight variable name (relative or absolute) */ const var_sct * const var, /* I [sct] Variable that needs the weight/mask variable */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Return the variable (weight or mask) that is in scope of variable that needs the weight/mask variable */ int nbr_wgt=0; /* [nbr] Number of weight/mask variables in file */ int grp_id; /* [ID] Group ID */ int var_id; /* [ID] Variable ID */ int idx_wgt; /* [nbr] Weight array counter */ /* Detect if the weight variable name is relative or absolute */ /* If first character is '/' then assume absolute path */ if ('/' == wgt_nm[0]){ /* Obtain variable GTT object using full variable name */ trv_sct *wgt_trv=trv_tbl_var_nm_fll(wgt_nm,trv_tbl); var_sct *wgt_var; /* Obtain group ID from API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,wgt_trv->grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,wgt_trv->nm,&var_id); /* Transfer from table to local variable */ wgt_var=nco_var_fll_trv(grp_id,var_id,wgt_trv,trv_tbl); /* Retrieve variable NB: using GTT version, that "knows" all the limits */ (void)nco_msa_var_get_trv(nc_id,wgt_var,trv_tbl); return wgt_var; /* Relative name; search all names in table */ } else { trv_sct **wgt_trv=NULL; /* [sct] Weight/mask list */ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && (!strcmp(trv_tbl->lst[tbl_idx].nm,wgt_nm))) nbr_wgt++; } /* Fill-in variable structure list for all weights */ wgt_trv=(trv_sct **)nco_malloc(nbr_wgt*sizeof(trv_sct *)); idx_wgt=0; /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Filter by name */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var && (!strcmp(trv_tbl->lst[tbl_idx].nm,wgt_nm))){ wgt_trv[idx_wgt]=&trv_tbl->lst[tbl_idx]; idx_wgt++; } /* Filter variables */ } /* Loop table */ /* Loop table */ for(unsigned idx_var=0;idx_varnbr;idx_var++){ /* Find the variable that needs the weight */ if(trv_tbl->lst[idx_var].nco_typ == nco_obj_typ_var && trv_tbl->lst[idx_var].flg_xtr && (strcmp(trv_tbl->lst[idx_var].nm_fll,var->nm_fll) == 0)){ trv_sct var_trv=trv_tbl->lst[idx_var]; /* Loop over weights */ for(idx_wgt=0;idx_wgtgrp_nm_fll,var_trv.grp_nm_fll)){ var_sct *wgt_var; /* Obtain group ID from API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,wgt_trv[idx_wgt]->grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,wgt_trv[idx_wgt]->nm,&var_id); /* Transfer from table to local variable */ wgt_var=nco_var_fll_trv(grp_id,var_id,wgt_trv[idx_wgt],trv_tbl); /* Retrieve variable NB: using GTT version, that "knows" all the limits */ (void)nco_msa_var_get_trv(nc_id,wgt_var,trv_tbl); wgt_trv=(trv_sct **)nco_free(wgt_trv); return wgt_var; } /* Same group */ } /* Loop over weights */ } /* Filter variables */ } /* Loop table */ } return NULL; } /* nco_var_get_wgt_trv() */ dmn_trv_sct * /* O [sct] Table dimension object */ nco_dmn_usr_sng /* [fnc] Parse input string and return table dimension object */ (const char * const usr_sng, /* I [sng] Object name */ const trv_tbl_sct * const trv_tbl, /* I [lst] Traversal table */ nco_bool *is_opt) /* O [flg] Dimension presence is optional (input string has '.') */ { /* Purpose: Parse input string and return table dimension object */ const char opt_chr='.'; /* Character indicating presence of following variable/dimension/attribute in file is optional */ *is_opt=False; /* Try absolute match */ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr_dmn;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng,trv_tbl->lst_dmn[tbl_idx].nm_fll) == 0){ return &trv_tbl->lst_dmn[tbl_idx]; } /* Match name */ } /* Loop table */ /* Try relative match */ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr_dmn;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng,trv_tbl->lst_dmn[tbl_idx].nm) == 0){ return &trv_tbl->lst_dmn[tbl_idx]; } /* Match name */ } /* Loop table */ /* Try optional absolute match */ /* Optional absolute match */ if(usr_sng[0] == opt_chr){ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr_dmn;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng+1,trv_tbl->lst_dmn[tbl_idx].nm_fll) == 0){ *is_opt=True; return &trv_tbl->lst_dmn[tbl_idx]; } /* Match name */ } /* Loop table */ } /* Optional absolute match */ /* Optional relative match */ if(usr_sng[0] == opt_chr){ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr_dmn;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng+1,trv_tbl->lst_dmn[tbl_idx].nm) == 0){ *is_opt=True; return &trv_tbl->lst_dmn[tbl_idx]; } /* Match name */ } /* Loop table */ } /* Optional relative match */ /* Cases of not found and optional */ if(usr_sng[0] == opt_chr){ *is_opt=True; } return NULL; } /* nco_dmn_usr_sng() */ trv_sct * /* O [sct] Table object */ nco_obj_usr_sng /* [fnc] Parse input string and return table object */ (const char * const usr_sng, /* I [sng] Object name */ const trv_tbl_sct * const trv_tbl, /* I [lst] Traversal table */ nco_bool *is_opt) /* O [flg] Dimension presence is optional (input string has '.') */ { /* Purpose: Parse input string and return table object */ const char opt_chr='.'; /* Character indicating presence of following variable/dimension/attribute in file is optional */ /* Only used by ncrename */ assert(nco_prg_id_get() == ncrename); *is_opt=False; /* Try absolute match */ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng,trv_tbl->lst[tbl_idx].nm_fll) == 0){ return &trv_tbl->lst[tbl_idx]; } /* Match name */ } /* Loop table */ /* Try relative match */ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Match relative name */ if(strcmp(usr_sng,trv_tbl->lst[tbl_idx].nm) == 0){ return &trv_tbl->lst[tbl_idx]; } /* Match name */ } /* Loop table */ /* Try optional absolute match */ /* Optional absolute match */ if(usr_sng[0] == opt_chr){ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Match absolute name */ if(strcmp(usr_sng+1,trv_tbl->lst[tbl_idx].nm_fll) == 0){ *is_opt=True; return &trv_tbl->lst[tbl_idx]; } /* Match name */ } /* Loop table */ } /* Optional absolute match */ /* Optional relative match */ if(usr_sng[0] == opt_chr){ /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Match relative name */ if(strcmp(usr_sng+1,trv_tbl->lst[tbl_idx].nm) == 0){ *is_opt=True; return &trv_tbl->lst[tbl_idx]; } /* Match name */ } /* Loop table */ } /* Optional relative match */ /* Cases of not found and optional */ if(usr_sng[0] == opt_chr){ *is_opt=True; } return NULL; } /* nco_obj_usr_sng() */ void nco_aed_prc_grp /* [fnc] Process attributes in groups */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Process attributes */ int grp_id; /* [id] Group ID */ nco_bool var_fnd=False; /* [flg] Variable was found */ /* Only used by ncatted */ assert(nco_prg_id_get() == ncatted); /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Is group */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_grp){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv_tbl->lst[tbl_idx].grp_nm_fll,&grp_id); /* Process attribute */ (void)nco_aed_prc(grp_id,NC_GLOBAL,aed); var_fnd=True; } /* Is group */ } /* Loop table */ if(!var_fnd){ (void)fprintf(stderr,"%s: No attributes were found\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } return; } /* nco_aed_prc_grp() */ void nco_aed_prc_glb /* [fnc] Process attributes in root group */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Process attributes */ int grp_id; /* [id] Group ID */ nco_bool var_fnd=False; /* [flg] Variable was found */ /* Only used by ncatted */ assert(nco_prg_id_get() == ncatted); /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Is root group */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_grp && strcmp("/",trv_tbl->lst[tbl_idx].nm_fll) == 0){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv_tbl->lst[tbl_idx].grp_nm_fll,&grp_id); /* Process attribute */ (void)nco_aed_prc(grp_id,NC_GLOBAL,aed); var_fnd=True; } /* Is group */ } /* Loop table */ if(!var_fnd){ (void)fprintf(stderr,"%s: Attribute was not found\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } return; } /* nco_aed_prc_grp() */ void nco_aed_prc_var /* [fnc] Process attributes in variables */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Process attributes */ int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ nco_bool var_fnd=False; /* [flg] Variable was found */ /* Only used by ncatted */ assert(nco_prg_id_get() == ncatted); /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ /* Is variable */ if(trv_tbl->lst[tbl_idx].nco_typ == nco_obj_typ_var){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv_tbl->lst[tbl_idx].grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,trv_tbl->lst[tbl_idx].nm,&var_id); /* Process attribute */ (void)nco_aed_prc(grp_id,var_id,aed); var_fnd=True; } /* Is variable */ } /* Loop table */ if(!var_fnd){ (void)fprintf(stderr,"%s: No attributes were found\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } return; } /* nco_aed_prc_var() */ void nco_aed_prc_var_xtr /* [fnc] Process attributes in variables that match table extraction flag */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Process attributes */ int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ nco_bool var_fnd=False; /* [flg] Variable was found */ /* Only used by ncatted */ assert(nco_prg_id_get() == ncatted); /* Loop table */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ trv_sct trv=trv_tbl->lst[tbl_idx]; /* Is variable to extract */ if(trv.nco_typ == nco_obj_typ_var && trv.flg_xtr){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,trv.nm,&var_id); /* Process attribute */ (void)nco_aed_prc(grp_id,var_id,aed); var_fnd=True; } /* Is variable */ } /* Loop table */ if(!var_fnd){ (void)fprintf(stderr,"%s: No attributes were found\n",nco_prg_nm_get()); nco_exit(EXIT_FAILURE); } return; } /* nco_aed_prc_var_xtr() */ void nco_aed_prc_var_nm /* [fnc] Process attributes in variables that match input name */ (const int nc_id, /* I [id] netCDF file ID */ const aed_sct aed, /* I [sct] Structure containing information necessary to edit */ const trv_tbl_sct * const trv_tbl) /* I [lst] Traversal table */ { /* Purpose: Process attributes in variables that match input name (absolute or relative) */ int grp_id; /* [id] Group ID */ int var_id; /* [id] Variable ID */ nco_bool var_fnd=False; /* [flg] Variable was found */ /* Only used by ncatted */ assert(nco_prg_id_get() == ncatted); /* Assume name is for variable */ /* Loop table (absolute name) */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ trv_sct trv=trv_tbl->lst[tbl_idx]; /* Variable name match */ if(trv.nco_typ == nco_obj_typ_var && strcmp(aed.var_nm,trv.nm_fll) == 0){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,trv.nm,&var_id); /* Process attribute */ (void)nco_aed_prc(grp_id,var_id,aed); /* Only 1 match possible, return */ return; } /* Is variable */ } /* Loop table */ /* Loop table (relative name, can be many) */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ trv_sct trv=trv_tbl->lst[tbl_idx]; /* Variable name (relative) match */ if(trv.nco_typ == nco_obj_typ_var && strcmp(aed.var_nm,trv.nm) == 0){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv.grp_nm_fll,&grp_id); /* Get variable ID */ (void)nco_inq_varid(grp_id,trv.nm,&var_id); /* Process attribute */ (void)nco_aed_prc(grp_id,var_id,aed); var_fnd=True; } /* Is variable */ } /* Loop table */ /* Try name for group */ /* Loop table (absolute name) */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ trv_sct trv=trv_tbl->lst[tbl_idx]; /* Group name match */ if(trv.nco_typ == nco_obj_typ_grp && strcmp(aed.var_nm,trv.nm_fll) == 0){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv.grp_nm_fll,&grp_id); /* Process attribute */ (void)nco_aed_prc(grp_id,NC_GLOBAL,aed); /* Only 1 match possible, return */ return; } /* Is variable */ } /* Loop table */ /* Loop table (relative name, can be many) */ for(unsigned tbl_idx=0;tbl_idxnbr;tbl_idx++){ trv_sct trv=trv_tbl->lst[tbl_idx]; /* Group name (relative) match */ if(trv.nco_typ == nco_obj_typ_grp && strcmp(aed.var_nm,trv.nm) == 0){ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,trv.grp_nm_fll,&grp_id); /* Process attribute */ (void)nco_aed_prc(grp_id,NC_GLOBAL,aed); var_fnd=True; } /* Is variable */ } /* Loop table */ if(!var_fnd){ (void)fprintf(stderr,"%s: Variable <%s> was not found\n",nco_prg_nm_get(),aed.var_nm); nco_exit(EXIT_FAILURE); } return; } /* nco_aed_prc_var_nm() */ void nco_grp_var_lst /* [fnc] Export list of variable names for group */ (const int nc_id, /* I [id] netCDF file ID */ const char * const grp_nm_fll, /* I [sng] Absolute group name */ char ***nm_lst, /* I/O [sng] List of names (relative) */ int *nm_lst_nbr) /* I/O [nbr] Number of items in list */ { /* Purpose: Export list of variable names for group */ char var_nm[NC_MAX_NAME+1]; /* [sng] Variable name */ int nbr_var; /* [nbr] Number of variables */ int grp_id; /* [id] Group ID */ /* Get group ID */ (void)nco_inq_grp_full_ncid(nc_id,grp_nm_fll,&grp_id); /* Obtain number of variable for group */ (void)nco_inq(grp_id,(int *)NULL,&nbr_var,(int *)NULL,(int *)NULL); /* Allocate list */ (*nm_lst)=(char **)nco_malloc(nbr_var*sizeof(char *)); /* Iterate variables for this group */ for(int idx_var=0;idx_varnco_typ == nco_obj_typ_var); /* Initialize return value */ *flg_cf_fnd=False; /* Obtain group ID from netCDF API using full group name */ (void)nco_inq_grp_full_ncid(nc_id,var_trv->grp_nm_fll,&grp_id); /* Obtain variable ID */ (void)nco_inq_varid(grp_id,var_trv->nm,&var_id); /* Find number of attributes */ (void)nco_inq_varnatts(grp_id,var_id,&nbr_att); assert(nbr_att == var_trv->nbr_att); /* Loop attributes */ for(int idx_att=0;idx_attnm_fll,nco_typ_sng(att_typ),nco_typ_sng(NC_CHAR)); return NULL; } /* end if */ att_val=(char *)nco_malloc((att_sz+1L)*sizeof(char)); if(att_sz > 0L) (void)nco_get_att(grp_id,var_id,att_nm,(void *)att_val,NC_CHAR); /* NUL-terminate attribute */ att_val[att_sz]='\0'; /* Split list into separate coordinate names Use nco_lst_prs_sgl_2D() not nco_lst_prs_2D() to avert TODO nco944 */ cf_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_cf); /* ...for each coordinate in CF convention attribute, i.e., "bounds" or "coordinate"... */ for(int idx_cf=0;idx_cfvar_nm_fll is relative here) */ var_nm_fll=nco_bld_nm_fll(grp_nm_fll,cmn_lst[idx_var].nm); /* Obtain variable GTT object using full variable name */ var_trv=trv_tbl_var_nm_fll(var_nm_fll,trv_tbl); /* Avoid coordinate variables */ if (var_trv->is_crd_var == True){ /* Utility function to detect inserted names in a name list */ lst_ins=nco_lst_ins(var_nm_fll,*skp_lst,idx_skp); /* Insert in list */ if (lst_ins == False){ (*skp_lst)[idx_skp].nm=strdup(var_nm_fll); idx_skp++; } /* Insert in list */ } /* Avoid coordinate variables */ /* Avoid special "CF" variables ('bounds', 'coordinates') */ var_cf=nco_var_has_cf(nc_id,var_trv,"bounds",&flg_cf); if (flg_cf == True){ /* Utility function to detect inserted names in a name list */ lst_ins=nco_lst_ins(var_nm_fll,*skp_lst,idx_skp); /* Insert in list */ if (lst_ins == False){ (*skp_lst)[idx_skp].nm=strdup(var_nm_fll); idx_skp++; } /* Insert in list */ } /* Avoid special "CF" variables ('bounds', 'coordinates') */ /* There is an associated 'CF" variable */ if (var_cf){ /* Second Loop input (relative) names */ for(int idx_var_2=0;idx_var_2var_nm_fll is relative here) */ if(strcmp(var_cf,cmn_lst[idx_var_2].nm) == 0){ char *var_nm_fll_2; /* [sng] Variable full name */ var_nm_fll_2=nco_bld_nm_fll(grp_nm_fll,cmn_lst[idx_var_2].nm); /* Utility function to detect inserted names in a name list */ lst_ins=nco_lst_ins(var_nm_fll_2,*skp_lst,idx_skp); /* Insert in list */ if (lst_ins == False){ (*skp_lst)[idx_skp].nm=strdup(var_nm_fll_2); idx_skp++; } /* Insert in list */ } /* Match */ } /* Second Loop input (relative) names */ /* Free */ var_cf=(char *)nco_free(var_cf); } /* There is an associated 'CF" variable */ /* Free */ var_nm_fll=(char *)nco_free(var_nm_fll); } /* Loop input (relative) names */ /* Re-Alloc */ (*skp_lst)=(nco_cmn_t *)nco_realloc((*skp_lst),idx_skp*sizeof(nco_cmn_t)); /* Export */ *nbr_skp_nm=idx_skp; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: DEBUG %s list of variables to skip for template definition\n",nco_prg_nm_get(),fnc_nm); for(int idx_var=0;idx_var\n",nco_prg_nm_get(),fnc_nm,(*skp_lst)[idx_var].nm); } } /* nco_nm_skp() */ void nco_bld_nsm /* [fnc] Build ensembles */ (const int nc_id, /* I [id] netCDF file ID */ trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */ { /* Purpose: Build ensembles */ const char fnc_nm[]="nco_bld_nsm()"; /* [sng] Function name */ char **nm_lst_1; /* [sng] List of names */ char **nm_lst_2; /* [sng] List of names */ int nm_lst_1_nbr; /* [nbr] Number of items in list */ int nm_lst_2_nbr; /* [nbr] Number of items in list */ int nbr_cmn_nm; /* [nbr] Number of common entries */ int nbr_nm; /* [nbr] Number of total entries */ int nbr_skp_nm; /* [nbr] Number of names to avoid for template definition (array skp_lst) */ int nsm_nbr=0; /* [nbr] Ensemble counter */ nco_bool flg_nsm_tpl; /* [flg] Variable is template */ nco_bool flg_ini_skp=False; nco_cmn_t *cmn_lst=NULL; /* [sct] A list of common names */ nco_cmn_t *skp_lst=NULL; /* [sct] A list of skip ('skp') names (NB: using same sct as common names, with different meaning) */ /* Insert ensembles (parent group name is key) */ /* Loop table */ for(unsigned idx_tbl_1=0;idx_tbl_1nbr;idx_tbl_1++){ trv_sct trv_1=trv_tbl->lst[idx_tbl_1]; /* Group (not root, with variables) */ if(trv_1.nco_typ == nco_obj_typ_grp && trv_1.grp_dpt > 0 && trv_1.nbr_var > 0){ /* Export list of variable names for group */ (void)nco_grp_var_lst(nc_id,trv_1.grp_nm_fll,&nm_lst_1,&nm_lst_1_nbr); if(nco_dbg_lvl_get() == nco_dbg_old) (void)fprintf(stdout,"%s: DEBUG %s looking for ensembles for <%s>\n",nco_prg_nm_get(),fnc_nm,trv_1.nm_fll); /* Loop table */ for(unsigned idx_tbl_2=0;idx_tbl_2nbr;idx_tbl_2++){ trv_sct trv_2=trv_tbl->lst[idx_tbl_2]; /* Same depth, same number of variables, same parent group */ if(trv_1.nco_typ == nco_obj_typ_grp && trv_1.grp_dpt == trv_2.grp_dpt && trv_1.nbr_var == trv_2.nbr_var && strcmp(trv_1.grp_nm_fll_prn,trv_2.grp_nm_fll_prn) == 0){ /* Assume not yet inserted in array */ nco_bool flg_ins=False; /* Loop constructed array to see if already inserted */ for(int idx_nsm=0;idx_nsmnsm_nbr;idx_nsm++){ /* Match */ if(strcmp(trv_tbl->nsm[idx_nsm].grp_nm_fll_prn,trv_2.grp_nm_fll_prn) == 0){ /* Mark as inserted in array */ flg_ins=True; break; } /* Match */ } /* Loop constructed array to see if already inserted */ /* Export list of variable names for group */ (void)nco_grp_var_lst(nc_id,trv_2.grp_nm_fll,&nm_lst_2,&nm_lst_2_nbr); /* Match 2 lists of variable names and export common names */ (void)nco_nm_mch(nm_lst_1,nm_lst_1_nbr,nm_lst_2,nm_lst_2_nbr,&cmn_lst,&nbr_nm,&nbr_cmn_nm); /* Found common names */ if (nbr_cmn_nm && nm_lst_1_nbr == nm_lst_2_nbr && nm_lst_1_nbr == nbr_cmn_nm && !flg_ins){ trv_tbl->nsm_nbr++; trv_tbl->nsm=(nsm_sct *)nco_realloc(trv_tbl->nsm,trv_tbl->nsm_nbr*sizeof(nsm_sct)); trv_tbl->nsm[trv_tbl->nsm_nbr-1].mbr_nbr=0; trv_tbl->nsm[trv_tbl->nsm_nbr-1].mbr=NULL; trv_tbl->nsm[trv_tbl->nsm_nbr-1].grp_nm_fll_prn=(char *)strdup(trv_2.grp_nm_fll_prn); /* Variable ensemble members */ trv_tbl->nsm[trv_tbl->nsm_nbr-1].mbr_var_nbr=0; trv_tbl->nsm[trv_tbl->nsm_nbr-1].var_mbr_fll=NULL; trv_tbl->nsm[trv_tbl->nsm_nbr-1].grp_mbr_fll=NULL; trv_tbl->nsm[trv_tbl->nsm_nbr-1].mbr_srt=0; trv_tbl->nsm[trv_tbl->nsm_nbr-1].mbr_end=0; /* Group (NB: outer loop) is ensemble parent group */ trv_tbl->lst[idx_tbl_1].flg_nsm_prn=True; if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: DEBUG %s inserted ensemble for <%s>\n",nco_prg_nm_get(),fnc_nm,trv_2.grp_nm_fll_prn); } } /* Found common names */ /* Free list 2 */ for(int idx_nm=0;idx_nmnsm_nbr;idx_nsm++){ (void)fprintf(stdout,"%s: DEBUG %s <%s>\n",nco_prg_nm_get(),fnc_nm,trv_tbl->nsm[idx_nsm].grp_nm_fll_prn); } } /* Insert names in ensembles */ /* Loop table */ for(unsigned idx_tbl_1=0;idx_tbl_1nbr;idx_tbl_1++){ trv_sct trv_1=trv_tbl->lst[idx_tbl_1]; /* Group (not root, with variables) */ if(trv_1.nco_typ == nco_obj_typ_grp && trv_1.grp_dpt > 0 && trv_1.nbr_var > 0){ /* Export list of variable names for group */ (void)nco_grp_var_lst(nc_id,trv_1.grp_nm_fll,&nm_lst_1,&nm_lst_1_nbr); if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: DEBUG %s looking for ensembles for <%s>\n",nco_prg_nm_get(),fnc_nm,trv_1.nm_fll); } /* Loop table */ for(unsigned idx_tbl_2=0;idx_tbl_2nbr;idx_tbl_2++){ trv_sct trv_2=trv_tbl->lst[idx_tbl_2]; /* Same depth, same number of variables, same parent group */ if(trv_1.nco_typ == nco_obj_typ_grp && trv_1.grp_dpt == trv_2.grp_dpt && trv_1.nbr_var == trv_2.nbr_var && strcmp(trv_1.grp_nm_fll_prn,trv_2.grp_nm_fll_prn) == 0){ /* Export list of variable names for group */ (void)nco_grp_var_lst(nc_id,trv_2.grp_nm_fll,&nm_lst_2,&nm_lst_2_nbr); /* Match 2 lists of variable names and export common names (NB: relative names) */ (void)nco_nm_mch(nm_lst_1,nm_lst_1_nbr,nm_lst_2,nm_lst_2_nbr,&cmn_lst,&nbr_nm,&nbr_cmn_nm); /* Found common names */ if (nbr_cmn_nm && nm_lst_1_nbr == nm_lst_2_nbr && nm_lst_1_nbr == nbr_cmn_nm){ /* Define a list of variables to avoid for template definition */ (void)nco_nm_skp(nc_id,trv_2.grp_nm_fll,cmn_lst,nbr_cmn_nm,&skp_lst,&nbr_skp_nm,trv_tbl); /* Mark the skip names as non extracted variables */ for(int idx_skp=0;idx_skpnsm_skp=(nm_tbl_sct *)nco_malloc(sizeof(nm_tbl_sct)); trv_tbl->nsm_skp->nbr=nbr_skp_nm; trv_tbl->nsm_skp->lst=NULL; trv_tbl->nsm_skp->lst=(nm_sct *)nco_realloc(trv_tbl->nsm_skp->lst,(nbr_skp_nm)*sizeof(nm_sct)); for(int idx_skp=0;idx_skpnsm_skp->lst[idx_skp].nm=strdup(skp_lst[idx_skp].nm); } flg_ini_skp=True; } /* Assume not yet inserted in array */ nco_bool flg_ins=False; /* Loop constructed array to see if already inserted (NB: to nsm_nbr) */ for(int idx_nsm=0;idx_nsmnsm[idx_nsm].mbr_nbr;idx_mbr++){ /* Match */ if(strcmp(trv_tbl->nsm[idx_nsm].mbr[idx_mbr].mbr_nm_fll,trv_2.grp_nm_fll) == 0){ /* Mark as inserted in array */ flg_ins=True; break; } /* Match */ } /* Loop names */ } /* Loop constructed array to see if already inserted */ /* Not inserted */ if (!flg_ins){ int mbr_nbr=trv_tbl->nsm[nsm_nbr].mbr_nbr; trv_tbl->nsm[nsm_nbr].mbr_nbr++; trv_tbl->nsm[nsm_nbr].mbr=(nsm_grp_sct *)nco_realloc(trv_tbl->nsm[nsm_nbr].mbr,(mbr_nbr+1)*sizeof(nsm_grp_sct)); trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].mbr_nm_fll=(char *)strdup(trv_2.grp_nm_fll); trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nbr=0; trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nm_fll=NULL; trv_tbl->nsm[nsm_nbr].grp_mbr_fll=(char **)nco_realloc(trv_tbl->nsm[nsm_nbr].grp_mbr_fll,(mbr_nbr+1)*sizeof(char *)); trv_tbl->nsm[nsm_nbr].grp_mbr_fll[mbr_nbr]=(char *)strdup(trv_2.grp_nm_fll); /* Update offsets */ trv_tbl->nsm[nsm_nbr].mbr_srt=0; trv_tbl->nsm[nsm_nbr].mbr_end=trv_tbl->nsm[nsm_nbr].mbr_nbr; /* Mark variables as ensemble members */ for(int idx_var=0;idx_varvar_nm_fll is relative here) */ char *var_nm_fll=nco_bld_nm_fll(trv_2.grp_nm_fll,cmn_lst[idx_var].nm); /* Template criteria: check the names to skip built above in nco_nm_skp() */ flg_nsm_tpl=True; /* Loop skip names */ for(int idx_skp=0;idx_skpnsm[nsm_nbr].mbr_var_nbr; trv_tbl->nsm[nsm_nbr].var_mbr_fll=(char **)nco_realloc(trv_tbl->nsm[nsm_nbr].var_mbr_fll,(mbr_var_nbr+1)*sizeof(char *)); trv_tbl->nsm[nsm_nbr].var_mbr_fll[mbr_var_nbr]=(char *)strdup(var_nm_fll); trv_tbl->nsm[nsm_nbr].mbr_var_nbr++; /* Mark group as emsemble member (NB: loop 2) */ trv_tbl->lst[idx_tbl_2].flg_nsm_mbr=True; /* If not the first group member, then it's not a template */ if(mbr_nbr > 0) flg_nsm_tpl=False; /* Mark ensemble member flag in table for "var_nm_fll" real member */ (void)trv_tbl_mrk_nsm_mbr(var_nm_fll,flg_nsm_tpl,trv_1.grp_nm_fll_prn,trv_tbl); } /* Ensemble members */ /* Insert variable in table ensemble struct */ trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nbr++; trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nm_fll=(char **)nco_realloc(trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nm_fll,trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nbr*sizeof(char *)); trv_tbl->nsm[nsm_nbr].mbr[mbr_nbr].var_nm_fll[idx_var]=(char *)strdup(var_nm_fll); if(nco_dbg_lvl_get() == nco_dbg_old){ (void)fprintf(stdout,"%s: DEBUG %s inserted ensemble variable <%s> as template %d\n",nco_prg_nm_get(),fnc_nm,var_nm_fll,flg_nsm_tpl); } /* Free */ var_nm_fll=(char *)nco_free(var_nm_fll); } /* Mark variables as ensemble members */ } /* Not inserted */ } /* Found common names */ /* Free list 2 */ for(int idx_nm=0;idx_nm= nco_dbg_fl){ nco_prn_nsm(trv_tbl); } assert(nsm_nbr == trv_tbl->nsm_nbr); } /* nco_bld_nsm() */ void nco_prn_nsm /* [fnc] Print ensembles */ (const trv_tbl_sct * const trv_tbl) /* I [sct] Traversal table */ { (void)fprintf(stdout,"%s: list of ensembles\n",nco_prg_nm_get()); for(int idx_nsm=0;idx_nsmnsm_nbr;idx_nsm++){ (void)fprintf(stdout,"%s: <%s>\n",nco_prg_nm_get(),trv_tbl->nsm[idx_nsm].grp_nm_fll_prn); } (void)fprintf(stdout,"%s: list of templates\n",nco_prg_nm_get()); int idx_tpl=0; for(unsigned uidx=0;uidxnbr;uidx++){ if(trv_tbl->lst[uidx].flg_nsm_tpl){ (void)fprintf(stdout,"%s: